xref: /csrg-svn/usr.bin/tn3270/telnet.c (revision 31131)
130088Sminshall /*
230088Sminshall  *	Copyright (c) 1984, 1985, 1986 by the Regents of the
330088Sminshall  *	University of California and by Gregory Glenn Minshall.
430088Sminshall  *
530088Sminshall  *	Permission to use, copy, modify, and distribute these
630088Sminshall  *	programs and their documentation for any purpose and
730088Sminshall  *	without fee is hereby granted, provided that this
830088Sminshall  *	copyright and permission appear on all copies and
930088Sminshall  *	supporting documentation, the name of the Regents of
1030088Sminshall  *	the University of California not be used in advertising
1130088Sminshall  *	or publicity pertaining to distribution of the programs
1230088Sminshall  *	without specific prior permission, and notice be given in
1330088Sminshall  *	supporting documentation that copying and distribution is
1430088Sminshall  *	by permission of the Regents of the University of California
1530088Sminshall  *	and by Gregory Glenn Minshall.  Neither the Regents of the
1630088Sminshall  *	University of California nor Gregory Glenn Minshall make
1730088Sminshall  *	representations about the suitability of this software
1830088Sminshall  *	for any purpose.  It is provided "as is" without
1930088Sminshall  *	express or implied warranty.
2030088Sminshall  */
2130088Sminshall 
2230088Sminshall #ifndef lint
2330088Sminshall static char copyright[] =
2430088Sminshall "@(#) Copyright (c) 1984, 1985, 1986 Regents of the University of California.\n\
2530088Sminshall  All rights reserved.\n";
2630320Sminshall #endif	/* not lint */
2730088Sminshall 
2830088Sminshall #ifndef lint
2930088Sminshall static char sccsid[] = "@(#)telnet.c	3.1  10/29/86";
3030320Sminshall #endif	/* not lint */
3130088Sminshall 
3230088Sminshall /*
3330088Sminshall  * User telnet program, modified for use by tn3270.c.
3430088Sminshall  *
3530088Sminshall  * Many of the FUNCTIONAL changes in this newest version of TELNET
3630088Sminshall  * were suggested by Dave Borman of Cray Research, Inc.
3730088Sminshall  *
3830088Sminshall  * Other changes in the tn3270 side come from Alan Crosswell (Columbia),
3930088Sminshall  * Bob Braden (ISI), Steve Jacobson (Berkeley), and Cliff Frost (Berkeley).
4030088Sminshall  *
4130088Sminshall  * This code is common between telnet(1c) and tn3270(1c).  There are the
4230088Sminshall  * following defines used to generate the various versions:
4330088Sminshall  *
4430088Sminshall  *	TN3270		- 	This is to be linked with tn3270.
4530088Sminshall  *
4630088Sminshall  *	DEBUG		-	Allow for some extra debugging operations.
4730088Sminshall  *
4830088Sminshall  *	NOT43		-	Allows the program to compile and run on
4930088Sminshall  *				a 4.2BSD system.
5030088Sminshall  *
5130088Sminshall  *	PUTCHAR		-	Within tn3270, on a NOT43 system,
5230088Sminshall  *				allows the use of the 4.3 curses
5330088Sminshall  *				(greater speed updating the screen).
5430088Sminshall  *				You need the 4.3 curses for this to work.
5530088Sminshall  *
5630088Sminshall  *	FD_SETSIZE	-	On whichever system, if this isn't defined,
5730088Sminshall  *				we patch over the FD_SET, etc., macros with
5830088Sminshall  *				some homebrewed ones.
5930088Sminshall  *
6030088Sminshall  *	SO_OOBINLINE	-	This is a socket option which we would like
6130088Sminshall  *				to set to allow TCP urgent data to come
6230088Sminshall  *				to us "inline".  This is NECESSARY for
6330088Sminshall  *				CORRECT operation, and desireable for
6430088Sminshall  *				simpler operation.
6530088Sminshall  *
6630088Sminshall  *	LNOFLSH		-	Detects the presence of the LNOFLSH bit
6730088Sminshall  *				in the tty structure.
6830088Sminshall  *
6930088Sminshall  *	unix		-	Compiles in unix specific stuff.
7030088Sminshall  *
71*31131Sminshall  *	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 
8630088Sminshall #include <netinet/in.h>
8730088Sminshall 
8831124Sminshall #if	defined(unix)
8931124Sminshall /* By the way, we need to include curses.h before telnet.h since,
9031124Sminshall  * among other things, telnet.h #defines 'DO', which is a variable
9131124Sminshall  * declared in curses.h.
9231124Sminshall  */
9330088Sminshall #include <curses.h>
9431124Sminshall #endif	/* defined(unix) */
9530088Sminshall 
9630088Sminshall #define	TELOPTS
9730088Sminshall #include <arpa/telnet.h>
9830088Sminshall 
9930088Sminshall #if	!defined(NOT43)
10030088Sminshall #include <arpa/inet.h>
10130088Sminshall #else	/* !defined(NOT43) */
10230088Sminshall extern unsigned long inet_addr();
10330088Sminshall extern char	*inet_ntoa();
10430088Sminshall #endif	/* !defined(NOT43) */
10530088Sminshall 
10630088Sminshall #include <stdio.h>
10730088Sminshall #include <ctype.h>
10830088Sminshall #include <errno.h>
10930088Sminshall #include <setjmp.h>
11030088Sminshall #include <netdb.h>
11131124Sminshall 
11231124Sminshall #if	defined(unix)
11330088Sminshall #include <strings.h>
11431124Sminshall #else	/* defined(unix) */
11531124Sminshall #include <string.h>
11631124Sminshall #endif	/* defined(unix) */
11730088Sminshall 
11830088Sminshall #if	defined(TN3270)
11930088Sminshall #include "ctlr/screen.h"
12030088Sminshall #include "system/globals.h"
12130088Sminshall #include "telnet.ext"
12230088Sminshall #include "ctlr/options.ext"
12330088Sminshall #include "ctlr/outbound.ext"
12430088Sminshall #include "keyboard/termin.ext"
125*31131Sminshall #endif	/* defined(TN3270) */
12630722Sminshall #include "general.h"
12730088Sminshall 
12830088Sminshall 
12930088Sminshall 
13030088Sminshall #ifndef	FD_SETSIZE
13130088Sminshall /*
13230088Sminshall  * The following is defined just in case someone should want to run
13330088Sminshall  * this telnet on a 4.2 system.
13430088Sminshall  *
13530088Sminshall  */
13630088Sminshall 
13730088Sminshall #define	FD_SET(n, p)	((p)->fds_bits[0] |= (1<<(n)))
13830088Sminshall #define	FD_CLR(n, p)	((p)->fds_bits[0] &= ~(1<<(n)))
13930088Sminshall #define	FD_ISSET(n, p)	((p)->fds_bits[0] & (1<<(n)))
14030088Sminshall #define FD_ZERO(p)	((p)->fds_bits[0] = 0)
14130088Sminshall 
14230088Sminshall #endif
14330088Sminshall 
14430088Sminshall #define	strip(x)	((x)&0x7f)
14530088Sminshall #define min(x,y)	((x<y)? x:y)
14630088Sminshall 
14730088Sminshall #if	defined(TN3270)
14830326Sminshall static char	Ibuf[8*BUFSIZ], *Ifrontp, *Ibackp;
14930088Sminshall #endif	/* defined(TN3270) */
15030088Sminshall 
15130326Sminshall static char	ttyobuf[2*BUFSIZ], *tfrontp, *tbackp;
15230088Sminshall #define	TTYADD(c)	{ if (!(SYNCHing||flushout)) { *tfrontp++ = c; } }
15330088Sminshall #define	TTYLOC()	(tfrontp)
15430088Sminshall #define	TTYMAX()	(ttyobuf+sizeof ttyobuf-1)
15530088Sminshall #define	TTYMIN()	(netobuf)
15630088Sminshall #define	TTYBYTES()	(tfrontp-tbackp)
15730088Sminshall #define	TTYROOM()	(TTYMAX()-TTYLOC()+1)
15830088Sminshall 
15930326Sminshall static char	netobuf[2*BUFSIZ], *nfrontp, *nbackp;
16030088Sminshall #define	NETADD(c)	{ *nfrontp++ = c; }
16130088Sminshall #define	NET2ADD(c1,c2)	{ NETADD(c1); NETADD(c2); }
16230088Sminshall #define NETLOC()	(nfrontp)
16330088Sminshall #define	NETMAX()	(netobuf+sizeof netobuf-1)
16430088Sminshall #define	NETBYTES()	(nfrontp-nbackp)
16530088Sminshall #define	NETROOM()	(NETMAX()-NETLOC()+1)
16630326Sminshall static char	*neturg;		/* one past last byte of urgent data */
16730088Sminshall 
16830326Sminshall static char	subbuffer[100],
16930326Sminshall 		*subpointer, *subend;	 /* buffer for sub-options */
17030088Sminshall #define	SB_CLEAR()	subpointer = subbuffer;
17130088Sminshall #define	SB_TERM()	subend = subpointer;
17230088Sminshall #define	SB_ACCUM(c)	if (subpointer < (subbuffer+sizeof subbuffer)) { \
17330088Sminshall 				*subpointer++ = (c); \
17430088Sminshall 			}
17530088Sminshall 
17630088Sminshall static char	sb_terminal[] = { IAC, SB,
17730088Sminshall 			TELOPT_TTYPE, TELQUAL_IS,
17830088Sminshall 			'I', 'B', 'M', '-', '3', '2', '7', '8', '-', '2',
17930088Sminshall 			IAC, SE };
18030088Sminshall #define	SBTERMMODEL	13
18130088Sminshall 
18230088Sminshall 
18330326Sminshall static char	hisopts[256];
18430326Sminshall static char	myopts[256];
18530088Sminshall 
18630088Sminshall static char	doopt[] = { IAC, DO, '%', 'c', 0 };
18730088Sminshall static char	dont[] = { IAC, DONT, '%', 'c', 0 };
18830088Sminshall static char	will[] = { IAC, WILL, '%', 'c', 0 };
18930088Sminshall static char	wont[] = { IAC, WONT, '%', 'c', 0 };
19030088Sminshall 
19130088Sminshall struct cmd {
19230088Sminshall 	char	*name;		/* command name */
19330088Sminshall 	char	*help;		/* help string */
19430088Sminshall 	int	(*handler)();	/* routine which executes command */
19530088Sminshall 	int	dohelp;		/* Should we give general help information? */
19630088Sminshall 	int	needconnect;	/* Do we need to be connected to execute? */
19730088Sminshall };
19830088Sminshall 
19930326Sminshall static char	sibuf[BUFSIZ], *sbp;
20030088Sminshall static char	tibuf[BUFSIZ], *tbp;
20130088Sminshall static fd_set ibits, obits, xbits;
20230088Sminshall 
20330088Sminshall 
20430088Sminshall static int
20530326Sminshall 	connected,
20630326Sminshall 	net,
20730326Sminshall 	scc,
20830326Sminshall 	tcc,
20930326Sminshall 	showoptions,
21030326Sminshall 	In3270,		/* Are we in 3270 mode? */
21130326Sminshall 	ISend,		/* trying to send network data in */
21230088Sminshall 	debug = 0,
21330326Sminshall 	crmod,
21430326Sminshall 	netdata,
21530722Sminshall 	askedSGA = 0,	/* We have talked about suppress go ahead */
21630088Sminshall 	telnetport = 1;
21730088Sminshall 
21830326Sminshall static FILE	*NetTrace = 0;		/* Not in bss, since needs to stay */
21930088Sminshall 
22030088Sminshall #define	CONTROL(x)	((x)&0x1f)		/* CTRL(x) is not portable */
22130088Sminshall 
22230088Sminshall static char
22330088Sminshall 	*prompt = 0,
22430326Sminshall 	escape,
22530326Sminshall 	echoc;
22630088Sminshall 
22730088Sminshall static int
22830326Sminshall 	SYNCHing,		/* we are in TELNET SYNCH mode */
22930326Sminshall 	flushout,		/* flush output */
23030088Sminshall 	autoflush = 0,		/* flush output when interrupting? */
23130326Sminshall 	autosynch,		/* send interrupt characters with SYNCH? */
23230326Sminshall 	localchars,		/* we recognize interrupt/quit */
23330326Sminshall 	donelclchars,	/* the user has set "localchars" */
23431124Sminshall 	dontlecho,		/* do we suppress local echoing right now? */
23531124Sminshall 	globalmode;
23630088Sminshall 
23730088Sminshall /*	The following are some tn3270 specific flags */
23830088Sminshall #if	defined(TN3270)
23930088Sminshall 
24030088Sminshall static int
24130326Sminshall 	Sent3270TerminalType;	/* Have we said we are a 3270? */
24230088Sminshall 
243*31131Sminshall /* Some real, live, globals. */
244*31131Sminshall int
245*31131Sminshall 	tout,			/* Output file descriptor */
246*31131Sminshall 	tin;			/* Input file descriptor */
247*31131Sminshall 
248*31131Sminshall #else	/* defined(TN3270) */
249*31131Sminshall static int tin, tout;		/* file descriptors */
250*31131Sminshall #endif	/* defined(TN3270) */
251*31131Sminshall 
252*31131Sminshall 
25330722Sminshall /*
25430722Sminshall  * Telnet receiver states for fsm
25530722Sminshall  */
25630722Sminshall #define	TS_DATA		0
25730722Sminshall #define	TS_IAC		1
25830722Sminshall #define	TS_WILL		2
25930722Sminshall #define	TS_WONT		3
26030722Sminshall #define	TS_DO		4
26130722Sminshall #define	TS_DONT		5
26230722Sminshall #define	TS_CR		6
26330722Sminshall #define	TS_SB		7		/* sub-option collection */
26430722Sminshall #define	TS_SE		8		/* looking for sub-option end */
26530722Sminshall 
26630722Sminshall static int	telrcv_state = TS_DATA;
26730088Sminshall 
26830088Sminshall static char	line[200];
26930326Sminshall static int	margc;
27030088Sminshall static char	*margv[20];
27130088Sminshall 
27231124Sminshall static jmp_buf	toplevel = { 0 };
27330088Sminshall static jmp_buf	peerdied;
27430088Sminshall 
27530088Sminshall extern	int errno;
27630088Sminshall 
27730088Sminshall 
27830088Sminshall static struct sockaddr_in sin;
27930088Sminshall 
28030088Sminshall static struct	servent *sp = 0;
28130088Sminshall 
28230326Sminshall static int	flushline;
28330088Sminshall 
28430326Sminshall static char	*hostname;
28530088Sminshall static char	hnamebuf[32];
28630088Sminshall 
28730088Sminshall /*
28830088Sminshall  * The following are some clocks used to decide how to interpret
28930088Sminshall  * the relationship between various variables.
29030088Sminshall  */
29130088Sminshall 
29230088Sminshall static struct {
29330088Sminshall     int
29430088Sminshall 	system,			/* what the current time is */
29530088Sminshall 	echotoggle,		/* last time user entered echo character */
29630088Sminshall 	modenegotiated,		/* last time operating mode negotiated */
29730088Sminshall 	didnetreceive,		/* last time we read data from network */
29830088Sminshall 	gotDM;			/* when did we last see a data mark */
29930326Sminshall } clocks;
30030088Sminshall 
30130088Sminshall #define	settimer(x)	clocks.x = clocks.system++
30230088Sminshall 
30331124Sminshall /*	Various modes */
30431124Sminshall #define	MODE_LINE(m)	(modelist[m].modetype & LINE)
30531124Sminshall #define	MODE_LOCAL_CHARS(m)	(modelist[m].modetype &  LOCAL_CHARS)
306*31131Sminshall #define	MODE_LOCAL_ECHO(m)	(modelist[m].modetype & LOCAL_ECHO)
307*31131Sminshall #define	MODE_COMMAND_LINE(m)	(modelist[m].modetype & COMMAND_LINE)
30831124Sminshall 
30931124Sminshall #define	LOCAL_CHARS	0x01		/* Characters processed locally */
31031124Sminshall #define	LINE		0x02		/* Line-by-line mode of operation */
311*31131Sminshall #define	LOCAL_ECHO	0x04		/* Echoing locally */
312*31131Sminshall #define	COMMAND_LINE	0x08		/* Command line mode */
31331124Sminshall 
31431124Sminshall static struct {
31531124Sminshall     char *modedescriptions;
31631124Sminshall     char modetype;
31731124Sminshall } modelist[] = {
318*31131Sminshall 	{ "telnet command mode", COMMAND_LINE },
31931124Sminshall 	{ "character-at-a-time mode", 0 },
320*31131Sminshall 	{ "character-at-a-time mode (local echo)", LOCAL_ECHO|LOCAL_CHARS },
32131124Sminshall 	{ "line-by-line mode (remote echo)", LINE | LOCAL_CHARS },
322*31131Sminshall 	{ "line-by-line mode", LINE | LOCAL_ECHO | LOCAL_CHARS },
32331124Sminshall 	{ "line-by-line mode (local echoing suppressed)", LINE | LOCAL_CHARS },
32431124Sminshall 	{ "3270 mode", 0 },
32531124Sminshall };
32631124Sminshall 
32731124Sminshall 
32830088Sminshall /*
32931124Sminshall  * The following routines try to encapsulate what is system dependent
33031124Sminshall  * (at least between 4.x and dos) which is used in telnet.c.
33131124Sminshall  */
33231124Sminshall 
33331124Sminshall #if	defined(unix)
33431124Sminshall #include <sys/ioctl.h>
33531124Sminshall #include <sys/time.h>
33631124Sminshall #include <signal.h>
33731124Sminshall 
33831124Sminshall int
33931124Sminshall 	HaveInput;		/* There is input available to scan */
34031124Sminshall 
34131124Sminshall #if	defined(TN3270)
34231124Sminshall static char	tline[200];
34331124Sminshall char	*transcom = 0;	/* transparent mode command (default: none) */
34431124Sminshall #endif	/* defined(TN3270) */
34531124Sminshall 
34631124Sminshall static struct	tchars otc = { 0 }, ntc = { 0 };
34731124Sminshall static struct	ltchars oltc = { 0 }, nltc = { 0 };
34831124Sminshall static struct	sgttyb ottyb = { 0 }, nttyb = { 0 };
34931124Sminshall 
35031124Sminshall 
351*31131Sminshall #define	TerminalWrite(fd,buf,n)	write(fd,buf,n)
352*31131Sminshall #define	TerminalRead(fd,buf,n)	read(fd,buf,n)
353*31131Sminshall 
35431124Sminshall /*
35531124Sminshall  *
35631124Sminshall  */
35731124Sminshall 
35831124Sminshall static int
359*31131Sminshall TerminalAutoFlush()					/* unix */
36031124Sminshall {
36131124Sminshall #if	defined(LNOFLSH)
36231124Sminshall     ioctl(0, TIOCLGET, (char *)&autoflush);
36331124Sminshall     return !(autoflush&LNOFLSH);	/* if LNOFLSH, no autoflush */
36431124Sminshall #else	/* LNOFLSH */
36531124Sminshall     return 1;
36631124Sminshall #endif	/* LNOFLSH */
36731124Sminshall }
36831124Sminshall 
36931124Sminshall /*
370*31131Sminshall  * TerminalSpecialChars()
37131124Sminshall  *
372*31131Sminshall  * Look at an input character to see if it is a special character
373*31131Sminshall  * and decide what to do.
37431124Sminshall  *
37531124Sminshall  * Output:
37631124Sminshall  *
37731124Sminshall  *	0	Don't add this character.
37831124Sminshall  *	1	Do add this character
37931124Sminshall  */
38031124Sminshall 
38131124Sminshall int
382*31131Sminshall TerminalSpecialChars(c)			/* unix */
38331124Sminshall int	c;
38431124Sminshall {
38531124Sminshall     void doflush(), intp(), sendbrk();
38631124Sminshall 
38731124Sminshall     if (c == ntc.t_intrc) {
38831124Sminshall 	intp();
38931124Sminshall 	return 0;
39031124Sminshall     } else if (c == ntc.t_quitc) {
39131124Sminshall 	sendbrk();
39231124Sminshall 	return 0;
39331124Sminshall     } else if (c == nltc.t_flushc) {
39431124Sminshall 	NET2ADD(IAC, AO);
39531124Sminshall 	if (autoflush) {
39631124Sminshall 	    doflush();
39731124Sminshall 	}
39831124Sminshall 	return 0;
39931124Sminshall     } else if (!MODE_LOCAL_CHARS(globalmode)) {
40031124Sminshall 	if (c == nttyb.sg_kill) {
40131124Sminshall 	    NET2ADD(IAC, EL);
40231124Sminshall 	    return 0;
40331124Sminshall 	} else if (c == nttyb.sg_erase) {
40431124Sminshall 	    NET2ADD(IAC, EC);
40531124Sminshall 	    return 0;
40631124Sminshall 	}
40731124Sminshall     }
40831124Sminshall     return 1;
40931124Sminshall }
41031124Sminshall 
41131124Sminshall 
41231124Sminshall /*
41331124Sminshall  * Flush output to the terminal
41431124Sminshall  */
41531124Sminshall 
41631124Sminshall static void
41731124Sminshall TerminalFlushOutput()				/* unix */
41831124Sminshall {
41931124Sminshall     (void) ioctl(fileno(stdout), TIOCFLUSH, (char *) 0);
42031124Sminshall }
42131124Sminshall 
42231124Sminshall static void
42331124Sminshall TerminalSaveState()				/* unix */
42431124Sminshall {
42531124Sminshall     ioctl(0, TIOCGETP, (char *)&ottyb);
42631124Sminshall     ioctl(0, TIOCGETC, (char *)&otc);
42731124Sminshall     ioctl(0, TIOCGLTC, (char *)&oltc);
42831124Sminshall 
42931124Sminshall     ntc = otc;
43031124Sminshall     nltc = oltc;
43131124Sminshall     nttyb = ottyb;
43231124Sminshall }
43331124Sminshall 
43431124Sminshall static void
43531124Sminshall TerminalRestoreState()				/* unix */
43631124Sminshall {
43731124Sminshall }
43831124Sminshall 
43931124Sminshall /*
44031124Sminshall  * TerminalNewMode - set up terminal to a specific mode.
44131124Sminshall  */
44231124Sminshall 
44331124Sminshall 
44431124Sminshall static void
445*31131Sminshall TerminalNewMode(f)					/* unix */
44631124Sminshall register int f;
44731124Sminshall {
44831124Sminshall     static int prevmode = 0;
44931124Sminshall     struct tchars *tc;
45031124Sminshall     struct tchars tc3;
45131124Sminshall     struct ltchars *ltc;
45231124Sminshall     struct sgttyb sb;
45331124Sminshall     int onoff;
45431124Sminshall     int old;
45531124Sminshall     struct	tchars notc2;
45631124Sminshall     struct	ltchars noltc2;
45731124Sminshall     static struct	tchars notc =	{ -1, -1, -1, -1, -1, -1 };
45831124Sminshall     static struct	ltchars noltc =	{ -1, -1, -1, -1, -1, -1 };
45931124Sminshall 
46031124Sminshall     globalmode = f;
46131124Sminshall     if (prevmode == f)
46231124Sminshall 	return;
46331124Sminshall     old = prevmode;
46431124Sminshall     prevmode = f;
46531124Sminshall     sb = nttyb;
46631124Sminshall 
46731124Sminshall     switch (f) {
46831124Sminshall 
46931124Sminshall     case 0:
47031124Sminshall 	onoff = 0;
47131124Sminshall 	tc = &otc;
47231124Sminshall 	ltc = &oltc;
47331124Sminshall 	break;
47431124Sminshall 
47531124Sminshall     case 1:		/* remote character processing, remote echo */
47631124Sminshall     case 2:		/* remote character processing, local echo */
47731124Sminshall     case 6:		/* 3270 mode - like 1, but with xon/xoff local */
47831124Sminshall 		    /* (might be nice to have "6" in telnet also...) */
47931124Sminshall 	    sb.sg_flags |= CBREAK;
48031124Sminshall 	    if ((f == 1) || (f == 6)) {
48131124Sminshall 		sb.sg_flags &= ~(ECHO|CRMOD);
48231124Sminshall 	    } else {
48331124Sminshall 		sb.sg_flags |= ECHO|CRMOD;
48431124Sminshall 	    }
48531124Sminshall 	    sb.sg_erase = sb.sg_kill = -1;
48631124Sminshall 	    if (f == 6) {
48731124Sminshall 		tc = &tc3;
48831124Sminshall 		tc3 = notc;
48931124Sminshall 		    /* get XON, XOFF characters */
49031124Sminshall 		tc3.t_startc = otc.t_startc;
49131124Sminshall 		tc3.t_stopc = otc.t_stopc;
49231124Sminshall 	    } else {
49331124Sminshall 		/*
49431124Sminshall 		 * If user hasn't specified one way or the other,
49531124Sminshall 		 * then default to not trapping signals.
49631124Sminshall 		 */
49731124Sminshall 		if (!donelclchars) {
49831124Sminshall 		    localchars = 0;
49931124Sminshall 		}
50031124Sminshall 		if (localchars) {
50131124Sminshall 		    notc2 = notc;
50231124Sminshall 		    notc2.t_intrc = ntc.t_intrc;
50331124Sminshall 		    notc2.t_quitc = ntc.t_quitc;
50431124Sminshall 		    tc = &notc2;
50531124Sminshall 		} else {
50631124Sminshall 		    tc = &notc;
50731124Sminshall 		}
50831124Sminshall 	    }
50931124Sminshall 	    ltc = &noltc;
51031124Sminshall 	    onoff = 1;
51131124Sminshall 	    break;
51231124Sminshall     case 3:		/* local character processing, remote echo */
51331124Sminshall     case 4:		/* local character processing, local echo */
51431124Sminshall     case 5:		/* local character processing, no echo */
51531124Sminshall 	    sb.sg_flags &= ~CBREAK;
51631124Sminshall 	    sb.sg_flags |= CRMOD;
51731124Sminshall 	    if (f == 4)
51831124Sminshall 		sb.sg_flags |= ECHO;
51931124Sminshall 	    else
52031124Sminshall 		sb.sg_flags &= ~ECHO;
52131124Sminshall 	    notc2 = ntc;
52231124Sminshall 	    tc = &notc2;
52331124Sminshall 	    noltc2 = oltc;
52431124Sminshall 	    ltc = &noltc2;
52531124Sminshall 	    /*
52631124Sminshall 	     * If user hasn't specified one way or the other,
52731124Sminshall 	     * then default to trapping signals.
52831124Sminshall 	     */
52931124Sminshall 	    if (!donelclchars) {
53031124Sminshall 		localchars = 1;
53131124Sminshall 	    }
53231124Sminshall 	    if (localchars) {
53331124Sminshall 		notc2.t_brkc = nltc.t_flushc;
53431124Sminshall 		noltc2.t_flushc = -1;
53531124Sminshall 	    } else {
53631124Sminshall 		notc2.t_intrc = notc2.t_quitc = -1;
53731124Sminshall 	    }
53831124Sminshall 	    noltc2.t_suspc = escape;
53931124Sminshall 	    noltc2.t_dsuspc = -1;
54031124Sminshall 	    onoff = 1;
54131124Sminshall 	    break;
54231124Sminshall 
54331124Sminshall     default:
54431124Sminshall 	    return;
54531124Sminshall     }
54631124Sminshall     ioctl(tin, TIOCSLTC, (char *)ltc);
54731124Sminshall     ioctl(tin, TIOCSETC, (char *)tc);
54831124Sminshall     ioctl(tin, TIOCSETP, (char *)&sb);
54931124Sminshall #if	(!defined(TN3270)) || ((!defined(NOT43)) || defined(PUTCHAR))
55031124Sminshall     ioctl(tin, FIONBIO, (char *)&onoff);
55131124Sminshall     ioctl(tout, FIONBIO, (char *)&onoff);
55231124Sminshall #endif	/* (!defined(TN3270)) || ((!defined(NOT43)) || defined(PUTCHAR)) */
55331124Sminshall #if	defined(TN3270) && !defined(DEBUG)
55431124Sminshall     ioctl(tin, FIOASYNC, (char *)&onoff);
55531124Sminshall #endif	/* defined(TN3270) && !defined(DEBUG) */
55631124Sminshall 
55731124Sminshall     if (MODE_LINE(f)) {
55831124Sminshall 	void doescape();
55931124Sminshall 
56031124Sminshall 	signal(SIGTSTP, doescape);
56131124Sminshall     } else if (MODE_LINE(old)) {
56231124Sminshall 	signal(SIGTSTP, SIG_DFL);
56331124Sminshall 	sigsetmask(sigblock(0) & ~(1<<(SIGTSTP-1)));
56431124Sminshall     }
56531124Sminshall }
56631124Sminshall 
56731124Sminshall 
568*31131Sminshall int
569*31131Sminshall NetClose(net)
570*31131Sminshall int	net;
571*31131Sminshall {
572*31131Sminshall     return close(net);
573*31131Sminshall }
574*31131Sminshall 
575*31131Sminshall 
57631124Sminshall static void
57731124Sminshall NetNonblockingIO(fd, onoff)				/* unix */
57831124Sminshall int
57931124Sminshall 	fd,
58031124Sminshall 	onoff;
58131124Sminshall {
58231124Sminshall     ioctl(net, FIONBIO, (char *)&onoff);
58331124Sminshall }
58431124Sminshall 
58531124Sminshall static void
58631124Sminshall NetSigIO(fd, onoff)				/* unix */
58731124Sminshall int
58831124Sminshall 	fd,
58931124Sminshall 	onoff;
59031124Sminshall {
59131124Sminshall     ioctl(net, FIOASYNC, (char *)&onoff);	/* hear about input */
59231124Sminshall }
59331124Sminshall 
59431124Sminshall static void
59531124Sminshall NetSetPgrp(fd)				/* unix */
59631124Sminshall int fd;
59731124Sminshall {
59831124Sminshall     int myPid;
59931124Sminshall 
60031124Sminshall     myPid = getpid();
60131124Sminshall #if	defined(NOT43)
60231124Sminshall     myPid = -myPid;
60331124Sminshall #endif	/* defined(NOT43) */
60431124Sminshall     ioctl(net, SIOCSPGRP, (char *)&myPid);	/* set my pid */
60531124Sminshall }
60631124Sminshall 
60731124Sminshall 
60831124Sminshall #endif	/* defined(unix) */
60931124Sminshall 
61031124Sminshall #if	defined(MSDOS)
61131124Sminshall #include <time.h>
612*31131Sminshall #include <signal.h>
61331124Sminshall 
61431124Sminshall #if	!defined(SO_OOBINLINE)
61531124Sminshall #define	SO_OOBINLINE
61631124Sminshall #endif	/* !defined(SO_OOBINLINE) */
61731124Sminshall 
61831124Sminshall 
61931124Sminshall static char
620*31131Sminshall     termEofChar,
62131124Sminshall     termEraseChar,
62231124Sminshall     termFlushChar,
62331124Sminshall     termIntChar,
62431124Sminshall     termKillChar,
625*31131Sminshall     termLiteralNextChar,
626*31131Sminshall     termQuitChar;
62731124Sminshall 
628*31131Sminshall 
629*31131Sminshall /*
630*31131Sminshall  * MSDOS doesn't have anyway of deciding whether a full-edited line
631*31131Sminshall  * is ready to be read in, so we need to do character-by-character
632*31131Sminshall  * reads, and then do the editing in the program (in the case where
633*31131Sminshall  * we are supporting line-by-line mode).
634*31131Sminshall  *
635*31131Sminshall  * The following routines, which are internal to the MSDOS-specific
636*31131Sminshall  * code, accomplish this miracle.
637*31131Sminshall  */
63831124Sminshall 
639*31131Sminshall #define Hex(c)	HEX[(c)&0xff]
640*31131Sminshall 
641*31131Sminshall static survivorSetup = 0;		/* Do we have ^C hooks in? */
642*31131Sminshall 
643*31131Sminshall static int
644*31131Sminshall 	lineend = 0,		/* There is a line terminator */
645*31131Sminshall 	ctrlCCount = 0;
646*31131Sminshall 
647*31131Sminshall static char	linein[200],		/* Where input line is assembled */
648*31131Sminshall 		*nextin = linein,	/* Next input character */
649*31131Sminshall 		*nextout = linein;	/* Next character to be consumed */
650*31131Sminshall 
651*31131Sminshall #define consumechar() \
652*31131Sminshall     if ((++nextout) >= nextin) { \
653*31131Sminshall 	nextout = nextin = linein; \
654*31131Sminshall 	lineend = 0; \
655*31131Sminshall     }
656*31131Sminshall 
657*31131Sminshall #define	characteratatime()	(!MODE_LINE(globalmode))	/* one by one */
658*31131Sminshall 
659*31131Sminshall 
66031124Sminshall /*
661*31131Sminshall  * killone()
662*31131Sminshall  *
663*31131Sminshall  *  Erase the last character on the line.
664*31131Sminshall  */
665*31131Sminshall 
666*31131Sminshall static void
667*31131Sminshall killone()
668*31131Sminshall {
669*31131Sminshall     if (lineend) {
670*31131Sminshall 	return;			/* ??? XXX */
671*31131Sminshall     }
672*31131Sminshall     if (nextin == linein) {
673*31131Sminshall 	return;			/* Nothing to do */
674*31131Sminshall     }
675*31131Sminshall     nextin--;
676*31131Sminshall     if (!(isspace(*nextin) || isprint(*nextin))) {
677*31131Sminshall 	putchar('\b');
678*31131Sminshall 	putchar(' ');
679*31131Sminshall 	putchar('\b');
680*31131Sminshall     }
681*31131Sminshall     putchar('\b');
682*31131Sminshall     putchar(' ');
683*31131Sminshall     putchar('\b');
684*31131Sminshall }
685*31131Sminshall 
686*31131Sminshall 
687*31131Sminshall /*
688*31131Sminshall  * setlineend()
689*31131Sminshall  *
690*31131Sminshall  *  Decide if it's time to send the current line up to the user
691*31131Sminshall  * process.
692*31131Sminshall  */
693*31131Sminshall 
694*31131Sminshall static void
695*31131Sminshall setlineend()
696*31131Sminshall {
697*31131Sminshall     if (nextin == nextout) {
698*31131Sminshall 	return;
699*31131Sminshall     }
700*31131Sminshall     if (characteratatime()) {
701*31131Sminshall 	lineend = 1;
702*31131Sminshall     } else if (nextin >= (linein+sizeof linein)) {
703*31131Sminshall 	lineend = 1;
704*31131Sminshall     } else {
705*31131Sminshall 	int c = *(nextin-1);
706*31131Sminshall 	if ((c == termIntChar)
707*31131Sminshall 		|| (c == termQuitChar)
708*31131Sminshall 		|| (c == termEofChar)) {
709*31131Sminshall 	    lineend = 1;
710*31131Sminshall 	} else if (c == termFlushChar) {
711*31131Sminshall 	    lineend = 1;
712*31131Sminshall 	} else if ((c == '\n') || (c == '\r')) {
713*31131Sminshall 	    lineend = 1;
714*31131Sminshall 	}
715*31131Sminshall     }
716*31131Sminshall     /* Otherwise, leave it alone (reset by 'consumechar') */
717*31131Sminshall }
718*31131Sminshall 
719*31131Sminshall /*
720*31131Sminshall  * OK, what we do here is:
721*31131Sminshall  *
722*31131Sminshall  *   o  If we are echoing, then
723*31131Sminshall  *	o  Look for character erase, line kill characters
724*31131Sminshall  *	o  Echo the character (using '^' if a control character)
725*31131Sminshall  *   o  Put the character in the input buffer
726*31131Sminshall  *   o  Set 'lineend' as necessary
727*31131Sminshall  */
728*31131Sminshall 
729*31131Sminshall static void
730*31131Sminshall DoNextChar(c)
731*31131Sminshall int	c;			/* Character to process */
732*31131Sminshall {
733*31131Sminshall     static char literalnextcharacter = 0;
734*31131Sminshall 
735*31131Sminshall     if (nextin >= (linein+sizeof linein)) {
736*31131Sminshall 	putchar('\7');		/* Ring bell */
737*31131Sminshall 	setlineend();
738*31131Sminshall 	return;
739*31131Sminshall     }
740*31131Sminshall     if (MODE_LOCAL_CHARS(globalmode)) {
741*31131Sminshall 	/* Look for some special character */
742*31131Sminshall 	if (!literalnextcharacter) {
743*31131Sminshall 	    if (c == termEraseChar) {
744*31131Sminshall 		killone();
745*31131Sminshall 		setlineend();
746*31131Sminshall 		return;
747*31131Sminshall 	    } else if (c == termKillChar) {
748*31131Sminshall 		while (nextin != linein) {
749*31131Sminshall 		    killone();
750*31131Sminshall 		}
751*31131Sminshall 		setlineend();
752*31131Sminshall 		return;
753*31131Sminshall 	    } else if (c == termLiteralNextChar) {
754*31131Sminshall 		literalnextcharacter = 1;
755*31131Sminshall 		return;
756*31131Sminshall 	    }
757*31131Sminshall 	}
758*31131Sminshall 
759*31131Sminshall 	if (MODE_LOCAL_ECHO(globalmode)) {
760*31131Sminshall 	    if ((literalnextcharacter == 0) && ((c == '\r') || (c == '\n'))) {
761*31131Sminshall 		putchar('\r');
762*31131Sminshall 		putchar('\n');
763*31131Sminshall 		c = '\n';
764*31131Sminshall 	    } else if (!isprint(c) && !isspace(c)) {
765*31131Sminshall 		putchar('^');
766*31131Sminshall 		putchar(c^0x40);
767*31131Sminshall 	    } else {
768*31131Sminshall 		putchar(c);
769*31131Sminshall 	    }
770*31131Sminshall 	}
771*31131Sminshall 	literalnextcharacter = 0;
772*31131Sminshall     }
773*31131Sminshall     *nextin++ = c;
774*31131Sminshall     setlineend();
775*31131Sminshall }
776*31131Sminshall 
777*31131Sminshall static int
778*31131Sminshall inputExists()
779*31131Sminshall {
780*31131Sminshall     int input;
781*31131Sminshall     static state = 0;
782*31131Sminshall 
783*31131Sminshall     while (ctrlCCount) {
784*31131Sminshall 	DoNextChar(0x03);
785*31131Sminshall 	ctrlCCount--;
786*31131Sminshall     }
787*31131Sminshall     if (lineend) {
788*31131Sminshall 	return 1;
789*31131Sminshall     }
790*31131Sminshall     if (!kbhit()) {
791*31131Sminshall 	return lineend;
792*31131Sminshall     }
793*31131Sminshall     input = getch();			/* MSC - get console character */
794*31131Sminshall #if	0	/* For BIOS variety of calls */
795*31131Sminshall     if ((input&0xff) == 0) {
796*31131Sminshall 	if ((input&0xff00) == 0x0300) {		/* Null */
797*31131Sminshall 	    DoNextChar(0);
798*31131Sminshall 	} else {
799*31131Sminshall 	    DoNextChar(0x01);
800*31131Sminshall 	    if (input&0x8000) {
801*31131Sminshall 		DoNextChar(0x01);
802*31131Sminshall 		DoNextChar((input>>8)&0x7f);
803*31131Sminshall 	    } else {
804*31131Sminshall 		DoNextChar((input>>8)&0xff);
805*31131Sminshall 	    }
806*31131Sminshall 	}
807*31131Sminshall     } else {
808*31131Sminshall 	DoNextChar(input&0xff);
809*31131Sminshall     }
810*31131Sminshall #endif	/* 0 */
811*31131Sminshall     if ((input&0xff) == 0) {
812*31131Sminshall 	DoNextChar(0x01);		/* ^A */
813*31131Sminshall     } else {
814*31131Sminshall 	DoNextChar(input&0xff);
815*31131Sminshall     }
816*31131Sminshall     return lineend;
817*31131Sminshall }
818*31131Sminshall 
819*31131Sminshall 
820*31131Sminshall void
821*31131Sminshall CtrlCInterrupt()
822*31131Sminshall {
823*31131Sminshall     if (!MODE_COMMAND_LINE(globalmode)) {
824*31131Sminshall 	ctrlCCount++;		/* XXX */
825*31131Sminshall 	signal(SIGINT, CtrlCInterrupt);
826*31131Sminshall     } else {
827*31131Sminshall 	closeallsockets();
828*31131Sminshall 	exit();
829*31131Sminshall     }
830*31131Sminshall }
831*31131Sminshall 
832*31131Sminshall /*
833*31131Sminshall  * The MSDOS routines, called from elsewhere.
834*31131Sminshall  */
835*31131Sminshall 
836*31131Sminshall 
837*31131Sminshall static int
838*31131Sminshall TerminalAutoFlush()				/* MSDOS */
839*31131Sminshall {
840*31131Sminshall     return 1;
841*31131Sminshall }
842*31131Sminshall 
843*31131Sminshall static int
844*31131Sminshall TerminalCanRead()
845*31131Sminshall {
846*31131Sminshall     return inputExists();
847*31131Sminshall }
848*31131Sminshall 
849*31131Sminshall 
850*31131Sminshall /*
85131124Sminshall  * Flush output to the terminal
85231124Sminshall  */
85331124Sminshall 
85431124Sminshall static void
85531124Sminshall TerminalFlushOutput()				/* MSDOS */
85631124Sminshall {
85731124Sminshall }
85831124Sminshall 
859*31131Sminshall 
86031124Sminshall static void
861*31131Sminshall TerminalNewMode(f)				/* MSDOS */
862*31131Sminshall register int f;
863*31131Sminshall {
864*31131Sminshall     globalmode = f;
865*31131Sminshall     signal(SIGINT, CtrlCInterrupt);
866*31131Sminshall }
867*31131Sminshall 
868*31131Sminshall 
869*31131Sminshall int
870*31131Sminshall TerminalRead(fd, buffer, count)
871*31131Sminshall int	fd;
872*31131Sminshall char	*buffer;
873*31131Sminshall int	count;
874*31131Sminshall {
875*31131Sminshall     int done = 0;
876*31131Sminshall 
877*31131Sminshall     for (;;) {
878*31131Sminshall 	while (inputExists() && (done < count)) {
879*31131Sminshall 	    *buffer++ = *nextout;
880*31131Sminshall 	    consumechar();
881*31131Sminshall 	    done++;
882*31131Sminshall 	}
883*31131Sminshall 	if (done) {
884*31131Sminshall 	    return(done);
885*31131Sminshall 	} else {
886*31131Sminshall 	    return 0;
887*31131Sminshall 	}
888*31131Sminshall     }
889*31131Sminshall }
890*31131Sminshall 
891*31131Sminshall 
892*31131Sminshall static void
89331124Sminshall TerminalSaveState()				/* MSDOS */
89431124Sminshall {
89531124Sminshall }
89631124Sminshall 
897*31131Sminshall int
898*31131Sminshall TerminalSpecialChars(c)			/* MSDOS */
899*31131Sminshall {
900*31131Sminshall     return 1;
901*31131Sminshall }
902*31131Sminshall 
903*31131Sminshall 
90431124Sminshall static void
90531124Sminshall TerminalRestoreState()				/* MSDOS */
90631124Sminshall {
90731124Sminshall }
90831124Sminshall 
909*31131Sminshall 
910*31131Sminshall static int
911*31131Sminshall TerminalWrite(fd, buffer, count)		/* MSDOS */
912*31131Sminshall int	fd;
913*31131Sminshall char	*buffer;
914*31131Sminshall int	count;
915*31131Sminshall {
916*31131Sminshall     return fwrite(buffer, sizeof (char), count, stdout);
917*31131Sminshall }
918*31131Sminshall 
919*31131Sminshall 
920*31131Sminshall static int
921*31131Sminshall NetClose(fd)
922*31131Sminshall {
923*31131Sminshall     return closesocket(fd);
924*31131Sminshall }
925*31131Sminshall 
92631124Sminshall static void
92731124Sminshall NetNonblockingIO(fd, onoff)				/* MSDOS */
92831124Sminshall int
92931124Sminshall 	fd,
93031124Sminshall 	onoff;
93131124Sminshall {
93231124Sminshall     if (SetSockOpt(net, SOL_SOCKET, SO_NONBLOCKING, onoff)) {
93331124Sminshall 	perror("setsockop (SO_NONBLOCKING) ");
934*31131Sminshall 	ExitString(stderr, "exiting\n", 1);
93531124Sminshall     }
93631124Sminshall }
93731124Sminshall 
93831124Sminshall static void
93931124Sminshall NetSigIO(fd)				/* MSDOS */
94031124Sminshall int fd;
94131124Sminshall {
94231124Sminshall }
94331124Sminshall 
94431124Sminshall static void
94531124Sminshall NetSetPgrp(fd)				/* MSDOS */
94631124Sminshall int fd;
94731124Sminshall {
94831124Sminshall }
94931124Sminshall 
95031124Sminshall 
95131124Sminshall #endif	/* defined(MSDOS) */
95231124Sminshall 
95331124Sminshall /*
95430326Sminshall  * Initialize variables.
95530326Sminshall  */
95630326Sminshall 
95730326Sminshall static void
95830326Sminshall tninit()
95930326Sminshall {
960*31131Sminshall #if	defined(TN3270)
961*31131Sminshall     Sent3270TerminalType = 0;
96230326Sminshall     Ifrontp = Ibackp = Ibuf;
963*31131Sminshall #endif	/* defined(TN3270) */
964*31131Sminshall 
96530326Sminshall     tfrontp = tbackp = ttyobuf;
96630326Sminshall     nfrontp = nbackp = netobuf;
96730326Sminshall 
96830326Sminshall     /* Don't change telnetport */
96930722Sminshall     SB_CLEAR();
97030722Sminshall     ClearArray(hisopts);
97130722Sminshall     ClearArray(myopts);
97230722Sminshall     sbp = sibuf;
97330722Sminshall     tbp = tibuf;
97430326Sminshall 
97530722Sminshall     connected = net = scc = tcc = In3270 = ISend = 0;
97630722Sminshall     telnetport = 0;
97731124Sminshall #if	defined(unix)
97831124Sminshall     HaveInput = 0;
97931124Sminshall #endif	/* defined(unix) */
98030722Sminshall 
98130722Sminshall     SYNCHing = 0;
98230722Sminshall 
98330722Sminshall     errno = 0;
98430722Sminshall 
98530722Sminshall     flushline = 0;
98630722Sminshall 
98730326Sminshall     /* Don't change NetTrace */
98830326Sminshall 
98930326Sminshall     escape = CONTROL(']');
99030326Sminshall     echoc = CONTROL('E');
99130326Sminshall 
99230326Sminshall     flushline = 1;
99330326Sminshall     sp = getservbyname("telnet", "tcp");
99430326Sminshall     if (sp == 0) {
99530326Sminshall 	ExitString(stderr, "telnet: tcp/telnet: unknown service\n",1);
99630326Sminshall 	/*NOTREACHED*/
99730326Sminshall     }
99830326Sminshall 
99930326Sminshall #if	defined(TN3270)
100030722Sminshall     init_ctlr();		/* Initialize some things */
100130722Sminshall     init_keyboard();
100230722Sminshall     init_screen();
100330722Sminshall     init_system();
100430326Sminshall #endif	/* defined(TN3270) */
100530326Sminshall }
100630326Sminshall 
100730326Sminshall /*
100830088Sminshall  * Various utility routines.
100930088Sminshall  */
101030088Sminshall 
101130088Sminshall static void
101230088Sminshall makeargv()
101330088Sminshall {
101430088Sminshall 	register char *cp;
101530088Sminshall 	register char **argp = margv;
101630088Sminshall 
101730088Sminshall 	margc = 0;
101830088Sminshall 	for (cp = line; *cp;) {
101930088Sminshall 		while (isspace(*cp))
102030088Sminshall 			cp++;
102130088Sminshall 		if (*cp == '\0')
102230088Sminshall 			break;
102330088Sminshall 		*argp++ = cp;
102430088Sminshall 		margc += 1;
102530088Sminshall 		while (*cp != '\0' && !isspace(*cp))
102630088Sminshall 			cp++;
102730088Sminshall 		if (*cp == '\0')
102830088Sminshall 			break;
102930088Sminshall 		*cp++ = '\0';
103030088Sminshall 	}
103130088Sminshall 	*argp++ = 0;
103230088Sminshall }
103330088Sminshall 
103430088Sminshall static char *ambiguous;		/* special return value */
103530088Sminshall #define Ambiguous(t)	((t)&ambiguous)
103630088Sminshall 
103730088Sminshall 
103830088Sminshall static char **
103930088Sminshall genget(name, table, next)
104030088Sminshall char	*name;		/* name to match */
104130088Sminshall char	**table;		/* name entry in table */
104230088Sminshall char	**(*next)();	/* routine to return next entry in table */
104330088Sminshall {
104430088Sminshall 	register char *p, *q;
104530088Sminshall 	register char **c, **found;
104630088Sminshall 	register int nmatches, longest;
104730088Sminshall 
104830088Sminshall 	longest = 0;
104930088Sminshall 	nmatches = 0;
105030088Sminshall 	found = 0;
105130088Sminshall 	for (c = table; (p = *c) != 0; c = (*next)(c)) {
105230088Sminshall 		for (q = name;
105330088Sminshall 		    (*q == *p) || (isupper(*q) && tolower(*q) == *p); p++, q++)
105430088Sminshall 			if (*q == 0)		/* exact match? */
105530088Sminshall 				return (c);
105630088Sminshall 		if (!*q) {			/* the name was a prefix */
105730088Sminshall 			if (q - name > longest) {
105830088Sminshall 				longest = q - name;
105930088Sminshall 				nmatches = 1;
106030088Sminshall 				found = c;
106130088Sminshall 			} else if (q - name == longest)
106230088Sminshall 				nmatches++;
106330088Sminshall 		}
106430088Sminshall 	}
106530088Sminshall 	if (nmatches > 1)
106630088Sminshall 		return Ambiguous(char **);
106730088Sminshall 	return (found);
106830088Sminshall }
106930088Sminshall 
107030088Sminshall /*
107130088Sminshall  * Make a character string into a number.
107230088Sminshall  *
107330088Sminshall  * Todo:  1.  Could take random integers (12, 0x12, 012, 0b1).
107430088Sminshall  */
107530088Sminshall 
107630088Sminshall static
107730088Sminshall special(s)
107830088Sminshall register char *s;
107930088Sminshall {
108030088Sminshall 	register char c;
108130088Sminshall 	char b;
108230088Sminshall 
108330088Sminshall 	switch (*s) {
108430088Sminshall 	case '^':
108530088Sminshall 		b = *++s;
108630088Sminshall 		if (b == '?') {
108730088Sminshall 		    c = b | 0x40;		/* DEL */
108830088Sminshall 		} else {
108930088Sminshall 		    c = b & 0x1f;
109030088Sminshall 		}
109130088Sminshall 		break;
109230088Sminshall 	default:
109330088Sminshall 		c = *s;
109430088Sminshall 		break;
109530088Sminshall 	}
109630088Sminshall 	return c;
109730088Sminshall }
109830088Sminshall 
109930088Sminshall /*
110030088Sminshall  * Construct a control character sequence
110130088Sminshall  * for a special character.
110230088Sminshall  */
110330088Sminshall static char *
110430088Sminshall control(c)
110530088Sminshall 	register int c;
110630088Sminshall {
110730088Sminshall 	static char buf[3];
110830088Sminshall 
110930088Sminshall 	if (c == 0x7f)
111030088Sminshall 		return ("^?");
111130088Sminshall 	if (c == '\377') {
111230088Sminshall 		return "off";
111330088Sminshall 	}
111430088Sminshall 	if (c >= 0x20) {
111530088Sminshall 		buf[0] = c;
111630088Sminshall 		buf[1] = 0;
111730088Sminshall 	} else {
111830088Sminshall 		buf[0] = '^';
111930088Sminshall 		buf[1] = '@'+c;
112030088Sminshall 		buf[2] = 0;
112130088Sminshall 	}
112230088Sminshall 	return (buf);
112330088Sminshall }
112430088Sminshall 
112530088Sminshall 
112630088Sminshall /*
112730088Sminshall  * upcase()
112830088Sminshall  *
112930088Sminshall  *	Upcase (in place) the argument.
113030088Sminshall  */
113130088Sminshall 
113230088Sminshall static void
113330088Sminshall upcase(argument)
113430088Sminshall register char *argument;
113530088Sminshall {
113630088Sminshall     register int c;
113730088Sminshall 
113830088Sminshall     while ((c = *argument) != 0) {
113930088Sminshall 	if (islower(c)) {
114030088Sminshall 	    *argument = toupper(c);
114130088Sminshall 	}
114230088Sminshall 	argument++;
114330088Sminshall     }
114430088Sminshall }
114531124Sminshall 
114631124Sminshall /*
114731124Sminshall  * SetSockOpt()
114831124Sminshall  *
114931124Sminshall  * Compensate for differences in 4.2 and 4.3 systems.
115031124Sminshall  */
115131124Sminshall 
115231124Sminshall static int
115331124Sminshall SetSockOpt(fd, level, option, yesno)
115431124Sminshall int
115531124Sminshall 	fd,
115631124Sminshall 	level,
115731124Sminshall 	option,
115831124Sminshall 	yesno;
115931124Sminshall {
116031124Sminshall #ifndef	NOT43
116131124Sminshall     return setsockopt(fd, level, option,
116231124Sminshall 				(char *)&yesno, sizeof yesno);
116331124Sminshall #else	/* NOT43 */
116431124Sminshall     if (yesno == 0) {		/* Can't do that in 4.2! */
116531124Sminshall 	fprintf(stderr, "Error: attempt to turn off an option 0x%x.\n",
116631124Sminshall 				option);
116731124Sminshall 	return -1;
116831124Sminshall     }
116931124Sminshall     return setsockopt(fd, level, option, 0, 0);
117031124Sminshall #endif	/* NOT43 */
117131124Sminshall }
117230088Sminshall 
117330088Sminshall /*
117430088Sminshall  * The following are routines used to print out debugging information.
117530088Sminshall  */
117630088Sminshall 
117730088Sminshall 
117830088Sminshall static void
117930088Sminshall Dump(direction, buffer, length)
118030088Sminshall char	direction;
118130088Sminshall char	*buffer;
118230088Sminshall int	length;
118330088Sminshall {
118430088Sminshall #   define BYTES_PER_LINE	32
118530088Sminshall #   define min(x,y)	((x<y)? x:y)
118630088Sminshall     char *pThis;
118730088Sminshall     int offset;
118830088Sminshall 
118930088Sminshall     offset = 0;
119030088Sminshall 
119130088Sminshall     while (length) {
119230088Sminshall 	/* print one line */
119330088Sminshall 	fprintf(NetTrace, "%c 0x%x\t", direction, offset);
119430088Sminshall 	pThis = buffer;
119530088Sminshall 	buffer = buffer+min(length, BYTES_PER_LINE);
119630088Sminshall 	while (pThis < buffer) {
119730088Sminshall 	    fprintf(NetTrace, "%.2x", (*pThis)&0xff);
119830088Sminshall 	    pThis++;
119930088Sminshall 	}
120030088Sminshall 	fprintf(NetTrace, "\n");
120130088Sminshall 	length -= BYTES_PER_LINE;
120230088Sminshall 	offset += BYTES_PER_LINE;
120330088Sminshall 	if (length < 0) {
120430088Sminshall 	    return;
120530088Sminshall 	}
120630088Sminshall 	/* find next unique line */
120730088Sminshall     }
120830088Sminshall }
120930088Sminshall 
121030088Sminshall 
121130088Sminshall /*VARARGS*/
121230088Sminshall static void
121330088Sminshall printoption(direction, fmt, option, what)
121430088Sminshall 	char *direction, *fmt;
121530088Sminshall 	int option, what;
121630088Sminshall {
121730088Sminshall 	if (!showoptions)
121830088Sminshall 		return;
121930088Sminshall 	fprintf(NetTrace, "%s ", direction+1);
122030088Sminshall 	if (fmt == doopt)
122130088Sminshall 		fmt = "do";
122230088Sminshall 	else if (fmt == dont)
122330088Sminshall 		fmt = "dont";
122430088Sminshall 	else if (fmt == will)
122530088Sminshall 		fmt = "will";
122630088Sminshall 	else if (fmt == wont)
122730088Sminshall 		fmt = "wont";
122830088Sminshall 	else
122930088Sminshall 		fmt = "???";
123030088Sminshall 	if (option < (sizeof telopts/sizeof telopts[0]))
123130088Sminshall 		fprintf(NetTrace, "%s %s", fmt, telopts[option]);
123230088Sminshall 	else
123330088Sminshall 		fprintf(NetTrace, "%s %d", fmt, option);
123430088Sminshall 	if (*direction == '<') {
123530088Sminshall 		fprintf(NetTrace, "\r\n");
123630088Sminshall 		return;
123730088Sminshall 	}
123830088Sminshall 	fprintf(NetTrace, " (%s)\r\n", what ? "reply" : "don't reply");
123930088Sminshall }
124030088Sminshall 
124130088Sminshall static void
124230088Sminshall printsub(direction, pointer, length)
124330088Sminshall char	*direction,		/* "<" or ">" */
124430088Sminshall 	*pointer;		/* where suboption data sits */
124530088Sminshall int	length;			/* length of suboption data */
124630088Sminshall {
124730088Sminshall     if (showoptions) {
124830088Sminshall 	fprintf(NetTrace, "%s suboption ",
124930088Sminshall 				(direction[0] == '<')? "Received":"Sent");
125030088Sminshall 	switch (pointer[0]) {
125130088Sminshall 	case TELOPT_TTYPE:
125230088Sminshall 	    fprintf(NetTrace, "Terminal type ");
125330088Sminshall 	    switch (pointer[1]) {
125430088Sminshall 	    case TELQUAL_IS:
125530088Sminshall 		{
125630088Sminshall 		    char tmpbuf[sizeof subbuffer];
125730088Sminshall 		    int minlen = min(length, sizeof tmpbuf);
125830088Sminshall 
1259*31131Sminshall 		    memcpy(tmpbuf, pointer+2, minlen);
126030088Sminshall 		    tmpbuf[minlen-1] = 0;
126130088Sminshall 		    fprintf(NetTrace, "is %s.\n", tmpbuf);
126230088Sminshall 		}
126330088Sminshall 		break;
126430088Sminshall 	    case TELQUAL_SEND:
126530088Sminshall 		fprintf(NetTrace, "- request to send.\n");
126630088Sminshall 		break;
126730088Sminshall 	    default:
126830088Sminshall 		fprintf(NetTrace,
126930088Sminshall 				"- unknown qualifier %d (0x%x).\n", pointer[1]);
127030088Sminshall 	    }
127130088Sminshall 	    break;
127230088Sminshall 	default:
127330088Sminshall 	    fprintf(NetTrace, "Unknown option %d (0x%x)\n",
127430088Sminshall 					pointer[0], pointer[0]);
127530088Sminshall 	}
127630088Sminshall     }
127730088Sminshall }
127830088Sminshall 
127930088Sminshall /*
128030088Sminshall  * Check to see if any out-of-band data exists on a socket (for
128130088Sminshall  * Telnet "synch" processing).
128230088Sminshall  */
128330088Sminshall 
128430088Sminshall static int
128530088Sminshall stilloob(s)
128630088Sminshall int	s;		/* socket number */
128730088Sminshall {
128830088Sminshall     static struct timeval timeout = { 0 };
128930088Sminshall     fd_set	excepts;
129030088Sminshall     int value;
129130088Sminshall 
129230088Sminshall     do {
129330088Sminshall 	FD_ZERO(&excepts);
129430088Sminshall 	FD_SET(s, &excepts);
129530088Sminshall 	value = select(s+1, (fd_set *)0, (fd_set *)0, &excepts, &timeout);
129630088Sminshall     } while ((value == -1) && (errno == EINTR));
129730088Sminshall 
129830088Sminshall     if (value < 0) {
129930088Sminshall 	perror("select");
130030088Sminshall 	quit();
130130088Sminshall     }
130230088Sminshall     if (FD_ISSET(s, &excepts)) {
130330088Sminshall 	return 1;
130430088Sminshall     } else {
130530088Sminshall 	return 0;
130630088Sminshall     }
130730088Sminshall }
130830088Sminshall 
130930088Sminshall 
131030088Sminshall /*
131130088Sminshall  *  netflush
131230088Sminshall  *		Send as much data as possible to the network,
131330088Sminshall  *	handling requests for urgent data.
131430088Sminshall  *
131530088Sminshall  *		The return value indicates whether we did any
131630088Sminshall  *	useful work.
131730088Sminshall  */
131830088Sminshall 
131930088Sminshall 
132030088Sminshall int
132130088Sminshall netflush()
132230088Sminshall {
132330088Sminshall     int n;
132430088Sminshall 
132530088Sminshall     if ((n = nfrontp - nbackp) > 0) {
132630088Sminshall 	if (!neturg) {
1327*31131Sminshall 	    n = send(net, nbackp, n, 0);	/* normal write */
132830088Sminshall 	} else {
132930088Sminshall 	    n = neturg - nbackp;
133030088Sminshall 	    /*
133130088Sminshall 	     * In 4.2 (and 4.3) systems, there is some question about
133230088Sminshall 	     * what byte in a sendOOB operation is the "OOB" data.
133330088Sminshall 	     * To make ourselves compatible, we only send ONE byte
133430088Sminshall 	     * out of band, the one WE THINK should be OOB (though
133530088Sminshall 	     * we really have more the TCP philosophy of urgent data
133630088Sminshall 	     * rather than the Unix philosophy of OOB data).
133730088Sminshall 	     */
133830088Sminshall 	    if (n > 1) {
133930088Sminshall 		n = send(net, nbackp, n-1, 0);	/* send URGENT all by itself */
134030088Sminshall 	    } else {
134130088Sminshall 		n = send(net, nbackp, n, MSG_OOB);	/* URGENT data */
134230088Sminshall 	    }
134330088Sminshall 	}
134430088Sminshall     }
134530088Sminshall     if (n < 0) {
134630088Sminshall 	if (errno != ENOBUFS && errno != EWOULDBLOCK) {
134730088Sminshall 	    setcommandmode();
134830088Sminshall 	    perror(hostname);
1349*31131Sminshall 	    NetClose(net);
135030088Sminshall 	    neturg = 0;
135130088Sminshall 	    longjmp(peerdied, -1);
135230088Sminshall 	    /*NOTREACHED*/
135330088Sminshall 	}
135430088Sminshall 	n = 0;
135530088Sminshall     }
135630088Sminshall     if (netdata && n) {
135730088Sminshall 	Dump('>', nbackp, n);
135830088Sminshall     }
135930088Sminshall     nbackp += n;
136030088Sminshall     if (nbackp >= neturg) {
136130088Sminshall 	neturg = 0;
136230088Sminshall     }
136330088Sminshall     if (nbackp == nfrontp) {
136430088Sminshall 	nbackp = nfrontp = netobuf;
136530088Sminshall     }
136630088Sminshall     return n > 0;
136730088Sminshall }
136830088Sminshall 
136930088Sminshall /*
137030088Sminshall  * nextitem()
137130088Sminshall  *
137230088Sminshall  *	Return the address of the next "item" in the TELNET data
137330088Sminshall  * stream.  This will be the address of the next character if
137430088Sminshall  * the current address is a user data character, or it will
137530088Sminshall  * be the address of the character following the TELNET command
137630088Sminshall  * if the current address is a TELNET IAC ("I Am a Command")
137730088Sminshall  * character.
137830088Sminshall  */
137930088Sminshall 
138030088Sminshall static char *
138130088Sminshall nextitem(current)
138230088Sminshall char	*current;
138330088Sminshall {
138430088Sminshall     if ((*current&0xff) != IAC) {
138530088Sminshall 	return current+1;
138630088Sminshall     }
138730088Sminshall     switch (*(current+1)&0xff) {
138830088Sminshall     case DO:
138930088Sminshall     case DONT:
139030088Sminshall     case WILL:
139130088Sminshall     case WONT:
139230088Sminshall 	return current+3;
139330088Sminshall     case SB:		/* loop forever looking for the SE */
139430088Sminshall 	{
139530088Sminshall 	    register char *look = current+2;
139630088Sminshall 
139730088Sminshall 	    for (;;) {
139830088Sminshall 		if ((*look++&0xff) == IAC) {
139930088Sminshall 		    if ((*look++&0xff) == SE) {
140030088Sminshall 			return look;
140130088Sminshall 		    }
140230088Sminshall 		}
140330088Sminshall 	    }
140430088Sminshall 	}
140530088Sminshall     default:
140630088Sminshall 	return current+2;
140730088Sminshall     }
140830088Sminshall }
140930088Sminshall /*
141030088Sminshall  * netclear()
141130088Sminshall  *
141230088Sminshall  *	We are about to do a TELNET SYNCH operation.  Clear
141330088Sminshall  * the path to the network.
141430088Sminshall  *
141530088Sminshall  *	Things are a bit tricky since we may have sent the first
141630088Sminshall  * byte or so of a previous TELNET command into the network.
141730088Sminshall  * So, we have to scan the network buffer from the beginning
141830088Sminshall  * until we are up to where we want to be.
141930088Sminshall  *
142030088Sminshall  *	A side effect of what we do, just to keep things
142130088Sminshall  * simple, is to clear the urgent data pointer.  The principal
142230088Sminshall  * caller should be setting the urgent data pointer AFTER calling
142330088Sminshall  * us in any case.
142430088Sminshall  */
142530088Sminshall 
142630088Sminshall static void
142730088Sminshall netclear()
142830088Sminshall {
142930088Sminshall     register char *thisitem, *next;
143030088Sminshall     char *good;
143130088Sminshall #define	wewant(p)	((nfrontp > p) && ((*p&0xff) == IAC) && \
143230088Sminshall 				((*(p+1)&0xff) != EC) && ((*(p+1)&0xff) != EL))
143330088Sminshall 
143430088Sminshall     thisitem = netobuf;
143530088Sminshall 
143630088Sminshall     while ((next = nextitem(thisitem)) <= nbackp) {
143730088Sminshall 	thisitem = next;
143830088Sminshall     }
143930088Sminshall 
144030088Sminshall     /* Now, thisitem is first before/at boundary. */
144130088Sminshall 
144230088Sminshall     good = netobuf;	/* where the good bytes go */
144330088Sminshall 
144430088Sminshall     while (nfrontp > thisitem) {
144530088Sminshall 	if (wewant(thisitem)) {
144630088Sminshall 	    int length;
144730088Sminshall 
144830088Sminshall 	    next = thisitem;
144930088Sminshall 	    do {
145030088Sminshall 		next = nextitem(next);
145130088Sminshall 	    } while (wewant(next) && (nfrontp > next));
145230088Sminshall 	    length = next-thisitem;
1453*31131Sminshall 	    memcpy(good, thisitem, length);
145430088Sminshall 	    good += length;
145530088Sminshall 	    thisitem = next;
145630088Sminshall 	} else {
145730088Sminshall 	    thisitem = nextitem(thisitem);
145830088Sminshall 	}
145930088Sminshall     }
146030088Sminshall 
146130088Sminshall     nbackp = netobuf;
146230088Sminshall     nfrontp = good;		/* next byte to be sent */
146330088Sminshall     neturg = 0;
146430088Sminshall }
146530088Sminshall 
146630088Sminshall /*
146730088Sminshall  * These routines add various telnet commands to the data stream.
146830088Sminshall  */
146930088Sminshall 
147030088Sminshall #if	defined(NOT43)
147130088Sminshall static int
147230088Sminshall #else	/* defined(NOT43) */
147330088Sminshall static void
147430088Sminshall #endif	/* defined(NOT43) */
147530088Sminshall dosynch()
147630088Sminshall {
147730088Sminshall     netclear();			/* clear the path to the network */
147830088Sminshall     NET2ADD(IAC, DM);
147930088Sminshall     neturg = NETLOC()-1;	/* Some systems are off by one XXX */
148030088Sminshall 
148130088Sminshall #if	defined(NOT43)
148230088Sminshall     return 0;
148330088Sminshall #endif	/* defined(NOT43) */
148430088Sminshall }
148530088Sminshall 
148630088Sminshall static void
148730088Sminshall doflush()
148830088Sminshall {
148930088Sminshall     NET2ADD(IAC, DO);
149030088Sminshall     NETADD(TELOPT_TM);
149130088Sminshall     flushline = 1;
149230088Sminshall     flushout = 1;
149330088Sminshall     ttyflush();
149430088Sminshall     /* do printoption AFTER flush, otherwise the output gets tossed... */
149530088Sminshall     printoption("<SENT", doopt, TELOPT_TM, 0);
149630088Sminshall }
149730088Sminshall 
149830088Sminshall static void
149930088Sminshall intp()
150030088Sminshall {
150130088Sminshall     NET2ADD(IAC, IP);
150230088Sminshall     if (autoflush) {
150330088Sminshall 	doflush();
150430088Sminshall     }
150530088Sminshall     if (autosynch) {
150630088Sminshall 	dosynch();
150730088Sminshall     }
150830088Sminshall }
150930088Sminshall 
151030088Sminshall static void
151130088Sminshall sendbrk()
151230088Sminshall {
151330088Sminshall     NET2ADD(IAC, BREAK);
151430088Sminshall     if (autoflush) {
151530088Sminshall 	doflush();
151630088Sminshall     }
151730088Sminshall     if (autosynch) {
151830088Sminshall 	dosynch();
151930088Sminshall     }
152030088Sminshall }
152130088Sminshall 
152230088Sminshall /*
152330088Sminshall  *		Send as much data as possible to the terminal.
152430088Sminshall  *
152530088Sminshall  *		The return value indicates whether we did any
152630088Sminshall  *	useful work.
152730088Sminshall  */
152830088Sminshall 
152930088Sminshall 
153030088Sminshall static int
153130088Sminshall ttyflush()
153230088Sminshall {
153330088Sminshall     int n;
153430088Sminshall 
153530088Sminshall     if ((n = tfrontp - tbackp) > 0) {
153630088Sminshall 	if (!(SYNCHing||flushout)) {
1537*31131Sminshall 	    n = TerminalWrite(tout, tbackp, n);
153830088Sminshall 	} else {
153931124Sminshall 	    TerminalFlushOutput();
154030088Sminshall 	    /* we leave 'n' alone! */
154130088Sminshall 	}
154230088Sminshall     }
154330088Sminshall     if (n >= 0) {
154430088Sminshall 	tbackp += n;
154530088Sminshall 	if (tbackp == tfrontp) {
154630088Sminshall 	    tbackp = tfrontp = ttyobuf;
154730088Sminshall 	}
154830088Sminshall     }
154930088Sminshall     return n > 0;
155030088Sminshall }
155130088Sminshall 
155230088Sminshall #if	defined(TN3270)
155330088Sminshall 
155430088Sminshall #if	defined(unix)
155530088Sminshall static void
155630088Sminshall inputAvailable()
155730088Sminshall {
155830088Sminshall     HaveInput = 1;
155930088Sminshall }
156030088Sminshall #endif	/* defined(unix) */
156130088Sminshall 
156230088Sminshall void
156330088Sminshall outputPurge()
156430088Sminshall {
156530088Sminshall     int tmp = flushout;
156630088Sminshall 
156730088Sminshall     flushout = 1;
156830088Sminshall 
156930088Sminshall     ttyflush();
157030088Sminshall 
157130088Sminshall     flushout = tmp;
157230088Sminshall }
157330088Sminshall 
157430088Sminshall #endif	/* defined(TN3270) */
157530088Sminshall 
157630088Sminshall #if	defined(unix)
157730088Sminshall /*
157830088Sminshall  * Various signal handling routines.
157930088Sminshall  */
158030088Sminshall 
158130088Sminshall static void
158230088Sminshall deadpeer()
158330088Sminshall {
158430088Sminshall 	setcommandmode();
158530088Sminshall 	longjmp(peerdied, -1);
158630088Sminshall }
158730088Sminshall 
158830088Sminshall static void
158930088Sminshall intr()
159030088Sminshall {
159130088Sminshall     if (localchars) {
159230088Sminshall 	intp();
159330088Sminshall 	return;
159430088Sminshall     }
159530088Sminshall     setcommandmode();
159630088Sminshall     longjmp(toplevel, -1);
159730088Sminshall }
159830088Sminshall 
159930088Sminshall static void
160030088Sminshall intr2()
160130088Sminshall {
160230088Sminshall     if (localchars) {
160330088Sminshall 	sendbrk();
160430088Sminshall 	return;
160530088Sminshall     }
160630088Sminshall }
160730088Sminshall 
160830088Sminshall static void
160930088Sminshall doescape()
161030088Sminshall {
161130088Sminshall     command(0);
161230088Sminshall }
161330088Sminshall #endif	/* defined(unix) */
161430088Sminshall 
161530088Sminshall /*
161630088Sminshall  * These routines decides on what the mode should be (based on the values
161730088Sminshall  * of various global variables).
161830088Sminshall  */
161930088Sminshall 
162030088Sminshall 
162130088Sminshall static
162230088Sminshall getconnmode()
162330088Sminshall {
162430088Sminshall     static char newmode[16] =
162530088Sminshall 			{ 4, 5, 3, 3, 2, 2, 1, 1, 6, 6, 6, 6, 6, 6, 6, 6 };
162630088Sminshall     int modeindex = 0;
162730088Sminshall 
162830088Sminshall     if (dontlecho && (clocks.echotoggle > clocks.modenegotiated)) {
162930088Sminshall 	modeindex += 1;
163030088Sminshall     }
163130088Sminshall     if (hisopts[TELOPT_ECHO]) {
163230088Sminshall 	modeindex += 2;
163330088Sminshall     }
163430088Sminshall     if (hisopts[TELOPT_SGA]) {
163530088Sminshall 	modeindex += 4;
163630088Sminshall     }
163730088Sminshall     if (In3270) {
163830088Sminshall 	modeindex += 8;
163930088Sminshall     }
164030088Sminshall     return newmode[modeindex];
164130088Sminshall }
164230088Sminshall 
164330088Sminshall void
164430088Sminshall setconnmode()
164530088Sminshall {
164631124Sminshall     TerminalNewMode(getconnmode());
164730088Sminshall }
164830088Sminshall 
164930088Sminshall 
165030088Sminshall void
165130088Sminshall setcommandmode()
165230088Sminshall {
165331124Sminshall     TerminalNewMode(0);
165430088Sminshall }
165530088Sminshall 
165630088Sminshall static void
165730088Sminshall willoption(option, reply)
165830088Sminshall 	int option, reply;
165930088Sminshall {
166030088Sminshall 	char *fmt;
166130088Sminshall 
166230088Sminshall 	switch (option) {
166330088Sminshall 
166430368Sminshall 	case TELOPT_ECHO:
166530088Sminshall #	if defined(TN3270)
166630368Sminshall 	    /*
166730368Sminshall 	     * The following is a pain in the rear-end.
166830368Sminshall 	     * Various IBM servers (some versions of Wiscnet,
166930368Sminshall 	     * possibly Fibronics/Spartacus, and who knows who
167030368Sminshall 	     * else) will NOT allow us to send "DO SGA" too early
167130368Sminshall 	     * in the setup proceedings.  On the other hand,
167230368Sminshall 	     * 4.2 servers (telnetd) won't set SGA correctly.
167330368Sminshall 	     * So, we are stuck.  Empirically (but, based on
167430368Sminshall 	     * a VERY small sample), the IBM servers don't send
167530368Sminshall 	     * out anything about ECHO, so we postpone our sending
167630368Sminshall 	     * "DO SGA" until we see "WILL ECHO" (which 4.2 servers
167730368Sminshall 	     * DO send).
167830368Sminshall 	     */
167930368Sminshall 	    {
168030368Sminshall 		if (askedSGA == 0) {
168130368Sminshall 		    askedSGA = 1;
168230368Sminshall 		    if (!hisopts[TELOPT_SGA]) {
168330368Sminshall 			willoption(TELOPT_SGA, 0);
168430368Sminshall 		    }
168530368Sminshall 		}
168630368Sminshall 	    }
168730368Sminshall 		/* Fall through */
168830088Sminshall 	case TELOPT_EOR:
168930088Sminshall 	case TELOPT_BINARY:
169030088Sminshall #endif	/* defined(TN3270) */
169130088Sminshall 	case TELOPT_SGA:
169230088Sminshall 		settimer(modenegotiated);
169330088Sminshall 		hisopts[option] = 1;
169430088Sminshall 		fmt = doopt;
169530088Sminshall 		setconnmode();		/* possibly set new tty mode */
169630088Sminshall 		break;
169730088Sminshall 
169830088Sminshall 	case TELOPT_TM:
169930088Sminshall 		return;			/* Never reply to TM will's/wont's */
170030088Sminshall 
170130088Sminshall 	default:
170230088Sminshall 		fmt = dont;
170330088Sminshall 		break;
170430088Sminshall 	}
170530088Sminshall 	sprintf(nfrontp, fmt, option);
170630088Sminshall 	nfrontp += sizeof (dont) - 2;
170730088Sminshall 	if (reply)
170830088Sminshall 		printoption(">SENT", fmt, option, reply);
170930088Sminshall 	else
171030088Sminshall 		printoption("<SENT", fmt, option, reply);
171130088Sminshall }
171230088Sminshall 
171330088Sminshall static void
171430088Sminshall wontoption(option, reply)
171530088Sminshall 	int option, reply;
171630088Sminshall {
171730088Sminshall 	char *fmt;
171830088Sminshall 
171930088Sminshall 	switch (option) {
172030088Sminshall 
172130088Sminshall 	case TELOPT_ECHO:
172230088Sminshall 	case TELOPT_SGA:
172330088Sminshall 		settimer(modenegotiated);
172430088Sminshall 		hisopts[option] = 0;
172530088Sminshall 		fmt = dont;
172630088Sminshall 		setconnmode();			/* Set new tty mode */
172730088Sminshall 		break;
172830088Sminshall 
172930088Sminshall 	case TELOPT_TM:
173030088Sminshall 		return;		/* Never reply to TM will's/wont's */
173130088Sminshall 
173230088Sminshall 	default:
173330088Sminshall 		fmt = dont;
173430088Sminshall 	}
173530088Sminshall 	sprintf(nfrontp, fmt, option);
173630088Sminshall 	nfrontp += sizeof (doopt) - 2;
173730088Sminshall 	if (reply)
173830088Sminshall 		printoption(">SENT", fmt, option, reply);
173930088Sminshall 	else
174030088Sminshall 		printoption("<SENT", fmt, option, reply);
174130088Sminshall }
174230088Sminshall 
174330088Sminshall static void
174430088Sminshall dooption(option)
174530088Sminshall 	int option;
174630088Sminshall {
174730088Sminshall 	char *fmt;
174830088Sminshall 
174930088Sminshall 	switch (option) {
175030088Sminshall 
175130088Sminshall 	case TELOPT_TM:
175230088Sminshall 		fmt = will;
175330088Sminshall 		break;
175430088Sminshall 
175530088Sminshall #	if defined(TN3270)
175630088Sminshall 	case TELOPT_EOR:
175730088Sminshall 	case TELOPT_BINARY:
175830088Sminshall #	endif	/* defined(TN3270) */
175930088Sminshall 	case TELOPT_TTYPE:		/* terminal type option */
176030088Sminshall 	case TELOPT_SGA:		/* no big deal */
176130088Sminshall 		fmt = will;
176230088Sminshall 		myopts[option] = 1;
176330088Sminshall 		break;
176430088Sminshall 
176530088Sminshall 	case TELOPT_ECHO:		/* We're never going to echo... */
176630088Sminshall 	default:
176730088Sminshall 		fmt = wont;
176830088Sminshall 		break;
176930088Sminshall 	}
177030088Sminshall 	sprintf(nfrontp, fmt, option);
177130088Sminshall 	nfrontp += sizeof (doopt) - 2;
177230088Sminshall 	printoption(">SENT", fmt, option, 0);
177330088Sminshall }
177430088Sminshall 
177530088Sminshall /*
177630088Sminshall  * suboption()
177730088Sminshall  *
177830088Sminshall  *	Look at the sub-option buffer, and try to be helpful to the other
177930088Sminshall  * side.
178030088Sminshall  *
178130088Sminshall  *	Currently we recognize:
178230088Sminshall  *
178330088Sminshall  *		Terminal type, send request.
178430088Sminshall  */
178530088Sminshall 
178630088Sminshall static void
178730088Sminshall suboption()
178830088Sminshall {
178930088Sminshall     printsub("<", subbuffer, subend-subbuffer+1);
179030088Sminshall     switch (subbuffer[0]&0xff) {
179130088Sminshall     case TELOPT_TTYPE:
179230088Sminshall 	if ((subbuffer[1]&0xff) != TELQUAL_SEND) {
179330088Sminshall 	    ;
179430088Sminshall 	} else {
179530088Sminshall 	    char *name;
179630088Sminshall 	    char namebuf[41];
179730088Sminshall 	    extern char *getenv();
179830088Sminshall 	    int len;
179930088Sminshall 
180030088Sminshall #if	defined(TN3270)
180130088Sminshall 	    /*
180230326Sminshall 	     * Try to send a 3270 type terminal name.  Decide which one based
180330088Sminshall 	     * on the format of our screen, and (in the future) color
180430088Sminshall 	     * capaiblities.
180530088Sminshall 	     */
180631124Sminshall #if	defined(unix)
1807*31131Sminshall 	    if (initscr() != ERR) {	/* Initialize curses to get line size */
1808*31131Sminshall 		MaxNumberLines = LINES;
1809*31131Sminshall 		MaxNumberColumns = COLS;
1810*31131Sminshall 	    }
1811*31131Sminshall #else	/* defined(unix) */
1812*31131Sminshall 	    InitTerminal();
1813*31131Sminshall #endif	/* defined(unix) */
1814*31131Sminshall 	    if ((MaxNumberLines >= 24) && (MaxNumberColumns >= 80)) {
181530088Sminshall 		Sent3270TerminalType = 1;
1816*31131Sminshall 		if ((MaxNumberLines >= 27) && (MaxNumberColumns >= 132)) {
181730088Sminshall 		    MaxNumberLines = 27;
181830088Sminshall 		    MaxNumberColumns = 132;
181930088Sminshall 		    sb_terminal[SBTERMMODEL] = '5';
1820*31131Sminshall 		} else if (MaxNumberLines >= 43) {
182130088Sminshall 		    MaxNumberLines = 43;
182230088Sminshall 		    MaxNumberColumns = 80;
182330088Sminshall 		    sb_terminal[SBTERMMODEL] = '4';
1824*31131Sminshall 		} else if (MaxNumberLines >= 32) {
182530088Sminshall 		    MaxNumberLines = 32;
182630088Sminshall 		    MaxNumberColumns = 80;
182730088Sminshall 		    sb_terminal[SBTERMMODEL] = '3';
182830088Sminshall 		} else {
182930088Sminshall 		    MaxNumberLines = 24;
183030088Sminshall 		    MaxNumberColumns = 80;
183130088Sminshall 		    sb_terminal[SBTERMMODEL] = '2';
183230088Sminshall 		}
183330088Sminshall 		NumberLines = 24;		/* before we start out... */
183430088Sminshall 		NumberColumns = 80;
183530088Sminshall 		ScreenSize = NumberLines*NumberColumns;
183630088Sminshall 		if ((MaxNumberLines*MaxNumberColumns) > MAXSCREENSIZE) {
183730088Sminshall 		    ExitString(stderr,
183830088Sminshall 			"Programming error:  MAXSCREENSIZE too small.\n", 1);
183930088Sminshall 		    /*NOTREACHED*/
184030088Sminshall 		}
1841*31131Sminshall 		memcpy(nfrontp, sb_terminal, sizeof sb_terminal);
184230088Sminshall 		printsub(">", nfrontp+2, sizeof sb_terminal-2);
184330088Sminshall 		nfrontp += sizeof sb_terminal;
184430088Sminshall 		return;
184530088Sminshall 	    }
184630088Sminshall #endif	/* defined(TN3270) */
184730088Sminshall 
184830088Sminshall 	    name = getenv("TERM");
184930088Sminshall 	    if ((name == 0) || ((len = strlen(name)) > 40)) {
185030088Sminshall 		name = "UNKNOWN";
185130088Sminshall 	    }
185230088Sminshall 	    if ((len + 4+2) < NETROOM()) {
185330088Sminshall 		strcpy(namebuf, name);
185430088Sminshall 		upcase(namebuf);
185530088Sminshall 		sprintf(nfrontp, "%c%c%c%c%s%c%c", IAC, SB, TELOPT_TTYPE,
185630088Sminshall 				    TELQUAL_IS, namebuf, IAC, SE);
185730088Sminshall 		printsub(">", nfrontp+2, 4+strlen(namebuf)+2-2-2);
185830088Sminshall 		nfrontp += 4+strlen(namebuf)+2;
185930088Sminshall 	    } else {
186030088Sminshall 		ExitString(stderr, "No room in buffer for terminal type.\n",
186130088Sminshall 							1);
186230088Sminshall 		/*NOTREACHED*/
186330088Sminshall 	    }
186430088Sminshall 	}
186530088Sminshall 
186630088Sminshall     default:
186730088Sminshall 	break;
186830088Sminshall     }
186930088Sminshall }
187030088Sminshall 
187130088Sminshall #if	defined(TN3270)
187230088Sminshall static void
187330088Sminshall SetIn3270()
187430088Sminshall {
187530088Sminshall     if (Sent3270TerminalType && myopts[TELOPT_BINARY]
187630088Sminshall 					&& hisopts[TELOPT_BINARY]) {
187730088Sminshall 	if (!In3270) {
187830088Sminshall 	    In3270 = 1;
187930326Sminshall 	    Init3270();		/* Initialize 3270 functions */
188030088Sminshall 	    /* initialize terminal key mapping */
188130326Sminshall 	    InitTerminal();	/* Start terminal going */
188230088Sminshall 	    setconnmode();
188330088Sminshall 	}
188430088Sminshall     } else {
188530088Sminshall 	if (In3270) {
188630088Sminshall 	    StopScreen(1);
188730088Sminshall 	    In3270 = 0;
188830088Sminshall 	    setconnmode();
188930088Sminshall 	}
189030088Sminshall     }
189130088Sminshall }
189230088Sminshall #endif	/* defined(TN3270) */
189330088Sminshall 
189430088Sminshall 
189530088Sminshall static void
189630088Sminshall telrcv()
189730088Sminshall {
189830088Sminshall     register int c;
189930722Sminshall     static int telrcv_state = TS_DATA;
190030088Sminshall #   if defined(TN3270)
190130088Sminshall     register int Scc;
190230088Sminshall     register char *Sbp;
190330088Sminshall #   endif /* defined(TN3270) */
190430088Sminshall 
190530088Sminshall     while ((scc > 0) && (TTYROOM() > 2)) {
190630088Sminshall 	c = *sbp++ & 0xff, scc--;
190730722Sminshall 	switch (telrcv_state) {
190830088Sminshall 
190930088Sminshall 	case TS_CR:
191030722Sminshall 	    telrcv_state = TS_DATA;
191130088Sminshall 	    if (c == '\0') {
191230088Sminshall 		break;	/* Ignore \0 after CR */
191330088Sminshall 	    } else if (c == '\n') {
191430088Sminshall 		if (hisopts[TELOPT_ECHO] && !crmod) {
191530088Sminshall 		    TTYADD(c);
191630088Sminshall 		}
191730088Sminshall 		break;
191830088Sminshall 	    }
191930088Sminshall 	    /* Else, fall through */
192030088Sminshall 
192130088Sminshall 	case TS_DATA:
192230088Sminshall 	    if (c == IAC) {
192330722Sminshall 		telrcv_state = TS_IAC;
192430088Sminshall 		continue;
192530088Sminshall 	    }
192630088Sminshall #	    if defined(TN3270)
192730088Sminshall 	    if (In3270) {
192830088Sminshall 		*Ifrontp++ = c;
192930088Sminshall 		Sbp = sbp;
193030088Sminshall 		Scc = scc;
193130088Sminshall 		while (Scc > 0) {
193230088Sminshall 		    c = *Sbp++ & 0377, Scc--;
193330088Sminshall 		    if (c == IAC) {
193430722Sminshall 			telrcv_state = TS_IAC;
193530088Sminshall 			break;
193630088Sminshall 		    }
193730088Sminshall 		    *Ifrontp++ = c;
193830088Sminshall 		}
193930088Sminshall 		sbp = Sbp;
194030088Sminshall 		scc = Scc;
194130088Sminshall 	    } else
194230088Sminshall #	    endif /* defined(TN3270) */
194330088Sminshall 		    /*
194430088Sminshall 		     * The 'crmod' hack (see following) is needed
194530088Sminshall 		     * since we can't * set CRMOD on output only.
194630088Sminshall 		     * Machines like MULTICS like to send \r without
194730088Sminshall 		     * \n; since we must turn off CRMOD to get proper
194830088Sminshall 		     * input, the mapping is done here (sigh).
194930088Sminshall 		     */
195030088Sminshall 	    if (c == '\r') {
195130088Sminshall 		if (scc > 0) {
195230088Sminshall 		    c = *sbp&0xff;
195330088Sminshall 		    if (c == 0) {
195430088Sminshall 			sbp++, scc--;
195530088Sminshall 			/* a "true" CR */
195630088Sminshall 			TTYADD('\r');
195730088Sminshall 		    } else if (!hisopts[TELOPT_ECHO] &&
195830088Sminshall 					(c == '\n')) {
195930088Sminshall 			sbp++, scc--;
196030088Sminshall 			TTYADD('\n');
196130088Sminshall 		    } else {
196230088Sminshall 			TTYADD('\r');
196330088Sminshall 			if (crmod) {
196430088Sminshall 				TTYADD('\n');
196530088Sminshall 			}
196630088Sminshall 		    }
196730088Sminshall 		} else {
196830722Sminshall 		    telrcv_state = TS_CR;
196930088Sminshall 		    TTYADD('\r');
197030088Sminshall 		    if (crmod) {
197130088Sminshall 			    TTYADD('\n');
197230088Sminshall 		    }
197330088Sminshall 		}
197430088Sminshall 	    } else {
197530088Sminshall 		TTYADD(c);
197630088Sminshall 	    }
197730088Sminshall 	    continue;
197830088Sminshall 
197930088Sminshall 	case TS_IAC:
198030088Sminshall 	    switch (c) {
198130088Sminshall 
198230088Sminshall 	    case WILL:
198330722Sminshall 		telrcv_state = TS_WILL;
198430088Sminshall 		continue;
198530088Sminshall 
198630088Sminshall 	    case WONT:
198730722Sminshall 		telrcv_state = TS_WONT;
198830088Sminshall 		continue;
198930088Sminshall 
199030088Sminshall 	    case DO:
199130722Sminshall 		telrcv_state = TS_DO;
199230088Sminshall 		continue;
199330088Sminshall 
199430088Sminshall 	    case DONT:
199530722Sminshall 		telrcv_state = TS_DONT;
199630088Sminshall 		continue;
199730088Sminshall 
199830088Sminshall 	    case DM:
199930088Sminshall 		    /*
200030088Sminshall 		     * We may have missed an urgent notification,
200130088Sminshall 		     * so make sure we flush whatever is in the
200230088Sminshall 		     * buffer currently.
200330088Sminshall 		     */
200430088Sminshall 		SYNCHing = 1;
200530088Sminshall 		ttyflush();
200630088Sminshall 		SYNCHing = stilloob(net);
200730088Sminshall 		settimer(gotDM);
200830088Sminshall 		break;
200930088Sminshall 
201030088Sminshall 	    case NOP:
201130088Sminshall 	    case GA:
201230088Sminshall 		break;
201330088Sminshall 
201430088Sminshall 	    case SB:
201530088Sminshall 		SB_CLEAR();
201630722Sminshall 		telrcv_state = TS_SB;
201730088Sminshall 		continue;
201830088Sminshall 
201930088Sminshall #	    if defined(TN3270)
202030088Sminshall 	    case EOR:
202130088Sminshall 		if (In3270) {
202230088Sminshall 		    Ibackp += DataFromNetwork(Ibackp, Ifrontp-Ibackp, 1);
202330088Sminshall 		    if (Ibackp == Ifrontp) {
202430088Sminshall 			Ibackp = Ifrontp = Ibuf;
202530088Sminshall 			ISend = 0;	/* should have been! */
202630088Sminshall 		    } else {
202730088Sminshall 			ISend = 1;
202830088Sminshall 		    }
202930088Sminshall 		}
203030088Sminshall 		break;
203130088Sminshall #	    endif /* defined(TN3270) */
203230088Sminshall 
203330088Sminshall 	    case IAC:
203430088Sminshall #	    if !defined(TN3270)
203530088Sminshall 		TTYADD(IAC);
203630088Sminshall #	    else /* !defined(TN3270) */
203730088Sminshall 		if (In3270) {
203830088Sminshall 		    *Ifrontp++ = IAC;
203930088Sminshall 		} else {
204030088Sminshall 		    TTYADD(IAC);
204130088Sminshall 		}
204230088Sminshall #	    endif /* !defined(TN3270) */
204330088Sminshall 		break;
204430088Sminshall 
204530088Sminshall 	    default:
204630088Sminshall 		break;
204730088Sminshall 	    }
204830722Sminshall 	    telrcv_state = TS_DATA;
204930088Sminshall 	    continue;
205030088Sminshall 
205130088Sminshall 	case TS_WILL:
205230088Sminshall 	    printoption(">RCVD", will, c, !hisopts[c]);
205330088Sminshall 	    if (c == TELOPT_TM) {
205430088Sminshall 		if (flushout) {
205530088Sminshall 		    flushout = 0;
205630088Sminshall 		}
205730088Sminshall 	    } else if (!hisopts[c]) {
205830088Sminshall 		willoption(c, 1);
205930088Sminshall 	    }
206030088Sminshall 	    SetIn3270();
206130722Sminshall 	    telrcv_state = TS_DATA;
206230088Sminshall 	    continue;
206330088Sminshall 
206430088Sminshall 	case TS_WONT:
206530088Sminshall 	    printoption(">RCVD", wont, c, hisopts[c]);
206630088Sminshall 	    if (c == TELOPT_TM) {
206730088Sminshall 		if (flushout) {
206830088Sminshall 		    flushout = 0;
206930088Sminshall 		}
207030088Sminshall 	    } else if (hisopts[c]) {
207130088Sminshall 		wontoption(c, 1);
207230088Sminshall 	    }
207330088Sminshall 	    SetIn3270();
207430722Sminshall 	    telrcv_state = TS_DATA;
207530088Sminshall 	    continue;
207630088Sminshall 
207730088Sminshall 	case TS_DO:
207830088Sminshall 	    printoption(">RCVD", doopt, c, !myopts[c]);
207930088Sminshall 	    if (!myopts[c])
208030088Sminshall 		dooption(c);
208130088Sminshall 	    SetIn3270();
208230722Sminshall 	    telrcv_state = TS_DATA;
208330088Sminshall 	    continue;
208430088Sminshall 
208530088Sminshall 	case TS_DONT:
208630088Sminshall 	    printoption(">RCVD", dont, c, myopts[c]);
208730088Sminshall 	    if (myopts[c]) {
208830088Sminshall 		myopts[c] = 0;
208930088Sminshall 		sprintf(nfrontp, wont, c);
209030088Sminshall 		nfrontp += sizeof (wont) - 2;
209130088Sminshall 		flushline = 1;
209230088Sminshall 		setconnmode();	/* set new tty mode (maybe) */
209330088Sminshall 		printoption(">SENT", wont, c, 0);
209430088Sminshall 	    }
209530088Sminshall 	    SetIn3270();
209630722Sminshall 	    telrcv_state = TS_DATA;
209730088Sminshall 	    continue;
209830088Sminshall 
209930088Sminshall 	case TS_SB:
210030088Sminshall 	    if (c == IAC) {
210130722Sminshall 		telrcv_state = TS_SE;
210230088Sminshall 	    } else {
210330088Sminshall 		SB_ACCUM(c);
210430088Sminshall 	    }
210530088Sminshall 	    continue;
210630088Sminshall 
210730088Sminshall 	case TS_SE:
210830088Sminshall 	    if (c != SE) {
210930088Sminshall 		if (c != IAC) {
211030088Sminshall 		    SB_ACCUM(IAC);
211130088Sminshall 		}
211230088Sminshall 		SB_ACCUM(c);
211330722Sminshall 		telrcv_state = TS_SB;
211430088Sminshall 	    } else {
211530088Sminshall 		SB_TERM();
211630088Sminshall 		suboption();	/* handle sub-option */
211730088Sminshall 		SetIn3270();
211830722Sminshall 		telrcv_state = TS_DATA;
211930088Sminshall 	    }
212030088Sminshall 	}
212130088Sminshall     }
212230088Sminshall }
212330088Sminshall 
212430088Sminshall #if	defined(TN3270)
212530088Sminshall 
212630088Sminshall /*
212730088Sminshall  * The following routines are places where the various tn3270
212830088Sminshall  * routines make calls into telnet.c.
212930088Sminshall  */
213030088Sminshall 
213130088Sminshall /* TtyChars() - returns the number of characters in the TTY buffer */
213230088Sminshall TtyChars()
213330088Sminshall {
213430088Sminshall     return(tfrontp-tbackp);
213530088Sminshall }
213630088Sminshall 
213730088Sminshall /*
213830088Sminshall  * DataToNetwork - queue up some data to go to network.  If "done" is set,
213930088Sminshall  * then when last byte is queued, we add on an IAC EOR sequence (so,
214030088Sminshall  * don't call us with "done" until you want that done...)
214130088Sminshall  *
214230088Sminshall  * We actually do send all the data to the network buffer, since our
214330088Sminshall  * only client needs for us to do that.
214430088Sminshall  */
214530088Sminshall 
214630088Sminshall int
214730088Sminshall DataToNetwork(buffer, count, done)
214830088Sminshall register char	*buffer;	/* where the data is */
214930088Sminshall register int	count;		/* how much to send */
215030088Sminshall int		done;		/* is this the last of a logical block */
215130088Sminshall {
215230088Sminshall     register int c;
215330088Sminshall     int origCount;
215430088Sminshall     fd_set o;
215530088Sminshall 
215630088Sminshall     origCount = count;
215730088Sminshall     FD_ZERO(&o);
215830088Sminshall 
215930088Sminshall     while (count) {
216030088Sminshall 	if ((netobuf+sizeof netobuf - nfrontp) < 6) {
216130088Sminshall 	    netflush();
216230088Sminshall 	    while ((netobuf+sizeof netobuf - nfrontp) < 6) {
216330088Sminshall 		FD_SET(net, &o);
216430088Sminshall 		(void) select(net+1, (fd_set *) 0, &o, (fd_set *) 0,
216530088Sminshall 						(struct timeval *) 0);
216630088Sminshall 		netflush();
216730088Sminshall 	    }
216830088Sminshall 	}
216930088Sminshall 	c = *buffer++;
217030088Sminshall 	count--;
217130088Sminshall 	if (c == IAC) {
217230088Sminshall 	    *nfrontp++ = IAC;
217330088Sminshall 	    *nfrontp++ = IAC;
217430088Sminshall 	} else {
217530088Sminshall 	    *nfrontp++ = c;
217630088Sminshall 	}
217730088Sminshall     }
217830088Sminshall 
217930088Sminshall     if (done && !count) {
218030088Sminshall 	*nfrontp++ = IAC;
218130088Sminshall 	*nfrontp++ = EOR;
218230088Sminshall 	netflush();		/* try to move along as quickly as ... */
218330088Sminshall     }
218430088Sminshall     return(origCount - count);
218530088Sminshall }
218630088Sminshall 
218730088Sminshall /* DataToTerminal - queue up some data to go to terminal. */
218830088Sminshall 
218930088Sminshall int
219030088Sminshall DataToTerminal(buffer, count)
219130088Sminshall register char	*buffer;		/* where the data is */
219230088Sminshall register int	count;			/* how much to send */
219330088Sminshall {
219430088Sminshall     int origCount;
2195*31131Sminshall #if	defined(unix)
219630088Sminshall     fd_set	o;
219730088Sminshall 
2198*31131Sminshall     FD_ZERO(&o);
2199*31131Sminshall #endif	/* defined(unix) */
220030088Sminshall     origCount = count;
220130088Sminshall 
220230088Sminshall     while (count) {
220330088Sminshall 	if (tfrontp >= ttyobuf+sizeof ttyobuf) {
220430088Sminshall 	    ttyflush();
220530088Sminshall 	    while (tfrontp >= ttyobuf+sizeof ttyobuf) {
2206*31131Sminshall #if	defined(unix)
220730088Sminshall 		FD_SET(tout, &o);
220830088Sminshall 		(void) select(tout+1, (fd_set *) 0, &o, (fd_set *) 0,
220930088Sminshall 						(struct timeval *) 0);
2210*31131Sminshall #endif	/* defined(unix) */
221130088Sminshall 		ttyflush();
221230088Sminshall 	    }
221330088Sminshall 	}
221430088Sminshall 	*tfrontp++ = *buffer++;
221530088Sminshall 	count--;
221630088Sminshall     }
221730088Sminshall     return(origCount - count);
221830088Sminshall }
221930088Sminshall 
222030088Sminshall /* EmptyTerminal - called to make sure that the terminal buffer is empty.
222130088Sminshall  *			Note that we consider the buffer to run all the
222230088Sminshall  *			way to the kernel (thus the select).
222330088Sminshall  */
222430088Sminshall 
222530088Sminshall void
222630088Sminshall EmptyTerminal()
222730088Sminshall {
2228*31131Sminshall #if	defined(unix)
222930088Sminshall     fd_set	o;
223030088Sminshall 
223130088Sminshall     FD_ZERO(&o);
2232*31131Sminshall #endif	/* defined(unix) */
223330088Sminshall 
223430088Sminshall     if (tfrontp == tbackp) {
2235*31131Sminshall #if	defined(unix)
223630088Sminshall 	FD_SET(tout, &o);
223730088Sminshall 	(void) select(tout+1, (int *) 0, &o, (int *) 0,
223830088Sminshall 			(struct timeval *) 0);	/* wait for TTLOWAT */
2239*31131Sminshall #endif	/* defined(unix) */
224030088Sminshall     } else {
224130088Sminshall 	while (tfrontp != tbackp) {
224230088Sminshall 	    ttyflush();
2243*31131Sminshall #if	defined(unix)
224430088Sminshall 	    FD_SET(tout, &o);
224530088Sminshall 	    (void) select(tout+1, (int *) 0, &o, (int *) 0,
224630088Sminshall 				(struct timeval *) 0);	/* wait for TTLOWAT */
2247*31131Sminshall #endif	/* defined(unix) */
224830088Sminshall 	}
224930088Sminshall     }
225030088Sminshall }
225130088Sminshall 
225230088Sminshall /*
225330088Sminshall  * Push3270 - Try to send data along the 3270 output (to screen) direction.
225430088Sminshall  */
225530088Sminshall 
225630088Sminshall static int
225730088Sminshall Push3270()
225830088Sminshall {
225930088Sminshall     int save = scc;
226030088Sminshall 
226130088Sminshall     if (scc) {
226230088Sminshall 	if (Ifrontp+scc > Ibuf+sizeof Ibuf) {
226330088Sminshall 	    if (Ibackp != Ibuf) {
2264*31131Sminshall 		memcpy(Ibuf, Ibackp, Ifrontp-Ibackp);
226530088Sminshall 		Ifrontp -= (Ibackp-Ibuf);
226630088Sminshall 		Ibackp = Ibuf;
226730088Sminshall 	    }
226830088Sminshall 	}
226930088Sminshall 	if (Ifrontp+scc < Ibuf+sizeof Ibuf) {
227030088Sminshall 	    telrcv();
227130088Sminshall 	}
227230088Sminshall     }
227330088Sminshall     return save != scc;
227430088Sminshall }
227530088Sminshall 
227630088Sminshall 
227730088Sminshall /*
227830088Sminshall  * Finish3270 - get the last dregs of 3270 data out to the terminal
227930088Sminshall  *		before quitting.
228030088Sminshall  */
228130088Sminshall 
228230088Sminshall static void
228330088Sminshall Finish3270()
228430088Sminshall {
228530088Sminshall     while (Push3270() || !DoTerminalOutput()) {
228630088Sminshall 	;
228730088Sminshall     }
228830088Sminshall }
228930088Sminshall 
229030088Sminshall 
229130088Sminshall 
229230088Sminshall /* StringToTerminal - output a null terminated string to the terminal */
229330088Sminshall 
229430088Sminshall void
229530088Sminshall StringToTerminal(s)
229630088Sminshall char *s;
229730088Sminshall {
229830088Sminshall     int count;
229930088Sminshall 
230030088Sminshall     count = strlen(s);
230130088Sminshall     if (count) {
230230088Sminshall 	(void) DataToTerminal(s, count);	/* we know it always goes... */
230330088Sminshall     }
230430088Sminshall }
230530088Sminshall 
230630088Sminshall 
230730088Sminshall #if	defined(TN3270) && ((!defined(NOT43)) || defined(PUTCHAR))
230830088Sminshall /* _putchar - output a single character to the terminal.  This name is so that
230930088Sminshall  *	curses(3x) can call us to send out data.
231030088Sminshall  */
231130088Sminshall 
231230088Sminshall void
231330088Sminshall _putchar(c)
231430088Sminshall char c;
231530088Sminshall {
231630088Sminshall     if (tfrontp >= ttyobuf+sizeof ttyobuf) {
231730088Sminshall 	(void) DataToTerminal(&c, 1);
231830088Sminshall     } else {
231930088Sminshall 	*tfrontp++ = c;		/* optimize if possible. */
232030088Sminshall     }
232130088Sminshall }
232230088Sminshall #endif	/* defined(TN3270) && ((!defined(NOT43)) || defined(PUTCHAR)) */
232330088Sminshall 
232430088Sminshall static void
232530088Sminshall SetForExit()
232630088Sminshall {
232730088Sminshall     setconnmode();
232830088Sminshall     if (In3270) {
232930088Sminshall 	Finish3270();
233030088Sminshall     }
233130088Sminshall     setcommandmode();
233230088Sminshall     fflush(stdout);
233330088Sminshall     fflush(stderr);
233430088Sminshall     if (In3270) {
233530088Sminshall 	StopScreen(1);
233630088Sminshall     }
233730088Sminshall     setconnmode();
233830088Sminshall     setcommandmode();
233930088Sminshall }
234030088Sminshall 
234130088Sminshall static void
234230088Sminshall Exit(returnCode)
234330088Sminshall int returnCode;
234430088Sminshall {
234530088Sminshall     SetForExit();
234630088Sminshall     exit(returnCode);
234730088Sminshall }
234830088Sminshall 
234930088Sminshall void
235030088Sminshall ExitString(file, string, returnCode)
235130088Sminshall FILE *file;
235230088Sminshall char *string;
235330088Sminshall int returnCode;
235430088Sminshall {
235530088Sminshall     SetForExit();
235630088Sminshall     fwrite(string, 1, strlen(string), file);
235730088Sminshall     exit(returnCode);
235830088Sminshall }
235930088Sminshall 
236030088Sminshall void
236130088Sminshall ExitPerror(string, returnCode)
236230088Sminshall char *string;
236330088Sminshall int returnCode;
236430088Sminshall {
236530088Sminshall     SetForExit();
236630088Sminshall     perror(string);
236730088Sminshall     exit(returnCode);
236830088Sminshall }
236930088Sminshall 
237030088Sminshall #endif	/* defined(TN3270) */
237130088Sminshall 
237230088Sminshall static
237330088Sminshall Scheduler(block)
237430088Sminshall int	block;			/* should we block in the select ? */
237530088Sminshall {
237630088Sminshall     register int c;
237730088Sminshall 		/* One wants to be a bit careful about setting returnValue
237830088Sminshall 		 * to one, since a one implies we did some useful work,
237930088Sminshall 		 * and therefore probably won't be called to block next
238030088Sminshall 		 * time (TN3270 mode only).
238130088Sminshall 		 */
238230088Sminshall     int returnValue = 0;
238330088Sminshall     static struct timeval TimeValue = { 0 };
238430088Sminshall 
238530088Sminshall     if (scc < 0 && tcc < 0) {
238630088Sminshall 	return -1;
238730088Sminshall     }
238830088Sminshall 
238930088Sminshall     if ((!MODE_LINE(globalmode) || flushline) && NETBYTES()) {
239030088Sminshall 	FD_SET(net, &obits);
239130088Sminshall     }
2392*31131Sminshall #if	!defined(MSDOS)
239330088Sminshall     if (TTYBYTES()) {
239430088Sminshall 	FD_SET(tout, &obits);
239530088Sminshall     }
239630088Sminshall     if ((tcc == 0) && NETROOM()) {
239730088Sminshall 	FD_SET(tin, &ibits);
239830088Sminshall     }
2399*31131Sminshall #endif	/* !defined(MSDOS) */
240030088Sminshall #   if !defined(TN3270)
240130088Sminshall     if (TTYROOM()) {
240230088Sminshall 	FD_SET(net, &ibits);
240330088Sminshall     }
240430088Sminshall #   else /* !defined(TN3270) */
240530088Sminshall     if (!ISend && TTYROOM()) {
240630088Sminshall 	FD_SET(net, &ibits);
240730088Sminshall     }
240830088Sminshall #   endif /* !defined(TN3270) */
240930088Sminshall     if (!SYNCHing) {
241030088Sminshall 	FD_SET(net, &xbits);
241130088Sminshall     }
241230088Sminshall #   if defined(TN3270) && defined(unix)
241330088Sminshall     if (HaveInput) {
241430088Sminshall 	HaveInput = 0;
241530088Sminshall 	signal(SIGIO, inputAvailable);
241630088Sminshall     }
241730088Sminshall #endif	/* defined(TN3270) && defined(unix) */
241830088Sminshall     if ((c = select(16, &ibits, &obits, &xbits,
2419*31131Sminshall 			block? (struct timeval *)0 : &TimeValue)) < 0) {
242030088Sminshall 	if (c == -1) {
242130088Sminshall 		    /*
242230088Sminshall 		     * we can get EINTR if we are in line mode,
242330088Sminshall 		     * and the user does an escape (TSTP), or
242430088Sminshall 		     * some other signal generator.
242530088Sminshall 		     */
242630088Sminshall 	    if (errno == EINTR) {
242730088Sminshall 		return 0;
242830088Sminshall 	    }
242930088Sminshall #	    if defined(TN3270)
243030088Sminshall 		    /*
243130088Sminshall 		     * we can get EBADF if we were in transparent
243230088Sminshall 		     * mode, and the transcom process died.
243330088Sminshall 		    */
243430088Sminshall 	    if (errno == EBADF) {
243530088Sminshall 			/*
243630088Sminshall 			 * zero the bits (even though kernel does it)
243730088Sminshall 			 * to make sure we are selecting on the right
243830088Sminshall 			 * ones.
243930088Sminshall 			*/
244030088Sminshall 		FD_ZERO(&ibits);
244130088Sminshall 		FD_ZERO(&obits);
244230088Sminshall 		FD_ZERO(&xbits);
244330088Sminshall 		return 0;
244430088Sminshall 	    }
244530088Sminshall #	    endif /* defined(TN3270) */
244630088Sminshall 		    /* I don't like this, does it ever happen? */
244730088Sminshall 	    printf("sleep(5) from telnet, after select\r\n");
244830088Sminshall #if	defined(unix)
244930088Sminshall 	    sleep(5);
245030088Sminshall #endif	/* defined(unix) */
245130088Sminshall 	}
245230088Sminshall 	return 0;
245330088Sminshall     }
245430088Sminshall 
245530088Sminshall     /*
245630088Sminshall      * Any urgent data?
245730088Sminshall      */
245830088Sminshall     if (FD_ISSET(net, &xbits)) {
245930088Sminshall 	FD_CLR(net, &xbits);
246030088Sminshall 	SYNCHing = 1;
246130088Sminshall 	ttyflush();	/* flush already enqueued data */
246230088Sminshall     }
246330088Sminshall 
246430088Sminshall     /*
246530088Sminshall      * Something to read from the network...
246630088Sminshall      */
246730088Sminshall     if (FD_ISSET(net, &ibits)) {
246830088Sminshall 	int canread;
246930088Sminshall 
247030088Sminshall 	FD_CLR(net, &ibits);
247130088Sminshall 	if (scc == 0) {
247230088Sminshall 	    sbp = sibuf;
247330088Sminshall 	}
247430422Sminshall 	canread = sibuf + sizeof sibuf - (sbp+scc);
247530088Sminshall #if	!defined(SO_OOBINLINE)
247630088Sminshall 	    /*
247730088Sminshall 	     * In 4.2 (and some early 4.3) systems, the
247830088Sminshall 	     * OOB indication and data handling in the kernel
247930088Sminshall 	     * is such that if two separate TCP Urgent requests
248030088Sminshall 	     * come in, one byte of TCP data will be overlaid.
248130088Sminshall 	     * This is fatal for Telnet, but we try to live
248230088Sminshall 	     * with it.
248330088Sminshall 	     *
248430088Sminshall 	     * In addition, in 4.2 (and...), a special protocol
248530088Sminshall 	     * is needed to pick up the TCP Urgent data in
248630088Sminshall 	     * the correct sequence.
248730088Sminshall 	     *
248830088Sminshall 	     * What we do is:  if we think we are in urgent
248930088Sminshall 	     * mode, we look to see if we are "at the mark".
249030088Sminshall 	     * If we are, we do an OOB receive.  If we run
249130088Sminshall 	     * this twice, we will do the OOB receive twice,
249230088Sminshall 	     * but the second will fail, since the second
249330088Sminshall 	     * time we were "at the mark", but there wasn't
249430088Sminshall 	     * any data there (the kernel doesn't reset
249530088Sminshall 	     * "at the mark" until we do a normal read).
249630088Sminshall 	     * Once we've read the OOB data, we go ahead
249730088Sminshall 	     * and do normal reads.
249830088Sminshall 	     *
249930088Sminshall 	     * There is also another problem, which is that
250030088Sminshall 	     * since the OOB byte we read doesn't put us
250130088Sminshall 	     * out of OOB state, and since that byte is most
250230088Sminshall 	     * likely the TELNET DM (data mark), we would
250330088Sminshall 	     * stay in the TELNET SYNCH (SYNCHing) state.
250430088Sminshall 	     * So, clocks to the rescue.  If we've "just"
250530088Sminshall 	     * received a DM, then we test for the
250630088Sminshall 	     * presence of OOB data when the receive OOB
250730088Sminshall 	     * fails (and AFTER we did the normal mode read
250830088Sminshall 	     * to clear "at the mark").
250930088Sminshall 	     */
251030088Sminshall 	if (SYNCHing) {
251130088Sminshall 	    int atmark;
251230088Sminshall 
251330088Sminshall 	    ioctl(net, SIOCATMARK, (char *)&atmark);
251430088Sminshall 	    if (atmark) {
251530422Sminshall 		c = recv(net, sbp+scc, canread, MSG_OOB);
251630088Sminshall 		if ((c == -1) && (errno == EINVAL)) {
2517*31131Sminshall 		    c = recv(net, sbp+scc, canread, 0);
251830088Sminshall 		    if (clocks.didnetreceive < clocks.gotDM) {
251930088Sminshall 			SYNCHing = stilloob(net);
252030088Sminshall 		    }
252130088Sminshall 		}
252230088Sminshall 	    } else {
2523*31131Sminshall 		c = recv(net, sbp+scc, canread, 0);
252430088Sminshall 	    }
252530088Sminshall 	} else {
2526*31131Sminshall 	    c = recv(net, sbp+scc, canread, 0);
252730088Sminshall 	}
252830088Sminshall 	settimer(didnetreceive);
252930088Sminshall #else	/* !defined(SO_OOBINLINE) */
2530*31131Sminshall 	c = recv(net, sbp+scc, canread, 0);
253130088Sminshall #endif	/* !defined(SO_OOBINLINE) */
253230088Sminshall 	if (c < 0 && errno == EWOULDBLOCK) {
253330088Sminshall 	    c = 0;
253430088Sminshall 	} else if (c <= 0) {
253530088Sminshall 	    return -1;
253630088Sminshall 	}
253730088Sminshall 	if (netdata) {
253830422Sminshall 	    Dump('<', sbp+scc, c);
253930088Sminshall 	}
254030088Sminshall 	scc += c;
254130088Sminshall 	returnValue = 1;
254230088Sminshall     }
254330088Sminshall 
254430088Sminshall     /*
254530088Sminshall      * Something to read from the tty...
254630088Sminshall      */
2547*31131Sminshall #if	defined(MSDOS)
2548*31131Sminshall     if ((tcc == 0) && NETROOM() && TerminalCanRead())
2549*31131Sminshall #else	/* defined(MSDOS) */
2550*31131Sminshall     if (FD_ISSET(tin, &ibits))
2551*31131Sminshall #endif	/* defined(MSDOS) */
2552*31131Sminshall 				    {
255330088Sminshall 	FD_CLR(tin, &ibits);
255430088Sminshall 	if (tcc == 0) {
255530088Sminshall 	    tbp = tibuf;	/* nothing left, reset */
255630088Sminshall 	}
2557*31131Sminshall 	c = TerminalRead(tin, tbp, tibuf+sizeof tibuf - tbp);
255830088Sminshall 	if (c < 0 && errno == EWOULDBLOCK) {
255930088Sminshall 	    c = 0;
256030088Sminshall 	} else {
256131124Sminshall #if	defined(unix)
256230088Sminshall 	    /* EOF detection for line mode!!!! */
256330088Sminshall 	    if (c == 0 && MODE_LOCAL_CHARS(globalmode)) {
256430088Sminshall 			/* must be an EOF... */
256530088Sminshall 		*tbp = ntc.t_eofc;
256630088Sminshall 		c = 1;
256730088Sminshall 	    }
256831124Sminshall #endif	/* defined(unix) */
256930088Sminshall 	    if (c <= 0) {
257030088Sminshall 		tcc = c;
257130088Sminshall 		return -1;
257230088Sminshall 	    }
257330088Sminshall 	}
257430088Sminshall 	tcc += c;
257530088Sminshall 	returnValue = 1;		/* did something useful */
257630088Sminshall     }
257730088Sminshall 
257830088Sminshall #   if defined(TN3270)
257930088Sminshall     if (tcc > 0) {
258030088Sminshall 	if (In3270) {
258130088Sminshall 	    c = DataFromTerminal(tbp, tcc);
258230088Sminshall 	    if (c) {
258330088Sminshall 		returnValue = 1;
258430088Sminshall 	    }
258530088Sminshall 	    tcc -= c;
258630088Sminshall 	    tbp += c;
258730088Sminshall 	} else {
258830320Sminshall #   endif /* defined(TN3270) */
258930088Sminshall 	    returnValue = 1;
259030088Sminshall 	    while (tcc > 0) {
259130088Sminshall 		register int sc;
259230088Sminshall 
259330088Sminshall 		if (NETROOM() < 2) {
259430088Sminshall 		    flushline = 1;
259530088Sminshall 		    break;
259630088Sminshall 		}
259730088Sminshall 		c = *tbp++ & 0xff, sc = strip(c), tcc--;
259830088Sminshall 		if (sc == escape) {
259930088Sminshall 		    command(0);
260030088Sminshall 		    tcc = 0;
260130088Sminshall 		    flushline = 1;
260230088Sminshall 		    break;
260330088Sminshall 		} else if (MODE_LINE(globalmode) && (sc == echoc)) {
260430088Sminshall 		    if (tcc > 0 && strip(*tbp) == echoc) {
260530088Sminshall 			tbp++;
260630088Sminshall 			tcc--;
260730088Sminshall 		    } else {
260830088Sminshall 			dontlecho = !dontlecho;
260930088Sminshall 			settimer(echotoggle);
261030088Sminshall 			setconnmode();
261130088Sminshall 			tcc = 0;
261230088Sminshall 			flushline = 1;
261330088Sminshall 			break;
261430088Sminshall 		    }
261530088Sminshall 		}
261630088Sminshall 		if (localchars) {
2617*31131Sminshall 		    if (TerminalSpecialChars(sc) == 0) {
261830088Sminshall 			break;
261930088Sminshall 		    }
262030088Sminshall 		}
262130088Sminshall 		switch (c) {
262230088Sminshall 		case '\n':
262330088Sminshall 			/*
262430088Sminshall 			 * If we are in CRMOD mode (\r ==> \n)
262530088Sminshall 			 * on our local machine, then probably
262630088Sminshall 			 * a newline (unix) is CRLF (TELNET).
262730088Sminshall 			 */
262830088Sminshall 		    if (MODE_LOCAL_CHARS(globalmode)) {
262930088Sminshall 			NETADD('\r');
263030088Sminshall 		    }
263130088Sminshall 		    NETADD('\n');
263230088Sminshall 		    flushline = 1;
263330088Sminshall 		    break;
263430088Sminshall 		case '\r':
263530088Sminshall 		    NET2ADD('\r', '\0');
263630088Sminshall 		    flushline = 1;
263730088Sminshall 		    break;
263830088Sminshall 		case IAC:
263930088Sminshall 		    NET2ADD(IAC, IAC);
264030088Sminshall 		    break;
264130088Sminshall 		default:
264230088Sminshall 		    NETADD(c);
264330088Sminshall 		    break;
264430088Sminshall 		}
264530088Sminshall 	    }
264630088Sminshall #   if defined(TN3270)
264730088Sminshall 	}
264830088Sminshall     }
264930088Sminshall #   endif /* defined(TN3270) */
265030088Sminshall 
265130088Sminshall     if ((!MODE_LINE(globalmode) || flushline) &&
265230088Sminshall 	FD_ISSET(net, &obits) && (NETBYTES() > 0)) {
265330088Sminshall 	FD_CLR(net, &obits);
265430088Sminshall 	returnValue = netflush();
265530088Sminshall     }
265630088Sminshall     if (scc > 0) {
265730088Sminshall #	if !defined(TN3270)
265830088Sminshall 	telrcv();
265930088Sminshall 	returnValue = 1;
266030088Sminshall #	else /* !defined(TN3270) */
266130088Sminshall 	returnValue = Push3270();
266230088Sminshall #	endif /* !defined(TN3270) */
266330088Sminshall     }
2664*31131Sminshall #if	defined(MSDOS)
2665*31131Sminshall     if (TTYBYTES())
2666*31131Sminshall #else	/* defined(MSDOS) */
2667*31131Sminshall     if (FD_ISSET(tout, &obits) && (TTYBYTES() > 0))
2668*31131Sminshall #endif	/* defined(MSDOS) */
2669*31131Sminshall 						    {
267030088Sminshall 	FD_CLR(tout, &obits);
267130088Sminshall 	returnValue = ttyflush();
267230088Sminshall     }
267330088Sminshall     return returnValue;
267430088Sminshall }
267530088Sminshall 
267630088Sminshall /*
267730088Sminshall  * Select from tty and network...
267830088Sminshall  */
267930088Sminshall static void
268030088Sminshall telnet()
268130088Sminshall {
2682*31131Sminshall #if	defined(MSDOS)
2683*31131Sminshall #define	SCHED_BLOCK	0		/* Don't block in MSDOS */
2684*31131Sminshall #else	/* defined(MSDOS) */
2685*31131Sminshall #define	SCHED_BLOCK	1
2686*31131Sminshall #endif	/* defined(MSDOS) */
2687*31131Sminshall 
268830088Sminshall #if	defined(TN3270) && defined(unix)
268930088Sminshall     int myPid;
269030088Sminshall #endif	/* defined(TN3270) */
269130088Sminshall 
269230088Sminshall     tout = fileno(stdout);
269330088Sminshall     tin = fileno(stdin);
269430088Sminshall     setconnmode();
269530088Sminshall     scc = 0;
269630088Sminshall     tcc = 0;
269730088Sminshall     FD_ZERO(&ibits);
269830088Sminshall     FD_ZERO(&obits);
269930088Sminshall     FD_ZERO(&xbits);
270030088Sminshall 
270131124Sminshall     NetNonblockingIO(net, 1);
270230088Sminshall 
270330088Sminshall #if	defined(TN3270)
270430088Sminshall #if	!defined(DEBUG)		/* DBX can't handle! */
270531124Sminshall     NetSigIO(net, 1);
270630088Sminshall #endif	/* !defined(DEBUG) */
270730088Sminshall 
270831124Sminshall     NetSetPgrp(net);
270930088Sminshall #endif	/* defined(TN3270) */
271030088Sminshall 
271130088Sminshall 
271231124Sminshall #if	defined(SO_OOBINLINE) && !defined(MSDOS)
271331124Sminshall     SetSockOpt(net, SOL_SOCKET, SO_OOBINLINE, 1);
271431124Sminshall #endif	/* defined(SO_OOBINLINE) && !defined(MSDOS) */
271531124Sminshall 
271630320Sminshall #   if !defined(TN3270)
271730088Sminshall     if (telnetport) {
271830088Sminshall 	if (!hisopts[TELOPT_SGA]) {
271930088Sminshall 	    willoption(TELOPT_SGA, 0);
272030088Sminshall 	}
272130088Sminshall 	if (!myopts[TELOPT_TTYPE]) {
272230088Sminshall 	    dooption(TELOPT_TTYPE, 0);
272330088Sminshall 	}
272430088Sminshall     }
272530320Sminshall #   endif /* !defined(TN3270) */
272630088Sminshall 
272730088Sminshall #   if !defined(TN3270)
272830088Sminshall     for (;;) {
2729*31131Sminshall 	if (Scheduler(SCHED_BLOCK) == -1) {
273030088Sminshall 	    setcommandmode();
273130088Sminshall 	    return;
273230088Sminshall 	}
273330088Sminshall     }
273430088Sminshall #   else /* !defined(TN3270) */
273530088Sminshall     for (;;) {
273630088Sminshall 	int schedValue;
273730088Sminshall 
273830088Sminshall 	while (!In3270) {
2739*31131Sminshall 	    if (Scheduler(SCHED_BLOCK) == -1) {
274030088Sminshall 		setcommandmode();
274130088Sminshall 		return;
274230088Sminshall 	    }
274330088Sminshall 	}
274430088Sminshall 
274530088Sminshall 	while ((schedValue = Scheduler(0)) != 0) {
274630088Sminshall 	    if (schedValue == -1) {
274730088Sminshall 		setcommandmode();
274830088Sminshall 		return;
274930088Sminshall 	    }
275030088Sminshall 	}
275130088Sminshall 		/* If there is data waiting to go out to terminal, don't
275230088Sminshall 		 * schedule any more data for the terminal.
275330088Sminshall 		 */
275430088Sminshall 	if (tfrontp-tbackp) {
275530088Sminshall 	    schedValue = 1;
275630088Sminshall 	} else {
275730088Sminshall 	    schedValue = DoTerminalOutput();
275830088Sminshall 	}
275930088Sminshall 	if (schedValue) {
2760*31131Sminshall 	    if (Scheduler(SCHED_BLOCK) == -1) {
276130088Sminshall 		setcommandmode();
276230088Sminshall 		return;
276330088Sminshall 	    }
276430088Sminshall 	}
276530088Sminshall     }
276630088Sminshall #   endif /* !defined(TN3270) */
276730088Sminshall }
276830088Sminshall 
276930088Sminshall /*
277030088Sminshall  *	The following are data structures and routines for
277130088Sminshall  *	the "send" command.
277230088Sminshall  *
277330088Sminshall  */
277430088Sminshall 
277530088Sminshall struct sendlist {
277630088Sminshall     char	*name;		/* How user refers to it (case independent) */
277730088Sminshall     int		what;		/* Character to be sent (<0 ==> special) */
277830088Sminshall     char	*help;		/* Help information (0 ==> no help) */
277930088Sminshall #if	defined(NOT43)
278030088Sminshall     int		(*routine)();	/* Routine to perform (for special ops) */
278130088Sminshall #else	/* defined(NOT43) */
278230088Sminshall     void	(*routine)();	/* Routine to perform (for special ops) */
278330088Sminshall #endif	/* defined(NOT43) */
278430088Sminshall };
278530088Sminshall 
278630088Sminshall #define	SENDQUESTION	-1
278730088Sminshall #define	SENDESCAPE	-3
278830088Sminshall 
278930088Sminshall static struct sendlist Sendlist[] = {
279030088Sminshall     { "ao", AO, "Send Telnet Abort output" },
279130088Sminshall     { "ayt", AYT, "Send Telnet 'Are You There'" },
279230088Sminshall     { "brk", BREAK, "Send Telnet Break" },
279330088Sminshall     { "ec", EC, "Send Telnet Erase Character" },
279430088Sminshall     { "el", EL, "Send Telnet Erase Line" },
279530088Sminshall     { "escape", SENDESCAPE, "Send current escape character" },
279630088Sminshall     { "ga", GA, "Send Telnet 'Go Ahead' sequence" },
279730088Sminshall     { "ip", IP, "Send Telnet Interrupt Process" },
279830088Sminshall     { "nop", NOP, "Send Telnet 'No operation'" },
279930088Sminshall     { "synch", SYNCH, "Perform Telnet 'Synch operation'", dosynch },
280030088Sminshall     { "?", SENDQUESTION, "Display send options" },
280130088Sminshall     { 0 }
280230088Sminshall };
280330088Sminshall 
280430088Sminshall static struct sendlist Sendlist2[] = {		/* some synonyms */
280530088Sminshall 	{ "break", BREAK, 0 },
280630088Sminshall 
280730088Sminshall 	{ "intp", IP, 0 },
280830088Sminshall 	{ "interrupt", IP, 0 },
280930088Sminshall 	{ "intr", IP, 0 },
281030088Sminshall 
281130088Sminshall 	{ "help", SENDQUESTION, 0 },
281230088Sminshall 
281330088Sminshall 	{ 0 }
281430088Sminshall };
281530088Sminshall 
281630088Sminshall static char **
281730088Sminshall getnextsend(name)
281830088Sminshall char *name;
281930088Sminshall {
282030088Sminshall     struct sendlist *c = (struct sendlist *) name;
282130088Sminshall 
282230088Sminshall     return (char **) (c+1);
282330088Sminshall }
282430088Sminshall 
282530088Sminshall static struct sendlist *
282630088Sminshall getsend(name)
282730088Sminshall char *name;
282830088Sminshall {
282930088Sminshall     struct sendlist *sl;
283030088Sminshall 
283130088Sminshall     if ((sl = (struct sendlist *)
283230088Sminshall 			genget(name, (char **) Sendlist, getnextsend)) != 0) {
283330088Sminshall 	return sl;
283430088Sminshall     } else {
283530088Sminshall 	return (struct sendlist *)
283630088Sminshall 				genget(name, (char **) Sendlist2, getnextsend);
283730088Sminshall     }
283830088Sminshall }
283930088Sminshall 
284030088Sminshall static
284130088Sminshall sendcmd(argc, argv)
284230088Sminshall int	argc;
284330088Sminshall char	**argv;
284430088Sminshall {
284530088Sminshall     int what;		/* what we are sending this time */
284630088Sminshall     int count;		/* how many bytes we are going to need to send */
284730088Sminshall     int i;
284830088Sminshall     int question = 0;	/* was at least one argument a question */
284930088Sminshall     struct sendlist *s;	/* pointer to current command */
285030088Sminshall 
285130088Sminshall     if (argc < 2) {
285230088Sminshall 	printf("need at least one argument for 'send' command\n");
285330088Sminshall 	printf("'send ?' for help\n");
285430088Sminshall 	return 0;
285530088Sminshall     }
285630088Sminshall     /*
285730088Sminshall      * First, validate all the send arguments.
285830088Sminshall      * In addition, we see how much space we are going to need, and
285930088Sminshall      * whether or not we will be doing a "SYNCH" operation (which
286030088Sminshall      * flushes the network queue).
286130088Sminshall      */
286230088Sminshall     count = 0;
286330088Sminshall     for (i = 1; i < argc; i++) {
286430088Sminshall 	s = getsend(argv[i]);
286530088Sminshall 	if (s == 0) {
286630088Sminshall 	    printf("Unknown send argument '%s'\n'send ?' for help.\n",
286730088Sminshall 			argv[i]);
286830088Sminshall 	    return 0;
286930088Sminshall 	} else if (s == Ambiguous(struct sendlist *)) {
287030088Sminshall 	    printf("Ambiguous send argument '%s'\n'send ?' for help.\n",
287130088Sminshall 			argv[i]);
287230088Sminshall 	    return 0;
287330088Sminshall 	}
287430088Sminshall 	switch (s->what) {
287530088Sminshall 	case SENDQUESTION:
287630088Sminshall 	    break;
287730088Sminshall 	case SENDESCAPE:
287830088Sminshall 	    count += 1;
287930088Sminshall 	    break;
288030088Sminshall 	case SYNCH:
288130088Sminshall 	    count += 2;
288230088Sminshall 	    break;
288330088Sminshall 	default:
288430088Sminshall 	    count += 2;
288530088Sminshall 	    break;
288630088Sminshall 	}
288730088Sminshall     }
288830088Sminshall     /* Now, do we have enough room? */
288930088Sminshall     if (NETROOM() < count) {
289030088Sminshall 	printf("There is not enough room in the buffer TO the network\n");
289130088Sminshall 	printf("to process your request.  Nothing will be done.\n");
289230088Sminshall 	printf("('send synch' will throw away most data in the network\n");
289330088Sminshall 	printf("buffer, if this might help.)\n");
289430088Sminshall 	return 0;
289530088Sminshall     }
289630088Sminshall     /* OK, they are all OK, now go through again and actually send */
289730088Sminshall     for (i = 1; i < argc; i++) {
289830088Sminshall 	if ((s = getsend(argv[i])) == 0) {
289930088Sminshall 	    fprintf(stderr, "Telnet 'send' error - argument disappeared!\n");
290030088Sminshall 	    quit();
290130088Sminshall 	    /*NOTREACHED*/
290230088Sminshall 	}
290330088Sminshall 	if (s->routine) {
290430088Sminshall 	    (*s->routine)(s);
290530088Sminshall 	} else {
290630088Sminshall 	    switch (what = s->what) {
290730088Sminshall 	    case SYNCH:
290830088Sminshall 		dosynch();
290930088Sminshall 		break;
291030088Sminshall 	    case SENDQUESTION:
291130088Sminshall 		for (s = Sendlist; s->name; s++) {
291230088Sminshall 		    if (s->help) {
291330088Sminshall 			printf(s->name);
291430088Sminshall 			if (s->help) {
291530088Sminshall 			    printf("\t%s", s->help);
291630088Sminshall 			}
291730088Sminshall 			printf("\n");
291830088Sminshall 		    }
291930088Sminshall 		}
292030088Sminshall 		question = 1;
292130088Sminshall 		break;
292230088Sminshall 	    case SENDESCAPE:
292330088Sminshall 		NETADD(escape);
292430088Sminshall 		break;
292530088Sminshall 	    default:
292630088Sminshall 		NET2ADD(IAC, what);
292730088Sminshall 		break;
292830088Sminshall 	    }
292930088Sminshall 	}
293030088Sminshall     }
293130088Sminshall     return !question;
293230088Sminshall }
293330088Sminshall 
293430088Sminshall /*
293530088Sminshall  * The following are the routines and data structures referred
293630088Sminshall  * to by the arguments to the "toggle" command.
293730088Sminshall  */
293830088Sminshall 
293930088Sminshall static
294030088Sminshall lclchars()
294130088Sminshall {
294230088Sminshall     donelclchars = 1;
294330088Sminshall     return 1;
294430088Sminshall }
294530088Sminshall 
294630088Sminshall static
294730088Sminshall togdebug()
294830088Sminshall {
294930088Sminshall #ifndef	NOT43
295030088Sminshall     if (net > 0 &&
295131124Sminshall 	(SetSockOpt(net, SOL_SOCKET, SO_DEBUG, debug)) < 0) {
295230088Sminshall 	    perror("setsockopt (SO_DEBUG)");
295330088Sminshall     }
295430320Sminshall #else	/* NOT43 */
295530088Sminshall     if (debug) {
295631124Sminshall 	if (net > 0 && SetSockOpt(net, SOL_SOCKET, SO_DEBUG, 0, 0) < 0)
295730088Sminshall 	    perror("setsockopt (SO_DEBUG)");
295830088Sminshall     } else
295930088Sminshall 	printf("Cannot turn off socket debugging\n");
296030320Sminshall #endif	/* NOT43 */
296130088Sminshall     return 1;
296230088Sminshall }
296330088Sminshall 
296430088Sminshall 
296530088Sminshall 
296630088Sminshall extern int togglehelp();
296730088Sminshall 
296830088Sminshall struct togglelist {
296930088Sminshall     char	*name;		/* name of toggle */
297030088Sminshall     char	*help;		/* help message */
297130088Sminshall     int		(*handler)();	/* routine to do actual setting */
297230088Sminshall     int		dohelp;		/* should we display help information */
297330088Sminshall     int		*variable;
297430088Sminshall     char	*actionexplanation;
297530088Sminshall };
297630088Sminshall 
297730088Sminshall static struct togglelist Togglelist[] = {
297830088Sminshall     { "autoflush",
297930088Sminshall 	"toggle flushing of output when sending interrupt characters",
298030088Sminshall 	    0,
298130088Sminshall 		1,
298230088Sminshall 		    &autoflush,
298330088Sminshall 			"flush output when sending interrupt characters" },
298430088Sminshall     { "autosynch",
298530088Sminshall 	"toggle automatic sending of interrupt characters in urgent mode",
298630088Sminshall 	    0,
298730088Sminshall 		1,
298830088Sminshall 		    &autosynch,
298930088Sminshall 			"send interrupt characters in urgent mode" },
299030088Sminshall     { "crmod",
299130088Sminshall 	"toggle mapping of received carriage returns",
299230088Sminshall 	    0,
299330088Sminshall 		1,
299430088Sminshall 		    &crmod,
299530088Sminshall 			"map carriage return on output" },
299630088Sminshall     { "localchars",
299730088Sminshall 	"toggle local recognition of certain control characters",
299830088Sminshall 	    lclchars,
299930088Sminshall 		1,
300030088Sminshall 		    &localchars,
300130088Sminshall 			"recognize certain control characters" },
300230088Sminshall     { " ", "", 0, 1 },		/* empty line */
300330088Sminshall     { "debug",
300430088Sminshall 	"(debugging) toggle debugging",
300530088Sminshall 	    togdebug,
300630088Sminshall 		1,
300730088Sminshall 		    &debug,
300830088Sminshall 			"turn on socket level debugging" },
300930088Sminshall     { "netdata",
301030088Sminshall 	"(debugging) toggle printing of hexadecimal network data",
301130088Sminshall 	    0,
301230088Sminshall 		1,
301330088Sminshall 		    &netdata,
301430088Sminshall 			"print hexadecimal representation of network traffic" },
301530088Sminshall     { "options",
301630088Sminshall 	"(debugging) toggle viewing of options processing",
301730088Sminshall 	    0,
301830088Sminshall 		1,
301930088Sminshall 		    &showoptions,
302030088Sminshall 			"show option processing" },
302130088Sminshall     { " ", "", 0, 1 },		/* empty line */
302230088Sminshall     { "?",
302330088Sminshall 	"display help information",
302430088Sminshall 	    togglehelp,
302530088Sminshall 		1 },
302630088Sminshall     { "help",
302730088Sminshall 	"display help information",
302830088Sminshall 	    togglehelp,
302930088Sminshall 		0 },
303030088Sminshall     { 0 }
303130088Sminshall };
303230088Sminshall 
303330088Sminshall static
303430088Sminshall togglehelp()
303530088Sminshall {
303630088Sminshall     struct togglelist *c;
303730088Sminshall 
303830088Sminshall     for (c = Togglelist; c->name; c++) {
303930088Sminshall 	if (c->dohelp) {
304030088Sminshall 	    printf("%s\t%s\n", c->name, c->help);
304130088Sminshall 	}
304230088Sminshall     }
304330088Sminshall     return 0;
304430088Sminshall }
304530088Sminshall 
304630088Sminshall static char **
304730088Sminshall getnexttoggle(name)
304830088Sminshall char *name;
304930088Sminshall {
305030088Sminshall     struct togglelist *c = (struct togglelist *) name;
305130088Sminshall 
305230088Sminshall     return (char **) (c+1);
305330088Sminshall }
305430088Sminshall 
305530088Sminshall static struct togglelist *
305630088Sminshall gettoggle(name)
305730088Sminshall char *name;
305830088Sminshall {
305930088Sminshall     return (struct togglelist *)
306030088Sminshall 			genget(name, (char **) Togglelist, getnexttoggle);
306130088Sminshall }
306230088Sminshall 
306330088Sminshall static
306430088Sminshall toggle(argc, argv)
306530088Sminshall int	argc;
306630088Sminshall char	*argv[];
306730088Sminshall {
306830088Sminshall     int retval = 1;
306930088Sminshall     char *name;
307030088Sminshall     struct togglelist *c;
307130088Sminshall 
307230088Sminshall     if (argc < 2) {
307330088Sminshall 	fprintf(stderr,
307430088Sminshall 	    "Need an argument to 'toggle' command.  'toggle ?' for help.\n");
307530088Sminshall 	return 0;
307630088Sminshall     }
307730088Sminshall     argc--;
307830088Sminshall     argv++;
307930088Sminshall     while (argc--) {
308030088Sminshall 	name = *argv++;
308130088Sminshall 	c = gettoggle(name);
308230088Sminshall 	if (c == Ambiguous(struct togglelist *)) {
308330088Sminshall 	    fprintf(stderr, "'%s': ambiguous argument ('toggle ?' for help).\n",
308430088Sminshall 					name);
308530088Sminshall 	    return 0;
308630088Sminshall 	} else if (c == 0) {
308730088Sminshall 	    fprintf(stderr, "'%s': unknown argument ('toggle ?' for help).\n",
308830088Sminshall 					name);
308930088Sminshall 	    return 0;
309030088Sminshall 	} else {
309130088Sminshall 	    if (c->variable) {
309230088Sminshall 		*c->variable = !*c->variable;		/* invert it */
309330088Sminshall 		printf("%s %s.\n", *c->variable? "Will" : "Won't",
309430088Sminshall 							c->actionexplanation);
309530088Sminshall 	    }
309630088Sminshall 	    if (c->handler) {
309730088Sminshall 		retval &= (*c->handler)(c);
309830088Sminshall 	    }
309930088Sminshall 	}
310030088Sminshall     }
310130088Sminshall     return retval;
310230088Sminshall }
310330088Sminshall 
310430088Sminshall /*
310530088Sminshall  * The following perform the "set" command.
310630088Sminshall  */
310730088Sminshall 
310830088Sminshall struct setlist {
310930088Sminshall     char *name;				/* name */
311030088Sminshall     char *help;				/* help information */
311130088Sminshall     char *charp;			/* where it is located at */
311230088Sminshall };
311330088Sminshall 
311430088Sminshall static struct setlist Setlist[] = {
311530088Sminshall     { "echo", 	"character to toggle local echoing on/off", &echoc },
311630088Sminshall     { "escape",	"character to escape back to telnet command mode", &escape },
311730088Sminshall     { " ", "" },
311830088Sminshall     { " ", "The following need 'localchars' to be toggled true", 0 },
311931124Sminshall #if	defined(unix)
312030088Sminshall     { "erase",	"character to cause an Erase Character", &nttyb.sg_erase },
312130088Sminshall     { "flushoutput", "character to cause an Abort Oubput", &nltc.t_flushc },
312230088Sminshall     { "interrupt", "character to cause an Interrupt Process", &ntc.t_intrc },
312330088Sminshall     { "kill",	"character to cause an Erase Line", &nttyb.sg_kill },
312430088Sminshall     { "quit",	"character to cause a Break", &ntc.t_quitc },
312530088Sminshall     { "eof",	"character to cause an EOF ", &ntc.t_eofc },
312631124Sminshall #endif	/* defined(unix) */
312731124Sminshall #if	defined(MSDOS)
312831124Sminshall     { "erase",	"character to cause an Erase Character", &termEraseChar },
312931124Sminshall     { "flushoutput", "character to cause an Abort Oubput", &termFlushChar },
313031124Sminshall     { "interrupt", "character to cause an Interrupt Process", &termIntChar },
313131124Sminshall     { "kill",	"character to cause an Erase Line", &termKillChar },
313231124Sminshall     { "quit",	"character to cause a Break", &termQuitChar },
313331124Sminshall     { "eof",	"character to cause an EOF ", &termEofChar },
313431124Sminshall #endif	/* defined(MSDOS) */
313530088Sminshall     { 0 }
313630088Sminshall };
313730088Sminshall 
313830088Sminshall static char **
313930088Sminshall getnextset(name)
314030088Sminshall char *name;
314130088Sminshall {
314230088Sminshall     struct setlist *c = (struct setlist *)name;
314330088Sminshall 
314430088Sminshall     return (char **) (c+1);
314530088Sminshall }
314630088Sminshall 
314730088Sminshall static struct setlist *
314830088Sminshall getset(name)
314930088Sminshall char *name;
315030088Sminshall {
315130088Sminshall     return (struct setlist *) genget(name, (char **) Setlist, getnextset);
315230088Sminshall }
315330088Sminshall 
315430088Sminshall static
315530088Sminshall setcmd(argc, argv)
315630088Sminshall int	argc;
315730088Sminshall char	*argv[];
315830088Sminshall {
315930088Sminshall     int value;
316030088Sminshall     struct setlist *ct;
316130088Sminshall 
316230088Sminshall     /* XXX back we go... sigh */
316330088Sminshall     if (argc != 3) {
316430088Sminshall 	if ((argc == 2) &&
316530088Sminshall 		    ((!strcmp(argv[1], "?")) || (!strcmp(argv[1], "help")))) {
316630088Sminshall 	    for (ct = Setlist; ct->name; ct++) {
316730088Sminshall 		printf("%s\t%s\n", ct->name, ct->help);
316830088Sminshall 	    }
316930088Sminshall 	    printf("?\tdisplay help information\n");
317030088Sminshall 	} else {
317130088Sminshall 	    printf("Format is 'set Name Value'\n'set ?' for help.\n");
317230088Sminshall 	}
317330088Sminshall 	return 0;
317430088Sminshall     }
317530088Sminshall 
317630088Sminshall     ct = getset(argv[1]);
317730088Sminshall     if (ct == 0) {
317830088Sminshall 	fprintf(stderr, "'%s': unknown argument ('set ?' for help).\n",
317930088Sminshall 			argv[1]);
318030088Sminshall 	return 0;
318130088Sminshall     } else if (ct == Ambiguous(struct setlist *)) {
318230088Sminshall 	fprintf(stderr, "'%s': ambiguous argument ('set ?' for help).\n",
318330088Sminshall 			argv[1]);
318430088Sminshall 	return 0;
318530088Sminshall     } else {
318630088Sminshall 	if (strcmp("off", argv[2])) {
318730088Sminshall 	    value = special(argv[2]);
318830088Sminshall 	} else {
318930088Sminshall 	    value = -1;
319030088Sminshall 	}
319130088Sminshall 	*(ct->charp) = value;
319230088Sminshall 	printf("%s character is '%s'.\n", ct->name, control(*(ct->charp)));
319330088Sminshall     }
319430088Sminshall     return 1;
319530088Sminshall }
319630088Sminshall 
319730088Sminshall /*
319830088Sminshall  * The following are the data structures and routines for the
319930088Sminshall  * 'mode' command.
320030088Sminshall  */
320130088Sminshall 
320230088Sminshall static
320330088Sminshall dolinemode()
320430088Sminshall {
320530088Sminshall     if (hisopts[TELOPT_SGA]) {
320630088Sminshall 	wontoption(TELOPT_SGA, 0);
320730088Sminshall     }
320830088Sminshall     if (hisopts[TELOPT_ECHO]) {
320930088Sminshall 	wontoption(TELOPT_ECHO, 0);
321030088Sminshall     }
321130088Sminshall     return 1;
321230088Sminshall }
321330088Sminshall 
321430088Sminshall static
321530088Sminshall docharmode()
321630088Sminshall {
321730088Sminshall     if (!hisopts[TELOPT_SGA]) {
321830088Sminshall 	willoption(TELOPT_SGA, 0);
321930088Sminshall     }
322030088Sminshall     if (!hisopts[TELOPT_ECHO]) {
322130088Sminshall 	willoption(TELOPT_ECHO, 0);
322230088Sminshall     }
322330088Sminshall     return 1;
322430088Sminshall }
322530088Sminshall 
322630088Sminshall static struct cmd Modelist[] = {
322730088Sminshall     { "character",	"character-at-a-time mode",	docharmode, 1, 1 },
322830088Sminshall     { "line",		"line-by-line mode",		dolinemode, 1, 1 },
322930088Sminshall     { 0 },
323030088Sminshall };
323130088Sminshall 
323230088Sminshall static char **
323330088Sminshall getnextmode(name)
323430088Sminshall char *name;
323530088Sminshall {
323630088Sminshall     struct cmd *c = (struct cmd *) name;
323730088Sminshall 
323830088Sminshall     return (char **) (c+1);
323930088Sminshall }
324030088Sminshall 
324130088Sminshall static struct cmd *
324230088Sminshall getmodecmd(name)
324330088Sminshall char *name;
324430088Sminshall {
324530088Sminshall     return (struct cmd *) genget(name, (char **) Modelist, getnextmode);
324630088Sminshall }
324730088Sminshall 
324830088Sminshall static
324930088Sminshall modecmd(argc, argv)
325030088Sminshall int	argc;
325130088Sminshall char	*argv[];
325230088Sminshall {
325330088Sminshall     struct cmd *mt;
325430088Sminshall 
325530088Sminshall     if ((argc != 2) || !strcmp(argv[1], "?") || !strcmp(argv[1], "help")) {
325630088Sminshall 	printf("format is:  'mode Mode', where 'Mode' is one of:\n\n");
325730088Sminshall 	for (mt = Modelist; mt->name; mt++) {
325830088Sminshall 	    printf("%s\t%s\n", mt->name, mt->help);
325930088Sminshall 	}
326030088Sminshall 	return 0;
326130088Sminshall     }
326230088Sminshall     mt = getmodecmd(argv[1]);
326330088Sminshall     if (mt == 0) {
326430088Sminshall 	fprintf(stderr, "Unknown mode '%s' ('mode ?' for help).\n", argv[1]);
326530088Sminshall 	return 0;
326630088Sminshall     } else if (mt == Ambiguous(struct cmd *)) {
326730088Sminshall 	fprintf(stderr, "Ambiguous mode '%s' ('mode ?' for help).\n", argv[1]);
326830088Sminshall 	return 0;
326930088Sminshall     } else {
327030088Sminshall 	(*mt->handler)();
327130088Sminshall     }
327230088Sminshall     return 1;
327330088Sminshall }
327430088Sminshall 
327530088Sminshall /*
327630088Sminshall  * The following data structures and routines implement the
327730088Sminshall  * "display" command.
327830088Sminshall  */
327930088Sminshall 
328030088Sminshall static
328130088Sminshall display(argc, argv)
328230088Sminshall int	argc;
328330088Sminshall char	*argv[];
328430088Sminshall {
328530088Sminshall #define	dotog(tl)	if (tl->variable && tl->actionexplanation) { \
328630088Sminshall 			    if (*tl->variable) { \
328730088Sminshall 				printf("will"); \
328830088Sminshall 			    } else { \
328930088Sminshall 				printf("won't"); \
329030088Sminshall 			    } \
329130088Sminshall 			    printf(" %s.\n", tl->actionexplanation); \
329230088Sminshall 			}
329330088Sminshall 
329430088Sminshall #define	doset(sl)   if (sl->name && *sl->name != ' ') { \
329530088Sminshall 			printf("[%s]\t%s.\n", control(*sl->charp), sl->name); \
329630088Sminshall 		    }
329730088Sminshall 
329830088Sminshall     struct togglelist *tl;
329930088Sminshall     struct setlist *sl;
330030088Sminshall 
330130088Sminshall     if (argc == 1) {
330230088Sminshall 	for (tl = Togglelist; tl->name; tl++) {
330330088Sminshall 	    dotog(tl);
330430088Sminshall 	}
330530088Sminshall 	printf("\n");
330630088Sminshall 	for (sl = Setlist; sl->name; sl++) {
330730088Sminshall 	    doset(sl);
330830088Sminshall 	}
330930088Sminshall     } else {
331030088Sminshall 	int i;
331130088Sminshall 
331230088Sminshall 	for (i = 1; i < argc; i++) {
331330088Sminshall 	    sl = getset(argv[i]);
331430088Sminshall 	    tl = gettoggle(argv[i]);
331530088Sminshall 	    if ((sl == Ambiguous(struct setlist *)) ||
331630088Sminshall 				(tl == Ambiguous(struct togglelist *))) {
331730088Sminshall 		printf("?Ambiguous argument '%s'.\n", argv[i]);
331830088Sminshall 		return 0;
331930088Sminshall 	    } else if (!sl && !tl) {
332030088Sminshall 		printf("?Unknown argument '%s'.\n", argv[i]);
332130088Sminshall 		return 0;
332230088Sminshall 	    } else {
332330088Sminshall 		if (tl) {
332430088Sminshall 		    dotog(tl);
332530088Sminshall 		}
332630088Sminshall 		if (sl) {
332730088Sminshall 		    doset(sl);
332830088Sminshall 		}
332930088Sminshall 	    }
333030088Sminshall 	}
333130088Sminshall     }
333230088Sminshall     return 1;
333330088Sminshall #undef	doset
333430088Sminshall #undef	dotog
333530088Sminshall }
333630088Sminshall 
333730088Sminshall /*
333830088Sminshall  * The following are the data structures, and many of the routines,
333930088Sminshall  * relating to command processing.
334030088Sminshall  */
334130088Sminshall 
334230088Sminshall /*
334330088Sminshall  * Set the escape character.
334430088Sminshall  */
334530088Sminshall static
334630088Sminshall setescape(argc, argv)
334730088Sminshall 	int argc;
334830088Sminshall 	char *argv[];
334930088Sminshall {
335030088Sminshall 	register char *arg;
335130088Sminshall 	char buf[50];
335230088Sminshall 
335330088Sminshall 	printf(
335430088Sminshall 	    "Deprecated usage - please use 'set escape%s%s' in the future.\n",
335530088Sminshall 				(argc > 2)? " ":"", (argc > 2)? argv[1]: "");
335630088Sminshall 	if (argc > 2)
335730088Sminshall 		arg = argv[1];
335830088Sminshall 	else {
335930088Sminshall 		printf("new escape character: ");
336030088Sminshall 		gets(buf);
336130088Sminshall 		arg = buf;
336230088Sminshall 	}
336330088Sminshall 	if (arg[0] != '\0')
336430088Sminshall 		escape = arg[0];
336530088Sminshall 	if (!In3270) {
336630088Sminshall 		printf("Escape character is '%s'.\n", control(escape));
336730088Sminshall 	}
336830088Sminshall 	fflush(stdout);
336930088Sminshall 	return 1;
337030088Sminshall }
337130088Sminshall 
337230088Sminshall /*VARARGS*/
337330088Sminshall static
337430088Sminshall togcrmod()
337530088Sminshall {
337630088Sminshall     crmod = !crmod;
337730088Sminshall     printf("Deprecated usage - please use 'toggle crmod' in the future.\n");
337830088Sminshall     printf("%s map carriage return on output.\n", crmod ? "Will" : "Won't");
337930088Sminshall     fflush(stdout);
338030088Sminshall     return 1;
338130088Sminshall }
338230088Sminshall 
338330088Sminshall /*VARARGS*/
338430088Sminshall suspend()
338530088Sminshall {
338630088Sminshall 	setcommandmode();
338730088Sminshall #if	defined(unix)
338830088Sminshall 	kill(0, SIGTSTP);
338931124Sminshall 	/* reget parameters in case they were changed */
339031124Sminshall 	TerminalSaveState();
339130088Sminshall #endif	/* defined(unix) */
339230088Sminshall 	return 1;
339330088Sminshall }
339430088Sminshall 
339530088Sminshall /*VARARGS*/
339630088Sminshall static
339730326Sminshall bye(argc, argv)
339830326Sminshall int	argc;		/* Number of arguments */
339930326Sminshall char	*argv[];	/* arguments */
340030088Sminshall {
340130088Sminshall     if (connected) {
340230088Sminshall 	shutdown(net, 2);
340330088Sminshall 	printf("Connection closed.\n");
3404*31131Sminshall 	NetClose(net);
340530088Sminshall 	connected = 0;
340630088Sminshall 	/* reset options */
340730326Sminshall 	tninit();
340830088Sminshall #if	defined(TN3270)
340930326Sminshall 	SetIn3270();		/* Get out of 3270 mode */
341030088Sminshall #endif	/* defined(TN3270) */
341130088Sminshall     }
341230326Sminshall     if ((argc != 2) || (strcmp(argv[1], "fromquit") != 0)) {
341330326Sminshall 	longjmp(toplevel, 1);
341430326Sminshall 	/* NOTREACHED */
341530326Sminshall     }
341630326Sminshall     return 1;			/* Keep lint, etc., happy */
341730088Sminshall }
341830088Sminshall 
341930088Sminshall /*VARARGS*/
342030088Sminshall quit()
342130088Sminshall {
342230326Sminshall 	(void) call(bye, "bye", "fromquit", 0);
342330088Sminshall 	Exit(0);
342430088Sminshall 	/*NOTREACHED*/
342530088Sminshall 	return 1;			/* just to keep lint happy */
342630088Sminshall }
342730088Sminshall 
342830088Sminshall /*
342930088Sminshall  * Print status about the connection.
343030088Sminshall  */
343130088Sminshall static
343230088Sminshall status(argc, argv)
343330088Sminshall int	argc;
343430088Sminshall char	*argv[];
343530088Sminshall {
343630088Sminshall     if (connected) {
343730088Sminshall 	printf("Connected to %s.\n", hostname);
343830088Sminshall 	if (argc < 2) {
343930088Sminshall 	    printf("Operating in %s.\n",
344030088Sminshall 				modelist[getconnmode()].modedescriptions);
344130088Sminshall 	    if (localchars) {
344230088Sminshall 		printf("Catching signals locally.\n");
344330088Sminshall 	    }
344430088Sminshall 	}
344530088Sminshall     } else {
344630088Sminshall 	printf("No connection.\n");
344730088Sminshall     }
344830088Sminshall #   if !defined(TN3270)
344930088Sminshall     printf("Escape character is '%s'.\n", control(escape));
345030088Sminshall     fflush(stdout);
345130088Sminshall #   else /* !defined(TN3270) */
345230088Sminshall     if ((!In3270) && ((argc < 2) || strcmp(argv[1], "notmuch"))) {
345330088Sminshall 	printf("Escape character is '%s'.\n", control(escape));
345430088Sminshall     }
345530088Sminshall #   if defined(unix)
345630088Sminshall     if (In3270 && transcom) {
345730088Sminshall        printf("Transparent mode command is '%s'.\n", transcom);
345830088Sminshall     }
345930088Sminshall #   endif /* defined(unix) */
346030088Sminshall     fflush(stdout);
346130088Sminshall     if (In3270) {
346230088Sminshall 	return 0;
346330088Sminshall     }
346430088Sminshall #   endif /* defined(TN3270) */
346530088Sminshall     return 1;
346630088Sminshall }
346730088Sminshall 
346830088Sminshall #if	defined(TN3270) && defined(unix)
346930088Sminshall static
347030088Sminshall settranscom(argc, argv)
347130088Sminshall 	int argc;
347230088Sminshall 	char *argv[];
347330088Sminshall {
347430088Sminshall 	int i, len = 0;
347530088Sminshall 	char *strcpy(), *strcat();
347630088Sminshall 
347730088Sminshall 	if (argc == 1 && transcom) {
347830088Sminshall 	   transcom = 0;
347930088Sminshall 	}
348030088Sminshall 	if (argc == 1) {
348130088Sminshall 	   return;
348230088Sminshall 	}
348330088Sminshall 	for (i = 1; i < argc; ++i) {
348430088Sminshall 	    len += 1 + strlen(argv[1]);
348530088Sminshall 	}
348630088Sminshall 	transcom = tline;
348730088Sminshall 	(void) strcpy(transcom, argv[1]);
348830088Sminshall 	for (i = 2; i < argc; ++i) {
348930088Sminshall 	    (void) strcat(transcom, " ");
349030088Sminshall 	    (void) strcat(transcom, argv[i]);
349130088Sminshall 	}
349230088Sminshall }
349330088Sminshall #endif	/* defined(TN3270) && defined(unix) */
349430088Sminshall 
349530088Sminshall 
349630088Sminshall static
349730088Sminshall tn(argc, argv)
349830088Sminshall 	int argc;
349930088Sminshall 	char *argv[];
350030088Sminshall {
350130088Sminshall     register struct hostent *host = 0;
3502*31131Sminshall #if defined(MSDOS)
350330088Sminshall     char *cp;
3504*31131Sminshall #endif	/* defined(MSDOS) */
350530088Sminshall 
350630088Sminshall     if (connected) {
350730088Sminshall 	printf("?Already connected to %s\n", hostname);
350830088Sminshall 	return 0;
350930088Sminshall     }
351030088Sminshall     if (argc < 2) {
351130088Sminshall 	(void) strcpy(line, "Connect ");
351230088Sminshall 	printf("(to) ");
351330088Sminshall 	gets(&line[strlen(line)]);
351430088Sminshall 	makeargv();
351530088Sminshall 	argc = margc;
351630088Sminshall 	argv = margv;
351730088Sminshall     }
351830088Sminshall     if (argc > 3) {
351930088Sminshall 	printf("usage: %s host-name [port]\n", argv[0]);
352030088Sminshall 	return 0;
352130088Sminshall     }
3522*31131Sminshall #if	defined(MSDOS)
352330088Sminshall     for (cp = argv[1]; *cp; cp++) {
352430088Sminshall 	if (isupper(*cp)) {
352530088Sminshall 	    *cp = tolower(*cp);
352630088Sminshall 	}
352730088Sminshall     }
3528*31131Sminshall #endif	/* defined(MSDOS) */
352930088Sminshall     sin.sin_addr.s_addr = inet_addr(argv[1]);
353030088Sminshall     if (sin.sin_addr.s_addr != -1) {
353130088Sminshall 	sin.sin_family = AF_INET;
353230088Sminshall 	(void) strcpy(hnamebuf, argv[1]);
353330088Sminshall 	hostname = hnamebuf;
353430088Sminshall     } else {
353530088Sminshall 	host = gethostbyname(argv[1]);
353630088Sminshall 	if (host) {
353730088Sminshall 	    sin.sin_family = host->h_addrtype;
353830088Sminshall #if	defined(h_addr)		/* In 4.3, this is a #define */
3539*31131Sminshall 	    memcpy((caddr_t)&sin.sin_addr,
3540*31131Sminshall 				host->h_addr_list[0], host->h_length);
354130088Sminshall #else	/* defined(h_addr) */
3542*31131Sminshall 	    memcpy((caddr_t)&sin.sin_addr, host->h_addr, host->h_length);
354330088Sminshall #endif	/* defined(h_addr) */
354430088Sminshall 	    hostname = host->h_name;
354530088Sminshall 	} else {
354630088Sminshall 	    printf("%s: unknown host\n", argv[1]);
354730088Sminshall 	    return 0;
354830088Sminshall 	}
354930088Sminshall     }
355030088Sminshall     sin.sin_port = sp->s_port;
355130088Sminshall     if (argc == 3) {
355230088Sminshall 	sin.sin_port = atoi(argv[2]);
355330088Sminshall 	if (sin.sin_port == 0) {
355430088Sminshall 	    sp = getservbyname(argv[2], "tcp");
355530088Sminshall 	    if (sp)
355630088Sminshall 		sin.sin_port = sp->s_port;
355730088Sminshall 	    else {
355830088Sminshall 		printf("%s: bad port number\n", argv[2]);
355930088Sminshall 		return 0;
356030088Sminshall 	    }
356130088Sminshall 	} else {
356230088Sminshall 	    sin.sin_port = atoi(argv[2]);
356330088Sminshall 	    sin.sin_port = htons(sin.sin_port);
356430088Sminshall 	}
356530088Sminshall 	telnetport = 0;
356630088Sminshall     } else {
356730088Sminshall 	telnetport = 1;
356830088Sminshall     }
356930088Sminshall #if	defined(unix)
357030088Sminshall     signal(SIGINT, intr);
357130088Sminshall     signal(SIGQUIT, intr2);
357230088Sminshall     signal(SIGPIPE, deadpeer);
357330088Sminshall #endif	/* defined(unix) */
357430088Sminshall     printf("Trying...\n");
357530088Sminshall     do {
357630088Sminshall 	net = socket(AF_INET, SOCK_STREAM, 0);
357730088Sminshall 	if (net < 0) {
357830088Sminshall 	    perror("telnet: socket");
357930088Sminshall 	    return 0;
358030088Sminshall 	}
358131124Sminshall 	if (debug && SetSockOpt(net, SOL_SOCKET, SO_DEBUG, 1) < 0) {
358230088Sminshall 		perror("setsockopt (SO_DEBUG)");
358331124Sminshall 	}
358430088Sminshall 
358530088Sminshall 	if (connect(net, (struct sockaddr *)&sin, sizeof (sin)) < 0) {
358630088Sminshall #if	defined(h_addr)		/* In 4.3, this is a #define */
358730088Sminshall 	    if (host && host->h_addr_list[1]) {
358830088Sminshall 		int oerrno = errno;
358930088Sminshall 
359030088Sminshall 		fprintf(stderr, "telnet: connect to address %s: ",
359130088Sminshall 						inet_ntoa(sin.sin_addr));
359230088Sminshall 		errno = oerrno;
359330088Sminshall 		perror((char *)0);
359430088Sminshall 		host->h_addr_list++;
3595*31131Sminshall 		memcpy((caddr_t)&sin.sin_addr,
3596*31131Sminshall 			host->h_addr_list[0], host->h_length);
359730088Sminshall 		fprintf(stderr, "Trying %s...\n",
359830088Sminshall 			inet_ntoa(sin.sin_addr));
3599*31131Sminshall 		(void) NetClose(net);
360030088Sminshall 		continue;
360130088Sminshall 	    }
360230088Sminshall #endif	/* defined(h_addr) */
360330088Sminshall 	    perror("telnet: Unable to connect to remote host");
360430088Sminshall #if defined(unix)
360530088Sminshall 	    signal(SIGINT, SIG_DFL);
360630088Sminshall 	    signal(SIGQUIT, SIG_DFL);
360730320Sminshall #endif	/* defined(unix) */
360830088Sminshall 	    return 0;
360930088Sminshall 	    }
361030088Sminshall 	connected++;
361130088Sminshall     } while (connected == 0);
361230088Sminshall     call(status, "status", "notmuch", 0);
361330088Sminshall     if (setjmp(peerdied) == 0)
361430088Sminshall 	telnet();
3615*31131Sminshall     NetClose(net);
361630088Sminshall     ExitString(stderr, "Connection closed by foreign host.\n",1);
361730088Sminshall     /*NOTREACHED*/
361830088Sminshall }
361930088Sminshall 
362030088Sminshall 
362130088Sminshall #define HELPINDENT (sizeof ("connect"))
362230088Sminshall 
362330088Sminshall static char
362430088Sminshall 	openhelp[] =	"connect to a site",
362530088Sminshall 	closehelp[] =	"close current connection",
362630088Sminshall 	quithelp[] =	"exit telnet",
362730088Sminshall 	zhelp[] =	"suspend telnet",
362830088Sminshall 	statushelp[] =	"print status information",
362930088Sminshall 	helphelp[] =	"print help information",
363030088Sminshall 	sendhelp[] =	"transmit special characters ('send ?' for more)",
363130088Sminshall 	sethelp[] = 	"set operating parameters ('set ?' for more)",
363230088Sminshall 	togglestring[] ="toggle operating parameters ('toggle ?' for more)",
363330088Sminshall 	displayhelp[] =	"display operating parameters",
363430088Sminshall #if	defined(TN3270) && defined(unix)
363530088Sminshall 	transcomhelp[] = "specify Unix command for transparent mode pipe",
363630088Sminshall #endif	/* defined(TN3270) && defined(unix) */
363730088Sminshall 	modehelp[] = "try to enter line-by-line or character-at-a-time mode";
363830088Sminshall 
363930088Sminshall extern int	help();
364030088Sminshall 
364130088Sminshall static struct cmd cmdtab[] = {
364230088Sminshall 	{ "close",	closehelp,	bye,		1, 1 },
364330088Sminshall 	{ "display",	displayhelp,	display,	1, 0 },
364430088Sminshall 	{ "mode",	modehelp,	modecmd,	1, 1 },
364530088Sminshall 	{ "open",	openhelp,	tn,		1, 0 },
364630088Sminshall 	{ "quit",	quithelp,	quit,		1, 0 },
364730088Sminshall 	{ "send",	sendhelp,	sendcmd,	1, 1 },
364830088Sminshall 	{ "set",	sethelp,	setcmd,		1, 0 },
364930088Sminshall 	{ "status",	statushelp,	status,		1, 0 },
365030088Sminshall 	{ "toggle",	togglestring,	toggle,		1, 0 },
365130088Sminshall #if	defined(TN3270) && defined(unix)
365230088Sminshall 	{ "transcom",	transcomhelp,	settranscom,	1, 0 },
365330088Sminshall #endif	/* defined(TN3270) && defined(unix) */
365430088Sminshall 	{ "z",		zhelp,		suspend,	1, 0 },
365530088Sminshall 	{ "?",		helphelp,	help,		1, 0 },
365630088Sminshall 	0
365730088Sminshall };
365830088Sminshall 
365930088Sminshall static char	crmodhelp[] =	"deprecated command -- use 'toggle crmod' instead";
366030088Sminshall static char	escapehelp[] =	"deprecated command -- use 'set escape' instead";
366130088Sminshall 
366230088Sminshall static struct cmd cmdtab2[] = {
366330088Sminshall 	{ "help",	helphelp,	help,		0, 0 },
366430088Sminshall 	{ "escape",	escapehelp,	setescape,	1, 0 },
366530088Sminshall 	{ "crmod",	crmodhelp,	togcrmod,	1, 0 },
366630088Sminshall 	0
366730088Sminshall };
366830088Sminshall 
366930088Sminshall /*
367030088Sminshall  * Call routine with argc, argv set from args (terminated by 0).
367130088Sminshall  * VARARGS2
367230088Sminshall  */
367330088Sminshall static
367430088Sminshall call(routine, args)
367530088Sminshall 	int (*routine)();
367630088Sminshall 	char *args;
367730088Sminshall {
367830088Sminshall 	register char **argp;
367930088Sminshall 	register int argc;
368030088Sminshall 
368130088Sminshall 	for (argc = 0, argp = &args; *argp++ != 0; argc++)
368230088Sminshall 		;
368330088Sminshall 	return (*routine)(argc, &args);
368430088Sminshall }
368530088Sminshall 
368630088Sminshall static char **
368730088Sminshall getnextcmd(name)
368830088Sminshall char *name;
368930088Sminshall {
369030088Sminshall     struct cmd *c = (struct cmd *) name;
369130088Sminshall 
369230088Sminshall     return (char **) (c+1);
369330088Sminshall }
369430088Sminshall 
369530088Sminshall static struct cmd *
369630088Sminshall getcmd(name)
369730088Sminshall char *name;
369830088Sminshall {
369930088Sminshall     struct cmd *cm;
370030088Sminshall 
370130088Sminshall     if ((cm = (struct cmd *) genget(name, (char **) cmdtab, getnextcmd)) != 0) {
370230088Sminshall 	return cm;
370330088Sminshall     } else {
370430088Sminshall 	return (struct cmd *) genget(name, (char **) cmdtab2, getnextcmd);
370530088Sminshall     }
370630088Sminshall }
370730088Sminshall 
370830088Sminshall void
370930088Sminshall command(top)
371030088Sminshall 	int top;
371130088Sminshall {
371230088Sminshall 	register struct cmd *c;
371330088Sminshall 
371430088Sminshall 	setcommandmode();
371530088Sminshall 	if (!top) {
371630088Sminshall 		putchar('\n');
371730088Sminshall 	} else {
371830088Sminshall #if	defined(unix)
371930088Sminshall 		signal(SIGINT, SIG_DFL);
372030088Sminshall 		signal(SIGQUIT, SIG_DFL);
372130088Sminshall #endif	/* defined(unix) */
372230088Sminshall 	}
372330088Sminshall 	for (;;) {
372430088Sminshall 		printf("%s> ", prompt);
372530088Sminshall 		if (gets(line) == NULL) {
372630088Sminshall 			if (feof(stdin) || ferror(stdin))
372730088Sminshall 				quit();
372830088Sminshall 			break;
372930088Sminshall 		}
373030088Sminshall 		if (line[0] == 0)
373130088Sminshall 			break;
373230088Sminshall 		makeargv();
373330088Sminshall 		c = getcmd(margv[0]);
373430088Sminshall 		if (c == Ambiguous(struct cmd *)) {
373530088Sminshall 			printf("?Ambiguous command\n");
373630088Sminshall 			continue;
373730088Sminshall 		}
373830088Sminshall 		if (c == 0) {
373930088Sminshall 			printf("?Invalid command\n");
374030088Sminshall 			continue;
374130088Sminshall 		}
374230088Sminshall 		if (c->needconnect && !connected) {
374330088Sminshall 			printf("?Need to be connected first.\n");
374430088Sminshall 			continue;
374530088Sminshall 		}
374630088Sminshall 		if ((*c->handler)(margc, margv)) {
374730088Sminshall 			break;
374830088Sminshall 		}
374930088Sminshall 	}
375030088Sminshall 	if (!top) {
375130088Sminshall 		if (!connected) {
375230088Sminshall 			longjmp(toplevel, 1);
375330088Sminshall 			/*NOTREACHED*/
375430088Sminshall 		}
375530088Sminshall 		setconnmode();
375630088Sminshall 	}
375730088Sminshall }
375830088Sminshall 
375930088Sminshall /*
376030088Sminshall  * Help command.
376130088Sminshall  */
376230088Sminshall static
376330088Sminshall help(argc, argv)
376430088Sminshall 	int argc;
376530088Sminshall 	char *argv[];
376630088Sminshall {
376730088Sminshall 	register struct cmd *c;
376830088Sminshall 
376930088Sminshall 	if (argc == 1) {
377030088Sminshall 		printf("Commands may be abbreviated.  Commands are:\n\n");
377130088Sminshall 		for (c = cmdtab; c->name; c++)
377230088Sminshall 			if (c->dohelp) {
377330088Sminshall 				printf("%-*s\t%s\n", HELPINDENT, c->name,
377430088Sminshall 								    c->help);
377530088Sminshall 			}
377630088Sminshall 		return 0;
377730088Sminshall 	}
377830088Sminshall 	while (--argc > 0) {
377930088Sminshall 		register char *arg;
378030088Sminshall 		arg = *++argv;
378130088Sminshall 		c = getcmd(arg);
378230088Sminshall 		if (c == Ambiguous(struct cmd *))
378330088Sminshall 			printf("?Ambiguous help command %s\n", arg);
378430088Sminshall 		else if (c == (struct cmd *)0)
378530088Sminshall 			printf("?Invalid help command %s\n", arg);
378630088Sminshall 		else
378730088Sminshall 			printf("%s\n", c->help);
378830088Sminshall 	}
378930088Sminshall 	return 0;
379030088Sminshall }
379130088Sminshall 
379230088Sminshall /*
379330088Sminshall  * main.  Parse arguments, invoke the protocol or command parser.
379430088Sminshall  */
379530088Sminshall 
379630088Sminshall 
379730088Sminshall void
379830088Sminshall main(argc, argv)
379930088Sminshall 	int argc;
380030088Sminshall 	char *argv[];
380130088Sminshall {
380230326Sminshall     tninit();		/* Clear out things */
380330326Sminshall 
380430088Sminshall     NetTrace = stdout;
380531124Sminshall     TerminalSaveState();
380631124Sminshall     autoflush = TerminalAutoFlush();
380731124Sminshall 
380830088Sminshall     prompt = argv[0];
380930088Sminshall     if (argc > 1 && !strcmp(argv[1], "-d")) {
381030088Sminshall 	debug = 1;
381130088Sminshall 	argv++;
381230088Sminshall 	argc--;
381330088Sminshall     }
381430088Sminshall     if (argc > 1 && !strcmp(argv[1], "-n")) {
381530088Sminshall 	argv++;
381630088Sminshall 	argc--;
381730088Sminshall 	if (argc > 1) {		/* get file name */
381830088Sminshall 	    NetTrace = fopen(argv[1], "w");
381930088Sminshall 	    argv++;
382030088Sminshall 	    argc--;
382130088Sminshall 	    if (NetTrace == NULL) {
382230088Sminshall 		NetTrace = stdout;
382330088Sminshall 	    }
382430088Sminshall 	}
382530088Sminshall     }
382630088Sminshall #if	defined(TN3270) && defined(unix)
382730088Sminshall     if (argc > 1 && !strcmp(argv[1], "-t")) {
382830088Sminshall 	argv++;
382930088Sminshall 	argc--;
383030088Sminshall 	if (argc > 1) {		/* get command name */
383130088Sminshall 	    transcom = tline;
383230088Sminshall 	    (void) strcpy(transcom, argv[1]);
383330088Sminshall 	    argv++;
383430088Sminshall 	    argc--;
383530088Sminshall 	}
383630088Sminshall     }
383730088Sminshall #endif	/* defined(TN3270) && defined(unix) */
383830088Sminshall     if (argc != 1) {
383930088Sminshall 	if (setjmp(toplevel) != 0)
384030088Sminshall 	    Exit(0);
384130088Sminshall 	tn(argc, argv);
384230088Sminshall     }
384330088Sminshall     setjmp(toplevel);
384430088Sminshall     for (;;)
384530088Sminshall 	command(1);
384630088Sminshall }
3847