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