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