xref: /csrg-svn/usr.bin/tn3270/telnet.c (revision 31124)
130088Sminshall /*
230088Sminshall  *	Copyright (c) 1984, 1985, 1986 by the Regents of the
330088Sminshall  *	University of California and by Gregory Glenn Minshall.
430088Sminshall  *
530088Sminshall  *	Permission to use, copy, modify, and distribute these
630088Sminshall  *	programs and their documentation for any purpose and
730088Sminshall  *	without fee is hereby granted, provided that this
830088Sminshall  *	copyright and permission appear on all copies and
930088Sminshall  *	supporting documentation, the name of the Regents of
1030088Sminshall  *	the University of California not be used in advertising
1130088Sminshall  *	or publicity pertaining to distribution of the programs
1230088Sminshall  *	without specific prior permission, and notice be given in
1330088Sminshall  *	supporting documentation that copying and distribution is
1430088Sminshall  *	by permission of the Regents of the University of California
1530088Sminshall  *	and by Gregory Glenn Minshall.  Neither the Regents of the
1630088Sminshall  *	University of California nor Gregory Glenn Minshall make
1730088Sminshall  *	representations about the suitability of this software
1830088Sminshall  *	for any purpose.  It is provided "as is" without
1930088Sminshall  *	express or implied warranty.
2030088Sminshall  */
2130088Sminshall 
2230088Sminshall #ifndef lint
2330088Sminshall static char copyright[] =
2430088Sminshall "@(#) Copyright (c) 1984, 1985, 1986 Regents of the University of California.\n\
2530088Sminshall  All rights reserved.\n";
2630320Sminshall #endif	/* not lint */
2730088Sminshall 
2830088Sminshall #ifndef lint
2930088Sminshall static char sccsid[] = "@(#)telnet.c	3.1  10/29/86";
3030320Sminshall #endif	/* not lint */
3130088Sminshall 
3230088Sminshall /*
3330088Sminshall  * User telnet program, modified for use by tn3270.c.
3430088Sminshall  *
3530088Sminshall  * Many of the FUNCTIONAL changes in this newest version of TELNET
3630088Sminshall  * were suggested by Dave Borman of Cray Research, Inc.
3730088Sminshall  *
3830088Sminshall  * Other changes in the tn3270 side come from Alan Crosswell (Columbia),
3930088Sminshall  * Bob Braden (ISI), Steve Jacobson (Berkeley), and Cliff Frost (Berkeley).
4030088Sminshall  *
4130088Sminshall  * This code is common between telnet(1c) and tn3270(1c).  There are the
4230088Sminshall  * following defines used to generate the various versions:
4330088Sminshall  *
4430088Sminshall  *	TN3270		- 	This is to be linked with tn3270.
4530088Sminshall  *
4630088Sminshall  *	DEBUG		-	Allow for some extra debugging operations.
4730088Sminshall  *
4830088Sminshall  *	NOT43		-	Allows the program to compile and run on
4930088Sminshall  *				a 4.2BSD system.
5030088Sminshall  *
5130088Sminshall  *	PUTCHAR		-	Within tn3270, on a NOT43 system,
5230088Sminshall  *				allows the use of the 4.3 curses
5330088Sminshall  *				(greater speed updating the screen).
5430088Sminshall  *				You need the 4.3 curses for this to work.
5530088Sminshall  *
5630088Sminshall  *	FD_SETSIZE	-	On whichever system, if this isn't defined,
5730088Sminshall  *				we patch over the FD_SET, etc., macros with
5830088Sminshall  *				some homebrewed ones.
5930088Sminshall  *
6030088Sminshall  *	SO_OOBINLINE	-	This is a socket option which we would like
6130088Sminshall  *				to set to allow TCP urgent data to come
6230088Sminshall  *				to us "inline".  This is NECESSARY for
6330088Sminshall  *				CORRECT operation, and desireable for
6430088Sminshall  *				simpler operation.
6530088Sminshall  *
6630088Sminshall  *	LNOFLSH		-	Detects the presence of the LNOFLSH bit
6730088Sminshall  *				in the tty structure.
6830088Sminshall  *
6930088Sminshall  *	unix		-	Compiles in unix specific stuff.
7030088Sminshall  *
7130088Sminshall  *	msdos		-	Compiles in msdos specific stuff.
7230088Sminshall  *
7330088Sminshall  */
7430088Sminshall 
7530088Sminshall #if	!defined(TN3270)
7630088Sminshall #define	ExitString(f,s,r)	{ fprintf(f, s); exit(r); }
7730088Sminshall #define	Exit(x)			exit(x)
7830088Sminshall #define	SetIn3270()
7930088Sminshall 
8030088Sminshall void	setcommandmode(), command();	/* forward declarations */
8130088Sminshall #endif	/* !defined(TN3270) */
8230088Sminshall 
8330088Sminshall #include <sys/types.h>
8430088Sminshall #include <sys/socket.h>
8530088Sminshall 
8630088Sminshall #include <netinet/in.h>
8730088Sminshall 
88*31124Sminshall #if	defined(unix)
89*31124Sminshall /* By the way, we need to include curses.h before telnet.h since,
90*31124Sminshall  * among other things, telnet.h #defines 'DO', which is a variable
91*31124Sminshall  * declared in curses.h.
92*31124Sminshall  */
9330088Sminshall #include <curses.h>
94*31124Sminshall #endif	/* defined(unix) */
9530088Sminshall 
9630088Sminshall #define	TELOPTS
9730088Sminshall #include <arpa/telnet.h>
9830088Sminshall 
9930088Sminshall #if	!defined(NOT43)
10030088Sminshall #include <arpa/inet.h>
10130088Sminshall #else	/* !defined(NOT43) */
10230088Sminshall extern unsigned long inet_addr();
10330088Sminshall extern char	*inet_ntoa();
10430088Sminshall #endif	/* !defined(NOT43) */
10530088Sminshall 
10630088Sminshall #include <stdio.h>
10730088Sminshall #include <ctype.h>
10830088Sminshall #include <errno.h>
10930088Sminshall #include <setjmp.h>
11030088Sminshall #include <netdb.h>
111*31124Sminshall 
112*31124Sminshall #if	defined(unix)
11330088Sminshall #include <strings.h>
114*31124Sminshall #else	/* defined(unix) */
115*31124Sminshall #include <string.h>
116*31124Sminshall #endif	/* defined(unix) */
11730088Sminshall 
11830088Sminshall #if	defined(TN3270)
11930088Sminshall #include "ctlr/screen.h"
12030088Sminshall #include "system/globals.h"
12130088Sminshall #include "telnet.ext"
12230088Sminshall #include "ctlr/options.ext"
12330088Sminshall #include "ctlr/outbound.ext"
12430088Sminshall #include "keyboard/termin.ext"
12530722Sminshall #include "general.h"
12630088Sminshall #endif	/* defined(TN3270) */
12730088Sminshall 
12830088Sminshall 
12930088Sminshall 
13030088Sminshall #ifndef	FD_SETSIZE
13130088Sminshall /*
13230088Sminshall  * The following is defined just in case someone should want to run
13330088Sminshall  * this telnet on a 4.2 system.
13430088Sminshall  *
13530088Sminshall  */
13630088Sminshall 
13730088Sminshall #define	FD_SET(n, p)	((p)->fds_bits[0] |= (1<<(n)))
13830088Sminshall #define	FD_CLR(n, p)	((p)->fds_bits[0] &= ~(1<<(n)))
13930088Sminshall #define	FD_ISSET(n, p)	((p)->fds_bits[0] & (1<<(n)))
14030088Sminshall #define FD_ZERO(p)	((p)->fds_bits[0] = 0)
14130088Sminshall 
14230088Sminshall #endif
14330088Sminshall 
14430088Sminshall #define	strip(x)	((x)&0x7f)
14530088Sminshall #define min(x,y)	((x<y)? x:y)
14630088Sminshall 
14730088Sminshall #if	defined(TN3270)
14830326Sminshall static char	Ibuf[8*BUFSIZ], *Ifrontp, *Ibackp;
14930088Sminshall #endif	/* defined(TN3270) */
15030088Sminshall 
15130326Sminshall static char	ttyobuf[2*BUFSIZ], *tfrontp, *tbackp;
15230088Sminshall #define	TTYADD(c)	{ if (!(SYNCHing||flushout)) { *tfrontp++ = c; } }
15330088Sminshall #define	TTYLOC()	(tfrontp)
15430088Sminshall #define	TTYMAX()	(ttyobuf+sizeof ttyobuf-1)
15530088Sminshall #define	TTYMIN()	(netobuf)
15630088Sminshall #define	TTYBYTES()	(tfrontp-tbackp)
15730088Sminshall #define	TTYROOM()	(TTYMAX()-TTYLOC()+1)
15830088Sminshall 
15930326Sminshall static char	netobuf[2*BUFSIZ], *nfrontp, *nbackp;
16030088Sminshall #define	NETADD(c)	{ *nfrontp++ = c; }
16130088Sminshall #define	NET2ADD(c1,c2)	{ NETADD(c1); NETADD(c2); }
16230088Sminshall #define NETLOC()	(nfrontp)
16330088Sminshall #define	NETMAX()	(netobuf+sizeof netobuf-1)
16430088Sminshall #define	NETBYTES()	(nfrontp-nbackp)
16530088Sminshall #define	NETROOM()	(NETMAX()-NETLOC()+1)
16630326Sminshall static char	*neturg;		/* one past last byte of urgent data */
16730088Sminshall 
16830326Sminshall static char	subbuffer[100],
16930326Sminshall 		*subpointer, *subend;	 /* buffer for sub-options */
17030088Sminshall #define	SB_CLEAR()	subpointer = subbuffer;
17130088Sminshall #define	SB_TERM()	subend = subpointer;
17230088Sminshall #define	SB_ACCUM(c)	if (subpointer < (subbuffer+sizeof subbuffer)) { \
17330088Sminshall 				*subpointer++ = (c); \
17430088Sminshall 			}
17530088Sminshall 
17630088Sminshall static char	sb_terminal[] = { IAC, SB,
17730088Sminshall 			TELOPT_TTYPE, TELQUAL_IS,
17830088Sminshall 			'I', 'B', 'M', '-', '3', '2', '7', '8', '-', '2',
17930088Sminshall 			IAC, SE };
18030088Sminshall #define	SBTERMMODEL	13
18130088Sminshall 
18230088Sminshall 
18330326Sminshall static char	hisopts[256];
18430326Sminshall static char	myopts[256];
18530088Sminshall 
18630088Sminshall static char	doopt[] = { IAC, DO, '%', 'c', 0 };
18730088Sminshall static char	dont[] = { IAC, DONT, '%', 'c', 0 };
18830088Sminshall static char	will[] = { IAC, WILL, '%', 'c', 0 };
18930088Sminshall static char	wont[] = { IAC, WONT, '%', 'c', 0 };
19030088Sminshall 
19130088Sminshall struct cmd {
19230088Sminshall 	char	*name;		/* command name */
19330088Sminshall 	char	*help;		/* help string */
19430088Sminshall 	int	(*handler)();	/* routine which executes command */
19530088Sminshall 	int	dohelp;		/* Should we give general help information? */
19630088Sminshall 	int	needconnect;	/* Do we need to be connected to execute? */
19730088Sminshall };
19830088Sminshall 
19930326Sminshall static char	sibuf[BUFSIZ], *sbp;
20030088Sminshall static char	tibuf[BUFSIZ], *tbp;
20130088Sminshall static fd_set ibits, obits, xbits;
20230088Sminshall 
20330088Sminshall 
20430088Sminshall static int
20530326Sminshall 	connected,
20630326Sminshall 	net,
20730326Sminshall 	scc,
20830326Sminshall 	tcc,
20930326Sminshall 	showoptions,
21030326Sminshall 	In3270,		/* Are we in 3270 mode? */
21130326Sminshall 	ISend,		/* trying to send network data in */
21230088Sminshall 	debug = 0,
21330326Sminshall 	crmod,
21430326Sminshall 	netdata,
21530722Sminshall 	askedSGA = 0,	/* We have talked about suppress go ahead */
21630088Sminshall 	telnetport = 1;
21730088Sminshall 
21830326Sminshall static FILE	*NetTrace = 0;		/* Not in bss, since needs to stay */
21930088Sminshall 
22030088Sminshall #define	CONTROL(x)	((x)&0x1f)		/* CTRL(x) is not portable */
22130088Sminshall 
22230088Sminshall static char
22330088Sminshall 	*prompt = 0,
22430326Sminshall 	escape,
22530326Sminshall 	echoc;
22630088Sminshall 
22730088Sminshall static int
22830326Sminshall 	SYNCHing,		/* we are in TELNET SYNCH mode */
22930326Sminshall 	flushout,		/* flush output */
23030088Sminshall 	autoflush = 0,		/* flush output when interrupting? */
23130326Sminshall 	autosynch,		/* send interrupt characters with SYNCH? */
23230326Sminshall 	localchars,		/* we recognize interrupt/quit */
23330326Sminshall 	donelclchars,	/* the user has set "localchars" */
234*31124Sminshall 	dontlecho,		/* do we suppress local echoing right now? */
235*31124Sminshall 	globalmode;
23630088Sminshall 
23730088Sminshall /*	The following are some tn3270 specific flags */
23830088Sminshall #if	defined(TN3270)
23930088Sminshall 
24030088Sminshall static int
24130326Sminshall 	Sent3270TerminalType;	/* Have we said we are a 3270? */
24230088Sminshall 
24330722Sminshall /*
24430722Sminshall  * Telnet receiver states for fsm
24530722Sminshall  */
24630722Sminshall #define	TS_DATA		0
24730722Sminshall #define	TS_IAC		1
24830722Sminshall #define	TS_WILL		2
24930722Sminshall #define	TS_WONT		3
25030722Sminshall #define	TS_DO		4
25130722Sminshall #define	TS_DONT		5
25230722Sminshall #define	TS_CR		6
25330722Sminshall #define	TS_SB		7		/* sub-option collection */
25430722Sminshall #define	TS_SE		8		/* looking for sub-option end */
25530722Sminshall 
25630722Sminshall static int	telrcv_state = TS_DATA;
25730088Sminshall /* Some real, live, globals. */
25830088Sminshall int
25930326Sminshall 	tout,			/* Output file descriptor */
26030326Sminshall 	tin;			/* Input file descriptor */
26130088Sminshall 
26230088Sminshall #else	/* defined(TN3270) */
26330326Sminshall static int tin, tout;		/* file descriptors */
26430088Sminshall #endif	/* defined(TN3270) */
26530088Sminshall 
26630088Sminshall static char	line[200];
26730326Sminshall static int	margc;
26830088Sminshall static char	*margv[20];
26930088Sminshall 
270*31124Sminshall static jmp_buf	toplevel = { 0 };
27130088Sminshall static jmp_buf	peerdied;
27230088Sminshall 
27330088Sminshall extern	int errno;
27430088Sminshall 
27530088Sminshall 
27630088Sminshall static struct sockaddr_in sin;
27730088Sminshall 
27830088Sminshall static struct	servent *sp = 0;
27930088Sminshall 
28030326Sminshall static int	flushline;
28130088Sminshall 
28230326Sminshall static char	*hostname;
28330088Sminshall static char	hnamebuf[32];
28430088Sminshall 
28530088Sminshall /*
28630088Sminshall  * The following are some clocks used to decide how to interpret
28730088Sminshall  * the relationship between various variables.
28830088Sminshall  */
28930088Sminshall 
29030088Sminshall static struct {
29130088Sminshall     int
29230088Sminshall 	system,			/* what the current time is */
29330088Sminshall 	echotoggle,		/* last time user entered echo character */
29430088Sminshall 	modenegotiated,		/* last time operating mode negotiated */
29530088Sminshall 	didnetreceive,		/* last time we read data from network */
29630088Sminshall 	gotDM;			/* when did we last see a data mark */
29730326Sminshall } clocks;
29830088Sminshall 
29930088Sminshall #define	settimer(x)	clocks.x = clocks.system++
30030088Sminshall 
301*31124Sminshall /*	Various modes */
302*31124Sminshall #define	MODE_LINE(m)	(modelist[m].modetype & LINE)
303*31124Sminshall #define	MODE_LOCAL_CHARS(m)	(modelist[m].modetype &  LOCAL_CHARS)
304*31124Sminshall 
305*31124Sminshall #define	LOCAL_CHARS	0x01		/* Characters processed locally */
306*31124Sminshall #define	LINE		0x02		/* Line-by-line mode of operation */
307*31124Sminshall 
308*31124Sminshall static struct {
309*31124Sminshall     char *modedescriptions;
310*31124Sminshall     char modetype;
311*31124Sminshall } modelist[] = {
312*31124Sminshall 	{ "telnet command mode", 0 },
313*31124Sminshall 	{ "character-at-a-time mode", 0 },
314*31124Sminshall 	{ "character-at-a-time mode (local echo)", LOCAL_CHARS },
315*31124Sminshall 	{ "line-by-line mode (remote echo)", LINE | LOCAL_CHARS },
316*31124Sminshall 	{ "line-by-line mode", LINE | LOCAL_CHARS },
317*31124Sminshall 	{ "line-by-line mode (local echoing suppressed)", LINE | LOCAL_CHARS },
318*31124Sminshall 	{ "3270 mode", 0 },
319*31124Sminshall };
320*31124Sminshall 
321*31124Sminshall 
32230088Sminshall /*
323*31124Sminshall  * The following routines try to encapsulate what is system dependent
324*31124Sminshall  * (at least between 4.x and dos) which is used in telnet.c.
325*31124Sminshall  */
326*31124Sminshall 
327*31124Sminshall #if	defined(unix)
328*31124Sminshall #include <sys/ioctl.h>
329*31124Sminshall #include <sys/time.h>
330*31124Sminshall #include <signal.h>
331*31124Sminshall 
332*31124Sminshall int
333*31124Sminshall 	HaveInput;		/* There is input available to scan */
334*31124Sminshall 
335*31124Sminshall #if	defined(TN3270)
336*31124Sminshall static char	tline[200];
337*31124Sminshall char	*transcom = 0;	/* transparent mode command (default: none) */
338*31124Sminshall #endif	/* defined(TN3270) */
339*31124Sminshall 
340*31124Sminshall static struct	tchars otc = { 0 }, ntc = { 0 };
341*31124Sminshall static struct	ltchars oltc = { 0 }, nltc = { 0 };
342*31124Sminshall static struct	sgttyb ottyb = { 0 }, nttyb = { 0 };
343*31124Sminshall 
344*31124Sminshall 
345*31124Sminshall /*
346*31124Sminshall  *
347*31124Sminshall  */
348*31124Sminshall 
349*31124Sminshall static int
350*31124Sminshall TerminalAutoFlush()
351*31124Sminshall {
352*31124Sminshall #if	defined(LNOFLSH)
353*31124Sminshall     ioctl(0, TIOCLGET, (char *)&autoflush);
354*31124Sminshall     return !(autoflush&LNOFLSH);	/* if LNOFLSH, no autoflush */
355*31124Sminshall #else	/* LNOFLSH */
356*31124Sminshall     return 1;
357*31124Sminshall #endif	/* LNOFLSH */
358*31124Sminshall }
359*31124Sminshall 
360*31124Sminshall /*
361*31124Sminshall  * TerminalEditLine()
362*31124Sminshall  *
363*31124Sminshall  * Look at an input character, and decide what to do.
364*31124Sminshall  *
365*31124Sminshall  * Output:
366*31124Sminshall  *
367*31124Sminshall  *	0	Don't add this character.
368*31124Sminshall  *	1	Do add this character
369*31124Sminshall  */
370*31124Sminshall 
371*31124Sminshall int
372*31124Sminshall TerminalEditLine(c)			/* unix */
373*31124Sminshall int	c;
374*31124Sminshall {
375*31124Sminshall     void doflush(), intp(), sendbrk();
376*31124Sminshall 
377*31124Sminshall     if (c == ntc.t_intrc) {
378*31124Sminshall 	intp();
379*31124Sminshall 	return 0;
380*31124Sminshall     } else if (c == ntc.t_quitc) {
381*31124Sminshall 	sendbrk();
382*31124Sminshall 	return 0;
383*31124Sminshall     } else if (c == nltc.t_flushc) {
384*31124Sminshall 	NET2ADD(IAC, AO);
385*31124Sminshall 	if (autoflush) {
386*31124Sminshall 	    doflush();
387*31124Sminshall 	}
388*31124Sminshall 	return 0;
389*31124Sminshall     } else if (!MODE_LOCAL_CHARS(globalmode)) {
390*31124Sminshall 	if (c == nttyb.sg_kill) {
391*31124Sminshall 	    NET2ADD(IAC, EL);
392*31124Sminshall 	    return 0;
393*31124Sminshall 	} else if (c == nttyb.sg_erase) {
394*31124Sminshall 	    NET2ADD(IAC, EC);
395*31124Sminshall 	    return 0;
396*31124Sminshall 	}
397*31124Sminshall     }
398*31124Sminshall     return 1;
399*31124Sminshall }
400*31124Sminshall 
401*31124Sminshall 
402*31124Sminshall /*
403*31124Sminshall  * Flush output to the terminal
404*31124Sminshall  */
405*31124Sminshall 
406*31124Sminshall static void
407*31124Sminshall TerminalFlushOutput()				/* unix */
408*31124Sminshall {
409*31124Sminshall     (void) ioctl(fileno(stdout), TIOCFLUSH, (char *) 0);
410*31124Sminshall }
411*31124Sminshall 
412*31124Sminshall static void
413*31124Sminshall TerminalSaveState()				/* unix */
414*31124Sminshall {
415*31124Sminshall     ioctl(0, TIOCGETP, (char *)&ottyb);
416*31124Sminshall     ioctl(0, TIOCGETC, (char *)&otc);
417*31124Sminshall     ioctl(0, TIOCGLTC, (char *)&oltc);
418*31124Sminshall 
419*31124Sminshall     ntc = otc;
420*31124Sminshall     nltc = oltc;
421*31124Sminshall     nttyb = ottyb;
422*31124Sminshall }
423*31124Sminshall 
424*31124Sminshall static void
425*31124Sminshall TerminalRestoreState()				/* unix */
426*31124Sminshall {
427*31124Sminshall }
428*31124Sminshall 
429*31124Sminshall /*
430*31124Sminshall  * TerminalNewMode - set up terminal to a specific mode.
431*31124Sminshall  */
432*31124Sminshall 
433*31124Sminshall 
434*31124Sminshall static void
435*31124Sminshall TerminalNewMode(f)
436*31124Sminshall register int f;
437*31124Sminshall {
438*31124Sminshall     static int prevmode = 0;
439*31124Sminshall     struct tchars *tc;
440*31124Sminshall     struct tchars tc3;
441*31124Sminshall     struct ltchars *ltc;
442*31124Sminshall     struct sgttyb sb;
443*31124Sminshall     int onoff;
444*31124Sminshall     int old;
445*31124Sminshall     struct	tchars notc2;
446*31124Sminshall     struct	ltchars noltc2;
447*31124Sminshall     static struct	tchars notc =	{ -1, -1, -1, -1, -1, -1 };
448*31124Sminshall     static struct	ltchars noltc =	{ -1, -1, -1, -1, -1, -1 };
449*31124Sminshall 
450*31124Sminshall     globalmode = f;
451*31124Sminshall     if (prevmode == f)
452*31124Sminshall 	return;
453*31124Sminshall     old = prevmode;
454*31124Sminshall     prevmode = f;
455*31124Sminshall     sb = nttyb;
456*31124Sminshall 
457*31124Sminshall     switch (f) {
458*31124Sminshall 
459*31124Sminshall     case 0:
460*31124Sminshall 	onoff = 0;
461*31124Sminshall 	tc = &otc;
462*31124Sminshall 	ltc = &oltc;
463*31124Sminshall 	break;
464*31124Sminshall 
465*31124Sminshall     case 1:		/* remote character processing, remote echo */
466*31124Sminshall     case 2:		/* remote character processing, local echo */
467*31124Sminshall     case 6:		/* 3270 mode - like 1, but with xon/xoff local */
468*31124Sminshall 		    /* (might be nice to have "6" in telnet also...) */
469*31124Sminshall 	    sb.sg_flags |= CBREAK;
470*31124Sminshall 	    if ((f == 1) || (f == 6)) {
471*31124Sminshall 		sb.sg_flags &= ~(ECHO|CRMOD);
472*31124Sminshall 	    } else {
473*31124Sminshall 		sb.sg_flags |= ECHO|CRMOD;
474*31124Sminshall 	    }
475*31124Sminshall 	    sb.sg_erase = sb.sg_kill = -1;
476*31124Sminshall 	    if (f == 6) {
477*31124Sminshall 		tc = &tc3;
478*31124Sminshall 		tc3 = notc;
479*31124Sminshall 		    /* get XON, XOFF characters */
480*31124Sminshall 		tc3.t_startc = otc.t_startc;
481*31124Sminshall 		tc3.t_stopc = otc.t_stopc;
482*31124Sminshall 	    } else {
483*31124Sminshall 		/*
484*31124Sminshall 		 * If user hasn't specified one way or the other,
485*31124Sminshall 		 * then default to not trapping signals.
486*31124Sminshall 		 */
487*31124Sminshall 		if (!donelclchars) {
488*31124Sminshall 		    localchars = 0;
489*31124Sminshall 		}
490*31124Sminshall 		if (localchars) {
491*31124Sminshall 		    notc2 = notc;
492*31124Sminshall 		    notc2.t_intrc = ntc.t_intrc;
493*31124Sminshall 		    notc2.t_quitc = ntc.t_quitc;
494*31124Sminshall 		    tc = &notc2;
495*31124Sminshall 		} else {
496*31124Sminshall 		    tc = &notc;
497*31124Sminshall 		}
498*31124Sminshall 	    }
499*31124Sminshall 	    ltc = &noltc;
500*31124Sminshall 	    onoff = 1;
501*31124Sminshall 	    break;
502*31124Sminshall     case 3:		/* local character processing, remote echo */
503*31124Sminshall     case 4:		/* local character processing, local echo */
504*31124Sminshall     case 5:		/* local character processing, no echo */
505*31124Sminshall 	    sb.sg_flags &= ~CBREAK;
506*31124Sminshall 	    sb.sg_flags |= CRMOD;
507*31124Sminshall 	    if (f == 4)
508*31124Sminshall 		sb.sg_flags |= ECHO;
509*31124Sminshall 	    else
510*31124Sminshall 		sb.sg_flags &= ~ECHO;
511*31124Sminshall 	    notc2 = ntc;
512*31124Sminshall 	    tc = &notc2;
513*31124Sminshall 	    noltc2 = oltc;
514*31124Sminshall 	    ltc = &noltc2;
515*31124Sminshall 	    /*
516*31124Sminshall 	     * If user hasn't specified one way or the other,
517*31124Sminshall 	     * then default to trapping signals.
518*31124Sminshall 	     */
519*31124Sminshall 	    if (!donelclchars) {
520*31124Sminshall 		localchars = 1;
521*31124Sminshall 	    }
522*31124Sminshall 	    if (localchars) {
523*31124Sminshall 		notc2.t_brkc = nltc.t_flushc;
524*31124Sminshall 		noltc2.t_flushc = -1;
525*31124Sminshall 	    } else {
526*31124Sminshall 		notc2.t_intrc = notc2.t_quitc = -1;
527*31124Sminshall 	    }
528*31124Sminshall 	    noltc2.t_suspc = escape;
529*31124Sminshall 	    noltc2.t_dsuspc = -1;
530*31124Sminshall 	    onoff = 1;
531*31124Sminshall 	    break;
532*31124Sminshall 
533*31124Sminshall     default:
534*31124Sminshall 	    return;
535*31124Sminshall     }
536*31124Sminshall     ioctl(tin, TIOCSLTC, (char *)ltc);
537*31124Sminshall     ioctl(tin, TIOCSETC, (char *)tc);
538*31124Sminshall     ioctl(tin, TIOCSETP, (char *)&sb);
539*31124Sminshall #if	(!defined(TN3270)) || ((!defined(NOT43)) || defined(PUTCHAR))
540*31124Sminshall     ioctl(tin, FIONBIO, (char *)&onoff);
541*31124Sminshall     ioctl(tout, FIONBIO, (char *)&onoff);
542*31124Sminshall #endif	/* (!defined(TN3270)) || ((!defined(NOT43)) || defined(PUTCHAR)) */
543*31124Sminshall #if	defined(TN3270) && !defined(DEBUG)
544*31124Sminshall     ioctl(tin, FIOASYNC, (char *)&onoff);
545*31124Sminshall #endif	/* defined(TN3270) && !defined(DEBUG) */
546*31124Sminshall 
547*31124Sminshall     if (MODE_LINE(f)) {
548*31124Sminshall 	void doescape();
549*31124Sminshall 
550*31124Sminshall 	signal(SIGTSTP, doescape);
551*31124Sminshall     } else if (MODE_LINE(old)) {
552*31124Sminshall 	signal(SIGTSTP, SIG_DFL);
553*31124Sminshall 	sigsetmask(sigblock(0) & ~(1<<(SIGTSTP-1)));
554*31124Sminshall     }
555*31124Sminshall }
556*31124Sminshall 
557*31124Sminshall 
558*31124Sminshall static void
559*31124Sminshall NetNonblockingIO(fd, onoff)				/* unix */
560*31124Sminshall int
561*31124Sminshall 	fd,
562*31124Sminshall 	onoff;
563*31124Sminshall {
564*31124Sminshall     ioctl(net, FIONBIO, (char *)&onoff);
565*31124Sminshall }
566*31124Sminshall 
567*31124Sminshall static void
568*31124Sminshall NetSigIO(fd, onoff)				/* unix */
569*31124Sminshall int
570*31124Sminshall 	fd,
571*31124Sminshall 	onoff;
572*31124Sminshall {
573*31124Sminshall     ioctl(net, FIOASYNC, (char *)&onoff);	/* hear about input */
574*31124Sminshall }
575*31124Sminshall 
576*31124Sminshall static void
577*31124Sminshall NetSetPgrp(fd)				/* unix */
578*31124Sminshall int fd;
579*31124Sminshall {
580*31124Sminshall     int myPid;
581*31124Sminshall 
582*31124Sminshall     myPid = getpid();
583*31124Sminshall #if	defined(NOT43)
584*31124Sminshall     myPid = -myPid;
585*31124Sminshall #endif	/* defined(NOT43) */
586*31124Sminshall     ioctl(net, SIOCSPGRP, (char *)&myPid);	/* set my pid */
587*31124Sminshall }
588*31124Sminshall 
589*31124Sminshall 
590*31124Sminshall #endif	/* defined(unix) */
591*31124Sminshall 
592*31124Sminshall #if	defined(MSDOS)
593*31124Sminshall #include <time.h>
594*31124Sminshall 
595*31124Sminshall #if	!defined(SO_OOBINLINE)
596*31124Sminshall #define	SO_OOBINLINE
597*31124Sminshall #endif	/* !defined(SO_OOBINLINE) */
598*31124Sminshall 
599*31124Sminshall 
600*31124Sminshall static char
601*31124Sminshall     termEraseChar,
602*31124Sminshall     termFlushChar,
603*31124Sminshall     termIntChar,
604*31124Sminshall     termKillChar,
605*31124Sminshall     termQuitChar,
606*31124Sminshall     termEofChar;
607*31124Sminshall 
608*31124Sminshall 
609*31124Sminshall /*
610*31124Sminshall  * Flush output to the terminal
611*31124Sminshall  */
612*31124Sminshall 
613*31124Sminshall static void
614*31124Sminshall TerminalFlushOutput()				/* MSDOS */
615*31124Sminshall {
616*31124Sminshall }
617*31124Sminshall 
618*31124Sminshall static void
619*31124Sminshall TerminalSaveState()				/* MSDOS */
620*31124Sminshall {
621*31124Sminshall }
622*31124Sminshall 
623*31124Sminshall static void
624*31124Sminshall TerminalRestoreState()				/* MSDOS */
625*31124Sminshall {
626*31124Sminshall }
627*31124Sminshall 
628*31124Sminshall static void
629*31124Sminshall NetNonblockingIO(fd, onoff)				/* MSDOS */
630*31124Sminshall int
631*31124Sminshall 	fd,
632*31124Sminshall 	onoff;
633*31124Sminshall {
634*31124Sminshall     if (SetSockOpt(net, SOL_SOCKET, SO_NONBLOCKING, onoff)) {
635*31124Sminshall 	perror("setsockop (SO_NONBLOCKING) ");
636*31124Sminshall 	XXX();
637*31124Sminshall     }
638*31124Sminshall }
639*31124Sminshall 
640*31124Sminshall static void
641*31124Sminshall NetSigIO(fd)				/* MSDOS */
642*31124Sminshall int fd;
643*31124Sminshall {
644*31124Sminshall }
645*31124Sminshall 
646*31124Sminshall static void
647*31124Sminshall NetSetPgrp(fd)				/* MSDOS */
648*31124Sminshall int fd;
649*31124Sminshall {
650*31124Sminshall }
651*31124Sminshall 
652*31124Sminshall 
653*31124Sminshall #endif	/* defined(MSDOS) */
654*31124Sminshall 
655*31124Sminshall /*
65630326Sminshall  * Initialize variables.
65730326Sminshall  */
65830326Sminshall 
65930326Sminshall static void
66030326Sminshall tninit()
66130326Sminshall {
66230326Sminshall     Ifrontp = Ibackp = Ibuf;
66330326Sminshall     tfrontp = tbackp = ttyobuf;
66430326Sminshall     nfrontp = nbackp = netobuf;
66530326Sminshall 
66630326Sminshall     /* Don't change telnetport */
66730722Sminshall     SB_CLEAR();
66830722Sminshall     ClearArray(hisopts);
66930722Sminshall     ClearArray(myopts);
67030722Sminshall     sbp = sibuf;
67130722Sminshall     tbp = tibuf;
67230326Sminshall 
67330722Sminshall     connected = net = scc = tcc = In3270 = ISend = 0;
67430722Sminshall     telnetport = 0;
675*31124Sminshall #if	defined(unix)
676*31124Sminshall     HaveInput = 0;
677*31124Sminshall #endif	/* defined(unix) */
67830722Sminshall 
67930722Sminshall     SYNCHing = 0;
68030722Sminshall     Sent3270TerminalType = 0;
68130722Sminshall 
68230722Sminshall     errno = 0;
68330722Sminshall 
68430722Sminshall     flushline = 0;
68530722Sminshall 
68630326Sminshall     /* Don't change NetTrace */
68730326Sminshall 
68830326Sminshall     escape = CONTROL(']');
68930326Sminshall     echoc = CONTROL('E');
69030326Sminshall 
69130326Sminshall     flushline = 1;
69230326Sminshall     sp = getservbyname("telnet", "tcp");
69330326Sminshall     if (sp == 0) {
69430326Sminshall 	ExitString(stderr, "telnet: tcp/telnet: unknown service\n",1);
69530326Sminshall 	/*NOTREACHED*/
69630326Sminshall     }
69730326Sminshall 
69830326Sminshall #if	defined(TN3270)
69930722Sminshall     init_ctlr();		/* Initialize some things */
70030722Sminshall     init_keyboard();
70130722Sminshall     init_screen();
70230722Sminshall     init_system();
70330326Sminshall #endif	/* defined(TN3270) */
70430326Sminshall }
70530326Sminshall 
70630326Sminshall /*
70730088Sminshall  * Various utility routines.
70830088Sminshall  */
70930088Sminshall 
71030088Sminshall static void
71130088Sminshall makeargv()
71230088Sminshall {
71330088Sminshall 	register char *cp;
71430088Sminshall 	register char **argp = margv;
71530088Sminshall 
71630088Sminshall 	margc = 0;
71730088Sminshall 	for (cp = line; *cp;) {
71830088Sminshall 		while (isspace(*cp))
71930088Sminshall 			cp++;
72030088Sminshall 		if (*cp == '\0')
72130088Sminshall 			break;
72230088Sminshall 		*argp++ = cp;
72330088Sminshall 		margc += 1;
72430088Sminshall 		while (*cp != '\0' && !isspace(*cp))
72530088Sminshall 			cp++;
72630088Sminshall 		if (*cp == '\0')
72730088Sminshall 			break;
72830088Sminshall 		*cp++ = '\0';
72930088Sminshall 	}
73030088Sminshall 	*argp++ = 0;
73130088Sminshall }
73230088Sminshall 
73330088Sminshall static char *ambiguous;		/* special return value */
73430088Sminshall #define Ambiguous(t)	((t)&ambiguous)
73530088Sminshall 
73630088Sminshall 
73730088Sminshall static char **
73830088Sminshall genget(name, table, next)
73930088Sminshall char	*name;		/* name to match */
74030088Sminshall char	**table;		/* name entry in table */
74130088Sminshall char	**(*next)();	/* routine to return next entry in table */
74230088Sminshall {
74330088Sminshall 	register char *p, *q;
74430088Sminshall 	register char **c, **found;
74530088Sminshall 	register int nmatches, longest;
74630088Sminshall 
74730088Sminshall 	longest = 0;
74830088Sminshall 	nmatches = 0;
74930088Sminshall 	found = 0;
75030088Sminshall 	for (c = table; (p = *c) != 0; c = (*next)(c)) {
75130088Sminshall 		for (q = name;
75230088Sminshall 		    (*q == *p) || (isupper(*q) && tolower(*q) == *p); p++, q++)
75330088Sminshall 			if (*q == 0)		/* exact match? */
75430088Sminshall 				return (c);
75530088Sminshall 		if (!*q) {			/* the name was a prefix */
75630088Sminshall 			if (q - name > longest) {
75730088Sminshall 				longest = q - name;
75830088Sminshall 				nmatches = 1;
75930088Sminshall 				found = c;
76030088Sminshall 			} else if (q - name == longest)
76130088Sminshall 				nmatches++;
76230088Sminshall 		}
76330088Sminshall 	}
76430088Sminshall 	if (nmatches > 1)
76530088Sminshall 		return Ambiguous(char **);
76630088Sminshall 	return (found);
76730088Sminshall }
76830088Sminshall 
76930088Sminshall /*
77030088Sminshall  * Make a character string into a number.
77130088Sminshall  *
77230088Sminshall  * Todo:  1.  Could take random integers (12, 0x12, 012, 0b1).
77330088Sminshall  */
77430088Sminshall 
77530088Sminshall static
77630088Sminshall special(s)
77730088Sminshall register char *s;
77830088Sminshall {
77930088Sminshall 	register char c;
78030088Sminshall 	char b;
78130088Sminshall 
78230088Sminshall 	switch (*s) {
78330088Sminshall 	case '^':
78430088Sminshall 		b = *++s;
78530088Sminshall 		if (b == '?') {
78630088Sminshall 		    c = b | 0x40;		/* DEL */
78730088Sminshall 		} else {
78830088Sminshall 		    c = b & 0x1f;
78930088Sminshall 		}
79030088Sminshall 		break;
79130088Sminshall 	default:
79230088Sminshall 		c = *s;
79330088Sminshall 		break;
79430088Sminshall 	}
79530088Sminshall 	return c;
79630088Sminshall }
79730088Sminshall 
79830088Sminshall /*
79930088Sminshall  * Construct a control character sequence
80030088Sminshall  * for a special character.
80130088Sminshall  */
80230088Sminshall static char *
80330088Sminshall control(c)
80430088Sminshall 	register int c;
80530088Sminshall {
80630088Sminshall 	static char buf[3];
80730088Sminshall 
80830088Sminshall 	if (c == 0x7f)
80930088Sminshall 		return ("^?");
81030088Sminshall 	if (c == '\377') {
81130088Sminshall 		return "off";
81230088Sminshall 	}
81330088Sminshall 	if (c >= 0x20) {
81430088Sminshall 		buf[0] = c;
81530088Sminshall 		buf[1] = 0;
81630088Sminshall 	} else {
81730088Sminshall 		buf[0] = '^';
81830088Sminshall 		buf[1] = '@'+c;
81930088Sminshall 		buf[2] = 0;
82030088Sminshall 	}
82130088Sminshall 	return (buf);
82230088Sminshall }
82330088Sminshall 
82430088Sminshall 
82530088Sminshall /*
82630088Sminshall  * upcase()
82730088Sminshall  *
82830088Sminshall  *	Upcase (in place) the argument.
82930088Sminshall  */
83030088Sminshall 
83130088Sminshall static void
83230088Sminshall upcase(argument)
83330088Sminshall register char *argument;
83430088Sminshall {
83530088Sminshall     register int c;
83630088Sminshall 
83730088Sminshall     while ((c = *argument) != 0) {
83830088Sminshall 	if (islower(c)) {
83930088Sminshall 	    *argument = toupper(c);
84030088Sminshall 	}
84130088Sminshall 	argument++;
84230088Sminshall     }
84330088Sminshall }
844*31124Sminshall 
845*31124Sminshall /*
846*31124Sminshall  * SetSockOpt()
847*31124Sminshall  *
848*31124Sminshall  * Compensate for differences in 4.2 and 4.3 systems.
849*31124Sminshall  */
850*31124Sminshall 
851*31124Sminshall static int
852*31124Sminshall SetSockOpt(fd, level, option, yesno)
853*31124Sminshall int
854*31124Sminshall 	fd,
855*31124Sminshall 	level,
856*31124Sminshall 	option,
857*31124Sminshall 	yesno;
858*31124Sminshall {
859*31124Sminshall #ifndef	NOT43
860*31124Sminshall     return setsockopt(fd, level, option,
861*31124Sminshall 				(char *)&yesno, sizeof yesno);
862*31124Sminshall #else	/* NOT43 */
863*31124Sminshall     if (yesno == 0) {		/* Can't do that in 4.2! */
864*31124Sminshall 	fprintf(stderr, "Error: attempt to turn off an option 0x%x.\n",
865*31124Sminshall 				option);
866*31124Sminshall 	return -1;
867*31124Sminshall     }
868*31124Sminshall     return setsockopt(fd, level, option, 0, 0);
869*31124Sminshall #endif	/* NOT43 */
870*31124Sminshall }
87130088Sminshall 
87230088Sminshall /*
87330088Sminshall  * The following are routines used to print out debugging information.
87430088Sminshall  */
87530088Sminshall 
87630088Sminshall 
87730088Sminshall static void
87830088Sminshall Dump(direction, buffer, length)
87930088Sminshall char	direction;
88030088Sminshall char	*buffer;
88130088Sminshall int	length;
88230088Sminshall {
88330088Sminshall #   define BYTES_PER_LINE	32
88430088Sminshall #   define min(x,y)	((x<y)? x:y)
88530088Sminshall     char *pThis;
88630088Sminshall     int offset;
88730088Sminshall 
88830088Sminshall     offset = 0;
88930088Sminshall 
89030088Sminshall     while (length) {
89130088Sminshall 	/* print one line */
89230088Sminshall 	fprintf(NetTrace, "%c 0x%x\t", direction, offset);
89330088Sminshall 	pThis = buffer;
89430088Sminshall 	buffer = buffer+min(length, BYTES_PER_LINE);
89530088Sminshall 	while (pThis < buffer) {
89630088Sminshall 	    fprintf(NetTrace, "%.2x", (*pThis)&0xff);
89730088Sminshall 	    pThis++;
89830088Sminshall 	}
89930088Sminshall 	fprintf(NetTrace, "\n");
90030088Sminshall 	length -= BYTES_PER_LINE;
90130088Sminshall 	offset += BYTES_PER_LINE;
90230088Sminshall 	if (length < 0) {
90330088Sminshall 	    return;
90430088Sminshall 	}
90530088Sminshall 	/* find next unique line */
90630088Sminshall     }
90730088Sminshall }
90830088Sminshall 
90930088Sminshall 
91030088Sminshall /*VARARGS*/
91130088Sminshall static void
91230088Sminshall printoption(direction, fmt, option, what)
91330088Sminshall 	char *direction, *fmt;
91430088Sminshall 	int option, what;
91530088Sminshall {
91630088Sminshall 	if (!showoptions)
91730088Sminshall 		return;
91830088Sminshall 	fprintf(NetTrace, "%s ", direction+1);
91930088Sminshall 	if (fmt == doopt)
92030088Sminshall 		fmt = "do";
92130088Sminshall 	else if (fmt == dont)
92230088Sminshall 		fmt = "dont";
92330088Sminshall 	else if (fmt == will)
92430088Sminshall 		fmt = "will";
92530088Sminshall 	else if (fmt == wont)
92630088Sminshall 		fmt = "wont";
92730088Sminshall 	else
92830088Sminshall 		fmt = "???";
92930088Sminshall 	if (option < (sizeof telopts/sizeof telopts[0]))
93030088Sminshall 		fprintf(NetTrace, "%s %s", fmt, telopts[option]);
93130088Sminshall 	else
93230088Sminshall 		fprintf(NetTrace, "%s %d", fmt, option);
93330088Sminshall 	if (*direction == '<') {
93430088Sminshall 		fprintf(NetTrace, "\r\n");
93530088Sminshall 		return;
93630088Sminshall 	}
93730088Sminshall 	fprintf(NetTrace, " (%s)\r\n", what ? "reply" : "don't reply");
93830088Sminshall }
93930088Sminshall 
94030088Sminshall static void
94130088Sminshall printsub(direction, pointer, length)
94230088Sminshall char	*direction,		/* "<" or ">" */
94330088Sminshall 	*pointer;		/* where suboption data sits */
94430088Sminshall int	length;			/* length of suboption data */
94530088Sminshall {
94630088Sminshall     if (showoptions) {
94730088Sminshall 	fprintf(NetTrace, "%s suboption ",
94830088Sminshall 				(direction[0] == '<')? "Received":"Sent");
94930088Sminshall 	switch (pointer[0]) {
95030088Sminshall 	case TELOPT_TTYPE:
95130088Sminshall 	    fprintf(NetTrace, "Terminal type ");
95230088Sminshall 	    switch (pointer[1]) {
95330088Sminshall 	    case TELQUAL_IS:
95430088Sminshall 		{
95530088Sminshall 		    char tmpbuf[sizeof subbuffer];
95630088Sminshall 		    int minlen = min(length, sizeof tmpbuf);
95730088Sminshall 
95830088Sminshall 		    bcopy(pointer+2, tmpbuf, minlen);
95930088Sminshall 		    tmpbuf[minlen-1] = 0;
96030088Sminshall 		    fprintf(NetTrace, "is %s.\n", tmpbuf);
96130088Sminshall 		}
96230088Sminshall 		break;
96330088Sminshall 	    case TELQUAL_SEND:
96430088Sminshall 		fprintf(NetTrace, "- request to send.\n");
96530088Sminshall 		break;
96630088Sminshall 	    default:
96730088Sminshall 		fprintf(NetTrace,
96830088Sminshall 				"- unknown qualifier %d (0x%x).\n", pointer[1]);
96930088Sminshall 	    }
97030088Sminshall 	    break;
97130088Sminshall 	default:
97230088Sminshall 	    fprintf(NetTrace, "Unknown option %d (0x%x)\n",
97330088Sminshall 					pointer[0], pointer[0]);
97430088Sminshall 	}
97530088Sminshall     }
97630088Sminshall }
97730088Sminshall 
97830088Sminshall /*
97930088Sminshall  * Check to see if any out-of-band data exists on a socket (for
98030088Sminshall  * Telnet "synch" processing).
98130088Sminshall  */
98230088Sminshall 
98330088Sminshall static int
98430088Sminshall stilloob(s)
98530088Sminshall int	s;		/* socket number */
98630088Sminshall {
98730088Sminshall     static struct timeval timeout = { 0 };
98830088Sminshall     fd_set	excepts;
98930088Sminshall     int value;
99030088Sminshall 
99130088Sminshall     do {
99230088Sminshall 	FD_ZERO(&excepts);
99330088Sminshall 	FD_SET(s, &excepts);
99430088Sminshall 	value = select(s+1, (fd_set *)0, (fd_set *)0, &excepts, &timeout);
99530088Sminshall     } while ((value == -1) && (errno == EINTR));
99630088Sminshall 
99730088Sminshall     if (value < 0) {
99830088Sminshall 	perror("select");
99930088Sminshall 	quit();
100030088Sminshall     }
100130088Sminshall     if (FD_ISSET(s, &excepts)) {
100230088Sminshall 	return 1;
100330088Sminshall     } else {
100430088Sminshall 	return 0;
100530088Sminshall     }
100630088Sminshall }
100730088Sminshall 
100830088Sminshall 
100930088Sminshall /*
101030088Sminshall  *  netflush
101130088Sminshall  *		Send as much data as possible to the network,
101230088Sminshall  *	handling requests for urgent data.
101330088Sminshall  *
101430088Sminshall  *		The return value indicates whether we did any
101530088Sminshall  *	useful work.
101630088Sminshall  */
101730088Sminshall 
101830088Sminshall 
101930088Sminshall int
102030088Sminshall netflush()
102130088Sminshall {
102230088Sminshall     int n;
102330088Sminshall 
102430088Sminshall     if ((n = nfrontp - nbackp) > 0) {
102530088Sminshall 	if (!neturg) {
102630088Sminshall 	    n = write(net, nbackp, n);	/* normal write */
102730088Sminshall 	} else {
102830088Sminshall 	    n = neturg - nbackp;
102930088Sminshall 	    /*
103030088Sminshall 	     * In 4.2 (and 4.3) systems, there is some question about
103130088Sminshall 	     * what byte in a sendOOB operation is the "OOB" data.
103230088Sminshall 	     * To make ourselves compatible, we only send ONE byte
103330088Sminshall 	     * out of band, the one WE THINK should be OOB (though
103430088Sminshall 	     * we really have more the TCP philosophy of urgent data
103530088Sminshall 	     * rather than the Unix philosophy of OOB data).
103630088Sminshall 	     */
103730088Sminshall 	    if (n > 1) {
103830088Sminshall 		n = send(net, nbackp, n-1, 0);	/* send URGENT all by itself */
103930088Sminshall 	    } else {
104030088Sminshall 		n = send(net, nbackp, n, MSG_OOB);	/* URGENT data */
104130088Sminshall 	    }
104230088Sminshall 	}
104330088Sminshall     }
104430088Sminshall     if (n < 0) {
104530088Sminshall 	if (errno != ENOBUFS && errno != EWOULDBLOCK) {
104630088Sminshall 	    setcommandmode();
104730088Sminshall 	    perror(hostname);
104830088Sminshall 	    close(net);
104930088Sminshall 	    neturg = 0;
105030088Sminshall 	    longjmp(peerdied, -1);
105130088Sminshall 	    /*NOTREACHED*/
105230088Sminshall 	}
105330088Sminshall 	n = 0;
105430088Sminshall     }
105530088Sminshall     if (netdata && n) {
105630088Sminshall 	Dump('>', nbackp, n);
105730088Sminshall     }
105830088Sminshall     nbackp += n;
105930088Sminshall     if (nbackp >= neturg) {
106030088Sminshall 	neturg = 0;
106130088Sminshall     }
106230088Sminshall     if (nbackp == nfrontp) {
106330088Sminshall 	nbackp = nfrontp = netobuf;
106430088Sminshall     }
106530088Sminshall     return n > 0;
106630088Sminshall }
106730088Sminshall 
106830088Sminshall /*
106930088Sminshall  * nextitem()
107030088Sminshall  *
107130088Sminshall  *	Return the address of the next "item" in the TELNET data
107230088Sminshall  * stream.  This will be the address of the next character if
107330088Sminshall  * the current address is a user data character, or it will
107430088Sminshall  * be the address of the character following the TELNET command
107530088Sminshall  * if the current address is a TELNET IAC ("I Am a Command")
107630088Sminshall  * character.
107730088Sminshall  */
107830088Sminshall 
107930088Sminshall static char *
108030088Sminshall nextitem(current)
108130088Sminshall char	*current;
108230088Sminshall {
108330088Sminshall     if ((*current&0xff) != IAC) {
108430088Sminshall 	return current+1;
108530088Sminshall     }
108630088Sminshall     switch (*(current+1)&0xff) {
108730088Sminshall     case DO:
108830088Sminshall     case DONT:
108930088Sminshall     case WILL:
109030088Sminshall     case WONT:
109130088Sminshall 	return current+3;
109230088Sminshall     case SB:		/* loop forever looking for the SE */
109330088Sminshall 	{
109430088Sminshall 	    register char *look = current+2;
109530088Sminshall 
109630088Sminshall 	    for (;;) {
109730088Sminshall 		if ((*look++&0xff) == IAC) {
109830088Sminshall 		    if ((*look++&0xff) == SE) {
109930088Sminshall 			return look;
110030088Sminshall 		    }
110130088Sminshall 		}
110230088Sminshall 	    }
110330088Sminshall 	}
110430088Sminshall     default:
110530088Sminshall 	return current+2;
110630088Sminshall     }
110730088Sminshall }
110830088Sminshall /*
110930088Sminshall  * netclear()
111030088Sminshall  *
111130088Sminshall  *	We are about to do a TELNET SYNCH operation.  Clear
111230088Sminshall  * the path to the network.
111330088Sminshall  *
111430088Sminshall  *	Things are a bit tricky since we may have sent the first
111530088Sminshall  * byte or so of a previous TELNET command into the network.
111630088Sminshall  * So, we have to scan the network buffer from the beginning
111730088Sminshall  * until we are up to where we want to be.
111830088Sminshall  *
111930088Sminshall  *	A side effect of what we do, just to keep things
112030088Sminshall  * simple, is to clear the urgent data pointer.  The principal
112130088Sminshall  * caller should be setting the urgent data pointer AFTER calling
112230088Sminshall  * us in any case.
112330088Sminshall  */
112430088Sminshall 
112530088Sminshall static void
112630088Sminshall netclear()
112730088Sminshall {
112830088Sminshall     register char *thisitem, *next;
112930088Sminshall     char *good;
113030088Sminshall #define	wewant(p)	((nfrontp > p) && ((*p&0xff) == IAC) && \
113130088Sminshall 				((*(p+1)&0xff) != EC) && ((*(p+1)&0xff) != EL))
113230088Sminshall 
113330088Sminshall     thisitem = netobuf;
113430088Sminshall 
113530088Sminshall     while ((next = nextitem(thisitem)) <= nbackp) {
113630088Sminshall 	thisitem = next;
113730088Sminshall     }
113830088Sminshall 
113930088Sminshall     /* Now, thisitem is first before/at boundary. */
114030088Sminshall 
114130088Sminshall     good = netobuf;	/* where the good bytes go */
114230088Sminshall 
114330088Sminshall     while (nfrontp > thisitem) {
114430088Sminshall 	if (wewant(thisitem)) {
114530088Sminshall 	    int length;
114630088Sminshall 
114730088Sminshall 	    next = thisitem;
114830088Sminshall 	    do {
114930088Sminshall 		next = nextitem(next);
115030088Sminshall 	    } while (wewant(next) && (nfrontp > next));
115130088Sminshall 	    length = next-thisitem;
115230088Sminshall 	    bcopy(thisitem, good, length);
115330088Sminshall 	    good += length;
115430088Sminshall 	    thisitem = next;
115530088Sminshall 	} else {
115630088Sminshall 	    thisitem = nextitem(thisitem);
115730088Sminshall 	}
115830088Sminshall     }
115930088Sminshall 
116030088Sminshall     nbackp = netobuf;
116130088Sminshall     nfrontp = good;		/* next byte to be sent */
116230088Sminshall     neturg = 0;
116330088Sminshall }
116430088Sminshall 
116530088Sminshall /*
116630088Sminshall  * These routines add various telnet commands to the data stream.
116730088Sminshall  */
116830088Sminshall 
116930088Sminshall #if	defined(NOT43)
117030088Sminshall static int
117130088Sminshall #else	/* defined(NOT43) */
117230088Sminshall static void
117330088Sminshall #endif	/* defined(NOT43) */
117430088Sminshall dosynch()
117530088Sminshall {
117630088Sminshall     netclear();			/* clear the path to the network */
117730088Sminshall     NET2ADD(IAC, DM);
117830088Sminshall     neturg = NETLOC()-1;	/* Some systems are off by one XXX */
117930088Sminshall 
118030088Sminshall #if	defined(NOT43)
118130088Sminshall     return 0;
118230088Sminshall #endif	/* defined(NOT43) */
118330088Sminshall }
118430088Sminshall 
118530088Sminshall static void
118630088Sminshall doflush()
118730088Sminshall {
118830088Sminshall     NET2ADD(IAC, DO);
118930088Sminshall     NETADD(TELOPT_TM);
119030088Sminshall     flushline = 1;
119130088Sminshall     flushout = 1;
119230088Sminshall     ttyflush();
119330088Sminshall     /* do printoption AFTER flush, otherwise the output gets tossed... */
119430088Sminshall     printoption("<SENT", doopt, TELOPT_TM, 0);
119530088Sminshall }
119630088Sminshall 
119730088Sminshall static void
119830088Sminshall intp()
119930088Sminshall {
120030088Sminshall     NET2ADD(IAC, IP);
120130088Sminshall     if (autoflush) {
120230088Sminshall 	doflush();
120330088Sminshall     }
120430088Sminshall     if (autosynch) {
120530088Sminshall 	dosynch();
120630088Sminshall     }
120730088Sminshall }
120830088Sminshall 
120930088Sminshall static void
121030088Sminshall sendbrk()
121130088Sminshall {
121230088Sminshall     NET2ADD(IAC, BREAK);
121330088Sminshall     if (autoflush) {
121430088Sminshall 	doflush();
121530088Sminshall     }
121630088Sminshall     if (autosynch) {
121730088Sminshall 	dosynch();
121830088Sminshall     }
121930088Sminshall }
122030088Sminshall 
122130088Sminshall /*
122230088Sminshall  *		Send as much data as possible to the terminal.
122330088Sminshall  *
122430088Sminshall  *		The return value indicates whether we did any
122530088Sminshall  *	useful work.
122630088Sminshall  */
122730088Sminshall 
122830088Sminshall 
122930088Sminshall static int
123030088Sminshall ttyflush()
123130088Sminshall {
123230088Sminshall     int n;
123330088Sminshall 
123430088Sminshall     if ((n = tfrontp - tbackp) > 0) {
123530088Sminshall 	if (!(SYNCHing||flushout)) {
123630088Sminshall 	    n = write(tout, tbackp, n);
123730088Sminshall 	} else {
1238*31124Sminshall 	    TerminalFlushOutput();
123930088Sminshall 	    /* we leave 'n' alone! */
124030088Sminshall 	}
124130088Sminshall     }
124230088Sminshall     if (n >= 0) {
124330088Sminshall 	tbackp += n;
124430088Sminshall 	if (tbackp == tfrontp) {
124530088Sminshall 	    tbackp = tfrontp = ttyobuf;
124630088Sminshall 	}
124730088Sminshall     }
124830088Sminshall     return n > 0;
124930088Sminshall }
125030088Sminshall 
125130088Sminshall #if	defined(TN3270)
125230088Sminshall 
125330088Sminshall #if	defined(unix)
125430088Sminshall static void
125530088Sminshall inputAvailable()
125630088Sminshall {
125730088Sminshall     HaveInput = 1;
125830088Sminshall }
125930088Sminshall #endif	/* defined(unix) */
126030088Sminshall 
126130088Sminshall void
126230088Sminshall outputPurge()
126330088Sminshall {
126430088Sminshall     int tmp = flushout;
126530088Sminshall 
126630088Sminshall     flushout = 1;
126730088Sminshall 
126830088Sminshall     ttyflush();
126930088Sminshall 
127030088Sminshall     flushout = tmp;
127130088Sminshall }
127230088Sminshall 
127330088Sminshall #endif	/* defined(TN3270) */
127430088Sminshall 
127530088Sminshall #if	defined(unix)
127630088Sminshall /*
127730088Sminshall  * Various signal handling routines.
127830088Sminshall  */
127930088Sminshall 
128030088Sminshall static void
128130088Sminshall deadpeer()
128230088Sminshall {
128330088Sminshall 	setcommandmode();
128430088Sminshall 	longjmp(peerdied, -1);
128530088Sminshall }
128630088Sminshall 
128730088Sminshall static void
128830088Sminshall intr()
128930088Sminshall {
129030088Sminshall     if (localchars) {
129130088Sminshall 	intp();
129230088Sminshall 	return;
129330088Sminshall     }
129430088Sminshall     setcommandmode();
129530088Sminshall     longjmp(toplevel, -1);
129630088Sminshall }
129730088Sminshall 
129830088Sminshall static void
129930088Sminshall intr2()
130030088Sminshall {
130130088Sminshall     if (localchars) {
130230088Sminshall 	sendbrk();
130330088Sminshall 	return;
130430088Sminshall     }
130530088Sminshall }
130630088Sminshall 
130730088Sminshall static void
130830088Sminshall doescape()
130930088Sminshall {
131030088Sminshall     command(0);
131130088Sminshall }
131230088Sminshall #endif	/* defined(unix) */
131330088Sminshall 
131430088Sminshall /*
131530088Sminshall  * These routines decides on what the mode should be (based on the values
131630088Sminshall  * of various global variables).
131730088Sminshall  */
131830088Sminshall 
131930088Sminshall 
132030088Sminshall static
132130088Sminshall getconnmode()
132230088Sminshall {
132330088Sminshall     static char newmode[16] =
132430088Sminshall 			{ 4, 5, 3, 3, 2, 2, 1, 1, 6, 6, 6, 6, 6, 6, 6, 6 };
132530088Sminshall     int modeindex = 0;
132630088Sminshall 
132730088Sminshall     if (dontlecho && (clocks.echotoggle > clocks.modenegotiated)) {
132830088Sminshall 	modeindex += 1;
132930088Sminshall     }
133030088Sminshall     if (hisopts[TELOPT_ECHO]) {
133130088Sminshall 	modeindex += 2;
133230088Sminshall     }
133330088Sminshall     if (hisopts[TELOPT_SGA]) {
133430088Sminshall 	modeindex += 4;
133530088Sminshall     }
133630088Sminshall     if (In3270) {
133730088Sminshall 	modeindex += 8;
133830088Sminshall     }
133930088Sminshall     return newmode[modeindex];
134030088Sminshall }
134130088Sminshall 
134230088Sminshall void
134330088Sminshall setconnmode()
134430088Sminshall {
1345*31124Sminshall     TerminalNewMode(getconnmode());
134630088Sminshall }
134730088Sminshall 
134830088Sminshall 
134930088Sminshall void
135030088Sminshall setcommandmode()
135130088Sminshall {
1352*31124Sminshall     TerminalNewMode(0);
135330088Sminshall }
135430088Sminshall 
135530088Sminshall static void
135630088Sminshall willoption(option, reply)
135730088Sminshall 	int option, reply;
135830088Sminshall {
135930088Sminshall 	char *fmt;
136030088Sminshall 
136130088Sminshall 	switch (option) {
136230088Sminshall 
136330368Sminshall 	case TELOPT_ECHO:
136430088Sminshall #	if defined(TN3270)
136530368Sminshall 	    /*
136630368Sminshall 	     * The following is a pain in the rear-end.
136730368Sminshall 	     * Various IBM servers (some versions of Wiscnet,
136830368Sminshall 	     * possibly Fibronics/Spartacus, and who knows who
136930368Sminshall 	     * else) will NOT allow us to send "DO SGA" too early
137030368Sminshall 	     * in the setup proceedings.  On the other hand,
137130368Sminshall 	     * 4.2 servers (telnetd) won't set SGA correctly.
137230368Sminshall 	     * So, we are stuck.  Empirically (but, based on
137330368Sminshall 	     * a VERY small sample), the IBM servers don't send
137430368Sminshall 	     * out anything about ECHO, so we postpone our sending
137530368Sminshall 	     * "DO SGA" until we see "WILL ECHO" (which 4.2 servers
137630368Sminshall 	     * DO send).
137730368Sminshall 	     */
137830368Sminshall 	    {
137930368Sminshall 		if (askedSGA == 0) {
138030368Sminshall 		    askedSGA = 1;
138130368Sminshall 		    if (!hisopts[TELOPT_SGA]) {
138230368Sminshall 			willoption(TELOPT_SGA, 0);
138330368Sminshall 		    }
138430368Sminshall 		}
138530368Sminshall 	    }
138630368Sminshall 		/* Fall through */
138730088Sminshall 	case TELOPT_EOR:
138830088Sminshall 	case TELOPT_BINARY:
138930088Sminshall #endif	/* defined(TN3270) */
139030088Sminshall 	case TELOPT_SGA:
139130088Sminshall 		settimer(modenegotiated);
139230088Sminshall 		hisopts[option] = 1;
139330088Sminshall 		fmt = doopt;
139430088Sminshall 		setconnmode();		/* possibly set new tty mode */
139530088Sminshall 		break;
139630088Sminshall 
139730088Sminshall 	case TELOPT_TM:
139830088Sminshall 		return;			/* Never reply to TM will's/wont's */
139930088Sminshall 
140030088Sminshall 	default:
140130088Sminshall 		fmt = dont;
140230088Sminshall 		break;
140330088Sminshall 	}
140430088Sminshall 	sprintf(nfrontp, fmt, option);
140530088Sminshall 	nfrontp += sizeof (dont) - 2;
140630088Sminshall 	if (reply)
140730088Sminshall 		printoption(">SENT", fmt, option, reply);
140830088Sminshall 	else
140930088Sminshall 		printoption("<SENT", fmt, option, reply);
141030088Sminshall }
141130088Sminshall 
141230088Sminshall static void
141330088Sminshall wontoption(option, reply)
141430088Sminshall 	int option, reply;
141530088Sminshall {
141630088Sminshall 	char *fmt;
141730088Sminshall 
141830088Sminshall 	switch (option) {
141930088Sminshall 
142030088Sminshall 	case TELOPT_ECHO:
142130088Sminshall 	case TELOPT_SGA:
142230088Sminshall 		settimer(modenegotiated);
142330088Sminshall 		hisopts[option] = 0;
142430088Sminshall 		fmt = dont;
142530088Sminshall 		setconnmode();			/* Set new tty mode */
142630088Sminshall 		break;
142730088Sminshall 
142830088Sminshall 	case TELOPT_TM:
142930088Sminshall 		return;		/* Never reply to TM will's/wont's */
143030088Sminshall 
143130088Sminshall 	default:
143230088Sminshall 		fmt = dont;
143330088Sminshall 	}
143430088Sminshall 	sprintf(nfrontp, fmt, option);
143530088Sminshall 	nfrontp += sizeof (doopt) - 2;
143630088Sminshall 	if (reply)
143730088Sminshall 		printoption(">SENT", fmt, option, reply);
143830088Sminshall 	else
143930088Sminshall 		printoption("<SENT", fmt, option, reply);
144030088Sminshall }
144130088Sminshall 
144230088Sminshall static void
144330088Sminshall dooption(option)
144430088Sminshall 	int option;
144530088Sminshall {
144630088Sminshall 	char *fmt;
144730088Sminshall 
144830088Sminshall 	switch (option) {
144930088Sminshall 
145030088Sminshall 	case TELOPT_TM:
145130088Sminshall 		fmt = will;
145230088Sminshall 		break;
145330088Sminshall 
145430088Sminshall #	if defined(TN3270)
145530088Sminshall 	case TELOPT_EOR:
145630088Sminshall 	case TELOPT_BINARY:
145730088Sminshall #	endif	/* defined(TN3270) */
145830088Sminshall 	case TELOPT_TTYPE:		/* terminal type option */
145930088Sminshall 	case TELOPT_SGA:		/* no big deal */
146030088Sminshall 		fmt = will;
146130088Sminshall 		myopts[option] = 1;
146230088Sminshall 		break;
146330088Sminshall 
146430088Sminshall 	case TELOPT_ECHO:		/* We're never going to echo... */
146530088Sminshall 	default:
146630088Sminshall 		fmt = wont;
146730088Sminshall 		break;
146830088Sminshall 	}
146930088Sminshall 	sprintf(nfrontp, fmt, option);
147030088Sminshall 	nfrontp += sizeof (doopt) - 2;
147130088Sminshall 	printoption(">SENT", fmt, option, 0);
147230088Sminshall }
147330088Sminshall 
147430088Sminshall /*
147530088Sminshall  * suboption()
147630088Sminshall  *
147730088Sminshall  *	Look at the sub-option buffer, and try to be helpful to the other
147830088Sminshall  * side.
147930088Sminshall  *
148030088Sminshall  *	Currently we recognize:
148130088Sminshall  *
148230088Sminshall  *		Terminal type, send request.
148330088Sminshall  */
148430088Sminshall 
148530088Sminshall static void
148630088Sminshall suboption()
148730088Sminshall {
148830088Sminshall     printsub("<", subbuffer, subend-subbuffer+1);
148930088Sminshall     switch (subbuffer[0]&0xff) {
149030088Sminshall     case TELOPT_TTYPE:
149130088Sminshall 	if ((subbuffer[1]&0xff) != TELQUAL_SEND) {
149230088Sminshall 	    ;
149330088Sminshall 	} else {
149430088Sminshall 	    char *name;
149530088Sminshall 	    char namebuf[41];
149630088Sminshall 	    extern char *getenv();
149730088Sminshall 	    int len;
149830088Sminshall 
149930088Sminshall #if	defined(TN3270)
150030088Sminshall 	    /*
150130326Sminshall 	     * Try to send a 3270 type terminal name.  Decide which one based
150230088Sminshall 	     * on the format of our screen, and (in the future) color
150330088Sminshall 	     * capaiblities.
150430088Sminshall 	     */
1505*31124Sminshall #if	defined(unix)
150630088Sminshall 	    if ((initscr() != ERR) &&	/* Initialize curses to get line size */
150730088Sminshall 		(LINES >= 24) && (COLS >= 80)) {
150830088Sminshall 		Sent3270TerminalType = 1;
150930088Sminshall 		if ((LINES >= 27) && (COLS >= 132)) {
151030088Sminshall 		    MaxNumberLines = 27;
151130088Sminshall 		    MaxNumberColumns = 132;
151230088Sminshall 		    sb_terminal[SBTERMMODEL] = '5';
151330088Sminshall 		} else if (LINES >= 43) {
151430088Sminshall 		    MaxNumberLines = 43;
151530088Sminshall 		    MaxNumberColumns = 80;
151630088Sminshall 		    sb_terminal[SBTERMMODEL] = '4';
151730088Sminshall 		} else if (LINES >= 32) {
151830088Sminshall 		    MaxNumberLines = 32;
151930088Sminshall 		    MaxNumberColumns = 80;
152030088Sminshall 		    sb_terminal[SBTERMMODEL] = '3';
152130088Sminshall 		} else {
152230088Sminshall 		    MaxNumberLines = 24;
152330088Sminshall 		    MaxNumberColumns = 80;
152430088Sminshall 		    sb_terminal[SBTERMMODEL] = '2';
152530088Sminshall 		}
152630088Sminshall 		NumberLines = 24;		/* before we start out... */
152730088Sminshall 		NumberColumns = 80;
152830088Sminshall 		ScreenSize = NumberLines*NumberColumns;
152930088Sminshall 		if ((MaxNumberLines*MaxNumberColumns) > MAXSCREENSIZE) {
153030088Sminshall 		    ExitString(stderr,
153130088Sminshall 			"Programming error:  MAXSCREENSIZE too small.\n", 1);
153230088Sminshall 		    /*NOTREACHED*/
153330088Sminshall 		}
153430088Sminshall 		bcopy(sb_terminal, nfrontp, sizeof sb_terminal);
153530088Sminshall 		printsub(">", nfrontp+2, sizeof sb_terminal-2);
153630088Sminshall 		nfrontp += sizeof sb_terminal;
153730088Sminshall 		return;
153830088Sminshall 	    }
1539*31124Sminshall #else	/* defined(unix) */
1540*31124Sminshall 	    XXX();
1541*31124Sminshall #endif	/* defined(unix) */
154230088Sminshall #endif	/* defined(TN3270) */
154330088Sminshall 
154430088Sminshall 	    name = getenv("TERM");
154530088Sminshall 	    if ((name == 0) || ((len = strlen(name)) > 40)) {
154630088Sminshall 		name = "UNKNOWN";
154730088Sminshall 	    }
154830088Sminshall 	    if ((len + 4+2) < NETROOM()) {
154930088Sminshall 		strcpy(namebuf, name);
155030088Sminshall 		upcase(namebuf);
155130088Sminshall 		sprintf(nfrontp, "%c%c%c%c%s%c%c", IAC, SB, TELOPT_TTYPE,
155230088Sminshall 				    TELQUAL_IS, namebuf, IAC, SE);
155330088Sminshall 		printsub(">", nfrontp+2, 4+strlen(namebuf)+2-2-2);
155430088Sminshall 		nfrontp += 4+strlen(namebuf)+2;
155530088Sminshall 	    } else {
155630088Sminshall 		ExitString(stderr, "No room in buffer for terminal type.\n",
155730088Sminshall 							1);
155830088Sminshall 		/*NOTREACHED*/
155930088Sminshall 	    }
156030088Sminshall 	}
156130088Sminshall 
156230088Sminshall     default:
156330088Sminshall 	break;
156430088Sminshall     }
156530088Sminshall }
156630088Sminshall 
156730088Sminshall #if	defined(TN3270)
156830088Sminshall static void
156930088Sminshall SetIn3270()
157030088Sminshall {
157130088Sminshall     if (Sent3270TerminalType && myopts[TELOPT_BINARY]
157230088Sminshall 					&& hisopts[TELOPT_BINARY]) {
157330088Sminshall 	if (!In3270) {
157430088Sminshall 	    In3270 = 1;
157530326Sminshall 	    Init3270();		/* Initialize 3270 functions */
157630088Sminshall 	    /* initialize terminal key mapping */
157730326Sminshall 	    InitTerminal();	/* Start terminal going */
157830088Sminshall 	    setconnmode();
157930088Sminshall 	}
158030088Sminshall     } else {
158130088Sminshall 	if (In3270) {
158230088Sminshall 	    StopScreen(1);
158330088Sminshall 	    In3270 = 0;
158430088Sminshall 	    setconnmode();
158530088Sminshall 	}
158630088Sminshall     }
158730088Sminshall }
158830088Sminshall #endif	/* defined(TN3270) */
158930088Sminshall 
159030088Sminshall 
159130088Sminshall static void
159230088Sminshall telrcv()
159330088Sminshall {
159430088Sminshall     register int c;
159530722Sminshall     static int telrcv_state = TS_DATA;
159630088Sminshall #   if defined(TN3270)
159730088Sminshall     register int Scc;
159830088Sminshall     register char *Sbp;
159930088Sminshall #   endif /* defined(TN3270) */
160030088Sminshall 
160130088Sminshall     while ((scc > 0) && (TTYROOM() > 2)) {
160230088Sminshall 	c = *sbp++ & 0xff, scc--;
160330722Sminshall 	switch (telrcv_state) {
160430088Sminshall 
160530088Sminshall 	case TS_CR:
160630722Sminshall 	    telrcv_state = TS_DATA;
160730088Sminshall 	    if (c == '\0') {
160830088Sminshall 		break;	/* Ignore \0 after CR */
160930088Sminshall 	    } else if (c == '\n') {
161030088Sminshall 		if (hisopts[TELOPT_ECHO] && !crmod) {
161130088Sminshall 		    TTYADD(c);
161230088Sminshall 		}
161330088Sminshall 		break;
161430088Sminshall 	    }
161530088Sminshall 	    /* Else, fall through */
161630088Sminshall 
161730088Sminshall 	case TS_DATA:
161830088Sminshall 	    if (c == IAC) {
161930722Sminshall 		telrcv_state = TS_IAC;
162030088Sminshall 		continue;
162130088Sminshall 	    }
162230088Sminshall #	    if defined(TN3270)
162330088Sminshall 	    if (In3270) {
162430088Sminshall 		*Ifrontp++ = c;
162530088Sminshall 		Sbp = sbp;
162630088Sminshall 		Scc = scc;
162730088Sminshall 		while (Scc > 0) {
162830088Sminshall 		    c = *Sbp++ & 0377, Scc--;
162930088Sminshall 		    if (c == IAC) {
163030722Sminshall 			telrcv_state = TS_IAC;
163130088Sminshall 			break;
163230088Sminshall 		    }
163330088Sminshall 		    *Ifrontp++ = c;
163430088Sminshall 		}
163530088Sminshall 		sbp = Sbp;
163630088Sminshall 		scc = Scc;
163730088Sminshall 	    } else
163830088Sminshall #	    endif /* defined(TN3270) */
163930088Sminshall 		    /*
164030088Sminshall 		     * The 'crmod' hack (see following) is needed
164130088Sminshall 		     * since we can't * set CRMOD on output only.
164230088Sminshall 		     * Machines like MULTICS like to send \r without
164330088Sminshall 		     * \n; since we must turn off CRMOD to get proper
164430088Sminshall 		     * input, the mapping is done here (sigh).
164530088Sminshall 		     */
164630088Sminshall 	    if (c == '\r') {
164730088Sminshall 		if (scc > 0) {
164830088Sminshall 		    c = *sbp&0xff;
164930088Sminshall 		    if (c == 0) {
165030088Sminshall 			sbp++, scc--;
165130088Sminshall 			/* a "true" CR */
165230088Sminshall 			TTYADD('\r');
165330088Sminshall 		    } else if (!hisopts[TELOPT_ECHO] &&
165430088Sminshall 					(c == '\n')) {
165530088Sminshall 			sbp++, scc--;
165630088Sminshall 			TTYADD('\n');
165730088Sminshall 		    } else {
165830088Sminshall 			TTYADD('\r');
165930088Sminshall 			if (crmod) {
166030088Sminshall 				TTYADD('\n');
166130088Sminshall 			}
166230088Sminshall 		    }
166330088Sminshall 		} else {
166430722Sminshall 		    telrcv_state = TS_CR;
166530088Sminshall 		    TTYADD('\r');
166630088Sminshall 		    if (crmod) {
166730088Sminshall 			    TTYADD('\n');
166830088Sminshall 		    }
166930088Sminshall 		}
167030088Sminshall 	    } else {
167130088Sminshall 		TTYADD(c);
167230088Sminshall 	    }
167330088Sminshall 	    continue;
167430088Sminshall 
167530088Sminshall 	case TS_IAC:
167630088Sminshall 	    switch (c) {
167730088Sminshall 
167830088Sminshall 	    case WILL:
167930722Sminshall 		telrcv_state = TS_WILL;
168030088Sminshall 		continue;
168130088Sminshall 
168230088Sminshall 	    case WONT:
168330722Sminshall 		telrcv_state = TS_WONT;
168430088Sminshall 		continue;
168530088Sminshall 
168630088Sminshall 	    case DO:
168730722Sminshall 		telrcv_state = TS_DO;
168830088Sminshall 		continue;
168930088Sminshall 
169030088Sminshall 	    case DONT:
169130722Sminshall 		telrcv_state = TS_DONT;
169230088Sminshall 		continue;
169330088Sminshall 
169430088Sminshall 	    case DM:
169530088Sminshall 		    /*
169630088Sminshall 		     * We may have missed an urgent notification,
169730088Sminshall 		     * so make sure we flush whatever is in the
169830088Sminshall 		     * buffer currently.
169930088Sminshall 		     */
170030088Sminshall 		SYNCHing = 1;
170130088Sminshall 		ttyflush();
170230088Sminshall 		SYNCHing = stilloob(net);
170330088Sminshall 		settimer(gotDM);
170430088Sminshall 		break;
170530088Sminshall 
170630088Sminshall 	    case NOP:
170730088Sminshall 	    case GA:
170830088Sminshall 		break;
170930088Sminshall 
171030088Sminshall 	    case SB:
171130088Sminshall 		SB_CLEAR();
171230722Sminshall 		telrcv_state = TS_SB;
171330088Sminshall 		continue;
171430088Sminshall 
171530088Sminshall #	    if defined(TN3270)
171630088Sminshall 	    case EOR:
171730088Sminshall 		if (In3270) {
171830088Sminshall 		    Ibackp += DataFromNetwork(Ibackp, Ifrontp-Ibackp, 1);
171930088Sminshall 		    if (Ibackp == Ifrontp) {
172030088Sminshall 			Ibackp = Ifrontp = Ibuf;
172130088Sminshall 			ISend = 0;	/* should have been! */
172230088Sminshall 		    } else {
172330088Sminshall 			ISend = 1;
172430088Sminshall 		    }
172530088Sminshall 		}
172630088Sminshall 		break;
172730088Sminshall #	    endif /* defined(TN3270) */
172830088Sminshall 
172930088Sminshall 	    case IAC:
173030088Sminshall #	    if !defined(TN3270)
173130088Sminshall 		TTYADD(IAC);
173230088Sminshall #	    else /* !defined(TN3270) */
173330088Sminshall 		if (In3270) {
173430088Sminshall 		    *Ifrontp++ = IAC;
173530088Sminshall 		} else {
173630088Sminshall 		    TTYADD(IAC);
173730088Sminshall 		}
173830088Sminshall #	    endif /* !defined(TN3270) */
173930088Sminshall 		break;
174030088Sminshall 
174130088Sminshall 	    default:
174230088Sminshall 		break;
174330088Sminshall 	    }
174430722Sminshall 	    telrcv_state = TS_DATA;
174530088Sminshall 	    continue;
174630088Sminshall 
174730088Sminshall 	case TS_WILL:
174830088Sminshall 	    printoption(">RCVD", will, c, !hisopts[c]);
174930088Sminshall 	    if (c == TELOPT_TM) {
175030088Sminshall 		if (flushout) {
175130088Sminshall 		    flushout = 0;
175230088Sminshall 		}
175330088Sminshall 	    } else if (!hisopts[c]) {
175430088Sminshall 		willoption(c, 1);
175530088Sminshall 	    }
175630088Sminshall 	    SetIn3270();
175730722Sminshall 	    telrcv_state = TS_DATA;
175830088Sminshall 	    continue;
175930088Sminshall 
176030088Sminshall 	case TS_WONT:
176130088Sminshall 	    printoption(">RCVD", wont, c, hisopts[c]);
176230088Sminshall 	    if (c == TELOPT_TM) {
176330088Sminshall 		if (flushout) {
176430088Sminshall 		    flushout = 0;
176530088Sminshall 		}
176630088Sminshall 	    } else if (hisopts[c]) {
176730088Sminshall 		wontoption(c, 1);
176830088Sminshall 	    }
176930088Sminshall 	    SetIn3270();
177030722Sminshall 	    telrcv_state = TS_DATA;
177130088Sminshall 	    continue;
177230088Sminshall 
177330088Sminshall 	case TS_DO:
177430088Sminshall 	    printoption(">RCVD", doopt, c, !myopts[c]);
177530088Sminshall 	    if (!myopts[c])
177630088Sminshall 		dooption(c);
177730088Sminshall 	    SetIn3270();
177830722Sminshall 	    telrcv_state = TS_DATA;
177930088Sminshall 	    continue;
178030088Sminshall 
178130088Sminshall 	case TS_DONT:
178230088Sminshall 	    printoption(">RCVD", dont, c, myopts[c]);
178330088Sminshall 	    if (myopts[c]) {
178430088Sminshall 		myopts[c] = 0;
178530088Sminshall 		sprintf(nfrontp, wont, c);
178630088Sminshall 		nfrontp += sizeof (wont) - 2;
178730088Sminshall 		flushline = 1;
178830088Sminshall 		setconnmode();	/* set new tty mode (maybe) */
178930088Sminshall 		printoption(">SENT", wont, c, 0);
179030088Sminshall 	    }
179130088Sminshall 	    SetIn3270();
179230722Sminshall 	    telrcv_state = TS_DATA;
179330088Sminshall 	    continue;
179430088Sminshall 
179530088Sminshall 	case TS_SB:
179630088Sminshall 	    if (c == IAC) {
179730722Sminshall 		telrcv_state = TS_SE;
179830088Sminshall 	    } else {
179930088Sminshall 		SB_ACCUM(c);
180030088Sminshall 	    }
180130088Sminshall 	    continue;
180230088Sminshall 
180330088Sminshall 	case TS_SE:
180430088Sminshall 	    if (c != SE) {
180530088Sminshall 		if (c != IAC) {
180630088Sminshall 		    SB_ACCUM(IAC);
180730088Sminshall 		}
180830088Sminshall 		SB_ACCUM(c);
180930722Sminshall 		telrcv_state = TS_SB;
181030088Sminshall 	    } else {
181130088Sminshall 		SB_TERM();
181230088Sminshall 		suboption();	/* handle sub-option */
181330088Sminshall 		SetIn3270();
181430722Sminshall 		telrcv_state = TS_DATA;
181530088Sminshall 	    }
181630088Sminshall 	}
181730088Sminshall     }
181830088Sminshall }
181930088Sminshall 
182030088Sminshall #if	defined(TN3270)
182130088Sminshall 
182230088Sminshall /*
182330088Sminshall  * The following routines are places where the various tn3270
182430088Sminshall  * routines make calls into telnet.c.
182530088Sminshall  */
182630088Sminshall 
182730088Sminshall /* TtyChars() - returns the number of characters in the TTY buffer */
182830088Sminshall TtyChars()
182930088Sminshall {
183030088Sminshall     return(tfrontp-tbackp);
183130088Sminshall }
183230088Sminshall 
183330088Sminshall /*
183430088Sminshall  * DataToNetwork - queue up some data to go to network.  If "done" is set,
183530088Sminshall  * then when last byte is queued, we add on an IAC EOR sequence (so,
183630088Sminshall  * don't call us with "done" until you want that done...)
183730088Sminshall  *
183830088Sminshall  * We actually do send all the data to the network buffer, since our
183930088Sminshall  * only client needs for us to do that.
184030088Sminshall  */
184130088Sminshall 
184230088Sminshall int
184330088Sminshall DataToNetwork(buffer, count, done)
184430088Sminshall register char	*buffer;	/* where the data is */
184530088Sminshall register int	count;		/* how much to send */
184630088Sminshall int		done;		/* is this the last of a logical block */
184730088Sminshall {
184830088Sminshall     register int c;
184930088Sminshall     int origCount;
185030088Sminshall     fd_set o;
185130088Sminshall 
185230088Sminshall     origCount = count;
185330088Sminshall     FD_ZERO(&o);
185430088Sminshall 
185530088Sminshall     while (count) {
185630088Sminshall 	if ((netobuf+sizeof netobuf - nfrontp) < 6) {
185730088Sminshall 	    netflush();
185830088Sminshall 	    while ((netobuf+sizeof netobuf - nfrontp) < 6) {
185930088Sminshall 		FD_SET(net, &o);
186030088Sminshall 		(void) select(net+1, (fd_set *) 0, &o, (fd_set *) 0,
186130088Sminshall 						(struct timeval *) 0);
186230088Sminshall 		netflush();
186330088Sminshall 	    }
186430088Sminshall 	}
186530088Sminshall 	c = *buffer++;
186630088Sminshall 	count--;
186730088Sminshall 	if (c == IAC) {
186830088Sminshall 	    *nfrontp++ = IAC;
186930088Sminshall 	    *nfrontp++ = IAC;
187030088Sminshall 	} else {
187130088Sminshall 	    *nfrontp++ = c;
187230088Sminshall 	}
187330088Sminshall     }
187430088Sminshall 
187530088Sminshall     if (done && !count) {
187630088Sminshall 	*nfrontp++ = IAC;
187730088Sminshall 	*nfrontp++ = EOR;
187830088Sminshall 	netflush();		/* try to move along as quickly as ... */
187930088Sminshall     }
188030088Sminshall     return(origCount - count);
188130088Sminshall }
188230088Sminshall 
188330088Sminshall /* DataToTerminal - queue up some data to go to terminal. */
188430088Sminshall 
188530088Sminshall int
188630088Sminshall DataToTerminal(buffer, count)
188730088Sminshall register char	*buffer;		/* where the data is */
188830088Sminshall register int	count;			/* how much to send */
188930088Sminshall {
189030088Sminshall     int origCount;
189130088Sminshall     fd_set	o;
189230088Sminshall 
189330088Sminshall     origCount = count;
189430088Sminshall     FD_ZERO(&o);
189530088Sminshall 
189630088Sminshall     while (count) {
189730088Sminshall 	if (tfrontp >= ttyobuf+sizeof ttyobuf) {
189830088Sminshall 	    ttyflush();
189930088Sminshall 	    while (tfrontp >= ttyobuf+sizeof ttyobuf) {
190030088Sminshall 		FD_SET(tout, &o);
190130088Sminshall 		(void) select(tout+1, (fd_set *) 0, &o, (fd_set *) 0,
190230088Sminshall 						(struct timeval *) 0);
190330088Sminshall 		ttyflush();
190430088Sminshall 	    }
190530088Sminshall 	}
190630088Sminshall 	*tfrontp++ = *buffer++;
190730088Sminshall 	count--;
190830088Sminshall     }
190930088Sminshall     return(origCount - count);
191030088Sminshall }
191130088Sminshall 
191230088Sminshall /* EmptyTerminal - called to make sure that the terminal buffer is empty.
191330088Sminshall  *			Note that we consider the buffer to run all the
191430088Sminshall  *			way to the kernel (thus the select).
191530088Sminshall  */
191630088Sminshall 
191730088Sminshall void
191830088Sminshall EmptyTerminal()
191930088Sminshall {
192030088Sminshall     fd_set	o;
192130088Sminshall 
192230088Sminshall     FD_ZERO(&o);
192330088Sminshall 
192430088Sminshall     if (tfrontp == tbackp) {
192530088Sminshall 	FD_SET(tout, &o);
192630088Sminshall 	(void) select(tout+1, (int *) 0, &o, (int *) 0,
192730088Sminshall 			(struct timeval *) 0);	/* wait for TTLOWAT */
192830088Sminshall     } else {
192930088Sminshall 	while (tfrontp != tbackp) {
193030088Sminshall 	    ttyflush();
193130088Sminshall 	    FD_SET(tout, &o);
193230088Sminshall 	    (void) select(tout+1, (int *) 0, &o, (int *) 0,
193330088Sminshall 				(struct timeval *) 0);	/* wait for TTLOWAT */
193430088Sminshall 	}
193530088Sminshall     }
193630088Sminshall }
193730088Sminshall 
193830088Sminshall /*
193930088Sminshall  * Push3270 - Try to send data along the 3270 output (to screen) direction.
194030088Sminshall  */
194130088Sminshall 
194230088Sminshall static int
194330088Sminshall Push3270()
194430088Sminshall {
194530088Sminshall     int save = scc;
194630088Sminshall 
194730088Sminshall     if (scc) {
194830088Sminshall 	if (Ifrontp+scc > Ibuf+sizeof Ibuf) {
194930088Sminshall 	    if (Ibackp != Ibuf) {
195030088Sminshall 		bcopy(Ibackp, Ibuf, Ifrontp-Ibackp);
195130088Sminshall 		Ifrontp -= (Ibackp-Ibuf);
195230088Sminshall 		Ibackp = Ibuf;
195330088Sminshall 	    }
195430088Sminshall 	}
195530088Sminshall 	if (Ifrontp+scc < Ibuf+sizeof Ibuf) {
195630088Sminshall 	    telrcv();
195730088Sminshall 	}
195830088Sminshall     }
195930088Sminshall     return save != scc;
196030088Sminshall }
196130088Sminshall 
196230088Sminshall 
196330088Sminshall /*
196430088Sminshall  * Finish3270 - get the last dregs of 3270 data out to the terminal
196530088Sminshall  *		before quitting.
196630088Sminshall  */
196730088Sminshall 
196830088Sminshall static void
196930088Sminshall Finish3270()
197030088Sminshall {
197130088Sminshall     while (Push3270() || !DoTerminalOutput()) {
197230088Sminshall 	;
197330088Sminshall     }
197430088Sminshall }
197530088Sminshall 
197630088Sminshall 
197730088Sminshall 
197830088Sminshall /* StringToTerminal - output a null terminated string to the terminal */
197930088Sminshall 
198030088Sminshall void
198130088Sminshall StringToTerminal(s)
198230088Sminshall char *s;
198330088Sminshall {
198430088Sminshall     int count;
198530088Sminshall 
198630088Sminshall     count = strlen(s);
198730088Sminshall     if (count) {
198830088Sminshall 	(void) DataToTerminal(s, count);	/* we know it always goes... */
198930088Sminshall     }
199030088Sminshall }
199130088Sminshall 
199230088Sminshall 
199330088Sminshall #if	defined(TN3270) && ((!defined(NOT43)) || defined(PUTCHAR))
199430088Sminshall /* _putchar - output a single character to the terminal.  This name is so that
199530088Sminshall  *	curses(3x) can call us to send out data.
199630088Sminshall  */
199730088Sminshall 
199830088Sminshall void
199930088Sminshall _putchar(c)
200030088Sminshall char c;
200130088Sminshall {
200230088Sminshall     if (tfrontp >= ttyobuf+sizeof ttyobuf) {
200330088Sminshall 	(void) DataToTerminal(&c, 1);
200430088Sminshall     } else {
200530088Sminshall 	*tfrontp++ = c;		/* optimize if possible. */
200630088Sminshall     }
200730088Sminshall }
200830088Sminshall #endif	/* defined(TN3270) && ((!defined(NOT43)) || defined(PUTCHAR)) */
200930088Sminshall 
201030088Sminshall static void
201130088Sminshall SetForExit()
201230088Sminshall {
201330088Sminshall     setconnmode();
201430088Sminshall     if (In3270) {
201530088Sminshall 	Finish3270();
201630088Sminshall     }
201730088Sminshall     setcommandmode();
201830088Sminshall     fflush(stdout);
201930088Sminshall     fflush(stderr);
202030088Sminshall     if (In3270) {
202130088Sminshall 	StopScreen(1);
202230088Sminshall     }
202330088Sminshall     setconnmode();
202430088Sminshall     setcommandmode();
202530088Sminshall }
202630088Sminshall 
202730088Sminshall static void
202830088Sminshall Exit(returnCode)
202930088Sminshall int returnCode;
203030088Sminshall {
203130088Sminshall     SetForExit();
203230088Sminshall     exit(returnCode);
203330088Sminshall }
203430088Sminshall 
203530088Sminshall void
203630088Sminshall ExitString(file, string, returnCode)
203730088Sminshall FILE *file;
203830088Sminshall char *string;
203930088Sminshall int returnCode;
204030088Sminshall {
204130088Sminshall     SetForExit();
204230088Sminshall     fwrite(string, 1, strlen(string), file);
204330088Sminshall     exit(returnCode);
204430088Sminshall }
204530088Sminshall 
204630088Sminshall void
204730088Sminshall ExitPerror(string, returnCode)
204830088Sminshall char *string;
204930088Sminshall int returnCode;
205030088Sminshall {
205130088Sminshall     SetForExit();
205230088Sminshall     perror(string);
205330088Sminshall     exit(returnCode);
205430088Sminshall }
205530088Sminshall 
205630088Sminshall #endif	/* defined(TN3270) */
205730088Sminshall 
205830088Sminshall static
205930088Sminshall Scheduler(block)
206030088Sminshall int	block;			/* should we block in the select ? */
206130088Sminshall {
206230088Sminshall     register int c;
206330088Sminshall 		/* One wants to be a bit careful about setting returnValue
206430088Sminshall 		 * to one, since a one implies we did some useful work,
206530088Sminshall 		 * and therefore probably won't be called to block next
206630088Sminshall 		 * time (TN3270 mode only).
206730088Sminshall 		 */
206830088Sminshall     int returnValue = 0;
206930088Sminshall     static struct timeval TimeValue = { 0 };
207030088Sminshall 
207130088Sminshall     if (scc < 0 && tcc < 0) {
207230088Sminshall 	return -1;
207330088Sminshall     }
207430088Sminshall 
207530088Sminshall     if ((!MODE_LINE(globalmode) || flushline) && NETBYTES()) {
207630088Sminshall 	FD_SET(net, &obits);
207730088Sminshall     }
207830088Sminshall     if (TTYBYTES()) {
207930088Sminshall 	FD_SET(tout, &obits);
208030088Sminshall     }
208130088Sminshall     if ((tcc == 0) && NETROOM()) {
208230088Sminshall 	FD_SET(tin, &ibits);
208330088Sminshall     }
208430088Sminshall #   if !defined(TN3270)
208530088Sminshall     if (TTYROOM()) {
208630088Sminshall 	FD_SET(net, &ibits);
208730088Sminshall     }
208830088Sminshall #   else /* !defined(TN3270) */
208930088Sminshall     if (!ISend && TTYROOM()) {
209030088Sminshall 	FD_SET(net, &ibits);
209130088Sminshall     }
209230088Sminshall #   endif /* !defined(TN3270) */
209330088Sminshall     if (!SYNCHing) {
209430088Sminshall 	FD_SET(net, &xbits);
209530088Sminshall     }
209630088Sminshall #   if defined(TN3270) && defined(unix)
209730088Sminshall     if (HaveInput) {
209830088Sminshall 	HaveInput = 0;
209930088Sminshall 	signal(SIGIO, inputAvailable);
210030088Sminshall     }
210130088Sminshall #endif	/* defined(TN3270) && defined(unix) */
210230088Sminshall     if ((c = select(16, &ibits, &obits, &xbits,
210330088Sminshall 			block? (struct timeval *)0 : &TimeValue)) < 1) {
210430088Sminshall 	if (c == -1) {
210530088Sminshall 		    /*
210630088Sminshall 		     * we can get EINTR if we are in line mode,
210730088Sminshall 		     * and the user does an escape (TSTP), or
210830088Sminshall 		     * some other signal generator.
210930088Sminshall 		     */
211030088Sminshall 	    if (errno == EINTR) {
211130088Sminshall 		return 0;
211230088Sminshall 	    }
211330088Sminshall #	    if defined(TN3270)
211430088Sminshall 		    /*
211530088Sminshall 		     * we can get EBADF if we were in transparent
211630088Sminshall 		     * mode, and the transcom process died.
211730088Sminshall 		    */
211830088Sminshall 	    if (errno == EBADF) {
211930088Sminshall 			/*
212030088Sminshall 			 * zero the bits (even though kernel does it)
212130088Sminshall 			 * to make sure we are selecting on the right
212230088Sminshall 			 * ones.
212330088Sminshall 			*/
212430088Sminshall 		FD_ZERO(&ibits);
212530088Sminshall 		FD_ZERO(&obits);
212630088Sminshall 		FD_ZERO(&xbits);
212730088Sminshall 		return 0;
212830088Sminshall 	    }
212930088Sminshall #	    endif /* defined(TN3270) */
213030088Sminshall 		    /* I don't like this, does it ever happen? */
213130088Sminshall 	    printf("sleep(5) from telnet, after select\r\n");
213230088Sminshall #if	defined(unix)
213330088Sminshall 	    sleep(5);
213430088Sminshall #endif	/* defined(unix) */
213530088Sminshall 	}
213630088Sminshall 	return 0;
213730088Sminshall     }
213830088Sminshall 
213930088Sminshall     /*
214030088Sminshall      * Any urgent data?
214130088Sminshall      */
214230088Sminshall     if (FD_ISSET(net, &xbits)) {
214330088Sminshall 	FD_CLR(net, &xbits);
214430088Sminshall 	SYNCHing = 1;
214530088Sminshall 	ttyflush();	/* flush already enqueued data */
214630088Sminshall     }
214730088Sminshall 
214830088Sminshall     /*
214930088Sminshall      * Something to read from the network...
215030088Sminshall      */
215130088Sminshall     if (FD_ISSET(net, &ibits)) {
215230088Sminshall 	int canread;
215330088Sminshall 
215430088Sminshall 	FD_CLR(net, &ibits);
215530088Sminshall 	if (scc == 0) {
215630088Sminshall 	    sbp = sibuf;
215730088Sminshall 	}
215830422Sminshall 	canread = sibuf + sizeof sibuf - (sbp+scc);
215930088Sminshall #if	!defined(SO_OOBINLINE)
216030088Sminshall 	    /*
216130088Sminshall 	     * In 4.2 (and some early 4.3) systems, the
216230088Sminshall 	     * OOB indication and data handling in the kernel
216330088Sminshall 	     * is such that if two separate TCP Urgent requests
216430088Sminshall 	     * come in, one byte of TCP data will be overlaid.
216530088Sminshall 	     * This is fatal for Telnet, but we try to live
216630088Sminshall 	     * with it.
216730088Sminshall 	     *
216830088Sminshall 	     * In addition, in 4.2 (and...), a special protocol
216930088Sminshall 	     * is needed to pick up the TCP Urgent data in
217030088Sminshall 	     * the correct sequence.
217130088Sminshall 	     *
217230088Sminshall 	     * What we do is:  if we think we are in urgent
217330088Sminshall 	     * mode, we look to see if we are "at the mark".
217430088Sminshall 	     * If we are, we do an OOB receive.  If we run
217530088Sminshall 	     * this twice, we will do the OOB receive twice,
217630088Sminshall 	     * but the second will fail, since the second
217730088Sminshall 	     * time we were "at the mark", but there wasn't
217830088Sminshall 	     * any data there (the kernel doesn't reset
217930088Sminshall 	     * "at the mark" until we do a normal read).
218030088Sminshall 	     * Once we've read the OOB data, we go ahead
218130088Sminshall 	     * and do normal reads.
218230088Sminshall 	     *
218330088Sminshall 	     * There is also another problem, which is that
218430088Sminshall 	     * since the OOB byte we read doesn't put us
218530088Sminshall 	     * out of OOB state, and since that byte is most
218630088Sminshall 	     * likely the TELNET DM (data mark), we would
218730088Sminshall 	     * stay in the TELNET SYNCH (SYNCHing) state.
218830088Sminshall 	     * So, clocks to the rescue.  If we've "just"
218930088Sminshall 	     * received a DM, then we test for the
219030088Sminshall 	     * presence of OOB data when the receive OOB
219130088Sminshall 	     * fails (and AFTER we did the normal mode read
219230088Sminshall 	     * to clear "at the mark").
219330088Sminshall 	     */
219430088Sminshall 	if (SYNCHing) {
219530088Sminshall 	    int atmark;
219630088Sminshall 
219730088Sminshall 	    ioctl(net, SIOCATMARK, (char *)&atmark);
219830088Sminshall 	    if (atmark) {
219930422Sminshall 		c = recv(net, sbp+scc, canread, MSG_OOB);
220030088Sminshall 		if ((c == -1) && (errno == EINVAL)) {
220130422Sminshall 		    c = read(net, sbp+scc, canread);
220230088Sminshall 		    if (clocks.didnetreceive < clocks.gotDM) {
220330088Sminshall 			SYNCHing = stilloob(net);
220430088Sminshall 		    }
220530088Sminshall 		}
220630088Sminshall 	    } else {
220730422Sminshall 		c = read(net, sbp+scc, canread);
220830088Sminshall 	    }
220930088Sminshall 	} else {
221030422Sminshall 	    c = read(net, sbp+scc, canread);
221130088Sminshall 	}
221230088Sminshall 	settimer(didnetreceive);
221330088Sminshall #else	/* !defined(SO_OOBINLINE) */
221430422Sminshall 	c = read(net, sbp+scc, canread);
221530088Sminshall #endif	/* !defined(SO_OOBINLINE) */
221630088Sminshall 	if (c < 0 && errno == EWOULDBLOCK) {
221730088Sminshall 	    c = 0;
221830088Sminshall 	} else if (c <= 0) {
221930088Sminshall 	    return -1;
222030088Sminshall 	}
222130088Sminshall 	if (netdata) {
222230422Sminshall 	    Dump('<', sbp+scc, c);
222330088Sminshall 	}
222430088Sminshall 	scc += c;
222530088Sminshall 	returnValue = 1;
222630088Sminshall     }
222730088Sminshall 
222830088Sminshall     /*
222930088Sminshall      * Something to read from the tty...
223030088Sminshall      */
223130088Sminshall     if (FD_ISSET(tin, &ibits)) {
223230088Sminshall 	FD_CLR(tin, &ibits);
223330088Sminshall 	if (tcc == 0) {
223430088Sminshall 	    tbp = tibuf;	/* nothing left, reset */
223530088Sminshall 	}
223630088Sminshall 	c = read(tin, tbp, tibuf+sizeof tibuf - tbp);
223730088Sminshall 	if (c < 0 && errno == EWOULDBLOCK) {
223830088Sminshall 	    c = 0;
223930088Sminshall 	} else {
2240*31124Sminshall #if	defined(unix)
224130088Sminshall 	    /* EOF detection for line mode!!!! */
224230088Sminshall 	    if (c == 0 && MODE_LOCAL_CHARS(globalmode)) {
224330088Sminshall 			/* must be an EOF... */
224430088Sminshall 		*tbp = ntc.t_eofc;
224530088Sminshall 		c = 1;
224630088Sminshall 	    }
2247*31124Sminshall #endif	/* defined(unix) */
224830088Sminshall 	    if (c <= 0) {
224930088Sminshall 		tcc = c;
225030088Sminshall 		return -1;
225130088Sminshall 	    }
225230088Sminshall 	}
225330088Sminshall 	tcc += c;
225430088Sminshall 	returnValue = 1;		/* did something useful */
225530088Sminshall     }
225630088Sminshall 
225730088Sminshall #   if defined(TN3270)
225830088Sminshall     if (tcc > 0) {
225930088Sminshall 	if (In3270) {
226030088Sminshall 	    c = DataFromTerminal(tbp, tcc);
226130088Sminshall 	    if (c) {
226230088Sminshall 		returnValue = 1;
226330088Sminshall 	    }
226430088Sminshall 	    tcc -= c;
226530088Sminshall 	    tbp += c;
226630088Sminshall 	} else {
226730320Sminshall #   endif /* defined(TN3270) */
226830088Sminshall 	    returnValue = 1;
226930088Sminshall 	    while (tcc > 0) {
227030088Sminshall 		register int sc;
227130088Sminshall 
227230088Sminshall 		if (NETROOM() < 2) {
227330088Sminshall 		    flushline = 1;
227430088Sminshall 		    break;
227530088Sminshall 		}
227630088Sminshall 		c = *tbp++ & 0xff, sc = strip(c), tcc--;
227730088Sminshall 		if (sc == escape) {
227830088Sminshall 		    command(0);
227930088Sminshall 		    tcc = 0;
228030088Sminshall 		    flushline = 1;
228130088Sminshall 		    break;
228230088Sminshall 		} else if (MODE_LINE(globalmode) && (sc == echoc)) {
228330088Sminshall 		    if (tcc > 0 && strip(*tbp) == echoc) {
228430088Sminshall 			tbp++;
228530088Sminshall 			tcc--;
228630088Sminshall 		    } else {
228730088Sminshall 			dontlecho = !dontlecho;
228830088Sminshall 			settimer(echotoggle);
228930088Sminshall 			setconnmode();
229030088Sminshall 			tcc = 0;
229130088Sminshall 			flushline = 1;
229230088Sminshall 			break;
229330088Sminshall 		    }
229430088Sminshall 		}
229530088Sminshall 		if (localchars) {
2296*31124Sminshall 		    if (TerminalEditLine(sc) == 0) {
229730088Sminshall 			break;
229830088Sminshall 		    }
229930088Sminshall 		}
230030088Sminshall 		switch (c) {
230130088Sminshall 		case '\n':
230230088Sminshall 			/*
230330088Sminshall 			 * If we are in CRMOD mode (\r ==> \n)
230430088Sminshall 			 * on our local machine, then probably
230530088Sminshall 			 * a newline (unix) is CRLF (TELNET).
230630088Sminshall 			 */
230730088Sminshall 		    if (MODE_LOCAL_CHARS(globalmode)) {
230830088Sminshall 			NETADD('\r');
230930088Sminshall 		    }
231030088Sminshall 		    NETADD('\n');
231130088Sminshall 		    flushline = 1;
231230088Sminshall 		    break;
231330088Sminshall 		case '\r':
231430088Sminshall 		    NET2ADD('\r', '\0');
231530088Sminshall 		    flushline = 1;
231630088Sminshall 		    break;
231730088Sminshall 		case IAC:
231830088Sminshall 		    NET2ADD(IAC, IAC);
231930088Sminshall 		    break;
232030088Sminshall 		default:
232130088Sminshall 		    NETADD(c);
232230088Sminshall 		    break;
232330088Sminshall 		}
232430088Sminshall 	    }
232530088Sminshall #   if defined(TN3270)
232630088Sminshall 	}
232730088Sminshall     }
232830088Sminshall #   endif /* defined(TN3270) */
232930088Sminshall 
233030088Sminshall     if ((!MODE_LINE(globalmode) || flushline) &&
233130088Sminshall 	FD_ISSET(net, &obits) && (NETBYTES() > 0)) {
233230088Sminshall 	FD_CLR(net, &obits);
233330088Sminshall 	returnValue = netflush();
233430088Sminshall     }
233530088Sminshall     if (scc > 0) {
233630088Sminshall #	if !defined(TN3270)
233730088Sminshall 	telrcv();
233830088Sminshall 	returnValue = 1;
233930088Sminshall #	else /* !defined(TN3270) */
234030088Sminshall 	returnValue = Push3270();
234130088Sminshall #	endif /* !defined(TN3270) */
234230088Sminshall     }
234330088Sminshall     if (FD_ISSET(tout, &obits) && (TTYBYTES() > 0)) {
234430088Sminshall 	FD_CLR(tout, &obits);
234530088Sminshall 	returnValue = ttyflush();
234630088Sminshall     }
234730088Sminshall     return returnValue;
234830088Sminshall }
234930088Sminshall 
235030088Sminshall /*
235130088Sminshall  * Select from tty and network...
235230088Sminshall  */
235330088Sminshall static void
235430088Sminshall telnet()
235530088Sminshall {
235630088Sminshall #if	defined(TN3270) && defined(unix)
235730088Sminshall     int myPid;
235830088Sminshall #endif	/* defined(TN3270) */
235930088Sminshall 
236030088Sminshall     tout = fileno(stdout);
236130088Sminshall     tin = fileno(stdin);
236230088Sminshall     setconnmode();
236330088Sminshall     scc = 0;
236430088Sminshall     tcc = 0;
236530088Sminshall     FD_ZERO(&ibits);
236630088Sminshall     FD_ZERO(&obits);
236730088Sminshall     FD_ZERO(&xbits);
236830088Sminshall 
2369*31124Sminshall     NetNonblockingIO(net, 1);
237030088Sminshall 
237130088Sminshall #if	defined(TN3270)
237230088Sminshall #if	!defined(DEBUG)		/* DBX can't handle! */
2373*31124Sminshall     NetSigIO(net, 1);
237430088Sminshall #endif	/* !defined(DEBUG) */
237530088Sminshall 
2376*31124Sminshall     NetSetPgrp(net);
237730088Sminshall #endif	/* defined(TN3270) */
237830088Sminshall 
237930088Sminshall 
2380*31124Sminshall #if	defined(SO_OOBINLINE) && !defined(MSDOS)
2381*31124Sminshall     SetSockOpt(net, SOL_SOCKET, SO_OOBINLINE, 1);
2382*31124Sminshall #endif	/* defined(SO_OOBINLINE) && !defined(MSDOS) */
2383*31124Sminshall 
238430320Sminshall #   if !defined(TN3270)
238530088Sminshall     if (telnetport) {
238630088Sminshall 	if (!hisopts[TELOPT_SGA]) {
238730088Sminshall 	    willoption(TELOPT_SGA, 0);
238830088Sminshall 	}
238930088Sminshall 	if (!myopts[TELOPT_TTYPE]) {
239030088Sminshall 	    dooption(TELOPT_TTYPE, 0);
239130088Sminshall 	}
239230088Sminshall     }
239330320Sminshall #   endif /* !defined(TN3270) */
239430088Sminshall 
239530088Sminshall #   if !defined(TN3270)
239630088Sminshall     for (;;) {
239730088Sminshall 	if (Scheduler(1) == -1) {
239830088Sminshall 	    setcommandmode();
239930088Sminshall 	    return;
240030088Sminshall 	}
240130088Sminshall     }
240230088Sminshall #   else /* !defined(TN3270) */
240330088Sminshall     for (;;) {
240430088Sminshall 	int schedValue;
240530088Sminshall 
240630088Sminshall 	while (!In3270) {
240730088Sminshall 	    if (Scheduler(1) == -1) {
240830088Sminshall 		setcommandmode();
240930088Sminshall 		return;
241030088Sminshall 	    }
241130088Sminshall 	}
241230088Sminshall 
241330088Sminshall 	while ((schedValue = Scheduler(0)) != 0) {
241430088Sminshall 	    if (schedValue == -1) {
241530088Sminshall 		setcommandmode();
241630088Sminshall 		return;
241730088Sminshall 	    }
241830088Sminshall 	}
241930088Sminshall 		/* If there is data waiting to go out to terminal, don't
242030088Sminshall 		 * schedule any more data for the terminal.
242130088Sminshall 		 */
242230088Sminshall 	if (tfrontp-tbackp) {
242330088Sminshall 	    schedValue = 1;
242430088Sminshall 	} else {
242530088Sminshall 	    schedValue = DoTerminalOutput();
242630088Sminshall 	}
242730088Sminshall 	if (schedValue) {
242830088Sminshall 	    if (Scheduler(1) == -1) {
242930088Sminshall 		setcommandmode();
243030088Sminshall 		return;
243130088Sminshall 	    }
243230088Sminshall 	}
243330088Sminshall     }
243430088Sminshall #   endif /* !defined(TN3270) */
243530088Sminshall }
243630088Sminshall 
243730088Sminshall /*
243830088Sminshall  *	The following are data structures and routines for
243930088Sminshall  *	the "send" command.
244030088Sminshall  *
244130088Sminshall  */
244230088Sminshall 
244330088Sminshall struct sendlist {
244430088Sminshall     char	*name;		/* How user refers to it (case independent) */
244530088Sminshall     int		what;		/* Character to be sent (<0 ==> special) */
244630088Sminshall     char	*help;		/* Help information (0 ==> no help) */
244730088Sminshall #if	defined(NOT43)
244830088Sminshall     int		(*routine)();	/* Routine to perform (for special ops) */
244930088Sminshall #else	/* defined(NOT43) */
245030088Sminshall     void	(*routine)();	/* Routine to perform (for special ops) */
245130088Sminshall #endif	/* defined(NOT43) */
245230088Sminshall };
245330088Sminshall 
245430088Sminshall #define	SENDQUESTION	-1
245530088Sminshall #define	SENDESCAPE	-3
245630088Sminshall 
245730088Sminshall static struct sendlist Sendlist[] = {
245830088Sminshall     { "ao", AO, "Send Telnet Abort output" },
245930088Sminshall     { "ayt", AYT, "Send Telnet 'Are You There'" },
246030088Sminshall     { "brk", BREAK, "Send Telnet Break" },
246130088Sminshall     { "ec", EC, "Send Telnet Erase Character" },
246230088Sminshall     { "el", EL, "Send Telnet Erase Line" },
246330088Sminshall     { "escape", SENDESCAPE, "Send current escape character" },
246430088Sminshall     { "ga", GA, "Send Telnet 'Go Ahead' sequence" },
246530088Sminshall     { "ip", IP, "Send Telnet Interrupt Process" },
246630088Sminshall     { "nop", NOP, "Send Telnet 'No operation'" },
246730088Sminshall     { "synch", SYNCH, "Perform Telnet 'Synch operation'", dosynch },
246830088Sminshall     { "?", SENDQUESTION, "Display send options" },
246930088Sminshall     { 0 }
247030088Sminshall };
247130088Sminshall 
247230088Sminshall static struct sendlist Sendlist2[] = {		/* some synonyms */
247330088Sminshall 	{ "break", BREAK, 0 },
247430088Sminshall 
247530088Sminshall 	{ "intp", IP, 0 },
247630088Sminshall 	{ "interrupt", IP, 0 },
247730088Sminshall 	{ "intr", IP, 0 },
247830088Sminshall 
247930088Sminshall 	{ "help", SENDQUESTION, 0 },
248030088Sminshall 
248130088Sminshall 	{ 0 }
248230088Sminshall };
248330088Sminshall 
248430088Sminshall static char **
248530088Sminshall getnextsend(name)
248630088Sminshall char *name;
248730088Sminshall {
248830088Sminshall     struct sendlist *c = (struct sendlist *) name;
248930088Sminshall 
249030088Sminshall     return (char **) (c+1);
249130088Sminshall }
249230088Sminshall 
249330088Sminshall static struct sendlist *
249430088Sminshall getsend(name)
249530088Sminshall char *name;
249630088Sminshall {
249730088Sminshall     struct sendlist *sl;
249830088Sminshall 
249930088Sminshall     if ((sl = (struct sendlist *)
250030088Sminshall 			genget(name, (char **) Sendlist, getnextsend)) != 0) {
250130088Sminshall 	return sl;
250230088Sminshall     } else {
250330088Sminshall 	return (struct sendlist *)
250430088Sminshall 				genget(name, (char **) Sendlist2, getnextsend);
250530088Sminshall     }
250630088Sminshall }
250730088Sminshall 
250830088Sminshall static
250930088Sminshall sendcmd(argc, argv)
251030088Sminshall int	argc;
251130088Sminshall char	**argv;
251230088Sminshall {
251330088Sminshall     int what;		/* what we are sending this time */
251430088Sminshall     int count;		/* how many bytes we are going to need to send */
251530088Sminshall     int i;
251630088Sminshall     int question = 0;	/* was at least one argument a question */
251730088Sminshall     struct sendlist *s;	/* pointer to current command */
251830088Sminshall 
251930088Sminshall     if (argc < 2) {
252030088Sminshall 	printf("need at least one argument for 'send' command\n");
252130088Sminshall 	printf("'send ?' for help\n");
252230088Sminshall 	return 0;
252330088Sminshall     }
252430088Sminshall     /*
252530088Sminshall      * First, validate all the send arguments.
252630088Sminshall      * In addition, we see how much space we are going to need, and
252730088Sminshall      * whether or not we will be doing a "SYNCH" operation (which
252830088Sminshall      * flushes the network queue).
252930088Sminshall      */
253030088Sminshall     count = 0;
253130088Sminshall     for (i = 1; i < argc; i++) {
253230088Sminshall 	s = getsend(argv[i]);
253330088Sminshall 	if (s == 0) {
253430088Sminshall 	    printf("Unknown send argument '%s'\n'send ?' for help.\n",
253530088Sminshall 			argv[i]);
253630088Sminshall 	    return 0;
253730088Sminshall 	} else if (s == Ambiguous(struct sendlist *)) {
253830088Sminshall 	    printf("Ambiguous send argument '%s'\n'send ?' for help.\n",
253930088Sminshall 			argv[i]);
254030088Sminshall 	    return 0;
254130088Sminshall 	}
254230088Sminshall 	switch (s->what) {
254330088Sminshall 	case SENDQUESTION:
254430088Sminshall 	    break;
254530088Sminshall 	case SENDESCAPE:
254630088Sminshall 	    count += 1;
254730088Sminshall 	    break;
254830088Sminshall 	case SYNCH:
254930088Sminshall 	    count += 2;
255030088Sminshall 	    break;
255130088Sminshall 	default:
255230088Sminshall 	    count += 2;
255330088Sminshall 	    break;
255430088Sminshall 	}
255530088Sminshall     }
255630088Sminshall     /* Now, do we have enough room? */
255730088Sminshall     if (NETROOM() < count) {
255830088Sminshall 	printf("There is not enough room in the buffer TO the network\n");
255930088Sminshall 	printf("to process your request.  Nothing will be done.\n");
256030088Sminshall 	printf("('send synch' will throw away most data in the network\n");
256130088Sminshall 	printf("buffer, if this might help.)\n");
256230088Sminshall 	return 0;
256330088Sminshall     }
256430088Sminshall     /* OK, they are all OK, now go through again and actually send */
256530088Sminshall     for (i = 1; i < argc; i++) {
256630088Sminshall 	if ((s = getsend(argv[i])) == 0) {
256730088Sminshall 	    fprintf(stderr, "Telnet 'send' error - argument disappeared!\n");
256830088Sminshall 	    quit();
256930088Sminshall 	    /*NOTREACHED*/
257030088Sminshall 	}
257130088Sminshall 	if (s->routine) {
257230088Sminshall 	    (*s->routine)(s);
257330088Sminshall 	} else {
257430088Sminshall 	    switch (what = s->what) {
257530088Sminshall 	    case SYNCH:
257630088Sminshall 		dosynch();
257730088Sminshall 		break;
257830088Sminshall 	    case SENDQUESTION:
257930088Sminshall 		for (s = Sendlist; s->name; s++) {
258030088Sminshall 		    if (s->help) {
258130088Sminshall 			printf(s->name);
258230088Sminshall 			if (s->help) {
258330088Sminshall 			    printf("\t%s", s->help);
258430088Sminshall 			}
258530088Sminshall 			printf("\n");
258630088Sminshall 		    }
258730088Sminshall 		}
258830088Sminshall 		question = 1;
258930088Sminshall 		break;
259030088Sminshall 	    case SENDESCAPE:
259130088Sminshall 		NETADD(escape);
259230088Sminshall 		break;
259330088Sminshall 	    default:
259430088Sminshall 		NET2ADD(IAC, what);
259530088Sminshall 		break;
259630088Sminshall 	    }
259730088Sminshall 	}
259830088Sminshall     }
259930088Sminshall     return !question;
260030088Sminshall }
260130088Sminshall 
260230088Sminshall /*
260330088Sminshall  * The following are the routines and data structures referred
260430088Sminshall  * to by the arguments to the "toggle" command.
260530088Sminshall  */
260630088Sminshall 
260730088Sminshall static
260830088Sminshall lclchars()
260930088Sminshall {
261030088Sminshall     donelclchars = 1;
261130088Sminshall     return 1;
261230088Sminshall }
261330088Sminshall 
261430088Sminshall static
261530088Sminshall togdebug()
261630088Sminshall {
261730088Sminshall #ifndef	NOT43
261830088Sminshall     if (net > 0 &&
2619*31124Sminshall 	(SetSockOpt(net, SOL_SOCKET, SO_DEBUG, debug)) < 0) {
262030088Sminshall 	    perror("setsockopt (SO_DEBUG)");
262130088Sminshall     }
262230320Sminshall #else	/* NOT43 */
262330088Sminshall     if (debug) {
2624*31124Sminshall 	if (net > 0 && SetSockOpt(net, SOL_SOCKET, SO_DEBUG, 0, 0) < 0)
262530088Sminshall 	    perror("setsockopt (SO_DEBUG)");
262630088Sminshall     } else
262730088Sminshall 	printf("Cannot turn off socket debugging\n");
262830320Sminshall #endif	/* NOT43 */
262930088Sminshall     return 1;
263030088Sminshall }
263130088Sminshall 
263230088Sminshall 
263330088Sminshall 
263430088Sminshall extern int togglehelp();
263530088Sminshall 
263630088Sminshall struct togglelist {
263730088Sminshall     char	*name;		/* name of toggle */
263830088Sminshall     char	*help;		/* help message */
263930088Sminshall     int		(*handler)();	/* routine to do actual setting */
264030088Sminshall     int		dohelp;		/* should we display help information */
264130088Sminshall     int		*variable;
264230088Sminshall     char	*actionexplanation;
264330088Sminshall };
264430088Sminshall 
264530088Sminshall static struct togglelist Togglelist[] = {
264630088Sminshall     { "autoflush",
264730088Sminshall 	"toggle flushing of output when sending interrupt characters",
264830088Sminshall 	    0,
264930088Sminshall 		1,
265030088Sminshall 		    &autoflush,
265130088Sminshall 			"flush output when sending interrupt characters" },
265230088Sminshall     { "autosynch",
265330088Sminshall 	"toggle automatic sending of interrupt characters in urgent mode",
265430088Sminshall 	    0,
265530088Sminshall 		1,
265630088Sminshall 		    &autosynch,
265730088Sminshall 			"send interrupt characters in urgent mode" },
265830088Sminshall     { "crmod",
265930088Sminshall 	"toggle mapping of received carriage returns",
266030088Sminshall 	    0,
266130088Sminshall 		1,
266230088Sminshall 		    &crmod,
266330088Sminshall 			"map carriage return on output" },
266430088Sminshall     { "localchars",
266530088Sminshall 	"toggle local recognition of certain control characters",
266630088Sminshall 	    lclchars,
266730088Sminshall 		1,
266830088Sminshall 		    &localchars,
266930088Sminshall 			"recognize certain control characters" },
267030088Sminshall     { " ", "", 0, 1 },		/* empty line */
267130088Sminshall     { "debug",
267230088Sminshall 	"(debugging) toggle debugging",
267330088Sminshall 	    togdebug,
267430088Sminshall 		1,
267530088Sminshall 		    &debug,
267630088Sminshall 			"turn on socket level debugging" },
267730088Sminshall     { "netdata",
267830088Sminshall 	"(debugging) toggle printing of hexadecimal network data",
267930088Sminshall 	    0,
268030088Sminshall 		1,
268130088Sminshall 		    &netdata,
268230088Sminshall 			"print hexadecimal representation of network traffic" },
268330088Sminshall     { "options",
268430088Sminshall 	"(debugging) toggle viewing of options processing",
268530088Sminshall 	    0,
268630088Sminshall 		1,
268730088Sminshall 		    &showoptions,
268830088Sminshall 			"show option processing" },
268930088Sminshall     { " ", "", 0, 1 },		/* empty line */
269030088Sminshall     { "?",
269130088Sminshall 	"display help information",
269230088Sminshall 	    togglehelp,
269330088Sminshall 		1 },
269430088Sminshall     { "help",
269530088Sminshall 	"display help information",
269630088Sminshall 	    togglehelp,
269730088Sminshall 		0 },
269830088Sminshall     { 0 }
269930088Sminshall };
270030088Sminshall 
270130088Sminshall static
270230088Sminshall togglehelp()
270330088Sminshall {
270430088Sminshall     struct togglelist *c;
270530088Sminshall 
270630088Sminshall     for (c = Togglelist; c->name; c++) {
270730088Sminshall 	if (c->dohelp) {
270830088Sminshall 	    printf("%s\t%s\n", c->name, c->help);
270930088Sminshall 	}
271030088Sminshall     }
271130088Sminshall     return 0;
271230088Sminshall }
271330088Sminshall 
271430088Sminshall static char **
271530088Sminshall getnexttoggle(name)
271630088Sminshall char *name;
271730088Sminshall {
271830088Sminshall     struct togglelist *c = (struct togglelist *) name;
271930088Sminshall 
272030088Sminshall     return (char **) (c+1);
272130088Sminshall }
272230088Sminshall 
272330088Sminshall static struct togglelist *
272430088Sminshall gettoggle(name)
272530088Sminshall char *name;
272630088Sminshall {
272730088Sminshall     return (struct togglelist *)
272830088Sminshall 			genget(name, (char **) Togglelist, getnexttoggle);
272930088Sminshall }
273030088Sminshall 
273130088Sminshall static
273230088Sminshall toggle(argc, argv)
273330088Sminshall int	argc;
273430088Sminshall char	*argv[];
273530088Sminshall {
273630088Sminshall     int retval = 1;
273730088Sminshall     char *name;
273830088Sminshall     struct togglelist *c;
273930088Sminshall 
274030088Sminshall     if (argc < 2) {
274130088Sminshall 	fprintf(stderr,
274230088Sminshall 	    "Need an argument to 'toggle' command.  'toggle ?' for help.\n");
274330088Sminshall 	return 0;
274430088Sminshall     }
274530088Sminshall     argc--;
274630088Sminshall     argv++;
274730088Sminshall     while (argc--) {
274830088Sminshall 	name = *argv++;
274930088Sminshall 	c = gettoggle(name);
275030088Sminshall 	if (c == Ambiguous(struct togglelist *)) {
275130088Sminshall 	    fprintf(stderr, "'%s': ambiguous argument ('toggle ?' for help).\n",
275230088Sminshall 					name);
275330088Sminshall 	    return 0;
275430088Sminshall 	} else if (c == 0) {
275530088Sminshall 	    fprintf(stderr, "'%s': unknown argument ('toggle ?' for help).\n",
275630088Sminshall 					name);
275730088Sminshall 	    return 0;
275830088Sminshall 	} else {
275930088Sminshall 	    if (c->variable) {
276030088Sminshall 		*c->variable = !*c->variable;		/* invert it */
276130088Sminshall 		printf("%s %s.\n", *c->variable? "Will" : "Won't",
276230088Sminshall 							c->actionexplanation);
276330088Sminshall 	    }
276430088Sminshall 	    if (c->handler) {
276530088Sminshall 		retval &= (*c->handler)(c);
276630088Sminshall 	    }
276730088Sminshall 	}
276830088Sminshall     }
276930088Sminshall     return retval;
277030088Sminshall }
277130088Sminshall 
277230088Sminshall /*
277330088Sminshall  * The following perform the "set" command.
277430088Sminshall  */
277530088Sminshall 
277630088Sminshall struct setlist {
277730088Sminshall     char *name;				/* name */
277830088Sminshall     char *help;				/* help information */
277930088Sminshall     char *charp;			/* where it is located at */
278030088Sminshall };
278130088Sminshall 
278230088Sminshall static struct setlist Setlist[] = {
278330088Sminshall     { "echo", 	"character to toggle local echoing on/off", &echoc },
278430088Sminshall     { "escape",	"character to escape back to telnet command mode", &escape },
278530088Sminshall     { " ", "" },
278630088Sminshall     { " ", "The following need 'localchars' to be toggled true", 0 },
2787*31124Sminshall #if	defined(unix)
278830088Sminshall     { "erase",	"character to cause an Erase Character", &nttyb.sg_erase },
278930088Sminshall     { "flushoutput", "character to cause an Abort Oubput", &nltc.t_flushc },
279030088Sminshall     { "interrupt", "character to cause an Interrupt Process", &ntc.t_intrc },
279130088Sminshall     { "kill",	"character to cause an Erase Line", &nttyb.sg_kill },
279230088Sminshall     { "quit",	"character to cause a Break", &ntc.t_quitc },
279330088Sminshall     { "eof",	"character to cause an EOF ", &ntc.t_eofc },
2794*31124Sminshall #endif	/* defined(unix) */
2795*31124Sminshall #if	defined(MSDOS)
2796*31124Sminshall     { "erase",	"character to cause an Erase Character", &termEraseChar },
2797*31124Sminshall     { "flushoutput", "character to cause an Abort Oubput", &termFlushChar },
2798*31124Sminshall     { "interrupt", "character to cause an Interrupt Process", &termIntChar },
2799*31124Sminshall     { "kill",	"character to cause an Erase Line", &termKillChar },
2800*31124Sminshall     { "quit",	"character to cause a Break", &termQuitChar },
2801*31124Sminshall     { "eof",	"character to cause an EOF ", &termEofChar },
2802*31124Sminshall #endif	/* defined(MSDOS) */
280330088Sminshall     { 0 }
280430088Sminshall };
280530088Sminshall 
280630088Sminshall static char **
280730088Sminshall getnextset(name)
280830088Sminshall char *name;
280930088Sminshall {
281030088Sminshall     struct setlist *c = (struct setlist *)name;
281130088Sminshall 
281230088Sminshall     return (char **) (c+1);
281330088Sminshall }
281430088Sminshall 
281530088Sminshall static struct setlist *
281630088Sminshall getset(name)
281730088Sminshall char *name;
281830088Sminshall {
281930088Sminshall     return (struct setlist *) genget(name, (char **) Setlist, getnextset);
282030088Sminshall }
282130088Sminshall 
282230088Sminshall static
282330088Sminshall setcmd(argc, argv)
282430088Sminshall int	argc;
282530088Sminshall char	*argv[];
282630088Sminshall {
282730088Sminshall     int value;
282830088Sminshall     struct setlist *ct;
282930088Sminshall 
283030088Sminshall     /* XXX back we go... sigh */
283130088Sminshall     if (argc != 3) {
283230088Sminshall 	if ((argc == 2) &&
283330088Sminshall 		    ((!strcmp(argv[1], "?")) || (!strcmp(argv[1], "help")))) {
283430088Sminshall 	    for (ct = Setlist; ct->name; ct++) {
283530088Sminshall 		printf("%s\t%s\n", ct->name, ct->help);
283630088Sminshall 	    }
283730088Sminshall 	    printf("?\tdisplay help information\n");
283830088Sminshall 	} else {
283930088Sminshall 	    printf("Format is 'set Name Value'\n'set ?' for help.\n");
284030088Sminshall 	}
284130088Sminshall 	return 0;
284230088Sminshall     }
284330088Sminshall 
284430088Sminshall     ct = getset(argv[1]);
284530088Sminshall     if (ct == 0) {
284630088Sminshall 	fprintf(stderr, "'%s': unknown argument ('set ?' for help).\n",
284730088Sminshall 			argv[1]);
284830088Sminshall 	return 0;
284930088Sminshall     } else if (ct == Ambiguous(struct setlist *)) {
285030088Sminshall 	fprintf(stderr, "'%s': ambiguous argument ('set ?' for help).\n",
285130088Sminshall 			argv[1]);
285230088Sminshall 	return 0;
285330088Sminshall     } else {
285430088Sminshall 	if (strcmp("off", argv[2])) {
285530088Sminshall 	    value = special(argv[2]);
285630088Sminshall 	} else {
285730088Sminshall 	    value = -1;
285830088Sminshall 	}
285930088Sminshall 	*(ct->charp) = value;
286030088Sminshall 	printf("%s character is '%s'.\n", ct->name, control(*(ct->charp)));
286130088Sminshall     }
286230088Sminshall     return 1;
286330088Sminshall }
286430088Sminshall 
286530088Sminshall /*
286630088Sminshall  * The following are the data structures and routines for the
286730088Sminshall  * 'mode' command.
286830088Sminshall  */
286930088Sminshall 
287030088Sminshall static
287130088Sminshall dolinemode()
287230088Sminshall {
287330088Sminshall     if (hisopts[TELOPT_SGA]) {
287430088Sminshall 	wontoption(TELOPT_SGA, 0);
287530088Sminshall     }
287630088Sminshall     if (hisopts[TELOPT_ECHO]) {
287730088Sminshall 	wontoption(TELOPT_ECHO, 0);
287830088Sminshall     }
287930088Sminshall     return 1;
288030088Sminshall }
288130088Sminshall 
288230088Sminshall static
288330088Sminshall docharmode()
288430088Sminshall {
288530088Sminshall     if (!hisopts[TELOPT_SGA]) {
288630088Sminshall 	willoption(TELOPT_SGA, 0);
288730088Sminshall     }
288830088Sminshall     if (!hisopts[TELOPT_ECHO]) {
288930088Sminshall 	willoption(TELOPT_ECHO, 0);
289030088Sminshall     }
289130088Sminshall     return 1;
289230088Sminshall }
289330088Sminshall 
289430088Sminshall static struct cmd Modelist[] = {
289530088Sminshall     { "character",	"character-at-a-time mode",	docharmode, 1, 1 },
289630088Sminshall     { "line",		"line-by-line mode",		dolinemode, 1, 1 },
289730088Sminshall     { 0 },
289830088Sminshall };
289930088Sminshall 
290030088Sminshall static char **
290130088Sminshall getnextmode(name)
290230088Sminshall char *name;
290330088Sminshall {
290430088Sminshall     struct cmd *c = (struct cmd *) name;
290530088Sminshall 
290630088Sminshall     return (char **) (c+1);
290730088Sminshall }
290830088Sminshall 
290930088Sminshall static struct cmd *
291030088Sminshall getmodecmd(name)
291130088Sminshall char *name;
291230088Sminshall {
291330088Sminshall     return (struct cmd *) genget(name, (char **) Modelist, getnextmode);
291430088Sminshall }
291530088Sminshall 
291630088Sminshall static
291730088Sminshall modecmd(argc, argv)
291830088Sminshall int	argc;
291930088Sminshall char	*argv[];
292030088Sminshall {
292130088Sminshall     struct cmd *mt;
292230088Sminshall 
292330088Sminshall     if ((argc != 2) || !strcmp(argv[1], "?") || !strcmp(argv[1], "help")) {
292430088Sminshall 	printf("format is:  'mode Mode', where 'Mode' is one of:\n\n");
292530088Sminshall 	for (mt = Modelist; mt->name; mt++) {
292630088Sminshall 	    printf("%s\t%s\n", mt->name, mt->help);
292730088Sminshall 	}
292830088Sminshall 	return 0;
292930088Sminshall     }
293030088Sminshall     mt = getmodecmd(argv[1]);
293130088Sminshall     if (mt == 0) {
293230088Sminshall 	fprintf(stderr, "Unknown mode '%s' ('mode ?' for help).\n", argv[1]);
293330088Sminshall 	return 0;
293430088Sminshall     } else if (mt == Ambiguous(struct cmd *)) {
293530088Sminshall 	fprintf(stderr, "Ambiguous mode '%s' ('mode ?' for help).\n", argv[1]);
293630088Sminshall 	return 0;
293730088Sminshall     } else {
293830088Sminshall 	(*mt->handler)();
293930088Sminshall     }
294030088Sminshall     return 1;
294130088Sminshall }
294230088Sminshall 
294330088Sminshall /*
294430088Sminshall  * The following data structures and routines implement the
294530088Sminshall  * "display" command.
294630088Sminshall  */
294730088Sminshall 
294830088Sminshall static
294930088Sminshall display(argc, argv)
295030088Sminshall int	argc;
295130088Sminshall char	*argv[];
295230088Sminshall {
295330088Sminshall #define	dotog(tl)	if (tl->variable && tl->actionexplanation) { \
295430088Sminshall 			    if (*tl->variable) { \
295530088Sminshall 				printf("will"); \
295630088Sminshall 			    } else { \
295730088Sminshall 				printf("won't"); \
295830088Sminshall 			    } \
295930088Sminshall 			    printf(" %s.\n", tl->actionexplanation); \
296030088Sminshall 			}
296130088Sminshall 
296230088Sminshall #define	doset(sl)   if (sl->name && *sl->name != ' ') { \
296330088Sminshall 			printf("[%s]\t%s.\n", control(*sl->charp), sl->name); \
296430088Sminshall 		    }
296530088Sminshall 
296630088Sminshall     struct togglelist *tl;
296730088Sminshall     struct setlist *sl;
296830088Sminshall 
296930088Sminshall     if (argc == 1) {
297030088Sminshall 	for (tl = Togglelist; tl->name; tl++) {
297130088Sminshall 	    dotog(tl);
297230088Sminshall 	}
297330088Sminshall 	printf("\n");
297430088Sminshall 	for (sl = Setlist; sl->name; sl++) {
297530088Sminshall 	    doset(sl);
297630088Sminshall 	}
297730088Sminshall     } else {
297830088Sminshall 	int i;
297930088Sminshall 
298030088Sminshall 	for (i = 1; i < argc; i++) {
298130088Sminshall 	    sl = getset(argv[i]);
298230088Sminshall 	    tl = gettoggle(argv[i]);
298330088Sminshall 	    if ((sl == Ambiguous(struct setlist *)) ||
298430088Sminshall 				(tl == Ambiguous(struct togglelist *))) {
298530088Sminshall 		printf("?Ambiguous argument '%s'.\n", argv[i]);
298630088Sminshall 		return 0;
298730088Sminshall 	    } else if (!sl && !tl) {
298830088Sminshall 		printf("?Unknown argument '%s'.\n", argv[i]);
298930088Sminshall 		return 0;
299030088Sminshall 	    } else {
299130088Sminshall 		if (tl) {
299230088Sminshall 		    dotog(tl);
299330088Sminshall 		}
299430088Sminshall 		if (sl) {
299530088Sminshall 		    doset(sl);
299630088Sminshall 		}
299730088Sminshall 	    }
299830088Sminshall 	}
299930088Sminshall     }
300030088Sminshall     return 1;
300130088Sminshall #undef	doset
300230088Sminshall #undef	dotog
300330088Sminshall }
300430088Sminshall 
300530088Sminshall /*
300630088Sminshall  * The following are the data structures, and many of the routines,
300730088Sminshall  * relating to command processing.
300830088Sminshall  */
300930088Sminshall 
301030088Sminshall /*
301130088Sminshall  * Set the escape character.
301230088Sminshall  */
301330088Sminshall static
301430088Sminshall setescape(argc, argv)
301530088Sminshall 	int argc;
301630088Sminshall 	char *argv[];
301730088Sminshall {
301830088Sminshall 	register char *arg;
301930088Sminshall 	char buf[50];
302030088Sminshall 
302130088Sminshall 	printf(
302230088Sminshall 	    "Deprecated usage - please use 'set escape%s%s' in the future.\n",
302330088Sminshall 				(argc > 2)? " ":"", (argc > 2)? argv[1]: "");
302430088Sminshall 	if (argc > 2)
302530088Sminshall 		arg = argv[1];
302630088Sminshall 	else {
302730088Sminshall 		printf("new escape character: ");
302830088Sminshall 		gets(buf);
302930088Sminshall 		arg = buf;
303030088Sminshall 	}
303130088Sminshall 	if (arg[0] != '\0')
303230088Sminshall 		escape = arg[0];
303330088Sminshall 	if (!In3270) {
303430088Sminshall 		printf("Escape character is '%s'.\n", control(escape));
303530088Sminshall 	}
303630088Sminshall 	fflush(stdout);
303730088Sminshall 	return 1;
303830088Sminshall }
303930088Sminshall 
304030088Sminshall /*VARARGS*/
304130088Sminshall static
304230088Sminshall togcrmod()
304330088Sminshall {
304430088Sminshall     crmod = !crmod;
304530088Sminshall     printf("Deprecated usage - please use 'toggle crmod' in the future.\n");
304630088Sminshall     printf("%s map carriage return on output.\n", crmod ? "Will" : "Won't");
304730088Sminshall     fflush(stdout);
304830088Sminshall     return 1;
304930088Sminshall }
305030088Sminshall 
305130088Sminshall /*VARARGS*/
305230088Sminshall suspend()
305330088Sminshall {
305430088Sminshall 	setcommandmode();
305530088Sminshall #if	defined(unix)
305630088Sminshall 	kill(0, SIGTSTP);
3057*31124Sminshall 	/* reget parameters in case they were changed */
3058*31124Sminshall 	TerminalSaveState();
305930088Sminshall #endif	/* defined(unix) */
306030088Sminshall 	return 1;
306130088Sminshall }
306230088Sminshall 
306330088Sminshall /*VARARGS*/
306430088Sminshall static
306530326Sminshall bye(argc, argv)
306630326Sminshall int	argc;		/* Number of arguments */
306730326Sminshall char	*argv[];	/* arguments */
306830088Sminshall {
306930088Sminshall     if (connected) {
307030088Sminshall 	shutdown(net, 2);
307130088Sminshall 	printf("Connection closed.\n");
307230088Sminshall 	close(net);
307330088Sminshall 	connected = 0;
307430088Sminshall 	/* reset options */
307530326Sminshall 	tninit();
307630088Sminshall #if	defined(TN3270)
307730326Sminshall 	SetIn3270();		/* Get out of 3270 mode */
307830088Sminshall #endif	/* defined(TN3270) */
307930088Sminshall     }
308030326Sminshall     if ((argc != 2) || (strcmp(argv[1], "fromquit") != 0)) {
308130326Sminshall 	longjmp(toplevel, 1);
308230326Sminshall 	/* NOTREACHED */
308330326Sminshall     }
308430326Sminshall     return 1;			/* Keep lint, etc., happy */
308530088Sminshall }
308630088Sminshall 
308730088Sminshall /*VARARGS*/
308830088Sminshall quit()
308930088Sminshall {
309030326Sminshall 	(void) call(bye, "bye", "fromquit", 0);
309130088Sminshall 	Exit(0);
309230088Sminshall 	/*NOTREACHED*/
309330088Sminshall 	return 1;			/* just to keep lint happy */
309430088Sminshall }
309530088Sminshall 
309630088Sminshall /*
309730088Sminshall  * Print status about the connection.
309830088Sminshall  */
309930088Sminshall static
310030088Sminshall status(argc, argv)
310130088Sminshall int	argc;
310230088Sminshall char	*argv[];
310330088Sminshall {
310430088Sminshall     if (connected) {
310530088Sminshall 	printf("Connected to %s.\n", hostname);
310630088Sminshall 	if (argc < 2) {
310730088Sminshall 	    printf("Operating in %s.\n",
310830088Sminshall 				modelist[getconnmode()].modedescriptions);
310930088Sminshall 	    if (localchars) {
311030088Sminshall 		printf("Catching signals locally.\n");
311130088Sminshall 	    }
311230088Sminshall 	}
311330088Sminshall     } else {
311430088Sminshall 	printf("No connection.\n");
311530088Sminshall     }
311630088Sminshall #   if !defined(TN3270)
311730088Sminshall     printf("Escape character is '%s'.\n", control(escape));
311830088Sminshall     fflush(stdout);
311930088Sminshall #   else /* !defined(TN3270) */
312030088Sminshall     if ((!In3270) && ((argc < 2) || strcmp(argv[1], "notmuch"))) {
312130088Sminshall 	printf("Escape character is '%s'.\n", control(escape));
312230088Sminshall     }
312330088Sminshall #   if defined(unix)
312430088Sminshall     if (In3270 && transcom) {
312530088Sminshall        printf("Transparent mode command is '%s'.\n", transcom);
312630088Sminshall     }
312730088Sminshall #   endif /* defined(unix) */
312830088Sminshall     fflush(stdout);
312930088Sminshall     if (In3270) {
313030088Sminshall 	return 0;
313130088Sminshall     }
313230088Sminshall #   endif /* defined(TN3270) */
313330088Sminshall     return 1;
313430088Sminshall }
313530088Sminshall 
313630088Sminshall #if	defined(TN3270) && defined(unix)
313730088Sminshall static
313830088Sminshall settranscom(argc, argv)
313930088Sminshall 	int argc;
314030088Sminshall 	char *argv[];
314130088Sminshall {
314230088Sminshall 	int i, len = 0;
314330088Sminshall 	char *strcpy(), *strcat();
314430088Sminshall 
314530088Sminshall 	if (argc == 1 && transcom) {
314630088Sminshall 	   transcom = 0;
314730088Sminshall 	}
314830088Sminshall 	if (argc == 1) {
314930088Sminshall 	   return;
315030088Sminshall 	}
315130088Sminshall 	for (i = 1; i < argc; ++i) {
315230088Sminshall 	    len += 1 + strlen(argv[1]);
315330088Sminshall 	}
315430088Sminshall 	transcom = tline;
315530088Sminshall 	(void) strcpy(transcom, argv[1]);
315630088Sminshall 	for (i = 2; i < argc; ++i) {
315730088Sminshall 	    (void) strcat(transcom, " ");
315830088Sminshall 	    (void) strcat(transcom, argv[i]);
315930088Sminshall 	}
316030088Sminshall }
316130088Sminshall #endif	/* defined(TN3270) && defined(unix) */
316230088Sminshall 
316330088Sminshall 
316430088Sminshall static
316530088Sminshall tn(argc, argv)
316630088Sminshall 	int argc;
316730088Sminshall 	char *argv[];
316830088Sminshall {
316930088Sminshall     register struct hostent *host = 0;
317030088Sminshall #if defined(msdos)
317130088Sminshall     char *cp;
317230320Sminshall #endif	/* defined(msdos) */
317330088Sminshall 
317430088Sminshall     if (connected) {
317530088Sminshall 	printf("?Already connected to %s\n", hostname);
317630088Sminshall 	return 0;
317730088Sminshall     }
317830088Sminshall     if (argc < 2) {
317930088Sminshall 	(void) strcpy(line, "Connect ");
318030088Sminshall 	printf("(to) ");
318130088Sminshall 	gets(&line[strlen(line)]);
318230088Sminshall 	makeargv();
318330088Sminshall 	argc = margc;
318430088Sminshall 	argv = margv;
318530088Sminshall     }
318630088Sminshall     if (argc > 3) {
318730088Sminshall 	printf("usage: %s host-name [port]\n", argv[0]);
318830088Sminshall 	return 0;
318930088Sminshall     }
319030088Sminshall #if	defined(msdos)
319130088Sminshall     for (cp = argv[1]; *cp; cp++) {
319230088Sminshall 	if (isupper(*cp)) {
319330088Sminshall 	    *cp = tolower(*cp);
319430088Sminshall 	}
319530088Sminshall     }
319630088Sminshall #endif	/* defined(msdos) */
319730088Sminshall     sin.sin_addr.s_addr = inet_addr(argv[1]);
319830088Sminshall     if (sin.sin_addr.s_addr != -1) {
319930088Sminshall 	sin.sin_family = AF_INET;
320030088Sminshall 	(void) strcpy(hnamebuf, argv[1]);
320130088Sminshall 	hostname = hnamebuf;
320230088Sminshall     } else {
320330088Sminshall 	host = gethostbyname(argv[1]);
320430088Sminshall 	if (host) {
320530088Sminshall 	    sin.sin_family = host->h_addrtype;
320630088Sminshall #if	defined(h_addr)		/* In 4.3, this is a #define */
320730088Sminshall 	    bcopy(host->h_addr_list[0], (caddr_t)&sin.sin_addr, host->h_length);
320830088Sminshall #else	/* defined(h_addr) */
320930088Sminshall 	    bcopy(host->h_addr, (caddr_t)&sin.sin_addr, host->h_length);
321030088Sminshall #endif	/* defined(h_addr) */
321130088Sminshall 	    hostname = host->h_name;
321230088Sminshall 	} else {
321330088Sminshall 	    printf("%s: unknown host\n", argv[1]);
321430088Sminshall 	    return 0;
321530088Sminshall 	}
321630088Sminshall     }
321730088Sminshall     sin.sin_port = sp->s_port;
321830088Sminshall     if (argc == 3) {
321930088Sminshall 	sin.sin_port = atoi(argv[2]);
322030088Sminshall 	if (sin.sin_port == 0) {
322130088Sminshall 	    sp = getservbyname(argv[2], "tcp");
322230088Sminshall 	    if (sp)
322330088Sminshall 		sin.sin_port = sp->s_port;
322430088Sminshall 	    else {
322530088Sminshall 		printf("%s: bad port number\n", argv[2]);
322630088Sminshall 		return 0;
322730088Sminshall 	    }
322830088Sminshall 	} else {
322930088Sminshall 	    sin.sin_port = atoi(argv[2]);
323030088Sminshall 	    sin.sin_port = htons(sin.sin_port);
323130088Sminshall 	}
323230088Sminshall 	telnetport = 0;
323330088Sminshall     } else {
323430088Sminshall 	telnetport = 1;
323530088Sminshall     }
323630088Sminshall #if	defined(unix)
323730088Sminshall     signal(SIGINT, intr);
323830088Sminshall     signal(SIGQUIT, intr2);
323930088Sminshall     signal(SIGPIPE, deadpeer);
324030088Sminshall #endif	/* defined(unix) */
324130088Sminshall     printf("Trying...\n");
324230088Sminshall     do {
324330088Sminshall 	net = socket(AF_INET, SOCK_STREAM, 0);
324430088Sminshall 	if (net < 0) {
324530088Sminshall 	    perror("telnet: socket");
324630088Sminshall 	    return 0;
324730088Sminshall 	}
3248*31124Sminshall 	if (debug && SetSockOpt(net, SOL_SOCKET, SO_DEBUG, 1) < 0) {
324930088Sminshall 		perror("setsockopt (SO_DEBUG)");
3250*31124Sminshall 	}
325130088Sminshall 
325230088Sminshall 	if (connect(net, (struct sockaddr *)&sin, sizeof (sin)) < 0) {
325330088Sminshall #if	defined(h_addr)		/* In 4.3, this is a #define */
325430088Sminshall 	    if (host && host->h_addr_list[1]) {
325530088Sminshall 		int oerrno = errno;
325630088Sminshall 
325730088Sminshall 		fprintf(stderr, "telnet: connect to address %s: ",
325830088Sminshall 						inet_ntoa(sin.sin_addr));
325930088Sminshall 		errno = oerrno;
326030088Sminshall 		perror((char *)0);
326130088Sminshall 		host->h_addr_list++;
326230088Sminshall 		bcopy(host->h_addr_list[0],
326330088Sminshall 		    (caddr_t)&sin.sin_addr, host->h_length);
326430088Sminshall 		fprintf(stderr, "Trying %s...\n",
326530088Sminshall 			inet_ntoa(sin.sin_addr));
326630088Sminshall 		(void) close(net);
326730088Sminshall 		continue;
326830088Sminshall 	    }
326930088Sminshall #endif	/* defined(h_addr) */
327030088Sminshall 	    perror("telnet: Unable to connect to remote host");
327130088Sminshall #if defined(unix)
327230088Sminshall 	    signal(SIGINT, SIG_DFL);
327330088Sminshall 	    signal(SIGQUIT, SIG_DFL);
327430320Sminshall #endif	/* defined(unix) */
327530088Sminshall 	    return 0;
327630088Sminshall 	    }
327730088Sminshall 	connected++;
327830088Sminshall     } while (connected == 0);
327930088Sminshall     call(status, "status", "notmuch", 0);
328030088Sminshall     if (setjmp(peerdied) == 0)
328130088Sminshall 	telnet();
328230088Sminshall     ExitString(stderr, "Connection closed by foreign host.\n",1);
328330088Sminshall     /*NOTREACHED*/
328430088Sminshall }
328530088Sminshall 
328630088Sminshall 
328730088Sminshall #define HELPINDENT (sizeof ("connect"))
328830088Sminshall 
328930088Sminshall static char
329030088Sminshall 	openhelp[] =	"connect to a site",
329130088Sminshall 	closehelp[] =	"close current connection",
329230088Sminshall 	quithelp[] =	"exit telnet",
329330088Sminshall 	zhelp[] =	"suspend telnet",
329430088Sminshall 	statushelp[] =	"print status information",
329530088Sminshall 	helphelp[] =	"print help information",
329630088Sminshall 	sendhelp[] =	"transmit special characters ('send ?' for more)",
329730088Sminshall 	sethelp[] = 	"set operating parameters ('set ?' for more)",
329830088Sminshall 	togglestring[] ="toggle operating parameters ('toggle ?' for more)",
329930088Sminshall 	displayhelp[] =	"display operating parameters",
330030088Sminshall #if	defined(TN3270) && defined(unix)
330130088Sminshall 	transcomhelp[] = "specify Unix command for transparent mode pipe",
330230088Sminshall #endif	/* defined(TN3270) && defined(unix) */
330330088Sminshall 	modehelp[] = "try to enter line-by-line or character-at-a-time mode";
330430088Sminshall 
330530088Sminshall extern int	help();
330630088Sminshall 
330730088Sminshall static struct cmd cmdtab[] = {
330830088Sminshall 	{ "close",	closehelp,	bye,		1, 1 },
330930088Sminshall 	{ "display",	displayhelp,	display,	1, 0 },
331030088Sminshall 	{ "mode",	modehelp,	modecmd,	1, 1 },
331130088Sminshall 	{ "open",	openhelp,	tn,		1, 0 },
331230088Sminshall 	{ "quit",	quithelp,	quit,		1, 0 },
331330088Sminshall 	{ "send",	sendhelp,	sendcmd,	1, 1 },
331430088Sminshall 	{ "set",	sethelp,	setcmd,		1, 0 },
331530088Sminshall 	{ "status",	statushelp,	status,		1, 0 },
331630088Sminshall 	{ "toggle",	togglestring,	toggle,		1, 0 },
331730088Sminshall #if	defined(TN3270) && defined(unix)
331830088Sminshall 	{ "transcom",	transcomhelp,	settranscom,	1, 0 },
331930088Sminshall #endif	/* defined(TN3270) && defined(unix) */
332030088Sminshall 	{ "z",		zhelp,		suspend,	1, 0 },
332130088Sminshall 	{ "?",		helphelp,	help,		1, 0 },
332230088Sminshall 	0
332330088Sminshall };
332430088Sminshall 
332530088Sminshall static char	crmodhelp[] =	"deprecated command -- use 'toggle crmod' instead";
332630088Sminshall static char	escapehelp[] =	"deprecated command -- use 'set escape' instead";
332730088Sminshall 
332830088Sminshall static struct cmd cmdtab2[] = {
332930088Sminshall 	{ "help",	helphelp,	help,		0, 0 },
333030088Sminshall 	{ "escape",	escapehelp,	setescape,	1, 0 },
333130088Sminshall 	{ "crmod",	crmodhelp,	togcrmod,	1, 0 },
333230088Sminshall 	0
333330088Sminshall };
333430088Sminshall 
333530088Sminshall /*
333630088Sminshall  * Call routine with argc, argv set from args (terminated by 0).
333730088Sminshall  * VARARGS2
333830088Sminshall  */
333930088Sminshall static
334030088Sminshall call(routine, args)
334130088Sminshall 	int (*routine)();
334230088Sminshall 	char *args;
334330088Sminshall {
334430088Sminshall 	register char **argp;
334530088Sminshall 	register int argc;
334630088Sminshall 
334730088Sminshall 	for (argc = 0, argp = &args; *argp++ != 0; argc++)
334830088Sminshall 		;
334930088Sminshall 	return (*routine)(argc, &args);
335030088Sminshall }
335130088Sminshall 
335230088Sminshall static char **
335330088Sminshall getnextcmd(name)
335430088Sminshall char *name;
335530088Sminshall {
335630088Sminshall     struct cmd *c = (struct cmd *) name;
335730088Sminshall 
335830088Sminshall     return (char **) (c+1);
335930088Sminshall }
336030088Sminshall 
336130088Sminshall static struct cmd *
336230088Sminshall getcmd(name)
336330088Sminshall char *name;
336430088Sminshall {
336530088Sminshall     struct cmd *cm;
336630088Sminshall 
336730088Sminshall     if ((cm = (struct cmd *) genget(name, (char **) cmdtab, getnextcmd)) != 0) {
336830088Sminshall 	return cm;
336930088Sminshall     } else {
337030088Sminshall 	return (struct cmd *) genget(name, (char **) cmdtab2, getnextcmd);
337130088Sminshall     }
337230088Sminshall }
337330088Sminshall 
337430088Sminshall void
337530088Sminshall command(top)
337630088Sminshall 	int top;
337730088Sminshall {
337830088Sminshall 	register struct cmd *c;
337930088Sminshall 
338030088Sminshall 	setcommandmode();
338130088Sminshall 	if (!top) {
338230088Sminshall 		putchar('\n');
338330088Sminshall 	} else {
338430088Sminshall #if	defined(unix)
338530088Sminshall 		signal(SIGINT, SIG_DFL);
338630088Sminshall 		signal(SIGQUIT, SIG_DFL);
338730088Sminshall #endif	/* defined(unix) */
338830088Sminshall 	}
338930088Sminshall 	for (;;) {
339030088Sminshall 		printf("%s> ", prompt);
339130088Sminshall 		if (gets(line) == NULL) {
339230088Sminshall 			if (feof(stdin) || ferror(stdin))
339330088Sminshall 				quit();
339430088Sminshall 			break;
339530088Sminshall 		}
339630088Sminshall 		if (line[0] == 0)
339730088Sminshall 			break;
339830088Sminshall 		makeargv();
339930088Sminshall 		c = getcmd(margv[0]);
340030088Sminshall 		if (c == Ambiguous(struct cmd *)) {
340130088Sminshall 			printf("?Ambiguous command\n");
340230088Sminshall 			continue;
340330088Sminshall 		}
340430088Sminshall 		if (c == 0) {
340530088Sminshall 			printf("?Invalid command\n");
340630088Sminshall 			continue;
340730088Sminshall 		}
340830088Sminshall 		if (c->needconnect && !connected) {
340930088Sminshall 			printf("?Need to be connected first.\n");
341030088Sminshall 			continue;
341130088Sminshall 		}
341230088Sminshall 		if ((*c->handler)(margc, margv)) {
341330088Sminshall 			break;
341430088Sminshall 		}
341530088Sminshall 	}
341630088Sminshall 	if (!top) {
341730088Sminshall 		if (!connected) {
341830088Sminshall 			longjmp(toplevel, 1);
341930088Sminshall 			/*NOTREACHED*/
342030088Sminshall 		}
342130088Sminshall 		setconnmode();
342230088Sminshall 	}
342330088Sminshall }
342430088Sminshall 
342530088Sminshall /*
342630088Sminshall  * Help command.
342730088Sminshall  */
342830088Sminshall static
342930088Sminshall help(argc, argv)
343030088Sminshall 	int argc;
343130088Sminshall 	char *argv[];
343230088Sminshall {
343330088Sminshall 	register struct cmd *c;
343430088Sminshall 
343530088Sminshall 	if (argc == 1) {
343630088Sminshall 		printf("Commands may be abbreviated.  Commands are:\n\n");
343730088Sminshall 		for (c = cmdtab; c->name; c++)
343830088Sminshall 			if (c->dohelp) {
343930088Sminshall 				printf("%-*s\t%s\n", HELPINDENT, c->name,
344030088Sminshall 								    c->help);
344130088Sminshall 			}
344230088Sminshall 		return 0;
344330088Sminshall 	}
344430088Sminshall 	while (--argc > 0) {
344530088Sminshall 		register char *arg;
344630088Sminshall 		arg = *++argv;
344730088Sminshall 		c = getcmd(arg);
344830088Sminshall 		if (c == Ambiguous(struct cmd *))
344930088Sminshall 			printf("?Ambiguous help command %s\n", arg);
345030088Sminshall 		else if (c == (struct cmd *)0)
345130088Sminshall 			printf("?Invalid help command %s\n", arg);
345230088Sminshall 		else
345330088Sminshall 			printf("%s\n", c->help);
345430088Sminshall 	}
345530088Sminshall 	return 0;
345630088Sminshall }
345730088Sminshall 
345830088Sminshall /*
345930088Sminshall  * main.  Parse arguments, invoke the protocol or command parser.
346030088Sminshall  */
346130088Sminshall 
346230088Sminshall 
346330088Sminshall void
346430088Sminshall main(argc, argv)
346530088Sminshall 	int argc;
346630088Sminshall 	char *argv[];
346730088Sminshall {
346830326Sminshall     tninit();		/* Clear out things */
346930326Sminshall 
347030088Sminshall     NetTrace = stdout;
3471*31124Sminshall     TerminalSaveState();
3472*31124Sminshall     autoflush = TerminalAutoFlush();
3473*31124Sminshall 
347430088Sminshall     prompt = argv[0];
347530088Sminshall     if (argc > 1 && !strcmp(argv[1], "-d")) {
347630088Sminshall 	debug = 1;
347730088Sminshall 	argv++;
347830088Sminshall 	argc--;
347930088Sminshall     }
348030088Sminshall     if (argc > 1 && !strcmp(argv[1], "-n")) {
348130088Sminshall 	argv++;
348230088Sminshall 	argc--;
348330088Sminshall 	if (argc > 1) {		/* get file name */
348430088Sminshall 	    NetTrace = fopen(argv[1], "w");
348530088Sminshall 	    argv++;
348630088Sminshall 	    argc--;
348730088Sminshall 	    if (NetTrace == NULL) {
348830088Sminshall 		NetTrace = stdout;
348930088Sminshall 	    }
349030088Sminshall 	}
349130088Sminshall     }
349230088Sminshall #if	defined(TN3270) && defined(unix)
349330088Sminshall     if (argc > 1 && !strcmp(argv[1], "-t")) {
349430088Sminshall 	argv++;
349530088Sminshall 	argc--;
349630088Sminshall 	if (argc > 1) {		/* get command name */
349730088Sminshall 	    transcom = tline;
349830088Sminshall 	    (void) strcpy(transcom, argv[1]);
349930088Sminshall 	    argv++;
350030088Sminshall 	    argc--;
350130088Sminshall 	}
350230088Sminshall     }
350330088Sminshall #endif	/* defined(TN3270) && defined(unix) */
350430088Sminshall     if (argc != 1) {
350530088Sminshall 	if (setjmp(toplevel) != 0)
350630088Sminshall 	    Exit(0);
350730088Sminshall 	tn(argc, argv);
350830088Sminshall     }
350930088Sminshall     setjmp(toplevel);
351030088Sminshall     for (;;)
351130088Sminshall 	command(1);
351230088Sminshall }
3513