130088Sminshall /*
2*36284Sminshall * Copyright (c) 1984-1987 by the Regents of the
3*36284Sminshall * University of California and by Gregory Glenn Minshall.
430088Sminshall *
5*36284Sminshall * Permission to use, copy, modify, and distribute these
6*36284Sminshall * programs and their documentation for any purpose and
7*36284Sminshall * without fee is hereby granted, provided that this
8*36284Sminshall * copyright and permission appear on all copies and
9*36284Sminshall * supporting documentation, the name of the Regents of
10*36284Sminshall * the University of California not be used in advertising
11*36284Sminshall * or publicity pertaining to distribution of the programs
12*36284Sminshall * without specific prior permission, and notice be given in
13*36284Sminshall * supporting documentation that copying and distribution is
14*36284Sminshall * by permission of the Regents of the University of California
15*36284Sminshall * and by Gregory Glenn Minshall. Neither the Regents of the
16*36284Sminshall * University of California nor Gregory Glenn Minshall make
17*36284Sminshall * representations about the suitability of this software
18*36284Sminshall * for any purpose. It is provided "as is" without
19*36284Sminshall * express or implied warranty.
2030088Sminshall */
2130088Sminshall
2230088Sminshall #ifndef lint
23*36284Sminshall static char copyright[] =
24*36284Sminshall "@(#) Copyright (c) 1984-1987 Regents of the University of California.\n\
2530088Sminshall All rights reserved.\n";
26*36284Sminshall #endif /* not lint */
2730088Sminshall
2830088Sminshall #ifndef lint
29*36284Sminshall static char sccsid[] = "@(#)telnet.c 1.18.1.1 (Berkeley) 12/04/88";
30*36284Sminshall #endif /* not lint */
3130088Sminshall
3230088Sminshall /*
3330088Sminshall * User telnet program, modified for use by tn3270.c.
3430088Sminshall *
3530088Sminshall * Many of the FUNCTIONAL changes in this newest version of TELNET
3630088Sminshall * were suggested by Dave Borman of Cray Research, Inc.
3730088Sminshall *
3830088Sminshall * Other changes in the tn3270 side come from Alan Crosswell (Columbia),
3930088Sminshall * Bob Braden (ISI), Steve Jacobson (Berkeley), and Cliff Frost (Berkeley).
4030088Sminshall *
4130088Sminshall * This code is common between telnet(1c) and tn3270(1c). There are the
4230088Sminshall * following defines used to generate the various versions:
4330088Sminshall *
4430088Sminshall * TN3270 - This is to be linked with tn3270.
4530088Sminshall *
4630088Sminshall * NOT43 - Allows the program to compile and run on
4730088Sminshall * a 4.2BSD system.
4830088Sminshall *
4930088Sminshall * PUTCHAR - Within tn3270, on a NOT43 system,
5030088Sminshall * allows the use of the 4.3 curses
5130088Sminshall * (greater speed updating the screen).
5230088Sminshall * You need the 4.3 curses for this to work.
5330088Sminshall *
5430088Sminshall * FD_SETSIZE - On whichever system, if this isn't defined,
5530088Sminshall * we patch over the FD_SET, etc., macros with
5630088Sminshall * some homebrewed ones.
5730088Sminshall *
5830088Sminshall * SO_OOBINLINE - This is a socket option which we would like
5930088Sminshall * to set to allow TCP urgent data to come
6030088Sminshall * to us "inline". This is NECESSARY for
6130088Sminshall * CORRECT operation, and desireable for
6230088Sminshall * simpler operation.
6330088Sminshall *
6430088Sminshall * LNOFLSH - Detects the presence of the LNOFLSH bit
6530088Sminshall * in the tty structure.
6630088Sminshall *
6730088Sminshall * unix - Compiles in unix specific stuff.
6830088Sminshall *
6931131Sminshall * MSDOS - Compiles in MSDOS specific stuff.
7030088Sminshall *
7130088Sminshall */
7230088Sminshall
7330088Sminshall #if !defined(TN3270)
7430088Sminshall #define ExitString(f,s,r) { fprintf(f, s); exit(r); }
7530088Sminshall #define Exit(x) exit(x)
7630088Sminshall #define SetIn3270()
7730088Sminshall
7830088Sminshall void setcommandmode(), command(); /* forward declarations */
7930088Sminshall #endif /* !defined(TN3270) */
8030088Sminshall
8130088Sminshall #include <sys/types.h>
8230088Sminshall #include <sys/socket.h>
8330088Sminshall
8430088Sminshall #include <netinet/in.h>
8530088Sminshall
8631124Sminshall #if defined(unix)
8731124Sminshall /* By the way, we need to include curses.h before telnet.h since,
8831124Sminshall * among other things, telnet.h #defines 'DO', which is a variable
8931124Sminshall * declared in curses.h.
9031124Sminshall */
9130088Sminshall #include <curses.h>
9231124Sminshall #endif /* defined(unix) */
9330088Sminshall
9430088Sminshall #define TELOPTS
9530088Sminshall #include <arpa/telnet.h>
9630088Sminshall
9730088Sminshall #if !defined(NOT43)
9830088Sminshall #include <arpa/inet.h>
9930088Sminshall #else /* !defined(NOT43) */
10030088Sminshall extern unsigned long inet_addr();
10130088Sminshall extern char *inet_ntoa();
10230088Sminshall #endif /* !defined(NOT43) */
10330088Sminshall
10430088Sminshall #include <stdio.h>
10530088Sminshall #include <ctype.h>
10630088Sminshall #include <errno.h>
10730088Sminshall #include <setjmp.h>
10830088Sminshall #include <netdb.h>
10931124Sminshall
11031124Sminshall #if defined(unix)
11130088Sminshall #include <strings.h>
11231124Sminshall #else /* defined(unix) */
11331124Sminshall #include <string.h>
11431124Sminshall #endif /* defined(unix) */
11530088Sminshall
11630088Sminshall #if defined(TN3270)
11731215Sminshall #include "ascii/termin.ext"
11830088Sminshall #include "ctlr/screen.h"
11931215Sminshall #include "ctlr/oia.h"
12031215Sminshall #include "ctlr/options.ext"
12131215Sminshall #include "ctlr/outbound.ext"
12231187Sminshall #include "general/globals.h"
12330088Sminshall #include "telnet.ext"
12431131Sminshall #endif /* defined(TN3270) */
12531215Sminshall
12631187Sminshall #include "general/general.h"
12730088Sminshall
12830088Sminshall
12930088Sminshall
13030088Sminshall #ifndef FD_SETSIZE
13130088Sminshall /*
13230088Sminshall * The following is defined just in case someone should want to run
13330088Sminshall * this telnet on a 4.2 system.
13430088Sminshall *
13530088Sminshall */
13630088Sminshall
13730088Sminshall #define FD_SET(n, p) ((p)->fds_bits[0] |= (1<<(n)))
13830088Sminshall #define FD_CLR(n, p) ((p)->fds_bits[0] &= ~(1<<(n)))
13930088Sminshall #define FD_ISSET(n, p) ((p)->fds_bits[0] & (1<<(n)))
14030088Sminshall #define FD_ZERO(p) ((p)->fds_bits[0] = 0)
14130088Sminshall
14230088Sminshall #endif
14330088Sminshall
14430088Sminshall #define strip(x) ((x)&0x7f)
14530088Sminshall #define min(x,y) ((x<y)? x:y)
14630088Sminshall
14730088Sminshall #if defined(TN3270)
14830326Sminshall static char Ibuf[8*BUFSIZ], *Ifrontp, *Ibackp;
14930088Sminshall #endif /* defined(TN3270) */
15030088Sminshall
15130326Sminshall static char ttyobuf[2*BUFSIZ], *tfrontp, *tbackp;
15230088Sminshall #define TTYADD(c) { if (!(SYNCHing||flushout)) { *tfrontp++ = c; } }
15330088Sminshall #define TTYLOC() (tfrontp)
15430088Sminshall #define TTYMAX() (ttyobuf+sizeof ttyobuf-1)
15530088Sminshall #define TTYMIN() (netobuf)
15630088Sminshall #define TTYBYTES() (tfrontp-tbackp)
15730088Sminshall #define TTYROOM() (TTYMAX()-TTYLOC()+1)
15830088Sminshall
15930326Sminshall static char netobuf[2*BUFSIZ], *nfrontp, *nbackp;
16030088Sminshall #define NETADD(c) { *nfrontp++ = c; }
16130088Sminshall #define NET2ADD(c1,c2) { NETADD(c1); NETADD(c2); }
16230088Sminshall #define NETLOC() (nfrontp)
16330088Sminshall #define NETMAX() (netobuf+sizeof netobuf-1)
16430088Sminshall #define NETBYTES() (nfrontp-nbackp)
16530088Sminshall #define NETROOM() (NETMAX()-NETLOC()+1)
16630326Sminshall static char *neturg; /* one past last byte of urgent data */
16730088Sminshall
16830326Sminshall static char subbuffer[100],
16930326Sminshall *subpointer, *subend; /* buffer for sub-options */
17030088Sminshall #define SB_CLEAR() subpointer = subbuffer;
17130088Sminshall #define SB_TERM() subend = subpointer;
17230088Sminshall #define SB_ACCUM(c) if (subpointer < (subbuffer+sizeof subbuffer)) { \
17330088Sminshall *subpointer++ = (c); \
17430088Sminshall }
17530088Sminshall
17630088Sminshall static char sb_terminal[] = { IAC, SB,
17730088Sminshall TELOPT_TTYPE, TELQUAL_IS,
17830088Sminshall 'I', 'B', 'M', '-', '3', '2', '7', '8', '-', '2',
17930088Sminshall IAC, SE };
18030088Sminshall #define SBTERMMODEL 13
18130088Sminshall
18230088Sminshall
18330326Sminshall static char hisopts[256];
18430326Sminshall static char myopts[256];
18530088Sminshall
18630088Sminshall static char doopt[] = { IAC, DO, '%', 'c', 0 };
18730088Sminshall static char dont[] = { IAC, DONT, '%', 'c', 0 };
18830088Sminshall static char will[] = { IAC, WILL, '%', 'c', 0 };
18930088Sminshall static char wont[] = { IAC, WONT, '%', 'c', 0 };
19030088Sminshall
19130088Sminshall struct cmd {
19230088Sminshall char *name; /* command name */
19330088Sminshall char *help; /* help string */
19430088Sminshall int (*handler)(); /* routine which executes command */
19530088Sminshall int dohelp; /* Should we give general help information? */
19630088Sminshall int needconnect; /* Do we need to be connected to execute? */
19730088Sminshall };
19830088Sminshall
19930326Sminshall static char sibuf[BUFSIZ], *sbp;
20030088Sminshall static char tibuf[BUFSIZ], *tbp;
20130088Sminshall static fd_set ibits, obits, xbits;
20230088Sminshall
20330088Sminshall
20430088Sminshall static int
20530326Sminshall connected,
20630326Sminshall net,
20730326Sminshall scc,
20830326Sminshall tcc,
20930326Sminshall showoptions,
21030326Sminshall In3270, /* Are we in 3270 mode? */
21130326Sminshall ISend, /* trying to send network data in */
21230088Sminshall debug = 0,
21330326Sminshall crmod,
214*36284Sminshall netdata,
21531478Sminshall noasynch = 0, /* User specified "-noasynch" on command line */
21630722Sminshall askedSGA = 0, /* We have talked about suppress go ahead */
21730088Sminshall telnetport = 1;
21830088Sminshall
21930326Sminshall static FILE *NetTrace = 0; /* Not in bss, since needs to stay */
22030088Sminshall
22130088Sminshall #define CONTROL(x) ((x)&0x1f) /* CTRL(x) is not portable */
22230088Sminshall
22330088Sminshall static char
22430088Sminshall *prompt = 0,
22530326Sminshall escape,
22630326Sminshall echoc;
22730088Sminshall
22830088Sminshall static int
22930326Sminshall SYNCHing, /* we are in TELNET SYNCH mode */
23030326Sminshall flushout, /* flush output */
23130088Sminshall autoflush = 0, /* flush output when interrupting? */
23230326Sminshall autosynch, /* send interrupt characters with SYNCH? */
23330326Sminshall localchars, /* we recognize interrupt/quit */
23431791Sminshall donelclchars, /* the user has set "localchars" */
23531791Sminshall donebinarytoggle, /* the user has put us in binary */
23631124Sminshall dontlecho, /* do we suppress local echoing right now? */
23731124Sminshall globalmode;
23830088Sminshall
23930088Sminshall /* The following are some tn3270 specific flags */
24030088Sminshall #if defined(TN3270)
24130088Sminshall
24230088Sminshall static int
24330326Sminshall Sent3270TerminalType; /* Have we said we are a 3270? */
24430088Sminshall
24531131Sminshall /* Some real, live, globals. */
24631131Sminshall int
24731131Sminshall tout, /* Output file descriptor */
24831131Sminshall tin; /* Input file descriptor */
24931131Sminshall
25031131Sminshall #else /* defined(TN3270) */
25131131Sminshall static int tin, tout; /* file descriptors */
25231131Sminshall #endif /* defined(TN3270) */
25331131Sminshall
25431131Sminshall
25530722Sminshall /*
25630722Sminshall * Telnet receiver states for fsm
25730722Sminshall */
25830722Sminshall #define TS_DATA 0
25930722Sminshall #define TS_IAC 1
26030722Sminshall #define TS_WILL 2
26130722Sminshall #define TS_WONT 3
26230722Sminshall #define TS_DO 4
26330722Sminshall #define TS_DONT 5
26430722Sminshall #define TS_CR 6
26530722Sminshall #define TS_SB 7 /* sub-option collection */
26630722Sminshall #define TS_SE 8 /* looking for sub-option end */
26730722Sminshall
26830722Sminshall static int telrcv_state = TS_DATA;
26930088Sminshall
27030088Sminshall static char line[200];
27130326Sminshall static int margc;
27230088Sminshall static char *margv[20];
27330088Sminshall
27431124Sminshall static jmp_buf toplevel = { 0 };
27530088Sminshall static jmp_buf peerdied;
27630088Sminshall
27730088Sminshall extern int errno;
27830088Sminshall
27930088Sminshall
28030088Sminshall static struct sockaddr_in sin;
28130088Sminshall
28230088Sminshall static struct servent *sp = 0;
28330088Sminshall
28430326Sminshall static int flushline;
28530088Sminshall
28630326Sminshall static char *hostname;
28730088Sminshall static char hnamebuf[32];
28830088Sminshall
28930088Sminshall /*
29030088Sminshall * The following are some clocks used to decide how to interpret
29130088Sminshall * the relationship between various variables.
29230088Sminshall */
29330088Sminshall
29430088Sminshall static struct {
29530088Sminshall int
29630088Sminshall system, /* what the current time is */
29730088Sminshall echotoggle, /* last time user entered echo character */
29830088Sminshall modenegotiated, /* last time operating mode negotiated */
29930088Sminshall didnetreceive, /* last time we read data from network */
30030088Sminshall gotDM; /* when did we last see a data mark */
30130326Sminshall } clocks;
30230088Sminshall
30330088Sminshall #define settimer(x) clocks.x = clocks.system++
30430088Sminshall
30531124Sminshall /* Various modes */
30631124Sminshall #define MODE_LINE(m) (modelist[m].modetype & LINE)
30731124Sminshall #define MODE_LOCAL_CHARS(m) (modelist[m].modetype & LOCAL_CHARS)
30831131Sminshall #define MODE_LOCAL_ECHO(m) (modelist[m].modetype & LOCAL_ECHO)
30931131Sminshall #define MODE_COMMAND_LINE(m) (modelist[m].modetype & COMMAND_LINE)
31031124Sminshall
31131124Sminshall #define LOCAL_CHARS 0x01 /* Characters processed locally */
31231124Sminshall #define LINE 0x02 /* Line-by-line mode of operation */
31331131Sminshall #define LOCAL_ECHO 0x04 /* Echoing locally */
31431131Sminshall #define COMMAND_LINE 0x08 /* Command line mode */
31531124Sminshall
31631124Sminshall static struct {
31731124Sminshall char *modedescriptions;
31831124Sminshall char modetype;
31931124Sminshall } modelist[] = {
32031131Sminshall { "telnet command mode", COMMAND_LINE },
32131124Sminshall { "character-at-a-time mode", 0 },
32231131Sminshall { "character-at-a-time mode (local echo)", LOCAL_ECHO|LOCAL_CHARS },
32331124Sminshall { "line-by-line mode (remote echo)", LINE | LOCAL_CHARS },
32431131Sminshall { "line-by-line mode", LINE | LOCAL_ECHO | LOCAL_CHARS },
32531124Sminshall { "line-by-line mode (local echoing suppressed)", LINE | LOCAL_CHARS },
32631124Sminshall { "3270 mode", 0 },
32731124Sminshall };
32831124Sminshall
32931124Sminshall
33030088Sminshall /*
33131124Sminshall * The following routines try to encapsulate what is system dependent
33231124Sminshall * (at least between 4.x and dos) which is used in telnet.c.
33331124Sminshall */
33431124Sminshall
33531124Sminshall #if defined(unix)
33631124Sminshall #include <sys/ioctl.h>
33731124Sminshall #include <sys/time.h>
33831124Sminshall #include <signal.h>
33931124Sminshall
34031124Sminshall int
34131124Sminshall HaveInput; /* There is input available to scan */
34231124Sminshall
34331124Sminshall #if defined(TN3270)
34431124Sminshall static char tline[200];
34531124Sminshall char *transcom = 0; /* transparent mode command (default: none) */
34631124Sminshall #endif /* defined(TN3270) */
34731124Sminshall
34831124Sminshall static struct tchars otc = { 0 }, ntc = { 0 };
34931124Sminshall static struct ltchars oltc = { 0 }, nltc = { 0 };
35031124Sminshall static struct sgttyb ottyb = { 0 }, nttyb = { 0 };
35131124Sminshall
35231124Sminshall
35331131Sminshall #define TerminalWrite(fd,buf,n) write(fd,buf,n)
35431131Sminshall #define TerminalRead(fd,buf,n) read(fd,buf,n)
35531131Sminshall
35631124Sminshall /*
35731124Sminshall *
35831124Sminshall */
35931124Sminshall
36031124Sminshall static int
TerminalAutoFlush()36131131Sminshall TerminalAutoFlush() /* unix */
36231124Sminshall {
36331124Sminshall #if defined(LNOFLSH)
36431124Sminshall ioctl(0, TIOCLGET, (char *)&autoflush);
36531124Sminshall return !(autoflush&LNOFLSH); /* if LNOFLSH, no autoflush */
36631124Sminshall #else /* LNOFLSH */
36731124Sminshall return 1;
36831124Sminshall #endif /* LNOFLSH */
36931124Sminshall }
37031124Sminshall
37131124Sminshall /*
37231131Sminshall * TerminalSpecialChars()
37331124Sminshall *
37431131Sminshall * Look at an input character to see if it is a special character
37531131Sminshall * and decide what to do.
37631124Sminshall *
37731124Sminshall * Output:
37831124Sminshall *
37931124Sminshall * 0 Don't add this character.
38031124Sminshall * 1 Do add this character
38131124Sminshall */
38231124Sminshall
38331124Sminshall int
TerminalSpecialChars(c)38431131Sminshall TerminalSpecialChars(c) /* unix */
38531124Sminshall int c;
38631124Sminshall {
38731124Sminshall void doflush(), intp(), sendbrk();
38831124Sminshall
38931124Sminshall if (c == ntc.t_intrc) {
39031124Sminshall intp();
39131124Sminshall return 0;
39231124Sminshall } else if (c == ntc.t_quitc) {
39331124Sminshall sendbrk();
39431124Sminshall return 0;
39531124Sminshall } else if (c == nltc.t_flushc) {
39631124Sminshall NET2ADD(IAC, AO);
39731124Sminshall if (autoflush) {
39831124Sminshall doflush();
39931124Sminshall }
40031124Sminshall return 0;
40131124Sminshall } else if (!MODE_LOCAL_CHARS(globalmode)) {
40231124Sminshall if (c == nttyb.sg_kill) {
40331124Sminshall NET2ADD(IAC, EL);
40431124Sminshall return 0;
40531124Sminshall } else if (c == nttyb.sg_erase) {
40631124Sminshall NET2ADD(IAC, EC);
40731124Sminshall return 0;
40831124Sminshall }
40931124Sminshall }
41031124Sminshall return 1;
41131124Sminshall }
41231124Sminshall
41331124Sminshall
41431124Sminshall /*
41531124Sminshall * Flush output to the terminal
41631124Sminshall */
41731124Sminshall
41831124Sminshall static void
TerminalFlushOutput()41931124Sminshall TerminalFlushOutput() /* unix */
42031124Sminshall {
42131124Sminshall (void) ioctl(fileno(stdout), TIOCFLUSH, (char *) 0);
42231124Sminshall }
42331124Sminshall
42431124Sminshall static void
TerminalSaveState()42531124Sminshall TerminalSaveState() /* unix */
42631124Sminshall {
42731124Sminshall ioctl(0, TIOCGETP, (char *)&ottyb);
42831124Sminshall ioctl(0, TIOCGETC, (char *)&otc);
42931124Sminshall ioctl(0, TIOCGLTC, (char *)&oltc);
43031124Sminshall
43131124Sminshall ntc = otc;
43231124Sminshall nltc = oltc;
43331124Sminshall nttyb = ottyb;
43431124Sminshall }
43531124Sminshall
43631124Sminshall static void
TerminalRestoreState()43731124Sminshall TerminalRestoreState() /* unix */
43831124Sminshall {
43931124Sminshall }
44031124Sminshall
44131124Sminshall /*
44231124Sminshall * TerminalNewMode - set up terminal to a specific mode.
44331124Sminshall */
44431124Sminshall
44531124Sminshall
44631124Sminshall static void
TerminalNewMode(f)44731131Sminshall TerminalNewMode(f) /* unix */
44831124Sminshall register int f;
44931124Sminshall {
45031124Sminshall static int prevmode = 0;
45131124Sminshall struct tchars *tc;
45231124Sminshall struct tchars tc3;
45331124Sminshall struct ltchars *ltc;
45431124Sminshall struct sgttyb sb;
45531124Sminshall int onoff;
45631124Sminshall int old;
45731124Sminshall struct tchars notc2;
45831124Sminshall struct ltchars noltc2;
45931124Sminshall static struct tchars notc = { -1, -1, -1, -1, -1, -1 };
46031124Sminshall static struct ltchars noltc = { -1, -1, -1, -1, -1, -1 };
46131124Sminshall
46231124Sminshall globalmode = f;
46331124Sminshall if (prevmode == f)
46431124Sminshall return;
46531124Sminshall old = prevmode;
46631124Sminshall prevmode = f;
46731124Sminshall sb = nttyb;
46831124Sminshall
46931124Sminshall switch (f) {
47031124Sminshall
47131124Sminshall case 0:
47231124Sminshall onoff = 0;
47331124Sminshall tc = &otc;
47431124Sminshall ltc = &oltc;
47531124Sminshall break;
47631124Sminshall
47731124Sminshall case 1: /* remote character processing, remote echo */
47831124Sminshall case 2: /* remote character processing, local echo */
47931124Sminshall case 6: /* 3270 mode - like 1, but with xon/xoff local */
48031124Sminshall /* (might be nice to have "6" in telnet also...) */
48131124Sminshall sb.sg_flags |= CBREAK;
48231124Sminshall if ((f == 1) || (f == 6)) {
48331124Sminshall sb.sg_flags &= ~(ECHO|CRMOD);
48431124Sminshall } else {
48531124Sminshall sb.sg_flags |= ECHO|CRMOD;
48631124Sminshall }
48731124Sminshall sb.sg_erase = sb.sg_kill = -1;
48831124Sminshall if (f == 6) {
48931124Sminshall tc = &tc3;
49031124Sminshall tc3 = notc;
49131124Sminshall /* get XON, XOFF characters */
49231124Sminshall tc3.t_startc = otc.t_startc;
49331124Sminshall tc3.t_stopc = otc.t_stopc;
49431124Sminshall } else {
49531124Sminshall /*
49631124Sminshall * If user hasn't specified one way or the other,
49731124Sminshall * then default to not trapping signals.
49831124Sminshall */
49931124Sminshall if (!donelclchars) {
50031124Sminshall localchars = 0;
50131124Sminshall }
50231124Sminshall if (localchars) {
50331124Sminshall notc2 = notc;
50431124Sminshall notc2.t_intrc = ntc.t_intrc;
50531124Sminshall notc2.t_quitc = ntc.t_quitc;
50631124Sminshall tc = ¬c2;
50731124Sminshall } else {
50831124Sminshall tc = ¬c;
50931124Sminshall }
51031124Sminshall }
51131124Sminshall ltc = &noltc;
51231124Sminshall onoff = 1;
51331124Sminshall break;
51431124Sminshall case 3: /* local character processing, remote echo */
51531124Sminshall case 4: /* local character processing, local echo */
51631124Sminshall case 5: /* local character processing, no echo */
51731124Sminshall sb.sg_flags &= ~CBREAK;
51831124Sminshall sb.sg_flags |= CRMOD;
51931124Sminshall if (f == 4)
52031124Sminshall sb.sg_flags |= ECHO;
52131124Sminshall else
52231124Sminshall sb.sg_flags &= ~ECHO;
52331124Sminshall notc2 = ntc;
52431124Sminshall tc = ¬c2;
52531124Sminshall noltc2 = oltc;
52631124Sminshall ltc = &noltc2;
52731124Sminshall /*
52831124Sminshall * If user hasn't specified one way or the other,
52931124Sminshall * then default to trapping signals.
53031124Sminshall */
53131124Sminshall if (!donelclchars) {
53231124Sminshall localchars = 1;
53331124Sminshall }
53431124Sminshall if (localchars) {
53531124Sminshall notc2.t_brkc = nltc.t_flushc;
53631124Sminshall noltc2.t_flushc = -1;
53731124Sminshall } else {
53831124Sminshall notc2.t_intrc = notc2.t_quitc = -1;
53931124Sminshall }
54031124Sminshall noltc2.t_suspc = escape;
54131124Sminshall noltc2.t_dsuspc = -1;
54231124Sminshall onoff = 1;
54331124Sminshall break;
54431124Sminshall
54531124Sminshall default:
54631124Sminshall return;
54731124Sminshall }
54831124Sminshall ioctl(tin, TIOCSLTC, (char *)ltc);
54931124Sminshall ioctl(tin, TIOCSETC, (char *)tc);
55031124Sminshall ioctl(tin, TIOCSETP, (char *)&sb);
55131124Sminshall #if (!defined(TN3270)) || ((!defined(NOT43)) || defined(PUTCHAR))
55231124Sminshall ioctl(tin, FIONBIO, (char *)&onoff);
55331124Sminshall ioctl(tout, FIONBIO, (char *)&onoff);
55431124Sminshall #endif /* (!defined(TN3270)) || ((!defined(NOT43)) || defined(PUTCHAR)) */
55531478Sminshall #if defined(TN3270)
55631478Sminshall if (noasynch == 0) {
55731478Sminshall ioctl(tin, FIOASYNC, (char *)&onoff);
55831478Sminshall }
55931478Sminshall #endif /* defined(TN3270) */
56031124Sminshall
56131124Sminshall if (MODE_LINE(f)) {
56231124Sminshall void doescape();
56331124Sminshall
56431124Sminshall signal(SIGTSTP, doescape);
56531124Sminshall } else if (MODE_LINE(old)) {
56631124Sminshall signal(SIGTSTP, SIG_DFL);
56731124Sminshall sigsetmask(sigblock(0) & ~(1<<(SIGTSTP-1)));
56831124Sminshall }
56931124Sminshall }
57031124Sminshall
57131124Sminshall
57231131Sminshall int
NetClose(net)57331131Sminshall NetClose(net)
57431131Sminshall int net;
57531131Sminshall {
57631131Sminshall return close(net);
57731131Sminshall }
57831131Sminshall
57931131Sminshall
58031124Sminshall static void
NetNonblockingIO(fd,onoff)58131124Sminshall NetNonblockingIO(fd, onoff) /* unix */
58231124Sminshall int
58331124Sminshall fd,
58431124Sminshall onoff;
58531124Sminshall {
58631124Sminshall ioctl(net, FIONBIO, (char *)&onoff);
58731124Sminshall }
58831124Sminshall
58931124Sminshall static void
NetSigIO(fd,onoff)59031124Sminshall NetSigIO(fd, onoff) /* unix */
59131124Sminshall int
59231124Sminshall fd,
59331124Sminshall onoff;
59431124Sminshall {
59531124Sminshall ioctl(net, FIOASYNC, (char *)&onoff); /* hear about input */
59631124Sminshall }
59731124Sminshall
59831124Sminshall static void
NetSetPgrp(fd)59931124Sminshall NetSetPgrp(fd) /* unix */
60031124Sminshall int fd;
60131124Sminshall {
60231124Sminshall int myPid;
60331124Sminshall
60431124Sminshall myPid = getpid();
60531124Sminshall #if defined(NOT43)
60631124Sminshall myPid = -myPid;
60731124Sminshall #endif /* defined(NOT43) */
60831124Sminshall ioctl(net, SIOCSPGRP, (char *)&myPid); /* set my pid */
60931124Sminshall }
61031124Sminshall
61131124Sminshall
61231124Sminshall #endif /* defined(unix) */
61331124Sminshall
61431124Sminshall #if defined(MSDOS)
61531124Sminshall #include <time.h>
61631131Sminshall #include <signal.h>
61731169Sminshall #include <process.h>
61831980Sminshall #include <fcntl.h>
61931980Sminshall #include <io.h>
62031978Sminshall #include <dos.h>
62131978Sminshall
62231124Sminshall #if !defined(SO_OOBINLINE)
62331124Sminshall #define SO_OOBINLINE
62431124Sminshall #endif /* !defined(SO_OOBINLINE) */
62531124Sminshall
62631124Sminshall
62731124Sminshall static char
62831131Sminshall termEofChar,
62931124Sminshall termEraseChar,
63031124Sminshall termFlushChar,
63131124Sminshall termIntChar,
63231124Sminshall termKillChar,
63331131Sminshall termLiteralNextChar,
63431131Sminshall termQuitChar;
63531124Sminshall
63631131Sminshall
63731131Sminshall /*
63831131Sminshall * MSDOS doesn't have anyway of deciding whether a full-edited line
63931131Sminshall * is ready to be read in, so we need to do character-by-character
64031131Sminshall * reads, and then do the editing in the program (in the case where
64131131Sminshall * we are supporting line-by-line mode).
64231131Sminshall *
64331131Sminshall * The following routines, which are internal to the MSDOS-specific
64431131Sminshall * code, accomplish this miracle.
64531131Sminshall */
64631124Sminshall
64731131Sminshall #define Hex(c) HEX[(c)&0xff]
64831131Sminshall
64931131Sminshall static survivorSetup = 0; /* Do we have ^C hooks in? */
65031131Sminshall
65131131Sminshall static int
65231131Sminshall lineend = 0, /* There is a line terminator */
65331131Sminshall ctrlCCount = 0;
65431131Sminshall
65531131Sminshall static char linein[200], /* Where input line is assembled */
65631131Sminshall *nextin = linein, /* Next input character */
65731131Sminshall *nextout = linein; /* Next character to be consumed */
65831131Sminshall
65931131Sminshall #define consumechar() \
66031131Sminshall if ((++nextout) >= nextin) { \
66131131Sminshall nextout = nextin = linein; \
66231131Sminshall lineend = 0; \
66331131Sminshall }
66431131Sminshall
66531131Sminshall #define characteratatime() (!MODE_LINE(globalmode)) /* one by one */
66631131Sminshall
66731131Sminshall
66831124Sminshall /*
66931131Sminshall * killone()
67031131Sminshall *
67131131Sminshall * Erase the last character on the line.
67231131Sminshall */
67331131Sminshall
67431131Sminshall static void
killone()67531131Sminshall killone()
67631131Sminshall {
67731131Sminshall if (lineend) {
67831131Sminshall return; /* ??? XXX */
67931131Sminshall }
68031131Sminshall if (nextin == linein) {
68131131Sminshall return; /* Nothing to do */
68231131Sminshall }
68331131Sminshall nextin--;
68431131Sminshall if (!(isspace(*nextin) || isprint(*nextin))) {
68531131Sminshall putchar('\b');
68631131Sminshall putchar(' ');
68731131Sminshall putchar('\b');
68831131Sminshall }
68931131Sminshall putchar('\b');
69031131Sminshall putchar(' ');
69131131Sminshall putchar('\b');
69231131Sminshall }
69331131Sminshall
69431131Sminshall
69531131Sminshall /*
69631131Sminshall * setlineend()
69731131Sminshall *
69831131Sminshall * Decide if it's time to send the current line up to the user
69931131Sminshall * process.
70031131Sminshall */
70131131Sminshall
70231131Sminshall static void
setlineend()70331131Sminshall setlineend()
70431131Sminshall {
70531131Sminshall if (nextin == nextout) {
70631131Sminshall return;
70731131Sminshall }
70831131Sminshall if (characteratatime()) {
70931131Sminshall lineend = 1;
71031131Sminshall } else if (nextin >= (linein+sizeof linein)) {
71131131Sminshall lineend = 1;
71231131Sminshall } else {
71331131Sminshall int c = *(nextin-1);
71431131Sminshall if ((c == termIntChar)
71531131Sminshall || (c == termQuitChar)
71631131Sminshall || (c == termEofChar)) {
71731131Sminshall lineend = 1;
71831131Sminshall } else if (c == termFlushChar) {
71931131Sminshall lineend = 1;
72031131Sminshall } else if ((c == '\n') || (c == '\r')) {
72131131Sminshall lineend = 1;
72231131Sminshall }
72331131Sminshall }
72431131Sminshall /* Otherwise, leave it alone (reset by 'consumechar') */
72531131Sminshall }
72631131Sminshall
72731131Sminshall /*
72831131Sminshall * OK, what we do here is:
72931131Sminshall *
73031131Sminshall * o If we are echoing, then
73131131Sminshall * o Look for character erase, line kill characters
73231131Sminshall * o Echo the character (using '^' if a control character)
73331131Sminshall * o Put the character in the input buffer
73431131Sminshall * o Set 'lineend' as necessary
73531131Sminshall */
73631131Sminshall
73731131Sminshall static void
DoNextChar(c)73831131Sminshall DoNextChar(c)
73931131Sminshall int c; /* Character to process */
74031131Sminshall {
74131131Sminshall static char literalnextcharacter = 0;
74231131Sminshall
74331131Sminshall if (nextin >= (linein+sizeof linein)) {
74431131Sminshall putchar('\7'); /* Ring bell */
74531131Sminshall setlineend();
74631131Sminshall return;
74731131Sminshall }
74831131Sminshall if (MODE_LOCAL_CHARS(globalmode)) {
74931131Sminshall /* Look for some special character */
75031131Sminshall if (!literalnextcharacter) {
75131131Sminshall if (c == termEraseChar) {
75231131Sminshall killone();
75331131Sminshall setlineend();
75431131Sminshall return;
75531131Sminshall } else if (c == termKillChar) {
75631131Sminshall while (nextin != linein) {
75731131Sminshall killone();
75831131Sminshall }
75931131Sminshall setlineend();
76031131Sminshall return;
76131131Sminshall } else if (c == termLiteralNextChar) {
76231131Sminshall literalnextcharacter = 1;
76331131Sminshall return;
76431131Sminshall }
76531131Sminshall }
76631131Sminshall
76731131Sminshall if (MODE_LOCAL_ECHO(globalmode)) {
76831131Sminshall if ((literalnextcharacter == 0) && ((c == '\r') || (c == '\n'))) {
76931131Sminshall putchar('\r');
77031131Sminshall putchar('\n');
77131131Sminshall c = '\n';
77231131Sminshall } else if (!isprint(c) && !isspace(c)) {
77331131Sminshall putchar('^');
77431131Sminshall putchar(c^0x40);
77531131Sminshall } else {
77631131Sminshall putchar(c);
77731131Sminshall }
77831131Sminshall }
77931131Sminshall literalnextcharacter = 0;
78031131Sminshall }
78131131Sminshall *nextin++ = c;
78231131Sminshall setlineend();
78331131Sminshall }
78431131Sminshall
78531131Sminshall static int
inputExists()78631131Sminshall inputExists()
78731131Sminshall {
78831131Sminshall int input;
78931131Sminshall static state = 0;
79031131Sminshall
79131131Sminshall while (ctrlCCount) {
79231131Sminshall DoNextChar(0x03);
79331131Sminshall ctrlCCount--;
79431131Sminshall }
79531131Sminshall if (lineend) {
79631131Sminshall return 1;
79731131Sminshall }
79831169Sminshall #if 1 /* For BIOS variety of calls */
79931169Sminshall if (kbhit() == 0) {
80031131Sminshall return lineend;
80131131Sminshall }
80231131Sminshall input = getch(); /* MSC - get console character */
80331131Sminshall if ((input&0xff) == 0) {
80431169Sminshall DoNextChar(0x01); /* ^A */
80531169Sminshall } else {
80631169Sminshall DoNextChar(input&0xff);
80731169Sminshall }
80831169Sminshall #else /* 0 */
80931169Sminshall if ((input = dirconio()) == -1) {
81031169Sminshall return lineend;
81131169Sminshall }
81231169Sminshall if ((input&0xff) == 0) {
81331131Sminshall if ((input&0xff00) == 0x0300) { /* Null */
81431131Sminshall DoNextChar(0);
81531131Sminshall } else {
81631131Sminshall DoNextChar(0x01);
81731131Sminshall if (input&0x8000) {
81831131Sminshall DoNextChar(0x01);
81931131Sminshall DoNextChar((input>>8)&0x7f);
82031131Sminshall } else {
82131131Sminshall DoNextChar((input>>8)&0xff);
82231131Sminshall }
82331131Sminshall }
82431131Sminshall } else {
82531131Sminshall DoNextChar(input&0xff);
82631131Sminshall }
82731131Sminshall #endif /* 0 */
82831131Sminshall return lineend;
82931131Sminshall }
83031131Sminshall
83131131Sminshall
83231131Sminshall void
CtrlCInterrupt()83331131Sminshall CtrlCInterrupt()
83431131Sminshall {
83531131Sminshall if (!MODE_COMMAND_LINE(globalmode)) {
83631131Sminshall ctrlCCount++; /* XXX */
83731131Sminshall signal(SIGINT, CtrlCInterrupt);
83831131Sminshall } else {
83931131Sminshall closeallsockets();
84031169Sminshall exit(1);
84131131Sminshall }
84231131Sminshall }
84331131Sminshall
84431131Sminshall /*
84531131Sminshall * The MSDOS routines, called from elsewhere.
84631131Sminshall */
84731131Sminshall
84831131Sminshall
84931131Sminshall static int
TerminalAutoFlush()85031131Sminshall TerminalAutoFlush() /* MSDOS */
85131131Sminshall {
85231131Sminshall return 1;
85331131Sminshall }
85431131Sminshall
85531131Sminshall static int
TerminalCanRead()85631131Sminshall TerminalCanRead()
85731131Sminshall {
85831131Sminshall return inputExists();
85931131Sminshall }
86031131Sminshall
86131131Sminshall
86231131Sminshall /*
86331124Sminshall * Flush output to the terminal
86431124Sminshall */
86531124Sminshall
86631124Sminshall static void
TerminalFlushOutput()86731124Sminshall TerminalFlushOutput() /* MSDOS */
86831124Sminshall {
86931124Sminshall }
87031124Sminshall
87131131Sminshall
87231124Sminshall static void
TerminalNewMode(f)87331131Sminshall TerminalNewMode(f) /* MSDOS */
87431131Sminshall register int f;
87531131Sminshall {
87631978Sminshall union REGS inregs;
87731978Sminshall struct SREGS segregs;
87831978Sminshall static old_1b_offset = 0, old_1b_segment = 0;
87931978Sminshall
88031131Sminshall globalmode = f;
88131978Sminshall if (MODE_COMMAND_LINE(f)) {
88231980Sminshall signal(SIGINT, SIG_DFL);
88331978Sminshall if (old_1b_segment|old_1b_offset) {
88431978Sminshall inregs.h.ah = 0x25;
88531978Sminshall inregs.h.al = 0x1b;
88631978Sminshall inregs.x.dx = old_1b_offset;
88731978Sminshall segregs.ds = old_1b_segment;
88831978Sminshall intdosx(&inregs, &inregs, &segregs);
88931978Sminshall old_1b_segment = old_1b_offset = 0;
89031978Sminshall }
89131980Sminshall if (setmode(fileno(stdout), O_TEXT) == -1) {
89231980Sminshall ExitPerror("setmode (text)", 1);
89331980Sminshall }
89431980Sminshall if (setmode(fileno(stdin), O_TEXT) == -1) {
89531980Sminshall ExitPerror("setmode (text)", 1);
89631980Sminshall }
89731978Sminshall } else {
89831980Sminshall signal(SIGINT, CtrlCInterrupt);
89931978Sminshall if ((old_1b_segment|old_1b_offset) == 0) {
90031978Sminshall extern void iret_subr();
90131978Sminshall void (far *foo_subr)() = iret_subr;
90231978Sminshall
90331978Sminshall inregs.h.ah = 0x35;
90431978Sminshall inregs.h.al = 0x1b;
90531978Sminshall intdosx(&inregs, &inregs, &segregs);
90631978Sminshall old_1b_segment = segregs.es;
90731978Sminshall old_1b_offset = inregs.x.bx;
90831978Sminshall inregs.h.ah = 0x25;
90931978Sminshall inregs.h.al = 0x1b;
91031978Sminshall inregs.x.dx = FP_OFF(foo_subr);
91131978Sminshall segregs.ds = FP_SEG(foo_subr);
91231978Sminshall intdosx(&inregs, &inregs, &segregs);
91331978Sminshall }
914*36284Sminshall if (setmode(fileno(stdout), O_BINARY) == -1) {
915*36284Sminshall ExitPerror("setmode (binary)", 1);
91631980Sminshall }
917*36284Sminshall if (setmode(fileno(stdin), O_BINARY) == -1) {
918*36284Sminshall ExitPerror("setmode (binary)", 1);
919*36284Sminshall }
92031978Sminshall }
92131131Sminshall }
92231131Sminshall
92331131Sminshall
92431131Sminshall int
TerminalRead(fd,buffer,count)92531131Sminshall TerminalRead(fd, buffer, count)
92631131Sminshall int fd;
92731131Sminshall char *buffer;
92831131Sminshall int count;
92931131Sminshall {
93031131Sminshall int done = 0;
93131131Sminshall
93231131Sminshall for (;;) {
93331131Sminshall while (inputExists() && (done < count)) {
93431131Sminshall *buffer++ = *nextout;
93531131Sminshall consumechar();
93631131Sminshall done++;
93731131Sminshall }
93831131Sminshall if (done) {
93931131Sminshall return(done);
94031131Sminshall } else {
94131131Sminshall return 0;
94231131Sminshall }
94331131Sminshall }
94431131Sminshall }
94531131Sminshall
94631131Sminshall
94731131Sminshall static void
TerminalSaveState()94831124Sminshall TerminalSaveState() /* MSDOS */
94931124Sminshall {
95031124Sminshall }
95131124Sminshall
95231131Sminshall int
TerminalSpecialChars(c)95331131Sminshall TerminalSpecialChars(c) /* MSDOS */
95431131Sminshall {
95531131Sminshall return 1;
95631131Sminshall }
95731131Sminshall
95831131Sminshall
95931124Sminshall static void
TerminalRestoreState()96031124Sminshall TerminalRestoreState() /* MSDOS */
96131124Sminshall {
96231124Sminshall }
96331124Sminshall
96431131Sminshall
96531131Sminshall static int
TerminalWrite(fd,buffer,count)96631131Sminshall TerminalWrite(fd, buffer, count) /* MSDOS */
96731131Sminshall int fd;
96831131Sminshall char *buffer;
96931131Sminshall int count;
97031131Sminshall {
97131131Sminshall return fwrite(buffer, sizeof (char), count, stdout);
97231131Sminshall }
97331131Sminshall
97431131Sminshall
97531131Sminshall static int
NetClose(fd)97631131Sminshall NetClose(fd)
97731131Sminshall {
97831131Sminshall return closesocket(fd);
97931131Sminshall }
98031131Sminshall
98131124Sminshall static void
NetNonblockingIO(fd,onoff)98231124Sminshall NetNonblockingIO(fd, onoff) /* MSDOS */
98331124Sminshall int
98431124Sminshall fd,
98531124Sminshall onoff;
98631124Sminshall {
98731124Sminshall if (SetSockOpt(net, SOL_SOCKET, SO_NONBLOCKING, onoff)) {
98831124Sminshall perror("setsockop (SO_NONBLOCKING) ");
98931131Sminshall ExitString(stderr, "exiting\n", 1);
99031124Sminshall }
99131124Sminshall }
99231124Sminshall
99331124Sminshall static void
NetSigIO(fd)99431124Sminshall NetSigIO(fd) /* MSDOS */
99531124Sminshall int fd;
99631124Sminshall {
99731124Sminshall }
99831124Sminshall
99931124Sminshall static void
NetSetPgrp(fd)100031124Sminshall NetSetPgrp(fd) /* MSDOS */
100131124Sminshall int fd;
100231124Sminshall {
100331124Sminshall }
100431124Sminshall
100531124Sminshall
100631124Sminshall #endif /* defined(MSDOS) */
100731124Sminshall
100831124Sminshall /*
100930326Sminshall * Initialize variables.
101030326Sminshall */
101130326Sminshall
101230326Sminshall static void
tninit()101330326Sminshall tninit()
101430326Sminshall {
101531131Sminshall #if defined(TN3270)
101631131Sminshall Sent3270TerminalType = 0;
101730326Sminshall Ifrontp = Ibackp = Ibuf;
101831131Sminshall #endif /* defined(TN3270) */
101931131Sminshall
102030326Sminshall tfrontp = tbackp = ttyobuf;
102130326Sminshall nfrontp = nbackp = netobuf;
102230326Sminshall
102330326Sminshall /* Don't change telnetport */
102430722Sminshall SB_CLEAR();
102530722Sminshall ClearArray(hisopts);
102630722Sminshall ClearArray(myopts);
102730722Sminshall sbp = sibuf;
102830722Sminshall tbp = tibuf;
102930326Sminshall
103031791Sminshall connected = net = scc = tcc = In3270 = ISend = donebinarytoggle = 0;
103130722Sminshall telnetport = 0;
103231124Sminshall #if defined(unix)
103331124Sminshall HaveInput = 0;
103431124Sminshall #endif /* defined(unix) */
103530722Sminshall
103630722Sminshall SYNCHing = 0;
103730722Sminshall
103830722Sminshall errno = 0;
103930722Sminshall
104030722Sminshall flushline = 0;
104130722Sminshall
104230326Sminshall /* Don't change NetTrace */
104330326Sminshall
104430326Sminshall escape = CONTROL(']');
104530326Sminshall echoc = CONTROL('E');
104630326Sminshall
104730326Sminshall flushline = 1;
104830326Sminshall sp = getservbyname("telnet", "tcp");
104930326Sminshall if (sp == 0) {
105030326Sminshall ExitString(stderr, "telnet: tcp/telnet: unknown service\n",1);
105130326Sminshall /*NOTREACHED*/
105230326Sminshall }
105330326Sminshall
105430326Sminshall #if defined(TN3270)
105530722Sminshall init_ctlr(); /* Initialize some things */
105630722Sminshall init_keyboard();
105730722Sminshall init_screen();
105830722Sminshall init_system();
105930326Sminshall #endif /* defined(TN3270) */
106030326Sminshall }
106130326Sminshall
106230326Sminshall /*
106330088Sminshall * Various utility routines.
106430088Sminshall */
106530088Sminshall
106630088Sminshall static void
makeargv()106730088Sminshall makeargv()
106830088Sminshall {
106931215Sminshall register char *cp;
107031215Sminshall register char **argp = margv;
107130088Sminshall
107231215Sminshall margc = 0;
107331215Sminshall cp = line;
107431215Sminshall if (*cp == '!') { /* Special case shell escape */
107531215Sminshall *argp++ = "!"; /* No room in string to get this */
107631215Sminshall margc++;
107731215Sminshall cp++;
107831215Sminshall }
107931215Sminshall while (*cp) {
108031215Sminshall while (isspace(*cp))
108131215Sminshall cp++;
108231215Sminshall if (*cp == '\0')
108331215Sminshall break;
108431215Sminshall *argp++ = cp;
108531215Sminshall margc += 1;
108631215Sminshall while (*cp != '\0' && !isspace(*cp))
108731215Sminshall cp++;
108831215Sminshall if (*cp == '\0')
108931215Sminshall break;
109031215Sminshall *cp++ = '\0';
109131215Sminshall }
109231215Sminshall *argp++ = 0;
109330088Sminshall }
109430088Sminshall
109530088Sminshall static char *ambiguous; /* special return value */
109630088Sminshall #define Ambiguous(t) ((t)&ambiguous)
109730088Sminshall
109830088Sminshall
109930088Sminshall static char **
genget(name,table,next)110030088Sminshall genget(name, table, next)
110130088Sminshall char *name; /* name to match */
110230088Sminshall char **table; /* name entry in table */
110330088Sminshall char **(*next)(); /* routine to return next entry in table */
110430088Sminshall {
110530088Sminshall register char *p, *q;
110630088Sminshall register char **c, **found;
110730088Sminshall register int nmatches, longest;
110830088Sminshall
110931793Sminshall if (name == 0) {
111031793Sminshall return 0;
111131793Sminshall }
111230088Sminshall longest = 0;
111330088Sminshall nmatches = 0;
111430088Sminshall found = 0;
111530088Sminshall for (c = table; (p = *c) != 0; c = (*next)(c)) {
111630088Sminshall for (q = name;
111730088Sminshall (*q == *p) || (isupper(*q) && tolower(*q) == *p); p++, q++)
111830088Sminshall if (*q == 0) /* exact match? */
111930088Sminshall return (c);
112030088Sminshall if (!*q) { /* the name was a prefix */
112130088Sminshall if (q - name > longest) {
112230088Sminshall longest = q - name;
112330088Sminshall nmatches = 1;
112430088Sminshall found = c;
112530088Sminshall } else if (q - name == longest)
112630088Sminshall nmatches++;
112730088Sminshall }
112830088Sminshall }
112930088Sminshall if (nmatches > 1)
113030088Sminshall return Ambiguous(char **);
113130088Sminshall return (found);
113230088Sminshall }
113330088Sminshall
113430088Sminshall /*
113530088Sminshall * Make a character string into a number.
113630088Sminshall *
113730088Sminshall * Todo: 1. Could take random integers (12, 0x12, 012, 0b1).
113830088Sminshall */
113930088Sminshall
114030088Sminshall static
special(s)114130088Sminshall special(s)
114230088Sminshall register char *s;
114330088Sminshall {
114430088Sminshall register char c;
114530088Sminshall char b;
114630088Sminshall
114730088Sminshall switch (*s) {
114830088Sminshall case '^':
114930088Sminshall b = *++s;
115030088Sminshall if (b == '?') {
115130088Sminshall c = b | 0x40; /* DEL */
115230088Sminshall } else {
115330088Sminshall c = b & 0x1f;
115430088Sminshall }
115530088Sminshall break;
115630088Sminshall default:
115730088Sminshall c = *s;
115830088Sminshall break;
115930088Sminshall }
116030088Sminshall return c;
116130088Sminshall }
116230088Sminshall
116330088Sminshall /*
116430088Sminshall * Construct a control character sequence
116530088Sminshall * for a special character.
116630088Sminshall */
116730088Sminshall static char *
control(c)116830088Sminshall control(c)
116930088Sminshall register int c;
117030088Sminshall {
117130088Sminshall static char buf[3];
117230088Sminshall
117330088Sminshall if (c == 0x7f)
117430088Sminshall return ("^?");
117530088Sminshall if (c == '\377') {
117630088Sminshall return "off";
117730088Sminshall }
117830088Sminshall if (c >= 0x20) {
117930088Sminshall buf[0] = c;
118030088Sminshall buf[1] = 0;
118130088Sminshall } else {
118230088Sminshall buf[0] = '^';
118330088Sminshall buf[1] = '@'+c;
118430088Sminshall buf[2] = 0;
118530088Sminshall }
118630088Sminshall return (buf);
118730088Sminshall }
118830088Sminshall
118930088Sminshall
119030088Sminshall /*
119130088Sminshall * upcase()
119230088Sminshall *
119330088Sminshall * Upcase (in place) the argument.
119430088Sminshall */
119530088Sminshall
119630088Sminshall static void
upcase(argument)119730088Sminshall upcase(argument)
119830088Sminshall register char *argument;
119930088Sminshall {
120030088Sminshall register int c;
120130088Sminshall
120230088Sminshall while ((c = *argument) != 0) {
120330088Sminshall if (islower(c)) {
120430088Sminshall *argument = toupper(c);
120530088Sminshall }
120630088Sminshall argument++;
120730088Sminshall }
120830088Sminshall }
120931124Sminshall
121031124Sminshall /*
121131124Sminshall * SetSockOpt()
121231124Sminshall *
121331124Sminshall * Compensate for differences in 4.2 and 4.3 systems.
121431124Sminshall */
121531124Sminshall
121631124Sminshall static int
SetSockOpt(fd,level,option,yesno)121731124Sminshall SetSockOpt(fd, level, option, yesno)
121831124Sminshall int
121931124Sminshall fd,
122031124Sminshall level,
122131124Sminshall option,
122231124Sminshall yesno;
122331124Sminshall {
122431124Sminshall #ifndef NOT43
122531124Sminshall return setsockopt(fd, level, option,
122631124Sminshall (char *)&yesno, sizeof yesno);
122731124Sminshall #else /* NOT43 */
122831124Sminshall if (yesno == 0) { /* Can't do that in 4.2! */
122931124Sminshall fprintf(stderr, "Error: attempt to turn off an option 0x%x.\n",
123031124Sminshall option);
123131124Sminshall return -1;
123231124Sminshall }
123331124Sminshall return setsockopt(fd, level, option, 0, 0);
123431124Sminshall #endif /* NOT43 */
123531124Sminshall }
123630088Sminshall
123730088Sminshall /*
123830088Sminshall * The following are routines used to print out debugging information.
123930088Sminshall */
124030088Sminshall
124130088Sminshall
124230088Sminshall static void
Dump(direction,buffer,length)124330088Sminshall Dump(direction, buffer, length)
124430088Sminshall char direction;
124530088Sminshall char *buffer;
124630088Sminshall int length;
124730088Sminshall {
124830088Sminshall # define BYTES_PER_LINE 32
124930088Sminshall # define min(x,y) ((x<y)? x:y)
125030088Sminshall char *pThis;
125130088Sminshall int offset;
125230088Sminshall
125330088Sminshall offset = 0;
125430088Sminshall
125530088Sminshall while (length) {
125630088Sminshall /* print one line */
125730088Sminshall fprintf(NetTrace, "%c 0x%x\t", direction, offset);
125830088Sminshall pThis = buffer;
125930088Sminshall buffer = buffer+min(length, BYTES_PER_LINE);
126030088Sminshall while (pThis < buffer) {
126130088Sminshall fprintf(NetTrace, "%.2x", (*pThis)&0xff);
126230088Sminshall pThis++;
126330088Sminshall }
126430088Sminshall fprintf(NetTrace, "\n");
126530088Sminshall length -= BYTES_PER_LINE;
126630088Sminshall offset += BYTES_PER_LINE;
126730088Sminshall if (length < 0) {
126830088Sminshall return;
126930088Sminshall }
127030088Sminshall /* find next unique line */
127130088Sminshall }
127230088Sminshall }
127330088Sminshall
127430088Sminshall
127530088Sminshall /*VARARGS*/
127630088Sminshall static void
printoption(direction,fmt,option,what)127730088Sminshall printoption(direction, fmt, option, what)
127830088Sminshall char *direction, *fmt;
127930088Sminshall int option, what;
128030088Sminshall {
128130088Sminshall if (!showoptions)
128230088Sminshall return;
128330088Sminshall fprintf(NetTrace, "%s ", direction+1);
128430088Sminshall if (fmt == doopt)
128530088Sminshall fmt = "do";
128630088Sminshall else if (fmt == dont)
128730088Sminshall fmt = "dont";
128830088Sminshall else if (fmt == will)
128930088Sminshall fmt = "will";
129030088Sminshall else if (fmt == wont)
129130088Sminshall fmt = "wont";
129230088Sminshall else
129330088Sminshall fmt = "???";
129430088Sminshall if (option < (sizeof telopts/sizeof telopts[0]))
129530088Sminshall fprintf(NetTrace, "%s %s", fmt, telopts[option]);
129630088Sminshall else
129730088Sminshall fprintf(NetTrace, "%s %d", fmt, option);
129830088Sminshall if (*direction == '<') {
129930088Sminshall fprintf(NetTrace, "\r\n");
130030088Sminshall return;
130130088Sminshall }
130230088Sminshall fprintf(NetTrace, " (%s)\r\n", what ? "reply" : "don't reply");
130330088Sminshall }
130430088Sminshall
130530088Sminshall static void
printsub(direction,pointer,length)130630088Sminshall printsub(direction, pointer, length)
130730088Sminshall char *direction, /* "<" or ">" */
130830088Sminshall *pointer; /* where suboption data sits */
130930088Sminshall int length; /* length of suboption data */
131030088Sminshall {
131130088Sminshall if (showoptions) {
131230088Sminshall fprintf(NetTrace, "%s suboption ",
131330088Sminshall (direction[0] == '<')? "Received":"Sent");
131430088Sminshall switch (pointer[0]) {
131530088Sminshall case TELOPT_TTYPE:
131630088Sminshall fprintf(NetTrace, "Terminal type ");
131730088Sminshall switch (pointer[1]) {
131830088Sminshall case TELQUAL_IS:
131930088Sminshall {
132030088Sminshall char tmpbuf[sizeof subbuffer];
1321*36284Sminshall int minlen = min(length, sizeof tmpbuf);
132230088Sminshall
132331131Sminshall memcpy(tmpbuf, pointer+2, minlen);
1324*36284Sminshall tmpbuf[minlen-1] = 0;
132530088Sminshall fprintf(NetTrace, "is %s.\n", tmpbuf);
132630088Sminshall }
132730088Sminshall break;
132830088Sminshall case TELQUAL_SEND:
132930088Sminshall fprintf(NetTrace, "- request to send.\n");
133030088Sminshall break;
133130088Sminshall default:
133230088Sminshall fprintf(NetTrace,
133330088Sminshall "- unknown qualifier %d (0x%x).\n", pointer[1]);
133430088Sminshall }
133530088Sminshall break;
133630088Sminshall default:
133730088Sminshall fprintf(NetTrace, "Unknown option %d (0x%x)\n",
133830088Sminshall pointer[0], pointer[0]);
133930088Sminshall }
134030088Sminshall }
134130088Sminshall }
134230088Sminshall
134330088Sminshall /*
134430088Sminshall * Check to see if any out-of-band data exists on a socket (for
134530088Sminshall * Telnet "synch" processing).
134630088Sminshall */
134730088Sminshall
134830088Sminshall static int
stilloob(s)134930088Sminshall stilloob(s)
135030088Sminshall int s; /* socket number */
135130088Sminshall {
135230088Sminshall static struct timeval timeout = { 0 };
135330088Sminshall fd_set excepts;
135430088Sminshall int value;
135530088Sminshall
135630088Sminshall do {
135730088Sminshall FD_ZERO(&excepts);
135830088Sminshall FD_SET(s, &excepts);
135930088Sminshall value = select(s+1, (fd_set *)0, (fd_set *)0, &excepts, &timeout);
136030088Sminshall } while ((value == -1) && (errno == EINTR));
136130088Sminshall
136230088Sminshall if (value < 0) {
136330088Sminshall perror("select");
136430088Sminshall quit();
136530088Sminshall }
136630088Sminshall if (FD_ISSET(s, &excepts)) {
136730088Sminshall return 1;
136830088Sminshall } else {
136930088Sminshall return 0;
137030088Sminshall }
137130088Sminshall }
137230088Sminshall
137330088Sminshall
137430088Sminshall /*
137530088Sminshall * netflush
137630088Sminshall * Send as much data as possible to the network,
137730088Sminshall * handling requests for urgent data.
137830088Sminshall *
137930088Sminshall * The return value indicates whether we did any
138030088Sminshall * useful work.
138130088Sminshall */
138230088Sminshall
138330088Sminshall
138430088Sminshall int
netflush()138530088Sminshall netflush()
138630088Sminshall {
138730088Sminshall int n;
138830088Sminshall
138930088Sminshall if ((n = nfrontp - nbackp) > 0) {
139030088Sminshall if (!neturg) {
139131131Sminshall n = send(net, nbackp, n, 0); /* normal write */
139230088Sminshall } else {
139330088Sminshall n = neturg - nbackp;
139430088Sminshall /*
139530088Sminshall * In 4.2 (and 4.3) systems, there is some question about
139630088Sminshall * what byte in a sendOOB operation is the "OOB" data.
139730088Sminshall * To make ourselves compatible, we only send ONE byte
139830088Sminshall * out of band, the one WE THINK should be OOB (though
139930088Sminshall * we really have more the TCP philosophy of urgent data
140030088Sminshall * rather than the Unix philosophy of OOB data).
140130088Sminshall */
140230088Sminshall if (n > 1) {
140330088Sminshall n = send(net, nbackp, n-1, 0); /* send URGENT all by itself */
140430088Sminshall } else {
140530088Sminshall n = send(net, nbackp, n, MSG_OOB); /* URGENT data */
140630088Sminshall }
140730088Sminshall }
140830088Sminshall }
140930088Sminshall if (n < 0) {
141030088Sminshall if (errno != ENOBUFS && errno != EWOULDBLOCK) {
141130088Sminshall setcommandmode();
141230088Sminshall perror(hostname);
141331131Sminshall NetClose(net);
141430088Sminshall neturg = 0;
141530088Sminshall longjmp(peerdied, -1);
141630088Sminshall /*NOTREACHED*/
141730088Sminshall }
141830088Sminshall n = 0;
141930088Sminshall }
142030088Sminshall if (netdata && n) {
142130088Sminshall Dump('>', nbackp, n);
142230088Sminshall }
142330088Sminshall nbackp += n;
142430088Sminshall if (nbackp >= neturg) {
142530088Sminshall neturg = 0;
142630088Sminshall }
142730088Sminshall if (nbackp == nfrontp) {
142830088Sminshall nbackp = nfrontp = netobuf;
142930088Sminshall }
143030088Sminshall return n > 0;
143130088Sminshall }
143230088Sminshall
143330088Sminshall /*
143430088Sminshall * nextitem()
143530088Sminshall *
143630088Sminshall * Return the address of the next "item" in the TELNET data
143730088Sminshall * stream. This will be the address of the next character if
143830088Sminshall * the current address is a user data character, or it will
143930088Sminshall * be the address of the character following the TELNET command
144030088Sminshall * if the current address is a TELNET IAC ("I Am a Command")
144130088Sminshall * character.
144230088Sminshall */
144330088Sminshall
144430088Sminshall static char *
nextitem(current)144530088Sminshall nextitem(current)
144630088Sminshall char *current;
144730088Sminshall {
144830088Sminshall if ((*current&0xff) != IAC) {
144930088Sminshall return current+1;
145030088Sminshall }
145130088Sminshall switch (*(current+1)&0xff) {
145230088Sminshall case DO:
145330088Sminshall case DONT:
145430088Sminshall case WILL:
145530088Sminshall case WONT:
145630088Sminshall return current+3;
145730088Sminshall case SB: /* loop forever looking for the SE */
145830088Sminshall {
145930088Sminshall register char *look = current+2;
146030088Sminshall
146130088Sminshall for (;;) {
146230088Sminshall if ((*look++&0xff) == IAC) {
146330088Sminshall if ((*look++&0xff) == SE) {
146430088Sminshall return look;
146530088Sminshall }
146630088Sminshall }
146730088Sminshall }
146830088Sminshall }
146930088Sminshall default:
147030088Sminshall return current+2;
147130088Sminshall }
147230088Sminshall }
147330088Sminshall /*
147430088Sminshall * netclear()
147530088Sminshall *
147630088Sminshall * We are about to do a TELNET SYNCH operation. Clear
147730088Sminshall * the path to the network.
147830088Sminshall *
147930088Sminshall * Things are a bit tricky since we may have sent the first
148030088Sminshall * byte or so of a previous TELNET command into the network.
148130088Sminshall * So, we have to scan the network buffer from the beginning
148230088Sminshall * until we are up to where we want to be.
148330088Sminshall *
148430088Sminshall * A side effect of what we do, just to keep things
148530088Sminshall * simple, is to clear the urgent data pointer. The principal
148630088Sminshall * caller should be setting the urgent data pointer AFTER calling
148730088Sminshall * us in any case.
148830088Sminshall */
148930088Sminshall
149030088Sminshall static void
netclear()149130088Sminshall netclear()
149230088Sminshall {
149330088Sminshall register char *thisitem, *next;
149430088Sminshall char *good;
149530088Sminshall #define wewant(p) ((nfrontp > p) && ((*p&0xff) == IAC) && \
149630088Sminshall ((*(p+1)&0xff) != EC) && ((*(p+1)&0xff) != EL))
149730088Sminshall
149830088Sminshall thisitem = netobuf;
149930088Sminshall
150030088Sminshall while ((next = nextitem(thisitem)) <= nbackp) {
150130088Sminshall thisitem = next;
150230088Sminshall }
150330088Sminshall
150430088Sminshall /* Now, thisitem is first before/at boundary. */
150530088Sminshall
150630088Sminshall good = netobuf; /* where the good bytes go */
150730088Sminshall
150830088Sminshall while (nfrontp > thisitem) {
150930088Sminshall if (wewant(thisitem)) {
151030088Sminshall int length;
151130088Sminshall
151230088Sminshall next = thisitem;
151330088Sminshall do {
151430088Sminshall next = nextitem(next);
151530088Sminshall } while (wewant(next) && (nfrontp > next));
151630088Sminshall length = next-thisitem;
151731131Sminshall memcpy(good, thisitem, length);
151830088Sminshall good += length;
151930088Sminshall thisitem = next;
152030088Sminshall } else {
152130088Sminshall thisitem = nextitem(thisitem);
152230088Sminshall }
152330088Sminshall }
152430088Sminshall
152530088Sminshall nbackp = netobuf;
152630088Sminshall nfrontp = good; /* next byte to be sent */
152730088Sminshall neturg = 0;
152830088Sminshall }
152930088Sminshall
153030088Sminshall /*
153130088Sminshall * These routines add various telnet commands to the data stream.
153230088Sminshall */
153330088Sminshall
153430088Sminshall #if defined(NOT43)
153530088Sminshall static int
153630088Sminshall #else /* defined(NOT43) */
153730088Sminshall static void
153830088Sminshall #endif /* defined(NOT43) */
dosynch()153930088Sminshall dosynch()
154030088Sminshall {
154130088Sminshall netclear(); /* clear the path to the network */
154230088Sminshall NET2ADD(IAC, DM);
154330088Sminshall neturg = NETLOC()-1; /* Some systems are off by one XXX */
154430088Sminshall
154530088Sminshall #if defined(NOT43)
154630088Sminshall return 0;
154730088Sminshall #endif /* defined(NOT43) */
154830088Sminshall }
154930088Sminshall
155030088Sminshall static void
doflush()155130088Sminshall doflush()
155230088Sminshall {
155330088Sminshall NET2ADD(IAC, DO);
155430088Sminshall NETADD(TELOPT_TM);
155530088Sminshall flushline = 1;
155630088Sminshall flushout = 1;
155730088Sminshall ttyflush();
155830088Sminshall /* do printoption AFTER flush, otherwise the output gets tossed... */
155930088Sminshall printoption("<SENT", doopt, TELOPT_TM, 0);
156030088Sminshall }
156130088Sminshall
156230088Sminshall static void
intp()156330088Sminshall intp()
156430088Sminshall {
156530088Sminshall NET2ADD(IAC, IP);
156630088Sminshall if (autoflush) {
156730088Sminshall doflush();
156830088Sminshall }
156930088Sminshall if (autosynch) {
157030088Sminshall dosynch();
157130088Sminshall }
157230088Sminshall }
157330088Sminshall
157430088Sminshall static void
sendbrk()157530088Sminshall sendbrk()
157630088Sminshall {
157730088Sminshall NET2ADD(IAC, BREAK);
157830088Sminshall if (autoflush) {
157930088Sminshall doflush();
158030088Sminshall }
158130088Sminshall if (autosynch) {
158230088Sminshall dosynch();
158330088Sminshall }
158430088Sminshall }
158530088Sminshall
158630088Sminshall /*
158730088Sminshall * Send as much data as possible to the terminal.
158830088Sminshall *
158930088Sminshall * The return value indicates whether we did any
159030088Sminshall * useful work.
159130088Sminshall */
159230088Sminshall
159330088Sminshall
159430088Sminshall static int
ttyflush()159530088Sminshall ttyflush()
159630088Sminshall {
159730088Sminshall int n;
159830088Sminshall
159930088Sminshall if ((n = tfrontp - tbackp) > 0) {
160030088Sminshall if (!(SYNCHing||flushout)) {
160131131Sminshall n = TerminalWrite(tout, tbackp, n);
160230088Sminshall } else {
160331124Sminshall TerminalFlushOutput();
160430088Sminshall /* we leave 'n' alone! */
160530088Sminshall }
160630088Sminshall }
160730088Sminshall if (n >= 0) {
160830088Sminshall tbackp += n;
160930088Sminshall if (tbackp == tfrontp) {
161030088Sminshall tbackp = tfrontp = ttyobuf;
161130088Sminshall }
161230088Sminshall }
161330088Sminshall return n > 0;
161430088Sminshall }
161530088Sminshall
161630088Sminshall #if defined(TN3270)
161730088Sminshall
161830088Sminshall #if defined(unix)
161930088Sminshall static void
inputAvailable()162030088Sminshall inputAvailable()
162130088Sminshall {
162230088Sminshall HaveInput = 1;
162330088Sminshall }
162430088Sminshall #endif /* defined(unix) */
162530088Sminshall
162630088Sminshall void
outputPurge()162730088Sminshall outputPurge()
162830088Sminshall {
162930088Sminshall int tmp = flushout;
163030088Sminshall
163130088Sminshall flushout = 1;
163230088Sminshall
163330088Sminshall ttyflush();
163430088Sminshall
163530088Sminshall flushout = tmp;
163630088Sminshall }
163730088Sminshall
163830088Sminshall #endif /* defined(TN3270) */
163930088Sminshall
164030088Sminshall #if defined(unix)
164130088Sminshall /*
164230088Sminshall * Various signal handling routines.
164330088Sminshall */
164430088Sminshall
164530088Sminshall static void
deadpeer()164630088Sminshall deadpeer()
164730088Sminshall {
164830088Sminshall setcommandmode();
164930088Sminshall longjmp(peerdied, -1);
165030088Sminshall }
165130088Sminshall
165230088Sminshall static void
intr()165330088Sminshall intr()
165430088Sminshall {
165530088Sminshall if (localchars) {
165630088Sminshall intp();
165730088Sminshall return;
165830088Sminshall }
165930088Sminshall setcommandmode();
166030088Sminshall longjmp(toplevel, -1);
166130088Sminshall }
166230088Sminshall
166330088Sminshall static void
intr2()166430088Sminshall intr2()
166530088Sminshall {
166630088Sminshall if (localchars) {
166730088Sminshall sendbrk();
166830088Sminshall return;
166930088Sminshall }
167030088Sminshall }
167130088Sminshall
167230088Sminshall static void
doescape()167330088Sminshall doescape()
167430088Sminshall {
167530088Sminshall command(0);
167630088Sminshall }
167730088Sminshall #endif /* defined(unix) */
167830088Sminshall
167930088Sminshall /*
168030088Sminshall * These routines decides on what the mode should be (based on the values
168130088Sminshall * of various global variables).
168230088Sminshall */
168330088Sminshall
168430088Sminshall
168530088Sminshall static
getconnmode()168630088Sminshall getconnmode()
168730088Sminshall {
168830088Sminshall static char newmode[16] =
168930088Sminshall { 4, 5, 3, 3, 2, 2, 1, 1, 6, 6, 6, 6, 6, 6, 6, 6 };
169030088Sminshall int modeindex = 0;
169130088Sminshall
169230088Sminshall if (dontlecho && (clocks.echotoggle > clocks.modenegotiated)) {
169330088Sminshall modeindex += 1;
169430088Sminshall }
169530088Sminshall if (hisopts[TELOPT_ECHO]) {
169630088Sminshall modeindex += 2;
169730088Sminshall }
169830088Sminshall if (hisopts[TELOPT_SGA]) {
169930088Sminshall modeindex += 4;
170030088Sminshall }
170130088Sminshall if (In3270) {
170230088Sminshall modeindex += 8;
170330088Sminshall }
170430088Sminshall return newmode[modeindex];
170530088Sminshall }
170630088Sminshall
170730088Sminshall void
setconnmode()170830088Sminshall setconnmode()
170930088Sminshall {
171031124Sminshall TerminalNewMode(getconnmode());
171130088Sminshall }
171230088Sminshall
171330088Sminshall
171430088Sminshall void
setcommandmode()171530088Sminshall setcommandmode()
171630088Sminshall {
171731124Sminshall TerminalNewMode(0);
171830088Sminshall }
171930088Sminshall
172030088Sminshall static void
willoption(option,reply)172130088Sminshall willoption(option, reply)
172230088Sminshall int option, reply;
172330088Sminshall {
172430088Sminshall char *fmt;
172530088Sminshall
172630088Sminshall switch (option) {
172730088Sminshall
172830368Sminshall case TELOPT_ECHO:
172930088Sminshall # if defined(TN3270)
173030368Sminshall /*
173130368Sminshall * The following is a pain in the rear-end.
173230368Sminshall * Various IBM servers (some versions of Wiscnet,
173330368Sminshall * possibly Fibronics/Spartacus, and who knows who
173430368Sminshall * else) will NOT allow us to send "DO SGA" too early
173530368Sminshall * in the setup proceedings. On the other hand,
173630368Sminshall * 4.2 servers (telnetd) won't set SGA correctly.
173730368Sminshall * So, we are stuck. Empirically (but, based on
173830368Sminshall * a VERY small sample), the IBM servers don't send
173930368Sminshall * out anything about ECHO, so we postpone our sending
174030368Sminshall * "DO SGA" until we see "WILL ECHO" (which 4.2 servers
174130368Sminshall * DO send).
174230368Sminshall */
174330368Sminshall {
174430368Sminshall if (askedSGA == 0) {
174530368Sminshall askedSGA = 1;
174630368Sminshall if (!hisopts[TELOPT_SGA]) {
174730368Sminshall willoption(TELOPT_SGA, 0);
174830368Sminshall }
174930368Sminshall }
175030368Sminshall }
175130368Sminshall /* Fall through */
175230088Sminshall case TELOPT_EOR:
175330088Sminshall case TELOPT_BINARY:
175430088Sminshall #endif /* defined(TN3270) */
175530088Sminshall case TELOPT_SGA:
175630088Sminshall settimer(modenegotiated);
175730088Sminshall hisopts[option] = 1;
175830088Sminshall fmt = doopt;
175930088Sminshall setconnmode(); /* possibly set new tty mode */
176030088Sminshall break;
176130088Sminshall
176230088Sminshall case TELOPT_TM:
176330088Sminshall return; /* Never reply to TM will's/wont's */
176430088Sminshall
176530088Sminshall default:
176630088Sminshall fmt = dont;
176730088Sminshall break;
176830088Sminshall }
176930088Sminshall sprintf(nfrontp, fmt, option);
177030088Sminshall nfrontp += sizeof (dont) - 2;
177130088Sminshall if (reply)
177230088Sminshall printoption(">SENT", fmt, option, reply);
177330088Sminshall else
177430088Sminshall printoption("<SENT", fmt, option, reply);
177530088Sminshall }
177630088Sminshall
177730088Sminshall static void
wontoption(option,reply)177830088Sminshall wontoption(option, reply)
177930088Sminshall int option, reply;
178030088Sminshall {
178130088Sminshall char *fmt;
178230088Sminshall
178330088Sminshall switch (option) {
178430088Sminshall
178530088Sminshall case TELOPT_ECHO:
178630088Sminshall case TELOPT_SGA:
178730088Sminshall settimer(modenegotiated);
178830088Sminshall hisopts[option] = 0;
178930088Sminshall fmt = dont;
179030088Sminshall setconnmode(); /* Set new tty mode */
179130088Sminshall break;
179230088Sminshall
179330088Sminshall case TELOPT_TM:
179430088Sminshall return; /* Never reply to TM will's/wont's */
179530088Sminshall
179630088Sminshall default:
179730088Sminshall fmt = dont;
179830088Sminshall }
179930088Sminshall sprintf(nfrontp, fmt, option);
180030088Sminshall nfrontp += sizeof (doopt) - 2;
180130088Sminshall if (reply)
180230088Sminshall printoption(">SENT", fmt, option, reply);
180330088Sminshall else
180430088Sminshall printoption("<SENT", fmt, option, reply);
180530088Sminshall }
180630088Sminshall
180730088Sminshall static void
dooption(option)180830088Sminshall dooption(option)
180930088Sminshall int option;
181030088Sminshall {
181130088Sminshall char *fmt;
181230088Sminshall
181330088Sminshall switch (option) {
181430088Sminshall
181530088Sminshall case TELOPT_TM:
181630088Sminshall fmt = will;
181730088Sminshall break;
181830088Sminshall
181930088Sminshall # if defined(TN3270)
182030088Sminshall case TELOPT_EOR:
182130088Sminshall case TELOPT_BINARY:
182230088Sminshall # endif /* defined(TN3270) */
182330088Sminshall case TELOPT_TTYPE: /* terminal type option */
182430088Sminshall case TELOPT_SGA: /* no big deal */
182530088Sminshall fmt = will;
182630088Sminshall myopts[option] = 1;
182730088Sminshall break;
182830088Sminshall
182930088Sminshall case TELOPT_ECHO: /* We're never going to echo... */
183030088Sminshall default:
183130088Sminshall fmt = wont;
183230088Sminshall break;
183330088Sminshall }
183430088Sminshall sprintf(nfrontp, fmt, option);
183530088Sminshall nfrontp += sizeof (doopt) - 2;
183630088Sminshall printoption(">SENT", fmt, option, 0);
183730088Sminshall }
183830088Sminshall
183930088Sminshall /*
184030088Sminshall * suboption()
184130088Sminshall *
184230088Sminshall * Look at the sub-option buffer, and try to be helpful to the other
184330088Sminshall * side.
184430088Sminshall *
184530088Sminshall * Currently we recognize:
184630088Sminshall *
184730088Sminshall * Terminal type, send request.
184830088Sminshall */
184930088Sminshall
185030088Sminshall static void
suboption()185130088Sminshall suboption()
185230088Sminshall {
185330088Sminshall printsub("<", subbuffer, subend-subbuffer+1);
185430088Sminshall switch (subbuffer[0]&0xff) {
185530088Sminshall case TELOPT_TTYPE:
185630088Sminshall if ((subbuffer[1]&0xff) != TELQUAL_SEND) {
185730088Sminshall ;
185830088Sminshall } else {
185930088Sminshall char *name;
186030088Sminshall char namebuf[41];
186130088Sminshall extern char *getenv();
186230088Sminshall int len;
186330088Sminshall
186430088Sminshall #if defined(TN3270)
186530088Sminshall /*
186630326Sminshall * Try to send a 3270 type terminal name. Decide which one based
186730088Sminshall * on the format of our screen, and (in the future) color
186830088Sminshall * capaiblities.
186930088Sminshall */
187031124Sminshall #if defined(unix)
187131131Sminshall if (initscr() != ERR) { /* Initialize curses to get line size */
187231131Sminshall MaxNumberLines = LINES;
187331131Sminshall MaxNumberColumns = COLS;
187431131Sminshall }
187531131Sminshall #else /* defined(unix) */
187631131Sminshall InitTerminal();
187731131Sminshall #endif /* defined(unix) */
187831131Sminshall if ((MaxNumberLines >= 24) && (MaxNumberColumns >= 80)) {
187930088Sminshall Sent3270TerminalType = 1;
188031131Sminshall if ((MaxNumberLines >= 27) && (MaxNumberColumns >= 132)) {
188130088Sminshall MaxNumberLines = 27;
188230088Sminshall MaxNumberColumns = 132;
188330088Sminshall sb_terminal[SBTERMMODEL] = '5';
188431131Sminshall } else if (MaxNumberLines >= 43) {
188530088Sminshall MaxNumberLines = 43;
188630088Sminshall MaxNumberColumns = 80;
188730088Sminshall sb_terminal[SBTERMMODEL] = '4';
188831131Sminshall } else if (MaxNumberLines >= 32) {
188930088Sminshall MaxNumberLines = 32;
189030088Sminshall MaxNumberColumns = 80;
189130088Sminshall sb_terminal[SBTERMMODEL] = '3';
189230088Sminshall } else {
189330088Sminshall MaxNumberLines = 24;
189430088Sminshall MaxNumberColumns = 80;
189530088Sminshall sb_terminal[SBTERMMODEL] = '2';
189630088Sminshall }
189730088Sminshall NumberLines = 24; /* before we start out... */
189830088Sminshall NumberColumns = 80;
189930088Sminshall ScreenSize = NumberLines*NumberColumns;
190030088Sminshall if ((MaxNumberLines*MaxNumberColumns) > MAXSCREENSIZE) {
190130088Sminshall ExitString(stderr,
190230088Sminshall "Programming error: MAXSCREENSIZE too small.\n", 1);
190330088Sminshall /*NOTREACHED*/
190430088Sminshall }
190531131Sminshall memcpy(nfrontp, sb_terminal, sizeof sb_terminal);
190630088Sminshall printsub(">", nfrontp+2, sizeof sb_terminal-2);
190730088Sminshall nfrontp += sizeof sb_terminal;
190830088Sminshall return;
190930088Sminshall }
191030088Sminshall #endif /* defined(TN3270) */
191130088Sminshall
191230088Sminshall name = getenv("TERM");
191330088Sminshall if ((name == 0) || ((len = strlen(name)) > 40)) {
191430088Sminshall name = "UNKNOWN";
191530088Sminshall }
191630088Sminshall if ((len + 4+2) < NETROOM()) {
191730088Sminshall strcpy(namebuf, name);
191830088Sminshall upcase(namebuf);
191930088Sminshall sprintf(nfrontp, "%c%c%c%c%s%c%c", IAC, SB, TELOPT_TTYPE,
192030088Sminshall TELQUAL_IS, namebuf, IAC, SE);
192130088Sminshall printsub(">", nfrontp+2, 4+strlen(namebuf)+2-2-2);
192230088Sminshall nfrontp += 4+strlen(namebuf)+2;
192330088Sminshall } else {
192430088Sminshall ExitString(stderr, "No room in buffer for terminal type.\n",
192530088Sminshall 1);
192630088Sminshall /*NOTREACHED*/
192730088Sminshall }
192830088Sminshall }
192930088Sminshall
193030088Sminshall default:
193130088Sminshall break;
193230088Sminshall }
193330088Sminshall }
193430088Sminshall
193530088Sminshall #if defined(TN3270)
193630088Sminshall static void
SetIn3270()193730088Sminshall SetIn3270()
193830088Sminshall {
193930088Sminshall if (Sent3270TerminalType && myopts[TELOPT_BINARY]
194031791Sminshall && hisopts[TELOPT_BINARY] && !donebinarytoggle) {
194130088Sminshall if (!In3270) {
194230088Sminshall In3270 = 1;
194330326Sminshall Init3270(); /* Initialize 3270 functions */
194430088Sminshall /* initialize terminal key mapping */
194530326Sminshall InitTerminal(); /* Start terminal going */
194630088Sminshall setconnmode();
194730088Sminshall }
194830088Sminshall } else {
194930088Sminshall if (In3270) {
195030088Sminshall StopScreen(1);
195130088Sminshall In3270 = 0;
195231215Sminshall Stop3270(); /* Tell 3270 we aren't here anymore */
195330088Sminshall setconnmode();
195430088Sminshall }
195530088Sminshall }
195630088Sminshall }
195730088Sminshall #endif /* defined(TN3270) */
195830088Sminshall
195930088Sminshall
196030088Sminshall static void
telrcv()196130088Sminshall telrcv()
196230088Sminshall {
196330088Sminshall register int c;
196430722Sminshall static int telrcv_state = TS_DATA;
196530088Sminshall # if defined(TN3270)
196630088Sminshall register int Scc;
196730088Sminshall register char *Sbp;
196830088Sminshall # endif /* defined(TN3270) */
196930088Sminshall
197030088Sminshall while ((scc > 0) && (TTYROOM() > 2)) {
197130088Sminshall c = *sbp++ & 0xff, scc--;
197230722Sminshall switch (telrcv_state) {
197330088Sminshall
197430088Sminshall case TS_CR:
197530722Sminshall telrcv_state = TS_DATA;
197630088Sminshall if (c == '\0') {
197730088Sminshall break; /* Ignore \0 after CR */
197830088Sminshall } else if (c == '\n') {
197930088Sminshall if (hisopts[TELOPT_ECHO] && !crmod) {
198030088Sminshall TTYADD(c);
198130088Sminshall }
198230088Sminshall break;
198330088Sminshall }
198430088Sminshall /* Else, fall through */
198530088Sminshall
198630088Sminshall case TS_DATA:
198730088Sminshall if (c == IAC) {
198830722Sminshall telrcv_state = TS_IAC;
198930088Sminshall continue;
199030088Sminshall }
199130088Sminshall # if defined(TN3270)
199230088Sminshall if (In3270) {
199330088Sminshall *Ifrontp++ = c;
199430088Sminshall Sbp = sbp;
199530088Sminshall Scc = scc;
199630088Sminshall while (Scc > 0) {
199730088Sminshall c = *Sbp++ & 0377, Scc--;
199830088Sminshall if (c == IAC) {
199930722Sminshall telrcv_state = TS_IAC;
200030088Sminshall break;
200130088Sminshall }
200230088Sminshall *Ifrontp++ = c;
200330088Sminshall }
200430088Sminshall sbp = Sbp;
200530088Sminshall scc = Scc;
200630088Sminshall } else
200730088Sminshall # endif /* defined(TN3270) */
200830088Sminshall /*
200930088Sminshall * The 'crmod' hack (see following) is needed
201030088Sminshall * since we can't * set CRMOD on output only.
201130088Sminshall * Machines like MULTICS like to send \r without
201230088Sminshall * \n; since we must turn off CRMOD to get proper
201330088Sminshall * input, the mapping is done here (sigh).
201430088Sminshall */
2015*36284Sminshall if (c == '\r') {
201630088Sminshall if (scc > 0) {
201730088Sminshall c = *sbp&0xff;
201830088Sminshall if (c == 0) {
201930088Sminshall sbp++, scc--;
202030088Sminshall /* a "true" CR */
202130088Sminshall TTYADD('\r');
202230088Sminshall } else if (!hisopts[TELOPT_ECHO] &&
202330088Sminshall (c == '\n')) {
202430088Sminshall sbp++, scc--;
202530088Sminshall TTYADD('\n');
202630088Sminshall } else {
202730088Sminshall TTYADD('\r');
202830088Sminshall if (crmod) {
202930088Sminshall TTYADD('\n');
203030088Sminshall }
203130088Sminshall }
203230088Sminshall } else {
203330722Sminshall telrcv_state = TS_CR;
203430088Sminshall TTYADD('\r');
203530088Sminshall if (crmod) {
203630088Sminshall TTYADD('\n');
203730088Sminshall }
203830088Sminshall }
203930088Sminshall } else {
204030088Sminshall TTYADD(c);
204130088Sminshall }
204230088Sminshall continue;
204330088Sminshall
204430088Sminshall case TS_IAC:
204530088Sminshall switch (c) {
204630088Sminshall
204730088Sminshall case WILL:
204830722Sminshall telrcv_state = TS_WILL;
204930088Sminshall continue;
205030088Sminshall
205130088Sminshall case WONT:
205230722Sminshall telrcv_state = TS_WONT;
205330088Sminshall continue;
205430088Sminshall
205530088Sminshall case DO:
205630722Sminshall telrcv_state = TS_DO;
205730088Sminshall continue;
205830088Sminshall
205930088Sminshall case DONT:
206030722Sminshall telrcv_state = TS_DONT;
206130088Sminshall continue;
206230088Sminshall
206330088Sminshall case DM:
206430088Sminshall /*
206530088Sminshall * We may have missed an urgent notification,
206630088Sminshall * so make sure we flush whatever is in the
206730088Sminshall * buffer currently.
206830088Sminshall */
206930088Sminshall SYNCHing = 1;
207030088Sminshall ttyflush();
207130088Sminshall SYNCHing = stilloob(net);
207230088Sminshall settimer(gotDM);
207330088Sminshall break;
207430088Sminshall
207530088Sminshall case NOP:
207630088Sminshall case GA:
207730088Sminshall break;
207830088Sminshall
207930088Sminshall case SB:
208030088Sminshall SB_CLEAR();
208130722Sminshall telrcv_state = TS_SB;
208230088Sminshall continue;
208330088Sminshall
208430088Sminshall # if defined(TN3270)
208530088Sminshall case EOR:
208630088Sminshall if (In3270) {
208730088Sminshall Ibackp += DataFromNetwork(Ibackp, Ifrontp-Ibackp, 1);
208830088Sminshall if (Ibackp == Ifrontp) {
208930088Sminshall Ibackp = Ifrontp = Ibuf;
209030088Sminshall ISend = 0; /* should have been! */
209130088Sminshall } else {
209230088Sminshall ISend = 1;
209330088Sminshall }
209430088Sminshall }
209530088Sminshall break;
209630088Sminshall # endif /* defined(TN3270) */
209730088Sminshall
209830088Sminshall case IAC:
209930088Sminshall # if !defined(TN3270)
210030088Sminshall TTYADD(IAC);
210130088Sminshall # else /* !defined(TN3270) */
210230088Sminshall if (In3270) {
210330088Sminshall *Ifrontp++ = IAC;
210430088Sminshall } else {
210530088Sminshall TTYADD(IAC);
210630088Sminshall }
210730088Sminshall # endif /* !defined(TN3270) */
210830088Sminshall break;
210930088Sminshall
211030088Sminshall default:
211130088Sminshall break;
211230088Sminshall }
211330722Sminshall telrcv_state = TS_DATA;
211430088Sminshall continue;
211530088Sminshall
211630088Sminshall case TS_WILL:
211730088Sminshall printoption(">RCVD", will, c, !hisopts[c]);
211830088Sminshall if (c == TELOPT_TM) {
211930088Sminshall if (flushout) {
212030088Sminshall flushout = 0;
212130088Sminshall }
212230088Sminshall } else if (!hisopts[c]) {
212330088Sminshall willoption(c, 1);
212430088Sminshall }
212530088Sminshall SetIn3270();
212630722Sminshall telrcv_state = TS_DATA;
212730088Sminshall continue;
212830088Sminshall
212930088Sminshall case TS_WONT:
213030088Sminshall printoption(">RCVD", wont, c, hisopts[c]);
213130088Sminshall if (c == TELOPT_TM) {
213230088Sminshall if (flushout) {
213330088Sminshall flushout = 0;
213430088Sminshall }
213530088Sminshall } else if (hisopts[c]) {
213630088Sminshall wontoption(c, 1);
213730088Sminshall }
213830088Sminshall SetIn3270();
213930722Sminshall telrcv_state = TS_DATA;
214030088Sminshall continue;
214130088Sminshall
214230088Sminshall case TS_DO:
214330088Sminshall printoption(">RCVD", doopt, c, !myopts[c]);
214430088Sminshall if (!myopts[c])
214530088Sminshall dooption(c);
214630088Sminshall SetIn3270();
214730722Sminshall telrcv_state = TS_DATA;
214830088Sminshall continue;
214930088Sminshall
215030088Sminshall case TS_DONT:
215130088Sminshall printoption(">RCVD", dont, c, myopts[c]);
215230088Sminshall if (myopts[c]) {
215330088Sminshall myopts[c] = 0;
215430088Sminshall sprintf(nfrontp, wont, c);
215530088Sminshall nfrontp += sizeof (wont) - 2;
215630088Sminshall flushline = 1;
215730088Sminshall setconnmode(); /* set new tty mode (maybe) */
215830088Sminshall printoption(">SENT", wont, c, 0);
215930088Sminshall }
216030088Sminshall SetIn3270();
216130722Sminshall telrcv_state = TS_DATA;
216230088Sminshall continue;
216330088Sminshall
216430088Sminshall case TS_SB:
216530088Sminshall if (c == IAC) {
216630722Sminshall telrcv_state = TS_SE;
216730088Sminshall } else {
216830088Sminshall SB_ACCUM(c);
216930088Sminshall }
217030088Sminshall continue;
217130088Sminshall
217230088Sminshall case TS_SE:
217330088Sminshall if (c != SE) {
217430088Sminshall if (c != IAC) {
217530088Sminshall SB_ACCUM(IAC);
217630088Sminshall }
217730088Sminshall SB_ACCUM(c);
217830722Sminshall telrcv_state = TS_SB;
217930088Sminshall } else {
218030088Sminshall SB_TERM();
218130088Sminshall suboption(); /* handle sub-option */
218230088Sminshall SetIn3270();
218330722Sminshall telrcv_state = TS_DATA;
218430088Sminshall }
218530088Sminshall }
218630088Sminshall }
218730088Sminshall }
218830088Sminshall
218930088Sminshall #if defined(TN3270)
219030088Sminshall
219130088Sminshall /*
219230088Sminshall * The following routines are places where the various tn3270
219330088Sminshall * routines make calls into telnet.c.
219430088Sminshall */
219530088Sminshall
219630088Sminshall /* TtyChars() - returns the number of characters in the TTY buffer */
TtyChars()219730088Sminshall TtyChars()
219830088Sminshall {
219930088Sminshall return(tfrontp-tbackp);
220030088Sminshall }
220130088Sminshall
220230088Sminshall /*
220330088Sminshall * DataToNetwork - queue up some data to go to network. If "done" is set,
220430088Sminshall * then when last byte is queued, we add on an IAC EOR sequence (so,
220530088Sminshall * don't call us with "done" until you want that done...)
220630088Sminshall *
220730088Sminshall * We actually do send all the data to the network buffer, since our
220830088Sminshall * only client needs for us to do that.
220930088Sminshall */
221030088Sminshall
221130088Sminshall int
DataToNetwork(buffer,count,done)221230088Sminshall DataToNetwork(buffer, count, done)
221330088Sminshall register char *buffer; /* where the data is */
221430088Sminshall register int count; /* how much to send */
221530088Sminshall int done; /* is this the last of a logical block */
221630088Sminshall {
221730088Sminshall register int c;
221830088Sminshall int origCount;
221930088Sminshall fd_set o;
222030088Sminshall
222130088Sminshall origCount = count;
222230088Sminshall FD_ZERO(&o);
222330088Sminshall
222430088Sminshall while (count) {
222530088Sminshall if ((netobuf+sizeof netobuf - nfrontp) < 6) {
222630088Sminshall netflush();
222730088Sminshall while ((netobuf+sizeof netobuf - nfrontp) < 6) {
222830088Sminshall FD_SET(net, &o);
222930088Sminshall (void) select(net+1, (fd_set *) 0, &o, (fd_set *) 0,
223030088Sminshall (struct timeval *) 0);
223130088Sminshall netflush();
223230088Sminshall }
223330088Sminshall }
223430088Sminshall c = *buffer++;
223530088Sminshall count--;
223630088Sminshall if (c == IAC) {
223730088Sminshall *nfrontp++ = IAC;
223830088Sminshall *nfrontp++ = IAC;
223930088Sminshall } else {
224030088Sminshall *nfrontp++ = c;
224130088Sminshall }
224230088Sminshall }
224330088Sminshall
224430088Sminshall if (done && !count) {
224530088Sminshall *nfrontp++ = IAC;
224630088Sminshall *nfrontp++ = EOR;
224730088Sminshall netflush(); /* try to move along as quickly as ... */
224830088Sminshall }
224930088Sminshall return(origCount - count);
225030088Sminshall }
225130088Sminshall
225230088Sminshall /* DataToTerminal - queue up some data to go to terminal. */
225330088Sminshall
225430088Sminshall int
DataToTerminal(buffer,count)225530088Sminshall DataToTerminal(buffer, count)
225630088Sminshall register char *buffer; /* where the data is */
225730088Sminshall register int count; /* how much to send */
225830088Sminshall {
225930088Sminshall int origCount;
226031131Sminshall #if defined(unix)
226130088Sminshall fd_set o;
226230088Sminshall
226331131Sminshall FD_ZERO(&o);
226431131Sminshall #endif /* defined(unix) */
226530088Sminshall origCount = count;
226630088Sminshall
226730088Sminshall while (count) {
226830088Sminshall if (tfrontp >= ttyobuf+sizeof ttyobuf) {
226930088Sminshall ttyflush();
227030088Sminshall while (tfrontp >= ttyobuf+sizeof ttyobuf) {
227131131Sminshall #if defined(unix)
227230088Sminshall FD_SET(tout, &o);
227330088Sminshall (void) select(tout+1, (fd_set *) 0, &o, (fd_set *) 0,
227430088Sminshall (struct timeval *) 0);
227531131Sminshall #endif /* defined(unix) */
227630088Sminshall ttyflush();
227730088Sminshall }
227830088Sminshall }
227930088Sminshall *tfrontp++ = *buffer++;
228030088Sminshall count--;
228130088Sminshall }
228230088Sminshall return(origCount - count);
228330088Sminshall }
228430088Sminshall
228530088Sminshall /* EmptyTerminal - called to make sure that the terminal buffer is empty.
228630088Sminshall * Note that we consider the buffer to run all the
228730088Sminshall * way to the kernel (thus the select).
228830088Sminshall */
228930088Sminshall
229030088Sminshall void
EmptyTerminal()229130088Sminshall EmptyTerminal()
229230088Sminshall {
229331131Sminshall #if defined(unix)
229430088Sminshall fd_set o;
229530088Sminshall
229630088Sminshall FD_ZERO(&o);
229731131Sminshall #endif /* defined(unix) */
229830088Sminshall
229930088Sminshall if (tfrontp == tbackp) {
230031131Sminshall #if defined(unix)
230130088Sminshall FD_SET(tout, &o);
230230088Sminshall (void) select(tout+1, (int *) 0, &o, (int *) 0,
230330088Sminshall (struct timeval *) 0); /* wait for TTLOWAT */
230431131Sminshall #endif /* defined(unix) */
230530088Sminshall } else {
230630088Sminshall while (tfrontp != tbackp) {
230730088Sminshall ttyflush();
230831131Sminshall #if defined(unix)
230930088Sminshall FD_SET(tout, &o);
231030088Sminshall (void) select(tout+1, (int *) 0, &o, (int *) 0,
231130088Sminshall (struct timeval *) 0); /* wait for TTLOWAT */
231231131Sminshall #endif /* defined(unix) */
231330088Sminshall }
231430088Sminshall }
231530088Sminshall }
231630088Sminshall
231730088Sminshall /*
231830088Sminshall * Push3270 - Try to send data along the 3270 output (to screen) direction.
231930088Sminshall */
232030088Sminshall
232130088Sminshall static int
Push3270()232230088Sminshall Push3270()
232330088Sminshall {
232430088Sminshall int save = scc;
232530088Sminshall
232630088Sminshall if (scc) {
232730088Sminshall if (Ifrontp+scc > Ibuf+sizeof Ibuf) {
232830088Sminshall if (Ibackp != Ibuf) {
232931131Sminshall memcpy(Ibuf, Ibackp, Ifrontp-Ibackp);
233030088Sminshall Ifrontp -= (Ibackp-Ibuf);
233130088Sminshall Ibackp = Ibuf;
233230088Sminshall }
233330088Sminshall }
233430088Sminshall if (Ifrontp+scc < Ibuf+sizeof Ibuf) {
233530088Sminshall telrcv();
233630088Sminshall }
233730088Sminshall }
233830088Sminshall return save != scc;
233930088Sminshall }
234030088Sminshall
234130088Sminshall
234230088Sminshall /*
234330088Sminshall * Finish3270 - get the last dregs of 3270 data out to the terminal
234430088Sminshall * before quitting.
234530088Sminshall */
234630088Sminshall
234730088Sminshall static void
Finish3270()234830088Sminshall Finish3270()
234930088Sminshall {
235030088Sminshall while (Push3270() || !DoTerminalOutput()) {
235131589Sminshall #if defined(unix)
235231589Sminshall HaveInput = 0;
235331589Sminshall #endif /* defined(unix) */
235430088Sminshall ;
235530088Sminshall }
235630088Sminshall }
235730088Sminshall
235830088Sminshall
235930088Sminshall
236030088Sminshall /* StringToTerminal - output a null terminated string to the terminal */
236130088Sminshall
236230088Sminshall void
StringToTerminal(s)236330088Sminshall StringToTerminal(s)
236430088Sminshall char *s;
236530088Sminshall {
236630088Sminshall int count;
236730088Sminshall
236830088Sminshall count = strlen(s);
236930088Sminshall if (count) {
237030088Sminshall (void) DataToTerminal(s, count); /* we know it always goes... */
237130088Sminshall }
237230088Sminshall }
237330088Sminshall
237430088Sminshall
237530088Sminshall #if defined(TN3270) && ((!defined(NOT43)) || defined(PUTCHAR))
237630088Sminshall /* _putchar - output a single character to the terminal. This name is so that
237730088Sminshall * curses(3x) can call us to send out data.
237830088Sminshall */
237930088Sminshall
238030088Sminshall void
_putchar(c)238130088Sminshall _putchar(c)
238230088Sminshall char c;
238330088Sminshall {
238430088Sminshall if (tfrontp >= ttyobuf+sizeof ttyobuf) {
238530088Sminshall (void) DataToTerminal(&c, 1);
238630088Sminshall } else {
238730088Sminshall *tfrontp++ = c; /* optimize if possible. */
238830088Sminshall }
238930088Sminshall }
239030088Sminshall #endif /* defined(TN3270) && ((!defined(NOT43)) || defined(PUTCHAR)) */
239130088Sminshall
239230088Sminshall static void
SetForExit()239330088Sminshall SetForExit()
239430088Sminshall {
239530088Sminshall setconnmode();
239630088Sminshall if (In3270) {
239730088Sminshall Finish3270();
239830088Sminshall }
239930088Sminshall setcommandmode();
240030088Sminshall fflush(stdout);
240130088Sminshall fflush(stderr);
240230088Sminshall if (In3270) {
240330088Sminshall StopScreen(1);
240430088Sminshall }
240530088Sminshall setconnmode();
240630088Sminshall setcommandmode();
240730088Sminshall }
240830088Sminshall
240930088Sminshall static void
Exit(returnCode)241030088Sminshall Exit(returnCode)
241130088Sminshall int returnCode;
241230088Sminshall {
241330088Sminshall SetForExit();
241430088Sminshall exit(returnCode);
241530088Sminshall }
241630088Sminshall
241730088Sminshall void
ExitString(file,string,returnCode)241830088Sminshall ExitString(file, string, returnCode)
241930088Sminshall FILE *file;
242030088Sminshall char *string;
242130088Sminshall int returnCode;
242230088Sminshall {
242330088Sminshall SetForExit();
242430088Sminshall fwrite(string, 1, strlen(string), file);
242530088Sminshall exit(returnCode);
242630088Sminshall }
242730088Sminshall
242830088Sminshall void
ExitPerror(string,returnCode)242930088Sminshall ExitPerror(string, returnCode)
243030088Sminshall char *string;
243130088Sminshall int returnCode;
243230088Sminshall {
243330088Sminshall SetForExit();
243430088Sminshall perror(string);
243530088Sminshall exit(returnCode);
243630088Sminshall }
243730088Sminshall
243830088Sminshall #endif /* defined(TN3270) */
243930088Sminshall
244031215Sminshall /*
244131215Sminshall * Scheduler()
244231215Sminshall *
244331215Sminshall * Try to do something.
244431215Sminshall *
244531215Sminshall * If we do something useful, return 1; else return 0.
244631215Sminshall *
244731215Sminshall */
244831215Sminshall
244931215Sminshall
245031215Sminshall int
Scheduler(block)245130088Sminshall Scheduler(block)
245230088Sminshall int block; /* should we block in the select ? */
245330088Sminshall {
245430088Sminshall register int c;
245530088Sminshall /* One wants to be a bit careful about setting returnValue
245630088Sminshall * to one, since a one implies we did some useful work,
245730088Sminshall * and therefore probably won't be called to block next
245830088Sminshall * time (TN3270 mode only).
245930088Sminshall */
246030088Sminshall int returnValue = 0;
246130088Sminshall static struct timeval TimeValue = { 0 };
246230088Sminshall
246330088Sminshall if (scc < 0 && tcc < 0) {
246430088Sminshall return -1;
246530088Sminshall }
246630088Sminshall
246730088Sminshall if ((!MODE_LINE(globalmode) || flushline) && NETBYTES()) {
246830088Sminshall FD_SET(net, &obits);
246930088Sminshall }
247031131Sminshall #if !defined(MSDOS)
247130088Sminshall if (TTYBYTES()) {
247230088Sminshall FD_SET(tout, &obits);
247330088Sminshall }
247431215Sminshall if ((tcc == 0) && NETROOM() && (shell_active == 0)) {
247530088Sminshall FD_SET(tin, &ibits);
247630088Sminshall }
247731131Sminshall #endif /* !defined(MSDOS) */
247830088Sminshall # if !defined(TN3270)
247930088Sminshall if (TTYROOM()) {
248030088Sminshall FD_SET(net, &ibits);
248130088Sminshall }
248230088Sminshall # else /* !defined(TN3270) */
248330088Sminshall if (!ISend && TTYROOM()) {
248430088Sminshall FD_SET(net, &ibits);
248530088Sminshall }
248630088Sminshall # endif /* !defined(TN3270) */
248730088Sminshall if (!SYNCHing) {
248830088Sminshall FD_SET(net, &xbits);
248930088Sminshall }
249030088Sminshall # if defined(TN3270) && defined(unix)
249130088Sminshall if (HaveInput) {
249230088Sminshall HaveInput = 0;
249330088Sminshall signal(SIGIO, inputAvailable);
249430088Sminshall }
249530088Sminshall #endif /* defined(TN3270) && defined(unix) */
249630088Sminshall if ((c = select(16, &ibits, &obits, &xbits,
249731131Sminshall block? (struct timeval *)0 : &TimeValue)) < 0) {
249830088Sminshall if (c == -1) {
249930088Sminshall /*
250030088Sminshall * we can get EINTR if we are in line mode,
250130088Sminshall * and the user does an escape (TSTP), or
250230088Sminshall * some other signal generator.
250330088Sminshall */
250430088Sminshall if (errno == EINTR) {
250530088Sminshall return 0;
250630088Sminshall }
250730088Sminshall # if defined(TN3270)
250830088Sminshall /*
250930088Sminshall * we can get EBADF if we were in transparent
251030088Sminshall * mode, and the transcom process died.
251130088Sminshall */
251230088Sminshall if (errno == EBADF) {
251330088Sminshall /*
251430088Sminshall * zero the bits (even though kernel does it)
251530088Sminshall * to make sure we are selecting on the right
251630088Sminshall * ones.
251730088Sminshall */
251830088Sminshall FD_ZERO(&ibits);
251930088Sminshall FD_ZERO(&obits);
252030088Sminshall FD_ZERO(&xbits);
252130088Sminshall return 0;
252230088Sminshall }
252330088Sminshall # endif /* defined(TN3270) */
252430088Sminshall /* I don't like this, does it ever happen? */
252530088Sminshall printf("sleep(5) from telnet, after select\r\n");
252630088Sminshall #if defined(unix)
252730088Sminshall sleep(5);
252830088Sminshall #endif /* defined(unix) */
252930088Sminshall }
253030088Sminshall return 0;
253130088Sminshall }
253230088Sminshall
253330088Sminshall /*
253430088Sminshall * Any urgent data?
253530088Sminshall */
253630088Sminshall if (FD_ISSET(net, &xbits)) {
253730088Sminshall FD_CLR(net, &xbits);
253830088Sminshall SYNCHing = 1;
253930088Sminshall ttyflush(); /* flush already enqueued data */
254030088Sminshall }
254130088Sminshall
254230088Sminshall /*
254330088Sminshall * Something to read from the network...
254430088Sminshall */
254530088Sminshall if (FD_ISSET(net, &ibits)) {
254630088Sminshall int canread;
254730088Sminshall
254830088Sminshall FD_CLR(net, &ibits);
254930088Sminshall if (scc == 0) {
255030088Sminshall sbp = sibuf;
255130088Sminshall }
255230422Sminshall canread = sibuf + sizeof sibuf - (sbp+scc);
255330088Sminshall #if !defined(SO_OOBINLINE)
255430088Sminshall /*
255530088Sminshall * In 4.2 (and some early 4.3) systems, the
255630088Sminshall * OOB indication and data handling in the kernel
255730088Sminshall * is such that if two separate TCP Urgent requests
255830088Sminshall * come in, one byte of TCP data will be overlaid.
255930088Sminshall * This is fatal for Telnet, but we try to live
256030088Sminshall * with it.
256130088Sminshall *
256230088Sminshall * In addition, in 4.2 (and...), a special protocol
256330088Sminshall * is needed to pick up the TCP Urgent data in
256430088Sminshall * the correct sequence.
256530088Sminshall *
256630088Sminshall * What we do is: if we think we are in urgent
256730088Sminshall * mode, we look to see if we are "at the mark".
256830088Sminshall * If we are, we do an OOB receive. If we run
256930088Sminshall * this twice, we will do the OOB receive twice,
257030088Sminshall * but the second will fail, since the second
257130088Sminshall * time we were "at the mark", but there wasn't
257230088Sminshall * any data there (the kernel doesn't reset
257330088Sminshall * "at the mark" until we do a normal read).
257430088Sminshall * Once we've read the OOB data, we go ahead
257530088Sminshall * and do normal reads.
257630088Sminshall *
257730088Sminshall * There is also another problem, which is that
257830088Sminshall * since the OOB byte we read doesn't put us
257930088Sminshall * out of OOB state, and since that byte is most
258030088Sminshall * likely the TELNET DM (data mark), we would
258130088Sminshall * stay in the TELNET SYNCH (SYNCHing) state.
258230088Sminshall * So, clocks to the rescue. If we've "just"
258330088Sminshall * received a DM, then we test for the
258430088Sminshall * presence of OOB data when the receive OOB
258530088Sminshall * fails (and AFTER we did the normal mode read
258630088Sminshall * to clear "at the mark").
258730088Sminshall */
258830088Sminshall if (SYNCHing) {
258930088Sminshall int atmark;
259030088Sminshall
259130088Sminshall ioctl(net, SIOCATMARK, (char *)&atmark);
259230088Sminshall if (atmark) {
259330422Sminshall c = recv(net, sbp+scc, canread, MSG_OOB);
259430088Sminshall if ((c == -1) && (errno == EINVAL)) {
259531131Sminshall c = recv(net, sbp+scc, canread, 0);
259630088Sminshall if (clocks.didnetreceive < clocks.gotDM) {
259730088Sminshall SYNCHing = stilloob(net);
259830088Sminshall }
259930088Sminshall }
260030088Sminshall } else {
260131131Sminshall c = recv(net, sbp+scc, canread, 0);
260230088Sminshall }
260330088Sminshall } else {
260431131Sminshall c = recv(net, sbp+scc, canread, 0);
260530088Sminshall }
260630088Sminshall settimer(didnetreceive);
260730088Sminshall #else /* !defined(SO_OOBINLINE) */
260831131Sminshall c = recv(net, sbp+scc, canread, 0);
260930088Sminshall #endif /* !defined(SO_OOBINLINE) */
261030088Sminshall if (c < 0 && errno == EWOULDBLOCK) {
261130088Sminshall c = 0;
261230088Sminshall } else if (c <= 0) {
261330088Sminshall return -1;
261430088Sminshall }
261530088Sminshall if (netdata) {
261630422Sminshall Dump('<', sbp+scc, c);
261730088Sminshall }
261830088Sminshall scc += c;
261930088Sminshall returnValue = 1;
262030088Sminshall }
262130088Sminshall
262230088Sminshall /*
262330088Sminshall * Something to read from the tty...
262430088Sminshall */
262531131Sminshall #if defined(MSDOS)
262631215Sminshall if ((tcc == 0) && NETROOM() && (shell_active == 0) && TerminalCanRead())
262731131Sminshall #else /* defined(MSDOS) */
262831131Sminshall if (FD_ISSET(tin, &ibits))
262931131Sminshall #endif /* defined(MSDOS) */
263031131Sminshall {
263130088Sminshall FD_CLR(tin, &ibits);
263230088Sminshall if (tcc == 0) {
263330088Sminshall tbp = tibuf; /* nothing left, reset */
263430088Sminshall }
263531131Sminshall c = TerminalRead(tin, tbp, tibuf+sizeof tibuf - tbp);
263630088Sminshall if (c < 0 && errno == EWOULDBLOCK) {
263730088Sminshall c = 0;
263830088Sminshall } else {
263931124Sminshall #if defined(unix)
264030088Sminshall /* EOF detection for line mode!!!! */
264130088Sminshall if (c == 0 && MODE_LOCAL_CHARS(globalmode)) {
264230088Sminshall /* must be an EOF... */
264330088Sminshall *tbp = ntc.t_eofc;
264430088Sminshall c = 1;
264530088Sminshall }
264631124Sminshall #endif /* defined(unix) */
264730088Sminshall if (c <= 0) {
264830088Sminshall tcc = c;
264930088Sminshall return -1;
265030088Sminshall }
265130088Sminshall }
265230088Sminshall tcc += c;
265330088Sminshall returnValue = 1; /* did something useful */
265430088Sminshall }
265530088Sminshall
265630088Sminshall # if defined(TN3270)
265730088Sminshall if (tcc > 0) {
265830088Sminshall if (In3270) {
265930088Sminshall c = DataFromTerminal(tbp, tcc);
266030088Sminshall if (c) {
266130088Sminshall returnValue = 1;
266230088Sminshall }
266330088Sminshall tcc -= c;
266430088Sminshall tbp += c;
266530088Sminshall } else {
266630320Sminshall # endif /* defined(TN3270) */
266730088Sminshall returnValue = 1;
266830088Sminshall while (tcc > 0) {
266930088Sminshall register int sc;
267030088Sminshall
267130088Sminshall if (NETROOM() < 2) {
267230088Sminshall flushline = 1;
267330088Sminshall break;
267430088Sminshall }
267530088Sminshall c = *tbp++ & 0xff, sc = strip(c), tcc--;
267630088Sminshall if (sc == escape) {
267730088Sminshall command(0);
267830088Sminshall tcc = 0;
267930088Sminshall flushline = 1;
268030088Sminshall break;
268130088Sminshall } else if (MODE_LINE(globalmode) && (sc == echoc)) {
268230088Sminshall if (tcc > 0 && strip(*tbp) == echoc) {
268330088Sminshall tbp++;
268430088Sminshall tcc--;
268530088Sminshall } else {
268630088Sminshall dontlecho = !dontlecho;
268730088Sminshall settimer(echotoggle);
268830088Sminshall setconnmode();
268930088Sminshall tcc = 0;
269030088Sminshall flushline = 1;
269130088Sminshall break;
269230088Sminshall }
269330088Sminshall }
269430088Sminshall if (localchars) {
269531131Sminshall if (TerminalSpecialChars(sc) == 0) {
269630088Sminshall break;
269730088Sminshall }
269830088Sminshall }
2699*36284Sminshall switch (c) {
2700*36284Sminshall case '\n':
2701*36284Sminshall /*
2702*36284Sminshall * If we are in CRMOD mode (\r ==> \n)
2703*36284Sminshall * on our local machine, then probably
2704*36284Sminshall * a newline (unix) is CRLF (TELNET).
2705*36284Sminshall */
2706*36284Sminshall if (MODE_LOCAL_CHARS(globalmode)) {
2707*36284Sminshall NETADD('\r');
270830088Sminshall }
2709*36284Sminshall NETADD('\n');
2710*36284Sminshall flushline = 1;
2711*36284Sminshall break;
2712*36284Sminshall case '\r':
2713*36284Sminshall NET2ADD('\r', '\0');
2714*36284Sminshall flushline = 1;
2715*36284Sminshall break;
2716*36284Sminshall case IAC:
271730088Sminshall NET2ADD(IAC, IAC);
2718*36284Sminshall break;
2719*36284Sminshall default:
272030088Sminshall NETADD(c);
2721*36284Sminshall break;
272230088Sminshall }
272330088Sminshall }
272430088Sminshall # if defined(TN3270)
272530088Sminshall }
272630088Sminshall }
272730088Sminshall # endif /* defined(TN3270) */
272830088Sminshall
2729*36284Sminshall if ((!MODE_LINE(globalmode) || flushline) &&
273030088Sminshall FD_ISSET(net, &obits) && (NETBYTES() > 0)) {
273130088Sminshall FD_CLR(net, &obits);
273230088Sminshall returnValue = netflush();
273330088Sminshall }
273430088Sminshall if (scc > 0) {
273530088Sminshall # if !defined(TN3270)
273630088Sminshall telrcv();
273730088Sminshall returnValue = 1;
273830088Sminshall # else /* !defined(TN3270) */
273930088Sminshall returnValue = Push3270();
274030088Sminshall # endif /* !defined(TN3270) */
274130088Sminshall }
274231131Sminshall #if defined(MSDOS)
274331131Sminshall if (TTYBYTES())
274431131Sminshall #else /* defined(MSDOS) */
274531131Sminshall if (FD_ISSET(tout, &obits) && (TTYBYTES() > 0))
274631131Sminshall #endif /* defined(MSDOS) */
274731131Sminshall {
274830088Sminshall FD_CLR(tout, &obits);
274930088Sminshall returnValue = ttyflush();
275030088Sminshall }
275130088Sminshall return returnValue;
275230088Sminshall }
275330088Sminshall
275430088Sminshall /*
275530088Sminshall * Select from tty and network...
275630088Sminshall */
275730088Sminshall static void
telnet()275830088Sminshall telnet()
275930088Sminshall {
276031131Sminshall #if defined(MSDOS)
276131131Sminshall #define SCHED_BLOCK 0 /* Don't block in MSDOS */
276231131Sminshall #else /* defined(MSDOS) */
276331131Sminshall #define SCHED_BLOCK 1
276431131Sminshall #endif /* defined(MSDOS) */
276531131Sminshall
276630088Sminshall #if defined(TN3270) && defined(unix)
276730088Sminshall int myPid;
276830088Sminshall #endif /* defined(TN3270) */
276930088Sminshall
277030088Sminshall tout = fileno(stdout);
277130088Sminshall tin = fileno(stdin);
277230088Sminshall setconnmode();
277330088Sminshall scc = 0;
277430088Sminshall tcc = 0;
277530088Sminshall FD_ZERO(&ibits);
277630088Sminshall FD_ZERO(&obits);
277730088Sminshall FD_ZERO(&xbits);
277830088Sminshall
277931124Sminshall NetNonblockingIO(net, 1);
278030088Sminshall
278130088Sminshall #if defined(TN3270)
278231478Sminshall if (noasynch == 0) { /* DBX can't handle! */
278331478Sminshall NetSigIO(net, 1);
278431478Sminshall }
278531124Sminshall NetSetPgrp(net);
278630088Sminshall #endif /* defined(TN3270) */
278730088Sminshall
278830088Sminshall
278931124Sminshall #if defined(SO_OOBINLINE) && !defined(MSDOS)
279031124Sminshall SetSockOpt(net, SOL_SOCKET, SO_OOBINLINE, 1);
279131124Sminshall #endif /* defined(SO_OOBINLINE) && !defined(MSDOS) */
279231124Sminshall
279330320Sminshall # if !defined(TN3270)
279430088Sminshall if (telnetport) {
279530088Sminshall if (!hisopts[TELOPT_SGA]) {
279630088Sminshall willoption(TELOPT_SGA, 0);
279730088Sminshall }
279830088Sminshall if (!myopts[TELOPT_TTYPE]) {
279930088Sminshall dooption(TELOPT_TTYPE, 0);
280030088Sminshall }
280130088Sminshall }
280230320Sminshall # endif /* !defined(TN3270) */
280330088Sminshall
280430088Sminshall # if !defined(TN3270)
280530088Sminshall for (;;) {
280631131Sminshall if (Scheduler(SCHED_BLOCK) == -1) {
280730088Sminshall setcommandmode();
280830088Sminshall return;
280930088Sminshall }
281030088Sminshall }
281130088Sminshall # else /* !defined(TN3270) */
281230088Sminshall for (;;) {
281330088Sminshall int schedValue;
281430088Sminshall
281531791Sminshall while (!In3270 && !shell_active) {
281631131Sminshall if (Scheduler(SCHED_BLOCK) == -1) {
281730088Sminshall setcommandmode();
281830088Sminshall return;
281930088Sminshall }
282030088Sminshall }
282130088Sminshall
282230088Sminshall while ((schedValue = Scheduler(0)) != 0) {
282330088Sminshall if (schedValue == -1) {
282430088Sminshall setcommandmode();
282530088Sminshall return;
282630088Sminshall }
282730088Sminshall }
282830088Sminshall /* If there is data waiting to go out to terminal, don't
282930088Sminshall * schedule any more data for the terminal.
283030088Sminshall */
283130088Sminshall if (tfrontp-tbackp) {
283230088Sminshall schedValue = 1;
283330088Sminshall } else {
283431215Sminshall if (shell_active) {
283531215Sminshall if (shell_continue() == 0) {
283631215Sminshall ConnectScreen();
283731215Sminshall }
283831791Sminshall } else if (In3270) {
283931215Sminshall schedValue = DoTerminalOutput();
284031215Sminshall }
284130088Sminshall }
284231215Sminshall if (schedValue && (shell_active == 0)) {
284331131Sminshall if (Scheduler(SCHED_BLOCK) == -1) {
284430088Sminshall setcommandmode();
284530088Sminshall return;
284630088Sminshall }
284730088Sminshall }
284830088Sminshall }
284930088Sminshall # endif /* !defined(TN3270) */
285030088Sminshall }
285130088Sminshall
285230088Sminshall /*
285330088Sminshall * The following are data structures and routines for
285430088Sminshall * the "send" command.
285530088Sminshall *
285630088Sminshall */
285730088Sminshall
285830088Sminshall struct sendlist {
285930088Sminshall char *name; /* How user refers to it (case independent) */
286030088Sminshall int what; /* Character to be sent (<0 ==> special) */
286130088Sminshall char *help; /* Help information (0 ==> no help) */
286230088Sminshall #if defined(NOT43)
286330088Sminshall int (*routine)(); /* Routine to perform (for special ops) */
286430088Sminshall #else /* defined(NOT43) */
286530088Sminshall void (*routine)(); /* Routine to perform (for special ops) */
286630088Sminshall #endif /* defined(NOT43) */
286730088Sminshall };
286830088Sminshall
286930088Sminshall #define SENDQUESTION -1
287030088Sminshall #define SENDESCAPE -3
287130088Sminshall
287230088Sminshall static struct sendlist Sendlist[] = {
287330088Sminshall { "ao", AO, "Send Telnet Abort output" },
287430088Sminshall { "ayt", AYT, "Send Telnet 'Are You There'" },
287530088Sminshall { "brk", BREAK, "Send Telnet Break" },
287630088Sminshall { "ec", EC, "Send Telnet Erase Character" },
287730088Sminshall { "el", EL, "Send Telnet Erase Line" },
287830088Sminshall { "escape", SENDESCAPE, "Send current escape character" },
287930088Sminshall { "ga", GA, "Send Telnet 'Go Ahead' sequence" },
288030088Sminshall { "ip", IP, "Send Telnet Interrupt Process" },
288130088Sminshall { "nop", NOP, "Send Telnet 'No operation'" },
288230088Sminshall { "synch", SYNCH, "Perform Telnet 'Synch operation'", dosynch },
288330088Sminshall { "?", SENDQUESTION, "Display send options" },
288430088Sminshall { 0 }
288530088Sminshall };
288630088Sminshall
288730088Sminshall static struct sendlist Sendlist2[] = { /* some synonyms */
288830088Sminshall { "break", BREAK, 0 },
288930088Sminshall
289030088Sminshall { "intp", IP, 0 },
289130088Sminshall { "interrupt", IP, 0 },
289230088Sminshall { "intr", IP, 0 },
289330088Sminshall
289430088Sminshall { "help", SENDQUESTION, 0 },
289530088Sminshall
289630088Sminshall { 0 }
289730088Sminshall };
289830088Sminshall
289930088Sminshall static char **
getnextsend(name)290030088Sminshall getnextsend(name)
290130088Sminshall char *name;
290230088Sminshall {
290330088Sminshall struct sendlist *c = (struct sendlist *) name;
290430088Sminshall
290530088Sminshall return (char **) (c+1);
290630088Sminshall }
290730088Sminshall
290830088Sminshall static struct sendlist *
getsend(name)290930088Sminshall getsend(name)
291030088Sminshall char *name;
291130088Sminshall {
291230088Sminshall struct sendlist *sl;
291330088Sminshall
291430088Sminshall if ((sl = (struct sendlist *)
291530088Sminshall genget(name, (char **) Sendlist, getnextsend)) != 0) {
291630088Sminshall return sl;
291730088Sminshall } else {
291830088Sminshall return (struct sendlist *)
291930088Sminshall genget(name, (char **) Sendlist2, getnextsend);
292030088Sminshall }
292130088Sminshall }
292230088Sminshall
292330088Sminshall static
sendcmd(argc,argv)292430088Sminshall sendcmd(argc, argv)
292530088Sminshall int argc;
292630088Sminshall char **argv;
292730088Sminshall {
292830088Sminshall int what; /* what we are sending this time */
292930088Sminshall int count; /* how many bytes we are going to need to send */
293030088Sminshall int i;
293130088Sminshall int question = 0; /* was at least one argument a question */
293230088Sminshall struct sendlist *s; /* pointer to current command */
293330088Sminshall
293430088Sminshall if (argc < 2) {
293530088Sminshall printf("need at least one argument for 'send' command\n");
293630088Sminshall printf("'send ?' for help\n");
293730088Sminshall return 0;
293830088Sminshall }
293930088Sminshall /*
294030088Sminshall * First, validate all the send arguments.
294130088Sminshall * In addition, we see how much space we are going to need, and
294230088Sminshall * whether or not we will be doing a "SYNCH" operation (which
294330088Sminshall * flushes the network queue).
294430088Sminshall */
294530088Sminshall count = 0;
294630088Sminshall for (i = 1; i < argc; i++) {
294730088Sminshall s = getsend(argv[i]);
294830088Sminshall if (s == 0) {
294930088Sminshall printf("Unknown send argument '%s'\n'send ?' for help.\n",
295030088Sminshall argv[i]);
295130088Sminshall return 0;
295230088Sminshall } else if (s == Ambiguous(struct sendlist *)) {
295330088Sminshall printf("Ambiguous send argument '%s'\n'send ?' for help.\n",
295430088Sminshall argv[i]);
295530088Sminshall return 0;
295630088Sminshall }
295730088Sminshall switch (s->what) {
295830088Sminshall case SENDQUESTION:
295930088Sminshall break;
296030088Sminshall case SENDESCAPE:
296130088Sminshall count += 1;
296230088Sminshall break;
296330088Sminshall case SYNCH:
296430088Sminshall count += 2;
296530088Sminshall break;
296630088Sminshall default:
296730088Sminshall count += 2;
296830088Sminshall break;
296930088Sminshall }
297030088Sminshall }
297130088Sminshall /* Now, do we have enough room? */
297230088Sminshall if (NETROOM() < count) {
297330088Sminshall printf("There is not enough room in the buffer TO the network\n");
297430088Sminshall printf("to process your request. Nothing will be done.\n");
297530088Sminshall printf("('send synch' will throw away most data in the network\n");
297630088Sminshall printf("buffer, if this might help.)\n");
297730088Sminshall return 0;
297830088Sminshall }
297930088Sminshall /* OK, they are all OK, now go through again and actually send */
298030088Sminshall for (i = 1; i < argc; i++) {
298130088Sminshall if ((s = getsend(argv[i])) == 0) {
298230088Sminshall fprintf(stderr, "Telnet 'send' error - argument disappeared!\n");
298330088Sminshall quit();
298430088Sminshall /*NOTREACHED*/
298530088Sminshall }
298630088Sminshall if (s->routine) {
298730088Sminshall (*s->routine)(s);
298830088Sminshall } else {
298930088Sminshall switch (what = s->what) {
299030088Sminshall case SYNCH:
299130088Sminshall dosynch();
299230088Sminshall break;
299330088Sminshall case SENDQUESTION:
299430088Sminshall for (s = Sendlist; s->name; s++) {
299530088Sminshall if (s->help) {
299630088Sminshall printf(s->name);
299730088Sminshall if (s->help) {
299830088Sminshall printf("\t%s", s->help);
299930088Sminshall }
300030088Sminshall printf("\n");
300130088Sminshall }
300230088Sminshall }
300330088Sminshall question = 1;
300430088Sminshall break;
300530088Sminshall case SENDESCAPE:
300630088Sminshall NETADD(escape);
300730088Sminshall break;
300830088Sminshall default:
300930088Sminshall NET2ADD(IAC, what);
301030088Sminshall break;
301130088Sminshall }
301230088Sminshall }
301330088Sminshall }
301430088Sminshall return !question;
301530088Sminshall }
301630088Sminshall
301730088Sminshall /*
301830088Sminshall * The following are the routines and data structures referred
301930088Sminshall * to by the arguments to the "toggle" command.
302030088Sminshall */
302130088Sminshall
302230088Sminshall static
lclchars()302330088Sminshall lclchars()
302430088Sminshall {
302530088Sminshall donelclchars = 1;
302630088Sminshall return 1;
302730088Sminshall }
302830088Sminshall
302930088Sminshall static
togdebug()303030088Sminshall togdebug()
303130088Sminshall {
303230088Sminshall #ifndef NOT43
303330088Sminshall if (net > 0 &&
303431124Sminshall (SetSockOpt(net, SOL_SOCKET, SO_DEBUG, debug)) < 0) {
303530088Sminshall perror("setsockopt (SO_DEBUG)");
303630088Sminshall }
303730320Sminshall #else /* NOT43 */
303830088Sminshall if (debug) {
303931124Sminshall if (net > 0 && SetSockOpt(net, SOL_SOCKET, SO_DEBUG, 0, 0) < 0)
304030088Sminshall perror("setsockopt (SO_DEBUG)");
304130088Sminshall } else
304230088Sminshall printf("Cannot turn off socket debugging\n");
304330320Sminshall #endif /* NOT43 */
304430088Sminshall return 1;
304530088Sminshall }
304630088Sminshall
304730088Sminshall
304831791Sminshall static int
togbinary()304931791Sminshall togbinary()
305031791Sminshall {
305131791Sminshall donebinarytoggle = 1;
305230088Sminshall
305331791Sminshall if (myopts[TELOPT_BINARY] == 0) { /* Go into binary mode */
305431791Sminshall NET2ADD(IAC, DO);
305531791Sminshall NETADD(TELOPT_BINARY);
305631791Sminshall printoption("<SENT", doopt, TELOPT_BINARY, 0);
305731791Sminshall NET2ADD(IAC, WILL);
305831791Sminshall NETADD(TELOPT_BINARY);
305931791Sminshall printoption("<SENT", doopt, TELOPT_BINARY, 0);
306031791Sminshall hisopts[TELOPT_BINARY] = myopts[TELOPT_BINARY] = 1;
306131791Sminshall printf("Negotiating binary mode with remote host.\n");
306231791Sminshall } else { /* Turn off binary mode */
306331791Sminshall NET2ADD(IAC, DONT);
306431791Sminshall NETADD(TELOPT_BINARY);
306531791Sminshall printoption("<SENT", dont, TELOPT_BINARY, 0);
306631791Sminshall NET2ADD(IAC, DONT);
306731791Sminshall NETADD(TELOPT_BINARY);
306831791Sminshall printoption("<SENT", dont, TELOPT_BINARY, 0);
306931791Sminshall hisopts[TELOPT_BINARY] = myopts[TELOPT_BINARY] = 0;
307031791Sminshall printf("Negotiating network ascii mode with remote host.\n");
307131791Sminshall }
307231791Sminshall return 1;
307331791Sminshall }
307431791Sminshall
307531791Sminshall
307631791Sminshall
307730088Sminshall extern int togglehelp();
307830088Sminshall
307930088Sminshall struct togglelist {
308030088Sminshall char *name; /* name of toggle */
308130088Sminshall char *help; /* help message */
308230088Sminshall int (*handler)(); /* routine to do actual setting */
308330088Sminshall int dohelp; /* should we display help information */
308430088Sminshall int *variable;
308530088Sminshall char *actionexplanation;
308630088Sminshall };
308730088Sminshall
308830088Sminshall static struct togglelist Togglelist[] = {
308930088Sminshall { "autoflush",
309030088Sminshall "toggle flushing of output when sending interrupt characters",
309130088Sminshall 0,
309230088Sminshall 1,
309330088Sminshall &autoflush,
309430088Sminshall "flush output when sending interrupt characters" },
309530088Sminshall { "autosynch",
309630088Sminshall "toggle automatic sending of interrupt characters in urgent mode",
309730088Sminshall 0,
309830088Sminshall 1,
309930088Sminshall &autosynch,
310030088Sminshall "send interrupt characters in urgent mode" },
310131791Sminshall { "binary",
310231791Sminshall "toggle sending and receiving of binary data",
310331791Sminshall togbinary,
310431791Sminshall 1,
310531791Sminshall 0,
3106*36284Sminshall "send and receive network data in binary mode" },
310730088Sminshall { "crmod",
310830088Sminshall "toggle mapping of received carriage returns",
310930088Sminshall 0,
311030088Sminshall 1,
311130088Sminshall &crmod,
311230088Sminshall "map carriage return on output" },
311330088Sminshall { "localchars",
311430088Sminshall "toggle local recognition of certain control characters",
311530088Sminshall lclchars,
311630088Sminshall 1,
311730088Sminshall &localchars,
311830088Sminshall "recognize certain control characters" },
311930088Sminshall { " ", "", 0, 1 }, /* empty line */
312030088Sminshall { "debug",
312130088Sminshall "(debugging) toggle debugging",
312230088Sminshall togdebug,
312330088Sminshall 1,
312430088Sminshall &debug,
312530088Sminshall "turn on socket level debugging" },
312630088Sminshall { "netdata",
312730088Sminshall "(debugging) toggle printing of hexadecimal network data",
312830088Sminshall 0,
312930088Sminshall 1,
313030088Sminshall &netdata,
313130088Sminshall "print hexadecimal representation of network traffic" },
313230088Sminshall { "options",
313330088Sminshall "(debugging) toggle viewing of options processing",
313430088Sminshall 0,
313530088Sminshall 1,
313630088Sminshall &showoptions,
313730088Sminshall "show option processing" },
313830088Sminshall { " ", "", 0, 1 }, /* empty line */
313930088Sminshall { "?",
314030088Sminshall "display help information",
314130088Sminshall togglehelp,
314230088Sminshall 1 },
314330088Sminshall { "help",
314430088Sminshall "display help information",
314530088Sminshall togglehelp,
314630088Sminshall 0 },
314730088Sminshall { 0 }
314830088Sminshall };
314930088Sminshall
315030088Sminshall static
togglehelp()315130088Sminshall togglehelp()
315230088Sminshall {
315330088Sminshall struct togglelist *c;
315430088Sminshall
315530088Sminshall for (c = Togglelist; c->name; c++) {
315630088Sminshall if (c->dohelp) {
315730088Sminshall printf("%s\t%s\n", c->name, c->help);
315830088Sminshall }
315930088Sminshall }
316030088Sminshall return 0;
316130088Sminshall }
316230088Sminshall
316330088Sminshall static char **
getnexttoggle(name)316430088Sminshall getnexttoggle(name)
316530088Sminshall char *name;
316630088Sminshall {
316730088Sminshall struct togglelist *c = (struct togglelist *) name;
316830088Sminshall
316930088Sminshall return (char **) (c+1);
317030088Sminshall }
317130088Sminshall
317230088Sminshall static struct togglelist *
gettoggle(name)317330088Sminshall gettoggle(name)
317430088Sminshall char *name;
317530088Sminshall {
317630088Sminshall return (struct togglelist *)
317730088Sminshall genget(name, (char **) Togglelist, getnexttoggle);
317830088Sminshall }
317930088Sminshall
318030088Sminshall static
toggle(argc,argv)318130088Sminshall toggle(argc, argv)
318230088Sminshall int argc;
318330088Sminshall char *argv[];
318430088Sminshall {
318530088Sminshall int retval = 1;
318630088Sminshall char *name;
318730088Sminshall struct togglelist *c;
318830088Sminshall
318930088Sminshall if (argc < 2) {
319030088Sminshall fprintf(stderr,
319130088Sminshall "Need an argument to 'toggle' command. 'toggle ?' for help.\n");
319230088Sminshall return 0;
319330088Sminshall }
319430088Sminshall argc--;
319530088Sminshall argv++;
319630088Sminshall while (argc--) {
319730088Sminshall name = *argv++;
319830088Sminshall c = gettoggle(name);
319930088Sminshall if (c == Ambiguous(struct togglelist *)) {
320030088Sminshall fprintf(stderr, "'%s': ambiguous argument ('toggle ?' for help).\n",
320130088Sminshall name);
320230088Sminshall return 0;
320330088Sminshall } else if (c == 0) {
320430088Sminshall fprintf(stderr, "'%s': unknown argument ('toggle ?' for help).\n",
320530088Sminshall name);
320630088Sminshall return 0;
320730088Sminshall } else {
320830088Sminshall if (c->variable) {
320930088Sminshall *c->variable = !*c->variable; /* invert it */
3210*36284Sminshall printf("%s %s.\n", *c->variable? "Will" : "Won't",
321130088Sminshall c->actionexplanation);
321230088Sminshall }
321330088Sminshall if (c->handler) {
321430088Sminshall retval &= (*c->handler)(c);
321530088Sminshall }
321630088Sminshall }
321730088Sminshall }
321830088Sminshall return retval;
321930088Sminshall }
322030088Sminshall
322130088Sminshall /*
322230088Sminshall * The following perform the "set" command.
322330088Sminshall */
322430088Sminshall
322530088Sminshall struct setlist {
322630088Sminshall char *name; /* name */
322730088Sminshall char *help; /* help information */
322830088Sminshall char *charp; /* where it is located at */
322930088Sminshall };
323030088Sminshall
323130088Sminshall static struct setlist Setlist[] = {
323230088Sminshall { "echo", "character to toggle local echoing on/off", &echoc },
323330088Sminshall { "escape", "character to escape back to telnet command mode", &escape },
323430088Sminshall { " ", "" },
323530088Sminshall { " ", "The following need 'localchars' to be toggled true", 0 },
323631124Sminshall #if defined(unix)
323730088Sminshall { "erase", "character to cause an Erase Character", &nttyb.sg_erase },
323830088Sminshall { "flushoutput", "character to cause an Abort Oubput", &nltc.t_flushc },
323930088Sminshall { "interrupt", "character to cause an Interrupt Process", &ntc.t_intrc },
324030088Sminshall { "kill", "character to cause an Erase Line", &nttyb.sg_kill },
324130088Sminshall { "quit", "character to cause a Break", &ntc.t_quitc },
324230088Sminshall { "eof", "character to cause an EOF ", &ntc.t_eofc },
324331124Sminshall #endif /* defined(unix) */
324431124Sminshall #if defined(MSDOS)
324531124Sminshall { "erase", "character to cause an Erase Character", &termEraseChar },
324631124Sminshall { "flushoutput", "character to cause an Abort Oubput", &termFlushChar },
324731124Sminshall { "interrupt", "character to cause an Interrupt Process", &termIntChar },
324831124Sminshall { "kill", "character to cause an Erase Line", &termKillChar },
324931124Sminshall { "quit", "character to cause a Break", &termQuitChar },
325031124Sminshall { "eof", "character to cause an EOF ", &termEofChar },
325131124Sminshall #endif /* defined(MSDOS) */
325230088Sminshall { 0 }
325330088Sminshall };
325430088Sminshall
325530088Sminshall static char **
getnextset(name)325630088Sminshall getnextset(name)
325730088Sminshall char *name;
325830088Sminshall {
325930088Sminshall struct setlist *c = (struct setlist *)name;
326030088Sminshall
326130088Sminshall return (char **) (c+1);
326230088Sminshall }
326330088Sminshall
326430088Sminshall static struct setlist *
getset(name)326530088Sminshall getset(name)
326630088Sminshall char *name;
326730088Sminshall {
326830088Sminshall return (struct setlist *) genget(name, (char **) Setlist, getnextset);
326930088Sminshall }
327030088Sminshall
327130088Sminshall static
setcmd(argc,argv)327230088Sminshall setcmd(argc, argv)
327330088Sminshall int argc;
327430088Sminshall char *argv[];
327530088Sminshall {
327630088Sminshall int value;
327730088Sminshall struct setlist *ct;
327830088Sminshall
327930088Sminshall /* XXX back we go... sigh */
328030088Sminshall if (argc != 3) {
328130088Sminshall if ((argc == 2) &&
328230088Sminshall ((!strcmp(argv[1], "?")) || (!strcmp(argv[1], "help")))) {
328330088Sminshall for (ct = Setlist; ct->name; ct++) {
328430088Sminshall printf("%s\t%s\n", ct->name, ct->help);
328530088Sminshall }
328630088Sminshall printf("?\tdisplay help information\n");
328730088Sminshall } else {
328830088Sminshall printf("Format is 'set Name Value'\n'set ?' for help.\n");
328930088Sminshall }
329030088Sminshall return 0;
329130088Sminshall }
329230088Sminshall
329330088Sminshall ct = getset(argv[1]);
329430088Sminshall if (ct == 0) {
329530088Sminshall fprintf(stderr, "'%s': unknown argument ('set ?' for help).\n",
329630088Sminshall argv[1]);
329730088Sminshall return 0;
329830088Sminshall } else if (ct == Ambiguous(struct setlist *)) {
329930088Sminshall fprintf(stderr, "'%s': ambiguous argument ('set ?' for help).\n",
330030088Sminshall argv[1]);
330130088Sminshall return 0;
330230088Sminshall } else {
330330088Sminshall if (strcmp("off", argv[2])) {
330430088Sminshall value = special(argv[2]);
330530088Sminshall } else {
330630088Sminshall value = -1;
330730088Sminshall }
330830088Sminshall *(ct->charp) = value;
330930088Sminshall printf("%s character is '%s'.\n", ct->name, control(*(ct->charp)));
331030088Sminshall }
331130088Sminshall return 1;
331230088Sminshall }
331330088Sminshall
331430088Sminshall /*
331530088Sminshall * The following are the data structures and routines for the
331630088Sminshall * 'mode' command.
331730088Sminshall */
331830088Sminshall
331930088Sminshall static
dolinemode()332030088Sminshall dolinemode()
332130088Sminshall {
332230088Sminshall if (hisopts[TELOPT_SGA]) {
332330088Sminshall wontoption(TELOPT_SGA, 0);
332430088Sminshall }
332530088Sminshall if (hisopts[TELOPT_ECHO]) {
332630088Sminshall wontoption(TELOPT_ECHO, 0);
332730088Sminshall }
332830088Sminshall return 1;
332930088Sminshall }
333030088Sminshall
333130088Sminshall static
docharmode()333230088Sminshall docharmode()
333330088Sminshall {
333430088Sminshall if (!hisopts[TELOPT_SGA]) {
333530088Sminshall willoption(TELOPT_SGA, 0);
333630088Sminshall }
333730088Sminshall if (!hisopts[TELOPT_ECHO]) {
333830088Sminshall willoption(TELOPT_ECHO, 0);
333930088Sminshall }
334030088Sminshall return 1;
334130088Sminshall }
334230088Sminshall
334330088Sminshall static struct cmd Modelist[] = {
334430088Sminshall { "character", "character-at-a-time mode", docharmode, 1, 1 },
334530088Sminshall { "line", "line-by-line mode", dolinemode, 1, 1 },
334630088Sminshall { 0 },
334730088Sminshall };
334830088Sminshall
334930088Sminshall static char **
getnextmode(name)335030088Sminshall getnextmode(name)
335130088Sminshall char *name;
335230088Sminshall {
335330088Sminshall struct cmd *c = (struct cmd *) name;
335430088Sminshall
335530088Sminshall return (char **) (c+1);
335630088Sminshall }
335730088Sminshall
335830088Sminshall static struct cmd *
getmodecmd(name)335930088Sminshall getmodecmd(name)
336030088Sminshall char *name;
336130088Sminshall {
336230088Sminshall return (struct cmd *) genget(name, (char **) Modelist, getnextmode);
336330088Sminshall }
336430088Sminshall
336530088Sminshall static
modecmd(argc,argv)336630088Sminshall modecmd(argc, argv)
336730088Sminshall int argc;
336830088Sminshall char *argv[];
336930088Sminshall {
337030088Sminshall struct cmd *mt;
337130088Sminshall
337230088Sminshall if ((argc != 2) || !strcmp(argv[1], "?") || !strcmp(argv[1], "help")) {
337330088Sminshall printf("format is: 'mode Mode', where 'Mode' is one of:\n\n");
337430088Sminshall for (mt = Modelist; mt->name; mt++) {
337530088Sminshall printf("%s\t%s\n", mt->name, mt->help);
337630088Sminshall }
337730088Sminshall return 0;
337830088Sminshall }
337930088Sminshall mt = getmodecmd(argv[1]);
338030088Sminshall if (mt == 0) {
338130088Sminshall fprintf(stderr, "Unknown mode '%s' ('mode ?' for help).\n", argv[1]);
338230088Sminshall return 0;
338330088Sminshall } else if (mt == Ambiguous(struct cmd *)) {
338430088Sminshall fprintf(stderr, "Ambiguous mode '%s' ('mode ?' for help).\n", argv[1]);
338530088Sminshall return 0;
338630088Sminshall } else {
338730088Sminshall (*mt->handler)();
338830088Sminshall }
338930088Sminshall return 1;
339030088Sminshall }
339130088Sminshall
339230088Sminshall /*
339330088Sminshall * The following data structures and routines implement the
339430088Sminshall * "display" command.
339530088Sminshall */
339630088Sminshall
339730088Sminshall static
display(argc,argv)339830088Sminshall display(argc, argv)
339930088Sminshall int argc;
340030088Sminshall char *argv[];
340130088Sminshall {
340230088Sminshall #define dotog(tl) if (tl->variable && tl->actionexplanation) { \
340330088Sminshall if (*tl->variable) { \
340430088Sminshall printf("will"); \
340530088Sminshall } else { \
340630088Sminshall printf("won't"); \
340730088Sminshall } \
340830088Sminshall printf(" %s.\n", tl->actionexplanation); \
340930088Sminshall }
341030088Sminshall
341130088Sminshall #define doset(sl) if (sl->name && *sl->name != ' ') { \
341230088Sminshall printf("[%s]\t%s.\n", control(*sl->charp), sl->name); \
341330088Sminshall }
341430088Sminshall
341530088Sminshall struct togglelist *tl;
341630088Sminshall struct setlist *sl;
341730088Sminshall
341830088Sminshall if (argc == 1) {
341930088Sminshall for (tl = Togglelist; tl->name; tl++) {
342030088Sminshall dotog(tl);
342130088Sminshall }
342230088Sminshall printf("\n");
342330088Sminshall for (sl = Setlist; sl->name; sl++) {
342430088Sminshall doset(sl);
342530088Sminshall }
342630088Sminshall } else {
342730088Sminshall int i;
342830088Sminshall
342930088Sminshall for (i = 1; i < argc; i++) {
343030088Sminshall sl = getset(argv[i]);
343130088Sminshall tl = gettoggle(argv[i]);
343230088Sminshall if ((sl == Ambiguous(struct setlist *)) ||
343330088Sminshall (tl == Ambiguous(struct togglelist *))) {
343430088Sminshall printf("?Ambiguous argument '%s'.\n", argv[i]);
343530088Sminshall return 0;
343630088Sminshall } else if (!sl && !tl) {
343730088Sminshall printf("?Unknown argument '%s'.\n", argv[i]);
343830088Sminshall return 0;
343930088Sminshall } else {
344030088Sminshall if (tl) {
344130088Sminshall dotog(tl);
344230088Sminshall }
344330088Sminshall if (sl) {
344430088Sminshall doset(sl);
344530088Sminshall }
344630088Sminshall }
344730088Sminshall }
344830088Sminshall }
344930088Sminshall return 1;
345030088Sminshall #undef doset
345130088Sminshall #undef dotog
345230088Sminshall }
345330088Sminshall
345430088Sminshall /*
345530088Sminshall * The following are the data structures, and many of the routines,
345630088Sminshall * relating to command processing.
345730088Sminshall */
345830088Sminshall
345930088Sminshall /*
346030088Sminshall * Set the escape character.
346130088Sminshall */
346230088Sminshall static
setescape(argc,argv)346330088Sminshall setescape(argc, argv)
346430088Sminshall int argc;
346530088Sminshall char *argv[];
346630088Sminshall {
346730088Sminshall register char *arg;
346830088Sminshall char buf[50];
346930088Sminshall
347030088Sminshall printf(
347130088Sminshall "Deprecated usage - please use 'set escape%s%s' in the future.\n",
347230088Sminshall (argc > 2)? " ":"", (argc > 2)? argv[1]: "");
347330088Sminshall if (argc > 2)
347430088Sminshall arg = argv[1];
347530088Sminshall else {
347630088Sminshall printf("new escape character: ");
347730088Sminshall gets(buf);
347830088Sminshall arg = buf;
347930088Sminshall }
348030088Sminshall if (arg[0] != '\0')
348130088Sminshall escape = arg[0];
348230088Sminshall if (!In3270) {
348330088Sminshall printf("Escape character is '%s'.\n", control(escape));
348430088Sminshall }
348530088Sminshall fflush(stdout);
348630088Sminshall return 1;
348730088Sminshall }
348830088Sminshall
348930088Sminshall /*VARARGS*/
349030088Sminshall static
togcrmod()349130088Sminshall togcrmod()
349230088Sminshall {
349330088Sminshall crmod = !crmod;
349430088Sminshall printf("Deprecated usage - please use 'toggle crmod' in the future.\n");
349530088Sminshall printf("%s map carriage return on output.\n", crmod ? "Will" : "Won't");
349630088Sminshall fflush(stdout);
349730088Sminshall return 1;
349830088Sminshall }
349930088Sminshall
350030088Sminshall /*VARARGS*/
suspend()350130088Sminshall suspend()
350230088Sminshall {
350330088Sminshall setcommandmode();
350430088Sminshall #if defined(unix)
350530088Sminshall kill(0, SIGTSTP);
350631215Sminshall #endif /* defined(unix) */
350731124Sminshall /* reget parameters in case they were changed */
350831124Sminshall TerminalSaveState();
350931215Sminshall setconnmode();
351030088Sminshall return 1;
351130088Sminshall }
351230088Sminshall
351330088Sminshall /*VARARGS*/
351430088Sminshall static
bye(argc,argv)351530326Sminshall bye(argc, argv)
351630326Sminshall int argc; /* Number of arguments */
351730326Sminshall char *argv[]; /* arguments */
351830088Sminshall {
351930088Sminshall if (connected) {
352030088Sminshall shutdown(net, 2);
352130088Sminshall printf("Connection closed.\n");
352231131Sminshall NetClose(net);
352330088Sminshall connected = 0;
352430088Sminshall /* reset options */
352530326Sminshall tninit();
352630088Sminshall #if defined(TN3270)
352730326Sminshall SetIn3270(); /* Get out of 3270 mode */
352830088Sminshall #endif /* defined(TN3270) */
352930088Sminshall }
353030326Sminshall if ((argc != 2) || (strcmp(argv[1], "fromquit") != 0)) {
353130326Sminshall longjmp(toplevel, 1);
353230326Sminshall /* NOTREACHED */
353330326Sminshall }
353430326Sminshall return 1; /* Keep lint, etc., happy */
353530088Sminshall }
353630088Sminshall
353730088Sminshall /*VARARGS*/
quit()353830088Sminshall quit()
353930088Sminshall {
354030326Sminshall (void) call(bye, "bye", "fromquit", 0);
354130088Sminshall Exit(0);
354230088Sminshall /*NOTREACHED*/
354330088Sminshall return 1; /* just to keep lint happy */
354430088Sminshall }
354530088Sminshall
354630088Sminshall /*
354730088Sminshall * Print status about the connection.
354830088Sminshall */
354930088Sminshall static
status(argc,argv)355030088Sminshall status(argc, argv)
355130088Sminshall int argc;
355230088Sminshall char *argv[];
355330088Sminshall {
355430088Sminshall if (connected) {
355530088Sminshall printf("Connected to %s.\n", hostname);
355630088Sminshall if (argc < 2) {
355730088Sminshall printf("Operating in %s.\n",
355830088Sminshall modelist[getconnmode()].modedescriptions);
355930088Sminshall if (localchars) {
356030088Sminshall printf("Catching signals locally.\n");
356130088Sminshall }
356230088Sminshall }
356330088Sminshall } else {
356430088Sminshall printf("No connection.\n");
356530088Sminshall }
356630088Sminshall # if !defined(TN3270)
356730088Sminshall printf("Escape character is '%s'.\n", control(escape));
356830088Sminshall fflush(stdout);
356930088Sminshall # else /* !defined(TN3270) */
357030088Sminshall if ((!In3270) && ((argc < 2) || strcmp(argv[1], "notmuch"))) {
357130088Sminshall printf("Escape character is '%s'.\n", control(escape));
357230088Sminshall }
357330088Sminshall # if defined(unix)
357430088Sminshall if (In3270 && transcom) {
357530088Sminshall printf("Transparent mode command is '%s'.\n", transcom);
357630088Sminshall }
357730088Sminshall # endif /* defined(unix) */
357830088Sminshall fflush(stdout);
357930088Sminshall if (In3270) {
358030088Sminshall return 0;
358130088Sminshall }
358230088Sminshall # endif /* defined(TN3270) */
358330088Sminshall return 1;
358430088Sminshall }
358530088Sminshall
358630088Sminshall #if defined(TN3270) && defined(unix)
358730088Sminshall static
settranscom(argc,argv)358830088Sminshall settranscom(argc, argv)
358930088Sminshall int argc;
359030088Sminshall char *argv[];
359130088Sminshall {
359230088Sminshall int i, len = 0;
359330088Sminshall char *strcpy(), *strcat();
359430088Sminshall
359530088Sminshall if (argc == 1 && transcom) {
359630088Sminshall transcom = 0;
359730088Sminshall }
359830088Sminshall if (argc == 1) {
359930088Sminshall return;
360030088Sminshall }
360130088Sminshall for (i = 1; i < argc; ++i) {
360230088Sminshall len += 1 + strlen(argv[1]);
360330088Sminshall }
360430088Sminshall transcom = tline;
360530088Sminshall (void) strcpy(transcom, argv[1]);
360630088Sminshall for (i = 2; i < argc; ++i) {
360730088Sminshall (void) strcat(transcom, " ");
360830088Sminshall (void) strcat(transcom, argv[i]);
360930088Sminshall }
361030088Sminshall }
361130088Sminshall #endif /* defined(TN3270) && defined(unix) */
361230088Sminshall
361330088Sminshall
361431169Sminshall
361530088Sminshall static
tn(argc,argv)361630088Sminshall tn(argc, argv)
361730088Sminshall int argc;
361830088Sminshall char *argv[];
361930088Sminshall {
362030088Sminshall register struct hostent *host = 0;
362131131Sminshall #if defined(MSDOS)
362230088Sminshall char *cp;
362331131Sminshall #endif /* defined(MSDOS) */
362430088Sminshall
362530088Sminshall if (connected) {
362630088Sminshall printf("?Already connected to %s\n", hostname);
362730088Sminshall return 0;
362830088Sminshall }
362930088Sminshall if (argc < 2) {
363030088Sminshall (void) strcpy(line, "Connect ");
363130088Sminshall printf("(to) ");
363230088Sminshall gets(&line[strlen(line)]);
363330088Sminshall makeargv();
363430088Sminshall argc = margc;
363530088Sminshall argv = margv;
363630088Sminshall }
363731793Sminshall if ((argc < 2) || (argc > 3)) {
363830088Sminshall printf("usage: %s host-name [port]\n", argv[0]);
363930088Sminshall return 0;
364030088Sminshall }
364131131Sminshall #if defined(MSDOS)
364230088Sminshall for (cp = argv[1]; *cp; cp++) {
364330088Sminshall if (isupper(*cp)) {
364430088Sminshall *cp = tolower(*cp);
364530088Sminshall }
364630088Sminshall }
364731131Sminshall #endif /* defined(MSDOS) */
364830088Sminshall sin.sin_addr.s_addr = inet_addr(argv[1]);
364930088Sminshall if (sin.sin_addr.s_addr != -1) {
365030088Sminshall sin.sin_family = AF_INET;
365130088Sminshall (void) strcpy(hnamebuf, argv[1]);
365230088Sminshall hostname = hnamebuf;
365330088Sminshall } else {
365430088Sminshall host = gethostbyname(argv[1]);
365530088Sminshall if (host) {
365630088Sminshall sin.sin_family = host->h_addrtype;
365730088Sminshall #if defined(h_addr) /* In 4.3, this is a #define */
365831131Sminshall memcpy((caddr_t)&sin.sin_addr,
365931131Sminshall host->h_addr_list[0], host->h_length);
366030088Sminshall #else /* defined(h_addr) */
366131131Sminshall memcpy((caddr_t)&sin.sin_addr, host->h_addr, host->h_length);
366230088Sminshall #endif /* defined(h_addr) */
366330088Sminshall hostname = host->h_name;
366430088Sminshall } else {
366530088Sminshall printf("%s: unknown host\n", argv[1]);
366630088Sminshall return 0;
366730088Sminshall }
366830088Sminshall }
366930088Sminshall sin.sin_port = sp->s_port;
367030088Sminshall if (argc == 3) {
367130088Sminshall sin.sin_port = atoi(argv[2]);
367230088Sminshall if (sin.sin_port == 0) {
367330088Sminshall sp = getservbyname(argv[2], "tcp");
367430088Sminshall if (sp)
367530088Sminshall sin.sin_port = sp->s_port;
367630088Sminshall else {
367730088Sminshall printf("%s: bad port number\n", argv[2]);
367830088Sminshall return 0;
367930088Sminshall }
368030088Sminshall } else {
368130088Sminshall sin.sin_port = atoi(argv[2]);
368230088Sminshall sin.sin_port = htons(sin.sin_port);
368330088Sminshall }
368430088Sminshall telnetport = 0;
368530088Sminshall } else {
368630088Sminshall telnetport = 1;
368730088Sminshall }
368830088Sminshall #if defined(unix)
368930088Sminshall signal(SIGINT, intr);
369030088Sminshall signal(SIGQUIT, intr2);
369130088Sminshall signal(SIGPIPE, deadpeer);
369230088Sminshall #endif /* defined(unix) */
369330088Sminshall printf("Trying...\n");
369430088Sminshall do {
369530088Sminshall net = socket(AF_INET, SOCK_STREAM, 0);
369630088Sminshall if (net < 0) {
369730088Sminshall perror("telnet: socket");
369830088Sminshall return 0;
369930088Sminshall }
370031124Sminshall if (debug && SetSockOpt(net, SOL_SOCKET, SO_DEBUG, 1) < 0) {
370130088Sminshall perror("setsockopt (SO_DEBUG)");
370231124Sminshall }
370330088Sminshall
370430088Sminshall if (connect(net, (struct sockaddr *)&sin, sizeof (sin)) < 0) {
370530088Sminshall #if defined(h_addr) /* In 4.3, this is a #define */
370630088Sminshall if (host && host->h_addr_list[1]) {
370730088Sminshall int oerrno = errno;
370830088Sminshall
370930088Sminshall fprintf(stderr, "telnet: connect to address %s: ",
371030088Sminshall inet_ntoa(sin.sin_addr));
371130088Sminshall errno = oerrno;
371230088Sminshall perror((char *)0);
371330088Sminshall host->h_addr_list++;
371431131Sminshall memcpy((caddr_t)&sin.sin_addr,
371531131Sminshall host->h_addr_list[0], host->h_length);
371630088Sminshall fprintf(stderr, "Trying %s...\n",
371730088Sminshall inet_ntoa(sin.sin_addr));
371831131Sminshall (void) NetClose(net);
371930088Sminshall continue;
372030088Sminshall }
372130088Sminshall #endif /* defined(h_addr) */
372230088Sminshall perror("telnet: Unable to connect to remote host");
372330088Sminshall #if defined(unix)
372430088Sminshall signal(SIGINT, SIG_DFL);
372530088Sminshall signal(SIGQUIT, SIG_DFL);
372630320Sminshall #endif /* defined(unix) */
372730088Sminshall return 0;
372830088Sminshall }
372930088Sminshall connected++;
373030088Sminshall } while (connected == 0);
373130088Sminshall call(status, "status", "notmuch", 0);
373230088Sminshall if (setjmp(peerdied) == 0)
373330088Sminshall telnet();
373431131Sminshall NetClose(net);
373530088Sminshall ExitString(stderr, "Connection closed by foreign host.\n",1);
373630088Sminshall /*NOTREACHED*/
373730088Sminshall }
373830088Sminshall
373930088Sminshall
374030088Sminshall #define HELPINDENT (sizeof ("connect"))
374130088Sminshall
374230088Sminshall static char
374330088Sminshall openhelp[] = "connect to a site",
374430088Sminshall closehelp[] = "close current connection",
374530088Sminshall quithelp[] = "exit telnet",
374630088Sminshall statushelp[] = "print status information",
374730088Sminshall helphelp[] = "print help information",
374830088Sminshall sendhelp[] = "transmit special characters ('send ?' for more)",
374930088Sminshall sethelp[] = "set operating parameters ('set ?' for more)",
375030088Sminshall togglestring[] ="toggle operating parameters ('toggle ?' for more)",
375130088Sminshall displayhelp[] = "display operating parameters",
375230088Sminshall #if defined(TN3270) && defined(unix)
375330088Sminshall transcomhelp[] = "specify Unix command for transparent mode pipe",
375430088Sminshall #endif /* defined(TN3270) && defined(unix) */
375531169Sminshall #if defined(unix)
375631169Sminshall zhelp[] = "suspend telnet",
375731169Sminshall #endif /* defined(unix */
375831478Sminshall #if defined(TN3270)
375931169Sminshall shellhelp[] = "invoke a subshell",
376031478Sminshall #endif /* defined(TN3270) */
376130088Sminshall modehelp[] = "try to enter line-by-line or character-at-a-time mode";
376230088Sminshall
376331169Sminshall extern int help(), shell();
376430088Sminshall
376530088Sminshall static struct cmd cmdtab[] = {
376630088Sminshall { "close", closehelp, bye, 1, 1 },
376730088Sminshall { "display", displayhelp, display, 1, 0 },
376830088Sminshall { "mode", modehelp, modecmd, 1, 1 },
376930088Sminshall { "open", openhelp, tn, 1, 0 },
377030088Sminshall { "quit", quithelp, quit, 1, 0 },
377130088Sminshall { "send", sendhelp, sendcmd, 1, 1 },
377230088Sminshall { "set", sethelp, setcmd, 1, 0 },
377330088Sminshall { "status", statushelp, status, 1, 0 },
377430088Sminshall { "toggle", togglestring, toggle, 1, 0 },
377530088Sminshall #if defined(TN3270) && defined(unix)
377630088Sminshall { "transcom", transcomhelp, settranscom, 1, 0 },
377730088Sminshall #endif /* defined(TN3270) && defined(unix) */
377831169Sminshall #if defined(unix)
377930088Sminshall { "z", zhelp, suspend, 1, 0 },
378031169Sminshall #endif /* defined(unix) */
378131478Sminshall #if defined(TN3270)
378231478Sminshall { "!", shellhelp, shell, 1, 1 },
378331478Sminshall #endif /* defined(TN3270) */
378430088Sminshall { "?", helphelp, help, 1, 0 },
378530088Sminshall 0
378630088Sminshall };
378730088Sminshall
378830088Sminshall static char crmodhelp[] = "deprecated command -- use 'toggle crmod' instead";
378930088Sminshall static char escapehelp[] = "deprecated command -- use 'set escape' instead";
379030088Sminshall
379130088Sminshall static struct cmd cmdtab2[] = {
379230088Sminshall { "help", helphelp, help, 0, 0 },
379330088Sminshall { "escape", escapehelp, setescape, 1, 0 },
379430088Sminshall { "crmod", crmodhelp, togcrmod, 1, 0 },
379530088Sminshall 0
379630088Sminshall };
379730088Sminshall
379830088Sminshall /*
379930088Sminshall * Call routine with argc, argv set from args (terminated by 0).
380030088Sminshall * VARARGS2
380130088Sminshall */
380230088Sminshall static
380330088Sminshall call(routine, args)
380430088Sminshall int (*routine)();
380530088Sminshall char *args;
380630088Sminshall {
380730088Sminshall register char **argp;
380830088Sminshall register int argc;
380930088Sminshall
381030088Sminshall for (argc = 0, argp = &args; *argp++ != 0; argc++)
381130088Sminshall ;
381230088Sminshall return (*routine)(argc, &args);
381330088Sminshall }
381430088Sminshall
381530088Sminshall static char **
getnextcmd(name)381630088Sminshall getnextcmd(name)
381730088Sminshall char *name;
381830088Sminshall {
381930088Sminshall struct cmd *c = (struct cmd *) name;
382030088Sminshall
382130088Sminshall return (char **) (c+1);
382230088Sminshall }
382330088Sminshall
382430088Sminshall static struct cmd *
getcmd(name)382530088Sminshall getcmd(name)
382630088Sminshall char *name;
382730088Sminshall {
382830088Sminshall struct cmd *cm;
382930088Sminshall
383030088Sminshall if ((cm = (struct cmd *) genget(name, (char **) cmdtab, getnextcmd)) != 0) {
383130088Sminshall return cm;
383230088Sminshall } else {
383330088Sminshall return (struct cmd *) genget(name, (char **) cmdtab2, getnextcmd);
383430088Sminshall }
383530088Sminshall }
383630088Sminshall
383730088Sminshall void
command(top)383830088Sminshall command(top)
383930088Sminshall int top;
384030088Sminshall {
384131478Sminshall register struct cmd *c;
384230088Sminshall
384331478Sminshall setcommandmode();
384431478Sminshall if (!top) {
384531478Sminshall putchar('\n');
384631478Sminshall } else {
384730088Sminshall #if defined(unix)
384831478Sminshall signal(SIGINT, SIG_DFL);
384931478Sminshall signal(SIGQUIT, SIG_DFL);
385030088Sminshall #endif /* defined(unix) */
385131478Sminshall }
385231478Sminshall for (;;) {
385331478Sminshall printf("%s> ", prompt);
385431478Sminshall if (gets(line) == NULL) {
385531478Sminshall if (feof(stdin) || ferror(stdin))
385631478Sminshall quit();
385731478Sminshall break;
385830088Sminshall }
385931478Sminshall if (line[0] == 0)
386031478Sminshall break;
386131478Sminshall makeargv();
386231478Sminshall c = getcmd(margv[0]);
386331478Sminshall if (c == Ambiguous(struct cmd *)) {
386431478Sminshall printf("?Ambiguous command\n");
386531478Sminshall continue;
386630088Sminshall }
386731478Sminshall if (c == 0) {
386831478Sminshall printf("?Invalid command\n");
386931478Sminshall continue;
387030088Sminshall }
387131478Sminshall if (c->needconnect && !connected) {
387231478Sminshall printf("?Need to be connected first.\n");
387331478Sminshall continue;
387431478Sminshall }
387531478Sminshall if ((*c->handler)(margc, margv)) {
387631478Sminshall break;
387731478Sminshall }
387831478Sminshall }
387931478Sminshall if (!top) {
388031478Sminshall if (!connected) {
388131478Sminshall longjmp(toplevel, 1);
388231478Sminshall /*NOTREACHED*/
388331478Sminshall }
388431478Sminshall if (shell_active == 0) {
388531478Sminshall setconnmode();
388631478Sminshall }
388731478Sminshall }
388830088Sminshall }
388930088Sminshall
389030088Sminshall /*
389130088Sminshall * Help command.
389230088Sminshall */
389330088Sminshall static
help(argc,argv)389430088Sminshall help(argc, argv)
389530088Sminshall int argc;
389630088Sminshall char *argv[];
389730088Sminshall {
389830088Sminshall register struct cmd *c;
389930088Sminshall
390030088Sminshall if (argc == 1) {
390130088Sminshall printf("Commands may be abbreviated. Commands are:\n\n");
390230088Sminshall for (c = cmdtab; c->name; c++)
390330088Sminshall if (c->dohelp) {
390430088Sminshall printf("%-*s\t%s\n", HELPINDENT, c->name,
390530088Sminshall c->help);
390630088Sminshall }
390730088Sminshall return 0;
390830088Sminshall }
390930088Sminshall while (--argc > 0) {
391030088Sminshall register char *arg;
391130088Sminshall arg = *++argv;
391230088Sminshall c = getcmd(arg);
391330088Sminshall if (c == Ambiguous(struct cmd *))
391430088Sminshall printf("?Ambiguous help command %s\n", arg);
391530088Sminshall else if (c == (struct cmd *)0)
391630088Sminshall printf("?Invalid help command %s\n", arg);
391730088Sminshall else
391830088Sminshall printf("%s\n", c->help);
391930088Sminshall }
392030088Sminshall return 0;
392130088Sminshall }
392230088Sminshall
392330088Sminshall /*
392430088Sminshall * main. Parse arguments, invoke the protocol or command parser.
392530088Sminshall */
392630088Sminshall
392730088Sminshall
392830088Sminshall void
main(argc,argv)392930088Sminshall main(argc, argv)
393030088Sminshall int argc;
393130088Sminshall char *argv[];
393230088Sminshall {
393330326Sminshall tninit(); /* Clear out things */
393430326Sminshall
393530088Sminshall NetTrace = stdout;
393631124Sminshall TerminalSaveState();
393731124Sminshall autoflush = TerminalAutoFlush();
393831124Sminshall
393930088Sminshall prompt = argv[0];
394031478Sminshall while ((argc > 1) && (argv[1][0] == '-')) {
394131478Sminshall if (!strcmp(argv[1], "-d")) {
394231478Sminshall debug = 1;
394331478Sminshall } else if (!strcmp(argv[1], "-n")) {
394431510Sminshall if ((argc > 1) && (argv[2][0] != '-')) { /* get file name */
394531510Sminshall NetTrace = fopen(argv[2], "w");
394631478Sminshall argv++;
394731478Sminshall argc--;
394831478Sminshall if (NetTrace == NULL) {
394931478Sminshall NetTrace = stdout;
395031478Sminshall }
395130088Sminshall }
395231478Sminshall } else {
395331478Sminshall #if defined(TN3270) && defined(unix)
395431478Sminshall if (!strcmp(argv[1], "-t")) {
395531978Sminshall if ((argc > 1) && (argv[2][0] != '-')) { /* get file name */
395631478Sminshall transcom = tline;
395731478Sminshall (void) strcpy(transcom, argv[1]);
395831478Sminshall argv++;
395931478Sminshall argc--;
396031478Sminshall }
396131478Sminshall } else if (!strcmp(argv[1], "-noasynch")) {
396231478Sminshall noasynch = 1;
396331478Sminshall } else
396431478Sminshall #endif /* defined(TN3270) && defined(unix) */
396531478Sminshall if (argv[1][1] != '\0') {
396631478Sminshall fprintf(stderr, "Unknown option *%s*.\n", argv[1]);
396731478Sminshall }
396830088Sminshall }
396931478Sminshall argc--;
397030088Sminshall argv++;
397130088Sminshall }
397230088Sminshall if (argc != 1) {
397330088Sminshall if (setjmp(toplevel) != 0)
397430088Sminshall Exit(0);
397530088Sminshall tn(argc, argv);
397630088Sminshall }
397730088Sminshall setjmp(toplevel);
397831215Sminshall for (;;) {
397931215Sminshall #if !defined(TN3270)
398030088Sminshall command(1);
398131215Sminshall #else /* !defined(TN3270) */
398231215Sminshall if (!shell_active) {
398331215Sminshall command(1);
398431215Sminshall } else {
398531478Sminshall #if defined(TN3270)
398631215Sminshall shell_continue();
398731478Sminshall #endif /* defined(TN3270) */
398831215Sminshall }
398931215Sminshall #endif /* !defined(TN3270) */
399031215Sminshall }
399130088Sminshall }
3992