xref: /csrg-svn/usr.bin/tn3270/telnet.c (revision 30326)
130088Sminshall /*
230088Sminshall  *	Copyright (c) 1984, 1985, 1986 by the Regents of the
330088Sminshall  *	University of California and by Gregory Glenn Minshall.
430088Sminshall  *
530088Sminshall  *	Permission to use, copy, modify, and distribute these
630088Sminshall  *	programs and their documentation for any purpose and
730088Sminshall  *	without fee is hereby granted, provided that this
830088Sminshall  *	copyright and permission appear on all copies and
930088Sminshall  *	supporting documentation, the name of the Regents of
1030088Sminshall  *	the University of California not be used in advertising
1130088Sminshall  *	or publicity pertaining to distribution of the programs
1230088Sminshall  *	without specific prior permission, and notice be given in
1330088Sminshall  *	supporting documentation that copying and distribution is
1430088Sminshall  *	by permission of the Regents of the University of California
1530088Sminshall  *	and by Gregory Glenn Minshall.  Neither the Regents of the
1630088Sminshall  *	University of California nor Gregory Glenn Minshall make
1730088Sminshall  *	representations about the suitability of this software
1830088Sminshall  *	for any purpose.  It is provided "as is" without
1930088Sminshall  *	express or implied warranty.
2030088Sminshall  */
2130088Sminshall 
2230088Sminshall #ifndef lint
2330088Sminshall static char copyright[] =
2430088Sminshall "@(#) Copyright (c) 1984, 1985, 1986 Regents of the University of California.\n\
2530088Sminshall  All rights reserved.\n";
2630320Sminshall #endif	/* not lint */
2730088Sminshall 
2830088Sminshall #ifndef lint
2930088Sminshall static char sccsid[] = "@(#)telnet.c	3.1  10/29/86";
3030320Sminshall #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  *	DEBUG		-	Allow for some extra debugging operations.
4730088Sminshall  *
4830088Sminshall  *	NOT43		-	Allows the program to compile and run on
4930088Sminshall  *				a 4.2BSD system.
5030088Sminshall  *
5130088Sminshall  *	PUTCHAR		-	Within tn3270, on a NOT43 system,
5230088Sminshall  *				allows the use of the 4.3 curses
5330088Sminshall  *				(greater speed updating the screen).
5430088Sminshall  *				You need the 4.3 curses for this to work.
5530088Sminshall  *
5630088Sminshall  *	FD_SETSIZE	-	On whichever system, if this isn't defined,
5730088Sminshall  *				we patch over the FD_SET, etc., macros with
5830088Sminshall  *				some homebrewed ones.
5930088Sminshall  *
6030088Sminshall  *	SO_OOBINLINE	-	This is a socket option which we would like
6130088Sminshall  *				to set to allow TCP urgent data to come
6230088Sminshall  *				to us "inline".  This is NECESSARY for
6330088Sminshall  *				CORRECT operation, and desireable for
6430088Sminshall  *				simpler operation.
6530088Sminshall  *
6630088Sminshall  *	LNOFLSH		-	Detects the presence of the LNOFLSH bit
6730088Sminshall  *				in the tty structure.
6830088Sminshall  *
6930088Sminshall  *	unix		-	Compiles in unix specific stuff.
7030088Sminshall  *
7130088Sminshall  *	msdos		-	Compiles in msdos specific stuff.
7230088Sminshall  *
7330088Sminshall  */
7430088Sminshall 
7530088Sminshall #if	!defined(TN3270)
7630088Sminshall #define	ExitString(f,s,r)	{ fprintf(f, s); exit(r); }
7730088Sminshall #define	Exit(x)			exit(x)
7830088Sminshall #define	SetIn3270()
7930088Sminshall 
8030088Sminshall void	setcommandmode(), command();	/* forward declarations */
8130088Sminshall #endif	/* !defined(TN3270) */
8230088Sminshall 
8330088Sminshall #include <sys/types.h>
8430088Sminshall #include <sys/socket.h>
8530088Sminshall #include <sys/ioctl.h>
8630088Sminshall #include <sys/time.h>
8730088Sminshall 
8830088Sminshall #include <netinet/in.h>
8930088Sminshall 
9030088Sminshall #include <curses.h>
9130088Sminshall 
9230088Sminshall #define	TELOPTS
9330088Sminshall #include <arpa/telnet.h>
9430088Sminshall 
9530088Sminshall #if	!defined(NOT43)
9630088Sminshall #include <arpa/inet.h>
9730088Sminshall #else	/* !defined(NOT43) */
9830088Sminshall extern unsigned long inet_addr();
9930088Sminshall extern char	*inet_ntoa();
10030088Sminshall #endif	/* !defined(NOT43) */
10130088Sminshall 
10230088Sminshall #include <stdio.h>
10330088Sminshall #include <ctype.h>
10430088Sminshall #include <errno.h>
10530088Sminshall #include <signal.h>
10630088Sminshall #include <setjmp.h>
10730088Sminshall #include <netdb.h>
10830088Sminshall #include <strings.h>
10930088Sminshall 
11030088Sminshall #if	defined(TN3270)
11130088Sminshall #include "ctlr/screen.h"
11230088Sminshall #include "system/globals.h"
11330088Sminshall #include "telnet.ext"
11430088Sminshall #include "ctlr/options.ext"
11530088Sminshall #include "ctlr/outbound.ext"
11630088Sminshall #include "keyboard/termin.ext"
11730088Sminshall #endif	/* defined(TN3270) */
11830088Sminshall 
11930088Sminshall 
12030088Sminshall 
12130088Sminshall #ifndef	FD_SETSIZE
12230088Sminshall /*
12330088Sminshall  * The following is defined just in case someone should want to run
12430088Sminshall  * this telnet on a 4.2 system.
12530088Sminshall  *
12630088Sminshall  */
12730088Sminshall 
12830088Sminshall #define	FD_SET(n, p)	((p)->fds_bits[0] |= (1<<(n)))
12930088Sminshall #define	FD_CLR(n, p)	((p)->fds_bits[0] &= ~(1<<(n)))
13030088Sminshall #define	FD_ISSET(n, p)	((p)->fds_bits[0] & (1<<(n)))
13130088Sminshall #define FD_ZERO(p)	((p)->fds_bits[0] = 0)
13230088Sminshall 
13330088Sminshall #endif
13430088Sminshall 
13530088Sminshall #define	strip(x)	((x)&0x7f)
13630088Sminshall #define min(x,y)	((x<y)? x:y)
13730088Sminshall 
13830088Sminshall #if	defined(TN3270)
139*30326Sminshall static char	Ibuf[8*BUFSIZ], *Ifrontp, *Ibackp;
14030088Sminshall #endif	/* defined(TN3270) */
14130088Sminshall 
142*30326Sminshall static char	ttyobuf[2*BUFSIZ], *tfrontp, *tbackp;
14330088Sminshall #define	TTYADD(c)	{ if (!(SYNCHing||flushout)) { *tfrontp++ = c; } }
14430088Sminshall #define	TTYLOC()	(tfrontp)
14530088Sminshall #define	TTYMAX()	(ttyobuf+sizeof ttyobuf-1)
14630088Sminshall #define	TTYMIN()	(netobuf)
14730088Sminshall #define	TTYBYTES()	(tfrontp-tbackp)
14830088Sminshall #define	TTYROOM()	(TTYMAX()-TTYLOC()+1)
14930088Sminshall 
150*30326Sminshall static char	netobuf[2*BUFSIZ], *nfrontp, *nbackp;
15130088Sminshall #define	NETADD(c)	{ *nfrontp++ = c; }
15230088Sminshall #define	NET2ADD(c1,c2)	{ NETADD(c1); NETADD(c2); }
15330088Sminshall #define NETLOC()	(nfrontp)
15430088Sminshall #define	NETMAX()	(netobuf+sizeof netobuf-1)
15530088Sminshall #define	NETBYTES()	(nfrontp-nbackp)
15630088Sminshall #define	NETROOM()	(NETMAX()-NETLOC()+1)
157*30326Sminshall static char	*neturg;		/* one past last byte of urgent data */
15830088Sminshall 
159*30326Sminshall static char	subbuffer[100],
160*30326Sminshall 		*subpointer, *subend;	 /* buffer for sub-options */
16130088Sminshall #define	SB_CLEAR()	subpointer = subbuffer;
16230088Sminshall #define	SB_TERM()	subend = subpointer;
16330088Sminshall #define	SB_ACCUM(c)	if (subpointer < (subbuffer+sizeof subbuffer)) { \
16430088Sminshall 				*subpointer++ = (c); \
16530088Sminshall 			}
16630088Sminshall 
16730088Sminshall static char	sb_terminal[] = { IAC, SB,
16830088Sminshall 			TELOPT_TTYPE, TELQUAL_IS,
16930088Sminshall 			'I', 'B', 'M', '-', '3', '2', '7', '8', '-', '2',
17030088Sminshall 			IAC, SE };
17130088Sminshall #define	SBTERMMODEL	13
17230088Sminshall 
17330088Sminshall 
174*30326Sminshall static char	hisopts[256];
175*30326Sminshall static char	myopts[256];
17630088Sminshall 
17730088Sminshall static char	doopt[] = { IAC, DO, '%', 'c', 0 };
17830088Sminshall static char	dont[] = { IAC, DONT, '%', 'c', 0 };
17930088Sminshall static char	will[] = { IAC, WILL, '%', 'c', 0 };
18030088Sminshall static char	wont[] = { IAC, WONT, '%', 'c', 0 };
18130088Sminshall 
18230088Sminshall struct cmd {
18330088Sminshall 	char	*name;		/* command name */
18430088Sminshall 	char	*help;		/* help string */
18530088Sminshall 	int	(*handler)();	/* routine which executes command */
18630088Sminshall 	int	dohelp;		/* Should we give general help information? */
18730088Sminshall 	int	needconnect;	/* Do we need to be connected to execute? */
18830088Sminshall };
18930088Sminshall 
190*30326Sminshall static char	sibuf[BUFSIZ], *sbp;
19130088Sminshall static char	tibuf[BUFSIZ], *tbp;
19230088Sminshall static fd_set ibits, obits, xbits;
19330088Sminshall 
19430088Sminshall 
19530088Sminshall static int
196*30326Sminshall 	connected,
197*30326Sminshall 	net,
198*30326Sminshall 	scc,
199*30326Sminshall 	tcc,
200*30326Sminshall 	showoptions,
201*30326Sminshall 	In3270,		/* Are we in 3270 mode? */
202*30326Sminshall 	ISend,		/* trying to send network data in */
20330088Sminshall 	debug = 0,
204*30326Sminshall 	crmod,
205*30326Sminshall 	netdata,
20630088Sminshall 	telnetport = 1;
20730088Sminshall 
208*30326Sminshall static FILE	*NetTrace = 0;		/* Not in bss, since needs to stay */
20930088Sminshall 
21030088Sminshall #define	CONTROL(x)	((x)&0x1f)		/* CTRL(x) is not portable */
21130088Sminshall 
21230088Sminshall static char
21330088Sminshall 	*prompt = 0,
214*30326Sminshall 	escape,
215*30326Sminshall 	echoc;
21630088Sminshall 
21730088Sminshall static int
218*30326Sminshall 	SYNCHing,		/* we are in TELNET SYNCH mode */
219*30326Sminshall 	flushout,		/* flush output */
22030088Sminshall 	autoflush = 0,		/* flush output when interrupting? */
221*30326Sminshall 	autosynch,		/* send interrupt characters with SYNCH? */
222*30326Sminshall 	localchars,		/* we recognize interrupt/quit */
223*30326Sminshall 	donelclchars,	/* the user has set "localchars" */
224*30326Sminshall 	dontlecho;		/* do we suppress local echoing right now? */
22530088Sminshall 
22630088Sminshall /*	The following are some tn3270 specific flags */
22730088Sminshall #if	defined(TN3270)
22830088Sminshall 
22930088Sminshall static int
230*30326Sminshall 	Sent3270TerminalType;	/* Have we said we are a 3270? */
23130088Sminshall 
23230088Sminshall /* Some real, live, globals. */
23330088Sminshall int
23430088Sminshall #if	defined(unix)
235*30326Sminshall 	HaveInput,		/* There is input available to scan */
23630088Sminshall #endif	/* defined(unix) */
237*30326Sminshall 	tout,			/* Output file descriptor */
238*30326Sminshall 	tin;			/* Input file descriptor */
23930088Sminshall #if	defined(unix)
24030088Sminshall char	*transcom = 0;	/* transparent mode command (default: none) */
24130088Sminshall #endif	/* defined(unix) */
24230088Sminshall 
24330088Sminshall #else	/* defined(TN3270) */
244*30326Sminshall static int tin, tout;		/* file descriptors */
24530088Sminshall #endif	/* defined(TN3270) */
24630088Sminshall 
24730088Sminshall static char	line[200];
24830088Sminshall #if	defined(TN3270) && defined(unix)
24930088Sminshall static char	tline[200];
25030088Sminshall #endif	/* defined(TN3270) && defined(unix) */
251*30326Sminshall static int	margc;
25230088Sminshall static char	*margv[20];
25330088Sminshall 
254*30326Sminshall static jmp_buf	toplevel = 0;
25530088Sminshall static jmp_buf	peerdied;
25630088Sminshall 
25730088Sminshall extern	int errno;
25830088Sminshall 
25930088Sminshall 
26030088Sminshall static struct sockaddr_in sin;
26130088Sminshall 
26230088Sminshall static struct	servent *sp = 0;
26330088Sminshall 
26430088Sminshall static struct	tchars otc = { 0 }, ntc = { 0 };
26530088Sminshall static struct	ltchars oltc = { 0 }, nltc = { 0 };
26630088Sminshall static struct	sgttyb ottyb = { 0 }, nttyb = { 0 };
267*30326Sminshall static int	flushline;
26830088Sminshall 
269*30326Sminshall static char	*hostname;
27030088Sminshall static char	hnamebuf[32];
27130088Sminshall 
27230088Sminshall /*
27330088Sminshall  * The following are some clocks used to decide how to interpret
27430088Sminshall  * the relationship between various variables.
27530088Sminshall  */
27630088Sminshall 
27730088Sminshall static struct {
27830088Sminshall     int
27930088Sminshall 	system,			/* what the current time is */
28030088Sminshall 	echotoggle,		/* last time user entered echo character */
28130088Sminshall 	modenegotiated,		/* last time operating mode negotiated */
28230088Sminshall 	didnetreceive,		/* last time we read data from network */
28330088Sminshall 	gotDM;			/* when did we last see a data mark */
284*30326Sminshall } clocks;
28530088Sminshall 
28630088Sminshall #define	settimer(x)	clocks.x = clocks.system++
28730088Sminshall 
28830088Sminshall /*
289*30326Sminshall  * Initialize variables.
290*30326Sminshall  */
291*30326Sminshall 
292*30326Sminshall static void
293*30326Sminshall tninit()
294*30326Sminshall {
295*30326Sminshall     extern char edata, end;
296*30326Sminshall 
297*30326Sminshall     bzero(&edata, &end - &edata);
298*30326Sminshall     Ifrontp = Ibackp = Ibuf;
299*30326Sminshall     tfrontp = tbackp = ttyobuf;
300*30326Sminshall     nfrontp = nbackp = netobuf;
301*30326Sminshall 
302*30326Sminshall     /* Don't change telnetport */
303*30326Sminshall 
304*30326Sminshall     /* Don't change NetTrace */
305*30326Sminshall 
306*30326Sminshall     escape = CONTROL(']');
307*30326Sminshall     echoc = CONTROL('E');
308*30326Sminshall 
309*30326Sminshall     flushline = 1;
310*30326Sminshall     sp = getservbyname("telnet", "tcp");
311*30326Sminshall     if (sp == 0) {
312*30326Sminshall 	ExitString(stderr, "telnet: tcp/telnet: unknown service\n",1);
313*30326Sminshall 	/*NOTREACHED*/
314*30326Sminshall     }
315*30326Sminshall 
316*30326Sminshall #if	defined(TN3270)
317*30326Sminshall     terminit();
318*30326Sminshall     ctlrinit();
319*30326Sminshall #endif	/* defined(TN3270) */
320*30326Sminshall }
321*30326Sminshall 
322*30326Sminshall /*
32330088Sminshall  * Various utility routines.
32430088Sminshall  */
32530088Sminshall 
32630088Sminshall static void
32730088Sminshall makeargv()
32830088Sminshall {
32930088Sminshall 	register char *cp;
33030088Sminshall 	register char **argp = margv;
33130088Sminshall 
33230088Sminshall 	margc = 0;
33330088Sminshall 	for (cp = line; *cp;) {
33430088Sminshall 		while (isspace(*cp))
33530088Sminshall 			cp++;
33630088Sminshall 		if (*cp == '\0')
33730088Sminshall 			break;
33830088Sminshall 		*argp++ = cp;
33930088Sminshall 		margc += 1;
34030088Sminshall 		while (*cp != '\0' && !isspace(*cp))
34130088Sminshall 			cp++;
34230088Sminshall 		if (*cp == '\0')
34330088Sminshall 			break;
34430088Sminshall 		*cp++ = '\0';
34530088Sminshall 	}
34630088Sminshall 	*argp++ = 0;
34730088Sminshall }
34830088Sminshall 
34930088Sminshall static char *ambiguous;		/* special return value */
35030088Sminshall #define Ambiguous(t)	((t)&ambiguous)
35130088Sminshall 
35230088Sminshall 
35330088Sminshall static char **
35430088Sminshall genget(name, table, next)
35530088Sminshall char	*name;		/* name to match */
35630088Sminshall char	**table;		/* name entry in table */
35730088Sminshall char	**(*next)();	/* routine to return next entry in table */
35830088Sminshall {
35930088Sminshall 	register char *p, *q;
36030088Sminshall 	register char **c, **found;
36130088Sminshall 	register int nmatches, longest;
36230088Sminshall 
36330088Sminshall 	longest = 0;
36430088Sminshall 	nmatches = 0;
36530088Sminshall 	found = 0;
36630088Sminshall 	for (c = table; (p = *c) != 0; c = (*next)(c)) {
36730088Sminshall 		for (q = name;
36830088Sminshall 		    (*q == *p) || (isupper(*q) && tolower(*q) == *p); p++, q++)
36930088Sminshall 			if (*q == 0)		/* exact match? */
37030088Sminshall 				return (c);
37130088Sminshall 		if (!*q) {			/* the name was a prefix */
37230088Sminshall 			if (q - name > longest) {
37330088Sminshall 				longest = q - name;
37430088Sminshall 				nmatches = 1;
37530088Sminshall 				found = c;
37630088Sminshall 			} else if (q - name == longest)
37730088Sminshall 				nmatches++;
37830088Sminshall 		}
37930088Sminshall 	}
38030088Sminshall 	if (nmatches > 1)
38130088Sminshall 		return Ambiguous(char **);
38230088Sminshall 	return (found);
38330088Sminshall }
38430088Sminshall 
38530088Sminshall /*
38630088Sminshall  * Make a character string into a number.
38730088Sminshall  *
38830088Sminshall  * Todo:  1.  Could take random integers (12, 0x12, 012, 0b1).
38930088Sminshall  */
39030088Sminshall 
39130088Sminshall static
39230088Sminshall special(s)
39330088Sminshall register char *s;
39430088Sminshall {
39530088Sminshall 	register char c;
39630088Sminshall 	char b;
39730088Sminshall 
39830088Sminshall 	switch (*s) {
39930088Sminshall 	case '^':
40030088Sminshall 		b = *++s;
40130088Sminshall 		if (b == '?') {
40230088Sminshall 		    c = b | 0x40;		/* DEL */
40330088Sminshall 		} else {
40430088Sminshall 		    c = b & 0x1f;
40530088Sminshall 		}
40630088Sminshall 		break;
40730088Sminshall 	default:
40830088Sminshall 		c = *s;
40930088Sminshall 		break;
41030088Sminshall 	}
41130088Sminshall 	return c;
41230088Sminshall }
41330088Sminshall 
41430088Sminshall /*
41530088Sminshall  * Construct a control character sequence
41630088Sminshall  * for a special character.
41730088Sminshall  */
41830088Sminshall static char *
41930088Sminshall control(c)
42030088Sminshall 	register int c;
42130088Sminshall {
42230088Sminshall 	static char buf[3];
42330088Sminshall 
42430088Sminshall 	if (c == 0x7f)
42530088Sminshall 		return ("^?");
42630088Sminshall 	if (c == '\377') {
42730088Sminshall 		return "off";
42830088Sminshall 	}
42930088Sminshall 	if (c >= 0x20) {
43030088Sminshall 		buf[0] = c;
43130088Sminshall 		buf[1] = 0;
43230088Sminshall 	} else {
43330088Sminshall 		buf[0] = '^';
43430088Sminshall 		buf[1] = '@'+c;
43530088Sminshall 		buf[2] = 0;
43630088Sminshall 	}
43730088Sminshall 	return (buf);
43830088Sminshall }
43930088Sminshall 
44030088Sminshall 
44130088Sminshall /*
44230088Sminshall  * upcase()
44330088Sminshall  *
44430088Sminshall  *	Upcase (in place) the argument.
44530088Sminshall  */
44630088Sminshall 
44730088Sminshall static void
44830088Sminshall upcase(argument)
44930088Sminshall register char *argument;
45030088Sminshall {
45130088Sminshall     register int c;
45230088Sminshall 
45330088Sminshall     while ((c = *argument) != 0) {
45430088Sminshall 	if (islower(c)) {
45530088Sminshall 	    *argument = toupper(c);
45630088Sminshall 	}
45730088Sminshall 	argument++;
45830088Sminshall     }
45930088Sminshall }
46030088Sminshall 
46130088Sminshall /*
46230088Sminshall  * The following are routines used to print out debugging information.
46330088Sminshall  */
46430088Sminshall 
46530088Sminshall 
46630088Sminshall static void
46730088Sminshall Dump(direction, buffer, length)
46830088Sminshall char	direction;
46930088Sminshall char	*buffer;
47030088Sminshall int	length;
47130088Sminshall {
47230088Sminshall #   define BYTES_PER_LINE	32
47330088Sminshall #   define min(x,y)	((x<y)? x:y)
47430088Sminshall     char *pThis;
47530088Sminshall     int offset;
47630088Sminshall 
47730088Sminshall     offset = 0;
47830088Sminshall 
47930088Sminshall     while (length) {
48030088Sminshall 	/* print one line */
48130088Sminshall 	fprintf(NetTrace, "%c 0x%x\t", direction, offset);
48230088Sminshall 	pThis = buffer;
48330088Sminshall 	buffer = buffer+min(length, BYTES_PER_LINE);
48430088Sminshall 	while (pThis < buffer) {
48530088Sminshall 	    fprintf(NetTrace, "%.2x", (*pThis)&0xff);
48630088Sminshall 	    pThis++;
48730088Sminshall 	}
48830088Sminshall 	fprintf(NetTrace, "\n");
48930088Sminshall 	length -= BYTES_PER_LINE;
49030088Sminshall 	offset += BYTES_PER_LINE;
49130088Sminshall 	if (length < 0) {
49230088Sminshall 	    return;
49330088Sminshall 	}
49430088Sminshall 	/* find next unique line */
49530088Sminshall     }
49630088Sminshall }
49730088Sminshall 
49830088Sminshall 
49930088Sminshall /*VARARGS*/
50030088Sminshall static void
50130088Sminshall printoption(direction, fmt, option, what)
50230088Sminshall 	char *direction, *fmt;
50330088Sminshall 	int option, what;
50430088Sminshall {
50530088Sminshall 	if (!showoptions)
50630088Sminshall 		return;
50730088Sminshall 	fprintf(NetTrace, "%s ", direction+1);
50830088Sminshall 	if (fmt == doopt)
50930088Sminshall 		fmt = "do";
51030088Sminshall 	else if (fmt == dont)
51130088Sminshall 		fmt = "dont";
51230088Sminshall 	else if (fmt == will)
51330088Sminshall 		fmt = "will";
51430088Sminshall 	else if (fmt == wont)
51530088Sminshall 		fmt = "wont";
51630088Sminshall 	else
51730088Sminshall 		fmt = "???";
51830088Sminshall 	if (option < (sizeof telopts/sizeof telopts[0]))
51930088Sminshall 		fprintf(NetTrace, "%s %s", fmt, telopts[option]);
52030088Sminshall 	else
52130088Sminshall 		fprintf(NetTrace, "%s %d", fmt, option);
52230088Sminshall 	if (*direction == '<') {
52330088Sminshall 		fprintf(NetTrace, "\r\n");
52430088Sminshall 		return;
52530088Sminshall 	}
52630088Sminshall 	fprintf(NetTrace, " (%s)\r\n", what ? "reply" : "don't reply");
52730088Sminshall }
52830088Sminshall 
52930088Sminshall static void
53030088Sminshall printsub(direction, pointer, length)
53130088Sminshall char	*direction,		/* "<" or ">" */
53230088Sminshall 	*pointer;		/* where suboption data sits */
53330088Sminshall int	length;			/* length of suboption data */
53430088Sminshall {
53530088Sminshall     if (showoptions) {
53630088Sminshall 	fprintf(NetTrace, "%s suboption ",
53730088Sminshall 				(direction[0] == '<')? "Received":"Sent");
53830088Sminshall 	switch (pointer[0]) {
53930088Sminshall 	case TELOPT_TTYPE:
54030088Sminshall 	    fprintf(NetTrace, "Terminal type ");
54130088Sminshall 	    switch (pointer[1]) {
54230088Sminshall 	    case TELQUAL_IS:
54330088Sminshall 		{
54430088Sminshall 		    char tmpbuf[sizeof subbuffer];
54530088Sminshall 		    int minlen = min(length, sizeof tmpbuf);
54630088Sminshall 
54730088Sminshall 		    bcopy(pointer+2, tmpbuf, minlen);
54830088Sminshall 		    tmpbuf[minlen-1] = 0;
54930088Sminshall 		    fprintf(NetTrace, "is %s.\n", tmpbuf);
55030088Sminshall 		}
55130088Sminshall 		break;
55230088Sminshall 	    case TELQUAL_SEND:
55330088Sminshall 		fprintf(NetTrace, "- request to send.\n");
55430088Sminshall 		break;
55530088Sminshall 	    default:
55630088Sminshall 		fprintf(NetTrace,
55730088Sminshall 				"- unknown qualifier %d (0x%x).\n", pointer[1]);
55830088Sminshall 	    }
55930088Sminshall 	    break;
56030088Sminshall 	default:
56130088Sminshall 	    fprintf(NetTrace, "Unknown option %d (0x%x)\n",
56230088Sminshall 					pointer[0], pointer[0]);
56330088Sminshall 	}
56430088Sminshall     }
56530088Sminshall }
56630088Sminshall 
56730088Sminshall /*
56830088Sminshall  * Check to see if any out-of-band data exists on a socket (for
56930088Sminshall  * Telnet "synch" processing).
57030088Sminshall  */
57130088Sminshall 
57230088Sminshall static int
57330088Sminshall stilloob(s)
57430088Sminshall int	s;		/* socket number */
57530088Sminshall {
57630088Sminshall     static struct timeval timeout = { 0 };
57730088Sminshall     fd_set	excepts;
57830088Sminshall     int value;
57930088Sminshall 
58030088Sminshall     do {
58130088Sminshall 	FD_ZERO(&excepts);
58230088Sminshall 	FD_SET(s, &excepts);
58330088Sminshall 	value = select(s+1, (fd_set *)0, (fd_set *)0, &excepts, &timeout);
58430088Sminshall     } while ((value == -1) && (errno == EINTR));
58530088Sminshall 
58630088Sminshall     if (value < 0) {
58730088Sminshall 	perror("select");
58830088Sminshall 	quit();
58930088Sminshall     }
59030088Sminshall     if (FD_ISSET(s, &excepts)) {
59130088Sminshall 	return 1;
59230088Sminshall     } else {
59330088Sminshall 	return 0;
59430088Sminshall     }
59530088Sminshall }
59630088Sminshall 
59730088Sminshall 
59830088Sminshall /*
59930088Sminshall  *  netflush
60030088Sminshall  *		Send as much data as possible to the network,
60130088Sminshall  *	handling requests for urgent data.
60230088Sminshall  *
60330088Sminshall  *		The return value indicates whether we did any
60430088Sminshall  *	useful work.
60530088Sminshall  */
60630088Sminshall 
60730088Sminshall 
60830088Sminshall int
60930088Sminshall netflush()
61030088Sminshall {
61130088Sminshall     int n;
61230088Sminshall 
61330088Sminshall     if ((n = nfrontp - nbackp) > 0) {
61430088Sminshall 	if (!neturg) {
61530088Sminshall 	    n = write(net, nbackp, n);	/* normal write */
61630088Sminshall 	} else {
61730088Sminshall 	    n = neturg - nbackp;
61830088Sminshall 	    /*
61930088Sminshall 	     * In 4.2 (and 4.3) systems, there is some question about
62030088Sminshall 	     * what byte in a sendOOB operation is the "OOB" data.
62130088Sminshall 	     * To make ourselves compatible, we only send ONE byte
62230088Sminshall 	     * out of band, the one WE THINK should be OOB (though
62330088Sminshall 	     * we really have more the TCP philosophy of urgent data
62430088Sminshall 	     * rather than the Unix philosophy of OOB data).
62530088Sminshall 	     */
62630088Sminshall 	    if (n > 1) {
62730088Sminshall 		n = send(net, nbackp, n-1, 0);	/* send URGENT all by itself */
62830088Sminshall 	    } else {
62930088Sminshall 		n = send(net, nbackp, n, MSG_OOB);	/* URGENT data */
63030088Sminshall 	    }
63130088Sminshall 	}
63230088Sminshall     }
63330088Sminshall     if (n < 0) {
63430088Sminshall 	if (errno != ENOBUFS && errno != EWOULDBLOCK) {
63530088Sminshall 	    setcommandmode();
63630088Sminshall 	    perror(hostname);
63730088Sminshall 	    close(net);
63830088Sminshall 	    neturg = 0;
63930088Sminshall 	    longjmp(peerdied, -1);
64030088Sminshall 	    /*NOTREACHED*/
64130088Sminshall 	}
64230088Sminshall 	n = 0;
64330088Sminshall     }
64430088Sminshall     if (netdata && n) {
64530088Sminshall 	Dump('>', nbackp, n);
64630088Sminshall     }
64730088Sminshall     nbackp += n;
64830088Sminshall     if (nbackp >= neturg) {
64930088Sminshall 	neturg = 0;
65030088Sminshall     }
65130088Sminshall     if (nbackp == nfrontp) {
65230088Sminshall 	nbackp = nfrontp = netobuf;
65330088Sminshall     }
65430088Sminshall     return n > 0;
65530088Sminshall }
65630088Sminshall 
65730088Sminshall /*
65830088Sminshall  * nextitem()
65930088Sminshall  *
66030088Sminshall  *	Return the address of the next "item" in the TELNET data
66130088Sminshall  * stream.  This will be the address of the next character if
66230088Sminshall  * the current address is a user data character, or it will
66330088Sminshall  * be the address of the character following the TELNET command
66430088Sminshall  * if the current address is a TELNET IAC ("I Am a Command")
66530088Sminshall  * character.
66630088Sminshall  */
66730088Sminshall 
66830088Sminshall static char *
66930088Sminshall nextitem(current)
67030088Sminshall char	*current;
67130088Sminshall {
67230088Sminshall     if ((*current&0xff) != IAC) {
67330088Sminshall 	return current+1;
67430088Sminshall     }
67530088Sminshall     switch (*(current+1)&0xff) {
67630088Sminshall     case DO:
67730088Sminshall     case DONT:
67830088Sminshall     case WILL:
67930088Sminshall     case WONT:
68030088Sminshall 	return current+3;
68130088Sminshall     case SB:		/* loop forever looking for the SE */
68230088Sminshall 	{
68330088Sminshall 	    register char *look = current+2;
68430088Sminshall 
68530088Sminshall 	    for (;;) {
68630088Sminshall 		if ((*look++&0xff) == IAC) {
68730088Sminshall 		    if ((*look++&0xff) == SE) {
68830088Sminshall 			return look;
68930088Sminshall 		    }
69030088Sminshall 		}
69130088Sminshall 	    }
69230088Sminshall 	}
69330088Sminshall     default:
69430088Sminshall 	return current+2;
69530088Sminshall     }
69630088Sminshall }
69730088Sminshall /*
69830088Sminshall  * netclear()
69930088Sminshall  *
70030088Sminshall  *	We are about to do a TELNET SYNCH operation.  Clear
70130088Sminshall  * the path to the network.
70230088Sminshall  *
70330088Sminshall  *	Things are a bit tricky since we may have sent the first
70430088Sminshall  * byte or so of a previous TELNET command into the network.
70530088Sminshall  * So, we have to scan the network buffer from the beginning
70630088Sminshall  * until we are up to where we want to be.
70730088Sminshall  *
70830088Sminshall  *	A side effect of what we do, just to keep things
70930088Sminshall  * simple, is to clear the urgent data pointer.  The principal
71030088Sminshall  * caller should be setting the urgent data pointer AFTER calling
71130088Sminshall  * us in any case.
71230088Sminshall  */
71330088Sminshall 
71430088Sminshall static void
71530088Sminshall netclear()
71630088Sminshall {
71730088Sminshall     register char *thisitem, *next;
71830088Sminshall     char *good;
71930088Sminshall #define	wewant(p)	((nfrontp > p) && ((*p&0xff) == IAC) && \
72030088Sminshall 				((*(p+1)&0xff) != EC) && ((*(p+1)&0xff) != EL))
72130088Sminshall 
72230088Sminshall     thisitem = netobuf;
72330088Sminshall 
72430088Sminshall     while ((next = nextitem(thisitem)) <= nbackp) {
72530088Sminshall 	thisitem = next;
72630088Sminshall     }
72730088Sminshall 
72830088Sminshall     /* Now, thisitem is first before/at boundary. */
72930088Sminshall 
73030088Sminshall     good = netobuf;	/* where the good bytes go */
73130088Sminshall 
73230088Sminshall     while (nfrontp > thisitem) {
73330088Sminshall 	if (wewant(thisitem)) {
73430088Sminshall 	    int length;
73530088Sminshall 
73630088Sminshall 	    next = thisitem;
73730088Sminshall 	    do {
73830088Sminshall 		next = nextitem(next);
73930088Sminshall 	    } while (wewant(next) && (nfrontp > next));
74030088Sminshall 	    length = next-thisitem;
74130088Sminshall 	    bcopy(thisitem, good, length);
74230088Sminshall 	    good += length;
74330088Sminshall 	    thisitem = next;
74430088Sminshall 	} else {
74530088Sminshall 	    thisitem = nextitem(thisitem);
74630088Sminshall 	}
74730088Sminshall     }
74830088Sminshall 
74930088Sminshall     nbackp = netobuf;
75030088Sminshall     nfrontp = good;		/* next byte to be sent */
75130088Sminshall     neturg = 0;
75230088Sminshall }
75330088Sminshall 
75430088Sminshall /*
75530088Sminshall  * These routines add various telnet commands to the data stream.
75630088Sminshall  */
75730088Sminshall 
75830088Sminshall #if	defined(NOT43)
75930088Sminshall static int
76030088Sminshall #else	/* defined(NOT43) */
76130088Sminshall static void
76230088Sminshall #endif	/* defined(NOT43) */
76330088Sminshall dosynch()
76430088Sminshall {
76530088Sminshall     netclear();			/* clear the path to the network */
76630088Sminshall     NET2ADD(IAC, DM);
76730088Sminshall     neturg = NETLOC()-1;	/* Some systems are off by one XXX */
76830088Sminshall 
76930088Sminshall #if	defined(NOT43)
77030088Sminshall     return 0;
77130088Sminshall #endif	/* defined(NOT43) */
77230088Sminshall }
77330088Sminshall 
77430088Sminshall static void
77530088Sminshall doflush()
77630088Sminshall {
77730088Sminshall     NET2ADD(IAC, DO);
77830088Sminshall     NETADD(TELOPT_TM);
77930088Sminshall     flushline = 1;
78030088Sminshall     flushout = 1;
78130088Sminshall     ttyflush();
78230088Sminshall     /* do printoption AFTER flush, otherwise the output gets tossed... */
78330088Sminshall     printoption("<SENT", doopt, TELOPT_TM, 0);
78430088Sminshall }
78530088Sminshall 
78630088Sminshall static void
78730088Sminshall intp()
78830088Sminshall {
78930088Sminshall     NET2ADD(IAC, IP);
79030088Sminshall     if (autoflush) {
79130088Sminshall 	doflush();
79230088Sminshall     }
79330088Sminshall     if (autosynch) {
79430088Sminshall 	dosynch();
79530088Sminshall     }
79630088Sminshall }
79730088Sminshall 
79830088Sminshall static void
79930088Sminshall sendbrk()
80030088Sminshall {
80130088Sminshall     NET2ADD(IAC, BREAK);
80230088Sminshall     if (autoflush) {
80330088Sminshall 	doflush();
80430088Sminshall     }
80530088Sminshall     if (autosynch) {
80630088Sminshall 	dosynch();
80730088Sminshall     }
80830088Sminshall }
80930088Sminshall 
81030088Sminshall /*
81130088Sminshall  *		Send as much data as possible to the terminal.
81230088Sminshall  *
81330088Sminshall  *		The return value indicates whether we did any
81430088Sminshall  *	useful work.
81530088Sminshall  */
81630088Sminshall 
81730088Sminshall 
81830088Sminshall static int
81930088Sminshall ttyflush()
82030088Sminshall {
82130088Sminshall     int n;
82230088Sminshall 
82330088Sminshall     if ((n = tfrontp - tbackp) > 0) {
82430088Sminshall 	if (!(SYNCHing||flushout)) {
82530088Sminshall 	    n = write(tout, tbackp, n);
82630088Sminshall 	} else {
82730088Sminshall 	    ioctl(fileno(stdout), TIOCFLUSH, (char *) 0);
82830088Sminshall 	    /* we leave 'n' alone! */
82930088Sminshall 	}
83030088Sminshall     }
83130088Sminshall     if (n >= 0) {
83230088Sminshall 	tbackp += n;
83330088Sminshall 	if (tbackp == tfrontp) {
83430088Sminshall 	    tbackp = tfrontp = ttyobuf;
83530088Sminshall 	}
83630088Sminshall     }
83730088Sminshall     return n > 0;
83830088Sminshall }
83930088Sminshall 
84030088Sminshall #if	defined(TN3270)
84130088Sminshall 
84230088Sminshall #if	defined(unix)
84330088Sminshall static void
84430088Sminshall inputAvailable()
84530088Sminshall {
84630088Sminshall     HaveInput = 1;
84730088Sminshall }
84830088Sminshall #endif	/* defined(unix) */
84930088Sminshall 
85030088Sminshall void
85130088Sminshall outputPurge()
85230088Sminshall {
85330088Sminshall     int tmp = flushout;
85430088Sminshall 
85530088Sminshall     flushout = 1;
85630088Sminshall 
85730088Sminshall     ttyflush();
85830088Sminshall 
85930088Sminshall     flushout = tmp;
86030088Sminshall }
86130088Sminshall 
86230088Sminshall #endif	/* defined(TN3270) */
86330088Sminshall 
86430088Sminshall #if	defined(unix)
86530088Sminshall /*
86630088Sminshall  * Various signal handling routines.
86730088Sminshall  */
86830088Sminshall 
86930088Sminshall static void
87030088Sminshall deadpeer()
87130088Sminshall {
87230088Sminshall 	setcommandmode();
87330088Sminshall 	longjmp(peerdied, -1);
87430088Sminshall }
87530088Sminshall 
87630088Sminshall static void
87730088Sminshall intr()
87830088Sminshall {
87930088Sminshall     if (localchars) {
88030088Sminshall 	intp();
88130088Sminshall 	return;
88230088Sminshall     }
88330088Sminshall     setcommandmode();
88430088Sminshall     longjmp(toplevel, -1);
88530088Sminshall }
88630088Sminshall 
88730088Sminshall static void
88830088Sminshall intr2()
88930088Sminshall {
89030088Sminshall     if (localchars) {
89130088Sminshall 	sendbrk();
89230088Sminshall 	return;
89330088Sminshall     }
89430088Sminshall }
89530088Sminshall 
89630088Sminshall static void
89730088Sminshall doescape()
89830088Sminshall {
89930088Sminshall     command(0);
90030088Sminshall }
90130088Sminshall #endif	/* defined(unix) */
90230088Sminshall 
90330088Sminshall static int	globalmode = 0;
90430088Sminshall /*	Various modes */
90530088Sminshall #define	MODE_LINE(m)	(modelist[m].modetype & LINE)
90630088Sminshall #define	MODE_LOCAL_CHARS(m)	(modelist[m].modetype &  LOCAL_CHARS)
90730088Sminshall 
90830088Sminshall #define	LOCAL_CHARS	0x01		/* Characters processed locally */
90930088Sminshall #define	LINE		0x02		/* Line-by-line mode of operation */
91030088Sminshall 
91130088Sminshall static struct {
91230088Sminshall     char *modedescriptions;
91330088Sminshall     char modetype;
91430088Sminshall } modelist[] = {
91530088Sminshall 	{ "telnet command mode", 0 },
91630088Sminshall 	{ "character-at-a-time mode", 0 },
91730088Sminshall 	{ "character-at-a-time mode (local echo)", LOCAL_CHARS },
91830088Sminshall 	{ "line-by-line mode (remote echo)", LINE | LOCAL_CHARS },
91930088Sminshall 	{ "line-by-line mode", LINE | LOCAL_CHARS },
92030088Sminshall 	{ "line-by-line mode (local echoing suppressed)", LINE | LOCAL_CHARS },
92130088Sminshall 	{ "3270 mode", 0 },
92230088Sminshall };
92330088Sminshall /*
92430088Sminshall  * Mode - set up terminal to a specific mode.
92530088Sminshall  */
92630088Sminshall 
92730088Sminshall 
92830088Sminshall static void
92930088Sminshall mode(f)
93030088Sminshall 	register int f;
93130088Sminshall {
93230088Sminshall     static int prevmode = 0;
93330088Sminshall     struct tchars *tc;
93430088Sminshall     struct tchars tc3;
93530088Sminshall     struct ltchars *ltc;
93630088Sminshall     struct sgttyb sb;
93730088Sminshall     int onoff;
93830088Sminshall #if	defined(unix)
93930088Sminshall     int old;
94030088Sminshall #endif	/* defined(unix) */
94130088Sminshall     struct	tchars notc2;
94230088Sminshall     struct	ltchars noltc2;
94330088Sminshall     static struct	tchars notc =	{ -1, -1, -1, -1, -1, -1 };
94430088Sminshall     static struct	ltchars noltc =	{ -1, -1, -1, -1, -1, -1 };
94530088Sminshall 
94630088Sminshall     globalmode = f;
94730088Sminshall     if (prevmode == f)
94830088Sminshall 	return;
94930088Sminshall #if	defined(unix)
95030088Sminshall     old = prevmode;
95130088Sminshall #endif	/* defined(unix) */
95230088Sminshall     prevmode = f;
95330088Sminshall     sb = nttyb;
95430088Sminshall 
95530088Sminshall     switch (f) {
95630088Sminshall 
95730088Sminshall     case 0:
95830088Sminshall 	onoff = 0;
95930088Sminshall 	tc = &otc;
96030088Sminshall 	ltc = &oltc;
96130088Sminshall 	break;
96230088Sminshall 
96330088Sminshall     case 1:		/* remote character processing, remote echo */
96430088Sminshall     case 2:		/* remote character processing, local echo */
96530088Sminshall     case 6:		/* 3270 mode - like 1, but with xon/xoff local */
96630088Sminshall 		    /* (might be nice to have "6" in telnet also...) */
96730088Sminshall 	    sb.sg_flags |= CBREAK;
96830088Sminshall 	    if ((f == 1) || (f == 6)) {
96930088Sminshall 		sb.sg_flags &= ~(ECHO|CRMOD);
97030088Sminshall 	    } else {
97130088Sminshall 		sb.sg_flags |= ECHO|CRMOD;
97230088Sminshall 	    }
97330088Sminshall 	    sb.sg_erase = sb.sg_kill = -1;
97430088Sminshall 	    if (f == 6) {
97530088Sminshall 		tc = &tc3;
97630088Sminshall 		tc3 = notc;
97730088Sminshall 		    /* get XON, XOFF characters */
97830088Sminshall 		tc3.t_startc = otc.t_startc;
97930088Sminshall 		tc3.t_stopc = otc.t_stopc;
98030088Sminshall 	    } else {
98130088Sminshall 		/*
98230088Sminshall 		 * If user hasn't specified one way or the other,
98330088Sminshall 		 * then default to not trapping signals.
98430088Sminshall 		 */
98530088Sminshall 		if (!donelclchars) {
98630088Sminshall 		    localchars = 0;
98730088Sminshall 		}
98830088Sminshall 		if (localchars) {
98930088Sminshall 		    notc2 = notc;
99030088Sminshall 		    notc2.t_intrc = ntc.t_intrc;
99130088Sminshall 		    notc2.t_quitc = ntc.t_quitc;
99230088Sminshall 		    tc = &notc2;
99330088Sminshall 		} else {
99430088Sminshall 		    tc = &notc;
99530088Sminshall 		}
99630088Sminshall 	    }
99730088Sminshall 	    ltc = &noltc;
99830088Sminshall 	    onoff = 1;
99930088Sminshall 	    break;
100030088Sminshall     case 3:		/* local character processing, remote echo */
100130088Sminshall     case 4:		/* local character processing, local echo */
100230088Sminshall     case 5:		/* local character processing, no echo */
100330088Sminshall 	    sb.sg_flags &= ~CBREAK;
100430088Sminshall 	    sb.sg_flags |= CRMOD;
100530088Sminshall 	    if (f == 4)
100630088Sminshall 		sb.sg_flags |= ECHO;
100730088Sminshall 	    else
100830088Sminshall 		sb.sg_flags &= ~ECHO;
100930088Sminshall 	    notc2 = ntc;
101030088Sminshall 	    tc = &notc2;
101130088Sminshall 	    noltc2 = oltc;
101230088Sminshall 	    ltc = &noltc2;
101330088Sminshall 	    /*
101430088Sminshall 	     * If user hasn't specified one way or the other,
101530088Sminshall 	     * then default to trapping signals.
101630088Sminshall 	     */
101730088Sminshall 	    if (!donelclchars) {
101830088Sminshall 		localchars = 1;
101930088Sminshall 	    }
102030088Sminshall 	    if (localchars) {
102130088Sminshall 		notc2.t_brkc = nltc.t_flushc;
102230088Sminshall 		noltc2.t_flushc = -1;
102330088Sminshall 	    } else {
102430088Sminshall 		notc2.t_intrc = notc2.t_quitc = -1;
102530088Sminshall 	    }
102630088Sminshall 	    noltc2.t_suspc = escape;
102730088Sminshall 	    noltc2.t_dsuspc = -1;
102830088Sminshall 	    onoff = 1;
102930088Sminshall 	    break;
103030088Sminshall 
103130088Sminshall     default:
103230088Sminshall 	    return;
103330088Sminshall     }
103430088Sminshall     ioctl(tin, TIOCSLTC, (char *)ltc);
103530088Sminshall     ioctl(tin, TIOCSETC, (char *)tc);
103630088Sminshall     ioctl(tin, TIOCSETP, (char *)&sb);
103730088Sminshall #if	(!defined(TN3270)) || ((!defined(NOT43)) || defined(PUTCHAR))
103830088Sminshall     ioctl(tin, FIONBIO, (char *)&onoff);
103930088Sminshall     ioctl(tout, FIONBIO, (char *)&onoff);
104030088Sminshall #endif	/* (!defined(TN3270)) || ((!defined(NOT43)) || defined(PUTCHAR)) */
104130088Sminshall #if	defined(TN3270) && !defined(DEBUG)
104230088Sminshall     ioctl(tin, FIOASYNC, (char *)&onoff);
104330088Sminshall #endif	/* defined(TN3270) && !defined(DEBUG) */
104430088Sminshall 
104530088Sminshall #if	defined(unix)
104630088Sminshall     if (MODE_LINE(f)) {
104730088Sminshall 	signal(SIGTSTP, doescape);
104830088Sminshall     } else if (MODE_LINE(old)) {
104930088Sminshall 	signal(SIGTSTP, SIG_DFL);
105030088Sminshall 	sigsetmask(sigblock(0) & ~(1<<(SIGTSTP-1)));
105130088Sminshall     }
105230088Sminshall #endif	/* defined(unix) */
105330088Sminshall }
105430088Sminshall 
105530088Sminshall /*
105630088Sminshall  * These routines decides on what the mode should be (based on the values
105730088Sminshall  * of various global variables).
105830088Sminshall  */
105930088Sminshall 
106030088Sminshall 
106130088Sminshall static
106230088Sminshall getconnmode()
106330088Sminshall {
106430088Sminshall     static char newmode[16] =
106530088Sminshall 			{ 4, 5, 3, 3, 2, 2, 1, 1, 6, 6, 6, 6, 6, 6, 6, 6 };
106630088Sminshall     int modeindex = 0;
106730088Sminshall 
106830088Sminshall     if (dontlecho && (clocks.echotoggle > clocks.modenegotiated)) {
106930088Sminshall 	modeindex += 1;
107030088Sminshall     }
107130088Sminshall     if (hisopts[TELOPT_ECHO]) {
107230088Sminshall 	modeindex += 2;
107330088Sminshall     }
107430088Sminshall     if (hisopts[TELOPT_SGA]) {
107530088Sminshall 	modeindex += 4;
107630088Sminshall     }
107730088Sminshall     if (In3270) {
107830088Sminshall 	modeindex += 8;
107930088Sminshall     }
108030088Sminshall     return newmode[modeindex];
108130088Sminshall }
108230088Sminshall 
108330088Sminshall void
108430088Sminshall setconnmode()
108530088Sminshall {
108630088Sminshall     mode(getconnmode());
108730088Sminshall }
108830088Sminshall 
108930088Sminshall 
109030088Sminshall void
109130088Sminshall setcommandmode()
109230088Sminshall {
109330088Sminshall     mode(0);
109430088Sminshall }
109530088Sminshall 
109630088Sminshall static void
109730088Sminshall willoption(option, reply)
109830088Sminshall 	int option, reply;
109930088Sminshall {
110030088Sminshall 	char *fmt;
110130088Sminshall 
110230088Sminshall 	switch (option) {
110330088Sminshall 
110430088Sminshall #	if defined(TN3270)
110530088Sminshall 	case TELOPT_EOR:
110630088Sminshall 	case TELOPT_BINARY:
110730088Sminshall #endif	/* defined(TN3270) */
110830088Sminshall 	case TELOPT_ECHO:
110930088Sminshall 	case TELOPT_SGA:
111030088Sminshall 		settimer(modenegotiated);
111130088Sminshall 		hisopts[option] = 1;
111230088Sminshall 		fmt = doopt;
111330088Sminshall 		setconnmode();		/* possibly set new tty mode */
111430088Sminshall 		break;
111530088Sminshall 
111630088Sminshall 	case TELOPT_TM:
111730088Sminshall 		return;			/* Never reply to TM will's/wont's */
111830088Sminshall 
111930088Sminshall 	default:
112030088Sminshall 		fmt = dont;
112130088Sminshall 		break;
112230088Sminshall 	}
112330088Sminshall 	sprintf(nfrontp, fmt, option);
112430088Sminshall 	nfrontp += sizeof (dont) - 2;
112530088Sminshall 	if (reply)
112630088Sminshall 		printoption(">SENT", fmt, option, reply);
112730088Sminshall 	else
112830088Sminshall 		printoption("<SENT", fmt, option, reply);
112930088Sminshall }
113030088Sminshall 
113130088Sminshall static void
113230088Sminshall wontoption(option, reply)
113330088Sminshall 	int option, reply;
113430088Sminshall {
113530088Sminshall 	char *fmt;
113630088Sminshall 
113730088Sminshall 	switch (option) {
113830088Sminshall 
113930088Sminshall 	case TELOPT_ECHO:
114030088Sminshall 	case TELOPT_SGA:
114130088Sminshall 		settimer(modenegotiated);
114230088Sminshall 		hisopts[option] = 0;
114330088Sminshall 		fmt = dont;
114430088Sminshall 		setconnmode();			/* Set new tty mode */
114530088Sminshall 		break;
114630088Sminshall 
114730088Sminshall 	case TELOPT_TM:
114830088Sminshall 		return;		/* Never reply to TM will's/wont's */
114930088Sminshall 
115030088Sminshall 	default:
115130088Sminshall 		fmt = dont;
115230088Sminshall 	}
115330088Sminshall 	sprintf(nfrontp, fmt, option);
115430088Sminshall 	nfrontp += sizeof (doopt) - 2;
115530088Sminshall 	if (reply)
115630088Sminshall 		printoption(">SENT", fmt, option, reply);
115730088Sminshall 	else
115830088Sminshall 		printoption("<SENT", fmt, option, reply);
115930088Sminshall }
116030088Sminshall 
116130088Sminshall static void
116230088Sminshall dooption(option)
116330088Sminshall 	int option;
116430088Sminshall {
116530088Sminshall 	char *fmt;
116630088Sminshall 
116730088Sminshall 	switch (option) {
116830088Sminshall 
116930088Sminshall 	case TELOPT_TM:
117030088Sminshall 		fmt = will;
117130088Sminshall 		break;
117230088Sminshall 
117330088Sminshall #	if defined(TN3270)
117430088Sminshall 	case TELOPT_EOR:
117530088Sminshall 	case TELOPT_BINARY:
117630088Sminshall #	endif	/* defined(TN3270) */
117730088Sminshall 	case TELOPT_TTYPE:		/* terminal type option */
117830088Sminshall 	case TELOPT_SGA:		/* no big deal */
117930088Sminshall 		fmt = will;
118030088Sminshall 		myopts[option] = 1;
118130088Sminshall 		break;
118230088Sminshall 
118330088Sminshall 	case TELOPT_ECHO:		/* We're never going to echo... */
118430088Sminshall 	default:
118530088Sminshall 		fmt = wont;
118630088Sminshall 		break;
118730088Sminshall 	}
118830088Sminshall 	sprintf(nfrontp, fmt, option);
118930088Sminshall 	nfrontp += sizeof (doopt) - 2;
119030088Sminshall 	printoption(">SENT", fmt, option, 0);
119130088Sminshall }
119230088Sminshall 
119330088Sminshall /*
119430088Sminshall  * suboption()
119530088Sminshall  *
119630088Sminshall  *	Look at the sub-option buffer, and try to be helpful to the other
119730088Sminshall  * side.
119830088Sminshall  *
119930088Sminshall  *	Currently we recognize:
120030088Sminshall  *
120130088Sminshall  *		Terminal type, send request.
120230088Sminshall  */
120330088Sminshall 
120430088Sminshall static void
120530088Sminshall suboption()
120630088Sminshall {
120730088Sminshall     printsub("<", subbuffer, subend-subbuffer+1);
120830088Sminshall     switch (subbuffer[0]&0xff) {
120930088Sminshall     case TELOPT_TTYPE:
121030088Sminshall 	if ((subbuffer[1]&0xff) != TELQUAL_SEND) {
121130088Sminshall 	    ;
121230088Sminshall 	} else {
121330088Sminshall 	    char *name;
121430088Sminshall 	    char namebuf[41];
121530088Sminshall 	    extern char *getenv();
121630088Sminshall 	    int len;
121730088Sminshall 
121830088Sminshall #if	defined(TN3270)
121930088Sminshall 	    /*
1220*30326Sminshall 	     * Try to send a 3270 type terminal name.  Decide which one based
122130088Sminshall 	     * on the format of our screen, and (in the future) color
122230088Sminshall 	     * capaiblities.
122330088Sminshall 	     */
122430088Sminshall 	    if ((initscr() != ERR) &&	/* Initialize curses to get line size */
122530088Sminshall 		(LINES >= 24) && (COLS >= 80)) {
122630088Sminshall 		Sent3270TerminalType = 1;
122730088Sminshall 		if ((LINES >= 27) && (COLS >= 132)) {
122830088Sminshall 		    MaxNumberLines = 27;
122930088Sminshall 		    MaxNumberColumns = 132;
123030088Sminshall 		    sb_terminal[SBTERMMODEL] = '5';
123130088Sminshall 		} else if (LINES >= 43) {
123230088Sminshall 		    MaxNumberLines = 43;
123330088Sminshall 		    MaxNumberColumns = 80;
123430088Sminshall 		    sb_terminal[SBTERMMODEL] = '4';
123530088Sminshall 		} else if (LINES >= 32) {
123630088Sminshall 		    MaxNumberLines = 32;
123730088Sminshall 		    MaxNumberColumns = 80;
123830088Sminshall 		    sb_terminal[SBTERMMODEL] = '3';
123930088Sminshall 		} else {
124030088Sminshall 		    MaxNumberLines = 24;
124130088Sminshall 		    MaxNumberColumns = 80;
124230088Sminshall 		    sb_terminal[SBTERMMODEL] = '2';
124330088Sminshall 		}
124430088Sminshall 		NumberLines = 24;		/* before we start out... */
124530088Sminshall 		NumberColumns = 80;
124630088Sminshall 		ScreenSize = NumberLines*NumberColumns;
124730088Sminshall 		if ((MaxNumberLines*MaxNumberColumns) > MAXSCREENSIZE) {
124830088Sminshall 		    ExitString(stderr,
124930088Sminshall 			"Programming error:  MAXSCREENSIZE too small.\n", 1);
125030088Sminshall 		    /*NOTREACHED*/
125130088Sminshall 		}
125230088Sminshall 		bcopy(sb_terminal, nfrontp, sizeof sb_terminal);
125330088Sminshall 		printsub(">", nfrontp+2, sizeof sb_terminal-2);
125430088Sminshall 		nfrontp += sizeof sb_terminal;
125530088Sminshall 		return;
125630088Sminshall 	    }
125730088Sminshall #endif	/* defined(TN3270) */
125830088Sminshall 
125930088Sminshall 	    name = getenv("TERM");
126030088Sminshall 	    if ((name == 0) || ((len = strlen(name)) > 40)) {
126130088Sminshall 		name = "UNKNOWN";
126230088Sminshall 	    }
126330088Sminshall 	    if ((len + 4+2) < NETROOM()) {
126430088Sminshall 		strcpy(namebuf, name);
126530088Sminshall 		upcase(namebuf);
126630088Sminshall 		sprintf(nfrontp, "%c%c%c%c%s%c%c", IAC, SB, TELOPT_TTYPE,
126730088Sminshall 				    TELQUAL_IS, namebuf, IAC, SE);
126830088Sminshall 		printsub(">", nfrontp+2, 4+strlen(namebuf)+2-2-2);
126930088Sminshall 		nfrontp += 4+strlen(namebuf)+2;
127030088Sminshall 	    } else {
127130088Sminshall 		ExitString(stderr, "No room in buffer for terminal type.\n",
127230088Sminshall 							1);
127330088Sminshall 		/*NOTREACHED*/
127430088Sminshall 	    }
127530088Sminshall 	}
127630088Sminshall 
127730088Sminshall     default:
127830088Sminshall 	break;
127930088Sminshall     }
128030088Sminshall }
128130088Sminshall 
128230088Sminshall #if	defined(TN3270)
128330088Sminshall static void
128430088Sminshall SetIn3270()
128530088Sminshall {
128630088Sminshall     if (Sent3270TerminalType && myopts[TELOPT_BINARY]
128730088Sminshall 					&& hisopts[TELOPT_BINARY]) {
128830088Sminshall 	if (!In3270) {
128930088Sminshall 	    In3270 = 1;
1290*30326Sminshall 	    Init3270();		/* Initialize 3270 functions */
129130088Sminshall 	    /* initialize terminal key mapping */
1292*30326Sminshall 	    InitTerminal();	/* Start terminal going */
129330088Sminshall 	    setconnmode();
129430088Sminshall 	}
129530088Sminshall     } else {
129630088Sminshall 	if (In3270) {
129730088Sminshall 	    StopScreen(1);
129830088Sminshall 	    In3270 = 0;
129930088Sminshall 	    setconnmode();
130030088Sminshall 	}
130130088Sminshall     }
130230088Sminshall }
130330088Sminshall #endif	/* defined(TN3270) */
130430088Sminshall 
130530088Sminshall /*
130630088Sminshall  * Telnet receiver states for fsm
130730088Sminshall  */
130830088Sminshall #define	TS_DATA		0
130930088Sminshall #define	TS_IAC		1
131030088Sminshall #define	TS_WILL		2
131130088Sminshall #define	TS_WONT		3
131230088Sminshall #define	TS_DO		4
131330088Sminshall #define	TS_DONT		5
131430088Sminshall #define	TS_CR		6
131530088Sminshall #define	TS_SB		7		/* sub-option collection */
131630088Sminshall #define	TS_SE		8		/* looking for sub-option end */
131730088Sminshall 
131830088Sminshall static void
131930088Sminshall telrcv()
132030088Sminshall {
132130088Sminshall     register int c;
132230088Sminshall     static int state = TS_DATA;
132330088Sminshall #   if defined(TN3270)
132430088Sminshall     register int Scc;
132530088Sminshall     register char *Sbp;
132630088Sminshall #   endif /* defined(TN3270) */
132730088Sminshall 
132830088Sminshall     while ((scc > 0) && (TTYROOM() > 2)) {
132930088Sminshall 	c = *sbp++ & 0xff, scc--;
133030088Sminshall 	switch (state) {
133130088Sminshall 
133230088Sminshall 	case TS_CR:
133330088Sminshall 	    state = TS_DATA;
133430088Sminshall 	    if (c == '\0') {
133530088Sminshall 		break;	/* Ignore \0 after CR */
133630088Sminshall 	    } else if (c == '\n') {
133730088Sminshall 		if (hisopts[TELOPT_ECHO] && !crmod) {
133830088Sminshall 		    TTYADD(c);
133930088Sminshall 		}
134030088Sminshall 		break;
134130088Sminshall 	    }
134230088Sminshall 	    /* Else, fall through */
134330088Sminshall 
134430088Sminshall 	case TS_DATA:
134530088Sminshall 	    if (c == IAC) {
134630088Sminshall 		state = TS_IAC;
134730088Sminshall 		continue;
134830088Sminshall 	    }
134930088Sminshall #	    if defined(TN3270)
135030088Sminshall 	    if (In3270) {
135130088Sminshall 		*Ifrontp++ = c;
135230088Sminshall 		Sbp = sbp;
135330088Sminshall 		Scc = scc;
135430088Sminshall 		while (Scc > 0) {
135530088Sminshall 		    c = *Sbp++ & 0377, Scc--;
135630088Sminshall 		    if (c == IAC) {
135730088Sminshall 			state = TS_IAC;
135830088Sminshall 			break;
135930088Sminshall 		    }
136030088Sminshall 		    *Ifrontp++ = c;
136130088Sminshall 		}
136230088Sminshall 		sbp = Sbp;
136330088Sminshall 		scc = Scc;
136430088Sminshall 	    } else
136530088Sminshall #	    endif /* defined(TN3270) */
136630088Sminshall 		    /*
136730088Sminshall 		     * The 'crmod' hack (see following) is needed
136830088Sminshall 		     * since we can't * set CRMOD on output only.
136930088Sminshall 		     * Machines like MULTICS like to send \r without
137030088Sminshall 		     * \n; since we must turn off CRMOD to get proper
137130088Sminshall 		     * input, the mapping is done here (sigh).
137230088Sminshall 		     */
137330088Sminshall 	    if (c == '\r') {
137430088Sminshall 		if (scc > 0) {
137530088Sminshall 		    c = *sbp&0xff;
137630088Sminshall 		    if (c == 0) {
137730088Sminshall 			sbp++, scc--;
137830088Sminshall 			/* a "true" CR */
137930088Sminshall 			TTYADD('\r');
138030088Sminshall 		    } else if (!hisopts[TELOPT_ECHO] &&
138130088Sminshall 					(c == '\n')) {
138230088Sminshall 			sbp++, scc--;
138330088Sminshall 			TTYADD('\n');
138430088Sminshall 		    } else {
138530088Sminshall 			TTYADD('\r');
138630088Sminshall 			if (crmod) {
138730088Sminshall 				TTYADD('\n');
138830088Sminshall 			}
138930088Sminshall 		    }
139030088Sminshall 		} else {
139130088Sminshall 		    state = TS_CR;
139230088Sminshall 		    TTYADD('\r');
139330088Sminshall 		    if (crmod) {
139430088Sminshall 			    TTYADD('\n');
139530088Sminshall 		    }
139630088Sminshall 		}
139730088Sminshall 	    } else {
139830088Sminshall 		TTYADD(c);
139930088Sminshall 	    }
140030088Sminshall 	    continue;
140130088Sminshall 
140230088Sminshall 	case TS_IAC:
140330088Sminshall 	    switch (c) {
140430088Sminshall 
140530088Sminshall 	    case WILL:
140630088Sminshall 		state = TS_WILL;
140730088Sminshall 		continue;
140830088Sminshall 
140930088Sminshall 	    case WONT:
141030088Sminshall 		state = TS_WONT;
141130088Sminshall 		continue;
141230088Sminshall 
141330088Sminshall 	    case DO:
141430088Sminshall 		state = TS_DO;
141530088Sminshall 		continue;
141630088Sminshall 
141730088Sminshall 	    case DONT:
141830088Sminshall 		state = TS_DONT;
141930088Sminshall 		continue;
142030088Sminshall 
142130088Sminshall 	    case DM:
142230088Sminshall 		    /*
142330088Sminshall 		     * We may have missed an urgent notification,
142430088Sminshall 		     * so make sure we flush whatever is in the
142530088Sminshall 		     * buffer currently.
142630088Sminshall 		     */
142730088Sminshall 		SYNCHing = 1;
142830088Sminshall 		ttyflush();
142930088Sminshall 		SYNCHing = stilloob(net);
143030088Sminshall 		settimer(gotDM);
143130088Sminshall 		break;
143230088Sminshall 
143330088Sminshall 	    case NOP:
143430088Sminshall 	    case GA:
143530088Sminshall 		break;
143630088Sminshall 
143730088Sminshall 	    case SB:
143830088Sminshall 		SB_CLEAR();
143930088Sminshall 		state = TS_SB;
144030088Sminshall 		continue;
144130088Sminshall 
144230088Sminshall #	    if defined(TN3270)
144330088Sminshall 	    case EOR:
144430088Sminshall 		if (In3270) {
144530088Sminshall 		    Ibackp += DataFromNetwork(Ibackp, Ifrontp-Ibackp, 1);
144630088Sminshall 		    if (Ibackp == Ifrontp) {
144730088Sminshall 			Ibackp = Ifrontp = Ibuf;
144830088Sminshall 			ISend = 0;	/* should have been! */
144930088Sminshall 		    } else {
145030088Sminshall 			ISend = 1;
145130088Sminshall 		    }
145230088Sminshall 		}
145330088Sminshall 		break;
145430088Sminshall #	    endif /* defined(TN3270) */
145530088Sminshall 
145630088Sminshall 	    case IAC:
145730088Sminshall #	    if !defined(TN3270)
145830088Sminshall 		TTYADD(IAC);
145930088Sminshall #	    else /* !defined(TN3270) */
146030088Sminshall 		if (In3270) {
146130088Sminshall 		    *Ifrontp++ = IAC;
146230088Sminshall 		} else {
146330088Sminshall 		    TTYADD(IAC);
146430088Sminshall 		}
146530088Sminshall #	    endif /* !defined(TN3270) */
146630088Sminshall 		break;
146730088Sminshall 
146830088Sminshall 	    default:
146930088Sminshall 		break;
147030088Sminshall 	    }
147130088Sminshall 	    state = TS_DATA;
147230088Sminshall 	    continue;
147330088Sminshall 
147430088Sminshall 	case TS_WILL:
147530088Sminshall 	    printoption(">RCVD", will, c, !hisopts[c]);
147630088Sminshall 	    if (c == TELOPT_TM) {
147730088Sminshall 		if (flushout) {
147830088Sminshall 		    flushout = 0;
147930088Sminshall 		}
148030088Sminshall 	    } else if (!hisopts[c]) {
148130088Sminshall 		willoption(c, 1);
148230088Sminshall 	    }
148330088Sminshall 	    SetIn3270();
148430088Sminshall 	    state = TS_DATA;
148530088Sminshall 	    continue;
148630088Sminshall 
148730088Sminshall 	case TS_WONT:
148830088Sminshall 	    printoption(">RCVD", wont, c, hisopts[c]);
148930088Sminshall 	    if (c == TELOPT_TM) {
149030088Sminshall 		if (flushout) {
149130088Sminshall 		    flushout = 0;
149230088Sminshall 		}
149330088Sminshall 	    } else if (hisopts[c]) {
149430088Sminshall 		wontoption(c, 1);
149530088Sminshall 	    }
149630088Sminshall 	    SetIn3270();
149730088Sminshall 	    state = TS_DATA;
149830088Sminshall 	    continue;
149930088Sminshall 
150030088Sminshall 	case TS_DO:
150130088Sminshall 	    printoption(">RCVD", doopt, c, !myopts[c]);
150230088Sminshall 	    if (!myopts[c])
150330088Sminshall 		dooption(c);
150430088Sminshall 	    SetIn3270();
150530088Sminshall 	    state = TS_DATA;
150630088Sminshall 	    continue;
150730088Sminshall 
150830088Sminshall 	case TS_DONT:
150930088Sminshall 	    printoption(">RCVD", dont, c, myopts[c]);
151030088Sminshall 	    if (myopts[c]) {
151130088Sminshall 		myopts[c] = 0;
151230088Sminshall 		sprintf(nfrontp, wont, c);
151330088Sminshall 		nfrontp += sizeof (wont) - 2;
151430088Sminshall 		flushline = 1;
151530088Sminshall 		setconnmode();	/* set new tty mode (maybe) */
151630088Sminshall 		printoption(">SENT", wont, c, 0);
151730088Sminshall 	    }
151830088Sminshall 	    SetIn3270();
151930088Sminshall 	    state = TS_DATA;
152030088Sminshall 	    continue;
152130088Sminshall 
152230088Sminshall 	case TS_SB:
152330088Sminshall 	    if (c == IAC) {
152430088Sminshall 		state = TS_SE;
152530088Sminshall 	    } else {
152630088Sminshall 		SB_ACCUM(c);
152730088Sminshall 	    }
152830088Sminshall 	    continue;
152930088Sminshall 
153030088Sminshall 	case TS_SE:
153130088Sminshall 	    if (c != SE) {
153230088Sminshall 		if (c != IAC) {
153330088Sminshall 		    SB_ACCUM(IAC);
153430088Sminshall 		}
153530088Sminshall 		SB_ACCUM(c);
153630088Sminshall 		state = TS_SB;
153730088Sminshall 	    } else {
153830088Sminshall 		SB_TERM();
153930088Sminshall 		suboption();	/* handle sub-option */
154030088Sminshall 		SetIn3270();
154130088Sminshall 		state = TS_DATA;
154230088Sminshall 	    }
154330088Sminshall 	}
154430088Sminshall     }
154530088Sminshall }
154630088Sminshall 
154730088Sminshall #if	defined(TN3270)
154830088Sminshall 
154930088Sminshall /*
155030088Sminshall  * The following routines are places where the various tn3270
155130088Sminshall  * routines make calls into telnet.c.
155230088Sminshall  */
155330088Sminshall 
155430088Sminshall /* TtyChars() - returns the number of characters in the TTY buffer */
155530088Sminshall TtyChars()
155630088Sminshall {
155730088Sminshall     return(tfrontp-tbackp);
155830088Sminshall }
155930088Sminshall 
156030088Sminshall /*
156130088Sminshall  * DataToNetwork - queue up some data to go to network.  If "done" is set,
156230088Sminshall  * then when last byte is queued, we add on an IAC EOR sequence (so,
156330088Sminshall  * don't call us with "done" until you want that done...)
156430088Sminshall  *
156530088Sminshall  * We actually do send all the data to the network buffer, since our
156630088Sminshall  * only client needs for us to do that.
156730088Sminshall  */
156830088Sminshall 
156930088Sminshall int
157030088Sminshall DataToNetwork(buffer, count, done)
157130088Sminshall register char	*buffer;	/* where the data is */
157230088Sminshall register int	count;		/* how much to send */
157330088Sminshall int		done;		/* is this the last of a logical block */
157430088Sminshall {
157530088Sminshall     register int c;
157630088Sminshall     int origCount;
157730088Sminshall     fd_set o;
157830088Sminshall 
157930088Sminshall     origCount = count;
158030088Sminshall     FD_ZERO(&o);
158130088Sminshall 
158230088Sminshall     while (count) {
158330088Sminshall 	if ((netobuf+sizeof netobuf - nfrontp) < 6) {
158430088Sminshall 	    netflush();
158530088Sminshall 	    while ((netobuf+sizeof netobuf - nfrontp) < 6) {
158630088Sminshall 		FD_SET(net, &o);
158730088Sminshall 		(void) select(net+1, (fd_set *) 0, &o, (fd_set *) 0,
158830088Sminshall 						(struct timeval *) 0);
158930088Sminshall 		netflush();
159030088Sminshall 	    }
159130088Sminshall 	}
159230088Sminshall 	c = *buffer++;
159330088Sminshall 	count--;
159430088Sminshall 	if (c == IAC) {
159530088Sminshall 	    *nfrontp++ = IAC;
159630088Sminshall 	    *nfrontp++ = IAC;
159730088Sminshall 	} else {
159830088Sminshall 	    *nfrontp++ = c;
159930088Sminshall 	}
160030088Sminshall     }
160130088Sminshall 
160230088Sminshall     if (done && !count) {
160330088Sminshall 	*nfrontp++ = IAC;
160430088Sminshall 	*nfrontp++ = EOR;
160530088Sminshall 	netflush();		/* try to move along as quickly as ... */
160630088Sminshall     }
160730088Sminshall     return(origCount - count);
160830088Sminshall }
160930088Sminshall 
161030088Sminshall /* DataToTerminal - queue up some data to go to terminal. */
161130088Sminshall 
161230088Sminshall int
161330088Sminshall DataToTerminal(buffer, count)
161430088Sminshall register char	*buffer;		/* where the data is */
161530088Sminshall register int	count;			/* how much to send */
161630088Sminshall {
161730088Sminshall     int origCount;
161830088Sminshall     fd_set	o;
161930088Sminshall 
162030088Sminshall     origCount = count;
162130088Sminshall     FD_ZERO(&o);
162230088Sminshall 
162330088Sminshall     while (count) {
162430088Sminshall 	if (tfrontp >= ttyobuf+sizeof ttyobuf) {
162530088Sminshall 	    ttyflush();
162630088Sminshall 	    while (tfrontp >= ttyobuf+sizeof ttyobuf) {
162730088Sminshall 		FD_SET(tout, &o);
162830088Sminshall 		(void) select(tout+1, (fd_set *) 0, &o, (fd_set *) 0,
162930088Sminshall 						(struct timeval *) 0);
163030088Sminshall 		ttyflush();
163130088Sminshall 	    }
163230088Sminshall 	}
163330088Sminshall 	*tfrontp++ = *buffer++;
163430088Sminshall 	count--;
163530088Sminshall     }
163630088Sminshall     return(origCount - count);
163730088Sminshall }
163830088Sminshall 
163930088Sminshall /* EmptyTerminal - called to make sure that the terminal buffer is empty.
164030088Sminshall  *			Note that we consider the buffer to run all the
164130088Sminshall  *			way to the kernel (thus the select).
164230088Sminshall  */
164330088Sminshall 
164430088Sminshall void
164530088Sminshall EmptyTerminal()
164630088Sminshall {
164730088Sminshall     fd_set	o;
164830088Sminshall 
164930088Sminshall     FD_ZERO(&o);
165030088Sminshall 
165130088Sminshall     if (tfrontp == tbackp) {
165230088Sminshall 	FD_SET(tout, &o);
165330088Sminshall 	(void) select(tout+1, (int *) 0, &o, (int *) 0,
165430088Sminshall 			(struct timeval *) 0);	/* wait for TTLOWAT */
165530088Sminshall     } else {
165630088Sminshall 	while (tfrontp != tbackp) {
165730088Sminshall 	    ttyflush();
165830088Sminshall 	    FD_SET(tout, &o);
165930088Sminshall 	    (void) select(tout+1, (int *) 0, &o, (int *) 0,
166030088Sminshall 				(struct timeval *) 0);	/* wait for TTLOWAT */
166130088Sminshall 	}
166230088Sminshall     }
166330088Sminshall }
166430088Sminshall 
166530088Sminshall /*
166630088Sminshall  * Push3270 - Try to send data along the 3270 output (to screen) direction.
166730088Sminshall  */
166830088Sminshall 
166930088Sminshall static int
167030088Sminshall Push3270()
167130088Sminshall {
167230088Sminshall     int save = scc;
167330088Sminshall 
167430088Sminshall     if (scc) {
167530088Sminshall 	if (Ifrontp+scc > Ibuf+sizeof Ibuf) {
167630088Sminshall 	    if (Ibackp != Ibuf) {
167730088Sminshall 		bcopy(Ibackp, Ibuf, Ifrontp-Ibackp);
167830088Sminshall 		Ifrontp -= (Ibackp-Ibuf);
167930088Sminshall 		Ibackp = Ibuf;
168030088Sminshall 	    }
168130088Sminshall 	}
168230088Sminshall 	if (Ifrontp+scc < Ibuf+sizeof Ibuf) {
168330088Sminshall 	    telrcv();
168430088Sminshall 	}
168530088Sminshall     }
168630088Sminshall     return save != scc;
168730088Sminshall }
168830088Sminshall 
168930088Sminshall 
169030088Sminshall /*
169130088Sminshall  * Finish3270 - get the last dregs of 3270 data out to the terminal
169230088Sminshall  *		before quitting.
169330088Sminshall  */
169430088Sminshall 
169530088Sminshall static void
169630088Sminshall Finish3270()
169730088Sminshall {
169830088Sminshall     while (Push3270() || !DoTerminalOutput()) {
169930088Sminshall 	;
170030088Sminshall     }
170130088Sminshall }
170230088Sminshall 
170330088Sminshall 
170430088Sminshall 
170530088Sminshall /* StringToTerminal - output a null terminated string to the terminal */
170630088Sminshall 
170730088Sminshall void
170830088Sminshall StringToTerminal(s)
170930088Sminshall char *s;
171030088Sminshall {
171130088Sminshall     int count;
171230088Sminshall 
171330088Sminshall     count = strlen(s);
171430088Sminshall     if (count) {
171530088Sminshall 	(void) DataToTerminal(s, count);	/* we know it always goes... */
171630088Sminshall     }
171730088Sminshall }
171830088Sminshall 
171930088Sminshall 
172030088Sminshall #if	defined(TN3270) && ((!defined(NOT43)) || defined(PUTCHAR))
172130088Sminshall /* _putchar - output a single character to the terminal.  This name is so that
172230088Sminshall  *	curses(3x) can call us to send out data.
172330088Sminshall  */
172430088Sminshall 
172530088Sminshall void
172630088Sminshall _putchar(c)
172730088Sminshall char c;
172830088Sminshall {
172930088Sminshall     if (tfrontp >= ttyobuf+sizeof ttyobuf) {
173030088Sminshall 	(void) DataToTerminal(&c, 1);
173130088Sminshall     } else {
173230088Sminshall 	*tfrontp++ = c;		/* optimize if possible. */
173330088Sminshall     }
173430088Sminshall }
173530088Sminshall #endif	/* defined(TN3270) && ((!defined(NOT43)) || defined(PUTCHAR)) */
173630088Sminshall 
173730088Sminshall static void
173830088Sminshall SetForExit()
173930088Sminshall {
174030088Sminshall     setconnmode();
174130088Sminshall     if (In3270) {
174230088Sminshall 	Finish3270();
174330088Sminshall     }
174430088Sminshall     setcommandmode();
174530088Sminshall     fflush(stdout);
174630088Sminshall     fflush(stderr);
174730088Sminshall     if (In3270) {
174830088Sminshall 	StopScreen(1);
174930088Sminshall     }
175030088Sminshall     setconnmode();
175130088Sminshall     setcommandmode();
175230088Sminshall }
175330088Sminshall 
175430088Sminshall static void
175530088Sminshall Exit(returnCode)
175630088Sminshall int returnCode;
175730088Sminshall {
175830088Sminshall     SetForExit();
175930088Sminshall     exit(returnCode);
176030088Sminshall }
176130088Sminshall 
176230088Sminshall void
176330088Sminshall ExitString(file, string, returnCode)
176430088Sminshall FILE *file;
176530088Sminshall char *string;
176630088Sminshall int returnCode;
176730088Sminshall {
176830088Sminshall     SetForExit();
176930088Sminshall     fwrite(string, 1, strlen(string), file);
177030088Sminshall     exit(returnCode);
177130088Sminshall }
177230088Sminshall 
177330088Sminshall void
177430088Sminshall ExitPerror(string, returnCode)
177530088Sminshall char *string;
177630088Sminshall int returnCode;
177730088Sminshall {
177830088Sminshall     SetForExit();
177930088Sminshall     perror(string);
178030088Sminshall     exit(returnCode);
178130088Sminshall }
178230088Sminshall 
178330088Sminshall #endif	/* defined(TN3270) */
178430088Sminshall 
178530088Sminshall static
178630088Sminshall Scheduler(block)
178730088Sminshall int	block;			/* should we block in the select ? */
178830088Sminshall {
178930088Sminshall     register int c;
179030088Sminshall 		/* One wants to be a bit careful about setting returnValue
179130088Sminshall 		 * to one, since a one implies we did some useful work,
179230088Sminshall 		 * and therefore probably won't be called to block next
179330088Sminshall 		 * time (TN3270 mode only).
179430088Sminshall 		 */
179530088Sminshall     int returnValue = 0;
179630088Sminshall     static struct timeval TimeValue = { 0 };
179730088Sminshall 
179830088Sminshall     if (scc < 0 && tcc < 0) {
179930088Sminshall 	return -1;
180030088Sminshall     }
180130088Sminshall 
180230088Sminshall     if ((!MODE_LINE(globalmode) || flushline) && NETBYTES()) {
180330088Sminshall 	FD_SET(net, &obits);
180430088Sminshall     }
180530088Sminshall     if (TTYBYTES()) {
180630088Sminshall 	FD_SET(tout, &obits);
180730088Sminshall     }
180830088Sminshall     if ((tcc == 0) && NETROOM()) {
180930088Sminshall 	FD_SET(tin, &ibits);
181030088Sminshall     }
181130088Sminshall #   if !defined(TN3270)
181230088Sminshall     if (TTYROOM()) {
181330088Sminshall 	FD_SET(net, &ibits);
181430088Sminshall     }
181530088Sminshall #   else /* !defined(TN3270) */
181630088Sminshall     if (!ISend && TTYROOM()) {
181730088Sminshall 	FD_SET(net, &ibits);
181830088Sminshall     }
181930088Sminshall #   endif /* !defined(TN3270) */
182030088Sminshall     if (!SYNCHing) {
182130088Sminshall 	FD_SET(net, &xbits);
182230088Sminshall     }
182330088Sminshall #   if defined(TN3270) && defined(unix)
182430088Sminshall     if (HaveInput) {
182530088Sminshall 	HaveInput = 0;
182630088Sminshall 	signal(SIGIO, inputAvailable);
182730088Sminshall     }
182830088Sminshall #endif	/* defined(TN3270) && defined(unix) */
182930088Sminshall     if ((c = select(16, &ibits, &obits, &xbits,
183030088Sminshall 			block? (struct timeval *)0 : &TimeValue)) < 1) {
183130088Sminshall 	if (c == -1) {
183230088Sminshall 		    /*
183330088Sminshall 		     * we can get EINTR if we are in line mode,
183430088Sminshall 		     * and the user does an escape (TSTP), or
183530088Sminshall 		     * some other signal generator.
183630088Sminshall 		     */
183730088Sminshall 	    if (errno == EINTR) {
183830088Sminshall 		return 0;
183930088Sminshall 	    }
184030088Sminshall #	    if defined(TN3270)
184130088Sminshall 		    /*
184230088Sminshall 		     * we can get EBADF if we were in transparent
184330088Sminshall 		     * mode, and the transcom process died.
184430088Sminshall 		    */
184530088Sminshall 	    if (errno == EBADF) {
184630088Sminshall 			/*
184730088Sminshall 			 * zero the bits (even though kernel does it)
184830088Sminshall 			 * to make sure we are selecting on the right
184930088Sminshall 			 * ones.
185030088Sminshall 			*/
185130088Sminshall 		FD_ZERO(&ibits);
185230088Sminshall 		FD_ZERO(&obits);
185330088Sminshall 		FD_ZERO(&xbits);
185430088Sminshall 		return 0;
185530088Sminshall 	    }
185630088Sminshall #	    endif /* defined(TN3270) */
185730088Sminshall 		    /* I don't like this, does it ever happen? */
185830088Sminshall 	    printf("sleep(5) from telnet, after select\r\n");
185930088Sminshall #if	defined(unix)
186030088Sminshall 	    sleep(5);
186130088Sminshall #endif	/* defined(unix) */
186230088Sminshall 	}
186330088Sminshall 	return 0;
186430088Sminshall     }
186530088Sminshall 
186630088Sminshall     /*
186730088Sminshall      * Any urgent data?
186830088Sminshall      */
186930088Sminshall     if (FD_ISSET(net, &xbits)) {
187030088Sminshall 	FD_CLR(net, &xbits);
187130088Sminshall 	SYNCHing = 1;
187230088Sminshall 	ttyflush();	/* flush already enqueued data */
187330088Sminshall     }
187430088Sminshall 
187530088Sminshall     /*
187630088Sminshall      * Something to read from the network...
187730088Sminshall      */
187830088Sminshall     if (FD_ISSET(net, &ibits)) {
187930088Sminshall 	int canread;
188030088Sminshall 
188130088Sminshall 	FD_CLR(net, &ibits);
188230088Sminshall 	if (scc == 0) {
188330088Sminshall 	    sbp = sibuf;
188430088Sminshall 	}
188530088Sminshall 	canread = sibuf + sizeof sibuf - sbp;
188630088Sminshall #if	!defined(SO_OOBINLINE)
188730088Sminshall 	    /*
188830088Sminshall 	     * In 4.2 (and some early 4.3) systems, the
188930088Sminshall 	     * OOB indication and data handling in the kernel
189030088Sminshall 	     * is such that if two separate TCP Urgent requests
189130088Sminshall 	     * come in, one byte of TCP data will be overlaid.
189230088Sminshall 	     * This is fatal for Telnet, but we try to live
189330088Sminshall 	     * with it.
189430088Sminshall 	     *
189530088Sminshall 	     * In addition, in 4.2 (and...), a special protocol
189630088Sminshall 	     * is needed to pick up the TCP Urgent data in
189730088Sminshall 	     * the correct sequence.
189830088Sminshall 	     *
189930088Sminshall 	     * What we do is:  if we think we are in urgent
190030088Sminshall 	     * mode, we look to see if we are "at the mark".
190130088Sminshall 	     * If we are, we do an OOB receive.  If we run
190230088Sminshall 	     * this twice, we will do the OOB receive twice,
190330088Sminshall 	     * but the second will fail, since the second
190430088Sminshall 	     * time we were "at the mark", but there wasn't
190530088Sminshall 	     * any data there (the kernel doesn't reset
190630088Sminshall 	     * "at the mark" until we do a normal read).
190730088Sminshall 	     * Once we've read the OOB data, we go ahead
190830088Sminshall 	     * and do normal reads.
190930088Sminshall 	     *
191030088Sminshall 	     * There is also another problem, which is that
191130088Sminshall 	     * since the OOB byte we read doesn't put us
191230088Sminshall 	     * out of OOB state, and since that byte is most
191330088Sminshall 	     * likely the TELNET DM (data mark), we would
191430088Sminshall 	     * stay in the TELNET SYNCH (SYNCHing) state.
191530088Sminshall 	     * So, clocks to the rescue.  If we've "just"
191630088Sminshall 	     * received a DM, then we test for the
191730088Sminshall 	     * presence of OOB data when the receive OOB
191830088Sminshall 	     * fails (and AFTER we did the normal mode read
191930088Sminshall 	     * to clear "at the mark").
192030088Sminshall 	     */
192130088Sminshall 	if (SYNCHing) {
192230088Sminshall 	    int atmark;
192330088Sminshall 
192430088Sminshall 	    ioctl(net, SIOCATMARK, (char *)&atmark);
192530088Sminshall 	    if (atmark) {
192630088Sminshall 		c = recv(net, sibuf, canread, MSG_OOB);
192730088Sminshall 		if ((c == -1) && (errno == EINVAL)) {
192830088Sminshall 		    c = read(net, sibuf, canread);
192930088Sminshall 		    if (clocks.didnetreceive < clocks.gotDM) {
193030088Sminshall 			SYNCHing = stilloob(net);
193130088Sminshall 		    }
193230088Sminshall 		}
193330088Sminshall 	    } else {
193430088Sminshall 		c = read(net, sibuf, canread);
193530088Sminshall 	    }
193630088Sminshall 	} else {
193730088Sminshall 	    c = read(net, sibuf, canread);
193830088Sminshall 	}
193930088Sminshall 	settimer(didnetreceive);
194030088Sminshall #else	/* !defined(SO_OOBINLINE) */
194130088Sminshall 	c = read(net, sbp, canread);
194230088Sminshall #endif	/* !defined(SO_OOBINLINE) */
194330088Sminshall 	if (c < 0 && errno == EWOULDBLOCK) {
194430088Sminshall 	    c = 0;
194530088Sminshall 	} else if (c <= 0) {
194630088Sminshall 	    return -1;
194730088Sminshall 	}
194830088Sminshall 	if (netdata) {
194930088Sminshall 	    Dump('<', sbp, c);
195030088Sminshall 	}
195130088Sminshall 	scc += c;
195230088Sminshall 	returnValue = 1;
195330088Sminshall     }
195430088Sminshall 
195530088Sminshall     /*
195630088Sminshall      * Something to read from the tty...
195730088Sminshall      */
195830088Sminshall     if (FD_ISSET(tin, &ibits)) {
195930088Sminshall 	FD_CLR(tin, &ibits);
196030088Sminshall 	if (tcc == 0) {
196130088Sminshall 	    tbp = tibuf;	/* nothing left, reset */
196230088Sminshall 	}
196330088Sminshall 	c = read(tin, tbp, tibuf+sizeof tibuf - tbp);
196430088Sminshall 	if (c < 0 && errno == EWOULDBLOCK) {
196530088Sminshall 	    c = 0;
196630088Sminshall 	} else {
196730088Sminshall 	    /* EOF detection for line mode!!!! */
196830088Sminshall 	    if (c == 0 && MODE_LOCAL_CHARS(globalmode)) {
196930088Sminshall 			/* must be an EOF... */
197030088Sminshall 		*tbp = ntc.t_eofc;
197130088Sminshall 		c = 1;
197230088Sminshall 	    }
197330088Sminshall 	    if (c <= 0) {
197430088Sminshall 		tcc = c;
197530088Sminshall 		return -1;
197630088Sminshall 	    }
197730088Sminshall 	}
197830088Sminshall 	tcc += c;
197930088Sminshall 	returnValue = 1;		/* did something useful */
198030088Sminshall     }
198130088Sminshall 
198230088Sminshall #   if defined(TN3270)
198330088Sminshall     if (tcc > 0) {
198430088Sminshall 	if (In3270) {
198530088Sminshall 	    c = DataFromTerminal(tbp, tcc);
198630088Sminshall 	    if (c) {
198730088Sminshall 		returnValue = 1;
198830088Sminshall 	    }
198930088Sminshall 	    tcc -= c;
199030088Sminshall 	    tbp += c;
199130088Sminshall 	} else {
199230320Sminshall #   endif /* defined(TN3270) */
199330088Sminshall 	    returnValue = 1;
199430088Sminshall 	    while (tcc > 0) {
199530088Sminshall 		register int sc;
199630088Sminshall 
199730088Sminshall 		if (NETROOM() < 2) {
199830088Sminshall 		    flushline = 1;
199930088Sminshall 		    break;
200030088Sminshall 		}
200130088Sminshall 		c = *tbp++ & 0xff, sc = strip(c), tcc--;
200230088Sminshall 		if (sc == escape) {
200330088Sminshall 		    command(0);
200430088Sminshall 		    tcc = 0;
200530088Sminshall 		    flushline = 1;
200630088Sminshall 		    break;
200730088Sminshall 		} else if (MODE_LINE(globalmode) && (sc == echoc)) {
200830088Sminshall 		    if (tcc > 0 && strip(*tbp) == echoc) {
200930088Sminshall 			tbp++;
201030088Sminshall 			tcc--;
201130088Sminshall 		    } else {
201230088Sminshall 			dontlecho = !dontlecho;
201330088Sminshall 			settimer(echotoggle);
201430088Sminshall 			setconnmode();
201530088Sminshall 			tcc = 0;
201630088Sminshall 			flushline = 1;
201730088Sminshall 			break;
201830088Sminshall 		    }
201930088Sminshall 		}
202030088Sminshall 		if (localchars) {
202130088Sminshall 		    if (sc == ntc.t_intrc) {
202230088Sminshall 			intp();
202330088Sminshall 			break;
202430088Sminshall 		    } else if (sc == ntc.t_quitc) {
202530088Sminshall 			sendbrk();
202630088Sminshall 			break;
202730088Sminshall 		    } else if (sc == nltc.t_flushc) {
202830088Sminshall 			NET2ADD(IAC, AO);
202930088Sminshall 			if (autoflush) {
203030088Sminshall 			    doflush();
203130088Sminshall 			}
203230088Sminshall 			break;
203330088Sminshall 		    } else if (MODE_LOCAL_CHARS(globalmode)) {
203430088Sminshall 			;
203530088Sminshall 		    } else if (sc == nttyb.sg_kill) {
203630088Sminshall 			NET2ADD(IAC, EL);
203730088Sminshall 			break;
203830088Sminshall 		    } else if (sc == nttyb.sg_erase) {
203930088Sminshall 			NET2ADD(IAC, EC);
204030088Sminshall 			break;
204130088Sminshall 		    }
204230088Sminshall 		}
204330088Sminshall 		switch (c) {
204430088Sminshall 		case '\n':
204530088Sminshall 			/*
204630088Sminshall 			 * If we are in CRMOD mode (\r ==> \n)
204730088Sminshall 			 * on our local machine, then probably
204830088Sminshall 			 * a newline (unix) is CRLF (TELNET).
204930088Sminshall 			 */
205030088Sminshall 		    if (MODE_LOCAL_CHARS(globalmode)) {
205130088Sminshall 			NETADD('\r');
205230088Sminshall 		    }
205330088Sminshall 		    NETADD('\n');
205430088Sminshall 		    flushline = 1;
205530088Sminshall 		    break;
205630088Sminshall 		case '\r':
205730088Sminshall 		    NET2ADD('\r', '\0');
205830088Sminshall 		    flushline = 1;
205930088Sminshall 		    break;
206030088Sminshall 		case IAC:
206130088Sminshall 		    NET2ADD(IAC, IAC);
206230088Sminshall 		    break;
206330088Sminshall 		default:
206430088Sminshall 		    NETADD(c);
206530088Sminshall 		    break;
206630088Sminshall 		}
206730088Sminshall 	    }
206830088Sminshall #   if defined(TN3270)
206930088Sminshall 	}
207030088Sminshall     }
207130088Sminshall #   endif /* defined(TN3270) */
207230088Sminshall 
207330088Sminshall     if ((!MODE_LINE(globalmode) || flushline) &&
207430088Sminshall 	FD_ISSET(net, &obits) && (NETBYTES() > 0)) {
207530088Sminshall 	FD_CLR(net, &obits);
207630088Sminshall 	returnValue = netflush();
207730088Sminshall     }
207830088Sminshall     if (scc > 0) {
207930088Sminshall #	if !defined(TN3270)
208030088Sminshall 	telrcv();
208130088Sminshall 	returnValue = 1;
208230088Sminshall #	else /* !defined(TN3270) */
208330088Sminshall 	returnValue = Push3270();
208430088Sminshall #	endif /* !defined(TN3270) */
208530088Sminshall     }
208630088Sminshall     if (FD_ISSET(tout, &obits) && (TTYBYTES() > 0)) {
208730088Sminshall 	FD_CLR(tout, &obits);
208830088Sminshall 	returnValue = ttyflush();
208930088Sminshall     }
209030088Sminshall     return returnValue;
209130088Sminshall }
209230088Sminshall 
209330088Sminshall /*
209430088Sminshall  * Select from tty and network...
209530088Sminshall  */
209630088Sminshall static void
209730088Sminshall telnet()
209830088Sminshall {
209930088Sminshall     int on = 1;
210030088Sminshall #if	defined(TN3270) && defined(unix)
210130088Sminshall     int myPid;
210230088Sminshall #endif	/* defined(TN3270) */
210330088Sminshall 
210430088Sminshall     tout = fileno(stdout);
210530088Sminshall     tin = fileno(stdin);
210630088Sminshall     setconnmode();
210730088Sminshall     scc = 0;
210830088Sminshall     tcc = 0;
210930088Sminshall     FD_ZERO(&ibits);
211030088Sminshall     FD_ZERO(&obits);
211130088Sminshall     FD_ZERO(&xbits);
211230088Sminshall 
211330088Sminshall     ioctl(net, FIONBIO, (char *)&on);
211430088Sminshall 
211530088Sminshall #if	defined(TN3270)
211630088Sminshall #if	!defined(DEBUG)		/* DBX can't handle! */
211730088Sminshall     ioctl(net, FIOASYNC, (char *)&on);	/* hear about input */
211830088Sminshall #endif	/* !defined(DEBUG) */
211930088Sminshall 
212030088Sminshall #if	defined(unix)
212130088Sminshall     myPid = getpid();
212230088Sminshall #if	defined(NOT43)
212330088Sminshall     myPid = -myPid;
212430088Sminshall #endif	/* defined(NOT43) */
212530088Sminshall     ioctl(net, SIOCSPGRP, (char *)&myPid);	/* set my pid */
212630088Sminshall #endif	/* defined(unix) */
212730088Sminshall 
212830088Sminshall #endif	/* defined(TN3270) */
212930088Sminshall 
213030088Sminshall #if	defined(SO_OOBINLINE)
213130088Sminshall     setsockopt(net, SOL_SOCKET, SO_OOBINLINE, &on, sizeof on);
213230088Sminshall #endif	/* defined(SO_OOBINLINE) */
213330088Sminshall 
213430320Sminshall #   if !defined(TN3270)
213530088Sminshall     if (telnetport) {
213630088Sminshall 	if (!hisopts[TELOPT_SGA]) {
213730088Sminshall 	    willoption(TELOPT_SGA, 0);
213830088Sminshall 	}
213930088Sminshall 	if (!myopts[TELOPT_TTYPE]) {
214030088Sminshall 	    dooption(TELOPT_TTYPE, 0);
214130088Sminshall 	}
214230088Sminshall     }
214330320Sminshall #   endif /* !defined(TN3270) */
214430088Sminshall 
214530088Sminshall #   if !defined(TN3270)
214630088Sminshall     for (;;) {
214730088Sminshall 	if (Scheduler(1) == -1) {
214830088Sminshall 	    setcommandmode();
214930088Sminshall 	    return;
215030088Sminshall 	}
215130088Sminshall     }
215230088Sminshall #   else /* !defined(TN3270) */
215330088Sminshall     for (;;) {
215430088Sminshall 	int schedValue;
215530088Sminshall 
215630088Sminshall 	while (!In3270) {
215730088Sminshall 	    if (Scheduler(1) == -1) {
215830088Sminshall 		setcommandmode();
215930088Sminshall 		return;
216030088Sminshall 	    }
216130088Sminshall 	}
216230088Sminshall 
216330088Sminshall 	while ((schedValue = Scheduler(0)) != 0) {
216430088Sminshall 	    if (schedValue == -1) {
216530088Sminshall 		setcommandmode();
216630088Sminshall 		return;
216730088Sminshall 	    }
216830088Sminshall 	}
216930088Sminshall 		/* If there is data waiting to go out to terminal, don't
217030088Sminshall 		 * schedule any more data for the terminal.
217130088Sminshall 		 */
217230088Sminshall 	if (tfrontp-tbackp) {
217330088Sminshall 	    schedValue = 1;
217430088Sminshall 	} else {
217530088Sminshall 	    schedValue = DoTerminalOutput();
217630088Sminshall 	}
217730088Sminshall 	if (schedValue) {
217830088Sminshall 	    if (Scheduler(1) == -1) {
217930088Sminshall 		setcommandmode();
218030088Sminshall 		return;
218130088Sminshall 	    }
218230088Sminshall 	}
218330088Sminshall     }
218430088Sminshall #   endif /* !defined(TN3270) */
218530088Sminshall }
218630088Sminshall 
218730088Sminshall /*
218830088Sminshall  *	The following are data structures and routines for
218930088Sminshall  *	the "send" command.
219030088Sminshall  *
219130088Sminshall  */
219230088Sminshall 
219330088Sminshall struct sendlist {
219430088Sminshall     char	*name;		/* How user refers to it (case independent) */
219530088Sminshall     int		what;		/* Character to be sent (<0 ==> special) */
219630088Sminshall     char	*help;		/* Help information (0 ==> no help) */
219730088Sminshall #if	defined(NOT43)
219830088Sminshall     int		(*routine)();	/* Routine to perform (for special ops) */
219930088Sminshall #else	/* defined(NOT43) */
220030088Sminshall     void	(*routine)();	/* Routine to perform (for special ops) */
220130088Sminshall #endif	/* defined(NOT43) */
220230088Sminshall };
220330088Sminshall 
220430088Sminshall #define	SENDQUESTION	-1
220530088Sminshall #define	SENDESCAPE	-3
220630088Sminshall 
220730088Sminshall static struct sendlist Sendlist[] = {
220830088Sminshall     { "ao", AO, "Send Telnet Abort output" },
220930088Sminshall     { "ayt", AYT, "Send Telnet 'Are You There'" },
221030088Sminshall     { "brk", BREAK, "Send Telnet Break" },
221130088Sminshall     { "ec", EC, "Send Telnet Erase Character" },
221230088Sminshall     { "el", EL, "Send Telnet Erase Line" },
221330088Sminshall     { "escape", SENDESCAPE, "Send current escape character" },
221430088Sminshall     { "ga", GA, "Send Telnet 'Go Ahead' sequence" },
221530088Sminshall     { "ip", IP, "Send Telnet Interrupt Process" },
221630088Sminshall     { "nop", NOP, "Send Telnet 'No operation'" },
221730088Sminshall     { "synch", SYNCH, "Perform Telnet 'Synch operation'", dosynch },
221830088Sminshall     { "?", SENDQUESTION, "Display send options" },
221930088Sminshall     { 0 }
222030088Sminshall };
222130088Sminshall 
222230088Sminshall static struct sendlist Sendlist2[] = {		/* some synonyms */
222330088Sminshall 	{ "break", BREAK, 0 },
222430088Sminshall 
222530088Sminshall 	{ "intp", IP, 0 },
222630088Sminshall 	{ "interrupt", IP, 0 },
222730088Sminshall 	{ "intr", IP, 0 },
222830088Sminshall 
222930088Sminshall 	{ "help", SENDQUESTION, 0 },
223030088Sminshall 
223130088Sminshall 	{ 0 }
223230088Sminshall };
223330088Sminshall 
223430088Sminshall static char **
223530088Sminshall getnextsend(name)
223630088Sminshall char *name;
223730088Sminshall {
223830088Sminshall     struct sendlist *c = (struct sendlist *) name;
223930088Sminshall 
224030088Sminshall     return (char **) (c+1);
224130088Sminshall }
224230088Sminshall 
224330088Sminshall static struct sendlist *
224430088Sminshall getsend(name)
224530088Sminshall char *name;
224630088Sminshall {
224730088Sminshall     struct sendlist *sl;
224830088Sminshall 
224930088Sminshall     if ((sl = (struct sendlist *)
225030088Sminshall 			genget(name, (char **) Sendlist, getnextsend)) != 0) {
225130088Sminshall 	return sl;
225230088Sminshall     } else {
225330088Sminshall 	return (struct sendlist *)
225430088Sminshall 				genget(name, (char **) Sendlist2, getnextsend);
225530088Sminshall     }
225630088Sminshall }
225730088Sminshall 
225830088Sminshall static
225930088Sminshall sendcmd(argc, argv)
226030088Sminshall int	argc;
226130088Sminshall char	**argv;
226230088Sminshall {
226330088Sminshall     int what;		/* what we are sending this time */
226430088Sminshall     int count;		/* how many bytes we are going to need to send */
226530088Sminshall     int i;
226630088Sminshall     int question = 0;	/* was at least one argument a question */
226730088Sminshall     struct sendlist *s;	/* pointer to current command */
226830088Sminshall 
226930088Sminshall     if (argc < 2) {
227030088Sminshall 	printf("need at least one argument for 'send' command\n");
227130088Sminshall 	printf("'send ?' for help\n");
227230088Sminshall 	return 0;
227330088Sminshall     }
227430088Sminshall     /*
227530088Sminshall      * First, validate all the send arguments.
227630088Sminshall      * In addition, we see how much space we are going to need, and
227730088Sminshall      * whether or not we will be doing a "SYNCH" operation (which
227830088Sminshall      * flushes the network queue).
227930088Sminshall      */
228030088Sminshall     count = 0;
228130088Sminshall     for (i = 1; i < argc; i++) {
228230088Sminshall 	s = getsend(argv[i]);
228330088Sminshall 	if (s == 0) {
228430088Sminshall 	    printf("Unknown send argument '%s'\n'send ?' for help.\n",
228530088Sminshall 			argv[i]);
228630088Sminshall 	    return 0;
228730088Sminshall 	} else if (s == Ambiguous(struct sendlist *)) {
228830088Sminshall 	    printf("Ambiguous send argument '%s'\n'send ?' for help.\n",
228930088Sminshall 			argv[i]);
229030088Sminshall 	    return 0;
229130088Sminshall 	}
229230088Sminshall 	switch (s->what) {
229330088Sminshall 	case SENDQUESTION:
229430088Sminshall 	    break;
229530088Sminshall 	case SENDESCAPE:
229630088Sminshall 	    count += 1;
229730088Sminshall 	    break;
229830088Sminshall 	case SYNCH:
229930088Sminshall 	    count += 2;
230030088Sminshall 	    break;
230130088Sminshall 	default:
230230088Sminshall 	    count += 2;
230330088Sminshall 	    break;
230430088Sminshall 	}
230530088Sminshall     }
230630088Sminshall     /* Now, do we have enough room? */
230730088Sminshall     if (NETROOM() < count) {
230830088Sminshall 	printf("There is not enough room in the buffer TO the network\n");
230930088Sminshall 	printf("to process your request.  Nothing will be done.\n");
231030088Sminshall 	printf("('send synch' will throw away most data in the network\n");
231130088Sminshall 	printf("buffer, if this might help.)\n");
231230088Sminshall 	return 0;
231330088Sminshall     }
231430088Sminshall     /* OK, they are all OK, now go through again and actually send */
231530088Sminshall     for (i = 1; i < argc; i++) {
231630088Sminshall 	if ((s = getsend(argv[i])) == 0) {
231730088Sminshall 	    fprintf(stderr, "Telnet 'send' error - argument disappeared!\n");
231830088Sminshall 	    quit();
231930088Sminshall 	    /*NOTREACHED*/
232030088Sminshall 	}
232130088Sminshall 	if (s->routine) {
232230088Sminshall 	    (*s->routine)(s);
232330088Sminshall 	} else {
232430088Sminshall 	    switch (what = s->what) {
232530088Sminshall 	    case SYNCH:
232630088Sminshall 		dosynch();
232730088Sminshall 		break;
232830088Sminshall 	    case SENDQUESTION:
232930088Sminshall 		for (s = Sendlist; s->name; s++) {
233030088Sminshall 		    if (s->help) {
233130088Sminshall 			printf(s->name);
233230088Sminshall 			if (s->help) {
233330088Sminshall 			    printf("\t%s", s->help);
233430088Sminshall 			}
233530088Sminshall 			printf("\n");
233630088Sminshall 		    }
233730088Sminshall 		}
233830088Sminshall 		question = 1;
233930088Sminshall 		break;
234030088Sminshall 	    case SENDESCAPE:
234130088Sminshall 		NETADD(escape);
234230088Sminshall 		break;
234330088Sminshall 	    default:
234430088Sminshall 		NET2ADD(IAC, what);
234530088Sminshall 		break;
234630088Sminshall 	    }
234730088Sminshall 	}
234830088Sminshall     }
234930088Sminshall     return !question;
235030088Sminshall }
235130088Sminshall 
235230088Sminshall /*
235330088Sminshall  * The following are the routines and data structures referred
235430088Sminshall  * to by the arguments to the "toggle" command.
235530088Sminshall  */
235630088Sminshall 
235730088Sminshall static
235830088Sminshall lclchars()
235930088Sminshall {
236030088Sminshall     donelclchars = 1;
236130088Sminshall     return 1;
236230088Sminshall }
236330088Sminshall 
236430088Sminshall static
236530088Sminshall togdebug()
236630088Sminshall {
236730088Sminshall #ifndef	NOT43
236830088Sminshall     if (net > 0 &&
236930088Sminshall 	setsockopt(net, SOL_SOCKET, SO_DEBUG, (char *)&debug, sizeof(debug))
237030088Sminshall 									< 0) {
237130088Sminshall 	    perror("setsockopt (SO_DEBUG)");
237230088Sminshall     }
237330320Sminshall #else	/* NOT43 */
237430088Sminshall     if (debug) {
237530088Sminshall 	if (net > 0 && setsockopt(net, SOL_SOCKET, SO_DEBUG, 0, 0) < 0)
237630088Sminshall 	    perror("setsockopt (SO_DEBUG)");
237730088Sminshall     } else
237830088Sminshall 	printf("Cannot turn off socket debugging\n");
237930320Sminshall #endif	/* NOT43 */
238030088Sminshall     return 1;
238130088Sminshall }
238230088Sminshall 
238330088Sminshall 
238430088Sminshall 
238530088Sminshall extern int togglehelp();
238630088Sminshall 
238730088Sminshall struct togglelist {
238830088Sminshall     char	*name;		/* name of toggle */
238930088Sminshall     char	*help;		/* help message */
239030088Sminshall     int		(*handler)();	/* routine to do actual setting */
239130088Sminshall     int		dohelp;		/* should we display help information */
239230088Sminshall     int		*variable;
239330088Sminshall     char	*actionexplanation;
239430088Sminshall };
239530088Sminshall 
239630088Sminshall static struct togglelist Togglelist[] = {
239730088Sminshall     { "autoflush",
239830088Sminshall 	"toggle flushing of output when sending interrupt characters",
239930088Sminshall 	    0,
240030088Sminshall 		1,
240130088Sminshall 		    &autoflush,
240230088Sminshall 			"flush output when sending interrupt characters" },
240330088Sminshall     { "autosynch",
240430088Sminshall 	"toggle automatic sending of interrupt characters in urgent mode",
240530088Sminshall 	    0,
240630088Sminshall 		1,
240730088Sminshall 		    &autosynch,
240830088Sminshall 			"send interrupt characters in urgent mode" },
240930088Sminshall     { "crmod",
241030088Sminshall 	"toggle mapping of received carriage returns",
241130088Sminshall 	    0,
241230088Sminshall 		1,
241330088Sminshall 		    &crmod,
241430088Sminshall 			"map carriage return on output" },
241530088Sminshall     { "localchars",
241630088Sminshall 	"toggle local recognition of certain control characters",
241730088Sminshall 	    lclchars,
241830088Sminshall 		1,
241930088Sminshall 		    &localchars,
242030088Sminshall 			"recognize certain control characters" },
242130088Sminshall     { " ", "", 0, 1 },		/* empty line */
242230088Sminshall     { "debug",
242330088Sminshall 	"(debugging) toggle debugging",
242430088Sminshall 	    togdebug,
242530088Sminshall 		1,
242630088Sminshall 		    &debug,
242730088Sminshall 			"turn on socket level debugging" },
242830088Sminshall     { "netdata",
242930088Sminshall 	"(debugging) toggle printing of hexadecimal network data",
243030088Sminshall 	    0,
243130088Sminshall 		1,
243230088Sminshall 		    &netdata,
243330088Sminshall 			"print hexadecimal representation of network traffic" },
243430088Sminshall     { "options",
243530088Sminshall 	"(debugging) toggle viewing of options processing",
243630088Sminshall 	    0,
243730088Sminshall 		1,
243830088Sminshall 		    &showoptions,
243930088Sminshall 			"show option processing" },
244030088Sminshall     { " ", "", 0, 1 },		/* empty line */
244130088Sminshall     { "?",
244230088Sminshall 	"display help information",
244330088Sminshall 	    togglehelp,
244430088Sminshall 		1 },
244530088Sminshall     { "help",
244630088Sminshall 	"display help information",
244730088Sminshall 	    togglehelp,
244830088Sminshall 		0 },
244930088Sminshall     { 0 }
245030088Sminshall };
245130088Sminshall 
245230088Sminshall static
245330088Sminshall togglehelp()
245430088Sminshall {
245530088Sminshall     struct togglelist *c;
245630088Sminshall 
245730088Sminshall     for (c = Togglelist; c->name; c++) {
245830088Sminshall 	if (c->dohelp) {
245930088Sminshall 	    printf("%s\t%s\n", c->name, c->help);
246030088Sminshall 	}
246130088Sminshall     }
246230088Sminshall     return 0;
246330088Sminshall }
246430088Sminshall 
246530088Sminshall static char **
246630088Sminshall getnexttoggle(name)
246730088Sminshall char *name;
246830088Sminshall {
246930088Sminshall     struct togglelist *c = (struct togglelist *) name;
247030088Sminshall 
247130088Sminshall     return (char **) (c+1);
247230088Sminshall }
247330088Sminshall 
247430088Sminshall static struct togglelist *
247530088Sminshall gettoggle(name)
247630088Sminshall char *name;
247730088Sminshall {
247830088Sminshall     return (struct togglelist *)
247930088Sminshall 			genget(name, (char **) Togglelist, getnexttoggle);
248030088Sminshall }
248130088Sminshall 
248230088Sminshall static
248330088Sminshall toggle(argc, argv)
248430088Sminshall int	argc;
248530088Sminshall char	*argv[];
248630088Sminshall {
248730088Sminshall     int retval = 1;
248830088Sminshall     char *name;
248930088Sminshall     struct togglelist *c;
249030088Sminshall 
249130088Sminshall     if (argc < 2) {
249230088Sminshall 	fprintf(stderr,
249330088Sminshall 	    "Need an argument to 'toggle' command.  'toggle ?' for help.\n");
249430088Sminshall 	return 0;
249530088Sminshall     }
249630088Sminshall     argc--;
249730088Sminshall     argv++;
249830088Sminshall     while (argc--) {
249930088Sminshall 	name = *argv++;
250030088Sminshall 	c = gettoggle(name);
250130088Sminshall 	if (c == Ambiguous(struct togglelist *)) {
250230088Sminshall 	    fprintf(stderr, "'%s': ambiguous argument ('toggle ?' for help).\n",
250330088Sminshall 					name);
250430088Sminshall 	    return 0;
250530088Sminshall 	} else if (c == 0) {
250630088Sminshall 	    fprintf(stderr, "'%s': unknown argument ('toggle ?' for help).\n",
250730088Sminshall 					name);
250830088Sminshall 	    return 0;
250930088Sminshall 	} else {
251030088Sminshall 	    if (c->variable) {
251130088Sminshall 		*c->variable = !*c->variable;		/* invert it */
251230088Sminshall 		printf("%s %s.\n", *c->variable? "Will" : "Won't",
251330088Sminshall 							c->actionexplanation);
251430088Sminshall 	    }
251530088Sminshall 	    if (c->handler) {
251630088Sminshall 		retval &= (*c->handler)(c);
251730088Sminshall 	    }
251830088Sminshall 	}
251930088Sminshall     }
252030088Sminshall     return retval;
252130088Sminshall }
252230088Sminshall 
252330088Sminshall /*
252430088Sminshall  * The following perform the "set" command.
252530088Sminshall  */
252630088Sminshall 
252730088Sminshall struct setlist {
252830088Sminshall     char *name;				/* name */
252930088Sminshall     char *help;				/* help information */
253030088Sminshall     char *charp;			/* where it is located at */
253130088Sminshall };
253230088Sminshall 
253330088Sminshall static struct setlist Setlist[] = {
253430088Sminshall     { "echo", 	"character to toggle local echoing on/off", &echoc },
253530088Sminshall     { "escape",	"character to escape back to telnet command mode", &escape },
253630088Sminshall     { " ", "" },
253730088Sminshall     { " ", "The following need 'localchars' to be toggled true", 0 },
253830088Sminshall     { "erase",	"character to cause an Erase Character", &nttyb.sg_erase },
253930088Sminshall     { "flushoutput", "character to cause an Abort Oubput", &nltc.t_flushc },
254030088Sminshall     { "interrupt", "character to cause an Interrupt Process", &ntc.t_intrc },
254130088Sminshall     { "kill",	"character to cause an Erase Line", &nttyb.sg_kill },
254230088Sminshall     { "quit",	"character to cause a Break", &ntc.t_quitc },
254330088Sminshall     { "eof",	"character to cause an EOF ", &ntc.t_eofc },
254430088Sminshall     { 0 }
254530088Sminshall };
254630088Sminshall 
254730088Sminshall static char **
254830088Sminshall getnextset(name)
254930088Sminshall char *name;
255030088Sminshall {
255130088Sminshall     struct setlist *c = (struct setlist *)name;
255230088Sminshall 
255330088Sminshall     return (char **) (c+1);
255430088Sminshall }
255530088Sminshall 
255630088Sminshall static struct setlist *
255730088Sminshall getset(name)
255830088Sminshall char *name;
255930088Sminshall {
256030088Sminshall     return (struct setlist *) genget(name, (char **) Setlist, getnextset);
256130088Sminshall }
256230088Sminshall 
256330088Sminshall static
256430088Sminshall setcmd(argc, argv)
256530088Sminshall int	argc;
256630088Sminshall char	*argv[];
256730088Sminshall {
256830088Sminshall     int value;
256930088Sminshall     struct setlist *ct;
257030088Sminshall 
257130088Sminshall     /* XXX back we go... sigh */
257230088Sminshall     if (argc != 3) {
257330088Sminshall 	if ((argc == 2) &&
257430088Sminshall 		    ((!strcmp(argv[1], "?")) || (!strcmp(argv[1], "help")))) {
257530088Sminshall 	    for (ct = Setlist; ct->name; ct++) {
257630088Sminshall 		printf("%s\t%s\n", ct->name, ct->help);
257730088Sminshall 	    }
257830088Sminshall 	    printf("?\tdisplay help information\n");
257930088Sminshall 	} else {
258030088Sminshall 	    printf("Format is 'set Name Value'\n'set ?' for help.\n");
258130088Sminshall 	}
258230088Sminshall 	return 0;
258330088Sminshall     }
258430088Sminshall 
258530088Sminshall     ct = getset(argv[1]);
258630088Sminshall     if (ct == 0) {
258730088Sminshall 	fprintf(stderr, "'%s': unknown argument ('set ?' for help).\n",
258830088Sminshall 			argv[1]);
258930088Sminshall 	return 0;
259030088Sminshall     } else if (ct == Ambiguous(struct setlist *)) {
259130088Sminshall 	fprintf(stderr, "'%s': ambiguous argument ('set ?' for help).\n",
259230088Sminshall 			argv[1]);
259330088Sminshall 	return 0;
259430088Sminshall     } else {
259530088Sminshall 	if (strcmp("off", argv[2])) {
259630088Sminshall 	    value = special(argv[2]);
259730088Sminshall 	} else {
259830088Sminshall 	    value = -1;
259930088Sminshall 	}
260030088Sminshall 	*(ct->charp) = value;
260130088Sminshall 	printf("%s character is '%s'.\n", ct->name, control(*(ct->charp)));
260230088Sminshall     }
260330088Sminshall     return 1;
260430088Sminshall }
260530088Sminshall 
260630088Sminshall /*
260730088Sminshall  * The following are the data structures and routines for the
260830088Sminshall  * 'mode' command.
260930088Sminshall  */
261030088Sminshall 
261130088Sminshall static
261230088Sminshall dolinemode()
261330088Sminshall {
261430088Sminshall     if (hisopts[TELOPT_SGA]) {
261530088Sminshall 	wontoption(TELOPT_SGA, 0);
261630088Sminshall     }
261730088Sminshall     if (hisopts[TELOPT_ECHO]) {
261830088Sminshall 	wontoption(TELOPT_ECHO, 0);
261930088Sminshall     }
262030088Sminshall     return 1;
262130088Sminshall }
262230088Sminshall 
262330088Sminshall static
262430088Sminshall docharmode()
262530088Sminshall {
262630088Sminshall     if (!hisopts[TELOPT_SGA]) {
262730088Sminshall 	willoption(TELOPT_SGA, 0);
262830088Sminshall     }
262930088Sminshall     if (!hisopts[TELOPT_ECHO]) {
263030088Sminshall 	willoption(TELOPT_ECHO, 0);
263130088Sminshall     }
263230088Sminshall     return 1;
263330088Sminshall }
263430088Sminshall 
263530088Sminshall static struct cmd Modelist[] = {
263630088Sminshall     { "character",	"character-at-a-time mode",	docharmode, 1, 1 },
263730088Sminshall     { "line",		"line-by-line mode",		dolinemode, 1, 1 },
263830088Sminshall     { 0 },
263930088Sminshall };
264030088Sminshall 
264130088Sminshall static char **
264230088Sminshall getnextmode(name)
264330088Sminshall char *name;
264430088Sminshall {
264530088Sminshall     struct cmd *c = (struct cmd *) name;
264630088Sminshall 
264730088Sminshall     return (char **) (c+1);
264830088Sminshall }
264930088Sminshall 
265030088Sminshall static struct cmd *
265130088Sminshall getmodecmd(name)
265230088Sminshall char *name;
265330088Sminshall {
265430088Sminshall     return (struct cmd *) genget(name, (char **) Modelist, getnextmode);
265530088Sminshall }
265630088Sminshall 
265730088Sminshall static
265830088Sminshall modecmd(argc, argv)
265930088Sminshall int	argc;
266030088Sminshall char	*argv[];
266130088Sminshall {
266230088Sminshall     struct cmd *mt;
266330088Sminshall 
266430088Sminshall     if ((argc != 2) || !strcmp(argv[1], "?") || !strcmp(argv[1], "help")) {
266530088Sminshall 	printf("format is:  'mode Mode', where 'Mode' is one of:\n\n");
266630088Sminshall 	for (mt = Modelist; mt->name; mt++) {
266730088Sminshall 	    printf("%s\t%s\n", mt->name, mt->help);
266830088Sminshall 	}
266930088Sminshall 	return 0;
267030088Sminshall     }
267130088Sminshall     mt = getmodecmd(argv[1]);
267230088Sminshall     if (mt == 0) {
267330088Sminshall 	fprintf(stderr, "Unknown mode '%s' ('mode ?' for help).\n", argv[1]);
267430088Sminshall 	return 0;
267530088Sminshall     } else if (mt == Ambiguous(struct cmd *)) {
267630088Sminshall 	fprintf(stderr, "Ambiguous mode '%s' ('mode ?' for help).\n", argv[1]);
267730088Sminshall 	return 0;
267830088Sminshall     } else {
267930088Sminshall 	(*mt->handler)();
268030088Sminshall     }
268130088Sminshall     return 1;
268230088Sminshall }
268330088Sminshall 
268430088Sminshall /*
268530088Sminshall  * The following data structures and routines implement the
268630088Sminshall  * "display" command.
268730088Sminshall  */
268830088Sminshall 
268930088Sminshall static
269030088Sminshall display(argc, argv)
269130088Sminshall int	argc;
269230088Sminshall char	*argv[];
269330088Sminshall {
269430088Sminshall #define	dotog(tl)	if (tl->variable && tl->actionexplanation) { \
269530088Sminshall 			    if (*tl->variable) { \
269630088Sminshall 				printf("will"); \
269730088Sminshall 			    } else { \
269830088Sminshall 				printf("won't"); \
269930088Sminshall 			    } \
270030088Sminshall 			    printf(" %s.\n", tl->actionexplanation); \
270130088Sminshall 			}
270230088Sminshall 
270330088Sminshall #define	doset(sl)   if (sl->name && *sl->name != ' ') { \
270430088Sminshall 			printf("[%s]\t%s.\n", control(*sl->charp), sl->name); \
270530088Sminshall 		    }
270630088Sminshall 
270730088Sminshall     struct togglelist *tl;
270830088Sminshall     struct setlist *sl;
270930088Sminshall 
271030088Sminshall     if (argc == 1) {
271130088Sminshall 	for (tl = Togglelist; tl->name; tl++) {
271230088Sminshall 	    dotog(tl);
271330088Sminshall 	}
271430088Sminshall 	printf("\n");
271530088Sminshall 	for (sl = Setlist; sl->name; sl++) {
271630088Sminshall 	    doset(sl);
271730088Sminshall 	}
271830088Sminshall     } else {
271930088Sminshall 	int i;
272030088Sminshall 
272130088Sminshall 	for (i = 1; i < argc; i++) {
272230088Sminshall 	    sl = getset(argv[i]);
272330088Sminshall 	    tl = gettoggle(argv[i]);
272430088Sminshall 	    if ((sl == Ambiguous(struct setlist *)) ||
272530088Sminshall 				(tl == Ambiguous(struct togglelist *))) {
272630088Sminshall 		printf("?Ambiguous argument '%s'.\n", argv[i]);
272730088Sminshall 		return 0;
272830088Sminshall 	    } else if (!sl && !tl) {
272930088Sminshall 		printf("?Unknown argument '%s'.\n", argv[i]);
273030088Sminshall 		return 0;
273130088Sminshall 	    } else {
273230088Sminshall 		if (tl) {
273330088Sminshall 		    dotog(tl);
273430088Sminshall 		}
273530088Sminshall 		if (sl) {
273630088Sminshall 		    doset(sl);
273730088Sminshall 		}
273830088Sminshall 	    }
273930088Sminshall 	}
274030088Sminshall     }
274130088Sminshall     return 1;
274230088Sminshall #undef	doset
274330088Sminshall #undef	dotog
274430088Sminshall }
274530088Sminshall 
274630088Sminshall /*
274730088Sminshall  * The following are the data structures, and many of the routines,
274830088Sminshall  * relating to command processing.
274930088Sminshall  */
275030088Sminshall 
275130088Sminshall /*
275230088Sminshall  * Set the escape character.
275330088Sminshall  */
275430088Sminshall static
275530088Sminshall setescape(argc, argv)
275630088Sminshall 	int argc;
275730088Sminshall 	char *argv[];
275830088Sminshall {
275930088Sminshall 	register char *arg;
276030088Sminshall 	char buf[50];
276130088Sminshall 
276230088Sminshall 	printf(
276330088Sminshall 	    "Deprecated usage - please use 'set escape%s%s' in the future.\n",
276430088Sminshall 				(argc > 2)? " ":"", (argc > 2)? argv[1]: "");
276530088Sminshall 	if (argc > 2)
276630088Sminshall 		arg = argv[1];
276730088Sminshall 	else {
276830088Sminshall 		printf("new escape character: ");
276930088Sminshall 		gets(buf);
277030088Sminshall 		arg = buf;
277130088Sminshall 	}
277230088Sminshall 	if (arg[0] != '\0')
277330088Sminshall 		escape = arg[0];
277430088Sminshall 	if (!In3270) {
277530088Sminshall 		printf("Escape character is '%s'.\n", control(escape));
277630088Sminshall 	}
277730088Sminshall 	fflush(stdout);
277830088Sminshall 	return 1;
277930088Sminshall }
278030088Sminshall 
278130088Sminshall /*VARARGS*/
278230088Sminshall static
278330088Sminshall togcrmod()
278430088Sminshall {
278530088Sminshall     crmod = !crmod;
278630088Sminshall     printf("Deprecated usage - please use 'toggle crmod' in the future.\n");
278730088Sminshall     printf("%s map carriage return on output.\n", crmod ? "Will" : "Won't");
278830088Sminshall     fflush(stdout);
278930088Sminshall     return 1;
279030088Sminshall }
279130088Sminshall 
279230088Sminshall /*VARARGS*/
279330088Sminshall suspend()
279430088Sminshall {
279530088Sminshall 	setcommandmode();
279630088Sminshall #if	defined(unix)
279730088Sminshall 	kill(0, SIGTSTP);
279830088Sminshall #endif	/* defined(unix) */
279930088Sminshall 	/* reget parameters in case they were changed */
280030088Sminshall 	ioctl(0, TIOCGETP, (char *)&ottyb);
280130088Sminshall 	ioctl(0, TIOCGETC, (char *)&otc);
280230088Sminshall 	ioctl(0, TIOCGLTC, (char *)&oltc);
280330088Sminshall 	return 1;
280430088Sminshall }
280530088Sminshall 
280630088Sminshall /*VARARGS*/
280730088Sminshall static
2808*30326Sminshall bye(argc, argv)
2809*30326Sminshall int	argc;		/* Number of arguments */
2810*30326Sminshall char	*argv[];	/* arguments */
281130088Sminshall {
281230088Sminshall     if (connected) {
281330088Sminshall 	shutdown(net, 2);
281430088Sminshall 	printf("Connection closed.\n");
281530088Sminshall 	close(net);
281630088Sminshall 	connected = 0;
281730088Sminshall 	/* reset options */
2818*30326Sminshall 	tninit();
281930088Sminshall #if	defined(TN3270)
2820*30326Sminshall 	SetIn3270();		/* Get out of 3270 mode */
282130088Sminshall #endif	/* defined(TN3270) */
282230088Sminshall     }
2823*30326Sminshall     if ((argc != 2) || (strcmp(argv[1], "fromquit") != 0)) {
2824*30326Sminshall 	longjmp(toplevel, 1);
2825*30326Sminshall 	/* NOTREACHED */
2826*30326Sminshall     }
2827*30326Sminshall     return 1;			/* Keep lint, etc., happy */
282830088Sminshall }
282930088Sminshall 
283030088Sminshall /*VARARGS*/
283130088Sminshall quit()
283230088Sminshall {
2833*30326Sminshall 	(void) call(bye, "bye", "fromquit", 0);
283430088Sminshall 	Exit(0);
283530088Sminshall 	/*NOTREACHED*/
283630088Sminshall 	return 1;			/* just to keep lint happy */
283730088Sminshall }
283830088Sminshall 
283930088Sminshall /*
284030088Sminshall  * Print status about the connection.
284130088Sminshall  */
284230088Sminshall static
284330088Sminshall status(argc, argv)
284430088Sminshall int	argc;
284530088Sminshall char	*argv[];
284630088Sminshall {
284730088Sminshall     if (connected) {
284830088Sminshall 	printf("Connected to %s.\n", hostname);
284930088Sminshall 	if (argc < 2) {
285030088Sminshall 	    printf("Operating in %s.\n",
285130088Sminshall 				modelist[getconnmode()].modedescriptions);
285230088Sminshall 	    if (localchars) {
285330088Sminshall 		printf("Catching signals locally.\n");
285430088Sminshall 	    }
285530088Sminshall 	}
285630088Sminshall     } else {
285730088Sminshall 	printf("No connection.\n");
285830088Sminshall     }
285930088Sminshall #   if !defined(TN3270)
286030088Sminshall     printf("Escape character is '%s'.\n", control(escape));
286130088Sminshall     fflush(stdout);
286230088Sminshall #   else /* !defined(TN3270) */
286330088Sminshall     if ((!In3270) && ((argc < 2) || strcmp(argv[1], "notmuch"))) {
286430088Sminshall 	printf("Escape character is '%s'.\n", control(escape));
286530088Sminshall     }
286630088Sminshall #   if defined(unix)
286730088Sminshall     if (In3270 && transcom) {
286830088Sminshall        printf("Transparent mode command is '%s'.\n", transcom);
286930088Sminshall     }
287030088Sminshall #   endif /* defined(unix) */
287130088Sminshall     fflush(stdout);
287230088Sminshall     if (In3270) {
287330088Sminshall 	return 0;
287430088Sminshall     }
287530088Sminshall #   endif /* defined(TN3270) */
287630088Sminshall     return 1;
287730088Sminshall }
287830088Sminshall 
287930088Sminshall #if	defined(TN3270) && defined(unix)
288030088Sminshall static
288130088Sminshall settranscom(argc, argv)
288230088Sminshall 	int argc;
288330088Sminshall 	char *argv[];
288430088Sminshall {
288530088Sminshall 	int i, len = 0;
288630088Sminshall 	char *strcpy(), *strcat();
288730088Sminshall 
288830088Sminshall 	if (argc == 1 && transcom) {
288930088Sminshall 	   transcom = 0;
289030088Sminshall 	}
289130088Sminshall 	if (argc == 1) {
289230088Sminshall 	   return;
289330088Sminshall 	}
289430088Sminshall 	for (i = 1; i < argc; ++i) {
289530088Sminshall 	    len += 1 + strlen(argv[1]);
289630088Sminshall 	}
289730088Sminshall 	transcom = tline;
289830088Sminshall 	(void) strcpy(transcom, argv[1]);
289930088Sminshall 	for (i = 2; i < argc; ++i) {
290030088Sminshall 	    (void) strcat(transcom, " ");
290130088Sminshall 	    (void) strcat(transcom, argv[i]);
290230088Sminshall 	}
290330088Sminshall }
290430088Sminshall #endif	/* defined(TN3270) && defined(unix) */
290530088Sminshall 
290630088Sminshall 
290730088Sminshall static
290830088Sminshall tn(argc, argv)
290930088Sminshall 	int argc;
291030088Sminshall 	char *argv[];
291130088Sminshall {
291230088Sminshall     register struct hostent *host = 0;
291330088Sminshall #if defined(msdos)
291430088Sminshall     char *cp;
291530320Sminshall #endif	/* defined(msdos) */
291630088Sminshall 
291730088Sminshall     if (connected) {
291830088Sminshall 	printf("?Already connected to %s\n", hostname);
291930088Sminshall 	return 0;
292030088Sminshall     }
292130088Sminshall     if (argc < 2) {
292230088Sminshall 	(void) strcpy(line, "Connect ");
292330088Sminshall 	printf("(to) ");
292430088Sminshall 	gets(&line[strlen(line)]);
292530088Sminshall 	makeargv();
292630088Sminshall 	argc = margc;
292730088Sminshall 	argv = margv;
292830088Sminshall     }
292930088Sminshall     if (argc > 3) {
293030088Sminshall 	printf("usage: %s host-name [port]\n", argv[0]);
293130088Sminshall 	return 0;
293230088Sminshall     }
293330088Sminshall #if	defined(msdos)
293430088Sminshall     for (cp = argv[1]; *cp; cp++) {
293530088Sminshall 	if (isupper(*cp)) {
293630088Sminshall 	    *cp = tolower(*cp);
293730088Sminshall 	}
293830088Sminshall     }
293930088Sminshall #endif	/* defined(msdos) */
294030088Sminshall     sin.sin_addr.s_addr = inet_addr(argv[1]);
294130088Sminshall     if (sin.sin_addr.s_addr != -1) {
294230088Sminshall 	sin.sin_family = AF_INET;
294330088Sminshall 	(void) strcpy(hnamebuf, argv[1]);
294430088Sminshall 	hostname = hnamebuf;
294530088Sminshall     } else {
294630088Sminshall 	host = gethostbyname(argv[1]);
294730088Sminshall 	if (host) {
294830088Sminshall 	    sin.sin_family = host->h_addrtype;
294930088Sminshall #if	defined(h_addr)		/* In 4.3, this is a #define */
295030088Sminshall 	    bcopy(host->h_addr_list[0], (caddr_t)&sin.sin_addr, host->h_length);
295130088Sminshall #else	/* defined(h_addr) */
295230088Sminshall 	    bcopy(host->h_addr, (caddr_t)&sin.sin_addr, host->h_length);
295330088Sminshall #endif	/* defined(h_addr) */
295430088Sminshall 	    hostname = host->h_name;
295530088Sminshall 	} else {
295630088Sminshall 	    printf("%s: unknown host\n", argv[1]);
295730088Sminshall 	    return 0;
295830088Sminshall 	}
295930088Sminshall     }
296030088Sminshall     sin.sin_port = sp->s_port;
296130088Sminshall     if (argc == 3) {
296230088Sminshall 	sin.sin_port = atoi(argv[2]);
296330088Sminshall 	if (sin.sin_port == 0) {
296430088Sminshall 	    sp = getservbyname(argv[2], "tcp");
296530088Sminshall 	    if (sp)
296630088Sminshall 		sin.sin_port = sp->s_port;
296730088Sminshall 	    else {
296830088Sminshall 		printf("%s: bad port number\n", argv[2]);
296930088Sminshall 		return 0;
297030088Sminshall 	    }
297130088Sminshall 	} else {
297230088Sminshall 	    sin.sin_port = atoi(argv[2]);
297330088Sminshall 	    sin.sin_port = htons(sin.sin_port);
297430088Sminshall 	}
297530088Sminshall 	telnetport = 0;
297630088Sminshall     } else {
297730088Sminshall 	telnetport = 1;
297830088Sminshall     }
297930088Sminshall #if	defined(unix)
298030088Sminshall     signal(SIGINT, intr);
298130088Sminshall     signal(SIGQUIT, intr2);
298230088Sminshall     signal(SIGPIPE, deadpeer);
298330088Sminshall #endif	/* defined(unix) */
298430088Sminshall     printf("Trying...\n");
298530088Sminshall     do {
298630088Sminshall 	net = socket(AF_INET, SOCK_STREAM, 0);
298730088Sminshall 	if (net < 0) {
298830088Sminshall 	    perror("telnet: socket");
298930088Sminshall 	    return 0;
299030088Sminshall 	}
299130088Sminshall #ifndef	NOT43
299230088Sminshall 	if (debug && setsockopt(net, SOL_SOCKET, SO_DEBUG,
299330088Sminshall 				(char *)&debug, sizeof(debug)) < 0)
299430320Sminshall #else	/* NOT43 */
299530088Sminshall 	if (debug && setsockopt(net, SOL_SOCKET, SO_DEBUG, 0, 0) < 0)
299630320Sminshall #endif	/* NOT43 */
299730088Sminshall 		perror("setsockopt (SO_DEBUG)");
299830088Sminshall 
299930088Sminshall 	if (connect(net, (struct sockaddr *)&sin, sizeof (sin)) < 0) {
300030088Sminshall #if	defined(h_addr)		/* In 4.3, this is a #define */
300130088Sminshall 	    if (host && host->h_addr_list[1]) {
300230088Sminshall 		int oerrno = errno;
300330088Sminshall 
300430088Sminshall 		fprintf(stderr, "telnet: connect to address %s: ",
300530088Sminshall 						inet_ntoa(sin.sin_addr));
300630088Sminshall 		errno = oerrno;
300730088Sminshall 		perror((char *)0);
300830088Sminshall 		host->h_addr_list++;
300930088Sminshall 		bcopy(host->h_addr_list[0],
301030088Sminshall 		    (caddr_t)&sin.sin_addr, host->h_length);
301130088Sminshall 		fprintf(stderr, "Trying %s...\n",
301230088Sminshall 			inet_ntoa(sin.sin_addr));
301330088Sminshall 		(void) close(net);
301430088Sminshall 		continue;
301530088Sminshall 	    }
301630088Sminshall #endif	/* defined(h_addr) */
301730088Sminshall 	    perror("telnet: Unable to connect to remote host");
301830088Sminshall #if defined(unix)
301930088Sminshall 	    signal(SIGINT, SIG_DFL);
302030088Sminshall 	    signal(SIGQUIT, SIG_DFL);
302130320Sminshall #endif	/* defined(unix) */
302230088Sminshall 	    return 0;
302330088Sminshall 	    }
302430088Sminshall 	connected++;
302530088Sminshall     } while (connected == 0);
302630088Sminshall     call(status, "status", "notmuch", 0);
302730088Sminshall     if (setjmp(peerdied) == 0)
302830088Sminshall 	telnet();
302930088Sminshall     ExitString(stderr, "Connection closed by foreign host.\n",1);
303030088Sminshall     /*NOTREACHED*/
303130088Sminshall }
303230088Sminshall 
303330088Sminshall 
303430088Sminshall #define HELPINDENT (sizeof ("connect"))
303530088Sminshall 
303630088Sminshall static char
303730088Sminshall 	openhelp[] =	"connect to a site",
303830088Sminshall 	closehelp[] =	"close current connection",
303930088Sminshall 	quithelp[] =	"exit telnet",
304030088Sminshall 	zhelp[] =	"suspend telnet",
304130088Sminshall 	statushelp[] =	"print status information",
304230088Sminshall 	helphelp[] =	"print help information",
304330088Sminshall 	sendhelp[] =	"transmit special characters ('send ?' for more)",
304430088Sminshall 	sethelp[] = 	"set operating parameters ('set ?' for more)",
304530088Sminshall 	togglestring[] ="toggle operating parameters ('toggle ?' for more)",
304630088Sminshall 	displayhelp[] =	"display operating parameters",
304730088Sminshall #if	defined(TN3270) && defined(unix)
304830088Sminshall 	transcomhelp[] = "specify Unix command for transparent mode pipe",
304930088Sminshall #endif	/* defined(TN3270) && defined(unix) */
305030088Sminshall 	modehelp[] = "try to enter line-by-line or character-at-a-time mode";
305130088Sminshall 
305230088Sminshall extern int	help();
305330088Sminshall 
305430088Sminshall static struct cmd cmdtab[] = {
305530088Sminshall 	{ "close",	closehelp,	bye,		1, 1 },
305630088Sminshall 	{ "display",	displayhelp,	display,	1, 0 },
305730088Sminshall 	{ "mode",	modehelp,	modecmd,	1, 1 },
305830088Sminshall 	{ "open",	openhelp,	tn,		1, 0 },
305930088Sminshall 	{ "quit",	quithelp,	quit,		1, 0 },
306030088Sminshall 	{ "send",	sendhelp,	sendcmd,	1, 1 },
306130088Sminshall 	{ "set",	sethelp,	setcmd,		1, 0 },
306230088Sminshall 	{ "status",	statushelp,	status,		1, 0 },
306330088Sminshall 	{ "toggle",	togglestring,	toggle,		1, 0 },
306430088Sminshall #if	defined(TN3270) && defined(unix)
306530088Sminshall 	{ "transcom",	transcomhelp,	settranscom,	1, 0 },
306630088Sminshall #endif	/* defined(TN3270) && defined(unix) */
306730088Sminshall 	{ "z",		zhelp,		suspend,	1, 0 },
306830088Sminshall 	{ "?",		helphelp,	help,		1, 0 },
306930088Sminshall 	0
307030088Sminshall };
307130088Sminshall 
307230088Sminshall static char	crmodhelp[] =	"deprecated command -- use 'toggle crmod' instead";
307330088Sminshall static char	escapehelp[] =	"deprecated command -- use 'set escape' instead";
307430088Sminshall 
307530088Sminshall static struct cmd cmdtab2[] = {
307630088Sminshall 	{ "help",	helphelp,	help,		0, 0 },
307730088Sminshall 	{ "escape",	escapehelp,	setescape,	1, 0 },
307830088Sminshall 	{ "crmod",	crmodhelp,	togcrmod,	1, 0 },
307930088Sminshall 	0
308030088Sminshall };
308130088Sminshall 
308230088Sminshall /*
308330088Sminshall  * Call routine with argc, argv set from args (terminated by 0).
308430088Sminshall  * VARARGS2
308530088Sminshall  */
308630088Sminshall static
308730088Sminshall call(routine, args)
308830088Sminshall 	int (*routine)();
308930088Sminshall 	char *args;
309030088Sminshall {
309130088Sminshall 	register char **argp;
309230088Sminshall 	register int argc;
309330088Sminshall 
309430088Sminshall 	for (argc = 0, argp = &args; *argp++ != 0; argc++)
309530088Sminshall 		;
309630088Sminshall 	return (*routine)(argc, &args);
309730088Sminshall }
309830088Sminshall 
309930088Sminshall static char **
310030088Sminshall getnextcmd(name)
310130088Sminshall char *name;
310230088Sminshall {
310330088Sminshall     struct cmd *c = (struct cmd *) name;
310430088Sminshall 
310530088Sminshall     return (char **) (c+1);
310630088Sminshall }
310730088Sminshall 
310830088Sminshall static struct cmd *
310930088Sminshall getcmd(name)
311030088Sminshall char *name;
311130088Sminshall {
311230088Sminshall     struct cmd *cm;
311330088Sminshall 
311430088Sminshall     if ((cm = (struct cmd *) genget(name, (char **) cmdtab, getnextcmd)) != 0) {
311530088Sminshall 	return cm;
311630088Sminshall     } else {
311730088Sminshall 	return (struct cmd *) genget(name, (char **) cmdtab2, getnextcmd);
311830088Sminshall     }
311930088Sminshall }
312030088Sminshall 
312130088Sminshall void
312230088Sminshall command(top)
312330088Sminshall 	int top;
312430088Sminshall {
312530088Sminshall 	register struct cmd *c;
312630088Sminshall 
312730088Sminshall 	setcommandmode();
312830088Sminshall 	if (!top) {
312930088Sminshall 		putchar('\n');
313030088Sminshall 	} else {
313130088Sminshall #if	defined(unix)
313230088Sminshall 		signal(SIGINT, SIG_DFL);
313330088Sminshall 		signal(SIGQUIT, SIG_DFL);
313430088Sminshall #endif	/* defined(unix) */
313530088Sminshall 	}
313630088Sminshall 	for (;;) {
313730088Sminshall 		printf("%s> ", prompt);
313830088Sminshall 		if (gets(line) == NULL) {
313930088Sminshall 			if (feof(stdin) || ferror(stdin))
314030088Sminshall 				quit();
314130088Sminshall 			break;
314230088Sminshall 		}
314330088Sminshall 		if (line[0] == 0)
314430088Sminshall 			break;
314530088Sminshall 		makeargv();
314630088Sminshall 		c = getcmd(margv[0]);
314730088Sminshall 		if (c == Ambiguous(struct cmd *)) {
314830088Sminshall 			printf("?Ambiguous command\n");
314930088Sminshall 			continue;
315030088Sminshall 		}
315130088Sminshall 		if (c == 0) {
315230088Sminshall 			printf("?Invalid command\n");
315330088Sminshall 			continue;
315430088Sminshall 		}
315530088Sminshall 		if (c->needconnect && !connected) {
315630088Sminshall 			printf("?Need to be connected first.\n");
315730088Sminshall 			continue;
315830088Sminshall 		}
315930088Sminshall 		if ((*c->handler)(margc, margv)) {
316030088Sminshall 			break;
316130088Sminshall 		}
316230088Sminshall 	}
316330088Sminshall 	if (!top) {
316430088Sminshall 		if (!connected) {
316530088Sminshall 			longjmp(toplevel, 1);
316630088Sminshall 			/*NOTREACHED*/
316730088Sminshall 		}
316830088Sminshall 		setconnmode();
316930088Sminshall 	}
317030088Sminshall }
317130088Sminshall 
317230088Sminshall /*
317330088Sminshall  * Help command.
317430088Sminshall  */
317530088Sminshall static
317630088Sminshall help(argc, argv)
317730088Sminshall 	int argc;
317830088Sminshall 	char *argv[];
317930088Sminshall {
318030088Sminshall 	register struct cmd *c;
318130088Sminshall 
318230088Sminshall 	if (argc == 1) {
318330088Sminshall 		printf("Commands may be abbreviated.  Commands are:\n\n");
318430088Sminshall 		for (c = cmdtab; c->name; c++)
318530088Sminshall 			if (c->dohelp) {
318630088Sminshall 				printf("%-*s\t%s\n", HELPINDENT, c->name,
318730088Sminshall 								    c->help);
318830088Sminshall 			}
318930088Sminshall 		return 0;
319030088Sminshall 	}
319130088Sminshall 	while (--argc > 0) {
319230088Sminshall 		register char *arg;
319330088Sminshall 		arg = *++argv;
319430088Sminshall 		c = getcmd(arg);
319530088Sminshall 		if (c == Ambiguous(struct cmd *))
319630088Sminshall 			printf("?Ambiguous help command %s\n", arg);
319730088Sminshall 		else if (c == (struct cmd *)0)
319830088Sminshall 			printf("?Invalid help command %s\n", arg);
319930088Sminshall 		else
320030088Sminshall 			printf("%s\n", c->help);
320130088Sminshall 	}
320230088Sminshall 	return 0;
320330088Sminshall }
320430088Sminshall 
320530088Sminshall /*
320630088Sminshall  * main.  Parse arguments, invoke the protocol or command parser.
320730088Sminshall  */
320830088Sminshall 
320930088Sminshall 
321030088Sminshall void
321130088Sminshall main(argc, argv)
321230088Sminshall 	int argc;
321330088Sminshall 	char *argv[];
321430088Sminshall {
3215*30326Sminshall     tninit();		/* Clear out things */
3216*30326Sminshall 
321730088Sminshall     NetTrace = stdout;
321830088Sminshall     ioctl(0, TIOCGETP, (char *)&ottyb);
321930088Sminshall     ioctl(0, TIOCGETC, (char *)&otc);
322030088Sminshall     ioctl(0, TIOCGLTC, (char *)&oltc);
322130088Sminshall #if	defined(LNOFLSH)
322230088Sminshall     ioctl(0, TIOCLGET, (char *)&autoflush);
322330088Sminshall     autoflush = !(autoflush&LNOFLSH);	/* if LNOFLSH, no autoflush */
322430088Sminshall #else	/* LNOFLSH */
322530088Sminshall     autoflush = 1;
322630088Sminshall #endif	/* LNOFLSH */
322730088Sminshall     ntc = otc;
322830088Sminshall     nltc = oltc;
322930088Sminshall     nttyb = ottyb;
323030088Sminshall     setbuf(stdin, (char *)0);
323130088Sminshall     setbuf(stdout, (char *)0);
323230088Sminshall     prompt = argv[0];
323330088Sminshall     if (argc > 1 && !strcmp(argv[1], "-d")) {
323430088Sminshall 	debug = 1;
323530088Sminshall 	argv++;
323630088Sminshall 	argc--;
323730088Sminshall     }
323830088Sminshall     if (argc > 1 && !strcmp(argv[1], "-n")) {
323930088Sminshall 	argv++;
324030088Sminshall 	argc--;
324130088Sminshall 	if (argc > 1) {		/* get file name */
324230088Sminshall 	    NetTrace = fopen(argv[1], "w");
324330088Sminshall 	    argv++;
324430088Sminshall 	    argc--;
324530088Sminshall 	    if (NetTrace == NULL) {
324630088Sminshall 		NetTrace = stdout;
324730088Sminshall 	    }
324830088Sminshall 	}
324930088Sminshall     }
325030088Sminshall #if	defined(TN3270) && defined(unix)
325130088Sminshall     if (argc > 1 && !strcmp(argv[1], "-t")) {
325230088Sminshall 	argv++;
325330088Sminshall 	argc--;
325430088Sminshall 	if (argc > 1) {		/* get command name */
325530088Sminshall 	    transcom = tline;
325630088Sminshall 	    (void) strcpy(transcom, argv[1]);
325730088Sminshall 	    argv++;
325830088Sminshall 	    argc--;
325930088Sminshall 	}
326030088Sminshall     }
326130088Sminshall #endif	/* defined(TN3270) && defined(unix) */
326230088Sminshall     if (argc != 1) {
326330088Sminshall 	if (setjmp(toplevel) != 0)
326430088Sminshall 	    Exit(0);
326530088Sminshall 	tn(argc, argv);
326630088Sminshall     }
326730088Sminshall     setjmp(toplevel);
326830088Sminshall     for (;;)
326930088Sminshall 	command(1);
327030088Sminshall }
3271