xref: /csrg-svn/usr.bin/telnet/telnet.c (revision 32377)
111758Ssam #ifndef lint
2*32377Sminshall static char copyright[] =
3*32377Sminshall "@(#) Copyright (c) 1984-1987 Regents of the University of California.\n\
421580Sdist  All rights reserved.\n";
5*32377Sminshall #endif	/* not lint */
611758Ssam 
721580Sdist #ifndef lint
8*32377Sminshall static char sccsid[] = "@(#)telnet.c	1.2 (Berkeley) 9/25/87";
9*32377Sminshall #endif	/* not lint */
1021580Sdist 
116000Sroot /*
12*32377Sminshall  * User telnet program, modified for use by tn3270.c.
1328066Sminshall  *
14*32377Sminshall  * Many of the FUNCTIONAL changes in this newest version of TELNET
1528066Sminshall  * were suggested by Dave Borman of Cray Research, Inc.
16*32377Sminshall  *
17*32377Sminshall  * Other changes in the tn3270 side come from Alan Crosswell (Columbia),
18*32377Sminshall  * Bob Braden (ISI), Steve Jacobson (Berkeley), and Cliff Frost (Berkeley).
19*32377Sminshall  *
20*32377Sminshall  * This code is common between telnet(1c) and tn3270(1c).  There are the
21*32377Sminshall  * following defines used to generate the various versions:
22*32377Sminshall  *
23*32377Sminshall  *	TN3270		- 	This is to be linked with tn3270.
24*32377Sminshall  *
25*32377Sminshall  *	NOT43		-	Allows the program to compile and run on
26*32377Sminshall  *				a 4.2BSD system.
27*32377Sminshall  *
28*32377Sminshall  *	PUTCHAR		-	Within tn3270, on a NOT43 system,
29*32377Sminshall  *				allows the use of the 4.3 curses
30*32377Sminshall  *				(greater speed updating the screen).
31*32377Sminshall  *				You need the 4.3 curses for this to work.
32*32377Sminshall  *
33*32377Sminshall  *	FD_SETSIZE	-	On whichever system, if this isn't defined,
34*32377Sminshall  *				we patch over the FD_SET, etc., macros with
35*32377Sminshall  *				some homebrewed ones.
36*32377Sminshall  *
37*32377Sminshall  *	SO_OOBINLINE	-	This is a socket option which we would like
38*32377Sminshall  *				to set to allow TCP urgent data to come
39*32377Sminshall  *				to us "inline".  This is NECESSARY for
40*32377Sminshall  *				CORRECT operation, and desireable for
41*32377Sminshall  *				simpler operation.
42*32377Sminshall  *
43*32377Sminshall  *	LNOFLSH		-	Detects the presence of the LNOFLSH bit
44*32377Sminshall  *				in the tty structure.
45*32377Sminshall  *
46*32377Sminshall  *	unix		-	Compiles in unix specific stuff.
47*32377Sminshall  *
48*32377Sminshall  *	MSDOS		-	Compiles in MSDOS specific stuff.
49*32377Sminshall  *
506000Sroot  */
5128066Sminshall 
529217Ssam #include <sys/types.h>
53*32377Sminshall #include <sys/time.h>
549217Ssam #include <sys/socket.h>
559217Ssam 
569217Ssam #include <netinet/in.h>
579217Ssam 
58*32377Sminshall #if	defined(unix)
59*32377Sminshall /* By the way, we need to include curses.h before telnet.h since,
60*32377Sminshall  * among other things, telnet.h #defines 'DO', which is a variable
61*32377Sminshall  * declared in curses.h.
62*32377Sminshall  */
63*32377Sminshall #include <curses.h>
64*32377Sminshall #endif	/* defined(unix) */
65*32377Sminshall 
6612212Ssam #include <arpa/telnet.h>
67*32377Sminshall 
68*32377Sminshall #if	!defined(NOT43)
6927186Sminshall #include <arpa/inet.h>
70*32377Sminshall #else	/* !defined(NOT43) */
71*32377Sminshall extern unsigned long inet_addr();
72*32377Sminshall extern char	*inet_ntoa();
73*32377Sminshall #endif	/* !defined(NOT43) */
7412212Ssam 
756000Sroot #include <ctype.h>
766000Sroot #include <errno.h>
778345Ssam #include <netdb.h>
78*32377Sminshall 
79*32377Sminshall #if	defined(unix)
8027186Sminshall #include <strings.h>
81*32377Sminshall #else	/* defined(unix) */
82*32377Sminshall #include <string.h>
83*32377Sminshall #endif	/* defined(unix) */
849217Ssam 
85*32377Sminshall #include "defines.h"
86*32377Sminshall #include "externs.h"
87*32377Sminshall #include "types.h"
88*32377Sminshall #include "general.h"
8927178Sminshall 
9027178Sminshall 
91*32377Sminshall #if	!defined(TN3270)
92*32377Sminshall #define	ExitString(f,s,r)	{ fprintf(f, s); exit(r); }
93*32377Sminshall #define	Exit(x)			exit(x)
94*32377Sminshall #define	SetIn3270()
95*32377Sminshall 
96*32377Sminshall void	setcommandmode(), command();	/* forward declarations */
97*32377Sminshall #endif	/* !defined(TN3270) */
98*32377Sminshall 
9927676Sminshall #ifndef	FD_SETSIZE
10027178Sminshall /*
10127178Sminshall  * The following is defined just in case someone should want to run
10227178Sminshall  * this telnet on a 4.2 system.
10327178Sminshall  *
10427178Sminshall  */
10527178Sminshall 
10627676Sminshall #define	FD_SET(n, p)	((p)->fds_bits[0] |= (1<<(n)))
10727676Sminshall #define	FD_CLR(n, p)	((p)->fds_bits[0] &= ~(1<<(n)))
10827676Sminshall #define	FD_ISSET(n, p)	((p)->fds_bits[0] & (1<<(n)))
10927676Sminshall #define FD_ZERO(p)	((p)->fds_bits[0] = 0)
11027178Sminshall 
11127178Sminshall #endif
11227178Sminshall 
11327228Sminshall #define	strip(x)	((x)&0x7f)
114*32377Sminshall #define min(x,y)	((x<y)? x:y)
1156000Sroot 
116*32377Sminshall #if	defined(TN3270)
117*32377Sminshall static char	Ibuf[8*BUFSIZ], *Ifrontp, *Ibackp;
118*32377Sminshall #endif	/* defined(TN3270) */
11927088Sminshall 
1206000Sroot 
121*32377Sminshall static char	subbuffer[SUBBUFSIZE],
122*32377Sminshall 		*subpointer, *subend;	 /* buffer for sub-options */
12327676Sminshall #define	SB_CLEAR()	subpointer = subbuffer;
12427676Sminshall #define	SB_TERM()	subend = subpointer;
12527676Sminshall #define	SB_ACCUM(c)	if (subpointer < (subbuffer+sizeof subbuffer)) { \
12627676Sminshall 				*subpointer++ = (c); \
12727676Sminshall 			}
12827676Sminshall 
129*32377Sminshall static char	sb_terminal[] = { IAC, SB,
130*32377Sminshall 			TELOPT_TTYPE, TELQUAL_IS,
131*32377Sminshall 			'I', 'B', 'M', '-', '3', '2', '7', '8', '-', '2',
132*32377Sminshall 			IAC, SE };
133*32377Sminshall #define	SBTERMMODEL	13
134*32377Sminshall 
135*32377Sminshall 
1366000Sroot char	hisopts[256];
1376000Sroot char	myopts[256];
1386000Sroot 
1396000Sroot char	doopt[] = { IAC, DO, '%', 'c', 0 };
1406000Sroot char	dont[] = { IAC, DONT, '%', 'c', 0 };
1416000Sroot char	will[] = { IAC, WILL, '%', 'c', 0 };
1426000Sroot char	wont[] = { IAC, WONT, '%', 'c', 0 };
1436000Sroot 
144*32377Sminshall static char	sibuf[BUFSIZ], *sbp;
145*32377Sminshall static char	tibuf[BUFSIZ], *tbp;
146*32377Sminshall static fd_set ibits, obits, xbits;
14727088Sminshall 
14827088Sminshall 
149*32377Sminshall int
150*32377Sminshall 	connected,
151*32377Sminshall 	net,
152*32377Sminshall 	scc,
153*32377Sminshall 	tcc,
154*32377Sminshall 	showoptions,
155*32377Sminshall 	In3270,		/* Are we in 3270 mode? */
156*32377Sminshall 	ISend,		/* trying to send network data in */
157*32377Sminshall 	debug = 0,
158*32377Sminshall 	crmod,
159*32377Sminshall 	netdata,	/* Print out network data flow */
160*32377Sminshall 	crlf,		/* Should '\r' be mapped to <CR><LF> (or <CR><NUL>)? */
161*32377Sminshall 	noasynch = 0,	/* User specified "-noasynch" on command line */
162*32377Sminshall 	askedSGA = 0,	/* We have talked about suppress go ahead */
163*32377Sminshall 	telnetport = 1;
16427088Sminshall 
165*32377Sminshall #define	CONTROL(x)	((x)&0x1f)		/* CTRL(x) is not portable */
1666000Sroot 
167*32377Sminshall char
168*32377Sminshall 	*prompt = 0,
169*32377Sminshall 	escape,
170*32377Sminshall 	echoc;
17127186Sminshall 
172*32377Sminshall int
173*32377Sminshall 	SYNCHing,		/* we are in TELNET SYNCH mode */
174*32377Sminshall 	flushout,		/* flush output */
175*32377Sminshall 	autoflush = 0,		/* flush output when interrupting? */
176*32377Sminshall 	autosynch,		/* send interrupt characters with SYNCH? */
177*32377Sminshall 	localchars,		/* we recognize interrupt/quit */
178*32377Sminshall 	donelclchars,		/* the user has set "localchars" */
179*32377Sminshall 	donebinarytoggle,	/* the user has put us in binary */
180*32377Sminshall 	dontlecho,		/* do we suppress local echoing right now? */
181*32377Sminshall 	globalmode;
1826000Sroot 
183*32377Sminshall /*	The following are some tn3270 specific flags */
184*32377Sminshall #if	defined(TN3270)
1856000Sroot 
186*32377Sminshall static int
187*32377Sminshall 	Sent3270TerminalType;	/* Have we said we are a 3270? */
1886000Sroot 
189*32377Sminshall #endif	/* defined(TN3270) */
19027186Sminshall int
19127186Sminshall 
192*32377Sminshall 	tout,			/* Output file descriptor */
193*32377Sminshall 	tin;			/* Input file descriptor */
19427186Sminshall 
19527186Sminshall 
19627186Sminshall 
19727186Sminshall /*
1986000Sroot  * Telnet receiver states for fsm
1996000Sroot  */
2006000Sroot #define	TS_DATA		0
2016000Sroot #define	TS_IAC		1
2026000Sroot #define	TS_WILL		2
2036000Sroot #define	TS_WONT		3
2046000Sroot #define	TS_DO		4
2056000Sroot #define	TS_DONT		5
20627021Sminshall #define	TS_CR		6
20727676Sminshall #define	TS_SB		7		/* sub-option collection */
20827676Sminshall #define	TS_SE		8		/* looking for sub-option end */
2096000Sroot 
210*32377Sminshall static int	telrcv_state;
2116000Sroot 
212*32377Sminshall jmp_buf	toplevel = { 0 };
213*32377Sminshall jmp_buf	peerdied;
2146000Sroot 
215*32377Sminshall int	flushline;
21627021Sminshall 
217*32377Sminshall /*
218*32377Sminshall  * The following are some clocks used to decide how to interpret
219*32377Sminshall  * the relationship between various variables.
220*32377Sminshall  */
2216000Sroot 
222*32377Sminshall Clocks clocks;
223*32377Sminshall 
224*32377Sminshall Modelist modelist[] = {
225*32377Sminshall 	{ "telnet command mode", COMMAND_LINE },
226*32377Sminshall 	{ "character-at-a-time mode", 0 },
227*32377Sminshall 	{ "character-at-a-time mode (local echo)", LOCAL_ECHO|LOCAL_CHARS },
228*32377Sminshall 	{ "line-by-line mode (remote echo)", LINE | LOCAL_CHARS },
229*32377Sminshall 	{ "line-by-line mode", LINE | LOCAL_ECHO | LOCAL_CHARS },
230*32377Sminshall 	{ "line-by-line mode (local echoing suppressed)", LINE | LOCAL_CHARS },
231*32377Sminshall 	{ "3270 mode", 0 },
232*32377Sminshall };
2336000Sroot 
234*32377Sminshall 
235*32377Sminshall /*
236*32377Sminshall  * Initialize telnet environment.
237*32377Sminshall  */
2386000Sroot 
239*32377Sminshall init_telnet()
240*32377Sminshall {
241*32377Sminshall     /* Don't change telnetport */
242*32377Sminshall     SB_CLEAR();
243*32377Sminshall     ClearArray(hisopts);
244*32377Sminshall     ClearArray(myopts);
245*32377Sminshall     sbp = sibuf;
246*32377Sminshall     tbp = tibuf;
2476000Sroot 
248*32377Sminshall     connected = net = scc = tcc = In3270 = ISend = donebinarytoggle = 0;
249*32377Sminshall     telnetport = 0;
2506000Sroot 
251*32377Sminshall #if	defined(unix) && defined(TN3270)
252*32377Sminshall     HaveInput = 0;
253*32377Sminshall #endif	/* defined(unix) && defined(TN3270) */
2546000Sroot 
255*32377Sminshall     SYNCHing = 0;
2566000Sroot 
257*32377Sminshall     errno = 0;
25827676Sminshall 
259*32377Sminshall     /* Don't change NetTrace */
2606000Sroot 
261*32377Sminshall     escape = CONTROL(']');
262*32377Sminshall     echoc = CONTROL('E');
2636000Sroot 
264*32377Sminshall     flushline = 1;
265*32377Sminshall     telrcv_state = TS_DATA;
266*32377Sminshall }
2676000Sroot 
2686000Sroot 
269*32377Sminshall void
27027676Sminshall willoption(option, reply)
27127676Sminshall 	int option, reply;
2726000Sroot {
2736000Sroot 	char *fmt;
2746000Sroot 
2756000Sroot 	switch (option) {
2766000Sroot 
2776000Sroot 	case TELOPT_ECHO:
278*32377Sminshall #	if defined(TN3270)
279*32377Sminshall 	    /*
280*32377Sminshall 	     * The following is a pain in the rear-end.
281*32377Sminshall 	     * Various IBM servers (some versions of Wiscnet,
282*32377Sminshall 	     * possibly Fibronics/Spartacus, and who knows who
283*32377Sminshall 	     * else) will NOT allow us to send "DO SGA" too early
284*32377Sminshall 	     * in the setup proceedings.  On the other hand,
285*32377Sminshall 	     * 4.2 servers (telnetd) won't set SGA correctly.
286*32377Sminshall 	     * So, we are stuck.  Empirically (but, based on
287*32377Sminshall 	     * a VERY small sample), the IBM servers don't send
288*32377Sminshall 	     * out anything about ECHO, so we postpone our sending
289*32377Sminshall 	     * "DO SGA" until we see "WILL ECHO" (which 4.2 servers
290*32377Sminshall 	     * DO send).
291*32377Sminshall 	     */
292*32377Sminshall 	    {
293*32377Sminshall 		if (askedSGA == 0) {
294*32377Sminshall 		    askedSGA = 1;
295*32377Sminshall 		    if (!hisopts[TELOPT_SGA]) {
296*32377Sminshall 			willoption(TELOPT_SGA, 0);
297*32377Sminshall 		    }
298*32377Sminshall 		}
299*32377Sminshall 	    }
300*32377Sminshall 		/* Fall through */
301*32377Sminshall 	case TELOPT_EOR:
302*32377Sminshall 	case TELOPT_BINARY:
303*32377Sminshall #endif	/* defined(TN3270) */
3046000Sroot 	case TELOPT_SGA:
30527110Sminshall 		settimer(modenegotiated);
3066000Sroot 		hisopts[option] = 1;
3076000Sroot 		fmt = doopt;
30827110Sminshall 		setconnmode();		/* possibly set new tty mode */
3096000Sroot 		break;
3106000Sroot 
3116000Sroot 	case TELOPT_TM:
31227110Sminshall 		return;			/* Never reply to TM will's/wont's */
3136000Sroot 
3146000Sroot 	default:
3156000Sroot 		fmt = dont;
3166000Sroot 		break;
3176000Sroot 	}
3186024Ssam 	sprintf(nfrontp, fmt, option);
3198378Ssam 	nfrontp += sizeof (dont) - 2;
32027676Sminshall 	if (reply)
321*32377Sminshall 		printoption(">SENT", fmt, option, reply);
32227676Sminshall 	else
323*32377Sminshall 		printoption("<SENT", fmt, option, reply);
3246000Sroot }
3256000Sroot 
326*32377Sminshall void
32727676Sminshall wontoption(option, reply)
32827676Sminshall 	int option, reply;
3296000Sroot {
3306000Sroot 	char *fmt;
3316000Sroot 
3326000Sroot 	switch (option) {
3336000Sroot 
3346000Sroot 	case TELOPT_ECHO:
3356000Sroot 	case TELOPT_SGA:
33627110Sminshall 		settimer(modenegotiated);
3376000Sroot 		hisopts[option] = 0;
3386000Sroot 		fmt = dont;
33927110Sminshall 		setconnmode();			/* Set new tty mode */
3406000Sroot 		break;
3416000Sroot 
34227110Sminshall 	case TELOPT_TM:
34327110Sminshall 		return;		/* Never reply to TM will's/wont's */
34427110Sminshall 
3456000Sroot 	default:
3466000Sroot 		fmt = dont;
3476000Sroot 	}
3486000Sroot 	sprintf(nfrontp, fmt, option);
3498378Ssam 	nfrontp += sizeof (doopt) - 2;
35027676Sminshall 	if (reply)
351*32377Sminshall 		printoption(">SENT", fmt, option, reply);
35227676Sminshall 	else
353*32377Sminshall 		printoption("<SENT", fmt, option, reply);
3546000Sroot }
3556000Sroot 
356*32377Sminshall static void
3576000Sroot dooption(option)
3586000Sroot 	int option;
3596000Sroot {
3606000Sroot 	char *fmt;
3616000Sroot 
3626000Sroot 	switch (option) {
3636000Sroot 
3646000Sroot 	case TELOPT_TM:
36513231Ssam 		fmt = will;
36613231Ssam 		break;
36713231Ssam 
368*32377Sminshall #	if defined(TN3270)
369*32377Sminshall 	case TELOPT_EOR:
370*32377Sminshall 	case TELOPT_BINARY:
371*32377Sminshall #	endif	/* defined(TN3270) */
37227676Sminshall 	case TELOPT_TTYPE:		/* terminal type option */
37327110Sminshall 	case TELOPT_SGA:		/* no big deal */
3746000Sroot 		fmt = will;
37527110Sminshall 		myopts[option] = 1;
3766000Sroot 		break;
3776000Sroot 
37827110Sminshall 	case TELOPT_ECHO:		/* We're never going to echo... */
3796000Sroot 	default:
3806000Sroot 		fmt = wont;
3816000Sroot 		break;
3826000Sroot 	}
3836000Sroot 	sprintf(nfrontp, fmt, option);
3848378Ssam 	nfrontp += sizeof (doopt) - 2;
385*32377Sminshall 	printoption(">SENT", fmt, option, 0);
3866000Sroot }
38727676Sminshall 
38827676Sminshall /*
38927676Sminshall  * suboption()
39027676Sminshall  *
39127676Sminshall  *	Look at the sub-option buffer, and try to be helpful to the other
39227676Sminshall  * side.
39327676Sminshall  *
39427676Sminshall  *	Currently we recognize:
39527676Sminshall  *
39627676Sminshall  *		Terminal type, send request.
39727676Sminshall  */
39827676Sminshall 
399*32377Sminshall static void
40027676Sminshall suboption()
40127676Sminshall {
402*32377Sminshall     printsub("<", subbuffer, subend-subbuffer+1);
40327676Sminshall     switch (subbuffer[0]&0xff) {
40427676Sminshall     case TELOPT_TTYPE:
40527676Sminshall 	if ((subbuffer[1]&0xff) != TELQUAL_SEND) {
40627676Sminshall 	    ;
40727676Sminshall 	} else {
40827676Sminshall 	    char *name;
40927676Sminshall 	    char namebuf[41];
410*32377Sminshall 	    extern char *getenv();
41127676Sminshall 	    int len;
41227676Sminshall 
413*32377Sminshall #if	defined(TN3270)
414*32377Sminshall 	    /*
415*32377Sminshall 	     * Try to send a 3270 type terminal name.  Decide which one based
416*32377Sminshall 	     * on the format of our screen, and (in the future) color
417*32377Sminshall 	     * capaiblities.
418*32377Sminshall 	     */
419*32377Sminshall #if	defined(unix)
420*32377Sminshall 	    if (initscr() != ERR) {	/* Initialize curses to get line size */
421*32377Sminshall 		MaxNumberLines = LINES;
422*32377Sminshall 		MaxNumberColumns = COLS;
423*32377Sminshall 	    }
424*32377Sminshall #else	/* defined(unix) */
425*32377Sminshall 	    InitTerminal();
426*32377Sminshall #endif	/* defined(unix) */
427*32377Sminshall 	    if ((MaxNumberLines >= 24) && (MaxNumberColumns >= 80)) {
428*32377Sminshall 		Sent3270TerminalType = 1;
429*32377Sminshall 		if ((MaxNumberLines >= 27) && (MaxNumberColumns >= 132)) {
430*32377Sminshall 		    MaxNumberLines = 27;
431*32377Sminshall 		    MaxNumberColumns = 132;
432*32377Sminshall 		    sb_terminal[SBTERMMODEL] = '5';
433*32377Sminshall 		} else if (MaxNumberLines >= 43) {
434*32377Sminshall 		    MaxNumberLines = 43;
435*32377Sminshall 		    MaxNumberColumns = 80;
436*32377Sminshall 		    sb_terminal[SBTERMMODEL] = '4';
437*32377Sminshall 		} else if (MaxNumberLines >= 32) {
438*32377Sminshall 		    MaxNumberLines = 32;
439*32377Sminshall 		    MaxNumberColumns = 80;
440*32377Sminshall 		    sb_terminal[SBTERMMODEL] = '3';
441*32377Sminshall 		} else {
442*32377Sminshall 		    MaxNumberLines = 24;
443*32377Sminshall 		    MaxNumberColumns = 80;
444*32377Sminshall 		    sb_terminal[SBTERMMODEL] = '2';
445*32377Sminshall 		}
446*32377Sminshall 		NumberLines = 24;		/* before we start out... */
447*32377Sminshall 		NumberColumns = 80;
448*32377Sminshall 		ScreenSize = NumberLines*NumberColumns;
449*32377Sminshall 		if ((MaxNumberLines*MaxNumberColumns) > MAXSCREENSIZE) {
450*32377Sminshall 		    ExitString(stderr,
451*32377Sminshall 			"Programming error:  MAXSCREENSIZE too small.\n", 1);
452*32377Sminshall 		    /*NOTREACHED*/
453*32377Sminshall 		}
454*32377Sminshall 		memcpy(nfrontp, sb_terminal, sizeof sb_terminal);
455*32377Sminshall 		printsub(">", nfrontp+2, sizeof sb_terminal-2);
456*32377Sminshall 		nfrontp += sizeof sb_terminal;
457*32377Sminshall 		return;
458*32377Sminshall 	    }
459*32377Sminshall #endif	/* defined(TN3270) */
460*32377Sminshall 
46127676Sminshall 	    name = getenv("TERM");
46227676Sminshall 	    if ((name == 0) || ((len = strlen(name)) > 40)) {
46327676Sminshall 		name = "UNKNOWN";
46427676Sminshall 	    }
46527676Sminshall 	    if ((len + 4+2) < NETROOM()) {
46627676Sminshall 		strcpy(namebuf, name);
46727676Sminshall 		upcase(namebuf);
46827676Sminshall 		sprintf(nfrontp, "%c%c%c%c%s%c%c", IAC, SB, TELOPT_TTYPE,
46927676Sminshall 				    TELQUAL_IS, namebuf, IAC, SE);
470*32377Sminshall 		printsub(">", nfrontp+2, 4+strlen(namebuf)+2-2-2);
47127676Sminshall 		nfrontp += 4+strlen(namebuf)+2;
472*32377Sminshall 	    } else {
473*32377Sminshall 		ExitString(stderr, "No room in buffer for terminal type.\n",
474*32377Sminshall 							1);
475*32377Sminshall 		/*NOTREACHED*/
47627676Sminshall 	    }
47727676Sminshall 	}
47827676Sminshall 
47927676Sminshall     default:
48027676Sminshall 	break;
48127676Sminshall     }
48227676Sminshall }
48327088Sminshall 
484*32377Sminshall #if	defined(TN3270)
485*32377Sminshall static void
486*32377Sminshall SetIn3270()
48727088Sminshall {
488*32377Sminshall     if (Sent3270TerminalType && myopts[TELOPT_BINARY]
489*32377Sminshall 			    && hisopts[TELOPT_BINARY] && !donebinarytoggle) {
490*32377Sminshall 	if (!In3270) {
491*32377Sminshall 	    In3270 = 1;
492*32377Sminshall 	    Init3270();		/* Initialize 3270 functions */
493*32377Sminshall 	    /* initialize terminal key mapping */
494*32377Sminshall 	    InitTerminal();	/* Start terminal going */
495*32377Sminshall 	    setconnmode();
496*32377Sminshall 	}
497*32377Sminshall     } else {
498*32377Sminshall 	if (In3270) {
499*32377Sminshall 	    StopScreen(1);
500*32377Sminshall 	    In3270 = 0;
501*32377Sminshall 	    Stop3270();		/* Tell 3270 we aren't here anymore */
502*32377Sminshall 	    setconnmode();
503*32377Sminshall 	}
50427228Sminshall     }
50527088Sminshall }
506*32377Sminshall #endif	/* defined(TN3270) */
507*32377Sminshall 
50827088Sminshall 
509*32377Sminshall static void
510*32377Sminshall telrcv()
51127110Sminshall {
512*32377Sminshall     register int c;
513*32377Sminshall     static int telrcv_state = TS_DATA;
514*32377Sminshall #   if defined(TN3270)
515*32377Sminshall     register int Scc;
516*32377Sminshall     register char *Sbp;
517*32377Sminshall #   endif /* defined(TN3270) */
51827088Sminshall 
519*32377Sminshall     while ((scc > 0) && (TTYROOM() > 2)) {
520*32377Sminshall 	c = *sbp++ & 0xff, scc--;
521*32377Sminshall 	switch (telrcv_state) {
52227110Sminshall 
523*32377Sminshall 	case TS_CR:
524*32377Sminshall 	    telrcv_state = TS_DATA;
525*32377Sminshall 	    if (c == '\0') {
526*32377Sminshall 		break;	/* Ignore \0 after CR */
527*32377Sminshall 	    } else if (c == '\n') {
528*32377Sminshall 		if (hisopts[TELOPT_ECHO] && !crmod) {
529*32377Sminshall 		    TTYADD(c);
530*32377Sminshall 		}
531*32377Sminshall 		break;
532*32377Sminshall 	    }
533*32377Sminshall 	    /* Else, fall through */
53427088Sminshall 
535*32377Sminshall 	case TS_DATA:
536*32377Sminshall 	    if (c == IAC) {
537*32377Sminshall 		telrcv_state = TS_IAC;
538*32377Sminshall 		continue;
539*32377Sminshall 	    }
540*32377Sminshall #	    if defined(TN3270)
541*32377Sminshall 	    if (In3270) {
542*32377Sminshall 		*Ifrontp++ = c;
543*32377Sminshall 		Sbp = sbp;
544*32377Sminshall 		Scc = scc;
545*32377Sminshall 		while (Scc > 0) {
546*32377Sminshall 		    c = *Sbp++ & 0377, Scc--;
547*32377Sminshall 		    if (c == IAC) {
548*32377Sminshall 			telrcv_state = TS_IAC;
549*32377Sminshall 			break;
550*32377Sminshall 		    }
551*32377Sminshall 		    *Ifrontp++ = c;
552*32377Sminshall 		}
553*32377Sminshall 		sbp = Sbp;
554*32377Sminshall 		scc = Scc;
555*32377Sminshall 	    } else
556*32377Sminshall #	    endif /* defined(TN3270) */
557*32377Sminshall 		    /*
558*32377Sminshall 		     * The 'crmod' hack (see following) is needed
559*32377Sminshall 		     * since we can't * set CRMOD on output only.
560*32377Sminshall 		     * Machines like MULTICS like to send \r without
561*32377Sminshall 		     * \n; since we must turn off CRMOD to get proper
562*32377Sminshall 		     * input, the mapping is done here (sigh).
563*32377Sminshall 		     */
564*32377Sminshall 	    if ((c == '\r') && !hisopts[TELOPT_BINARY]) {
565*32377Sminshall 		if (scc > 0) {
566*32377Sminshall 		    c = *sbp&0xff;
567*32377Sminshall 		    if (c == 0) {
568*32377Sminshall 			sbp++, scc--;
569*32377Sminshall 			/* a "true" CR */
570*32377Sminshall 			TTYADD('\r');
571*32377Sminshall 		    } else if (!hisopts[TELOPT_ECHO] &&
572*32377Sminshall 					(c == '\n')) {
573*32377Sminshall 			sbp++, scc--;
574*32377Sminshall 			TTYADD('\n');
575*32377Sminshall 		    } else {
576*32377Sminshall 			TTYADD('\r');
577*32377Sminshall 			if (crmod) {
578*32377Sminshall 				TTYADD('\n');
579*32377Sminshall 			}
580*32377Sminshall 		    }
581*32377Sminshall 		} else {
582*32377Sminshall 		    telrcv_state = TS_CR;
583*32377Sminshall 		    TTYADD('\r');
584*32377Sminshall 		    if (crmod) {
585*32377Sminshall 			    TTYADD('\n');
586*32377Sminshall 		    }
587*32377Sminshall 		}
588*32377Sminshall 	    } else {
589*32377Sminshall 		TTYADD(c);
590*32377Sminshall 	    }
591*32377Sminshall 	    continue;
59227088Sminshall 
593*32377Sminshall 	case TS_IAC:
594*32377Sminshall 	    switch (c) {
595*32377Sminshall 
596*32377Sminshall 	    case WILL:
597*32377Sminshall 		telrcv_state = TS_WILL;
598*32377Sminshall 		continue;
59927261Sminshall 
600*32377Sminshall 	    case WONT:
601*32377Sminshall 		telrcv_state = TS_WONT;
602*32377Sminshall 		continue;
60327261Sminshall 
604*32377Sminshall 	    case DO:
605*32377Sminshall 		telrcv_state = TS_DO;
606*32377Sminshall 		continue;
60727261Sminshall 
608*32377Sminshall 	    case DONT:
609*32377Sminshall 		telrcv_state = TS_DONT;
610*32377Sminshall 		continue;
61127261Sminshall 
612*32377Sminshall 	    case DM:
613*32377Sminshall 		    /*
614*32377Sminshall 		     * We may have missed an urgent notification,
615*32377Sminshall 		     * so make sure we flush whatever is in the
616*32377Sminshall 		     * buffer currently.
617*32377Sminshall 		     */
618*32377Sminshall 		SYNCHing = 1;
619*32377Sminshall 		ttyflush(1);
620*32377Sminshall 		SYNCHing = stilloob(net);
621*32377Sminshall 		settimer(gotDM);
622*32377Sminshall 		break;
62327088Sminshall 
624*32377Sminshall 	    case NOP:
625*32377Sminshall 	    case GA:
626*32377Sminshall 		break;
62727088Sminshall 
628*32377Sminshall 	    case SB:
629*32377Sminshall 		SB_CLEAR();
630*32377Sminshall 		telrcv_state = TS_SB;
631*32377Sminshall 		continue;
63227261Sminshall 
633*32377Sminshall #	    if defined(TN3270)
634*32377Sminshall 	    case EOR:
635*32377Sminshall 		if (In3270) {
636*32377Sminshall 		    Ibackp += DataFromNetwork(Ibackp, Ifrontp-Ibackp, 1);
637*32377Sminshall 		    if (Ibackp == Ifrontp) {
638*32377Sminshall 			Ibackp = Ifrontp = Ibuf;
639*32377Sminshall 			ISend = 0;	/* should have been! */
640*32377Sminshall 		    } else {
641*32377Sminshall 			ISend = 1;
64227088Sminshall 		    }
64327088Sminshall 		}
64427088Sminshall 		break;
645*32377Sminshall #	    endif /* defined(TN3270) */
646*32377Sminshall 
647*32377Sminshall 	    case IAC:
648*32377Sminshall #	    if !defined(TN3270)
649*32377Sminshall 		TTYADD(IAC);
650*32377Sminshall #	    else /* !defined(TN3270) */
651*32377Sminshall 		if (In3270) {
652*32377Sminshall 		    *Ifrontp++ = IAC;
653*32377Sminshall 		} else {
654*32377Sminshall 		    TTYADD(IAC);
655*32377Sminshall 		}
656*32377Sminshall #	    endif /* !defined(TN3270) */
65727088Sminshall 		break;
658*32377Sminshall 
65927088Sminshall 	    default:
66027088Sminshall 		break;
66127088Sminshall 	    }
662*32377Sminshall 	    telrcv_state = TS_DATA;
663*32377Sminshall 	    continue;
66427088Sminshall 
665*32377Sminshall 	case TS_WILL:
666*32377Sminshall 	    printoption(">RCVD", will, c, !hisopts[c]);
667*32377Sminshall 	    if (c == TELOPT_TM) {
668*32377Sminshall 		if (flushout) {
669*32377Sminshall 		    flushout = 0;
670*32377Sminshall 		}
671*32377Sminshall 	    } else if (!hisopts[c]) {
672*32377Sminshall 		willoption(c, 1);
673*32377Sminshall 	    }
674*32377Sminshall 	    SetIn3270();
675*32377Sminshall 	    telrcv_state = TS_DATA;
676*32377Sminshall 	    continue;
67727110Sminshall 
678*32377Sminshall 	case TS_WONT:
679*32377Sminshall 	    printoption(">RCVD", wont, c, hisopts[c]);
680*32377Sminshall 	    if (c == TELOPT_TM) {
681*32377Sminshall 		if (flushout) {
682*32377Sminshall 		    flushout = 0;
683*32377Sminshall 		}
684*32377Sminshall 	    } else if (hisopts[c]) {
685*32377Sminshall 		wontoption(c, 1);
686*32377Sminshall 	    }
687*32377Sminshall 	    SetIn3270();
688*32377Sminshall 	    telrcv_state = TS_DATA;
689*32377Sminshall 	    continue;
69027088Sminshall 
691*32377Sminshall 	case TS_DO:
692*32377Sminshall 	    printoption(">RCVD", doopt, c, !myopts[c]);
693*32377Sminshall 	    if (!myopts[c])
694*32377Sminshall 		dooption(c);
695*32377Sminshall 	    SetIn3270();
696*32377Sminshall 	    telrcv_state = TS_DATA;
697*32377Sminshall 	    continue;
69827088Sminshall 
699*32377Sminshall 	case TS_DONT:
700*32377Sminshall 	    printoption(">RCVD", dont, c, myopts[c]);
701*32377Sminshall 	    if (myopts[c]) {
702*32377Sminshall 		myopts[c] = 0;
703*32377Sminshall 		sprintf(nfrontp, wont, c);
704*32377Sminshall 		nfrontp += sizeof (wont) - 2;
705*32377Sminshall 		flushline = 1;
706*32377Sminshall 		setconnmode();	/* set new tty mode (maybe) */
707*32377Sminshall 		printoption(">SENT", wont, c, 0);
708*32377Sminshall 	    }
709*32377Sminshall 	    SetIn3270();
710*32377Sminshall 	    telrcv_state = TS_DATA;
711*32377Sminshall 	    continue;
71227088Sminshall 
713*32377Sminshall 	case TS_SB:
714*32377Sminshall 	    if (c == IAC) {
715*32377Sminshall 		telrcv_state = TS_SE;
716*32377Sminshall 	    } else {
717*32377Sminshall 		SB_ACCUM(c);
718*32377Sminshall 	    }
719*32377Sminshall 	    continue;
72027088Sminshall 
721*32377Sminshall 	case TS_SE:
722*32377Sminshall 	    if (c != SE) {
723*32377Sminshall 		if (c != IAC) {
724*32377Sminshall 		    SB_ACCUM(IAC);
725*32377Sminshall 		}
726*32377Sminshall 		SB_ACCUM(c);
727*32377Sminshall 		telrcv_state = TS_SB;
728*32377Sminshall 	    } else {
729*32377Sminshall 		SB_TERM();
730*32377Sminshall 		suboption();	/* handle sub-option */
731*32377Sminshall 		SetIn3270();
732*32377Sminshall 		telrcv_state = TS_DATA;
733*32377Sminshall 	    }
73427088Sminshall 	}
73527088Sminshall     }
73627088Sminshall }
737*32377Sminshall 
738*32377Sminshall #if	defined(TN3270)
739*32377Sminshall static void
740*32377Sminshall SetForExit()
741*32377Sminshall {
742*32377Sminshall     setconnmode();
743*32377Sminshall     if (In3270) {
744*32377Sminshall 	Finish3270();
745*32377Sminshall     }
746*32377Sminshall     setcommandmode();
747*32377Sminshall     fflush(stdout);
748*32377Sminshall     fflush(stderr);
749*32377Sminshall     if (In3270) {
750*32377Sminshall 	StopScreen(1);
751*32377Sminshall     }
752*32377Sminshall     setconnmode();
753*32377Sminshall     setcommandmode();
754*32377Sminshall }
75527088Sminshall 
756*32377Sminshall static void
757*32377Sminshall Exit(returnCode)
758*32377Sminshall int returnCode;
75927088Sminshall {
760*32377Sminshall     SetForExit();
761*32377Sminshall     exit(returnCode);
76227088Sminshall }
76327088Sminshall 
764*32377Sminshall void
765*32377Sminshall ExitString(file, string, returnCode)
766*32377Sminshall FILE *file;
767*32377Sminshall char *string;
768*32377Sminshall int returnCode;
76927088Sminshall {
770*32377Sminshall     SetForExit();
771*32377Sminshall     fwrite(string, 1, strlen(string), file);
772*32377Sminshall     exit(returnCode);
77327088Sminshall }
77427088Sminshall 
775*32377Sminshall void
776*32377Sminshall ExitPerror(string, returnCode)
777*32377Sminshall char *string;
778*32377Sminshall int returnCode;
77927088Sminshall {
780*32377Sminshall     SetForExit();
781*32377Sminshall     perror(string);
782*32377Sminshall     exit(returnCode);
783*32377Sminshall }
784*32377Sminshall #endif	/* defined(TN3270) */
78527088Sminshall 
78627088Sminshall 
78727088Sminshall /*
788*32377Sminshall  * Scheduler()
789*32377Sminshall  *
790*32377Sminshall  * Try to do something.
791*32377Sminshall  *
792*32377Sminshall  * If we do something useful, return 1; else return 0.
793*32377Sminshall  *
79427110Sminshall  */
79527110Sminshall 
79627110Sminshall 
797*32377Sminshall int
798*32377Sminshall Scheduler(block)
799*32377Sminshall int	block;			/* should we block in the select ? */
80027110Sminshall {
801*32377Sminshall     register int c;
802*32377Sminshall 		/* One wants to be a bit careful about setting returnValue
803*32377Sminshall 		 * to one, since a one implies we did some useful work,
804*32377Sminshall 		 * and therefore probably won't be called to block next
805*32377Sminshall 		 * time (TN3270 mode only).
806*32377Sminshall 		 */
807*32377Sminshall     int returnValue = 0;
808*32377Sminshall     static struct timeval TimeValue = { 0 };
80927110Sminshall 
810*32377Sminshall     if (scc < 0 && tcc < 0) {
811*32377Sminshall 	return -1;
81227110Sminshall     }
81327110Sminshall 
814*32377Sminshall     if ((!MODE_LINE(globalmode) || flushline) && NETBYTES()) {
815*32377Sminshall 	FD_SET(net, &obits);
816*32377Sminshall     }
817*32377Sminshall #if	!defined(MSDOS)
818*32377Sminshall     if (TTYBYTES()) {
819*32377Sminshall 	FD_SET(tout, &obits);
82027110Sminshall     }
821*32377Sminshall #if	defined(TN3270)
822*32377Sminshall     if ((tcc == 0) && NETROOM() && (shell_active == 0)) {
823*32377Sminshall 	FD_SET(tin, &ibits);
82427110Sminshall     }
825*32377Sminshall #else	/* defined(TN3270) */
826*32377Sminshall     if ((tcc == 0) && NETROOM()) {
827*32377Sminshall 	FD_SET(tin, &ibits);
82827110Sminshall     }
829*32377Sminshall #endif	/* defined(TN3270) */
830*32377Sminshall #endif	/* !defined(MSDOS) */
831*32377Sminshall #   if !defined(TN3270)
832*32377Sminshall     if (TTYROOM()) {
833*32377Sminshall 	FD_SET(net, &ibits);
83427110Sminshall     }
835*32377Sminshall #   else /* !defined(TN3270) */
836*32377Sminshall     if (!ISend && TTYROOM()) {
837*32377Sminshall 	FD_SET(net, &ibits);
83827110Sminshall     }
839*32377Sminshall #   endif /* !defined(TN3270) */
840*32377Sminshall     if (!SYNCHing) {
841*32377Sminshall 	FD_SET(net, &xbits);
842*32377Sminshall     }
843*32377Sminshall #   if defined(TN3270) && defined(unix)
844*32377Sminshall     if (HaveInput) {
845*32377Sminshall 	HaveInput = 0;
846*32377Sminshall 	signal(SIGIO, inputAvailable);
847*32377Sminshall     }
848*32377Sminshall #endif	/* defined(TN3270) && defined(unix) */
849*32377Sminshall     if ((c = select(16, &ibits, &obits, &xbits,
850*32377Sminshall 			block? (struct timeval *)0 : &TimeValue)) < 0) {
851*32377Sminshall 	if (c == -1) {
852*32377Sminshall 		    /*
853*32377Sminshall 		     * we can get EINTR if we are in line mode,
854*32377Sminshall 		     * and the user does an escape (TSTP), or
855*32377Sminshall 		     * some other signal generator.
856*32377Sminshall 		     */
857*32377Sminshall 	    if (errno == EINTR) {
858*32377Sminshall 		return 0;
859*32377Sminshall 	    }
860*32377Sminshall #	    if defined(TN3270)
861*32377Sminshall 		    /*
862*32377Sminshall 		     * we can get EBADF if we were in transparent
863*32377Sminshall 		     * mode, and the transcom process died.
864*32377Sminshall 		    */
865*32377Sminshall 	    if (errno == EBADF) {
866*32377Sminshall 			/*
867*32377Sminshall 			 * zero the bits (even though kernel does it)
868*32377Sminshall 			 * to make sure we are selecting on the right
869*32377Sminshall 			 * ones.
870*32377Sminshall 			*/
871*32377Sminshall 		FD_ZERO(&ibits);
872*32377Sminshall 		FD_ZERO(&obits);
873*32377Sminshall 		FD_ZERO(&xbits);
874*32377Sminshall 		return 0;
875*32377Sminshall 	    }
876*32377Sminshall #	    endif /* defined(TN3270) */
877*32377Sminshall 		    /* I don't like this, does it ever happen? */
878*32377Sminshall 	    printf("sleep(5) from telnet, after select\r\n");
879*32377Sminshall #if	defined(unix)
880*32377Sminshall 	    sleep(5);
881*32377Sminshall #endif	/* defined(unix) */
88227110Sminshall 	}
88327261Sminshall 	return 0;
88427110Sminshall     }
885*32377Sminshall 
886*32377Sminshall     /*
887*32377Sminshall      * Any urgent data?
888*32377Sminshall      */
889*32377Sminshall     if (FD_ISSET(net, &xbits)) {
890*32377Sminshall 	FD_CLR(net, &xbits);
891*32377Sminshall 	SYNCHing = 1;
892*32377Sminshall 	ttyflush(1);	/* flush already enqueued data */
89327110Sminshall     }
89427178Sminshall 
895*32377Sminshall     /*
896*32377Sminshall      * Something to read from the network...
897*32377Sminshall      */
898*32377Sminshall     if (FD_ISSET(net, &ibits)) {
899*32377Sminshall 	int canread;
90027178Sminshall 
901*32377Sminshall 	FD_CLR(net, &ibits);
902*32377Sminshall 	if (scc == 0) {
903*32377Sminshall 	    sbp = sibuf;
904*32377Sminshall 	}
905*32377Sminshall 	canread = sibuf + sizeof sibuf - (sbp+scc);
906*32377Sminshall #if	!defined(SO_OOBINLINE)
907*32377Sminshall 	    /*
908*32377Sminshall 	     * In 4.2 (and some early 4.3) systems, the
909*32377Sminshall 	     * OOB indication and data handling in the kernel
910*32377Sminshall 	     * is such that if two separate TCP Urgent requests
911*32377Sminshall 	     * come in, one byte of TCP data will be overlaid.
912*32377Sminshall 	     * This is fatal for Telnet, but we try to live
913*32377Sminshall 	     * with it.
914*32377Sminshall 	     *
915*32377Sminshall 	     * In addition, in 4.2 (and...), a special protocol
916*32377Sminshall 	     * is needed to pick up the TCP Urgent data in
917*32377Sminshall 	     * the correct sequence.
918*32377Sminshall 	     *
919*32377Sminshall 	     * What we do is:  if we think we are in urgent
920*32377Sminshall 	     * mode, we look to see if we are "at the mark".
921*32377Sminshall 	     * If we are, we do an OOB receive.  If we run
922*32377Sminshall 	     * this twice, we will do the OOB receive twice,
923*32377Sminshall 	     * but the second will fail, since the second
924*32377Sminshall 	     * time we were "at the mark", but there wasn't
925*32377Sminshall 	     * any data there (the kernel doesn't reset
926*32377Sminshall 	     * "at the mark" until we do a normal read).
927*32377Sminshall 	     * Once we've read the OOB data, we go ahead
928*32377Sminshall 	     * and do normal reads.
929*32377Sminshall 	     *
930*32377Sminshall 	     * There is also another problem, which is that
931*32377Sminshall 	     * since the OOB byte we read doesn't put us
932*32377Sminshall 	     * out of OOB state, and since that byte is most
933*32377Sminshall 	     * likely the TELNET DM (data mark), we would
934*32377Sminshall 	     * stay in the TELNET SYNCH (SYNCHing) state.
935*32377Sminshall 	     * So, clocks to the rescue.  If we've "just"
936*32377Sminshall 	     * received a DM, then we test for the
937*32377Sminshall 	     * presence of OOB data when the receive OOB
938*32377Sminshall 	     * fails (and AFTER we did the normal mode read
939*32377Sminshall 	     * to clear "at the mark").
940*32377Sminshall 	     */
941*32377Sminshall 	if (SYNCHing) {
942*32377Sminshall 	    int atmark;
943*32377Sminshall 
944*32377Sminshall 	    ioctl(net, SIOCATMARK, (char *)&atmark);
945*32377Sminshall 	    if (atmark) {
946*32377Sminshall 		c = recv(net, sbp+scc, canread, MSG_OOB);
947*32377Sminshall 		if ((c == -1) && (errno == EINVAL)) {
948*32377Sminshall 		    c = recv(net, sbp+scc, canread, 0);
949*32377Sminshall 		    if (clocks.didnetreceive < clocks.gotDM) {
950*32377Sminshall 			SYNCHing = stilloob(net);
95127261Sminshall 		    }
952*32377Sminshall 		}
953*32377Sminshall 	    } else {
954*32377Sminshall 		c = recv(net, sbp+scc, canread, 0);
955*32377Sminshall 	    }
956*32377Sminshall 	} else {
957*32377Sminshall 	    c = recv(net, sbp+scc, canread, 0);
958*32377Sminshall 	}
959*32377Sminshall 	settimer(didnetreceive);
960*32377Sminshall #else	/* !defined(SO_OOBINLINE) */
961*32377Sminshall 	c = recv(net, sbp+scc, canread, 0);
962*32377Sminshall #endif	/* !defined(SO_OOBINLINE) */
963*32377Sminshall 	if (c < 0 && errno == EWOULDBLOCK) {
964*32377Sminshall 	    c = 0;
965*32377Sminshall 	} else if (c <= 0) {
966*32377Sminshall 	    return -1;
967*32377Sminshall 	}
968*32377Sminshall 	if (netdata) {
969*32377Sminshall 	    Dump('<', sbp+scc, c);
970*32377Sminshall 	}
971*32377Sminshall 	scc += c;
972*32377Sminshall 	returnValue = 1;
973*32377Sminshall     }
97427178Sminshall 
975*32377Sminshall     /*
976*32377Sminshall      * Something to read from the tty...
977*32377Sminshall      */
978*32377Sminshall #if	defined(MSDOS)
979*32377Sminshall     if ((tcc == 0) && NETROOM() && (shell_active == 0) && TerminalCanRead())
980*32377Sminshall #else	/* defined(MSDOS) */
981*32377Sminshall     if (FD_ISSET(tin, &ibits))
982*32377Sminshall #endif	/* defined(MSDOS) */
983*32377Sminshall 				    {
984*32377Sminshall 	FD_CLR(tin, &ibits);
985*32377Sminshall 	if (tcc == 0) {
986*32377Sminshall 	    tbp = tibuf;	/* nothing left, reset */
98727178Sminshall 	}
988*32377Sminshall 	c = TerminalRead(tin, tbp, tibuf+sizeof tibuf - tbp);
989*32377Sminshall 	if (c < 0 && errno == EWOULDBLOCK) {
990*32377Sminshall 	    c = 0;
991*32377Sminshall 	} else {
992*32377Sminshall #if	defined(unix)
993*32377Sminshall 	    /* EOF detection for line mode!!!! */
994*32377Sminshall 	    if (c == 0 && MODE_LOCAL_CHARS(globalmode)) {
995*32377Sminshall 			/* must be an EOF... */
996*32377Sminshall 		*tbp = termEofChar;
997*32377Sminshall 		c = 1;
998*32377Sminshall 	    }
999*32377Sminshall #endif	/* defined(unix) */
1000*32377Sminshall 	    if (c <= 0) {
1001*32377Sminshall 		tcc = c;
1002*32377Sminshall 		return -1;
1003*32377Sminshall 	    }
100427178Sminshall 	}
1005*32377Sminshall 	tcc += c;
1006*32377Sminshall 	returnValue = 1;		/* did something useful */
1007*32377Sminshall     }
100827178Sminshall 
1009*32377Sminshall #   if defined(TN3270)
1010*32377Sminshall     if (tcc > 0) {
1011*32377Sminshall 	if (In3270) {
1012*32377Sminshall 	    c = DataFromTerminal(tbp, tcc);
1013*32377Sminshall 	    if (c) {
1014*32377Sminshall 		returnValue = 1;
1015*32377Sminshall 	    }
1016*32377Sminshall 	    tcc -= c;
1017*32377Sminshall 	    tbp += c;
1018*32377Sminshall 	} else {
1019*32377Sminshall #   endif /* defined(TN3270) */
1020*32377Sminshall 	    returnValue = 1;
1021*32377Sminshall 	    while (tcc > 0) {
1022*32377Sminshall 		register int sc;
1023*32377Sminshall 
1024*32377Sminshall 		if (NETROOM() < 2) {
1025*32377Sminshall 		    flushline = 1;
1026*32377Sminshall 		    break;
102727186Sminshall 		}
1028*32377Sminshall 		c = *tbp++ & 0xff, sc = strip(c), tcc--;
1029*32377Sminshall 		if (sc == escape) {
1030*32377Sminshall 		    command(0);
1031*32377Sminshall 		    tcc = 0;
1032*32377Sminshall 		    flushline = 1;
1033*32377Sminshall 		    break;
1034*32377Sminshall 		} else if (MODE_LINE(globalmode) && (sc == echoc)) {
1035*32377Sminshall 		    if (tcc > 0 && strip(*tbp) == echoc) {
1036*32377Sminshall 			tbp++;
1037*32377Sminshall 			tcc--;
1038*32377Sminshall 		    } else {
1039*32377Sminshall 			dontlecho = !dontlecho;
1040*32377Sminshall 			settimer(echotoggle);
1041*32377Sminshall 			setconnmode();
1042*32377Sminshall 			tcc = 0;
1043*32377Sminshall 			flushline = 1;
1044*32377Sminshall 			break;
1045*32377Sminshall 		    }
104627186Sminshall 		}
1047*32377Sminshall 		if (localchars) {
1048*32377Sminshall 		    if (TerminalSpecialChars(sc) == 0) {
1049*32377Sminshall 			break;
1050*32377Sminshall 		    }
1051*32377Sminshall 		}
1052*32377Sminshall 		if (!myopts[TELOPT_BINARY]) {
1053*32377Sminshall 		    switch (c) {
1054*32377Sminshall 		    case '\n':
1055*32377Sminshall 			    /*
1056*32377Sminshall 			     * If we are in CRMOD mode (\r ==> \n)
1057*32377Sminshall 			     * on our local machine, then probably
1058*32377Sminshall 			     * a newline (unix) is CRLF (TELNET).
1059*32377Sminshall 			     */
1060*32377Sminshall 			if (MODE_LOCAL_CHARS(globalmode)) {
1061*32377Sminshall 			    NETADD('\r');
1062*32377Sminshall 			}
1063*32377Sminshall 			NETADD('\n');
1064*32377Sminshall 			flushline = 1;
1065*32377Sminshall 			break;
1066*32377Sminshall 		    case '\r':
1067*32377Sminshall 			if (!crlf) {
1068*32377Sminshall 			    NET2ADD('\r', '\0');
1069*32377Sminshall 			} else {
1070*32377Sminshall 			    NET2ADD('\r', '\n');
1071*32377Sminshall 			}
1072*32377Sminshall 			flushline = 1;
1073*32377Sminshall 			break;
1074*32377Sminshall 		    case IAC:
1075*32377Sminshall 			NET2ADD(IAC, IAC);
1076*32377Sminshall 			break;
1077*32377Sminshall 		    default:
1078*32377Sminshall 			NETADD(c);
1079*32377Sminshall 			break;
1080*32377Sminshall 		    }
1081*32377Sminshall 		} else if (c == IAC) {
1082*32377Sminshall 		    NET2ADD(IAC, IAC);
1083*32377Sminshall 		} else {
1084*32377Sminshall 		    NETADD(c);
1085*32377Sminshall 		}
108627178Sminshall 	    }
1087*32377Sminshall #   if defined(TN3270)
108827178Sminshall 	}
108927178Sminshall     }
1090*32377Sminshall #   endif /* defined(TN3270) */
1091*32377Sminshall 
1092*32377Sminshall     if ((!MODE_LINE(globalmode) || flushline || myopts[TELOPT_BINARY]) &&
1093*32377Sminshall 	FD_ISSET(net, &obits) && (NETBYTES() > 0)) {
1094*32377Sminshall 	FD_CLR(net, &obits);
1095*32377Sminshall 	returnValue = netflush();
1096*32377Sminshall     }
1097*32377Sminshall     if (scc > 0) {
1098*32377Sminshall #	if !defined(TN3270)
1099*32377Sminshall 	telrcv();
1100*32377Sminshall 	returnValue = 1;
1101*32377Sminshall #	else /* !defined(TN3270) */
1102*32377Sminshall 	returnValue = Push3270();
1103*32377Sminshall #	endif /* !defined(TN3270) */
1104*32377Sminshall     }
1105*32377Sminshall #if	defined(MSDOS)
1106*32377Sminshall     if (TTYBYTES())
1107*32377Sminshall #else	/* defined(MSDOS) */
1108*32377Sminshall     if (FD_ISSET(tout, &obits) && (TTYBYTES() > 0))
1109*32377Sminshall #endif	/* defined(MSDOS) */
1110*32377Sminshall 						    {
1111*32377Sminshall 	FD_CLR(tout, &obits);
1112*32377Sminshall 	returnValue = ttyflush(SYNCHing|flushout);
1113*32377Sminshall     }
1114*32377Sminshall     return returnValue;
111527178Sminshall }
111627178Sminshall 
111727178Sminshall /*
1118*32377Sminshall  * Select from tty and network...
111927088Sminshall  */
1120*32377Sminshall void
1121*32377Sminshall telnet()
112227088Sminshall {
1123*32377Sminshall #if	defined(MSDOS)
1124*32377Sminshall #define	SCHED_BLOCK	0		/* Don't block in MSDOS */
1125*32377Sminshall #else	/* defined(MSDOS) */
1126*32377Sminshall #define	SCHED_BLOCK	1
1127*32377Sminshall #endif	/* defined(MSDOS) */
112827088Sminshall 
1129*32377Sminshall #if	defined(TN3270) && defined(unix)
1130*32377Sminshall     int myPid;
1131*32377Sminshall #endif	/* defined(TN3270) */
113227088Sminshall 
1133*32377Sminshall     tout = fileno(stdout);
1134*32377Sminshall     tin = fileno(stdin);
1135*32377Sminshall     setconnmode();
1136*32377Sminshall     scc = 0;
1137*32377Sminshall     tcc = 0;
1138*32377Sminshall     FD_ZERO(&ibits);
1139*32377Sminshall     FD_ZERO(&obits);
1140*32377Sminshall     FD_ZERO(&xbits);
114127261Sminshall 
1142*32377Sminshall     NetNonblockingIO(net, 1);
114327088Sminshall 
1144*32377Sminshall #if	defined(TN3270)
1145*32377Sminshall     if (noasynch == 0) {			/* DBX can't handle! */
1146*32377Sminshall 	NetSigIO(net, 1);
1147*32377Sminshall     }
1148*32377Sminshall     NetSetPgrp(net);
1149*32377Sminshall #endif	/* defined(TN3270) */
115027088Sminshall 
115127088Sminshall 
1152*32377Sminshall #if	defined(SO_OOBINLINE) && !defined(MSDOS)
1153*32377Sminshall     SetSockOpt(net, SOL_SOCKET, SO_OOBINLINE, 1);
1154*32377Sminshall #endif	/* defined(SO_OOBINLINE) && !defined(MSDOS) */
115527088Sminshall 
1156*32377Sminshall #   if !defined(TN3270)
1157*32377Sminshall     if (telnetport) {
1158*32377Sminshall 	if (!hisopts[TELOPT_SGA]) {
1159*32377Sminshall 	    willoption(TELOPT_SGA, 0);
116027110Sminshall 	}
1161*32377Sminshall 	if (!myopts[TELOPT_TTYPE]) {
1162*32377Sminshall 	    dooption(TELOPT_TTYPE, 0);
1163*32377Sminshall 	}
116427178Sminshall     }
1165*32377Sminshall #   endif /* !defined(TN3270) */
116627088Sminshall 
1167*32377Sminshall #   if !defined(TN3270)
1168*32377Sminshall     for (;;) {
1169*32377Sminshall 	if (Scheduler(SCHED_BLOCK) == -1) {
1170*32377Sminshall 	    setcommandmode();
1171*32377Sminshall 	    return;
1172*32377Sminshall 	}
1173*32377Sminshall     }
1174*32377Sminshall #   else /* !defined(TN3270) */
1175*32377Sminshall     for (;;) {
1176*32377Sminshall 	int schedValue;
117727088Sminshall 
1178*32377Sminshall 	while (!In3270 && !shell_active) {
1179*32377Sminshall 	    if (Scheduler(SCHED_BLOCK) == -1) {
1180*32377Sminshall 		setcommandmode();
1181*32377Sminshall 		return;
1182*32377Sminshall 	    }
118327088Sminshall 	}
1184*32377Sminshall 
1185*32377Sminshall 	while ((schedValue = Scheduler(0)) != 0) {
1186*32377Sminshall 	    if (schedValue == -1) {
1187*32377Sminshall 		setcommandmode();
1188*32377Sminshall 		return;
1189*32377Sminshall 	    }
119027088Sminshall 	}
1191*32377Sminshall 		/* If there is data waiting to go out to terminal, don't
1192*32377Sminshall 		 * schedule any more data for the terminal.
1193*32377Sminshall 		 */
1194*32377Sminshall 	if (tfrontp-tbackp) {
1195*32377Sminshall 	    schedValue = 1;
119627088Sminshall 	} else {
1197*32377Sminshall 	    if (shell_active) {
1198*32377Sminshall 		if (shell_continue() == 0) {
1199*32377Sminshall 		    ConnectScreen();
120027088Sminshall 		}
1201*32377Sminshall 	    } else if (In3270) {
1202*32377Sminshall 		schedValue = DoTerminalOutput();
1203*32377Sminshall 	    }
120427088Sminshall 	}
1205*32377Sminshall 	if (schedValue && (shell_active == 0)) {
1206*32377Sminshall 	    if (Scheduler(SCHED_BLOCK) == -1) {
1207*32377Sminshall 		setcommandmode();
1208*32377Sminshall 		return;
1209*32377Sminshall 	    }
121027088Sminshall 	}
1211*32377Sminshall     }
1212*32377Sminshall #   endif /* !defined(TN3270) */
121327088Sminshall }
1214*32377Sminshall 
121527088Sminshall /*
1216*32377Sminshall  * These routines add various telnet commands to the data stream.
121727088Sminshall  */
1218*32377Sminshall 
1219*32377Sminshall void
1220*32377Sminshall xmitAO()
122127088Sminshall {
1222*32377Sminshall     NET2ADD(IAC, AO);
1223*32377Sminshall     if (autoflush) {
1224*32377Sminshall 	doflush();
1225*32377Sminshall     }
1226*32377Sminshall }
122727088Sminshall 
1228*32377Sminshall 
1229*32377Sminshall void
1230*32377Sminshall xmitEL()
123127088Sminshall {
1232*32377Sminshall     NET2ADD(IAC, EL);
123327088Sminshall }
123427088Sminshall 
1235*32377Sminshall void
1236*32377Sminshall xmitEC()
123727088Sminshall {
1238*32377Sminshall     NET2ADD(IAC, EC);
123927088Sminshall }
124027088Sminshall 
1241*32377Sminshall 
1242*32377Sminshall #if	defined(NOT43)
1243*32377Sminshall int
1244*32377Sminshall #else	/* defined(NOT43) */
1245*32377Sminshall void
1246*32377Sminshall #endif	/* defined(NOT43) */
1247*32377Sminshall dosynch()
124827088Sminshall {
1249*32377Sminshall     netclear();			/* clear the path to the network */
1250*32377Sminshall     NET2ADD(IAC, DM);
125127088Sminshall 
1252*32377Sminshall #if	defined(NOT43)
1253*32377Sminshall     return 0;
1254*32377Sminshall #endif	/* defined(NOT43) */
125527088Sminshall }
125627088Sminshall 
1257*32377Sminshall void
1258*32377Sminshall doflush()
125927088Sminshall {
1260*32377Sminshall     NET2ADD(IAC, DO);
1261*32377Sminshall     NETADD(TELOPT_TM);
1262*32377Sminshall     flushline = 1;
1263*32377Sminshall     flushout = 1;
1264*32377Sminshall     ttyflush(1);			/* Flush/drop output */
1265*32377Sminshall     /* do printoption AFTER flush, otherwise the output gets tossed... */
1266*32377Sminshall     printoption("<SENT", doopt, TELOPT_TM, 0);
126727088Sminshall }
126827088Sminshall 
1269*32377Sminshall void
1270*32377Sminshall intp()
127127088Sminshall {
1272*32377Sminshall     NET2ADD(IAC, IP);
1273*32377Sminshall     flushline = 1;
1274*32377Sminshall     if (autoflush) {
1275*32377Sminshall 	doflush();
1276*32377Sminshall     }
1277*32377Sminshall     if (autosynch) {
1278*32377Sminshall 	dosynch();
1279*32377Sminshall     }
128027088Sminshall }
128127186Sminshall 
1282*32377Sminshall void
1283*32377Sminshall sendbrk()
128427186Sminshall {
1285*32377Sminshall     NET2ADD(IAC, BREAK);
1286*32377Sminshall     flushline = 1;
1287*32377Sminshall     if (autoflush) {
1288*32377Sminshall 	doflush();
1289*32377Sminshall     }
1290*32377Sminshall     if (autosynch) {
1291*32377Sminshall 	dosynch();
1292*32377Sminshall     }
129327186Sminshall }
1294