xref: /csrg-svn/usr.bin/tn3270/telnet.c (revision 30088)
1*30088Sminshall /*
2*30088Sminshall  *	Copyright (c) 1984, 1985, 1986 by the Regents of the
3*30088Sminshall  *	University of California and by Gregory Glenn Minshall.
4*30088Sminshall  *
5*30088Sminshall  *	Permission to use, copy, modify, and distribute these
6*30088Sminshall  *	programs and their documentation for any purpose and
7*30088Sminshall  *	without fee is hereby granted, provided that this
8*30088Sminshall  *	copyright and permission appear on all copies and
9*30088Sminshall  *	supporting documentation, the name of the Regents of
10*30088Sminshall  *	the University of California not be used in advertising
11*30088Sminshall  *	or publicity pertaining to distribution of the programs
12*30088Sminshall  *	without specific prior permission, and notice be given in
13*30088Sminshall  *	supporting documentation that copying and distribution is
14*30088Sminshall  *	by permission of the Regents of the University of California
15*30088Sminshall  *	and by Gregory Glenn Minshall.  Neither the Regents of the
16*30088Sminshall  *	University of California nor Gregory Glenn Minshall make
17*30088Sminshall  *	representations about the suitability of this software
18*30088Sminshall  *	for any purpose.  It is provided "as is" without
19*30088Sminshall  *	express or implied warranty.
20*30088Sminshall  */
21*30088Sminshall 
22*30088Sminshall #ifndef lint
23*30088Sminshall static char copyright[] =
24*30088Sminshall "@(#) Copyright (c) 1984, 1985, 1986 Regents of the University of California.\n\
25*30088Sminshall  All rights reserved.\n";
26*30088Sminshall #endif not lint
27*30088Sminshall 
28*30088Sminshall #ifndef lint
29*30088Sminshall static char sccsid[] = "@(#)telnet.c	3.1  10/29/86";
30*30088Sminshall #endif not lint
31*30088Sminshall 
32*30088Sminshall /*
33*30088Sminshall  * User telnet program, modified for use by tn3270.c.
34*30088Sminshall  *
35*30088Sminshall  * Many of the FUNCTIONAL changes in this newest version of TELNET
36*30088Sminshall  * were suggested by Dave Borman of Cray Research, Inc.
37*30088Sminshall  *
38*30088Sminshall  * Other changes in the tn3270 side come from Alan Crosswell (Columbia),
39*30088Sminshall  * Bob Braden (ISI), Steve Jacobson (Berkeley), and Cliff Frost (Berkeley).
40*30088Sminshall  *
41*30088Sminshall  * This code is common between telnet(1c) and tn3270(1c).  There are the
42*30088Sminshall  * following defines used to generate the various versions:
43*30088Sminshall  *
44*30088Sminshall  *	TN3270		- 	This is to be linked with tn3270.
45*30088Sminshall  *
46*30088Sminshall  *	DEBUG		-	Allow for some extra debugging operations.
47*30088Sminshall  *
48*30088Sminshall  *	NOT43		-	Allows the program to compile and run on
49*30088Sminshall  *				a 4.2BSD system.
50*30088Sminshall  *
51*30088Sminshall  *	PUTCHAR		-	Within tn3270, on a NOT43 system,
52*30088Sminshall  *				allows the use of the 4.3 curses
53*30088Sminshall  *				(greater speed updating the screen).
54*30088Sminshall  *				You need the 4.3 curses for this to work.
55*30088Sminshall  *
56*30088Sminshall  *	FD_SETSIZE	-	On whichever system, if this isn't defined,
57*30088Sminshall  *				we patch over the FD_SET, etc., macros with
58*30088Sminshall  *				some homebrewed ones.
59*30088Sminshall  *
60*30088Sminshall  *	SO_OOBINLINE	-	This is a socket option which we would like
61*30088Sminshall  *				to set to allow TCP urgent data to come
62*30088Sminshall  *				to us "inline".  This is NECESSARY for
63*30088Sminshall  *				CORRECT operation, and desireable for
64*30088Sminshall  *				simpler operation.
65*30088Sminshall  *
66*30088Sminshall  *	LNOFLSH		-	Detects the presence of the LNOFLSH bit
67*30088Sminshall  *				in the tty structure.
68*30088Sminshall  *
69*30088Sminshall  *	unix		-	Compiles in unix specific stuff.
70*30088Sminshall  *
71*30088Sminshall  *	msdos		-	Compiles in msdos specific stuff.
72*30088Sminshall  *
73*30088Sminshall  */
74*30088Sminshall 
75*30088Sminshall #if	!defined(TN3270)
76*30088Sminshall #define	ExitString(f,s,r)	{ fprintf(f, s); exit(r); }
77*30088Sminshall #define	Exit(x)			exit(x)
78*30088Sminshall #define	SetIn3270()
79*30088Sminshall 
80*30088Sminshall void	setcommandmode(), command();	/* forward declarations */
81*30088Sminshall #endif	/* !defined(TN3270) */
82*30088Sminshall 
83*30088Sminshall #include <sys/types.h>
84*30088Sminshall #include <sys/socket.h>
85*30088Sminshall #include <sys/ioctl.h>
86*30088Sminshall #include <sys/time.h>
87*30088Sminshall 
88*30088Sminshall #include <netinet/in.h>
89*30088Sminshall 
90*30088Sminshall #include <curses.h>
91*30088Sminshall 
92*30088Sminshall #define	TELOPTS
93*30088Sminshall #include <arpa/telnet.h>
94*30088Sminshall 
95*30088Sminshall #if	!defined(NOT43)
96*30088Sminshall #include <arpa/inet.h>
97*30088Sminshall #else	/* !defined(NOT43) */
98*30088Sminshall extern unsigned long inet_addr();
99*30088Sminshall extern char	*inet_ntoa();
100*30088Sminshall #endif	/* !defined(NOT43) */
101*30088Sminshall 
102*30088Sminshall #include <stdio.h>
103*30088Sminshall #include <ctype.h>
104*30088Sminshall #include <errno.h>
105*30088Sminshall #include <signal.h>
106*30088Sminshall #include <setjmp.h>
107*30088Sminshall #include <netdb.h>
108*30088Sminshall #include <strings.h>
109*30088Sminshall 
110*30088Sminshall #if	defined(TN3270)
111*30088Sminshall #include "ctlr/screen.h"
112*30088Sminshall #include "system/globals.h"
113*30088Sminshall #include "telnet.ext"
114*30088Sminshall #include "ctlr/options.ext"
115*30088Sminshall #include "ctlr/outbound.ext"
116*30088Sminshall #include "keyboard/termin.ext"
117*30088Sminshall #endif	/* defined(TN3270) */
118*30088Sminshall 
119*30088Sminshall 
120*30088Sminshall 
121*30088Sminshall #ifndef	FD_SETSIZE
122*30088Sminshall /*
123*30088Sminshall  * The following is defined just in case someone should want to run
124*30088Sminshall  * this telnet on a 4.2 system.
125*30088Sminshall  *
126*30088Sminshall  */
127*30088Sminshall 
128*30088Sminshall #define	FD_SET(n, p)	((p)->fds_bits[0] |= (1<<(n)))
129*30088Sminshall #define	FD_CLR(n, p)	((p)->fds_bits[0] &= ~(1<<(n)))
130*30088Sminshall #define	FD_ISSET(n, p)	((p)->fds_bits[0] & (1<<(n)))
131*30088Sminshall #define FD_ZERO(p)	((p)->fds_bits[0] = 0)
132*30088Sminshall 
133*30088Sminshall #endif
134*30088Sminshall 
135*30088Sminshall #define	strip(x)	((x)&0x7f)
136*30088Sminshall #define min(x,y)	((x<y)? x:y)
137*30088Sminshall 
138*30088Sminshall #if	defined(TN3270)
139*30088Sminshall static char	Ibuf[8*BUFSIZ], *Ifrontp = Ibuf, *Ibackp = Ibuf;
140*30088Sminshall #endif	/* defined(TN3270) */
141*30088Sminshall 
142*30088Sminshall static char	ttyobuf[2*BUFSIZ], *tfrontp = ttyobuf, *tbackp = ttyobuf;
143*30088Sminshall #define	TTYADD(c)	{ if (!(SYNCHing||flushout)) { *tfrontp++ = c; } }
144*30088Sminshall #define	TTYLOC()	(tfrontp)
145*30088Sminshall #define	TTYMAX()	(ttyobuf+sizeof ttyobuf-1)
146*30088Sminshall #define	TTYMIN()	(netobuf)
147*30088Sminshall #define	TTYBYTES()	(tfrontp-tbackp)
148*30088Sminshall #define	TTYROOM()	(TTYMAX()-TTYLOC()+1)
149*30088Sminshall 
150*30088Sminshall static char	netobuf[2*BUFSIZ], *nfrontp = netobuf, *nbackp = netobuf;
151*30088Sminshall #define	NETADD(c)	{ *nfrontp++ = c; }
152*30088Sminshall #define	NET2ADD(c1,c2)	{ NETADD(c1); NETADD(c2); }
153*30088Sminshall #define NETLOC()	(nfrontp)
154*30088Sminshall #define	NETMAX()	(netobuf+sizeof netobuf-1)
155*30088Sminshall #define	NETBYTES()	(nfrontp-nbackp)
156*30088Sminshall #define	NETROOM()	(NETMAX()-NETLOC()+1)
157*30088Sminshall static char	*neturg = 0;		/* one past last byte of urgent data */
158*30088Sminshall 
159*30088Sminshall static char	subbuffer[100] = 0,
160*30088Sminshall 		*subpointer, *subend = 0;	 /* buffer for sub-options */
161*30088Sminshall #define	SB_CLEAR()	subpointer = subbuffer;
162*30088Sminshall #define	SB_TERM()	subend = subpointer;
163*30088Sminshall #define	SB_ACCUM(c)	if (subpointer < (subbuffer+sizeof subbuffer)) { \
164*30088Sminshall 				*subpointer++ = (c); \
165*30088Sminshall 			}
166*30088Sminshall 
167*30088Sminshall static char	sb_terminal[] = { IAC, SB,
168*30088Sminshall 			TELOPT_TTYPE, TELQUAL_IS,
169*30088Sminshall 			'I', 'B', 'M', '-', '3', '2', '7', '8', '-', '2',
170*30088Sminshall 			IAC, SE };
171*30088Sminshall #define	SBTERMMODEL	13
172*30088Sminshall 
173*30088Sminshall 
174*30088Sminshall static char	hisopts[256] = 0;
175*30088Sminshall static char	myopts[256] = 0;
176*30088Sminshall 
177*30088Sminshall static char	doopt[] = { IAC, DO, '%', 'c', 0 };
178*30088Sminshall static char	dont[] = { IAC, DONT, '%', 'c', 0 };
179*30088Sminshall static char	will[] = { IAC, WILL, '%', 'c', 0 };
180*30088Sminshall static char	wont[] = { IAC, WONT, '%', 'c', 0 };
181*30088Sminshall 
182*30088Sminshall struct cmd {
183*30088Sminshall 	char	*name;		/* command name */
184*30088Sminshall 	char	*help;		/* help string */
185*30088Sminshall 	int	(*handler)();	/* routine which executes command */
186*30088Sminshall 	int	dohelp;		/* Should we give general help information? */
187*30088Sminshall 	int	needconnect;	/* Do we need to be connected to execute? */
188*30088Sminshall };
189*30088Sminshall 
190*30088Sminshall static char	sibuf[BUFSIZ], *sbp = 0;
191*30088Sminshall static char	tibuf[BUFSIZ], *tbp;
192*30088Sminshall static fd_set ibits, obits, xbits;
193*30088Sminshall 
194*30088Sminshall 
195*30088Sminshall static int
196*30088Sminshall 	connected = 0,
197*30088Sminshall 	net = 0,
198*30088Sminshall 	scc = 0,
199*30088Sminshall 	tcc = 0,
200*30088Sminshall 	showoptions = 0,
201*30088Sminshall 	In3270 = 0,		/* Are we in 3270 mode? */
202*30088Sminshall 	ISend = 0,		/* trying to send network data in */
203*30088Sminshall 	debug = 0,
204*30088Sminshall 	crmod = 0,
205*30088Sminshall 	netdata = 0,
206*30088Sminshall 	telnetport = 1;
207*30088Sminshall 
208*30088Sminshall static FILE	*NetTrace = 0;
209*30088Sminshall 
210*30088Sminshall #define	CONTROL(x)	((x)&0x1f)		/* CTRL(x) is not portable */
211*30088Sminshall 
212*30088Sminshall static char
213*30088Sminshall 	*prompt = 0,
214*30088Sminshall 	escape = CONTROL(']'),
215*30088Sminshall 	echoc = CONTROL('E');
216*30088Sminshall 
217*30088Sminshall static int
218*30088Sminshall 	SYNCHing = 0,		/* we are in TELNET SYNCH mode */
219*30088Sminshall 	flushout = 0,		/* flush output */
220*30088Sminshall 	autoflush = 0,		/* flush output when interrupting? */
221*30088Sminshall 	autosynch = 0,		/* send interrupt characters with SYNCH? */
222*30088Sminshall 	localchars = 0,		/* we recognize interrupt/quit */
223*30088Sminshall 	donelclchars = 0,	/* the user has set "localchars" */
224*30088Sminshall 	dontlecho = 0;		/* do we suppress local echoing right now? */
225*30088Sminshall 
226*30088Sminshall /*	The following are some tn3270 specific flags */
227*30088Sminshall #if	defined(TN3270)
228*30088Sminshall 
229*30088Sminshall static int
230*30088Sminshall 	Sent3270TerminalType = 0;	/* Have we said we are a 3270? */
231*30088Sminshall 
232*30088Sminshall /* Some real, live, globals. */
233*30088Sminshall int
234*30088Sminshall #if	defined(unix)
235*30088Sminshall 	HaveInput = 0,		/* There is input available to scan */
236*30088Sminshall #endif	/* defined(unix) */
237*30088Sminshall 	tout = 0,			/* Output file descriptor */
238*30088Sminshall 	tin = 0;			/* Input file descriptor */
239*30088Sminshall #if	defined(unix)
240*30088Sminshall char	*transcom = 0;	/* transparent mode command (default: none) */
241*30088Sminshall #endif	/* defined(unix) */
242*30088Sminshall 
243*30088Sminshall #else	/* defined(TN3270) */
244*30088Sminshall static int tin = 0, tout = 0;		/* file descriptors */
245*30088Sminshall #endif	/* defined(TN3270) */
246*30088Sminshall 
247*30088Sminshall static char	line[200];
248*30088Sminshall #if	defined(TN3270) && defined(unix)
249*30088Sminshall static char	tline[200];
250*30088Sminshall #endif	/* defined(TN3270) && defined(unix) */
251*30088Sminshall static int	margc = 0;
252*30088Sminshall static char	*margv[20];
253*30088Sminshall 
254*30088Sminshall static jmp_buf	toplevel;
255*30088Sminshall static jmp_buf	peerdied;
256*30088Sminshall 
257*30088Sminshall extern	int errno;
258*30088Sminshall 
259*30088Sminshall 
260*30088Sminshall static struct sockaddr_in sin;
261*30088Sminshall 
262*30088Sminshall static struct	servent *sp = 0;
263*30088Sminshall 
264*30088Sminshall static struct	tchars otc = { 0 }, ntc = { 0 };
265*30088Sminshall static struct	ltchars oltc = { 0 }, nltc = { 0 };
266*30088Sminshall static struct	sgttyb ottyb = { 0 }, nttyb = { 0 };
267*30088Sminshall static int	flushline = 1;
268*30088Sminshall 
269*30088Sminshall static char	*hostname = 0;
270*30088Sminshall static char	hnamebuf[32];
271*30088Sminshall 
272*30088Sminshall /*
273*30088Sminshall  * The following are some clocks used to decide how to interpret
274*30088Sminshall  * the relationship between various variables.
275*30088Sminshall  */
276*30088Sminshall 
277*30088Sminshall static struct {
278*30088Sminshall     int
279*30088Sminshall 	system,			/* what the current time is */
280*30088Sminshall 	echotoggle,		/* last time user entered echo character */
281*30088Sminshall 	modenegotiated,		/* last time operating mode negotiated */
282*30088Sminshall 	didnetreceive,		/* last time we read data from network */
283*30088Sminshall 	gotDM;			/* when did we last see a data mark */
284*30088Sminshall } clocks = { 0 };
285*30088Sminshall 
286*30088Sminshall #define	settimer(x)	clocks.x = clocks.system++
287*30088Sminshall 
288*30088Sminshall /*
289*30088Sminshall  * Various utility routines.
290*30088Sminshall  */
291*30088Sminshall 
292*30088Sminshall static void
293*30088Sminshall makeargv()
294*30088Sminshall {
295*30088Sminshall 	register char *cp;
296*30088Sminshall 	register char **argp = margv;
297*30088Sminshall 
298*30088Sminshall 	margc = 0;
299*30088Sminshall 	for (cp = line; *cp;) {
300*30088Sminshall 		while (isspace(*cp))
301*30088Sminshall 			cp++;
302*30088Sminshall 		if (*cp == '\0')
303*30088Sminshall 			break;
304*30088Sminshall 		*argp++ = cp;
305*30088Sminshall 		margc += 1;
306*30088Sminshall 		while (*cp != '\0' && !isspace(*cp))
307*30088Sminshall 			cp++;
308*30088Sminshall 		if (*cp == '\0')
309*30088Sminshall 			break;
310*30088Sminshall 		*cp++ = '\0';
311*30088Sminshall 	}
312*30088Sminshall 	*argp++ = 0;
313*30088Sminshall }
314*30088Sminshall 
315*30088Sminshall static char *ambiguous;		/* special return value */
316*30088Sminshall #define Ambiguous(t)	((t)&ambiguous)
317*30088Sminshall 
318*30088Sminshall 
319*30088Sminshall static char **
320*30088Sminshall genget(name, table, next)
321*30088Sminshall char	*name;		/* name to match */
322*30088Sminshall char	**table;		/* name entry in table */
323*30088Sminshall char	**(*next)();	/* routine to return next entry in table */
324*30088Sminshall {
325*30088Sminshall 	register char *p, *q;
326*30088Sminshall 	register char **c, **found;
327*30088Sminshall 	register int nmatches, longest;
328*30088Sminshall 
329*30088Sminshall 	longest = 0;
330*30088Sminshall 	nmatches = 0;
331*30088Sminshall 	found = 0;
332*30088Sminshall 	for (c = table; (p = *c) != 0; c = (*next)(c)) {
333*30088Sminshall 		for (q = name;
334*30088Sminshall 		    (*q == *p) || (isupper(*q) && tolower(*q) == *p); p++, q++)
335*30088Sminshall 			if (*q == 0)		/* exact match? */
336*30088Sminshall 				return (c);
337*30088Sminshall 		if (!*q) {			/* the name was a prefix */
338*30088Sminshall 			if (q - name > longest) {
339*30088Sminshall 				longest = q - name;
340*30088Sminshall 				nmatches = 1;
341*30088Sminshall 				found = c;
342*30088Sminshall 			} else if (q - name == longest)
343*30088Sminshall 				nmatches++;
344*30088Sminshall 		}
345*30088Sminshall 	}
346*30088Sminshall 	if (nmatches > 1)
347*30088Sminshall 		return Ambiguous(char **);
348*30088Sminshall 	return (found);
349*30088Sminshall }
350*30088Sminshall 
351*30088Sminshall /*
352*30088Sminshall  * Make a character string into a number.
353*30088Sminshall  *
354*30088Sminshall  * Todo:  1.  Could take random integers (12, 0x12, 012, 0b1).
355*30088Sminshall  */
356*30088Sminshall 
357*30088Sminshall static
358*30088Sminshall special(s)
359*30088Sminshall register char *s;
360*30088Sminshall {
361*30088Sminshall 	register char c;
362*30088Sminshall 	char b;
363*30088Sminshall 
364*30088Sminshall 	switch (*s) {
365*30088Sminshall 	case '^':
366*30088Sminshall 		b = *++s;
367*30088Sminshall 		if (b == '?') {
368*30088Sminshall 		    c = b | 0x40;		/* DEL */
369*30088Sminshall 		} else {
370*30088Sminshall 		    c = b & 0x1f;
371*30088Sminshall 		}
372*30088Sminshall 		break;
373*30088Sminshall 	default:
374*30088Sminshall 		c = *s;
375*30088Sminshall 		break;
376*30088Sminshall 	}
377*30088Sminshall 	return c;
378*30088Sminshall }
379*30088Sminshall 
380*30088Sminshall /*
381*30088Sminshall  * Construct a control character sequence
382*30088Sminshall  * for a special character.
383*30088Sminshall  */
384*30088Sminshall static char *
385*30088Sminshall control(c)
386*30088Sminshall 	register int c;
387*30088Sminshall {
388*30088Sminshall 	static char buf[3];
389*30088Sminshall 
390*30088Sminshall 	if (c == 0x7f)
391*30088Sminshall 		return ("^?");
392*30088Sminshall 	if (c == '\377') {
393*30088Sminshall 		return "off";
394*30088Sminshall 	}
395*30088Sminshall 	if (c >= 0x20) {
396*30088Sminshall 		buf[0] = c;
397*30088Sminshall 		buf[1] = 0;
398*30088Sminshall 	} else {
399*30088Sminshall 		buf[0] = '^';
400*30088Sminshall 		buf[1] = '@'+c;
401*30088Sminshall 		buf[2] = 0;
402*30088Sminshall 	}
403*30088Sminshall 	return (buf);
404*30088Sminshall }
405*30088Sminshall 
406*30088Sminshall 
407*30088Sminshall /*
408*30088Sminshall  * upcase()
409*30088Sminshall  *
410*30088Sminshall  *	Upcase (in place) the argument.
411*30088Sminshall  */
412*30088Sminshall 
413*30088Sminshall static void
414*30088Sminshall upcase(argument)
415*30088Sminshall register char *argument;
416*30088Sminshall {
417*30088Sminshall     register int c;
418*30088Sminshall 
419*30088Sminshall     while ((c = *argument) != 0) {
420*30088Sminshall 	if (islower(c)) {
421*30088Sminshall 	    *argument = toupper(c);
422*30088Sminshall 	}
423*30088Sminshall 	argument++;
424*30088Sminshall     }
425*30088Sminshall }
426*30088Sminshall 
427*30088Sminshall /*
428*30088Sminshall  * The following are routines used to print out debugging information.
429*30088Sminshall  */
430*30088Sminshall 
431*30088Sminshall 
432*30088Sminshall static void
433*30088Sminshall Dump(direction, buffer, length)
434*30088Sminshall char	direction;
435*30088Sminshall char	*buffer;
436*30088Sminshall int	length;
437*30088Sminshall {
438*30088Sminshall #   define BYTES_PER_LINE	32
439*30088Sminshall #   define min(x,y)	((x<y)? x:y)
440*30088Sminshall     char *pThis;
441*30088Sminshall     int offset;
442*30088Sminshall 
443*30088Sminshall     offset = 0;
444*30088Sminshall 
445*30088Sminshall     while (length) {
446*30088Sminshall 	/* print one line */
447*30088Sminshall 	fprintf(NetTrace, "%c 0x%x\t", direction, offset);
448*30088Sminshall 	pThis = buffer;
449*30088Sminshall 	buffer = buffer+min(length, BYTES_PER_LINE);
450*30088Sminshall 	while (pThis < buffer) {
451*30088Sminshall 	    fprintf(NetTrace, "%.2x", (*pThis)&0xff);
452*30088Sminshall 	    pThis++;
453*30088Sminshall 	}
454*30088Sminshall 	fprintf(NetTrace, "\n");
455*30088Sminshall 	length -= BYTES_PER_LINE;
456*30088Sminshall 	offset += BYTES_PER_LINE;
457*30088Sminshall 	if (length < 0) {
458*30088Sminshall 	    return;
459*30088Sminshall 	}
460*30088Sminshall 	/* find next unique line */
461*30088Sminshall     }
462*30088Sminshall }
463*30088Sminshall 
464*30088Sminshall 
465*30088Sminshall /*VARARGS*/
466*30088Sminshall static void
467*30088Sminshall printoption(direction, fmt, option, what)
468*30088Sminshall 	char *direction, *fmt;
469*30088Sminshall 	int option, what;
470*30088Sminshall {
471*30088Sminshall 	if (!showoptions)
472*30088Sminshall 		return;
473*30088Sminshall 	fprintf(NetTrace, "%s ", direction+1);
474*30088Sminshall 	if (fmt == doopt)
475*30088Sminshall 		fmt = "do";
476*30088Sminshall 	else if (fmt == dont)
477*30088Sminshall 		fmt = "dont";
478*30088Sminshall 	else if (fmt == will)
479*30088Sminshall 		fmt = "will";
480*30088Sminshall 	else if (fmt == wont)
481*30088Sminshall 		fmt = "wont";
482*30088Sminshall 	else
483*30088Sminshall 		fmt = "???";
484*30088Sminshall 	if (option < (sizeof telopts/sizeof telopts[0]))
485*30088Sminshall 		fprintf(NetTrace, "%s %s", fmt, telopts[option]);
486*30088Sminshall 	else
487*30088Sminshall 		fprintf(NetTrace, "%s %d", fmt, option);
488*30088Sminshall 	if (*direction == '<') {
489*30088Sminshall 		fprintf(NetTrace, "\r\n");
490*30088Sminshall 		return;
491*30088Sminshall 	}
492*30088Sminshall 	fprintf(NetTrace, " (%s)\r\n", what ? "reply" : "don't reply");
493*30088Sminshall }
494*30088Sminshall 
495*30088Sminshall static void
496*30088Sminshall printsub(direction, pointer, length)
497*30088Sminshall char	*direction,		/* "<" or ">" */
498*30088Sminshall 	*pointer;		/* where suboption data sits */
499*30088Sminshall int	length;			/* length of suboption data */
500*30088Sminshall {
501*30088Sminshall     if (showoptions) {
502*30088Sminshall 	fprintf(NetTrace, "%s suboption ",
503*30088Sminshall 				(direction[0] == '<')? "Received":"Sent");
504*30088Sminshall 	switch (pointer[0]) {
505*30088Sminshall 	case TELOPT_TTYPE:
506*30088Sminshall 	    fprintf(NetTrace, "Terminal type ");
507*30088Sminshall 	    switch (pointer[1]) {
508*30088Sminshall 	    case TELQUAL_IS:
509*30088Sminshall 		{
510*30088Sminshall 		    char tmpbuf[sizeof subbuffer];
511*30088Sminshall 		    int minlen = min(length, sizeof tmpbuf);
512*30088Sminshall 
513*30088Sminshall 		    bcopy(pointer+2, tmpbuf, minlen);
514*30088Sminshall 		    tmpbuf[minlen-1] = 0;
515*30088Sminshall 		    fprintf(NetTrace, "is %s.\n", tmpbuf);
516*30088Sminshall 		}
517*30088Sminshall 		break;
518*30088Sminshall 	    case TELQUAL_SEND:
519*30088Sminshall 		fprintf(NetTrace, "- request to send.\n");
520*30088Sminshall 		break;
521*30088Sminshall 	    default:
522*30088Sminshall 		fprintf(NetTrace,
523*30088Sminshall 				"- unknown qualifier %d (0x%x).\n", pointer[1]);
524*30088Sminshall 	    }
525*30088Sminshall 	    break;
526*30088Sminshall 	default:
527*30088Sminshall 	    fprintf(NetTrace, "Unknown option %d (0x%x)\n",
528*30088Sminshall 					pointer[0], pointer[0]);
529*30088Sminshall 	}
530*30088Sminshall     }
531*30088Sminshall }
532*30088Sminshall 
533*30088Sminshall /*
534*30088Sminshall  * Check to see if any out-of-band data exists on a socket (for
535*30088Sminshall  * Telnet "synch" processing).
536*30088Sminshall  */
537*30088Sminshall 
538*30088Sminshall static int
539*30088Sminshall stilloob(s)
540*30088Sminshall int	s;		/* socket number */
541*30088Sminshall {
542*30088Sminshall     static struct timeval timeout = { 0 };
543*30088Sminshall     fd_set	excepts;
544*30088Sminshall     int value;
545*30088Sminshall 
546*30088Sminshall     do {
547*30088Sminshall 	FD_ZERO(&excepts);
548*30088Sminshall 	FD_SET(s, &excepts);
549*30088Sminshall 	value = select(s+1, (fd_set *)0, (fd_set *)0, &excepts, &timeout);
550*30088Sminshall     } while ((value == -1) && (errno == EINTR));
551*30088Sminshall 
552*30088Sminshall     if (value < 0) {
553*30088Sminshall 	perror("select");
554*30088Sminshall 	quit();
555*30088Sminshall     }
556*30088Sminshall     if (FD_ISSET(s, &excepts)) {
557*30088Sminshall 	return 1;
558*30088Sminshall     } else {
559*30088Sminshall 	return 0;
560*30088Sminshall     }
561*30088Sminshall }
562*30088Sminshall 
563*30088Sminshall 
564*30088Sminshall /*
565*30088Sminshall  *  netflush
566*30088Sminshall  *		Send as much data as possible to the network,
567*30088Sminshall  *	handling requests for urgent data.
568*30088Sminshall  *
569*30088Sminshall  *		The return value indicates whether we did any
570*30088Sminshall  *	useful work.
571*30088Sminshall  */
572*30088Sminshall 
573*30088Sminshall 
574*30088Sminshall int
575*30088Sminshall netflush()
576*30088Sminshall {
577*30088Sminshall     int n;
578*30088Sminshall 
579*30088Sminshall     if ((n = nfrontp - nbackp) > 0) {
580*30088Sminshall 	if (!neturg) {
581*30088Sminshall 	    n = write(net, nbackp, n);	/* normal write */
582*30088Sminshall 	} else {
583*30088Sminshall 	    n = neturg - nbackp;
584*30088Sminshall 	    /*
585*30088Sminshall 	     * In 4.2 (and 4.3) systems, there is some question about
586*30088Sminshall 	     * what byte in a sendOOB operation is the "OOB" data.
587*30088Sminshall 	     * To make ourselves compatible, we only send ONE byte
588*30088Sminshall 	     * out of band, the one WE THINK should be OOB (though
589*30088Sminshall 	     * we really have more the TCP philosophy of urgent data
590*30088Sminshall 	     * rather than the Unix philosophy of OOB data).
591*30088Sminshall 	     */
592*30088Sminshall 	    if (n > 1) {
593*30088Sminshall 		n = send(net, nbackp, n-1, 0);	/* send URGENT all by itself */
594*30088Sminshall 	    } else {
595*30088Sminshall 		n = send(net, nbackp, n, MSG_OOB);	/* URGENT data */
596*30088Sminshall 	    }
597*30088Sminshall 	}
598*30088Sminshall     }
599*30088Sminshall     if (n < 0) {
600*30088Sminshall 	if (errno != ENOBUFS && errno != EWOULDBLOCK) {
601*30088Sminshall 	    setcommandmode();
602*30088Sminshall 	    perror(hostname);
603*30088Sminshall 	    close(net);
604*30088Sminshall 	    neturg = 0;
605*30088Sminshall 	    longjmp(peerdied, -1);
606*30088Sminshall 	    /*NOTREACHED*/
607*30088Sminshall 	}
608*30088Sminshall 	n = 0;
609*30088Sminshall     }
610*30088Sminshall     if (netdata && n) {
611*30088Sminshall 	Dump('>', nbackp, n);
612*30088Sminshall     }
613*30088Sminshall     nbackp += n;
614*30088Sminshall     if (nbackp >= neturg) {
615*30088Sminshall 	neturg = 0;
616*30088Sminshall     }
617*30088Sminshall     if (nbackp == nfrontp) {
618*30088Sminshall 	nbackp = nfrontp = netobuf;
619*30088Sminshall     }
620*30088Sminshall     return n > 0;
621*30088Sminshall }
622*30088Sminshall 
623*30088Sminshall /*
624*30088Sminshall  * nextitem()
625*30088Sminshall  *
626*30088Sminshall  *	Return the address of the next "item" in the TELNET data
627*30088Sminshall  * stream.  This will be the address of the next character if
628*30088Sminshall  * the current address is a user data character, or it will
629*30088Sminshall  * be the address of the character following the TELNET command
630*30088Sminshall  * if the current address is a TELNET IAC ("I Am a Command")
631*30088Sminshall  * character.
632*30088Sminshall  */
633*30088Sminshall 
634*30088Sminshall static char *
635*30088Sminshall nextitem(current)
636*30088Sminshall char	*current;
637*30088Sminshall {
638*30088Sminshall     if ((*current&0xff) != IAC) {
639*30088Sminshall 	return current+1;
640*30088Sminshall     }
641*30088Sminshall     switch (*(current+1)&0xff) {
642*30088Sminshall     case DO:
643*30088Sminshall     case DONT:
644*30088Sminshall     case WILL:
645*30088Sminshall     case WONT:
646*30088Sminshall 	return current+3;
647*30088Sminshall     case SB:		/* loop forever looking for the SE */
648*30088Sminshall 	{
649*30088Sminshall 	    register char *look = current+2;
650*30088Sminshall 
651*30088Sminshall 	    for (;;) {
652*30088Sminshall 		if ((*look++&0xff) == IAC) {
653*30088Sminshall 		    if ((*look++&0xff) == SE) {
654*30088Sminshall 			return look;
655*30088Sminshall 		    }
656*30088Sminshall 		}
657*30088Sminshall 	    }
658*30088Sminshall 	}
659*30088Sminshall     default:
660*30088Sminshall 	return current+2;
661*30088Sminshall     }
662*30088Sminshall }
663*30088Sminshall /*
664*30088Sminshall  * netclear()
665*30088Sminshall  *
666*30088Sminshall  *	We are about to do a TELNET SYNCH operation.  Clear
667*30088Sminshall  * the path to the network.
668*30088Sminshall  *
669*30088Sminshall  *	Things are a bit tricky since we may have sent the first
670*30088Sminshall  * byte or so of a previous TELNET command into the network.
671*30088Sminshall  * So, we have to scan the network buffer from the beginning
672*30088Sminshall  * until we are up to where we want to be.
673*30088Sminshall  *
674*30088Sminshall  *	A side effect of what we do, just to keep things
675*30088Sminshall  * simple, is to clear the urgent data pointer.  The principal
676*30088Sminshall  * caller should be setting the urgent data pointer AFTER calling
677*30088Sminshall  * us in any case.
678*30088Sminshall  */
679*30088Sminshall 
680*30088Sminshall static void
681*30088Sminshall netclear()
682*30088Sminshall {
683*30088Sminshall     register char *thisitem, *next;
684*30088Sminshall     char *good;
685*30088Sminshall #define	wewant(p)	((nfrontp > p) && ((*p&0xff) == IAC) && \
686*30088Sminshall 				((*(p+1)&0xff) != EC) && ((*(p+1)&0xff) != EL))
687*30088Sminshall 
688*30088Sminshall     thisitem = netobuf;
689*30088Sminshall 
690*30088Sminshall     while ((next = nextitem(thisitem)) <= nbackp) {
691*30088Sminshall 	thisitem = next;
692*30088Sminshall     }
693*30088Sminshall 
694*30088Sminshall     /* Now, thisitem is first before/at boundary. */
695*30088Sminshall 
696*30088Sminshall     good = netobuf;	/* where the good bytes go */
697*30088Sminshall 
698*30088Sminshall     while (nfrontp > thisitem) {
699*30088Sminshall 	if (wewant(thisitem)) {
700*30088Sminshall 	    int length;
701*30088Sminshall 
702*30088Sminshall 	    next = thisitem;
703*30088Sminshall 	    do {
704*30088Sminshall 		next = nextitem(next);
705*30088Sminshall 	    } while (wewant(next) && (nfrontp > next));
706*30088Sminshall 	    length = next-thisitem;
707*30088Sminshall 	    bcopy(thisitem, good, length);
708*30088Sminshall 	    good += length;
709*30088Sminshall 	    thisitem = next;
710*30088Sminshall 	} else {
711*30088Sminshall 	    thisitem = nextitem(thisitem);
712*30088Sminshall 	}
713*30088Sminshall     }
714*30088Sminshall 
715*30088Sminshall     nbackp = netobuf;
716*30088Sminshall     nfrontp = good;		/* next byte to be sent */
717*30088Sminshall     neturg = 0;
718*30088Sminshall }
719*30088Sminshall 
720*30088Sminshall /*
721*30088Sminshall  * These routines add various telnet commands to the data stream.
722*30088Sminshall  */
723*30088Sminshall 
724*30088Sminshall #if	defined(NOT43)
725*30088Sminshall static int
726*30088Sminshall #else	/* defined(NOT43) */
727*30088Sminshall static void
728*30088Sminshall #endif	/* defined(NOT43) */
729*30088Sminshall dosynch()
730*30088Sminshall {
731*30088Sminshall     netclear();			/* clear the path to the network */
732*30088Sminshall     NET2ADD(IAC, DM);
733*30088Sminshall     neturg = NETLOC()-1;	/* Some systems are off by one XXX */
734*30088Sminshall 
735*30088Sminshall #if	defined(NOT43)
736*30088Sminshall     return 0;
737*30088Sminshall #endif	/* defined(NOT43) */
738*30088Sminshall }
739*30088Sminshall 
740*30088Sminshall static void
741*30088Sminshall doflush()
742*30088Sminshall {
743*30088Sminshall     NET2ADD(IAC, DO);
744*30088Sminshall     NETADD(TELOPT_TM);
745*30088Sminshall     flushline = 1;
746*30088Sminshall     flushout = 1;
747*30088Sminshall     ttyflush();
748*30088Sminshall     /* do printoption AFTER flush, otherwise the output gets tossed... */
749*30088Sminshall     printoption("<SENT", doopt, TELOPT_TM, 0);
750*30088Sminshall }
751*30088Sminshall 
752*30088Sminshall static void
753*30088Sminshall intp()
754*30088Sminshall {
755*30088Sminshall     NET2ADD(IAC, IP);
756*30088Sminshall     if (autoflush) {
757*30088Sminshall 	doflush();
758*30088Sminshall     }
759*30088Sminshall     if (autosynch) {
760*30088Sminshall 	dosynch();
761*30088Sminshall     }
762*30088Sminshall }
763*30088Sminshall 
764*30088Sminshall static void
765*30088Sminshall sendbrk()
766*30088Sminshall {
767*30088Sminshall     NET2ADD(IAC, BREAK);
768*30088Sminshall     if (autoflush) {
769*30088Sminshall 	doflush();
770*30088Sminshall     }
771*30088Sminshall     if (autosynch) {
772*30088Sminshall 	dosynch();
773*30088Sminshall     }
774*30088Sminshall }
775*30088Sminshall 
776*30088Sminshall /*
777*30088Sminshall  *		Send as much data as possible to the terminal.
778*30088Sminshall  *
779*30088Sminshall  *		The return value indicates whether we did any
780*30088Sminshall  *	useful work.
781*30088Sminshall  */
782*30088Sminshall 
783*30088Sminshall 
784*30088Sminshall static int
785*30088Sminshall ttyflush()
786*30088Sminshall {
787*30088Sminshall     int n;
788*30088Sminshall 
789*30088Sminshall     if ((n = tfrontp - tbackp) > 0) {
790*30088Sminshall 	if (!(SYNCHing||flushout)) {
791*30088Sminshall 	    n = write(tout, tbackp, n);
792*30088Sminshall 	} else {
793*30088Sminshall 	    ioctl(fileno(stdout), TIOCFLUSH, (char *) 0);
794*30088Sminshall 	    /* we leave 'n' alone! */
795*30088Sminshall 	}
796*30088Sminshall     }
797*30088Sminshall     if (n >= 0) {
798*30088Sminshall 	tbackp += n;
799*30088Sminshall 	if (tbackp == tfrontp) {
800*30088Sminshall 	    tbackp = tfrontp = ttyobuf;
801*30088Sminshall 	}
802*30088Sminshall     }
803*30088Sminshall     return n > 0;
804*30088Sminshall }
805*30088Sminshall 
806*30088Sminshall #if	defined(TN3270)
807*30088Sminshall 
808*30088Sminshall #if	defined(unix)
809*30088Sminshall static void
810*30088Sminshall inputAvailable()
811*30088Sminshall {
812*30088Sminshall     HaveInput = 1;
813*30088Sminshall }
814*30088Sminshall #endif	/* defined(unix) */
815*30088Sminshall 
816*30088Sminshall void
817*30088Sminshall outputPurge()
818*30088Sminshall {
819*30088Sminshall     int tmp = flushout;
820*30088Sminshall 
821*30088Sminshall     flushout = 1;
822*30088Sminshall 
823*30088Sminshall     ttyflush();
824*30088Sminshall 
825*30088Sminshall     flushout = tmp;
826*30088Sminshall }
827*30088Sminshall 
828*30088Sminshall #endif	/* defined(TN3270) */
829*30088Sminshall 
830*30088Sminshall #if	defined(unix)
831*30088Sminshall /*
832*30088Sminshall  * Various signal handling routines.
833*30088Sminshall  */
834*30088Sminshall 
835*30088Sminshall static void
836*30088Sminshall deadpeer()
837*30088Sminshall {
838*30088Sminshall 	setcommandmode();
839*30088Sminshall 	longjmp(peerdied, -1);
840*30088Sminshall }
841*30088Sminshall 
842*30088Sminshall static void
843*30088Sminshall intr()
844*30088Sminshall {
845*30088Sminshall     if (localchars) {
846*30088Sminshall 	intp();
847*30088Sminshall 	return;
848*30088Sminshall     }
849*30088Sminshall     setcommandmode();
850*30088Sminshall     longjmp(toplevel, -1);
851*30088Sminshall }
852*30088Sminshall 
853*30088Sminshall static void
854*30088Sminshall intr2()
855*30088Sminshall {
856*30088Sminshall     if (localchars) {
857*30088Sminshall 	sendbrk();
858*30088Sminshall 	return;
859*30088Sminshall     }
860*30088Sminshall }
861*30088Sminshall 
862*30088Sminshall static void
863*30088Sminshall doescape()
864*30088Sminshall {
865*30088Sminshall     command(0);
866*30088Sminshall }
867*30088Sminshall #endif	/* defined(unix) */
868*30088Sminshall 
869*30088Sminshall static int	globalmode = 0;
870*30088Sminshall /*	Various modes */
871*30088Sminshall #define	MODE_LINE(m)	(modelist[m].modetype & LINE)
872*30088Sminshall #define	MODE_LOCAL_CHARS(m)	(modelist[m].modetype &  LOCAL_CHARS)
873*30088Sminshall 
874*30088Sminshall #define	LOCAL_CHARS	0x01		/* Characters processed locally */
875*30088Sminshall #define	LINE		0x02		/* Line-by-line mode of operation */
876*30088Sminshall 
877*30088Sminshall static struct {
878*30088Sminshall     char *modedescriptions;
879*30088Sminshall     char modetype;
880*30088Sminshall } modelist[] = {
881*30088Sminshall 	{ "telnet command mode", 0 },
882*30088Sminshall 	{ "character-at-a-time mode", 0 },
883*30088Sminshall 	{ "character-at-a-time mode (local echo)", LOCAL_CHARS },
884*30088Sminshall 	{ "line-by-line mode (remote echo)", LINE | LOCAL_CHARS },
885*30088Sminshall 	{ "line-by-line mode", LINE | LOCAL_CHARS },
886*30088Sminshall 	{ "line-by-line mode (local echoing suppressed)", LINE | LOCAL_CHARS },
887*30088Sminshall 	{ "3270 mode", 0 },
888*30088Sminshall };
889*30088Sminshall /*
890*30088Sminshall  * Mode - set up terminal to a specific mode.
891*30088Sminshall  */
892*30088Sminshall 
893*30088Sminshall 
894*30088Sminshall static void
895*30088Sminshall mode(f)
896*30088Sminshall 	register int f;
897*30088Sminshall {
898*30088Sminshall     static int prevmode = 0;
899*30088Sminshall     struct tchars *tc;
900*30088Sminshall     struct tchars tc3;
901*30088Sminshall     struct ltchars *ltc;
902*30088Sminshall     struct sgttyb sb;
903*30088Sminshall     int onoff;
904*30088Sminshall #if	defined(unix)
905*30088Sminshall     int old;
906*30088Sminshall #endif	/* defined(unix) */
907*30088Sminshall     struct	tchars notc2;
908*30088Sminshall     struct	ltchars noltc2;
909*30088Sminshall     static struct	tchars notc =	{ -1, -1, -1, -1, -1, -1 };
910*30088Sminshall     static struct	ltchars noltc =	{ -1, -1, -1, -1, -1, -1 };
911*30088Sminshall 
912*30088Sminshall     globalmode = f;
913*30088Sminshall     if (prevmode == f)
914*30088Sminshall 	return;
915*30088Sminshall #if	defined(unix)
916*30088Sminshall     old = prevmode;
917*30088Sminshall #endif	/* defined(unix) */
918*30088Sminshall     prevmode = f;
919*30088Sminshall     sb = nttyb;
920*30088Sminshall 
921*30088Sminshall     switch (f) {
922*30088Sminshall 
923*30088Sminshall     case 0:
924*30088Sminshall 	onoff = 0;
925*30088Sminshall 	tc = &otc;
926*30088Sminshall 	ltc = &oltc;
927*30088Sminshall 	break;
928*30088Sminshall 
929*30088Sminshall     case 1:		/* remote character processing, remote echo */
930*30088Sminshall     case 2:		/* remote character processing, local echo */
931*30088Sminshall     case 6:		/* 3270 mode - like 1, but with xon/xoff local */
932*30088Sminshall 		    /* (might be nice to have "6" in telnet also...) */
933*30088Sminshall 	    sb.sg_flags |= CBREAK;
934*30088Sminshall 	    if ((f == 1) || (f == 6)) {
935*30088Sminshall 		sb.sg_flags &= ~(ECHO|CRMOD);
936*30088Sminshall 	    } else {
937*30088Sminshall 		sb.sg_flags |= ECHO|CRMOD;
938*30088Sminshall 	    }
939*30088Sminshall 	    sb.sg_erase = sb.sg_kill = -1;
940*30088Sminshall 	    if (f == 6) {
941*30088Sminshall 		tc = &tc3;
942*30088Sminshall 		tc3 = notc;
943*30088Sminshall 		    /* get XON, XOFF characters */
944*30088Sminshall 		tc3.t_startc = otc.t_startc;
945*30088Sminshall 		tc3.t_stopc = otc.t_stopc;
946*30088Sminshall 	    } else {
947*30088Sminshall 		/*
948*30088Sminshall 		 * If user hasn't specified one way or the other,
949*30088Sminshall 		 * then default to not trapping signals.
950*30088Sminshall 		 */
951*30088Sminshall 		if (!donelclchars) {
952*30088Sminshall 		    localchars = 0;
953*30088Sminshall 		}
954*30088Sminshall 		if (localchars) {
955*30088Sminshall 		    notc2 = notc;
956*30088Sminshall 		    notc2.t_intrc = ntc.t_intrc;
957*30088Sminshall 		    notc2.t_quitc = ntc.t_quitc;
958*30088Sminshall 		    tc = &notc2;
959*30088Sminshall 		} else {
960*30088Sminshall 		    tc = &notc;
961*30088Sminshall 		}
962*30088Sminshall 	    }
963*30088Sminshall 	    ltc = &noltc;
964*30088Sminshall 	    onoff = 1;
965*30088Sminshall 	    break;
966*30088Sminshall     case 3:		/* local character processing, remote echo */
967*30088Sminshall     case 4:		/* local character processing, local echo */
968*30088Sminshall     case 5:		/* local character processing, no echo */
969*30088Sminshall 	    sb.sg_flags &= ~CBREAK;
970*30088Sminshall 	    sb.sg_flags |= CRMOD;
971*30088Sminshall 	    if (f == 4)
972*30088Sminshall 		sb.sg_flags |= ECHO;
973*30088Sminshall 	    else
974*30088Sminshall 		sb.sg_flags &= ~ECHO;
975*30088Sminshall 	    notc2 = ntc;
976*30088Sminshall 	    tc = &notc2;
977*30088Sminshall 	    noltc2 = oltc;
978*30088Sminshall 	    ltc = &noltc2;
979*30088Sminshall 	    /*
980*30088Sminshall 	     * If user hasn't specified one way or the other,
981*30088Sminshall 	     * then default to trapping signals.
982*30088Sminshall 	     */
983*30088Sminshall 	    if (!donelclchars) {
984*30088Sminshall 		localchars = 1;
985*30088Sminshall 	    }
986*30088Sminshall 	    if (localchars) {
987*30088Sminshall 		notc2.t_brkc = nltc.t_flushc;
988*30088Sminshall 		noltc2.t_flushc = -1;
989*30088Sminshall 	    } else {
990*30088Sminshall 		notc2.t_intrc = notc2.t_quitc = -1;
991*30088Sminshall 	    }
992*30088Sminshall 	    noltc2.t_suspc = escape;
993*30088Sminshall 	    noltc2.t_dsuspc = -1;
994*30088Sminshall 	    onoff = 1;
995*30088Sminshall 	    break;
996*30088Sminshall 
997*30088Sminshall     default:
998*30088Sminshall 	    return;
999*30088Sminshall     }
1000*30088Sminshall     ioctl(tin, TIOCSLTC, (char *)ltc);
1001*30088Sminshall     ioctl(tin, TIOCSETC, (char *)tc);
1002*30088Sminshall     ioctl(tin, TIOCSETP, (char *)&sb);
1003*30088Sminshall #if	(!defined(TN3270)) || ((!defined(NOT43)) || defined(PUTCHAR))
1004*30088Sminshall     ioctl(tin, FIONBIO, (char *)&onoff);
1005*30088Sminshall     ioctl(tout, FIONBIO, (char *)&onoff);
1006*30088Sminshall #endif	/* (!defined(TN3270)) || ((!defined(NOT43)) || defined(PUTCHAR)) */
1007*30088Sminshall #if	defined(TN3270) && !defined(DEBUG)
1008*30088Sminshall     ioctl(tin, FIOASYNC, (char *)&onoff);
1009*30088Sminshall #endif	/* defined(TN3270) && !defined(DEBUG) */
1010*30088Sminshall 
1011*30088Sminshall #if	defined(unix)
1012*30088Sminshall     if (MODE_LINE(f)) {
1013*30088Sminshall 	signal(SIGTSTP, doescape);
1014*30088Sminshall     } else if (MODE_LINE(old)) {
1015*30088Sminshall 	signal(SIGTSTP, SIG_DFL);
1016*30088Sminshall 	sigsetmask(sigblock(0) & ~(1<<(SIGTSTP-1)));
1017*30088Sminshall     }
1018*30088Sminshall #endif	/* defined(unix) */
1019*30088Sminshall }
1020*30088Sminshall 
1021*30088Sminshall /*
1022*30088Sminshall  * These routines decides on what the mode should be (based on the values
1023*30088Sminshall  * of various global variables).
1024*30088Sminshall  */
1025*30088Sminshall 
1026*30088Sminshall 
1027*30088Sminshall static
1028*30088Sminshall getconnmode()
1029*30088Sminshall {
1030*30088Sminshall     static char newmode[16] =
1031*30088Sminshall 			{ 4, 5, 3, 3, 2, 2, 1, 1, 6, 6, 6, 6, 6, 6, 6, 6 };
1032*30088Sminshall     int modeindex = 0;
1033*30088Sminshall 
1034*30088Sminshall     if (dontlecho && (clocks.echotoggle > clocks.modenegotiated)) {
1035*30088Sminshall 	modeindex += 1;
1036*30088Sminshall     }
1037*30088Sminshall     if (hisopts[TELOPT_ECHO]) {
1038*30088Sminshall 	modeindex += 2;
1039*30088Sminshall     }
1040*30088Sminshall     if (hisopts[TELOPT_SGA]) {
1041*30088Sminshall 	modeindex += 4;
1042*30088Sminshall     }
1043*30088Sminshall     if (In3270) {
1044*30088Sminshall 	modeindex += 8;
1045*30088Sminshall     }
1046*30088Sminshall     return newmode[modeindex];
1047*30088Sminshall }
1048*30088Sminshall 
1049*30088Sminshall void
1050*30088Sminshall setconnmode()
1051*30088Sminshall {
1052*30088Sminshall     mode(getconnmode());
1053*30088Sminshall }
1054*30088Sminshall 
1055*30088Sminshall 
1056*30088Sminshall void
1057*30088Sminshall setcommandmode()
1058*30088Sminshall {
1059*30088Sminshall     mode(0);
1060*30088Sminshall }
1061*30088Sminshall 
1062*30088Sminshall static void
1063*30088Sminshall willoption(option, reply)
1064*30088Sminshall 	int option, reply;
1065*30088Sminshall {
1066*30088Sminshall 	char *fmt;
1067*30088Sminshall 
1068*30088Sminshall 	switch (option) {
1069*30088Sminshall 
1070*30088Sminshall #	if defined(TN3270)
1071*30088Sminshall 	case TELOPT_EOR:
1072*30088Sminshall 	case TELOPT_BINARY:
1073*30088Sminshall #endif	/* defined(TN3270) */
1074*30088Sminshall 	case TELOPT_ECHO:
1075*30088Sminshall 	case TELOPT_SGA:
1076*30088Sminshall 		settimer(modenegotiated);
1077*30088Sminshall 		hisopts[option] = 1;
1078*30088Sminshall 		fmt = doopt;
1079*30088Sminshall 		setconnmode();		/* possibly set new tty mode */
1080*30088Sminshall 		break;
1081*30088Sminshall 
1082*30088Sminshall 	case TELOPT_TM:
1083*30088Sminshall 		return;			/* Never reply to TM will's/wont's */
1084*30088Sminshall 
1085*30088Sminshall 	default:
1086*30088Sminshall 		fmt = dont;
1087*30088Sminshall 		break;
1088*30088Sminshall 	}
1089*30088Sminshall 	sprintf(nfrontp, fmt, option);
1090*30088Sminshall 	nfrontp += sizeof (dont) - 2;
1091*30088Sminshall 	if (reply)
1092*30088Sminshall 		printoption(">SENT", fmt, option, reply);
1093*30088Sminshall 	else
1094*30088Sminshall 		printoption("<SENT", fmt, option, reply);
1095*30088Sminshall }
1096*30088Sminshall 
1097*30088Sminshall static void
1098*30088Sminshall wontoption(option, reply)
1099*30088Sminshall 	int option, reply;
1100*30088Sminshall {
1101*30088Sminshall 	char *fmt;
1102*30088Sminshall 
1103*30088Sminshall 	switch (option) {
1104*30088Sminshall 
1105*30088Sminshall 	case TELOPT_ECHO:
1106*30088Sminshall 	case TELOPT_SGA:
1107*30088Sminshall 		settimer(modenegotiated);
1108*30088Sminshall 		hisopts[option] = 0;
1109*30088Sminshall 		fmt = dont;
1110*30088Sminshall 		setconnmode();			/* Set new tty mode */
1111*30088Sminshall 		break;
1112*30088Sminshall 
1113*30088Sminshall 	case TELOPT_TM:
1114*30088Sminshall 		return;		/* Never reply to TM will's/wont's */
1115*30088Sminshall 
1116*30088Sminshall 	default:
1117*30088Sminshall 		fmt = dont;
1118*30088Sminshall 	}
1119*30088Sminshall 	sprintf(nfrontp, fmt, option);
1120*30088Sminshall 	nfrontp += sizeof (doopt) - 2;
1121*30088Sminshall 	if (reply)
1122*30088Sminshall 		printoption(">SENT", fmt, option, reply);
1123*30088Sminshall 	else
1124*30088Sminshall 		printoption("<SENT", fmt, option, reply);
1125*30088Sminshall }
1126*30088Sminshall 
1127*30088Sminshall static void
1128*30088Sminshall dooption(option)
1129*30088Sminshall 	int option;
1130*30088Sminshall {
1131*30088Sminshall 	char *fmt;
1132*30088Sminshall 
1133*30088Sminshall 	switch (option) {
1134*30088Sminshall 
1135*30088Sminshall 	case TELOPT_TM:
1136*30088Sminshall 		fmt = will;
1137*30088Sminshall 		break;
1138*30088Sminshall 
1139*30088Sminshall #	if defined(TN3270)
1140*30088Sminshall 	case TELOPT_EOR:
1141*30088Sminshall 	case TELOPT_BINARY:
1142*30088Sminshall #	endif	/* defined(TN3270) */
1143*30088Sminshall 	case TELOPT_TTYPE:		/* terminal type option */
1144*30088Sminshall 	case TELOPT_SGA:		/* no big deal */
1145*30088Sminshall 		fmt = will;
1146*30088Sminshall 		myopts[option] = 1;
1147*30088Sminshall 		break;
1148*30088Sminshall 
1149*30088Sminshall 	case TELOPT_ECHO:		/* We're never going to echo... */
1150*30088Sminshall 	default:
1151*30088Sminshall 		fmt = wont;
1152*30088Sminshall 		break;
1153*30088Sminshall 	}
1154*30088Sminshall 	sprintf(nfrontp, fmt, option);
1155*30088Sminshall 	nfrontp += sizeof (doopt) - 2;
1156*30088Sminshall 	printoption(">SENT", fmt, option, 0);
1157*30088Sminshall }
1158*30088Sminshall 
1159*30088Sminshall /*
1160*30088Sminshall  * suboption()
1161*30088Sminshall  *
1162*30088Sminshall  *	Look at the sub-option buffer, and try to be helpful to the other
1163*30088Sminshall  * side.
1164*30088Sminshall  *
1165*30088Sminshall  *	Currently we recognize:
1166*30088Sminshall  *
1167*30088Sminshall  *		Terminal type, send request.
1168*30088Sminshall  */
1169*30088Sminshall 
1170*30088Sminshall static void
1171*30088Sminshall suboption()
1172*30088Sminshall {
1173*30088Sminshall     printsub("<", subbuffer, subend-subbuffer+1);
1174*30088Sminshall     switch (subbuffer[0]&0xff) {
1175*30088Sminshall     case TELOPT_TTYPE:
1176*30088Sminshall 	if ((subbuffer[1]&0xff) != TELQUAL_SEND) {
1177*30088Sminshall 	    ;
1178*30088Sminshall 	} else {
1179*30088Sminshall 	    char *name;
1180*30088Sminshall 	    char namebuf[41];
1181*30088Sminshall 	    extern char *getenv();
1182*30088Sminshall 	    int len;
1183*30088Sminshall 
1184*30088Sminshall #if	defined(TN3270)
1185*30088Sminshall 	    /*
1186*30088Sminshall 	     * Try to send a 3270 type terminal name.  Decide which one base
1187*30088Sminshall 	     * on the format of our screen, and (in the future) color
1188*30088Sminshall 	     * capaiblities.
1189*30088Sminshall 	     */
1190*30088Sminshall 	    if ((initscr() != ERR) &&	/* Initialize curses to get line size */
1191*30088Sminshall 		(LINES >= 24) && (COLS >= 80)) {
1192*30088Sminshall 		Sent3270TerminalType = 1;
1193*30088Sminshall 		if ((LINES >= 27) && (COLS >= 132)) {
1194*30088Sminshall 		    MaxNumberLines = 27;
1195*30088Sminshall 		    MaxNumberColumns = 132;
1196*30088Sminshall 		    sb_terminal[SBTERMMODEL] = '5';
1197*30088Sminshall 		} else if (LINES >= 43) {
1198*30088Sminshall 		    MaxNumberLines = 43;
1199*30088Sminshall 		    MaxNumberColumns = 80;
1200*30088Sminshall 		    sb_terminal[SBTERMMODEL] = '4';
1201*30088Sminshall 		} else if (LINES >= 32) {
1202*30088Sminshall 		    MaxNumberLines = 32;
1203*30088Sminshall 		    MaxNumberColumns = 80;
1204*30088Sminshall 		    sb_terminal[SBTERMMODEL] = '3';
1205*30088Sminshall 		} else {
1206*30088Sminshall 		    MaxNumberLines = 24;
1207*30088Sminshall 		    MaxNumberColumns = 80;
1208*30088Sminshall 		    sb_terminal[SBTERMMODEL] = '2';
1209*30088Sminshall 		}
1210*30088Sminshall 		NumberLines = 24;		/* before we start out... */
1211*30088Sminshall 		NumberColumns = 80;
1212*30088Sminshall 		ScreenSize = NumberLines*NumberColumns;
1213*30088Sminshall 		if ((MaxNumberLines*MaxNumberColumns) > MAXSCREENSIZE) {
1214*30088Sminshall 		    ExitString(stderr,
1215*30088Sminshall 			"Programming error:  MAXSCREENSIZE too small.\n", 1);
1216*30088Sminshall 		    /*NOTREACHED*/
1217*30088Sminshall 		}
1218*30088Sminshall 		bcopy(sb_terminal, nfrontp, sizeof sb_terminal);
1219*30088Sminshall 		printsub(">", nfrontp+2, sizeof sb_terminal-2);
1220*30088Sminshall 		nfrontp += sizeof sb_terminal;
1221*30088Sminshall 		return;
1222*30088Sminshall 	    }
1223*30088Sminshall #endif	/* defined(TN3270) */
1224*30088Sminshall 
1225*30088Sminshall 	    name = getenv("TERM");
1226*30088Sminshall 	    if ((name == 0) || ((len = strlen(name)) > 40)) {
1227*30088Sminshall 		name = "UNKNOWN";
1228*30088Sminshall 	    }
1229*30088Sminshall 	    if ((len + 4+2) < NETROOM()) {
1230*30088Sminshall 		strcpy(namebuf, name);
1231*30088Sminshall 		upcase(namebuf);
1232*30088Sminshall 		sprintf(nfrontp, "%c%c%c%c%s%c%c", IAC, SB, TELOPT_TTYPE,
1233*30088Sminshall 				    TELQUAL_IS, namebuf, IAC, SE);
1234*30088Sminshall 		printsub(">", nfrontp+2, 4+strlen(namebuf)+2-2-2);
1235*30088Sminshall 		nfrontp += 4+strlen(namebuf)+2;
1236*30088Sminshall 	    } else {
1237*30088Sminshall 		ExitString(stderr, "No room in buffer for terminal type.\n",
1238*30088Sminshall 							1);
1239*30088Sminshall 		/*NOTREACHED*/
1240*30088Sminshall 	    }
1241*30088Sminshall 	}
1242*30088Sminshall 
1243*30088Sminshall     default:
1244*30088Sminshall 	break;
1245*30088Sminshall     }
1246*30088Sminshall }
1247*30088Sminshall 
1248*30088Sminshall #if	defined(TN3270)
1249*30088Sminshall static void
1250*30088Sminshall SetIn3270()
1251*30088Sminshall {
1252*30088Sminshall     if (Sent3270TerminalType && myopts[TELOPT_BINARY]
1253*30088Sminshall 					&& hisopts[TELOPT_BINARY]) {
1254*30088Sminshall 	if (!In3270) {
1255*30088Sminshall 	    In3270 = 1;
1256*30088Sminshall 	    OptInit();		/* initialize mappings */
1257*30088Sminshall 	    /* initialize terminal key mapping */
1258*30088Sminshall 	    (void) DataFromTerminal(ttyobuf, 0);
1259*30088Sminshall 	    StartScreen();	/* Start terminal going */
1260*30088Sminshall 	    setconnmode();
1261*30088Sminshall 	}
1262*30088Sminshall     } else {
1263*30088Sminshall 	if (In3270) {
1264*30088Sminshall 	    StopScreen(1);
1265*30088Sminshall 	    In3270 = 0;
1266*30088Sminshall 	    setconnmode();
1267*30088Sminshall 	}
1268*30088Sminshall     }
1269*30088Sminshall }
1270*30088Sminshall #endif	/* defined(TN3270) */
1271*30088Sminshall 
1272*30088Sminshall /*
1273*30088Sminshall  * Telnet receiver states for fsm
1274*30088Sminshall  */
1275*30088Sminshall #define	TS_DATA		0
1276*30088Sminshall #define	TS_IAC		1
1277*30088Sminshall #define	TS_WILL		2
1278*30088Sminshall #define	TS_WONT		3
1279*30088Sminshall #define	TS_DO		4
1280*30088Sminshall #define	TS_DONT		5
1281*30088Sminshall #define	TS_CR		6
1282*30088Sminshall #define	TS_SB		7		/* sub-option collection */
1283*30088Sminshall #define	TS_SE		8		/* looking for sub-option end */
1284*30088Sminshall 
1285*30088Sminshall static void
1286*30088Sminshall telrcv()
1287*30088Sminshall {
1288*30088Sminshall     register int c;
1289*30088Sminshall     static int state = TS_DATA;
1290*30088Sminshall #   if defined(TN3270)
1291*30088Sminshall     register int Scc;
1292*30088Sminshall     register char *Sbp;
1293*30088Sminshall #   endif /* defined(TN3270) */
1294*30088Sminshall 
1295*30088Sminshall     while ((scc > 0) && (TTYROOM() > 2)) {
1296*30088Sminshall 	c = *sbp++ & 0xff, scc--;
1297*30088Sminshall 	switch (state) {
1298*30088Sminshall 
1299*30088Sminshall 	case TS_CR:
1300*30088Sminshall 	    state = TS_DATA;
1301*30088Sminshall 	    if (c == '\0') {
1302*30088Sminshall 		break;	/* Ignore \0 after CR */
1303*30088Sminshall 	    } else if (c == '\n') {
1304*30088Sminshall 		if (hisopts[TELOPT_ECHO] && !crmod) {
1305*30088Sminshall 		    TTYADD(c);
1306*30088Sminshall 		}
1307*30088Sminshall 		break;
1308*30088Sminshall 	    }
1309*30088Sminshall 	    /* Else, fall through */
1310*30088Sminshall 
1311*30088Sminshall 	case TS_DATA:
1312*30088Sminshall 	    if (c == IAC) {
1313*30088Sminshall 		state = TS_IAC;
1314*30088Sminshall 		continue;
1315*30088Sminshall 	    }
1316*30088Sminshall #	    if defined(TN3270)
1317*30088Sminshall 	    if (In3270) {
1318*30088Sminshall 		*Ifrontp++ = c;
1319*30088Sminshall 		Sbp = sbp;
1320*30088Sminshall 		Scc = scc;
1321*30088Sminshall 		while (Scc > 0) {
1322*30088Sminshall 		    c = *Sbp++ & 0377, Scc--;
1323*30088Sminshall 		    if (c == IAC) {
1324*30088Sminshall 			state = TS_IAC;
1325*30088Sminshall 			break;
1326*30088Sminshall 		    }
1327*30088Sminshall 		    *Ifrontp++ = c;
1328*30088Sminshall 		}
1329*30088Sminshall 		sbp = Sbp;
1330*30088Sminshall 		scc = Scc;
1331*30088Sminshall 	    } else
1332*30088Sminshall #	    endif /* defined(TN3270) */
1333*30088Sminshall 		    /*
1334*30088Sminshall 		     * The 'crmod' hack (see following) is needed
1335*30088Sminshall 		     * since we can't * set CRMOD on output only.
1336*30088Sminshall 		     * Machines like MULTICS like to send \r without
1337*30088Sminshall 		     * \n; since we must turn off CRMOD to get proper
1338*30088Sminshall 		     * input, the mapping is done here (sigh).
1339*30088Sminshall 		     */
1340*30088Sminshall 	    if (c == '\r') {
1341*30088Sminshall 		if (scc > 0) {
1342*30088Sminshall 		    c = *sbp&0xff;
1343*30088Sminshall 		    if (c == 0) {
1344*30088Sminshall 			sbp++, scc--;
1345*30088Sminshall 			/* a "true" CR */
1346*30088Sminshall 			TTYADD('\r');
1347*30088Sminshall 		    } else if (!hisopts[TELOPT_ECHO] &&
1348*30088Sminshall 					(c == '\n')) {
1349*30088Sminshall 			sbp++, scc--;
1350*30088Sminshall 			TTYADD('\n');
1351*30088Sminshall 		    } else {
1352*30088Sminshall 			TTYADD('\r');
1353*30088Sminshall 			if (crmod) {
1354*30088Sminshall 				TTYADD('\n');
1355*30088Sminshall 			}
1356*30088Sminshall 		    }
1357*30088Sminshall 		} else {
1358*30088Sminshall 		    state = TS_CR;
1359*30088Sminshall 		    TTYADD('\r');
1360*30088Sminshall 		    if (crmod) {
1361*30088Sminshall 			    TTYADD('\n');
1362*30088Sminshall 		    }
1363*30088Sminshall 		}
1364*30088Sminshall 	    } else {
1365*30088Sminshall 		TTYADD(c);
1366*30088Sminshall 	    }
1367*30088Sminshall 	    continue;
1368*30088Sminshall 
1369*30088Sminshall 	case TS_IAC:
1370*30088Sminshall 	    switch (c) {
1371*30088Sminshall 
1372*30088Sminshall 	    case WILL:
1373*30088Sminshall 		state = TS_WILL;
1374*30088Sminshall 		continue;
1375*30088Sminshall 
1376*30088Sminshall 	    case WONT:
1377*30088Sminshall 		state = TS_WONT;
1378*30088Sminshall 		continue;
1379*30088Sminshall 
1380*30088Sminshall 	    case DO:
1381*30088Sminshall 		state = TS_DO;
1382*30088Sminshall 		continue;
1383*30088Sminshall 
1384*30088Sminshall 	    case DONT:
1385*30088Sminshall 		state = TS_DONT;
1386*30088Sminshall 		continue;
1387*30088Sminshall 
1388*30088Sminshall 	    case DM:
1389*30088Sminshall 		    /*
1390*30088Sminshall 		     * We may have missed an urgent notification,
1391*30088Sminshall 		     * so make sure we flush whatever is in the
1392*30088Sminshall 		     * buffer currently.
1393*30088Sminshall 		     */
1394*30088Sminshall 		SYNCHing = 1;
1395*30088Sminshall 		ttyflush();
1396*30088Sminshall 		SYNCHing = stilloob(net);
1397*30088Sminshall 		settimer(gotDM);
1398*30088Sminshall 		break;
1399*30088Sminshall 
1400*30088Sminshall 	    case NOP:
1401*30088Sminshall 	    case GA:
1402*30088Sminshall 		break;
1403*30088Sminshall 
1404*30088Sminshall 	    case SB:
1405*30088Sminshall 		SB_CLEAR();
1406*30088Sminshall 		state = TS_SB;
1407*30088Sminshall 		continue;
1408*30088Sminshall 
1409*30088Sminshall #	    if defined(TN3270)
1410*30088Sminshall 	    case EOR:
1411*30088Sminshall 		if (In3270) {
1412*30088Sminshall 		    Ibackp += DataFromNetwork(Ibackp, Ifrontp-Ibackp, 1);
1413*30088Sminshall 		    if (Ibackp == Ifrontp) {
1414*30088Sminshall 			Ibackp = Ifrontp = Ibuf;
1415*30088Sminshall 			ISend = 0;	/* should have been! */
1416*30088Sminshall 		    } else {
1417*30088Sminshall 			ISend = 1;
1418*30088Sminshall 		    }
1419*30088Sminshall 		}
1420*30088Sminshall 		break;
1421*30088Sminshall #	    endif /* defined(TN3270) */
1422*30088Sminshall 
1423*30088Sminshall 	    case IAC:
1424*30088Sminshall #	    if !defined(TN3270)
1425*30088Sminshall 		TTYADD(IAC);
1426*30088Sminshall #	    else /* !defined(TN3270) */
1427*30088Sminshall 		if (In3270) {
1428*30088Sminshall 		    *Ifrontp++ = IAC;
1429*30088Sminshall 		} else {
1430*30088Sminshall 		    TTYADD(IAC);
1431*30088Sminshall 		}
1432*30088Sminshall #	    endif /* !defined(TN3270) */
1433*30088Sminshall 		break;
1434*30088Sminshall 
1435*30088Sminshall 	    default:
1436*30088Sminshall 		break;
1437*30088Sminshall 	    }
1438*30088Sminshall 	    state = TS_DATA;
1439*30088Sminshall 	    continue;
1440*30088Sminshall 
1441*30088Sminshall 	case TS_WILL:
1442*30088Sminshall 	    printoption(">RCVD", will, c, !hisopts[c]);
1443*30088Sminshall 	    if (c == TELOPT_TM) {
1444*30088Sminshall 		if (flushout) {
1445*30088Sminshall 		    flushout = 0;
1446*30088Sminshall 		}
1447*30088Sminshall 	    } else if (!hisopts[c]) {
1448*30088Sminshall 		willoption(c, 1);
1449*30088Sminshall 	    }
1450*30088Sminshall 	    SetIn3270();
1451*30088Sminshall 	    state = TS_DATA;
1452*30088Sminshall 	    continue;
1453*30088Sminshall 
1454*30088Sminshall 	case TS_WONT:
1455*30088Sminshall 	    printoption(">RCVD", wont, c, hisopts[c]);
1456*30088Sminshall 	    if (c == TELOPT_TM) {
1457*30088Sminshall 		if (flushout) {
1458*30088Sminshall 		    flushout = 0;
1459*30088Sminshall 		}
1460*30088Sminshall 	    } else if (hisopts[c]) {
1461*30088Sminshall 		wontoption(c, 1);
1462*30088Sminshall 	    }
1463*30088Sminshall 	    SetIn3270();
1464*30088Sminshall 	    state = TS_DATA;
1465*30088Sminshall 	    continue;
1466*30088Sminshall 
1467*30088Sminshall 	case TS_DO:
1468*30088Sminshall 	    printoption(">RCVD", doopt, c, !myopts[c]);
1469*30088Sminshall 	    if (!myopts[c])
1470*30088Sminshall 		dooption(c);
1471*30088Sminshall 	    SetIn3270();
1472*30088Sminshall 	    state = TS_DATA;
1473*30088Sminshall 	    continue;
1474*30088Sminshall 
1475*30088Sminshall 	case TS_DONT:
1476*30088Sminshall 	    printoption(">RCVD", dont, c, myopts[c]);
1477*30088Sminshall 	    if (myopts[c]) {
1478*30088Sminshall 		myopts[c] = 0;
1479*30088Sminshall 		sprintf(nfrontp, wont, c);
1480*30088Sminshall 		nfrontp += sizeof (wont) - 2;
1481*30088Sminshall 		flushline = 1;
1482*30088Sminshall 		setconnmode();	/* set new tty mode (maybe) */
1483*30088Sminshall 		printoption(">SENT", wont, c, 0);
1484*30088Sminshall 	    }
1485*30088Sminshall 	    SetIn3270();
1486*30088Sminshall 	    state = TS_DATA;
1487*30088Sminshall 	    continue;
1488*30088Sminshall 
1489*30088Sminshall 	case TS_SB:
1490*30088Sminshall 	    if (c == IAC) {
1491*30088Sminshall 		state = TS_SE;
1492*30088Sminshall 	    } else {
1493*30088Sminshall 		SB_ACCUM(c);
1494*30088Sminshall 	    }
1495*30088Sminshall 	    continue;
1496*30088Sminshall 
1497*30088Sminshall 	case TS_SE:
1498*30088Sminshall 	    if (c != SE) {
1499*30088Sminshall 		if (c != IAC) {
1500*30088Sminshall 		    SB_ACCUM(IAC);
1501*30088Sminshall 		}
1502*30088Sminshall 		SB_ACCUM(c);
1503*30088Sminshall 		state = TS_SB;
1504*30088Sminshall 	    } else {
1505*30088Sminshall 		SB_TERM();
1506*30088Sminshall 		suboption();	/* handle sub-option */
1507*30088Sminshall 		SetIn3270();
1508*30088Sminshall 		state = TS_DATA;
1509*30088Sminshall 	    }
1510*30088Sminshall 	}
1511*30088Sminshall     }
1512*30088Sminshall }
1513*30088Sminshall 
1514*30088Sminshall #if	defined(TN3270)
1515*30088Sminshall 
1516*30088Sminshall /*
1517*30088Sminshall  * The following routines are places where the various tn3270
1518*30088Sminshall  * routines make calls into telnet.c.
1519*30088Sminshall  */
1520*30088Sminshall 
1521*30088Sminshall /* TtyChars() - returns the number of characters in the TTY buffer */
1522*30088Sminshall TtyChars()
1523*30088Sminshall {
1524*30088Sminshall     return(tfrontp-tbackp);
1525*30088Sminshall }
1526*30088Sminshall 
1527*30088Sminshall /*
1528*30088Sminshall  * DataToNetwork - queue up some data to go to network.  If "done" is set,
1529*30088Sminshall  * then when last byte is queued, we add on an IAC EOR sequence (so,
1530*30088Sminshall  * don't call us with "done" until you want that done...)
1531*30088Sminshall  *
1532*30088Sminshall  * We actually do send all the data to the network buffer, since our
1533*30088Sminshall  * only client needs for us to do that.
1534*30088Sminshall  */
1535*30088Sminshall 
1536*30088Sminshall int
1537*30088Sminshall DataToNetwork(buffer, count, done)
1538*30088Sminshall register char	*buffer;	/* where the data is */
1539*30088Sminshall register int	count;		/* how much to send */
1540*30088Sminshall int		done;		/* is this the last of a logical block */
1541*30088Sminshall {
1542*30088Sminshall     register int c;
1543*30088Sminshall     int origCount;
1544*30088Sminshall     fd_set o;
1545*30088Sminshall 
1546*30088Sminshall     origCount = count;
1547*30088Sminshall     FD_ZERO(&o);
1548*30088Sminshall 
1549*30088Sminshall     while (count) {
1550*30088Sminshall 	if ((netobuf+sizeof netobuf - nfrontp) < 6) {
1551*30088Sminshall 	    netflush();
1552*30088Sminshall 	    while ((netobuf+sizeof netobuf - nfrontp) < 6) {
1553*30088Sminshall 		FD_SET(net, &o);
1554*30088Sminshall 		(void) select(net+1, (fd_set *) 0, &o, (fd_set *) 0,
1555*30088Sminshall 						(struct timeval *) 0);
1556*30088Sminshall 		netflush();
1557*30088Sminshall 	    }
1558*30088Sminshall 	}
1559*30088Sminshall 	c = *buffer++;
1560*30088Sminshall 	count--;
1561*30088Sminshall 	if (c == IAC) {
1562*30088Sminshall 	    *nfrontp++ = IAC;
1563*30088Sminshall 	    *nfrontp++ = IAC;
1564*30088Sminshall 	} else {
1565*30088Sminshall 	    *nfrontp++ = c;
1566*30088Sminshall 	}
1567*30088Sminshall     }
1568*30088Sminshall 
1569*30088Sminshall     if (done && !count) {
1570*30088Sminshall 	*nfrontp++ = IAC;
1571*30088Sminshall 	*nfrontp++ = EOR;
1572*30088Sminshall 	netflush();		/* try to move along as quickly as ... */
1573*30088Sminshall     }
1574*30088Sminshall     return(origCount - count);
1575*30088Sminshall }
1576*30088Sminshall 
1577*30088Sminshall /* DataToTerminal - queue up some data to go to terminal. */
1578*30088Sminshall 
1579*30088Sminshall int
1580*30088Sminshall DataToTerminal(buffer, count)
1581*30088Sminshall register char	*buffer;		/* where the data is */
1582*30088Sminshall register int	count;			/* how much to send */
1583*30088Sminshall {
1584*30088Sminshall     int origCount;
1585*30088Sminshall     fd_set	o;
1586*30088Sminshall 
1587*30088Sminshall     origCount = count;
1588*30088Sminshall     FD_ZERO(&o);
1589*30088Sminshall 
1590*30088Sminshall     while (count) {
1591*30088Sminshall 	if (tfrontp >= ttyobuf+sizeof ttyobuf) {
1592*30088Sminshall 	    ttyflush();
1593*30088Sminshall 	    while (tfrontp >= ttyobuf+sizeof ttyobuf) {
1594*30088Sminshall 		FD_SET(tout, &o);
1595*30088Sminshall 		(void) select(tout+1, (fd_set *) 0, &o, (fd_set *) 0,
1596*30088Sminshall 						(struct timeval *) 0);
1597*30088Sminshall 		ttyflush();
1598*30088Sminshall 	    }
1599*30088Sminshall 	}
1600*30088Sminshall 	*tfrontp++ = *buffer++;
1601*30088Sminshall 	count--;
1602*30088Sminshall     }
1603*30088Sminshall     return(origCount - count);
1604*30088Sminshall }
1605*30088Sminshall 
1606*30088Sminshall /* EmptyTerminal - called to make sure that the terminal buffer is empty.
1607*30088Sminshall  *			Note that we consider the buffer to run all the
1608*30088Sminshall  *			way to the kernel (thus the select).
1609*30088Sminshall  */
1610*30088Sminshall 
1611*30088Sminshall void
1612*30088Sminshall EmptyTerminal()
1613*30088Sminshall {
1614*30088Sminshall     fd_set	o;
1615*30088Sminshall 
1616*30088Sminshall     FD_ZERO(&o);
1617*30088Sminshall 
1618*30088Sminshall     if (tfrontp == tbackp) {
1619*30088Sminshall 	FD_SET(tout, &o);
1620*30088Sminshall 	(void) select(tout+1, (int *) 0, &o, (int *) 0,
1621*30088Sminshall 			(struct timeval *) 0);	/* wait for TTLOWAT */
1622*30088Sminshall     } else {
1623*30088Sminshall 	while (tfrontp != tbackp) {
1624*30088Sminshall 	    ttyflush();
1625*30088Sminshall 	    FD_SET(tout, &o);
1626*30088Sminshall 	    (void) select(tout+1, (int *) 0, &o, (int *) 0,
1627*30088Sminshall 				(struct timeval *) 0);	/* wait for TTLOWAT */
1628*30088Sminshall 	}
1629*30088Sminshall     }
1630*30088Sminshall }
1631*30088Sminshall 
1632*30088Sminshall /*
1633*30088Sminshall  * Push3270 - Try to send data along the 3270 output (to screen) direction.
1634*30088Sminshall  */
1635*30088Sminshall 
1636*30088Sminshall static int
1637*30088Sminshall Push3270()
1638*30088Sminshall {
1639*30088Sminshall     int save = scc;
1640*30088Sminshall 
1641*30088Sminshall     if (scc) {
1642*30088Sminshall 	if (Ifrontp+scc > Ibuf+sizeof Ibuf) {
1643*30088Sminshall 	    if (Ibackp != Ibuf) {
1644*30088Sminshall 		bcopy(Ibackp, Ibuf, Ifrontp-Ibackp);
1645*30088Sminshall 		Ifrontp -= (Ibackp-Ibuf);
1646*30088Sminshall 		Ibackp = Ibuf;
1647*30088Sminshall 	    }
1648*30088Sminshall 	}
1649*30088Sminshall 	if (Ifrontp+scc < Ibuf+sizeof Ibuf) {
1650*30088Sminshall 	    telrcv();
1651*30088Sminshall 	}
1652*30088Sminshall     }
1653*30088Sminshall     return save != scc;
1654*30088Sminshall }
1655*30088Sminshall 
1656*30088Sminshall 
1657*30088Sminshall /*
1658*30088Sminshall  * Finish3270 - get the last dregs of 3270 data out to the terminal
1659*30088Sminshall  *		before quitting.
1660*30088Sminshall  */
1661*30088Sminshall 
1662*30088Sminshall static void
1663*30088Sminshall Finish3270()
1664*30088Sminshall {
1665*30088Sminshall     while (Push3270() || !DoTerminalOutput()) {
1666*30088Sminshall 	;
1667*30088Sminshall     }
1668*30088Sminshall }
1669*30088Sminshall 
1670*30088Sminshall 
1671*30088Sminshall 
1672*30088Sminshall /* StringToTerminal - output a null terminated string to the terminal */
1673*30088Sminshall 
1674*30088Sminshall void
1675*30088Sminshall StringToTerminal(s)
1676*30088Sminshall char *s;
1677*30088Sminshall {
1678*30088Sminshall     int count;
1679*30088Sminshall 
1680*30088Sminshall     count = strlen(s);
1681*30088Sminshall     if (count) {
1682*30088Sminshall 	(void) DataToTerminal(s, count);	/* we know it always goes... */
1683*30088Sminshall     }
1684*30088Sminshall }
1685*30088Sminshall 
1686*30088Sminshall 
1687*30088Sminshall #if	defined(TN3270) && ((!defined(NOT43)) || defined(PUTCHAR))
1688*30088Sminshall /* _putchar - output a single character to the terminal.  This name is so that
1689*30088Sminshall  *	curses(3x) can call us to send out data.
1690*30088Sminshall  */
1691*30088Sminshall 
1692*30088Sminshall void
1693*30088Sminshall _putchar(c)
1694*30088Sminshall char c;
1695*30088Sminshall {
1696*30088Sminshall     if (tfrontp >= ttyobuf+sizeof ttyobuf) {
1697*30088Sminshall 	(void) DataToTerminal(&c, 1);
1698*30088Sminshall     } else {
1699*30088Sminshall 	*tfrontp++ = c;		/* optimize if possible. */
1700*30088Sminshall     }
1701*30088Sminshall }
1702*30088Sminshall #endif	/* defined(TN3270) && ((!defined(NOT43)) || defined(PUTCHAR)) */
1703*30088Sminshall 
1704*30088Sminshall static void
1705*30088Sminshall SetForExit()
1706*30088Sminshall {
1707*30088Sminshall     setconnmode();
1708*30088Sminshall     if (In3270) {
1709*30088Sminshall 	Finish3270();
1710*30088Sminshall     }
1711*30088Sminshall     setcommandmode();
1712*30088Sminshall     fflush(stdout);
1713*30088Sminshall     fflush(stderr);
1714*30088Sminshall     if (In3270) {
1715*30088Sminshall 	StopScreen(1);
1716*30088Sminshall     }
1717*30088Sminshall     setconnmode();
1718*30088Sminshall     setcommandmode();
1719*30088Sminshall }
1720*30088Sminshall 
1721*30088Sminshall static void
1722*30088Sminshall Exit(returnCode)
1723*30088Sminshall int returnCode;
1724*30088Sminshall {
1725*30088Sminshall     SetForExit();
1726*30088Sminshall     exit(returnCode);
1727*30088Sminshall }
1728*30088Sminshall 
1729*30088Sminshall void
1730*30088Sminshall ExitString(file, string, returnCode)
1731*30088Sminshall FILE *file;
1732*30088Sminshall char *string;
1733*30088Sminshall int returnCode;
1734*30088Sminshall {
1735*30088Sminshall     SetForExit();
1736*30088Sminshall     fwrite(string, 1, strlen(string), file);
1737*30088Sminshall     exit(returnCode);
1738*30088Sminshall }
1739*30088Sminshall 
1740*30088Sminshall void
1741*30088Sminshall ExitPerror(string, returnCode)
1742*30088Sminshall char *string;
1743*30088Sminshall int returnCode;
1744*30088Sminshall {
1745*30088Sminshall     SetForExit();
1746*30088Sminshall     perror(string);
1747*30088Sminshall     exit(returnCode);
1748*30088Sminshall }
1749*30088Sminshall 
1750*30088Sminshall #endif	/* defined(TN3270) */
1751*30088Sminshall 
1752*30088Sminshall static
1753*30088Sminshall Scheduler(block)
1754*30088Sminshall int	block;			/* should we block in the select ? */
1755*30088Sminshall {
1756*30088Sminshall     register int c;
1757*30088Sminshall 		/* One wants to be a bit careful about setting returnValue
1758*30088Sminshall 		 * to one, since a one implies we did some useful work,
1759*30088Sminshall 		 * and therefore probably won't be called to block next
1760*30088Sminshall 		 * time (TN3270 mode only).
1761*30088Sminshall 		 */
1762*30088Sminshall     int returnValue = 0;
1763*30088Sminshall     static struct timeval TimeValue = { 0 };
1764*30088Sminshall 
1765*30088Sminshall     if (scc < 0 && tcc < 0) {
1766*30088Sminshall 	return -1;
1767*30088Sminshall     }
1768*30088Sminshall 
1769*30088Sminshall     if ((!MODE_LINE(globalmode) || flushline) && NETBYTES()) {
1770*30088Sminshall 	FD_SET(net, &obits);
1771*30088Sminshall     }
1772*30088Sminshall     if (TTYBYTES()) {
1773*30088Sminshall 	FD_SET(tout, &obits);
1774*30088Sminshall     }
1775*30088Sminshall     if ((tcc == 0) && NETROOM()) {
1776*30088Sminshall 	FD_SET(tin, &ibits);
1777*30088Sminshall     }
1778*30088Sminshall #   if !defined(TN3270)
1779*30088Sminshall     if (TTYROOM()) {
1780*30088Sminshall 	FD_SET(net, &ibits);
1781*30088Sminshall     }
1782*30088Sminshall #   else /* !defined(TN3270) */
1783*30088Sminshall     if (!ISend && TTYROOM()) {
1784*30088Sminshall 	FD_SET(net, &ibits);
1785*30088Sminshall     }
1786*30088Sminshall #   endif /* !defined(TN3270) */
1787*30088Sminshall     if (!SYNCHing) {
1788*30088Sminshall 	FD_SET(net, &xbits);
1789*30088Sminshall     }
1790*30088Sminshall #   if defined(TN3270) && defined(unix)
1791*30088Sminshall     if (HaveInput) {
1792*30088Sminshall 	HaveInput = 0;
1793*30088Sminshall 	signal(SIGIO, inputAvailable);
1794*30088Sminshall     }
1795*30088Sminshall #endif	/* defined(TN3270) && defined(unix) */
1796*30088Sminshall     if ((c = select(16, &ibits, &obits, &xbits,
1797*30088Sminshall 			block? (struct timeval *)0 : &TimeValue)) < 1) {
1798*30088Sminshall 	if (c == -1) {
1799*30088Sminshall 		    /*
1800*30088Sminshall 		     * we can get EINTR if we are in line mode,
1801*30088Sminshall 		     * and the user does an escape (TSTP), or
1802*30088Sminshall 		     * some other signal generator.
1803*30088Sminshall 		     */
1804*30088Sminshall 	    if (errno == EINTR) {
1805*30088Sminshall 		return 0;
1806*30088Sminshall 	    }
1807*30088Sminshall #	    if defined(TN3270)
1808*30088Sminshall 		    /*
1809*30088Sminshall 		     * we can get EBADF if we were in transparent
1810*30088Sminshall 		     * mode, and the transcom process died.
1811*30088Sminshall 		    */
1812*30088Sminshall 	    if (errno == EBADF) {
1813*30088Sminshall 			/*
1814*30088Sminshall 			 * zero the bits (even though kernel does it)
1815*30088Sminshall 			 * to make sure we are selecting on the right
1816*30088Sminshall 			 * ones.
1817*30088Sminshall 			*/
1818*30088Sminshall 		FD_ZERO(&ibits);
1819*30088Sminshall 		FD_ZERO(&obits);
1820*30088Sminshall 		FD_ZERO(&xbits);
1821*30088Sminshall 		return 0;
1822*30088Sminshall 	    }
1823*30088Sminshall #	    endif /* defined(TN3270) */
1824*30088Sminshall 		    /* I don't like this, does it ever happen? */
1825*30088Sminshall 	    printf("sleep(5) from telnet, after select\r\n");
1826*30088Sminshall #if	defined(unix)
1827*30088Sminshall 	    sleep(5);
1828*30088Sminshall #endif	/* defined(unix) */
1829*30088Sminshall 	}
1830*30088Sminshall 	return 0;
1831*30088Sminshall     }
1832*30088Sminshall 
1833*30088Sminshall     /*
1834*30088Sminshall      * Any urgent data?
1835*30088Sminshall      */
1836*30088Sminshall     if (FD_ISSET(net, &xbits)) {
1837*30088Sminshall 	FD_CLR(net, &xbits);
1838*30088Sminshall 	SYNCHing = 1;
1839*30088Sminshall 	ttyflush();	/* flush already enqueued data */
1840*30088Sminshall     }
1841*30088Sminshall 
1842*30088Sminshall     /*
1843*30088Sminshall      * Something to read from the network...
1844*30088Sminshall      */
1845*30088Sminshall     if (FD_ISSET(net, &ibits)) {
1846*30088Sminshall 	int canread;
1847*30088Sminshall 
1848*30088Sminshall 	FD_CLR(net, &ibits);
1849*30088Sminshall 	if (scc == 0) {
1850*30088Sminshall 	    sbp = sibuf;
1851*30088Sminshall 	}
1852*30088Sminshall 	canread = sibuf + sizeof sibuf - sbp;
1853*30088Sminshall #if	!defined(SO_OOBINLINE)
1854*30088Sminshall 	    /*
1855*30088Sminshall 	     * In 4.2 (and some early 4.3) systems, the
1856*30088Sminshall 	     * OOB indication and data handling in the kernel
1857*30088Sminshall 	     * is such that if two separate TCP Urgent requests
1858*30088Sminshall 	     * come in, one byte of TCP data will be overlaid.
1859*30088Sminshall 	     * This is fatal for Telnet, but we try to live
1860*30088Sminshall 	     * with it.
1861*30088Sminshall 	     *
1862*30088Sminshall 	     * In addition, in 4.2 (and...), a special protocol
1863*30088Sminshall 	     * is needed to pick up the TCP Urgent data in
1864*30088Sminshall 	     * the correct sequence.
1865*30088Sminshall 	     *
1866*30088Sminshall 	     * What we do is:  if we think we are in urgent
1867*30088Sminshall 	     * mode, we look to see if we are "at the mark".
1868*30088Sminshall 	     * If we are, we do an OOB receive.  If we run
1869*30088Sminshall 	     * this twice, we will do the OOB receive twice,
1870*30088Sminshall 	     * but the second will fail, since the second
1871*30088Sminshall 	     * time we were "at the mark", but there wasn't
1872*30088Sminshall 	     * any data there (the kernel doesn't reset
1873*30088Sminshall 	     * "at the mark" until we do a normal read).
1874*30088Sminshall 	     * Once we've read the OOB data, we go ahead
1875*30088Sminshall 	     * and do normal reads.
1876*30088Sminshall 	     *
1877*30088Sminshall 	     * There is also another problem, which is that
1878*30088Sminshall 	     * since the OOB byte we read doesn't put us
1879*30088Sminshall 	     * out of OOB state, and since that byte is most
1880*30088Sminshall 	     * likely the TELNET DM (data mark), we would
1881*30088Sminshall 	     * stay in the TELNET SYNCH (SYNCHing) state.
1882*30088Sminshall 	     * So, clocks to the rescue.  If we've "just"
1883*30088Sminshall 	     * received a DM, then we test for the
1884*30088Sminshall 	     * presence of OOB data when the receive OOB
1885*30088Sminshall 	     * fails (and AFTER we did the normal mode read
1886*30088Sminshall 	     * to clear "at the mark").
1887*30088Sminshall 	     */
1888*30088Sminshall 	if (SYNCHing) {
1889*30088Sminshall 	    int atmark;
1890*30088Sminshall 
1891*30088Sminshall 	    ioctl(net, SIOCATMARK, (char *)&atmark);
1892*30088Sminshall 	    if (atmark) {
1893*30088Sminshall 		c = recv(net, sibuf, canread, MSG_OOB);
1894*30088Sminshall 		if ((c == -1) && (errno == EINVAL)) {
1895*30088Sminshall 		    c = read(net, sibuf, canread);
1896*30088Sminshall 		    if (clocks.didnetreceive < clocks.gotDM) {
1897*30088Sminshall 			SYNCHing = stilloob(net);
1898*30088Sminshall 		    }
1899*30088Sminshall 		}
1900*30088Sminshall 	    } else {
1901*30088Sminshall 		c = read(net, sibuf, canread);
1902*30088Sminshall 	    }
1903*30088Sminshall 	} else {
1904*30088Sminshall 	    c = read(net, sibuf, canread);
1905*30088Sminshall 	}
1906*30088Sminshall 	settimer(didnetreceive);
1907*30088Sminshall #else	/* !defined(SO_OOBINLINE) */
1908*30088Sminshall 	c = read(net, sbp, canread);
1909*30088Sminshall #endif	/* !defined(SO_OOBINLINE) */
1910*30088Sminshall 	if (c < 0 && errno == EWOULDBLOCK) {
1911*30088Sminshall 	    c = 0;
1912*30088Sminshall 	} else if (c <= 0) {
1913*30088Sminshall 	    return -1;
1914*30088Sminshall 	}
1915*30088Sminshall 	if (netdata) {
1916*30088Sminshall 	    Dump('<', sbp, c);
1917*30088Sminshall 	}
1918*30088Sminshall 	scc += c;
1919*30088Sminshall 	returnValue = 1;
1920*30088Sminshall     }
1921*30088Sminshall 
1922*30088Sminshall     /*
1923*30088Sminshall      * Something to read from the tty...
1924*30088Sminshall      */
1925*30088Sminshall     if (FD_ISSET(tin, &ibits)) {
1926*30088Sminshall 	FD_CLR(tin, &ibits);
1927*30088Sminshall 	if (tcc == 0) {
1928*30088Sminshall 	    tbp = tibuf;	/* nothing left, reset */
1929*30088Sminshall 	}
1930*30088Sminshall 	c = read(tin, tbp, tibuf+sizeof tibuf - tbp);
1931*30088Sminshall 	if (c < 0 && errno == EWOULDBLOCK) {
1932*30088Sminshall 	    c = 0;
1933*30088Sminshall 	} else {
1934*30088Sminshall 	    /* EOF detection for line mode!!!! */
1935*30088Sminshall 	    if (c == 0 && MODE_LOCAL_CHARS(globalmode)) {
1936*30088Sminshall 			/* must be an EOF... */
1937*30088Sminshall 		*tbp = ntc.t_eofc;
1938*30088Sminshall 		c = 1;
1939*30088Sminshall 	    }
1940*30088Sminshall 	    if (c <= 0) {
1941*30088Sminshall 		tcc = c;
1942*30088Sminshall 		return -1;
1943*30088Sminshall 	    }
1944*30088Sminshall 	}
1945*30088Sminshall 	tcc += c;
1946*30088Sminshall 	returnValue = 1;		/* did something useful */
1947*30088Sminshall     }
1948*30088Sminshall 
1949*30088Sminshall #   if defined(TN3270)
1950*30088Sminshall     if (tcc > 0) {
1951*30088Sminshall 	if (In3270) {
1952*30088Sminshall 	    c = DataFromTerminal(tbp, tcc);
1953*30088Sminshall 	    if (c) {
1954*30088Sminshall 		returnValue = 1;
1955*30088Sminshall 	    }
1956*30088Sminshall 	    tcc -= c;
1957*30088Sminshall 	    tbp += c;
1958*30088Sminshall 	} else {
1959*30088Sminshall #   endif defined(TN3270)
1960*30088Sminshall 	    returnValue = 1;
1961*30088Sminshall 	    while (tcc > 0) {
1962*30088Sminshall 		register int sc;
1963*30088Sminshall 
1964*30088Sminshall 		if (NETROOM() < 2) {
1965*30088Sminshall 		    flushline = 1;
1966*30088Sminshall 		    break;
1967*30088Sminshall 		}
1968*30088Sminshall 		c = *tbp++ & 0xff, sc = strip(c), tcc--;
1969*30088Sminshall 		if (sc == escape) {
1970*30088Sminshall 		    command(0);
1971*30088Sminshall 		    tcc = 0;
1972*30088Sminshall 		    flushline = 1;
1973*30088Sminshall 		    break;
1974*30088Sminshall 		} else if (MODE_LINE(globalmode) && (sc == echoc)) {
1975*30088Sminshall 		    if (tcc > 0 && strip(*tbp) == echoc) {
1976*30088Sminshall 			tbp++;
1977*30088Sminshall 			tcc--;
1978*30088Sminshall 		    } else {
1979*30088Sminshall 			dontlecho = !dontlecho;
1980*30088Sminshall 			settimer(echotoggle);
1981*30088Sminshall 			setconnmode();
1982*30088Sminshall 			tcc = 0;
1983*30088Sminshall 			flushline = 1;
1984*30088Sminshall 			break;
1985*30088Sminshall 		    }
1986*30088Sminshall 		}
1987*30088Sminshall 		if (localchars) {
1988*30088Sminshall 		    if (sc == ntc.t_intrc) {
1989*30088Sminshall 			intp();
1990*30088Sminshall 			break;
1991*30088Sminshall 		    } else if (sc == ntc.t_quitc) {
1992*30088Sminshall 			sendbrk();
1993*30088Sminshall 			break;
1994*30088Sminshall 		    } else if (sc == nltc.t_flushc) {
1995*30088Sminshall 			NET2ADD(IAC, AO);
1996*30088Sminshall 			if (autoflush) {
1997*30088Sminshall 			    doflush();
1998*30088Sminshall 			}
1999*30088Sminshall 			break;
2000*30088Sminshall 		    } else if (MODE_LOCAL_CHARS(globalmode)) {
2001*30088Sminshall 			;
2002*30088Sminshall 		    } else if (sc == nttyb.sg_kill) {
2003*30088Sminshall 			NET2ADD(IAC, EL);
2004*30088Sminshall 			break;
2005*30088Sminshall 		    } else if (sc == nttyb.sg_erase) {
2006*30088Sminshall 			NET2ADD(IAC, EC);
2007*30088Sminshall 			break;
2008*30088Sminshall 		    }
2009*30088Sminshall 		}
2010*30088Sminshall 		switch (c) {
2011*30088Sminshall 		case '\n':
2012*30088Sminshall 			/*
2013*30088Sminshall 			 * If we are in CRMOD mode (\r ==> \n)
2014*30088Sminshall 			 * on our local machine, then probably
2015*30088Sminshall 			 * a newline (unix) is CRLF (TELNET).
2016*30088Sminshall 			 */
2017*30088Sminshall 		    if (MODE_LOCAL_CHARS(globalmode)) {
2018*30088Sminshall 			NETADD('\r');
2019*30088Sminshall 		    }
2020*30088Sminshall 		    NETADD('\n');
2021*30088Sminshall 		    flushline = 1;
2022*30088Sminshall 		    break;
2023*30088Sminshall 		case '\r':
2024*30088Sminshall 		    NET2ADD('\r', '\0');
2025*30088Sminshall 		    flushline = 1;
2026*30088Sminshall 		    break;
2027*30088Sminshall 		case IAC:
2028*30088Sminshall 		    NET2ADD(IAC, IAC);
2029*30088Sminshall 		    break;
2030*30088Sminshall 		default:
2031*30088Sminshall 		    NETADD(c);
2032*30088Sminshall 		    break;
2033*30088Sminshall 		}
2034*30088Sminshall 	    }
2035*30088Sminshall #   if defined(TN3270)
2036*30088Sminshall 	}
2037*30088Sminshall     }
2038*30088Sminshall #   endif /* defined(TN3270) */
2039*30088Sminshall 
2040*30088Sminshall     if ((!MODE_LINE(globalmode) || flushline) &&
2041*30088Sminshall 	FD_ISSET(net, &obits) && (NETBYTES() > 0)) {
2042*30088Sminshall 	FD_CLR(net, &obits);
2043*30088Sminshall 	returnValue = netflush();
2044*30088Sminshall     }
2045*30088Sminshall     if (scc > 0) {
2046*30088Sminshall #	if !defined(TN3270)
2047*30088Sminshall 	telrcv();
2048*30088Sminshall 	returnValue = 1;
2049*30088Sminshall #	else /* !defined(TN3270) */
2050*30088Sminshall 	returnValue = Push3270();
2051*30088Sminshall #	endif /* !defined(TN3270) */
2052*30088Sminshall     }
2053*30088Sminshall     if (FD_ISSET(tout, &obits) && (TTYBYTES() > 0)) {
2054*30088Sminshall 	FD_CLR(tout, &obits);
2055*30088Sminshall 	returnValue = ttyflush();
2056*30088Sminshall     }
2057*30088Sminshall     return returnValue;
2058*30088Sminshall }
2059*30088Sminshall 
2060*30088Sminshall /*
2061*30088Sminshall  * Select from tty and network...
2062*30088Sminshall  */
2063*30088Sminshall static void
2064*30088Sminshall telnet()
2065*30088Sminshall {
2066*30088Sminshall     int on = 1;
2067*30088Sminshall #if	defined(TN3270) && defined(unix)
2068*30088Sminshall     int myPid;
2069*30088Sminshall #endif	/* defined(TN3270) */
2070*30088Sminshall 
2071*30088Sminshall     tout = fileno(stdout);
2072*30088Sminshall     tin = fileno(stdin);
2073*30088Sminshall     setconnmode();
2074*30088Sminshall     scc = 0;
2075*30088Sminshall     tcc = 0;
2076*30088Sminshall     FD_ZERO(&ibits);
2077*30088Sminshall     FD_ZERO(&obits);
2078*30088Sminshall     FD_ZERO(&xbits);
2079*30088Sminshall 
2080*30088Sminshall     ioctl(net, FIONBIO, (char *)&on);
2081*30088Sminshall 
2082*30088Sminshall #if	defined(TN3270)
2083*30088Sminshall #if	!defined(DEBUG)		/* DBX can't handle! */
2084*30088Sminshall     ioctl(net, FIOASYNC, (char *)&on);	/* hear about input */
2085*30088Sminshall #endif	/* !defined(DEBUG) */
2086*30088Sminshall 
2087*30088Sminshall #if	defined(unix)
2088*30088Sminshall     myPid = getpid();
2089*30088Sminshall #if	defined(NOT43)
2090*30088Sminshall     myPid = -myPid;
2091*30088Sminshall #endif	/* defined(NOT43) */
2092*30088Sminshall     ioctl(net, SIOCSPGRP, (char *)&myPid);	/* set my pid */
2093*30088Sminshall #endif	/* defined(unix) */
2094*30088Sminshall 
2095*30088Sminshall #endif	/* defined(TN3270) */
2096*30088Sminshall 
2097*30088Sminshall #if	defined(SO_OOBINLINE)
2098*30088Sminshall     setsockopt(net, SOL_SOCKET, SO_OOBINLINE, &on, sizeof on);
2099*30088Sminshall #endif	/* defined(SO_OOBINLINE) */
2100*30088Sminshall 
2101*30088Sminshall     if (telnetport) {
2102*30088Sminshall 	if (!hisopts[TELOPT_SGA]) {
2103*30088Sminshall 	    willoption(TELOPT_SGA, 0);
2104*30088Sminshall 	}
2105*30088Sminshall #   if !defined(TN3270)
2106*30088Sminshall 	if (!myopts[TELOPT_TTYPE]) {
2107*30088Sminshall 	    dooption(TELOPT_TTYPE, 0);
2108*30088Sminshall 	}
2109*30088Sminshall #   endif !defined(TN3270)
2110*30088Sminshall     }
2111*30088Sminshall 
2112*30088Sminshall #   if !defined(TN3270)
2113*30088Sminshall     for (;;) {
2114*30088Sminshall 	if (Scheduler(1) == -1) {
2115*30088Sminshall 	    setcommandmode();
2116*30088Sminshall 	    return;
2117*30088Sminshall 	}
2118*30088Sminshall     }
2119*30088Sminshall #   else /* !defined(TN3270) */
2120*30088Sminshall     for (;;) {
2121*30088Sminshall 	int schedValue;
2122*30088Sminshall 
2123*30088Sminshall 	while (!In3270) {
2124*30088Sminshall 	    if (Scheduler(1) == -1) {
2125*30088Sminshall 		setcommandmode();
2126*30088Sminshall 		return;
2127*30088Sminshall 	    }
2128*30088Sminshall 	}
2129*30088Sminshall 
2130*30088Sminshall 	while ((schedValue = Scheduler(0)) != 0) {
2131*30088Sminshall 	    if (schedValue == -1) {
2132*30088Sminshall 		setcommandmode();
2133*30088Sminshall 		return;
2134*30088Sminshall 	    }
2135*30088Sminshall 	}
2136*30088Sminshall 		/* If there is data waiting to go out to terminal, don't
2137*30088Sminshall 		 * schedule any more data for the terminal.
2138*30088Sminshall 		 */
2139*30088Sminshall 	if (tfrontp-tbackp) {
2140*30088Sminshall 	    schedValue = 1;
2141*30088Sminshall 	} else {
2142*30088Sminshall 	    schedValue = DoTerminalOutput();
2143*30088Sminshall 	}
2144*30088Sminshall 	if (schedValue) {
2145*30088Sminshall 	    if (Scheduler(1) == -1) {
2146*30088Sminshall 		setcommandmode();
2147*30088Sminshall 		return;
2148*30088Sminshall 	    }
2149*30088Sminshall 	}
2150*30088Sminshall     }
2151*30088Sminshall #   endif /* !defined(TN3270) */
2152*30088Sminshall }
2153*30088Sminshall 
2154*30088Sminshall /*
2155*30088Sminshall  *	The following are data structures and routines for
2156*30088Sminshall  *	the "send" command.
2157*30088Sminshall  *
2158*30088Sminshall  */
2159*30088Sminshall 
2160*30088Sminshall struct sendlist {
2161*30088Sminshall     char	*name;		/* How user refers to it (case independent) */
2162*30088Sminshall     int		what;		/* Character to be sent (<0 ==> special) */
2163*30088Sminshall     char	*help;		/* Help information (0 ==> no help) */
2164*30088Sminshall #if	defined(NOT43)
2165*30088Sminshall     int		(*routine)();	/* Routine to perform (for special ops) */
2166*30088Sminshall #else	/* defined(NOT43) */
2167*30088Sminshall     void	(*routine)();	/* Routine to perform (for special ops) */
2168*30088Sminshall #endif	/* defined(NOT43) */
2169*30088Sminshall };
2170*30088Sminshall 
2171*30088Sminshall #define	SENDQUESTION	-1
2172*30088Sminshall #define	SENDESCAPE	-3
2173*30088Sminshall 
2174*30088Sminshall static struct sendlist Sendlist[] = {
2175*30088Sminshall     { "ao", AO, "Send Telnet Abort output" },
2176*30088Sminshall     { "ayt", AYT, "Send Telnet 'Are You There'" },
2177*30088Sminshall     { "brk", BREAK, "Send Telnet Break" },
2178*30088Sminshall     { "ec", EC, "Send Telnet Erase Character" },
2179*30088Sminshall     { "el", EL, "Send Telnet Erase Line" },
2180*30088Sminshall     { "escape", SENDESCAPE, "Send current escape character" },
2181*30088Sminshall     { "ga", GA, "Send Telnet 'Go Ahead' sequence" },
2182*30088Sminshall     { "ip", IP, "Send Telnet Interrupt Process" },
2183*30088Sminshall     { "nop", NOP, "Send Telnet 'No operation'" },
2184*30088Sminshall     { "synch", SYNCH, "Perform Telnet 'Synch operation'", dosynch },
2185*30088Sminshall     { "?", SENDQUESTION, "Display send options" },
2186*30088Sminshall     { 0 }
2187*30088Sminshall };
2188*30088Sminshall 
2189*30088Sminshall static struct sendlist Sendlist2[] = {		/* some synonyms */
2190*30088Sminshall 	{ "break", BREAK, 0 },
2191*30088Sminshall 
2192*30088Sminshall 	{ "intp", IP, 0 },
2193*30088Sminshall 	{ "interrupt", IP, 0 },
2194*30088Sminshall 	{ "intr", IP, 0 },
2195*30088Sminshall 
2196*30088Sminshall 	{ "help", SENDQUESTION, 0 },
2197*30088Sminshall 
2198*30088Sminshall 	{ 0 }
2199*30088Sminshall };
2200*30088Sminshall 
2201*30088Sminshall static char **
2202*30088Sminshall getnextsend(name)
2203*30088Sminshall char *name;
2204*30088Sminshall {
2205*30088Sminshall     struct sendlist *c = (struct sendlist *) name;
2206*30088Sminshall 
2207*30088Sminshall     return (char **) (c+1);
2208*30088Sminshall }
2209*30088Sminshall 
2210*30088Sminshall static struct sendlist *
2211*30088Sminshall getsend(name)
2212*30088Sminshall char *name;
2213*30088Sminshall {
2214*30088Sminshall     struct sendlist *sl;
2215*30088Sminshall 
2216*30088Sminshall     if ((sl = (struct sendlist *)
2217*30088Sminshall 			genget(name, (char **) Sendlist, getnextsend)) != 0) {
2218*30088Sminshall 	return sl;
2219*30088Sminshall     } else {
2220*30088Sminshall 	return (struct sendlist *)
2221*30088Sminshall 				genget(name, (char **) Sendlist2, getnextsend);
2222*30088Sminshall     }
2223*30088Sminshall }
2224*30088Sminshall 
2225*30088Sminshall static
2226*30088Sminshall sendcmd(argc, argv)
2227*30088Sminshall int	argc;
2228*30088Sminshall char	**argv;
2229*30088Sminshall {
2230*30088Sminshall     int what;		/* what we are sending this time */
2231*30088Sminshall     int count;		/* how many bytes we are going to need to send */
2232*30088Sminshall     int i;
2233*30088Sminshall     int question = 0;	/* was at least one argument a question */
2234*30088Sminshall     struct sendlist *s;	/* pointer to current command */
2235*30088Sminshall 
2236*30088Sminshall     if (argc < 2) {
2237*30088Sminshall 	printf("need at least one argument for 'send' command\n");
2238*30088Sminshall 	printf("'send ?' for help\n");
2239*30088Sminshall 	return 0;
2240*30088Sminshall     }
2241*30088Sminshall     /*
2242*30088Sminshall      * First, validate all the send arguments.
2243*30088Sminshall      * In addition, we see how much space we are going to need, and
2244*30088Sminshall      * whether or not we will be doing a "SYNCH" operation (which
2245*30088Sminshall      * flushes the network queue).
2246*30088Sminshall      */
2247*30088Sminshall     count = 0;
2248*30088Sminshall     for (i = 1; i < argc; i++) {
2249*30088Sminshall 	s = getsend(argv[i]);
2250*30088Sminshall 	if (s == 0) {
2251*30088Sminshall 	    printf("Unknown send argument '%s'\n'send ?' for help.\n",
2252*30088Sminshall 			argv[i]);
2253*30088Sminshall 	    return 0;
2254*30088Sminshall 	} else if (s == Ambiguous(struct sendlist *)) {
2255*30088Sminshall 	    printf("Ambiguous send argument '%s'\n'send ?' for help.\n",
2256*30088Sminshall 			argv[i]);
2257*30088Sminshall 	    return 0;
2258*30088Sminshall 	}
2259*30088Sminshall 	switch (s->what) {
2260*30088Sminshall 	case SENDQUESTION:
2261*30088Sminshall 	    break;
2262*30088Sminshall 	case SENDESCAPE:
2263*30088Sminshall 	    count += 1;
2264*30088Sminshall 	    break;
2265*30088Sminshall 	case SYNCH:
2266*30088Sminshall 	    count += 2;
2267*30088Sminshall 	    break;
2268*30088Sminshall 	default:
2269*30088Sminshall 	    count += 2;
2270*30088Sminshall 	    break;
2271*30088Sminshall 	}
2272*30088Sminshall     }
2273*30088Sminshall     /* Now, do we have enough room? */
2274*30088Sminshall     if (NETROOM() < count) {
2275*30088Sminshall 	printf("There is not enough room in the buffer TO the network\n");
2276*30088Sminshall 	printf("to process your request.  Nothing will be done.\n");
2277*30088Sminshall 	printf("('send synch' will throw away most data in the network\n");
2278*30088Sminshall 	printf("buffer, if this might help.)\n");
2279*30088Sminshall 	return 0;
2280*30088Sminshall     }
2281*30088Sminshall     /* OK, they are all OK, now go through again and actually send */
2282*30088Sminshall     for (i = 1; i < argc; i++) {
2283*30088Sminshall 	if ((s = getsend(argv[i])) == 0) {
2284*30088Sminshall 	    fprintf(stderr, "Telnet 'send' error - argument disappeared!\n");
2285*30088Sminshall 	    quit();
2286*30088Sminshall 	    /*NOTREACHED*/
2287*30088Sminshall 	}
2288*30088Sminshall 	if (s->routine) {
2289*30088Sminshall 	    (*s->routine)(s);
2290*30088Sminshall 	} else {
2291*30088Sminshall 	    switch (what = s->what) {
2292*30088Sminshall 	    case SYNCH:
2293*30088Sminshall 		dosynch();
2294*30088Sminshall 		break;
2295*30088Sminshall 	    case SENDQUESTION:
2296*30088Sminshall 		for (s = Sendlist; s->name; s++) {
2297*30088Sminshall 		    if (s->help) {
2298*30088Sminshall 			printf(s->name);
2299*30088Sminshall 			if (s->help) {
2300*30088Sminshall 			    printf("\t%s", s->help);
2301*30088Sminshall 			}
2302*30088Sminshall 			printf("\n");
2303*30088Sminshall 		    }
2304*30088Sminshall 		}
2305*30088Sminshall 		question = 1;
2306*30088Sminshall 		break;
2307*30088Sminshall 	    case SENDESCAPE:
2308*30088Sminshall 		NETADD(escape);
2309*30088Sminshall 		break;
2310*30088Sminshall 	    default:
2311*30088Sminshall 		NET2ADD(IAC, what);
2312*30088Sminshall 		break;
2313*30088Sminshall 	    }
2314*30088Sminshall 	}
2315*30088Sminshall     }
2316*30088Sminshall     return !question;
2317*30088Sminshall }
2318*30088Sminshall 
2319*30088Sminshall /*
2320*30088Sminshall  * The following are the routines and data structures referred
2321*30088Sminshall  * to by the arguments to the "toggle" command.
2322*30088Sminshall  */
2323*30088Sminshall 
2324*30088Sminshall static
2325*30088Sminshall lclchars()
2326*30088Sminshall {
2327*30088Sminshall     donelclchars = 1;
2328*30088Sminshall     return 1;
2329*30088Sminshall }
2330*30088Sminshall 
2331*30088Sminshall static
2332*30088Sminshall togdebug()
2333*30088Sminshall {
2334*30088Sminshall #ifndef	NOT43
2335*30088Sminshall     if (net > 0 &&
2336*30088Sminshall 	setsockopt(net, SOL_SOCKET, SO_DEBUG, (char *)&debug, sizeof(debug))
2337*30088Sminshall 									< 0) {
2338*30088Sminshall 	    perror("setsockopt (SO_DEBUG)");
2339*30088Sminshall     }
2340*30088Sminshall #else	NOT43
2341*30088Sminshall     if (debug) {
2342*30088Sminshall 	if (net > 0 && setsockopt(net, SOL_SOCKET, SO_DEBUG, 0, 0) < 0)
2343*30088Sminshall 	    perror("setsockopt (SO_DEBUG)");
2344*30088Sminshall     } else
2345*30088Sminshall 	printf("Cannot turn off socket debugging\n");
2346*30088Sminshall #endif	NOT43
2347*30088Sminshall     return 1;
2348*30088Sminshall }
2349*30088Sminshall 
2350*30088Sminshall 
2351*30088Sminshall 
2352*30088Sminshall extern int togglehelp();
2353*30088Sminshall 
2354*30088Sminshall struct togglelist {
2355*30088Sminshall     char	*name;		/* name of toggle */
2356*30088Sminshall     char	*help;		/* help message */
2357*30088Sminshall     int		(*handler)();	/* routine to do actual setting */
2358*30088Sminshall     int		dohelp;		/* should we display help information */
2359*30088Sminshall     int		*variable;
2360*30088Sminshall     char	*actionexplanation;
2361*30088Sminshall };
2362*30088Sminshall 
2363*30088Sminshall static struct togglelist Togglelist[] = {
2364*30088Sminshall     { "autoflush",
2365*30088Sminshall 	"toggle flushing of output when sending interrupt characters",
2366*30088Sminshall 	    0,
2367*30088Sminshall 		1,
2368*30088Sminshall 		    &autoflush,
2369*30088Sminshall 			"flush output when sending interrupt characters" },
2370*30088Sminshall     { "autosynch",
2371*30088Sminshall 	"toggle automatic sending of interrupt characters in urgent mode",
2372*30088Sminshall 	    0,
2373*30088Sminshall 		1,
2374*30088Sminshall 		    &autosynch,
2375*30088Sminshall 			"send interrupt characters in urgent mode" },
2376*30088Sminshall     { "crmod",
2377*30088Sminshall 	"toggle mapping of received carriage returns",
2378*30088Sminshall 	    0,
2379*30088Sminshall 		1,
2380*30088Sminshall 		    &crmod,
2381*30088Sminshall 			"map carriage return on output" },
2382*30088Sminshall     { "localchars",
2383*30088Sminshall 	"toggle local recognition of certain control characters",
2384*30088Sminshall 	    lclchars,
2385*30088Sminshall 		1,
2386*30088Sminshall 		    &localchars,
2387*30088Sminshall 			"recognize certain control characters" },
2388*30088Sminshall     { " ", "", 0, 1 },		/* empty line */
2389*30088Sminshall     { "debug",
2390*30088Sminshall 	"(debugging) toggle debugging",
2391*30088Sminshall 	    togdebug,
2392*30088Sminshall 		1,
2393*30088Sminshall 		    &debug,
2394*30088Sminshall 			"turn on socket level debugging" },
2395*30088Sminshall     { "netdata",
2396*30088Sminshall 	"(debugging) toggle printing of hexadecimal network data",
2397*30088Sminshall 	    0,
2398*30088Sminshall 		1,
2399*30088Sminshall 		    &netdata,
2400*30088Sminshall 			"print hexadecimal representation of network traffic" },
2401*30088Sminshall     { "options",
2402*30088Sminshall 	"(debugging) toggle viewing of options processing",
2403*30088Sminshall 	    0,
2404*30088Sminshall 		1,
2405*30088Sminshall 		    &showoptions,
2406*30088Sminshall 			"show option processing" },
2407*30088Sminshall     { " ", "", 0, 1 },		/* empty line */
2408*30088Sminshall     { "?",
2409*30088Sminshall 	"display help information",
2410*30088Sminshall 	    togglehelp,
2411*30088Sminshall 		1 },
2412*30088Sminshall     { "help",
2413*30088Sminshall 	"display help information",
2414*30088Sminshall 	    togglehelp,
2415*30088Sminshall 		0 },
2416*30088Sminshall     { 0 }
2417*30088Sminshall };
2418*30088Sminshall 
2419*30088Sminshall static
2420*30088Sminshall togglehelp()
2421*30088Sminshall {
2422*30088Sminshall     struct togglelist *c;
2423*30088Sminshall 
2424*30088Sminshall     for (c = Togglelist; c->name; c++) {
2425*30088Sminshall 	if (c->dohelp) {
2426*30088Sminshall 	    printf("%s\t%s\n", c->name, c->help);
2427*30088Sminshall 	}
2428*30088Sminshall     }
2429*30088Sminshall     return 0;
2430*30088Sminshall }
2431*30088Sminshall 
2432*30088Sminshall static char **
2433*30088Sminshall getnexttoggle(name)
2434*30088Sminshall char *name;
2435*30088Sminshall {
2436*30088Sminshall     struct togglelist *c = (struct togglelist *) name;
2437*30088Sminshall 
2438*30088Sminshall     return (char **) (c+1);
2439*30088Sminshall }
2440*30088Sminshall 
2441*30088Sminshall static struct togglelist *
2442*30088Sminshall gettoggle(name)
2443*30088Sminshall char *name;
2444*30088Sminshall {
2445*30088Sminshall     return (struct togglelist *)
2446*30088Sminshall 			genget(name, (char **) Togglelist, getnexttoggle);
2447*30088Sminshall }
2448*30088Sminshall 
2449*30088Sminshall static
2450*30088Sminshall toggle(argc, argv)
2451*30088Sminshall int	argc;
2452*30088Sminshall char	*argv[];
2453*30088Sminshall {
2454*30088Sminshall     int retval = 1;
2455*30088Sminshall     char *name;
2456*30088Sminshall     struct togglelist *c;
2457*30088Sminshall 
2458*30088Sminshall     if (argc < 2) {
2459*30088Sminshall 	fprintf(stderr,
2460*30088Sminshall 	    "Need an argument to 'toggle' command.  'toggle ?' for help.\n");
2461*30088Sminshall 	return 0;
2462*30088Sminshall     }
2463*30088Sminshall     argc--;
2464*30088Sminshall     argv++;
2465*30088Sminshall     while (argc--) {
2466*30088Sminshall 	name = *argv++;
2467*30088Sminshall 	c = gettoggle(name);
2468*30088Sminshall 	if (c == Ambiguous(struct togglelist *)) {
2469*30088Sminshall 	    fprintf(stderr, "'%s': ambiguous argument ('toggle ?' for help).\n",
2470*30088Sminshall 					name);
2471*30088Sminshall 	    return 0;
2472*30088Sminshall 	} else if (c == 0) {
2473*30088Sminshall 	    fprintf(stderr, "'%s': unknown argument ('toggle ?' for help).\n",
2474*30088Sminshall 					name);
2475*30088Sminshall 	    return 0;
2476*30088Sminshall 	} else {
2477*30088Sminshall 	    if (c->variable) {
2478*30088Sminshall 		*c->variable = !*c->variable;		/* invert it */
2479*30088Sminshall 		printf("%s %s.\n", *c->variable? "Will" : "Won't",
2480*30088Sminshall 							c->actionexplanation);
2481*30088Sminshall 	    }
2482*30088Sminshall 	    if (c->handler) {
2483*30088Sminshall 		retval &= (*c->handler)(c);
2484*30088Sminshall 	    }
2485*30088Sminshall 	}
2486*30088Sminshall     }
2487*30088Sminshall     return retval;
2488*30088Sminshall }
2489*30088Sminshall 
2490*30088Sminshall /*
2491*30088Sminshall  * The following perform the "set" command.
2492*30088Sminshall  */
2493*30088Sminshall 
2494*30088Sminshall struct setlist {
2495*30088Sminshall     char *name;				/* name */
2496*30088Sminshall     char *help;				/* help information */
2497*30088Sminshall     char *charp;			/* where it is located at */
2498*30088Sminshall };
2499*30088Sminshall 
2500*30088Sminshall static struct setlist Setlist[] = {
2501*30088Sminshall     { "echo", 	"character to toggle local echoing on/off", &echoc },
2502*30088Sminshall     { "escape",	"character to escape back to telnet command mode", &escape },
2503*30088Sminshall     { " ", "" },
2504*30088Sminshall     { " ", "The following need 'localchars' to be toggled true", 0 },
2505*30088Sminshall     { "erase",	"character to cause an Erase Character", &nttyb.sg_erase },
2506*30088Sminshall     { "flushoutput", "character to cause an Abort Oubput", &nltc.t_flushc },
2507*30088Sminshall     { "interrupt", "character to cause an Interrupt Process", &ntc.t_intrc },
2508*30088Sminshall     { "kill",	"character to cause an Erase Line", &nttyb.sg_kill },
2509*30088Sminshall     { "quit",	"character to cause a Break", &ntc.t_quitc },
2510*30088Sminshall     { "eof",	"character to cause an EOF ", &ntc.t_eofc },
2511*30088Sminshall     { 0 }
2512*30088Sminshall };
2513*30088Sminshall 
2514*30088Sminshall static char **
2515*30088Sminshall getnextset(name)
2516*30088Sminshall char *name;
2517*30088Sminshall {
2518*30088Sminshall     struct setlist *c = (struct setlist *)name;
2519*30088Sminshall 
2520*30088Sminshall     return (char **) (c+1);
2521*30088Sminshall }
2522*30088Sminshall 
2523*30088Sminshall static struct setlist *
2524*30088Sminshall getset(name)
2525*30088Sminshall char *name;
2526*30088Sminshall {
2527*30088Sminshall     return (struct setlist *) genget(name, (char **) Setlist, getnextset);
2528*30088Sminshall }
2529*30088Sminshall 
2530*30088Sminshall static
2531*30088Sminshall setcmd(argc, argv)
2532*30088Sminshall int	argc;
2533*30088Sminshall char	*argv[];
2534*30088Sminshall {
2535*30088Sminshall     int value;
2536*30088Sminshall     struct setlist *ct;
2537*30088Sminshall 
2538*30088Sminshall     /* XXX back we go... sigh */
2539*30088Sminshall     if (argc != 3) {
2540*30088Sminshall 	if ((argc == 2) &&
2541*30088Sminshall 		    ((!strcmp(argv[1], "?")) || (!strcmp(argv[1], "help")))) {
2542*30088Sminshall 	    for (ct = Setlist; ct->name; ct++) {
2543*30088Sminshall 		printf("%s\t%s\n", ct->name, ct->help);
2544*30088Sminshall 	    }
2545*30088Sminshall 	    printf("?\tdisplay help information\n");
2546*30088Sminshall 	} else {
2547*30088Sminshall 	    printf("Format is 'set Name Value'\n'set ?' for help.\n");
2548*30088Sminshall 	}
2549*30088Sminshall 	return 0;
2550*30088Sminshall     }
2551*30088Sminshall 
2552*30088Sminshall     ct = getset(argv[1]);
2553*30088Sminshall     if (ct == 0) {
2554*30088Sminshall 	fprintf(stderr, "'%s': unknown argument ('set ?' for help).\n",
2555*30088Sminshall 			argv[1]);
2556*30088Sminshall 	return 0;
2557*30088Sminshall     } else if (ct == Ambiguous(struct setlist *)) {
2558*30088Sminshall 	fprintf(stderr, "'%s': ambiguous argument ('set ?' for help).\n",
2559*30088Sminshall 			argv[1]);
2560*30088Sminshall 	return 0;
2561*30088Sminshall     } else {
2562*30088Sminshall 	if (strcmp("off", argv[2])) {
2563*30088Sminshall 	    value = special(argv[2]);
2564*30088Sminshall 	} else {
2565*30088Sminshall 	    value = -1;
2566*30088Sminshall 	}
2567*30088Sminshall 	*(ct->charp) = value;
2568*30088Sminshall 	printf("%s character is '%s'.\n", ct->name, control(*(ct->charp)));
2569*30088Sminshall     }
2570*30088Sminshall     return 1;
2571*30088Sminshall }
2572*30088Sminshall 
2573*30088Sminshall /*
2574*30088Sminshall  * The following are the data structures and routines for the
2575*30088Sminshall  * 'mode' command.
2576*30088Sminshall  */
2577*30088Sminshall 
2578*30088Sminshall static
2579*30088Sminshall dolinemode()
2580*30088Sminshall {
2581*30088Sminshall     if (hisopts[TELOPT_SGA]) {
2582*30088Sminshall 	wontoption(TELOPT_SGA, 0);
2583*30088Sminshall     }
2584*30088Sminshall     if (hisopts[TELOPT_ECHO]) {
2585*30088Sminshall 	wontoption(TELOPT_ECHO, 0);
2586*30088Sminshall     }
2587*30088Sminshall     return 1;
2588*30088Sminshall }
2589*30088Sminshall 
2590*30088Sminshall static
2591*30088Sminshall docharmode()
2592*30088Sminshall {
2593*30088Sminshall     if (!hisopts[TELOPT_SGA]) {
2594*30088Sminshall 	willoption(TELOPT_SGA, 0);
2595*30088Sminshall     }
2596*30088Sminshall     if (!hisopts[TELOPT_ECHO]) {
2597*30088Sminshall 	willoption(TELOPT_ECHO, 0);
2598*30088Sminshall     }
2599*30088Sminshall     return 1;
2600*30088Sminshall }
2601*30088Sminshall 
2602*30088Sminshall static struct cmd Modelist[] = {
2603*30088Sminshall     { "character",	"character-at-a-time mode",	docharmode, 1, 1 },
2604*30088Sminshall     { "line",		"line-by-line mode",		dolinemode, 1, 1 },
2605*30088Sminshall     { 0 },
2606*30088Sminshall };
2607*30088Sminshall 
2608*30088Sminshall static char **
2609*30088Sminshall getnextmode(name)
2610*30088Sminshall char *name;
2611*30088Sminshall {
2612*30088Sminshall     struct cmd *c = (struct cmd *) name;
2613*30088Sminshall 
2614*30088Sminshall     return (char **) (c+1);
2615*30088Sminshall }
2616*30088Sminshall 
2617*30088Sminshall static struct cmd *
2618*30088Sminshall getmodecmd(name)
2619*30088Sminshall char *name;
2620*30088Sminshall {
2621*30088Sminshall     return (struct cmd *) genget(name, (char **) Modelist, getnextmode);
2622*30088Sminshall }
2623*30088Sminshall 
2624*30088Sminshall static
2625*30088Sminshall modecmd(argc, argv)
2626*30088Sminshall int	argc;
2627*30088Sminshall char	*argv[];
2628*30088Sminshall {
2629*30088Sminshall     struct cmd *mt;
2630*30088Sminshall 
2631*30088Sminshall     if ((argc != 2) || !strcmp(argv[1], "?") || !strcmp(argv[1], "help")) {
2632*30088Sminshall 	printf("format is:  'mode Mode', where 'Mode' is one of:\n\n");
2633*30088Sminshall 	for (mt = Modelist; mt->name; mt++) {
2634*30088Sminshall 	    printf("%s\t%s\n", mt->name, mt->help);
2635*30088Sminshall 	}
2636*30088Sminshall 	return 0;
2637*30088Sminshall     }
2638*30088Sminshall     mt = getmodecmd(argv[1]);
2639*30088Sminshall     if (mt == 0) {
2640*30088Sminshall 	fprintf(stderr, "Unknown mode '%s' ('mode ?' for help).\n", argv[1]);
2641*30088Sminshall 	return 0;
2642*30088Sminshall     } else if (mt == Ambiguous(struct cmd *)) {
2643*30088Sminshall 	fprintf(stderr, "Ambiguous mode '%s' ('mode ?' for help).\n", argv[1]);
2644*30088Sminshall 	return 0;
2645*30088Sminshall     } else {
2646*30088Sminshall 	(*mt->handler)();
2647*30088Sminshall     }
2648*30088Sminshall     return 1;
2649*30088Sminshall }
2650*30088Sminshall 
2651*30088Sminshall /*
2652*30088Sminshall  * The following data structures and routines implement the
2653*30088Sminshall  * "display" command.
2654*30088Sminshall  */
2655*30088Sminshall 
2656*30088Sminshall static
2657*30088Sminshall display(argc, argv)
2658*30088Sminshall int	argc;
2659*30088Sminshall char	*argv[];
2660*30088Sminshall {
2661*30088Sminshall #define	dotog(tl)	if (tl->variable && tl->actionexplanation) { \
2662*30088Sminshall 			    if (*tl->variable) { \
2663*30088Sminshall 				printf("will"); \
2664*30088Sminshall 			    } else { \
2665*30088Sminshall 				printf("won't"); \
2666*30088Sminshall 			    } \
2667*30088Sminshall 			    printf(" %s.\n", tl->actionexplanation); \
2668*30088Sminshall 			}
2669*30088Sminshall 
2670*30088Sminshall #define	doset(sl)   if (sl->name && *sl->name != ' ') { \
2671*30088Sminshall 			printf("[%s]\t%s.\n", control(*sl->charp), sl->name); \
2672*30088Sminshall 		    }
2673*30088Sminshall 
2674*30088Sminshall     struct togglelist *tl;
2675*30088Sminshall     struct setlist *sl;
2676*30088Sminshall 
2677*30088Sminshall     if (argc == 1) {
2678*30088Sminshall 	for (tl = Togglelist; tl->name; tl++) {
2679*30088Sminshall 	    dotog(tl);
2680*30088Sminshall 	}
2681*30088Sminshall 	printf("\n");
2682*30088Sminshall 	for (sl = Setlist; sl->name; sl++) {
2683*30088Sminshall 	    doset(sl);
2684*30088Sminshall 	}
2685*30088Sminshall     } else {
2686*30088Sminshall 	int i;
2687*30088Sminshall 
2688*30088Sminshall 	for (i = 1; i < argc; i++) {
2689*30088Sminshall 	    sl = getset(argv[i]);
2690*30088Sminshall 	    tl = gettoggle(argv[i]);
2691*30088Sminshall 	    if ((sl == Ambiguous(struct setlist *)) ||
2692*30088Sminshall 				(tl == Ambiguous(struct togglelist *))) {
2693*30088Sminshall 		printf("?Ambiguous argument '%s'.\n", argv[i]);
2694*30088Sminshall 		return 0;
2695*30088Sminshall 	    } else if (!sl && !tl) {
2696*30088Sminshall 		printf("?Unknown argument '%s'.\n", argv[i]);
2697*30088Sminshall 		return 0;
2698*30088Sminshall 	    } else {
2699*30088Sminshall 		if (tl) {
2700*30088Sminshall 		    dotog(tl);
2701*30088Sminshall 		}
2702*30088Sminshall 		if (sl) {
2703*30088Sminshall 		    doset(sl);
2704*30088Sminshall 		}
2705*30088Sminshall 	    }
2706*30088Sminshall 	}
2707*30088Sminshall     }
2708*30088Sminshall     return 1;
2709*30088Sminshall #undef	doset
2710*30088Sminshall #undef	dotog
2711*30088Sminshall }
2712*30088Sminshall 
2713*30088Sminshall /*
2714*30088Sminshall  * The following are the data structures, and many of the routines,
2715*30088Sminshall  * relating to command processing.
2716*30088Sminshall  */
2717*30088Sminshall 
2718*30088Sminshall /*
2719*30088Sminshall  * Set the escape character.
2720*30088Sminshall  */
2721*30088Sminshall static
2722*30088Sminshall setescape(argc, argv)
2723*30088Sminshall 	int argc;
2724*30088Sminshall 	char *argv[];
2725*30088Sminshall {
2726*30088Sminshall 	register char *arg;
2727*30088Sminshall 	char buf[50];
2728*30088Sminshall 
2729*30088Sminshall 	printf(
2730*30088Sminshall 	    "Deprecated usage - please use 'set escape%s%s' in the future.\n",
2731*30088Sminshall 				(argc > 2)? " ":"", (argc > 2)? argv[1]: "");
2732*30088Sminshall 	if (argc > 2)
2733*30088Sminshall 		arg = argv[1];
2734*30088Sminshall 	else {
2735*30088Sminshall 		printf("new escape character: ");
2736*30088Sminshall 		gets(buf);
2737*30088Sminshall 		arg = buf;
2738*30088Sminshall 	}
2739*30088Sminshall 	if (arg[0] != '\0')
2740*30088Sminshall 		escape = arg[0];
2741*30088Sminshall 	if (!In3270) {
2742*30088Sminshall 		printf("Escape character is '%s'.\n", control(escape));
2743*30088Sminshall 	}
2744*30088Sminshall 	fflush(stdout);
2745*30088Sminshall 	return 1;
2746*30088Sminshall }
2747*30088Sminshall 
2748*30088Sminshall /*VARARGS*/
2749*30088Sminshall static
2750*30088Sminshall togcrmod()
2751*30088Sminshall {
2752*30088Sminshall     crmod = !crmod;
2753*30088Sminshall     printf("Deprecated usage - please use 'toggle crmod' in the future.\n");
2754*30088Sminshall     printf("%s map carriage return on output.\n", crmod ? "Will" : "Won't");
2755*30088Sminshall     fflush(stdout);
2756*30088Sminshall     return 1;
2757*30088Sminshall }
2758*30088Sminshall 
2759*30088Sminshall /*VARARGS*/
2760*30088Sminshall suspend()
2761*30088Sminshall {
2762*30088Sminshall 	setcommandmode();
2763*30088Sminshall #if	defined(unix)
2764*30088Sminshall 	kill(0, SIGTSTP);
2765*30088Sminshall #endif	/* defined(unix) */
2766*30088Sminshall 	/* reget parameters in case they were changed */
2767*30088Sminshall 	ioctl(0, TIOCGETP, (char *)&ottyb);
2768*30088Sminshall 	ioctl(0, TIOCGETC, (char *)&otc);
2769*30088Sminshall 	ioctl(0, TIOCGLTC, (char *)&oltc);
2770*30088Sminshall 	return 1;
2771*30088Sminshall }
2772*30088Sminshall 
2773*30088Sminshall /*VARARGS*/
2774*30088Sminshall static
2775*30088Sminshall bye()
2776*30088Sminshall {
2777*30088Sminshall     if (connected) {
2778*30088Sminshall 	shutdown(net, 2);
2779*30088Sminshall 	printf("Connection closed.\n");
2780*30088Sminshall 	close(net);
2781*30088Sminshall 	connected = 0;
2782*30088Sminshall 	/* reset options */
2783*30088Sminshall 	bzero((char *)hisopts, sizeof hisopts);
2784*30088Sminshall 	bzero((char *)myopts, sizeof myopts);
2785*30088Sminshall 	SYNCHing = flushout = 0;
2786*30088Sminshall 	flushline = 1;
2787*30088Sminshall #if	defined(TN3270)
2788*30088Sminshall 		/*
2789*30088Sminshall 		 * The problem is that we were called from command() which
2790*30088Sminshall 		 * was called from DataFrom3270() which was called from
2791*30088Sminshall 		 * DataFromTerminal() which was called from...
2792*30088Sminshall 		 *
2793*30088Sminshall 		 * So, just quit.
2794*30088Sminshall 		 */
2795*30088Sminshall 	if (In3270) {
2796*30088Sminshall 	    Exit(0);
2797*30088Sminshall 	}
2798*30088Sminshall #endif	/* defined(TN3270) */
2799*30088Sminshall     }
2800*30088Sminshall     return 1;
2801*30088Sminshall }
2802*30088Sminshall 
2803*30088Sminshall /*VARARGS*/
2804*30088Sminshall quit()
2805*30088Sminshall {
2806*30088Sminshall 	(void) call(bye, "bye", 0);
2807*30088Sminshall 	Exit(0);
2808*30088Sminshall 	/*NOTREACHED*/
2809*30088Sminshall 	return 1;			/* just to keep lint happy */
2810*30088Sminshall }
2811*30088Sminshall 
2812*30088Sminshall /*
2813*30088Sminshall  * Print status about the connection.
2814*30088Sminshall  */
2815*30088Sminshall static
2816*30088Sminshall status(argc, argv)
2817*30088Sminshall int	argc;
2818*30088Sminshall char	*argv[];
2819*30088Sminshall {
2820*30088Sminshall     if (connected) {
2821*30088Sminshall 	printf("Connected to %s.\n", hostname);
2822*30088Sminshall 	if (argc < 2) {
2823*30088Sminshall 	    printf("Operating in %s.\n",
2824*30088Sminshall 				modelist[getconnmode()].modedescriptions);
2825*30088Sminshall 	    if (localchars) {
2826*30088Sminshall 		printf("Catching signals locally.\n");
2827*30088Sminshall 	    }
2828*30088Sminshall 	}
2829*30088Sminshall     } else {
2830*30088Sminshall 	printf("No connection.\n");
2831*30088Sminshall     }
2832*30088Sminshall #   if !defined(TN3270)
2833*30088Sminshall     printf("Escape character is '%s'.\n", control(escape));
2834*30088Sminshall     fflush(stdout);
2835*30088Sminshall #   else /* !defined(TN3270) */
2836*30088Sminshall     if ((!In3270) && ((argc < 2) || strcmp(argv[1], "notmuch"))) {
2837*30088Sminshall 	printf("Escape character is '%s'.\n", control(escape));
2838*30088Sminshall     }
2839*30088Sminshall #   if defined(unix)
2840*30088Sminshall     if (In3270 && transcom) {
2841*30088Sminshall        printf("Transparent mode command is '%s'.\n", transcom);
2842*30088Sminshall     }
2843*30088Sminshall #   endif /* defined(unix) */
2844*30088Sminshall     fflush(stdout);
2845*30088Sminshall     if (In3270) {
2846*30088Sminshall 	return 0;
2847*30088Sminshall     }
2848*30088Sminshall #   endif /* defined(TN3270) */
2849*30088Sminshall     return 1;
2850*30088Sminshall }
2851*30088Sminshall 
2852*30088Sminshall #if	defined(TN3270) && defined(unix)
2853*30088Sminshall static
2854*30088Sminshall settranscom(argc, argv)
2855*30088Sminshall 	int argc;
2856*30088Sminshall 	char *argv[];
2857*30088Sminshall {
2858*30088Sminshall 	int i, len = 0;
2859*30088Sminshall 	char *strcpy(), *strcat();
2860*30088Sminshall 
2861*30088Sminshall 	if (argc == 1 && transcom) {
2862*30088Sminshall 	   transcom = 0;
2863*30088Sminshall 	}
2864*30088Sminshall 	if (argc == 1) {
2865*30088Sminshall 	   return;
2866*30088Sminshall 	}
2867*30088Sminshall 	for (i = 1; i < argc; ++i) {
2868*30088Sminshall 	    len += 1 + strlen(argv[1]);
2869*30088Sminshall 	}
2870*30088Sminshall 	transcom = tline;
2871*30088Sminshall 	(void) strcpy(transcom, argv[1]);
2872*30088Sminshall 	for (i = 2; i < argc; ++i) {
2873*30088Sminshall 	    (void) strcat(transcom, " ");
2874*30088Sminshall 	    (void) strcat(transcom, argv[i]);
2875*30088Sminshall 	}
2876*30088Sminshall }
2877*30088Sminshall #endif	/* defined(TN3270) && defined(unix) */
2878*30088Sminshall 
2879*30088Sminshall 
2880*30088Sminshall static
2881*30088Sminshall tn(argc, argv)
2882*30088Sminshall 	int argc;
2883*30088Sminshall 	char *argv[];
2884*30088Sminshall {
2885*30088Sminshall     register struct hostent *host = 0;
2886*30088Sminshall #if defined(msdos)
2887*30088Sminshall     char *cp;
2888*30088Sminshall #endif /* defined(msdos) */
2889*30088Sminshall 
2890*30088Sminshall     if (connected) {
2891*30088Sminshall 	printf("?Already connected to %s\n", hostname);
2892*30088Sminshall 	return 0;
2893*30088Sminshall     }
2894*30088Sminshall     if (argc < 2) {
2895*30088Sminshall 	(void) strcpy(line, "Connect ");
2896*30088Sminshall 	printf("(to) ");
2897*30088Sminshall 	gets(&line[strlen(line)]);
2898*30088Sminshall 	makeargv();
2899*30088Sminshall 	argc = margc;
2900*30088Sminshall 	argv = margv;
2901*30088Sminshall     }
2902*30088Sminshall     if (argc > 3) {
2903*30088Sminshall 	printf("usage: %s host-name [port]\n", argv[0]);
2904*30088Sminshall 	return 0;
2905*30088Sminshall     }
2906*30088Sminshall #if	defined(msdos)
2907*30088Sminshall     for (cp = argv[1]; *cp; cp++) {
2908*30088Sminshall 	if (isupper(*cp)) {
2909*30088Sminshall 	    *cp = tolower(*cp);
2910*30088Sminshall 	}
2911*30088Sminshall     }
2912*30088Sminshall #endif	/* defined(msdos) */
2913*30088Sminshall     sin.sin_addr.s_addr = inet_addr(argv[1]);
2914*30088Sminshall     if (sin.sin_addr.s_addr != -1) {
2915*30088Sminshall 	sin.sin_family = AF_INET;
2916*30088Sminshall 	(void) strcpy(hnamebuf, argv[1]);
2917*30088Sminshall 	hostname = hnamebuf;
2918*30088Sminshall     } else {
2919*30088Sminshall 	host = gethostbyname(argv[1]);
2920*30088Sminshall 	if (host) {
2921*30088Sminshall 	    sin.sin_family = host->h_addrtype;
2922*30088Sminshall #if	defined(h_addr)		/* In 4.3, this is a #define */
2923*30088Sminshall 	    bcopy(host->h_addr_list[0], (caddr_t)&sin.sin_addr, host->h_length);
2924*30088Sminshall #else	/* defined(h_addr) */
2925*30088Sminshall 	    bcopy(host->h_addr, (caddr_t)&sin.sin_addr, host->h_length);
2926*30088Sminshall #endif	/* defined(h_addr) */
2927*30088Sminshall 	    hostname = host->h_name;
2928*30088Sminshall 	} else {
2929*30088Sminshall 	    printf("%s: unknown host\n", argv[1]);
2930*30088Sminshall 	    return 0;
2931*30088Sminshall 	}
2932*30088Sminshall     }
2933*30088Sminshall     sin.sin_port = sp->s_port;
2934*30088Sminshall     if (argc == 3) {
2935*30088Sminshall 	sin.sin_port = atoi(argv[2]);
2936*30088Sminshall 	if (sin.sin_port == 0) {
2937*30088Sminshall 	    sp = getservbyname(argv[2], "tcp");
2938*30088Sminshall 	    if (sp)
2939*30088Sminshall 		sin.sin_port = sp->s_port;
2940*30088Sminshall 	    else {
2941*30088Sminshall 		printf("%s: bad port number\n", argv[2]);
2942*30088Sminshall 		return 0;
2943*30088Sminshall 	    }
2944*30088Sminshall 	} else {
2945*30088Sminshall 	    sin.sin_port = atoi(argv[2]);
2946*30088Sminshall 	    sin.sin_port = htons(sin.sin_port);
2947*30088Sminshall 	}
2948*30088Sminshall 	telnetport = 0;
2949*30088Sminshall     } else {
2950*30088Sminshall 	telnetport = 1;
2951*30088Sminshall     }
2952*30088Sminshall #if	defined(unix)
2953*30088Sminshall     signal(SIGINT, intr);
2954*30088Sminshall     signal(SIGQUIT, intr2);
2955*30088Sminshall     signal(SIGPIPE, deadpeer);
2956*30088Sminshall #endif	/* defined(unix) */
2957*30088Sminshall     printf("Trying...\n");
2958*30088Sminshall     do {
2959*30088Sminshall 	net = socket(AF_INET, SOCK_STREAM, 0);
2960*30088Sminshall 	if (net < 0) {
2961*30088Sminshall 	    perror("telnet: socket");
2962*30088Sminshall 	    return 0;
2963*30088Sminshall 	}
2964*30088Sminshall #ifndef	NOT43
2965*30088Sminshall 	if (debug && setsockopt(net, SOL_SOCKET, SO_DEBUG,
2966*30088Sminshall 				(char *)&debug, sizeof(debug)) < 0)
2967*30088Sminshall #else	NOT43
2968*30088Sminshall 	if (debug && setsockopt(net, SOL_SOCKET, SO_DEBUG, 0, 0) < 0)
2969*30088Sminshall #endif	NOT43
2970*30088Sminshall 		perror("setsockopt (SO_DEBUG)");
2971*30088Sminshall 
2972*30088Sminshall 	if (connect(net, (struct sockaddr *)&sin, sizeof (sin)) < 0) {
2973*30088Sminshall #if	defined(h_addr)		/* In 4.3, this is a #define */
2974*30088Sminshall 	    if (host && host->h_addr_list[1]) {
2975*30088Sminshall 		int oerrno = errno;
2976*30088Sminshall 
2977*30088Sminshall 		fprintf(stderr, "telnet: connect to address %s: ",
2978*30088Sminshall 						inet_ntoa(sin.sin_addr));
2979*30088Sminshall 		errno = oerrno;
2980*30088Sminshall 		perror((char *)0);
2981*30088Sminshall 		host->h_addr_list++;
2982*30088Sminshall 		bcopy(host->h_addr_list[0],
2983*30088Sminshall 		    (caddr_t)&sin.sin_addr, host->h_length);
2984*30088Sminshall 		fprintf(stderr, "Trying %s...\n",
2985*30088Sminshall 			inet_ntoa(sin.sin_addr));
2986*30088Sminshall 		(void) close(net);
2987*30088Sminshall 		continue;
2988*30088Sminshall 	    }
2989*30088Sminshall #endif	/* defined(h_addr) */
2990*30088Sminshall 	    perror("telnet: Unable to connect to remote host");
2991*30088Sminshall #if defined(unix)
2992*30088Sminshall 	    signal(SIGINT, SIG_DFL);
2993*30088Sminshall 	    signal(SIGQUIT, SIG_DFL);
2994*30088Sminshall #endif /* defined(unix) */
2995*30088Sminshall 	    return 0;
2996*30088Sminshall 	    }
2997*30088Sminshall 	connected++;
2998*30088Sminshall     } while (connected == 0);
2999*30088Sminshall     call(status, "status", "notmuch", 0);
3000*30088Sminshall     if (setjmp(peerdied) == 0)
3001*30088Sminshall 	telnet();
3002*30088Sminshall     ExitString(stderr, "Connection closed by foreign host.\n",1);
3003*30088Sminshall     /*NOTREACHED*/
3004*30088Sminshall }
3005*30088Sminshall 
3006*30088Sminshall 
3007*30088Sminshall #define HELPINDENT (sizeof ("connect"))
3008*30088Sminshall 
3009*30088Sminshall static char
3010*30088Sminshall 	openhelp[] =	"connect to a site",
3011*30088Sminshall 	closehelp[] =	"close current connection",
3012*30088Sminshall 	quithelp[] =	"exit telnet",
3013*30088Sminshall 	zhelp[] =	"suspend telnet",
3014*30088Sminshall 	statushelp[] =	"print status information",
3015*30088Sminshall 	helphelp[] =	"print help information",
3016*30088Sminshall 	sendhelp[] =	"transmit special characters ('send ?' for more)",
3017*30088Sminshall 	sethelp[] = 	"set operating parameters ('set ?' for more)",
3018*30088Sminshall 	togglestring[] ="toggle operating parameters ('toggle ?' for more)",
3019*30088Sminshall 	displayhelp[] =	"display operating parameters",
3020*30088Sminshall #if	defined(TN3270) && defined(unix)
3021*30088Sminshall 	transcomhelp[] = "specify Unix command for transparent mode pipe",
3022*30088Sminshall #endif	/* defined(TN3270) && defined(unix) */
3023*30088Sminshall 	modehelp[] = "try to enter line-by-line or character-at-a-time mode";
3024*30088Sminshall 
3025*30088Sminshall extern int	help();
3026*30088Sminshall 
3027*30088Sminshall static struct cmd cmdtab[] = {
3028*30088Sminshall 	{ "close",	closehelp,	bye,		1, 1 },
3029*30088Sminshall 	{ "display",	displayhelp,	display,	1, 0 },
3030*30088Sminshall 	{ "mode",	modehelp,	modecmd,	1, 1 },
3031*30088Sminshall 	{ "open",	openhelp,	tn,		1, 0 },
3032*30088Sminshall 	{ "quit",	quithelp,	quit,		1, 0 },
3033*30088Sminshall 	{ "send",	sendhelp,	sendcmd,	1, 1 },
3034*30088Sminshall 	{ "set",	sethelp,	setcmd,		1, 0 },
3035*30088Sminshall 	{ "status",	statushelp,	status,		1, 0 },
3036*30088Sminshall 	{ "toggle",	togglestring,	toggle,		1, 0 },
3037*30088Sminshall #if	defined(TN3270) && defined(unix)
3038*30088Sminshall 	{ "transcom",	transcomhelp,	settranscom,	1, 0 },
3039*30088Sminshall #endif	/* defined(TN3270) && defined(unix) */
3040*30088Sminshall 	{ "z",		zhelp,		suspend,	1, 0 },
3041*30088Sminshall 	{ "?",		helphelp,	help,		1, 0 },
3042*30088Sminshall 	0
3043*30088Sminshall };
3044*30088Sminshall 
3045*30088Sminshall static char	crmodhelp[] =	"deprecated command -- use 'toggle crmod' instead";
3046*30088Sminshall static char	escapehelp[] =	"deprecated command -- use 'set escape' instead";
3047*30088Sminshall 
3048*30088Sminshall static struct cmd cmdtab2[] = {
3049*30088Sminshall 	{ "help",	helphelp,	help,		0, 0 },
3050*30088Sminshall 	{ "escape",	escapehelp,	setescape,	1, 0 },
3051*30088Sminshall 	{ "crmod",	crmodhelp,	togcrmod,	1, 0 },
3052*30088Sminshall 	0
3053*30088Sminshall };
3054*30088Sminshall 
3055*30088Sminshall /*
3056*30088Sminshall  * Call routine with argc, argv set from args (terminated by 0).
3057*30088Sminshall  * VARARGS2
3058*30088Sminshall  */
3059*30088Sminshall static
3060*30088Sminshall call(routine, args)
3061*30088Sminshall 	int (*routine)();
3062*30088Sminshall 	char *args;
3063*30088Sminshall {
3064*30088Sminshall 	register char **argp;
3065*30088Sminshall 	register int argc;
3066*30088Sminshall 
3067*30088Sminshall 	for (argc = 0, argp = &args; *argp++ != 0; argc++)
3068*30088Sminshall 		;
3069*30088Sminshall 	return (*routine)(argc, &args);
3070*30088Sminshall }
3071*30088Sminshall 
3072*30088Sminshall static char **
3073*30088Sminshall getnextcmd(name)
3074*30088Sminshall char *name;
3075*30088Sminshall {
3076*30088Sminshall     struct cmd *c = (struct cmd *) name;
3077*30088Sminshall 
3078*30088Sminshall     return (char **) (c+1);
3079*30088Sminshall }
3080*30088Sminshall 
3081*30088Sminshall static struct cmd *
3082*30088Sminshall getcmd(name)
3083*30088Sminshall char *name;
3084*30088Sminshall {
3085*30088Sminshall     struct cmd *cm;
3086*30088Sminshall 
3087*30088Sminshall     if ((cm = (struct cmd *) genget(name, (char **) cmdtab, getnextcmd)) != 0) {
3088*30088Sminshall 	return cm;
3089*30088Sminshall     } else {
3090*30088Sminshall 	return (struct cmd *) genget(name, (char **) cmdtab2, getnextcmd);
3091*30088Sminshall     }
3092*30088Sminshall }
3093*30088Sminshall 
3094*30088Sminshall void
3095*30088Sminshall command(top)
3096*30088Sminshall 	int top;
3097*30088Sminshall {
3098*30088Sminshall 	register struct cmd *c;
3099*30088Sminshall 
3100*30088Sminshall 	setcommandmode();
3101*30088Sminshall 	if (!top) {
3102*30088Sminshall 		putchar('\n');
3103*30088Sminshall 	} else {
3104*30088Sminshall #if	defined(unix)
3105*30088Sminshall 		signal(SIGINT, SIG_DFL);
3106*30088Sminshall 		signal(SIGQUIT, SIG_DFL);
3107*30088Sminshall #endif	/* defined(unix) */
3108*30088Sminshall 	}
3109*30088Sminshall 	for (;;) {
3110*30088Sminshall 		printf("%s> ", prompt);
3111*30088Sminshall 		if (gets(line) == NULL) {
3112*30088Sminshall 			if (feof(stdin) || ferror(stdin))
3113*30088Sminshall 				quit();
3114*30088Sminshall 			break;
3115*30088Sminshall 		}
3116*30088Sminshall 		if (line[0] == 0)
3117*30088Sminshall 			break;
3118*30088Sminshall 		makeargv();
3119*30088Sminshall 		c = getcmd(margv[0]);
3120*30088Sminshall 		if (c == Ambiguous(struct cmd *)) {
3121*30088Sminshall 			printf("?Ambiguous command\n");
3122*30088Sminshall 			continue;
3123*30088Sminshall 		}
3124*30088Sminshall 		if (c == 0) {
3125*30088Sminshall 			printf("?Invalid command\n");
3126*30088Sminshall 			continue;
3127*30088Sminshall 		}
3128*30088Sminshall 		if (c->needconnect && !connected) {
3129*30088Sminshall 			printf("?Need to be connected first.\n");
3130*30088Sminshall 			continue;
3131*30088Sminshall 		}
3132*30088Sminshall 		if ((*c->handler)(margc, margv)) {
3133*30088Sminshall 			break;
3134*30088Sminshall 		}
3135*30088Sminshall 	}
3136*30088Sminshall 	if (!top) {
3137*30088Sminshall 		if (!connected) {
3138*30088Sminshall 			longjmp(toplevel, 1);
3139*30088Sminshall 			/*NOTREACHED*/
3140*30088Sminshall 		}
3141*30088Sminshall 		setconnmode();
3142*30088Sminshall 	}
3143*30088Sminshall }
3144*30088Sminshall 
3145*30088Sminshall /*
3146*30088Sminshall  * Help command.
3147*30088Sminshall  */
3148*30088Sminshall static
3149*30088Sminshall help(argc, argv)
3150*30088Sminshall 	int argc;
3151*30088Sminshall 	char *argv[];
3152*30088Sminshall {
3153*30088Sminshall 	register struct cmd *c;
3154*30088Sminshall 
3155*30088Sminshall 	if (argc == 1) {
3156*30088Sminshall 		printf("Commands may be abbreviated.  Commands are:\n\n");
3157*30088Sminshall 		for (c = cmdtab; c->name; c++)
3158*30088Sminshall 			if (c->dohelp) {
3159*30088Sminshall 				printf("%-*s\t%s\n", HELPINDENT, c->name,
3160*30088Sminshall 								    c->help);
3161*30088Sminshall 			}
3162*30088Sminshall 		return 0;
3163*30088Sminshall 	}
3164*30088Sminshall 	while (--argc > 0) {
3165*30088Sminshall 		register char *arg;
3166*30088Sminshall 		arg = *++argv;
3167*30088Sminshall 		c = getcmd(arg);
3168*30088Sminshall 		if (c == Ambiguous(struct cmd *))
3169*30088Sminshall 			printf("?Ambiguous help command %s\n", arg);
3170*30088Sminshall 		else if (c == (struct cmd *)0)
3171*30088Sminshall 			printf("?Invalid help command %s\n", arg);
3172*30088Sminshall 		else
3173*30088Sminshall 			printf("%s\n", c->help);
3174*30088Sminshall 	}
3175*30088Sminshall 	return 0;
3176*30088Sminshall }
3177*30088Sminshall 
3178*30088Sminshall /*
3179*30088Sminshall  * main.  Parse arguments, invoke the protocol or command parser.
3180*30088Sminshall  */
3181*30088Sminshall 
3182*30088Sminshall 
3183*30088Sminshall void
3184*30088Sminshall main(argc, argv)
3185*30088Sminshall 	int argc;
3186*30088Sminshall 	char *argv[];
3187*30088Sminshall {
3188*30088Sminshall     sp = getservbyname("telnet", "tcp");
3189*30088Sminshall     if (sp == 0) {
3190*30088Sminshall 	ExitString(stderr, "telnet: tcp/telnet: unknown service\n",1);
3191*30088Sminshall 	/*NOTREACHED*/
3192*30088Sminshall     }
3193*30088Sminshall     NetTrace = stdout;
3194*30088Sminshall     ioctl(0, TIOCGETP, (char *)&ottyb);
3195*30088Sminshall     ioctl(0, TIOCGETC, (char *)&otc);
3196*30088Sminshall     ioctl(0, TIOCGLTC, (char *)&oltc);
3197*30088Sminshall #if	defined(LNOFLSH)
3198*30088Sminshall     ioctl(0, TIOCLGET, (char *)&autoflush);
3199*30088Sminshall     autoflush = !(autoflush&LNOFLSH);	/* if LNOFLSH, no autoflush */
3200*30088Sminshall #else	/* LNOFLSH */
3201*30088Sminshall     autoflush = 1;
3202*30088Sminshall #endif	/* LNOFLSH */
3203*30088Sminshall     ntc = otc;
3204*30088Sminshall     nltc = oltc;
3205*30088Sminshall     nttyb = ottyb;
3206*30088Sminshall     setbuf(stdin, (char *)0);
3207*30088Sminshall     setbuf(stdout, (char *)0);
3208*30088Sminshall     prompt = argv[0];
3209*30088Sminshall     if (argc > 1 && !strcmp(argv[1], "-d")) {
3210*30088Sminshall 	debug = 1;
3211*30088Sminshall 	argv++;
3212*30088Sminshall 	argc--;
3213*30088Sminshall     }
3214*30088Sminshall     if (argc > 1 && !strcmp(argv[1], "-n")) {
3215*30088Sminshall 	argv++;
3216*30088Sminshall 	argc--;
3217*30088Sminshall 	if (argc > 1) {		/* get file name */
3218*30088Sminshall 	    NetTrace = fopen(argv[1], "w");
3219*30088Sminshall 	    argv++;
3220*30088Sminshall 	    argc--;
3221*30088Sminshall 	    if (NetTrace == NULL) {
3222*30088Sminshall 		NetTrace = stdout;
3223*30088Sminshall 	    }
3224*30088Sminshall 	}
3225*30088Sminshall     }
3226*30088Sminshall #if	defined(TN3270) && defined(unix)
3227*30088Sminshall     if (argc > 1 && !strcmp(argv[1], "-t")) {
3228*30088Sminshall 	argv++;
3229*30088Sminshall 	argc--;
3230*30088Sminshall 	if (argc > 1) {		/* get command name */
3231*30088Sminshall 	    transcom = tline;
3232*30088Sminshall 	    (void) strcpy(transcom, argv[1]);
3233*30088Sminshall 	    argv++;
3234*30088Sminshall 	    argc--;
3235*30088Sminshall 	}
3236*30088Sminshall     }
3237*30088Sminshall #endif	/* defined(TN3270) && defined(unix) */
3238*30088Sminshall     if (argc != 1) {
3239*30088Sminshall 	if (setjmp(toplevel) != 0)
3240*30088Sminshall 	    Exit(0);
3241*30088Sminshall 	tn(argc, argv);
3242*30088Sminshall     }
3243*30088Sminshall     setjmp(toplevel);
3244*30088Sminshall     for (;;)
3245*30088Sminshall 	command(1);
3246*30088Sminshall }
3247