xref: /csrg-svn/usr.bin/telnet/telnet.c (revision 32381)
111758Ssam #ifndef lint
232377Sminshall static char copyright[] =
332377Sminshall "@(#) Copyright (c) 1984-1987 Regents of the University of California.\n\
421580Sdist  All rights reserved.\n";
532377Sminshall #endif	/* not lint */
611758Ssam 
721580Sdist #ifndef lint
832377Sminshall static char sccsid[] = "@(#)telnet.c	1.2 (Berkeley) 9/25/87";
932377Sminshall #endif	/* not lint */
1021580Sdist 
119217Ssam #include <sys/types.h>
1232377Sminshall #include <sys/time.h>
139217Ssam #include <sys/socket.h>
149217Ssam 
159217Ssam #include <netinet/in.h>
169217Ssam 
1732377Sminshall #if	defined(unix)
1832377Sminshall /* By the way, we need to include curses.h before telnet.h since,
1932377Sminshall  * among other things, telnet.h #defines 'DO', which is a variable
2032377Sminshall  * declared in curses.h.
2132377Sminshall  */
2232377Sminshall #include <curses.h>
2332377Sminshall #endif	/* defined(unix) */
2432377Sminshall 
2512212Ssam #include <arpa/telnet.h>
2632377Sminshall 
2732377Sminshall #if	!defined(NOT43)
2827186Sminshall #include <arpa/inet.h>
2932377Sminshall #else	/* !defined(NOT43) */
3032377Sminshall extern unsigned long inet_addr();
3132377Sminshall extern char	*inet_ntoa();
3232377Sminshall #endif	/* !defined(NOT43) */
3312212Ssam 
346000Sroot #include <ctype.h>
356000Sroot #include <errno.h>
368345Ssam #include <netdb.h>
3732377Sminshall 
3832377Sminshall #if	defined(unix)
3927186Sminshall #include <strings.h>
4032377Sminshall #else	/* defined(unix) */
4132377Sminshall #include <string.h>
4232377Sminshall #endif	/* defined(unix) */
439217Ssam 
44*32381Sminshall #include "ring.h"
45*32381Sminshall 
4632377Sminshall #include "defines.h"
4732377Sminshall #include "externs.h"
4832377Sminshall #include "types.h"
4932377Sminshall #include "general.h"
5027178Sminshall 
5127178Sminshall 
5232377Sminshall void	setcommandmode(), command();	/* forward declarations */
5332377Sminshall 
5427676Sminshall #ifndef	FD_SETSIZE
5527178Sminshall /*
5627178Sminshall  * The following is defined just in case someone should want to run
5727178Sminshall  * this telnet on a 4.2 system.
5827178Sminshall  *
5927178Sminshall  */
6027178Sminshall 
6127676Sminshall #define	FD_SET(n, p)	((p)->fds_bits[0] |= (1<<(n)))
6227676Sminshall #define	FD_CLR(n, p)	((p)->fds_bits[0] &= ~(1<<(n)))
6327676Sminshall #define	FD_ISSET(n, p)	((p)->fds_bits[0] & (1<<(n)))
6427676Sminshall #define FD_ZERO(p)	((p)->fds_bits[0] = 0)
6527178Sminshall 
6627178Sminshall #endif
6727178Sminshall 
6827228Sminshall #define	strip(x)	((x)&0x7f)
6932377Sminshall #define min(x,y)	((x<y)? x:y)
706000Sroot 
7132377Sminshall #if	defined(TN3270)
7232377Sminshall static char	Ibuf[8*BUFSIZ], *Ifrontp, *Ibackp;
7332377Sminshall #endif	/* defined(TN3270) */
7427088Sminshall 
756000Sroot 
7632377Sminshall static char	subbuffer[SUBBUFSIZE],
7732377Sminshall 		*subpointer, *subend;	 /* buffer for sub-options */
7827676Sminshall #define	SB_CLEAR()	subpointer = subbuffer;
7927676Sminshall #define	SB_TERM()	subend = subpointer;
8027676Sminshall #define	SB_ACCUM(c)	if (subpointer < (subbuffer+sizeof subbuffer)) { \
8127676Sminshall 				*subpointer++ = (c); \
8227676Sminshall 			}
8327676Sminshall 
8432377Sminshall static char	sb_terminal[] = { IAC, SB,
8532377Sminshall 			TELOPT_TTYPE, TELQUAL_IS,
8632377Sminshall 			'I', 'B', 'M', '-', '3', '2', '7', '8', '-', '2',
8732377Sminshall 			IAC, SE };
8832377Sminshall #define	SBTERMMODEL	13
8932377Sminshall 
9032377Sminshall 
916000Sroot char	hisopts[256];
926000Sroot char	myopts[256];
936000Sroot 
946000Sroot char	doopt[] = { IAC, DO, '%', 'c', 0 };
956000Sroot char	dont[] = { IAC, DONT, '%', 'c', 0 };
966000Sroot char	will[] = { IAC, WILL, '%', 'c', 0 };
976000Sroot char	wont[] = { IAC, WONT, '%', 'c', 0 };
986000Sroot 
9932377Sminshall static char	sibuf[BUFSIZ], *sbp;
10032377Sminshall static char	tibuf[BUFSIZ], *tbp;
10132377Sminshall static fd_set ibits, obits, xbits;
10227088Sminshall 
10327088Sminshall 
10432377Sminshall int
10532377Sminshall 	connected,
10632377Sminshall 	net,
10732377Sminshall 	scc,
10832377Sminshall 	tcc,
10932377Sminshall 	showoptions,
11032377Sminshall 	In3270,		/* Are we in 3270 mode? */
11132377Sminshall 	ISend,		/* trying to send network data in */
11232377Sminshall 	debug = 0,
11332377Sminshall 	crmod,
11432377Sminshall 	netdata,	/* Print out network data flow */
11532377Sminshall 	crlf,		/* Should '\r' be mapped to <CR><LF> (or <CR><NUL>)? */
11632377Sminshall 	noasynch = 0,	/* User specified "-noasynch" on command line */
11732377Sminshall 	askedSGA = 0,	/* We have talked about suppress go ahead */
11832377Sminshall 	telnetport = 1;
11927088Sminshall 
12032377Sminshall #define	CONTROL(x)	((x)&0x1f)		/* CTRL(x) is not portable */
1216000Sroot 
12232377Sminshall char
12332377Sminshall 	*prompt = 0,
12432377Sminshall 	escape,
12532377Sminshall 	echoc;
12627186Sminshall 
12732377Sminshall int
12832377Sminshall 	SYNCHing,		/* we are in TELNET SYNCH mode */
12932377Sminshall 	flushout,		/* flush output */
13032377Sminshall 	autoflush = 0,		/* flush output when interrupting? */
13132377Sminshall 	autosynch,		/* send interrupt characters with SYNCH? */
13232377Sminshall 	localchars,		/* we recognize interrupt/quit */
13332377Sminshall 	donelclchars,		/* the user has set "localchars" */
13432377Sminshall 	donebinarytoggle,	/* the user has put us in binary */
13532377Sminshall 	dontlecho,		/* do we suppress local echoing right now? */
13632377Sminshall 	globalmode;
1376000Sroot 
13832377Sminshall /*	The following are some tn3270 specific flags */
13932377Sminshall #if	defined(TN3270)
1406000Sroot 
14132377Sminshall static int
14232377Sminshall 	Sent3270TerminalType;	/* Have we said we are a 3270? */
1436000Sroot 
14432377Sminshall #endif	/* defined(TN3270) */
14527186Sminshall int
14627186Sminshall 
14732377Sminshall 	tout,			/* Output file descriptor */
14832377Sminshall 	tin;			/* Input file descriptor */
14927186Sminshall 
15027186Sminshall 
15127186Sminshall 
15227186Sminshall /*
1536000Sroot  * Telnet receiver states for fsm
1546000Sroot  */
1556000Sroot #define	TS_DATA		0
1566000Sroot #define	TS_IAC		1
1576000Sroot #define	TS_WILL		2
1586000Sroot #define	TS_WONT		3
1596000Sroot #define	TS_DO		4
1606000Sroot #define	TS_DONT		5
16127021Sminshall #define	TS_CR		6
16227676Sminshall #define	TS_SB		7		/* sub-option collection */
16327676Sminshall #define	TS_SE		8		/* looking for sub-option end */
1646000Sroot 
16532377Sminshall static int	telrcv_state;
1666000Sroot 
16732377Sminshall jmp_buf	toplevel = { 0 };
16832377Sminshall jmp_buf	peerdied;
1696000Sroot 
17032377Sminshall int	flushline;
17127021Sminshall 
17232377Sminshall /*
17332377Sminshall  * The following are some clocks used to decide how to interpret
17432377Sminshall  * the relationship between various variables.
17532377Sminshall  */
1766000Sroot 
17732377Sminshall Clocks clocks;
17832377Sminshall 
17932377Sminshall Modelist modelist[] = {
18032377Sminshall 	{ "telnet command mode", COMMAND_LINE },
18132377Sminshall 	{ "character-at-a-time mode", 0 },
18232377Sminshall 	{ "character-at-a-time mode (local echo)", LOCAL_ECHO|LOCAL_CHARS },
18332377Sminshall 	{ "line-by-line mode (remote echo)", LINE | LOCAL_CHARS },
18432377Sminshall 	{ "line-by-line mode", LINE | LOCAL_ECHO | LOCAL_CHARS },
18532377Sminshall 	{ "line-by-line mode (local echoing suppressed)", LINE | LOCAL_CHARS },
18632377Sminshall 	{ "3270 mode", 0 },
18732377Sminshall };
1886000Sroot 
18932377Sminshall 
19032377Sminshall /*
19132377Sminshall  * Initialize telnet environment.
19232377Sminshall  */
1936000Sroot 
19432377Sminshall init_telnet()
19532377Sminshall {
19632377Sminshall     /* Don't change telnetport */
19732377Sminshall     SB_CLEAR();
19832377Sminshall     ClearArray(hisopts);
19932377Sminshall     ClearArray(myopts);
20032377Sminshall     sbp = sibuf;
20132377Sminshall     tbp = tibuf;
2026000Sroot 
20332377Sminshall     connected = net = scc = tcc = In3270 = ISend = donebinarytoggle = 0;
20432377Sminshall     telnetport = 0;
2056000Sroot 
20632377Sminshall #if	defined(unix) && defined(TN3270)
20732377Sminshall     HaveInput = 0;
20832377Sminshall #endif	/* defined(unix) && defined(TN3270) */
2096000Sroot 
21032377Sminshall     SYNCHing = 0;
2116000Sroot 
21232377Sminshall     errno = 0;
21327676Sminshall 
21432377Sminshall     /* Don't change NetTrace */
2156000Sroot 
21632377Sminshall     escape = CONTROL(']');
21732377Sminshall     echoc = CONTROL('E');
2186000Sroot 
21932377Sminshall     flushline = 1;
22032377Sminshall     telrcv_state = TS_DATA;
22132377Sminshall }
2226000Sroot 
2236000Sroot 
22432377Sminshall void
22527676Sminshall willoption(option, reply)
22627676Sminshall 	int option, reply;
2276000Sroot {
2286000Sroot 	char *fmt;
2296000Sroot 
2306000Sroot 	switch (option) {
2316000Sroot 
2326000Sroot 	case TELOPT_ECHO:
23332377Sminshall #	if defined(TN3270)
23432377Sminshall 	    /*
23532377Sminshall 	     * The following is a pain in the rear-end.
23632377Sminshall 	     * Various IBM servers (some versions of Wiscnet,
23732377Sminshall 	     * possibly Fibronics/Spartacus, and who knows who
23832377Sminshall 	     * else) will NOT allow us to send "DO SGA" too early
23932377Sminshall 	     * in the setup proceedings.  On the other hand,
24032377Sminshall 	     * 4.2 servers (telnetd) won't set SGA correctly.
24132377Sminshall 	     * So, we are stuck.  Empirically (but, based on
24232377Sminshall 	     * a VERY small sample), the IBM servers don't send
24332377Sminshall 	     * out anything about ECHO, so we postpone our sending
24432377Sminshall 	     * "DO SGA" until we see "WILL ECHO" (which 4.2 servers
24532377Sminshall 	     * DO send).
24632377Sminshall 	     */
24732377Sminshall 	    {
24832377Sminshall 		if (askedSGA == 0) {
24932377Sminshall 		    askedSGA = 1;
25032377Sminshall 		    if (!hisopts[TELOPT_SGA]) {
25132377Sminshall 			willoption(TELOPT_SGA, 0);
25232377Sminshall 		    }
25332377Sminshall 		}
25432377Sminshall 	    }
25532377Sminshall 		/* Fall through */
25632377Sminshall 	case TELOPT_EOR:
25732377Sminshall 	case TELOPT_BINARY:
25832377Sminshall #endif	/* defined(TN3270) */
2596000Sroot 	case TELOPT_SGA:
26027110Sminshall 		settimer(modenegotiated);
2616000Sroot 		hisopts[option] = 1;
2626000Sroot 		fmt = doopt;
26327110Sminshall 		setconnmode();		/* possibly set new tty mode */
2646000Sroot 		break;
2656000Sroot 
2666000Sroot 	case TELOPT_TM:
26727110Sminshall 		return;			/* Never reply to TM will's/wont's */
2686000Sroot 
2696000Sroot 	default:
2706000Sroot 		fmt = dont;
2716000Sroot 		break;
2726000Sroot 	}
273*32381Sminshall 	netoprint(fmt, option);
27427676Sminshall 	if (reply)
27532377Sminshall 		printoption(">SENT", fmt, option, reply);
27627676Sminshall 	else
27732377Sminshall 		printoption("<SENT", fmt, option, reply);
2786000Sroot }
2796000Sroot 
28032377Sminshall void
28127676Sminshall wontoption(option, reply)
28227676Sminshall 	int option, reply;
2836000Sroot {
2846000Sroot 	char *fmt;
2856000Sroot 
2866000Sroot 	switch (option) {
2876000Sroot 
2886000Sroot 	case TELOPT_ECHO:
2896000Sroot 	case TELOPT_SGA:
29027110Sminshall 		settimer(modenegotiated);
2916000Sroot 		hisopts[option] = 0;
2926000Sroot 		fmt = dont;
29327110Sminshall 		setconnmode();			/* Set new tty mode */
2946000Sroot 		break;
2956000Sroot 
29627110Sminshall 	case TELOPT_TM:
29727110Sminshall 		return;		/* Never reply to TM will's/wont's */
29827110Sminshall 
2996000Sroot 	default:
3006000Sroot 		fmt = dont;
3016000Sroot 	}
302*32381Sminshall 	netoprint(fmt, option);
30327676Sminshall 	if (reply)
30432377Sminshall 		printoption(">SENT", fmt, option, reply);
30527676Sminshall 	else
30632377Sminshall 		printoption("<SENT", fmt, option, reply);
3076000Sroot }
3086000Sroot 
30932377Sminshall static void
3106000Sroot dooption(option)
3116000Sroot 	int option;
3126000Sroot {
3136000Sroot 	char *fmt;
3146000Sroot 
3156000Sroot 	switch (option) {
3166000Sroot 
3176000Sroot 	case TELOPT_TM:
31813231Ssam 		fmt = will;
31913231Ssam 		break;
32013231Ssam 
32132377Sminshall #	if defined(TN3270)
32232377Sminshall 	case TELOPT_EOR:
32332377Sminshall 	case TELOPT_BINARY:
32432377Sminshall #	endif	/* defined(TN3270) */
32527676Sminshall 	case TELOPT_TTYPE:		/* terminal type option */
32627110Sminshall 	case TELOPT_SGA:		/* no big deal */
3276000Sroot 		fmt = will;
32827110Sminshall 		myopts[option] = 1;
3296000Sroot 		break;
3306000Sroot 
33127110Sminshall 	case TELOPT_ECHO:		/* We're never going to echo... */
3326000Sroot 	default:
3336000Sroot 		fmt = wont;
3346000Sroot 		break;
3356000Sroot 	}
336*32381Sminshall 	netoprint(fmt, option);
33732377Sminshall 	printoption(">SENT", fmt, option, 0);
3386000Sroot }
33927676Sminshall 
34027676Sminshall /*
34127676Sminshall  * suboption()
34227676Sminshall  *
34327676Sminshall  *	Look at the sub-option buffer, and try to be helpful to the other
34427676Sminshall  * side.
34527676Sminshall  *
34627676Sminshall  *	Currently we recognize:
34727676Sminshall  *
34827676Sminshall  *		Terminal type, send request.
34927676Sminshall  */
35027676Sminshall 
35132377Sminshall static void
35227676Sminshall suboption()
35327676Sminshall {
35432377Sminshall     printsub("<", subbuffer, subend-subbuffer+1);
35527676Sminshall     switch (subbuffer[0]&0xff) {
35627676Sminshall     case TELOPT_TTYPE:
35727676Sminshall 	if ((subbuffer[1]&0xff) != TELQUAL_SEND) {
35827676Sminshall 	    ;
35927676Sminshall 	} else {
36027676Sminshall 	    char *name;
36127676Sminshall 	    char namebuf[41];
36232377Sminshall 	    extern char *getenv();
36327676Sminshall 	    int len;
36427676Sminshall 
36532377Sminshall #if	defined(TN3270)
36632377Sminshall 	    /*
36732377Sminshall 	     * Try to send a 3270 type terminal name.  Decide which one based
36832377Sminshall 	     * on the format of our screen, and (in the future) color
36932377Sminshall 	     * capaiblities.
37032377Sminshall 	     */
37132377Sminshall #if	defined(unix)
37232377Sminshall 	    if (initscr() != ERR) {	/* Initialize curses to get line size */
37332377Sminshall 		MaxNumberLines = LINES;
37432377Sminshall 		MaxNumberColumns = COLS;
37532377Sminshall 	    }
37632377Sminshall #else	/* defined(unix) */
37732377Sminshall 	    InitTerminal();
37832377Sminshall #endif	/* defined(unix) */
37932377Sminshall 	    if ((MaxNumberLines >= 24) && (MaxNumberColumns >= 80)) {
38032377Sminshall 		Sent3270TerminalType = 1;
38132377Sminshall 		if ((MaxNumberLines >= 27) && (MaxNumberColumns >= 132)) {
38232377Sminshall 		    MaxNumberLines = 27;
38332377Sminshall 		    MaxNumberColumns = 132;
38432377Sminshall 		    sb_terminal[SBTERMMODEL] = '5';
38532377Sminshall 		} else if (MaxNumberLines >= 43) {
38632377Sminshall 		    MaxNumberLines = 43;
38732377Sminshall 		    MaxNumberColumns = 80;
38832377Sminshall 		    sb_terminal[SBTERMMODEL] = '4';
38932377Sminshall 		} else if (MaxNumberLines >= 32) {
39032377Sminshall 		    MaxNumberLines = 32;
39132377Sminshall 		    MaxNumberColumns = 80;
39232377Sminshall 		    sb_terminal[SBTERMMODEL] = '3';
39332377Sminshall 		} else {
39432377Sminshall 		    MaxNumberLines = 24;
39532377Sminshall 		    MaxNumberColumns = 80;
39632377Sminshall 		    sb_terminal[SBTERMMODEL] = '2';
39732377Sminshall 		}
39832377Sminshall 		NumberLines = 24;		/* before we start out... */
39932377Sminshall 		NumberColumns = 80;
40032377Sminshall 		ScreenSize = NumberLines*NumberColumns;
40132377Sminshall 		if ((MaxNumberLines*MaxNumberColumns) > MAXSCREENSIZE) {
402*32381Sminshall 		    ExitString("Programming error:  MAXSCREENSIZE too small.\n",
403*32381Sminshall 									1);
40432377Sminshall 		    /*NOTREACHED*/
40532377Sminshall 		}
406*32381Sminshall 		printsub(">", sb_terminal+2, sizeof sb_terminal-2);
407*32381Sminshall 		ring_add_data(&netoring, sb_terminal, sizeof sb_terminal);
40832377Sminshall 		return;
40932377Sminshall 	    }
41032377Sminshall #endif	/* defined(TN3270) */
41132377Sminshall 
41227676Sminshall 	    name = getenv("TERM");
41327676Sminshall 	    if ((name == 0) || ((len = strlen(name)) > 40)) {
41427676Sminshall 		name = "UNKNOWN";
41527676Sminshall 	    }
41627676Sminshall 	    if ((len + 4+2) < NETROOM()) {
41727676Sminshall 		strcpy(namebuf, name);
41827676Sminshall 		upcase(namebuf);
419*32381Sminshall 		netoprint("%c%c%c%c%s%c%c", IAC, SB, TELOPT_TTYPE,
42027676Sminshall 				    TELQUAL_IS, namebuf, IAC, SE);
421*32381Sminshall 		/* XXX */
422*32381Sminshall 		/* printsub(">", nfrontp+2, 4+strlen(namebuf)+2-2-2); */
42332377Sminshall 	    } else {
424*32381Sminshall 		ExitString("No room in buffer for terminal type.\n",
42532377Sminshall 							1);
42632377Sminshall 		/*NOTREACHED*/
42727676Sminshall 	    }
42827676Sminshall 	}
42927676Sminshall 
43027676Sminshall     default:
43127676Sminshall 	break;
43227676Sminshall     }
43327676Sminshall }
43427088Sminshall 
43532377Sminshall #if	defined(TN3270)
43632377Sminshall static void
43732377Sminshall SetIn3270()
43827088Sminshall {
43932377Sminshall     if (Sent3270TerminalType && myopts[TELOPT_BINARY]
44032377Sminshall 			    && hisopts[TELOPT_BINARY] && !donebinarytoggle) {
44132377Sminshall 	if (!In3270) {
44232377Sminshall 	    In3270 = 1;
44332377Sminshall 	    Init3270();		/* Initialize 3270 functions */
44432377Sminshall 	    /* initialize terminal key mapping */
44532377Sminshall 	    InitTerminal();	/* Start terminal going */
44632377Sminshall 	    setconnmode();
44732377Sminshall 	}
44832377Sminshall     } else {
44932377Sminshall 	if (In3270) {
45032377Sminshall 	    StopScreen(1);
45132377Sminshall 	    In3270 = 0;
45232377Sminshall 	    Stop3270();		/* Tell 3270 we aren't here anymore */
45332377Sminshall 	    setconnmode();
45432377Sminshall 	}
45527228Sminshall     }
45627088Sminshall }
45732377Sminshall #endif	/* defined(TN3270) */
45832377Sminshall 
45927088Sminshall 
46032377Sminshall static void
46132377Sminshall telrcv()
46227110Sminshall {
46332377Sminshall     register int c;
46432377Sminshall     static int telrcv_state = TS_DATA;
46532377Sminshall #   if defined(TN3270)
46632377Sminshall     register int Scc;
46732377Sminshall     register char *Sbp;
46832377Sminshall #   endif /* defined(TN3270) */
46927088Sminshall 
47032377Sminshall     while ((scc > 0) && (TTYROOM() > 2)) {
47132377Sminshall 	c = *sbp++ & 0xff, scc--;
47232377Sminshall 	switch (telrcv_state) {
47327110Sminshall 
47432377Sminshall 	case TS_CR:
47532377Sminshall 	    telrcv_state = TS_DATA;
47632377Sminshall 	    if (c == '\0') {
47732377Sminshall 		break;	/* Ignore \0 after CR */
47832377Sminshall 	    } else if (c == '\n') {
47932377Sminshall 		if (hisopts[TELOPT_ECHO] && !crmod) {
48032377Sminshall 		    TTYADD(c);
48132377Sminshall 		}
48232377Sminshall 		break;
48332377Sminshall 	    }
48432377Sminshall 	    /* Else, fall through */
48527088Sminshall 
48632377Sminshall 	case TS_DATA:
48732377Sminshall 	    if (c == IAC) {
48832377Sminshall 		telrcv_state = TS_IAC;
48932377Sminshall 		continue;
49032377Sminshall 	    }
49132377Sminshall #	    if defined(TN3270)
49232377Sminshall 	    if (In3270) {
49332377Sminshall 		*Ifrontp++ = c;
49432377Sminshall 		Sbp = sbp;
49532377Sminshall 		Scc = scc;
49632377Sminshall 		while (Scc > 0) {
49732377Sminshall 		    c = *Sbp++ & 0377, Scc--;
49832377Sminshall 		    if (c == IAC) {
49932377Sminshall 			telrcv_state = TS_IAC;
50032377Sminshall 			break;
50132377Sminshall 		    }
50232377Sminshall 		    *Ifrontp++ = c;
50332377Sminshall 		}
50432377Sminshall 		sbp = Sbp;
50532377Sminshall 		scc = Scc;
50632377Sminshall 	    } else
50732377Sminshall #	    endif /* defined(TN3270) */
50832377Sminshall 		    /*
50932377Sminshall 		     * The 'crmod' hack (see following) is needed
51032377Sminshall 		     * since we can't * set CRMOD on output only.
51132377Sminshall 		     * Machines like MULTICS like to send \r without
51232377Sminshall 		     * \n; since we must turn off CRMOD to get proper
51332377Sminshall 		     * input, the mapping is done here (sigh).
51432377Sminshall 		     */
51532377Sminshall 	    if ((c == '\r') && !hisopts[TELOPT_BINARY]) {
51632377Sminshall 		if (scc > 0) {
51732377Sminshall 		    c = *sbp&0xff;
51832377Sminshall 		    if (c == 0) {
51932377Sminshall 			sbp++, scc--;
52032377Sminshall 			/* a "true" CR */
52132377Sminshall 			TTYADD('\r');
52232377Sminshall 		    } else if (!hisopts[TELOPT_ECHO] &&
52332377Sminshall 					(c == '\n')) {
52432377Sminshall 			sbp++, scc--;
52532377Sminshall 			TTYADD('\n');
52632377Sminshall 		    } else {
52732377Sminshall 			TTYADD('\r');
52832377Sminshall 			if (crmod) {
52932377Sminshall 				TTYADD('\n');
53032377Sminshall 			}
53132377Sminshall 		    }
53232377Sminshall 		} else {
53332377Sminshall 		    telrcv_state = TS_CR;
53432377Sminshall 		    TTYADD('\r');
53532377Sminshall 		    if (crmod) {
53632377Sminshall 			    TTYADD('\n');
53732377Sminshall 		    }
53832377Sminshall 		}
53932377Sminshall 	    } else {
54032377Sminshall 		TTYADD(c);
54132377Sminshall 	    }
54232377Sminshall 	    continue;
54327088Sminshall 
54432377Sminshall 	case TS_IAC:
54532377Sminshall 	    switch (c) {
54632377Sminshall 
54732377Sminshall 	    case WILL:
54832377Sminshall 		telrcv_state = TS_WILL;
54932377Sminshall 		continue;
55027261Sminshall 
55132377Sminshall 	    case WONT:
55232377Sminshall 		telrcv_state = TS_WONT;
55332377Sminshall 		continue;
55427261Sminshall 
55532377Sminshall 	    case DO:
55632377Sminshall 		telrcv_state = TS_DO;
55732377Sminshall 		continue;
55827261Sminshall 
55932377Sminshall 	    case DONT:
56032377Sminshall 		telrcv_state = TS_DONT;
56132377Sminshall 		continue;
56227261Sminshall 
56332377Sminshall 	    case DM:
56432377Sminshall 		    /*
56532377Sminshall 		     * We may have missed an urgent notification,
56632377Sminshall 		     * so make sure we flush whatever is in the
56732377Sminshall 		     * buffer currently.
56832377Sminshall 		     */
56932377Sminshall 		SYNCHing = 1;
57032377Sminshall 		ttyflush(1);
57132377Sminshall 		SYNCHing = stilloob(net);
57232377Sminshall 		settimer(gotDM);
57332377Sminshall 		break;
57427088Sminshall 
57532377Sminshall 	    case NOP:
57632377Sminshall 	    case GA:
57732377Sminshall 		break;
57827088Sminshall 
57932377Sminshall 	    case SB:
58032377Sminshall 		SB_CLEAR();
58132377Sminshall 		telrcv_state = TS_SB;
58232377Sminshall 		continue;
58327261Sminshall 
58432377Sminshall #	    if defined(TN3270)
58532377Sminshall 	    case EOR:
58632377Sminshall 		if (In3270) {
58732377Sminshall 		    Ibackp += DataFromNetwork(Ibackp, Ifrontp-Ibackp, 1);
58832377Sminshall 		    if (Ibackp == Ifrontp) {
58932377Sminshall 			Ibackp = Ifrontp = Ibuf;
59032377Sminshall 			ISend = 0;	/* should have been! */
59132377Sminshall 		    } else {
59232377Sminshall 			ISend = 1;
59327088Sminshall 		    }
59427088Sminshall 		}
59527088Sminshall 		break;
59632377Sminshall #	    endif /* defined(TN3270) */
59732377Sminshall 
59832377Sminshall 	    case IAC:
59932377Sminshall #	    if !defined(TN3270)
60032377Sminshall 		TTYADD(IAC);
60132377Sminshall #	    else /* !defined(TN3270) */
60232377Sminshall 		if (In3270) {
60332377Sminshall 		    *Ifrontp++ = IAC;
60432377Sminshall 		} else {
60532377Sminshall 		    TTYADD(IAC);
60632377Sminshall 		}
60732377Sminshall #	    endif /* !defined(TN3270) */
60827088Sminshall 		break;
60932377Sminshall 
61027088Sminshall 	    default:
61127088Sminshall 		break;
61227088Sminshall 	    }
61332377Sminshall 	    telrcv_state = TS_DATA;
61432377Sminshall 	    continue;
61527088Sminshall 
61632377Sminshall 	case TS_WILL:
61732377Sminshall 	    printoption(">RCVD", will, c, !hisopts[c]);
61832377Sminshall 	    if (c == TELOPT_TM) {
61932377Sminshall 		if (flushout) {
62032377Sminshall 		    flushout = 0;
62132377Sminshall 		}
62232377Sminshall 	    } else if (!hisopts[c]) {
62332377Sminshall 		willoption(c, 1);
62432377Sminshall 	    }
62532377Sminshall 	    SetIn3270();
62632377Sminshall 	    telrcv_state = TS_DATA;
62732377Sminshall 	    continue;
62827110Sminshall 
62932377Sminshall 	case TS_WONT:
63032377Sminshall 	    printoption(">RCVD", wont, c, hisopts[c]);
63132377Sminshall 	    if (c == TELOPT_TM) {
63232377Sminshall 		if (flushout) {
63332377Sminshall 		    flushout = 0;
63432377Sminshall 		}
63532377Sminshall 	    } else if (hisopts[c]) {
63632377Sminshall 		wontoption(c, 1);
63732377Sminshall 	    }
63832377Sminshall 	    SetIn3270();
63932377Sminshall 	    telrcv_state = TS_DATA;
64032377Sminshall 	    continue;
64127088Sminshall 
64232377Sminshall 	case TS_DO:
64332377Sminshall 	    printoption(">RCVD", doopt, c, !myopts[c]);
64432377Sminshall 	    if (!myopts[c])
64532377Sminshall 		dooption(c);
64632377Sminshall 	    SetIn3270();
64732377Sminshall 	    telrcv_state = TS_DATA;
64832377Sminshall 	    continue;
64927088Sminshall 
65032377Sminshall 	case TS_DONT:
65132377Sminshall 	    printoption(">RCVD", dont, c, myopts[c]);
65232377Sminshall 	    if (myopts[c]) {
65332377Sminshall 		myopts[c] = 0;
654*32381Sminshall 		netoprint(wont, c);
65532377Sminshall 		flushline = 1;
65632377Sminshall 		setconnmode();	/* set new tty mode (maybe) */
65732377Sminshall 		printoption(">SENT", wont, c, 0);
65832377Sminshall 	    }
65932377Sminshall 	    SetIn3270();
66032377Sminshall 	    telrcv_state = TS_DATA;
66132377Sminshall 	    continue;
66227088Sminshall 
66332377Sminshall 	case TS_SB:
66432377Sminshall 	    if (c == IAC) {
66532377Sminshall 		telrcv_state = TS_SE;
66632377Sminshall 	    } else {
66732377Sminshall 		SB_ACCUM(c);
66832377Sminshall 	    }
66932377Sminshall 	    continue;
67027088Sminshall 
67132377Sminshall 	case TS_SE:
67232377Sminshall 	    if (c != SE) {
67332377Sminshall 		if (c != IAC) {
67432377Sminshall 		    SB_ACCUM(IAC);
67532377Sminshall 		}
67632377Sminshall 		SB_ACCUM(c);
67732377Sminshall 		telrcv_state = TS_SB;
67832377Sminshall 	    } else {
67932377Sminshall 		SB_TERM();
68032377Sminshall 		suboption();	/* handle sub-option */
68132377Sminshall 		SetIn3270();
68232377Sminshall 		telrcv_state = TS_DATA;
68332377Sminshall 	    }
68427088Sminshall 	}
68527088Sminshall     }
68627088Sminshall }
68732377Sminshall 
68832377Sminshall #if	defined(TN3270)
68932377Sminshall static void
69032377Sminshall SetForExit()
69132377Sminshall {
69232377Sminshall     setconnmode();
69332377Sminshall     if (In3270) {
69432377Sminshall 	Finish3270();
69532377Sminshall     }
69632377Sminshall     setcommandmode();
69732377Sminshall     fflush(stdout);
69832377Sminshall     fflush(stderr);
69932377Sminshall     if (In3270) {
70032377Sminshall 	StopScreen(1);
70132377Sminshall     }
70232377Sminshall     setconnmode();
70332377Sminshall     setcommandmode();
70432377Sminshall }
70527088Sminshall 
70632377Sminshall static void
70732377Sminshall Exit(returnCode)
70832377Sminshall int returnCode;
70927088Sminshall {
71032377Sminshall     SetForExit();
71132377Sminshall     exit(returnCode);
71227088Sminshall }
71327088Sminshall 
71432377Sminshall void
715*32381Sminshall ExitString(string, returnCode)
71632377Sminshall char *string;
71732377Sminshall int returnCode;
71827088Sminshall {
71932377Sminshall     SetForExit();
720*32381Sminshall     fwrite(string, 1, strlen(string), stderr);
72132377Sminshall     exit(returnCode);
72227088Sminshall }
72327088Sminshall 
72432377Sminshall void
72532377Sminshall ExitPerror(string, returnCode)
72632377Sminshall char *string;
72732377Sminshall int returnCode;
72827088Sminshall {
72932377Sminshall     SetForExit();
73032377Sminshall     perror(string);
73132377Sminshall     exit(returnCode);
73232377Sminshall }
73332377Sminshall #endif	/* defined(TN3270) */
73427088Sminshall 
73527088Sminshall 
73627088Sminshall /*
73732377Sminshall  * Scheduler()
73832377Sminshall  *
73932377Sminshall  * Try to do something.
74032377Sminshall  *
74132377Sminshall  * If we do something useful, return 1; else return 0.
74232377Sminshall  *
74327110Sminshall  */
74427110Sminshall 
74527110Sminshall 
74632377Sminshall int
74732377Sminshall Scheduler(block)
74832377Sminshall int	block;			/* should we block in the select ? */
74927110Sminshall {
75032377Sminshall     register int c;
75132377Sminshall 		/* One wants to be a bit careful about setting returnValue
75232377Sminshall 		 * to one, since a one implies we did some useful work,
75332377Sminshall 		 * and therefore probably won't be called to block next
75432377Sminshall 		 * time (TN3270 mode only).
75532377Sminshall 		 */
75632377Sminshall     int returnValue = 0;
75732377Sminshall     static struct timeval TimeValue = { 0 };
75827110Sminshall 
75932377Sminshall     if (scc < 0 && tcc < 0) {
76032377Sminshall 	return -1;
76127110Sminshall     }
76227110Sminshall 
76332377Sminshall     if ((!MODE_LINE(globalmode) || flushline) && NETBYTES()) {
76432377Sminshall 	FD_SET(net, &obits);
76532377Sminshall     }
76632377Sminshall #if	!defined(MSDOS)
76732377Sminshall     if (TTYBYTES()) {
76832377Sminshall 	FD_SET(tout, &obits);
76927110Sminshall     }
77032377Sminshall #if	defined(TN3270)
77132377Sminshall     if ((tcc == 0) && NETROOM() && (shell_active == 0)) {
77232377Sminshall 	FD_SET(tin, &ibits);
77327110Sminshall     }
77432377Sminshall #else	/* defined(TN3270) */
77532377Sminshall     if ((tcc == 0) && NETROOM()) {
77632377Sminshall 	FD_SET(tin, &ibits);
77727110Sminshall     }
77832377Sminshall #endif	/* defined(TN3270) */
77932377Sminshall #endif	/* !defined(MSDOS) */
78032377Sminshall #   if !defined(TN3270)
78132377Sminshall     if (TTYROOM()) {
78232377Sminshall 	FD_SET(net, &ibits);
78327110Sminshall     }
78432377Sminshall #   else /* !defined(TN3270) */
78532377Sminshall     if (!ISend && TTYROOM()) {
78632377Sminshall 	FD_SET(net, &ibits);
78727110Sminshall     }
78832377Sminshall #   endif /* !defined(TN3270) */
78932377Sminshall     if (!SYNCHing) {
79032377Sminshall 	FD_SET(net, &xbits);
79132377Sminshall     }
79232377Sminshall #   if defined(TN3270) && defined(unix)
79332377Sminshall     if (HaveInput) {
79432377Sminshall 	HaveInput = 0;
79532377Sminshall 	signal(SIGIO, inputAvailable);
79632377Sminshall     }
79732377Sminshall #endif	/* defined(TN3270) && defined(unix) */
79832377Sminshall     if ((c = select(16, &ibits, &obits, &xbits,
79932377Sminshall 			block? (struct timeval *)0 : &TimeValue)) < 0) {
80032377Sminshall 	if (c == -1) {
80132377Sminshall 		    /*
80232377Sminshall 		     * we can get EINTR if we are in line mode,
80332377Sminshall 		     * and the user does an escape (TSTP), or
80432377Sminshall 		     * some other signal generator.
80532377Sminshall 		     */
80632377Sminshall 	    if (errno == EINTR) {
80732377Sminshall 		return 0;
80832377Sminshall 	    }
80932377Sminshall #	    if defined(TN3270)
81032377Sminshall 		    /*
81132377Sminshall 		     * we can get EBADF if we were in transparent
81232377Sminshall 		     * mode, and the transcom process died.
81332377Sminshall 		    */
81432377Sminshall 	    if (errno == EBADF) {
81532377Sminshall 			/*
81632377Sminshall 			 * zero the bits (even though kernel does it)
81732377Sminshall 			 * to make sure we are selecting on the right
81832377Sminshall 			 * ones.
81932377Sminshall 			*/
82032377Sminshall 		FD_ZERO(&ibits);
82132377Sminshall 		FD_ZERO(&obits);
82232377Sminshall 		FD_ZERO(&xbits);
82332377Sminshall 		return 0;
82432377Sminshall 	    }
82532377Sminshall #	    endif /* defined(TN3270) */
82632377Sminshall 		    /* I don't like this, does it ever happen? */
82732377Sminshall 	    printf("sleep(5) from telnet, after select\r\n");
82832377Sminshall #if	defined(unix)
82932377Sminshall 	    sleep(5);
83032377Sminshall #endif	/* defined(unix) */
83127110Sminshall 	}
83227261Sminshall 	return 0;
83327110Sminshall     }
83432377Sminshall 
83532377Sminshall     /*
83632377Sminshall      * Any urgent data?
83732377Sminshall      */
83832377Sminshall     if (FD_ISSET(net, &xbits)) {
83932377Sminshall 	FD_CLR(net, &xbits);
84032377Sminshall 	SYNCHing = 1;
84132377Sminshall 	ttyflush(1);	/* flush already enqueued data */
84227110Sminshall     }
84327178Sminshall 
84432377Sminshall     /*
84532377Sminshall      * Something to read from the network...
84632377Sminshall      */
84732377Sminshall     if (FD_ISSET(net, &ibits)) {
84832377Sminshall 	int canread;
84927178Sminshall 
85032377Sminshall 	FD_CLR(net, &ibits);
85132377Sminshall 	if (scc == 0) {
85232377Sminshall 	    sbp = sibuf;
85332377Sminshall 	}
85432377Sminshall 	canread = sibuf + sizeof sibuf - (sbp+scc);
85532377Sminshall #if	!defined(SO_OOBINLINE)
85632377Sminshall 	    /*
85732377Sminshall 	     * In 4.2 (and some early 4.3) systems, the
85832377Sminshall 	     * OOB indication and data handling in the kernel
85932377Sminshall 	     * is such that if two separate TCP Urgent requests
86032377Sminshall 	     * come in, one byte of TCP data will be overlaid.
86132377Sminshall 	     * This is fatal for Telnet, but we try to live
86232377Sminshall 	     * with it.
86332377Sminshall 	     *
86432377Sminshall 	     * In addition, in 4.2 (and...), a special protocol
86532377Sminshall 	     * is needed to pick up the TCP Urgent data in
86632377Sminshall 	     * the correct sequence.
86732377Sminshall 	     *
86832377Sminshall 	     * What we do is:  if we think we are in urgent
86932377Sminshall 	     * mode, we look to see if we are "at the mark".
87032377Sminshall 	     * If we are, we do an OOB receive.  If we run
87132377Sminshall 	     * this twice, we will do the OOB receive twice,
87232377Sminshall 	     * but the second will fail, since the second
87332377Sminshall 	     * time we were "at the mark", but there wasn't
87432377Sminshall 	     * any data there (the kernel doesn't reset
87532377Sminshall 	     * "at the mark" until we do a normal read).
87632377Sminshall 	     * Once we've read the OOB data, we go ahead
87732377Sminshall 	     * and do normal reads.
87832377Sminshall 	     *
87932377Sminshall 	     * There is also another problem, which is that
88032377Sminshall 	     * since the OOB byte we read doesn't put us
88132377Sminshall 	     * out of OOB state, and since that byte is most
88232377Sminshall 	     * likely the TELNET DM (data mark), we would
88332377Sminshall 	     * stay in the TELNET SYNCH (SYNCHing) state.
88432377Sminshall 	     * So, clocks to the rescue.  If we've "just"
88532377Sminshall 	     * received a DM, then we test for the
88632377Sminshall 	     * presence of OOB data when the receive OOB
88732377Sminshall 	     * fails (and AFTER we did the normal mode read
88832377Sminshall 	     * to clear "at the mark").
88932377Sminshall 	     */
89032377Sminshall 	if (SYNCHing) {
89132377Sminshall 	    int atmark;
89232377Sminshall 
89332377Sminshall 	    ioctl(net, SIOCATMARK, (char *)&atmark);
89432377Sminshall 	    if (atmark) {
89532377Sminshall 		c = recv(net, sbp+scc, canread, MSG_OOB);
89632377Sminshall 		if ((c == -1) && (errno == EINVAL)) {
89732377Sminshall 		    c = recv(net, sbp+scc, canread, 0);
89832377Sminshall 		    if (clocks.didnetreceive < clocks.gotDM) {
89932377Sminshall 			SYNCHing = stilloob(net);
90027261Sminshall 		    }
90132377Sminshall 		}
90232377Sminshall 	    } else {
90332377Sminshall 		c = recv(net, sbp+scc, canread, 0);
90432377Sminshall 	    }
90532377Sminshall 	} else {
90632377Sminshall 	    c = recv(net, sbp+scc, canread, 0);
90732377Sminshall 	}
90832377Sminshall 	settimer(didnetreceive);
90932377Sminshall #else	/* !defined(SO_OOBINLINE) */
91032377Sminshall 	c = recv(net, sbp+scc, canread, 0);
91132377Sminshall #endif	/* !defined(SO_OOBINLINE) */
91232377Sminshall 	if (c < 0 && errno == EWOULDBLOCK) {
91332377Sminshall 	    c = 0;
91432377Sminshall 	} else if (c <= 0) {
91532377Sminshall 	    return -1;
91632377Sminshall 	}
91732377Sminshall 	if (netdata) {
91832377Sminshall 	    Dump('<', sbp+scc, c);
91932377Sminshall 	}
92032377Sminshall 	scc += c;
92132377Sminshall 	returnValue = 1;
92232377Sminshall     }
92327178Sminshall 
92432377Sminshall     /*
92532377Sminshall      * Something to read from the tty...
92632377Sminshall      */
92732377Sminshall #if	defined(MSDOS)
92832377Sminshall     if ((tcc == 0) && NETROOM() && (shell_active == 0) && TerminalCanRead())
92932377Sminshall #else	/* defined(MSDOS) */
93032377Sminshall     if (FD_ISSET(tin, &ibits))
93132377Sminshall #endif	/* defined(MSDOS) */
93232377Sminshall 				    {
93332377Sminshall 	FD_CLR(tin, &ibits);
93432377Sminshall 	if (tcc == 0) {
93532377Sminshall 	    tbp = tibuf;	/* nothing left, reset */
93627178Sminshall 	}
93732377Sminshall 	c = TerminalRead(tin, tbp, tibuf+sizeof tibuf - tbp);
93832377Sminshall 	if (c < 0 && errno == EWOULDBLOCK) {
93932377Sminshall 	    c = 0;
94032377Sminshall 	} else {
94132377Sminshall #if	defined(unix)
94232377Sminshall 	    /* EOF detection for line mode!!!! */
94332377Sminshall 	    if (c == 0 && MODE_LOCAL_CHARS(globalmode)) {
94432377Sminshall 			/* must be an EOF... */
94532377Sminshall 		*tbp = termEofChar;
94632377Sminshall 		c = 1;
94732377Sminshall 	    }
94832377Sminshall #endif	/* defined(unix) */
94932377Sminshall 	    if (c <= 0) {
95032377Sminshall 		tcc = c;
95132377Sminshall 		return -1;
95232377Sminshall 	    }
95327178Sminshall 	}
95432377Sminshall 	tcc += c;
95532377Sminshall 	returnValue = 1;		/* did something useful */
95632377Sminshall     }
95727178Sminshall 
95832377Sminshall #   if defined(TN3270)
95932377Sminshall     if (tcc > 0) {
96032377Sminshall 	if (In3270) {
96132377Sminshall 	    c = DataFromTerminal(tbp, tcc);
96232377Sminshall 	    if (c) {
96332377Sminshall 		returnValue = 1;
96432377Sminshall 	    }
96532377Sminshall 	    tcc -= c;
96632377Sminshall 	    tbp += c;
96732377Sminshall 	} else {
96832377Sminshall #   endif /* defined(TN3270) */
96932377Sminshall 	    returnValue = 1;
97032377Sminshall 	    while (tcc > 0) {
97132377Sminshall 		register int sc;
97232377Sminshall 
97332377Sminshall 		if (NETROOM() < 2) {
97432377Sminshall 		    flushline = 1;
97532377Sminshall 		    break;
97627186Sminshall 		}
97732377Sminshall 		c = *tbp++ & 0xff, sc = strip(c), tcc--;
97832377Sminshall 		if (sc == escape) {
97932377Sminshall 		    command(0);
98032377Sminshall 		    tcc = 0;
98132377Sminshall 		    flushline = 1;
98232377Sminshall 		    break;
98332377Sminshall 		} else if (MODE_LINE(globalmode) && (sc == echoc)) {
98432377Sminshall 		    if (tcc > 0 && strip(*tbp) == echoc) {
98532377Sminshall 			tbp++;
98632377Sminshall 			tcc--;
98732377Sminshall 		    } else {
98832377Sminshall 			dontlecho = !dontlecho;
98932377Sminshall 			settimer(echotoggle);
99032377Sminshall 			setconnmode();
99132377Sminshall 			tcc = 0;
99232377Sminshall 			flushline = 1;
99332377Sminshall 			break;
99432377Sminshall 		    }
99527186Sminshall 		}
99632377Sminshall 		if (localchars) {
99732377Sminshall 		    if (TerminalSpecialChars(sc) == 0) {
99832377Sminshall 			break;
99932377Sminshall 		    }
100032377Sminshall 		}
100132377Sminshall 		if (!myopts[TELOPT_BINARY]) {
100232377Sminshall 		    switch (c) {
100332377Sminshall 		    case '\n':
100432377Sminshall 			    /*
100532377Sminshall 			     * If we are in CRMOD mode (\r ==> \n)
100632377Sminshall 			     * on our local machine, then probably
100732377Sminshall 			     * a newline (unix) is CRLF (TELNET).
100832377Sminshall 			     */
100932377Sminshall 			if (MODE_LOCAL_CHARS(globalmode)) {
101032377Sminshall 			    NETADD('\r');
101132377Sminshall 			}
101232377Sminshall 			NETADD('\n');
101332377Sminshall 			flushline = 1;
101432377Sminshall 			break;
101532377Sminshall 		    case '\r':
101632377Sminshall 			if (!crlf) {
101732377Sminshall 			    NET2ADD('\r', '\0');
101832377Sminshall 			} else {
101932377Sminshall 			    NET2ADD('\r', '\n');
102032377Sminshall 			}
102132377Sminshall 			flushline = 1;
102232377Sminshall 			break;
102332377Sminshall 		    case IAC:
102432377Sminshall 			NET2ADD(IAC, IAC);
102532377Sminshall 			break;
102632377Sminshall 		    default:
102732377Sminshall 			NETADD(c);
102832377Sminshall 			break;
102932377Sminshall 		    }
103032377Sminshall 		} else if (c == IAC) {
103132377Sminshall 		    NET2ADD(IAC, IAC);
103232377Sminshall 		} else {
103332377Sminshall 		    NETADD(c);
103432377Sminshall 		}
103527178Sminshall 	    }
103632377Sminshall #   if defined(TN3270)
103727178Sminshall 	}
103827178Sminshall     }
103932377Sminshall #   endif /* defined(TN3270) */
104032377Sminshall 
104132377Sminshall     if ((!MODE_LINE(globalmode) || flushline || myopts[TELOPT_BINARY]) &&
104232377Sminshall 	FD_ISSET(net, &obits) && (NETBYTES() > 0)) {
104332377Sminshall 	FD_CLR(net, &obits);
104432377Sminshall 	returnValue = netflush();
104532377Sminshall     }
104632377Sminshall     if (scc > 0) {
104732377Sminshall #	if !defined(TN3270)
104832377Sminshall 	telrcv();
104932377Sminshall 	returnValue = 1;
105032377Sminshall #	else /* !defined(TN3270) */
105132377Sminshall 	returnValue = Push3270();
105232377Sminshall #	endif /* !defined(TN3270) */
105332377Sminshall     }
105432377Sminshall #if	defined(MSDOS)
105532377Sminshall     if (TTYBYTES())
105632377Sminshall #else	/* defined(MSDOS) */
105732377Sminshall     if (FD_ISSET(tout, &obits) && (TTYBYTES() > 0))
105832377Sminshall #endif	/* defined(MSDOS) */
105932377Sminshall 						    {
106032377Sminshall 	FD_CLR(tout, &obits);
106132377Sminshall 	returnValue = ttyflush(SYNCHing|flushout);
106232377Sminshall     }
106332377Sminshall     return returnValue;
106427178Sminshall }
106527178Sminshall 
106627178Sminshall /*
106732377Sminshall  * Select from tty and network...
106827088Sminshall  */
106932377Sminshall void
107032377Sminshall telnet()
107127088Sminshall {
107232377Sminshall #if	defined(MSDOS)
107332377Sminshall #define	SCHED_BLOCK	0		/* Don't block in MSDOS */
107432377Sminshall #else	/* defined(MSDOS) */
107532377Sminshall #define	SCHED_BLOCK	1
107632377Sminshall #endif	/* defined(MSDOS) */
107727088Sminshall 
107832377Sminshall #if	defined(TN3270) && defined(unix)
107932377Sminshall     int myPid;
108032377Sminshall #endif	/* defined(TN3270) */
108127088Sminshall 
108232377Sminshall     tout = fileno(stdout);
108332377Sminshall     tin = fileno(stdin);
108432377Sminshall     setconnmode();
108532377Sminshall     scc = 0;
108632377Sminshall     tcc = 0;
108732377Sminshall     FD_ZERO(&ibits);
108832377Sminshall     FD_ZERO(&obits);
108932377Sminshall     FD_ZERO(&xbits);
109027261Sminshall 
109132377Sminshall     NetNonblockingIO(net, 1);
109227088Sminshall 
109332377Sminshall #if	defined(TN3270)
109432377Sminshall     if (noasynch == 0) {			/* DBX can't handle! */
109532377Sminshall 	NetSigIO(net, 1);
109632377Sminshall     }
109732377Sminshall     NetSetPgrp(net);
109832377Sminshall #endif	/* defined(TN3270) */
109927088Sminshall 
110027088Sminshall 
110132377Sminshall #if	defined(SO_OOBINLINE) && !defined(MSDOS)
110232377Sminshall     SetSockOpt(net, SOL_SOCKET, SO_OOBINLINE, 1);
110332377Sminshall #endif	/* defined(SO_OOBINLINE) && !defined(MSDOS) */
110427088Sminshall 
110532377Sminshall #   if !defined(TN3270)
110632377Sminshall     if (telnetport) {
110732377Sminshall 	if (!hisopts[TELOPT_SGA]) {
110832377Sminshall 	    willoption(TELOPT_SGA, 0);
110927110Sminshall 	}
111032377Sminshall 	if (!myopts[TELOPT_TTYPE]) {
111132377Sminshall 	    dooption(TELOPT_TTYPE, 0);
111232377Sminshall 	}
111327178Sminshall     }
111432377Sminshall #   endif /* !defined(TN3270) */
111527088Sminshall 
111632377Sminshall #   if !defined(TN3270)
111732377Sminshall     for (;;) {
111832377Sminshall 	if (Scheduler(SCHED_BLOCK) == -1) {
111932377Sminshall 	    setcommandmode();
112032377Sminshall 	    return;
112132377Sminshall 	}
112232377Sminshall     }
112332377Sminshall #   else /* !defined(TN3270) */
112432377Sminshall     for (;;) {
112532377Sminshall 	int schedValue;
112627088Sminshall 
112732377Sminshall 	while (!In3270 && !shell_active) {
112832377Sminshall 	    if (Scheduler(SCHED_BLOCK) == -1) {
112932377Sminshall 		setcommandmode();
113032377Sminshall 		return;
113132377Sminshall 	    }
113227088Sminshall 	}
113332377Sminshall 
113432377Sminshall 	while ((schedValue = Scheduler(0)) != 0) {
113532377Sminshall 	    if (schedValue == -1) {
113632377Sminshall 		setcommandmode();
113732377Sminshall 		return;
113832377Sminshall 	    }
113927088Sminshall 	}
114032377Sminshall 		/* If there is data waiting to go out to terminal, don't
114132377Sminshall 		 * schedule any more data for the terminal.
114232377Sminshall 		 */
114332377Sminshall 	if (tfrontp-tbackp) {
114432377Sminshall 	    schedValue = 1;
114527088Sminshall 	} else {
114632377Sminshall 	    if (shell_active) {
114732377Sminshall 		if (shell_continue() == 0) {
114832377Sminshall 		    ConnectScreen();
114927088Sminshall 		}
115032377Sminshall 	    } else if (In3270) {
115132377Sminshall 		schedValue = DoTerminalOutput();
115232377Sminshall 	    }
115327088Sminshall 	}
115432377Sminshall 	if (schedValue && (shell_active == 0)) {
115532377Sminshall 	    if (Scheduler(SCHED_BLOCK) == -1) {
115632377Sminshall 		setcommandmode();
115732377Sminshall 		return;
115832377Sminshall 	    }
115927088Sminshall 	}
116032377Sminshall     }
116132377Sminshall #   endif /* !defined(TN3270) */
116227088Sminshall }
116332377Sminshall 
116427088Sminshall /*
116532377Sminshall  * These routines add various telnet commands to the data stream.
116627088Sminshall  */
116732377Sminshall 
116832377Sminshall void
116932377Sminshall xmitAO()
117027088Sminshall {
117132377Sminshall     NET2ADD(IAC, AO);
117232377Sminshall     if (autoflush) {
117332377Sminshall 	doflush();
117432377Sminshall     }
117532377Sminshall }
117627088Sminshall 
117732377Sminshall 
117832377Sminshall void
117932377Sminshall xmitEL()
118027088Sminshall {
118132377Sminshall     NET2ADD(IAC, EL);
118227088Sminshall }
118327088Sminshall 
118432377Sminshall void
118532377Sminshall xmitEC()
118627088Sminshall {
118732377Sminshall     NET2ADD(IAC, EC);
118827088Sminshall }
118927088Sminshall 
119032377Sminshall 
119132377Sminshall #if	defined(NOT43)
119232377Sminshall int
119332377Sminshall #else	/* defined(NOT43) */
119432377Sminshall void
119532377Sminshall #endif	/* defined(NOT43) */
119632377Sminshall dosynch()
119727088Sminshall {
119832377Sminshall     netclear();			/* clear the path to the network */
119932377Sminshall     NET2ADD(IAC, DM);
120027088Sminshall 
120132377Sminshall #if	defined(NOT43)
120232377Sminshall     return 0;
120332377Sminshall #endif	/* defined(NOT43) */
120427088Sminshall }
120527088Sminshall 
120632377Sminshall void
120732377Sminshall doflush()
120827088Sminshall {
120932377Sminshall     NET2ADD(IAC, DO);
121032377Sminshall     NETADD(TELOPT_TM);
121132377Sminshall     flushline = 1;
121232377Sminshall     flushout = 1;
121332377Sminshall     ttyflush(1);			/* Flush/drop output */
121432377Sminshall     /* do printoption AFTER flush, otherwise the output gets tossed... */
121532377Sminshall     printoption("<SENT", doopt, TELOPT_TM, 0);
121627088Sminshall }
121727088Sminshall 
121832377Sminshall void
121932377Sminshall intp()
122027088Sminshall {
122132377Sminshall     NET2ADD(IAC, IP);
122232377Sminshall     flushline = 1;
122332377Sminshall     if (autoflush) {
122432377Sminshall 	doflush();
122532377Sminshall     }
122632377Sminshall     if (autosynch) {
122732377Sminshall 	dosynch();
122832377Sminshall     }
122927088Sminshall }
123027186Sminshall 
123132377Sminshall void
123232377Sminshall sendbrk()
123327186Sminshall {
123432377Sminshall     NET2ADD(IAC, BREAK);
123532377Sminshall     flushline = 1;
123632377Sminshall     if (autoflush) {
123732377Sminshall 	doflush();
123832377Sminshall     }
123932377Sminshall     if (autosynch) {
124032377Sminshall 	dosynch();
124132377Sminshall     }
124227186Sminshall }
1243