xref: /csrg-svn/usr.bin/telnet/telnet.c (revision 37219)
133685Sbostic /*
233685Sbostic  * Copyright (c) 1988 Regents of the University of California.
333685Sbostic  * All rights reserved.
433685Sbostic  *
533685Sbostic  * Redistribution and use in source and binary forms are permitted
634898Sbostic  * provided that the above copyright notice and this paragraph are
734898Sbostic  * duplicated in all such forms and that any documentation,
834898Sbostic  * advertising materials, and other materials related to such
934898Sbostic  * distribution and use acknowledge that the software was developed
1034898Sbostic  * by the University of California, Berkeley.  The name of the
1134898Sbostic  * University may not be used to endorse or promote products derived
1234898Sbostic  * from this software without specific prior written permission.
1334898Sbostic  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
1434898Sbostic  * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
1534898Sbostic  * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
1633685Sbostic  */
1711758Ssam 
1821580Sdist #ifndef lint
19*37219Sminshall static char sccsid[] = "@(#)telnet.c	5.39 (Berkeley) 03/20/89";
2033685Sbostic #endif /* not lint */
2121580Sdist 
229217Ssam #include <sys/types.h>
239217Ssam 
2432377Sminshall #if	defined(unix)
2533804Sminshall #include <signal.h>
2632377Sminshall /* By the way, we need to include curses.h before telnet.h since,
2732377Sminshall  * among other things, telnet.h #defines 'DO', which is a variable
2832377Sminshall  * declared in curses.h.
2932377Sminshall  */
3032377Sminshall #include <curses.h>
3132377Sminshall #endif	/* defined(unix) */
3232377Sminshall 
3312212Ssam #include <arpa/telnet.h>
3432377Sminshall 
3532377Sminshall #if	defined(unix)
3627186Sminshall #include <strings.h>
3732377Sminshall #else	/* defined(unix) */
3832377Sminshall #include <string.h>
3932377Sminshall #endif	/* defined(unix) */
409217Ssam 
4132381Sminshall #include "ring.h"
4232381Sminshall 
4332377Sminshall #include "defines.h"
4432377Sminshall #include "externs.h"
4532377Sminshall #include "types.h"
4632377Sminshall #include "general.h"
4727178Sminshall 
4827178Sminshall 
4927228Sminshall #define	strip(x)	((x)&0x7f)
506000Sroot 
5127088Sminshall 
5232377Sminshall static char	subbuffer[SUBBUFSIZE],
5332377Sminshall 		*subpointer, *subend;	 /* buffer for sub-options */
5427676Sminshall #define	SB_CLEAR()	subpointer = subbuffer;
5527676Sminshall #define	SB_TERM()	subend = subpointer;
5627676Sminshall #define	SB_ACCUM(c)	if (subpointer < (subbuffer+sizeof subbuffer)) { \
5727676Sminshall 				*subpointer++ = (c); \
5827676Sminshall 			}
5927676Sminshall 
606000Sroot char	hisopts[256];
616000Sroot char	myopts[256];
626000Sroot 
636000Sroot char	doopt[] = { IAC, DO, '%', 'c', 0 };
646000Sroot char	dont[] = { IAC, DONT, '%', 'c', 0 };
656000Sroot char	will[] = { IAC, WILL, '%', 'c', 0 };
666000Sroot char	wont[] = { IAC, WONT, '%', 'c', 0 };
676000Sroot 
6832377Sminshall int
6932377Sminshall 	connected,
7032377Sminshall 	showoptions,
7132377Sminshall 	In3270,		/* Are we in 3270 mode? */
7232377Sminshall 	ISend,		/* trying to send network data in */
7332377Sminshall 	debug = 0,
7432377Sminshall 	crmod,
7532377Sminshall 	netdata,	/* Print out network data flow */
7632377Sminshall 	crlf,		/* Should '\r' be mapped to <CR><LF> (or <CR><NUL>)? */
7734848Sminshall #if	defined(TN3270)
7836241Sminshall 	noasynchtty = 0,/* User specified "-noasynch" on command line */
7936241Sminshall 	noasynchnet = 0,/* User specified "-noasynch" on command line */
8032377Sminshall 	askedSGA = 0,	/* We have talked about suppress go ahead */
8134848Sminshall #endif	/* defined(TN3270) */
8233286Sminshall 	telnetport,
8332531Sminshall 	SYNCHing,	/* we are in TELNET SYNCH mode */
8432531Sminshall 	flushout,	/* flush output */
8532531Sminshall 	autoflush = 0,	/* flush output when interrupting? */
8632531Sminshall 	autosynch,	/* send interrupt characters with SYNCH? */
87*37219Sminshall 	localflow,	/* we handle flow control locally */
8832531Sminshall 	localchars,	/* we recognize interrupt/quit */
8932531Sminshall 	donelclchars,	/* the user has set "localchars" */
9032531Sminshall 	donebinarytoggle,	/* the user has put us in binary */
9132531Sminshall 	dontlecho,	/* do we suppress local echoing right now? */
9232531Sminshall 	globalmode;
9327088Sminshall 
9432377Sminshall #define	CONTROL(x)	((x)&0x1f)		/* CTRL(x) is not portable */
956000Sroot 
9632377Sminshall char
9732377Sminshall 	*prompt = 0,
9832377Sminshall 	escape,
9932377Sminshall 	echoc;
10027186Sminshall 
10127186Sminshall /*
1026000Sroot  * Telnet receiver states for fsm
1036000Sroot  */
1046000Sroot #define	TS_DATA		0
1056000Sroot #define	TS_IAC		1
1066000Sroot #define	TS_WILL		2
1076000Sroot #define	TS_WONT		3
1086000Sroot #define	TS_DO		4
1096000Sroot #define	TS_DONT		5
11027021Sminshall #define	TS_CR		6
11127676Sminshall #define	TS_SB		7		/* sub-option collection */
11227676Sminshall #define	TS_SE		8		/* looking for sub-option end */
1136000Sroot 
11432377Sminshall static int	telrcv_state;
1156000Sroot 
11632377Sminshall jmp_buf	toplevel = { 0 };
11732377Sminshall jmp_buf	peerdied;
1186000Sroot 
11932377Sminshall int	flushline;
12027021Sminshall 
12132377Sminshall /*
12232377Sminshall  * The following are some clocks used to decide how to interpret
12332377Sminshall  * the relationship between various variables.
12432377Sminshall  */
1256000Sroot 
12632377Sminshall Clocks clocks;
12732377Sminshall 
12832377Sminshall Modelist modelist[] = {
12932377Sminshall 	{ "telnet command mode", COMMAND_LINE },
13032377Sminshall 	{ "character-at-a-time mode", 0 },
13132377Sminshall 	{ "character-at-a-time mode (local echo)", LOCAL_ECHO|LOCAL_CHARS },
13232377Sminshall 	{ "line-by-line mode (remote echo)", LINE | LOCAL_CHARS },
13332377Sminshall 	{ "line-by-line mode", LINE | LOCAL_ECHO | LOCAL_CHARS },
13432377Sminshall 	{ "line-by-line mode (local echoing suppressed)", LINE | LOCAL_CHARS },
13532377Sminshall 	{ "3270 mode", 0 },
13632377Sminshall };
1376000Sroot 
13832377Sminshall 
13932377Sminshall /*
14032377Sminshall  * Initialize telnet environment.
14132377Sminshall  */
1426000Sroot 
14332377Sminshall init_telnet()
14432377Sminshall {
14532377Sminshall     SB_CLEAR();
14632377Sminshall     ClearArray(hisopts);
14732377Sminshall     ClearArray(myopts);
1486000Sroot 
149*37219Sminshall     connected = In3270 = ISend = localflow = donebinarytoggle = 0;
1506000Sroot 
15132377Sminshall     SYNCHing = 0;
1526000Sroot 
15332377Sminshall     /* Don't change NetTrace */
1546000Sroot 
15532377Sminshall     escape = CONTROL(']');
15632377Sminshall     echoc = CONTROL('E');
1576000Sroot 
15832377Sminshall     flushline = 1;
15932377Sminshall     telrcv_state = TS_DATA;
16032377Sminshall }
16132554Sminshall 
1626000Sroot 
16332554Sminshall #include <varargs.h>
1646000Sroot 
16534848Sminshall /*VARARGS*/
16632554Sminshall static void
16732554Sminshall printring(va_alist)
16832554Sminshall va_dcl
16932554Sminshall {
17032554Sminshall     va_list ap;
17132554Sminshall     char buffer[100];		/* where things go */
17232554Sminshall     char *ptr;
17332554Sminshall     char *format;
17432554Sminshall     char *string;
17532554Sminshall     Ring *ring;
17632554Sminshall     int i;
17732554Sminshall 
17832554Sminshall     va_start(ap);
17932554Sminshall 
18032554Sminshall     ring = va_arg(ap, Ring *);
18132554Sminshall     format = va_arg(ap, char *);
18232554Sminshall     ptr = buffer;
18332554Sminshall 
18432554Sminshall     while ((i = *format++) != 0) {
18532554Sminshall 	if (i == '%') {
18632554Sminshall 	    i = *format++;
18732554Sminshall 	    switch (i) {
18832554Sminshall 	    case 'c':
18932554Sminshall 		*ptr++ = va_arg(ap, int);
19032554Sminshall 		break;
19132554Sminshall 	    case 's':
19232554Sminshall 		string = va_arg(ap, char *);
19332554Sminshall 		ring_supply_data(ring, buffer, ptr-buffer);
19432554Sminshall 		ring_supply_data(ring, string, strlen(string));
19532554Sminshall 		ptr = buffer;
19632554Sminshall 		break;
19732554Sminshall 	    case 0:
19832554Sminshall 		ExitString("printring: trailing %%.\n", 1);
19932554Sminshall 		/*NOTREACHED*/
20032554Sminshall 	    default:
20132554Sminshall 		ExitString("printring: unknown format character.\n", 1);
20232554Sminshall 		/*NOTREACHED*/
20332554Sminshall 	    }
20432554Sminshall 	} else {
20532554Sminshall 	    *ptr++ = i;
20632554Sminshall 	}
20732554Sminshall     }
20832554Sminshall     ring_supply_data(ring, buffer, ptr-buffer);
20932554Sminshall }
21032554Sminshall 
21132554Sminshall 
21232377Sminshall void
21327676Sminshall willoption(option, reply)
21427676Sminshall 	int option, reply;
2156000Sroot {
2166000Sroot 	char *fmt;
2176000Sroot 
2186000Sroot 	switch (option) {
2196000Sroot 
2206000Sroot 	case TELOPT_ECHO:
22132377Sminshall #	if defined(TN3270)
22232377Sminshall 	    /*
22332377Sminshall 	     * The following is a pain in the rear-end.
22432377Sminshall 	     * Various IBM servers (some versions of Wiscnet,
22532377Sminshall 	     * possibly Fibronics/Spartacus, and who knows who
22632377Sminshall 	     * else) will NOT allow us to send "DO SGA" too early
22732377Sminshall 	     * in the setup proceedings.  On the other hand,
22832377Sminshall 	     * 4.2 servers (telnetd) won't set SGA correctly.
22932377Sminshall 	     * So, we are stuck.  Empirically (but, based on
23032377Sminshall 	     * a VERY small sample), the IBM servers don't send
23132377Sminshall 	     * out anything about ECHO, so we postpone our sending
23232377Sminshall 	     * "DO SGA" until we see "WILL ECHO" (which 4.2 servers
23332377Sminshall 	     * DO send).
23432377Sminshall 	     */
23532377Sminshall 	    {
23632377Sminshall 		if (askedSGA == 0) {
23732377Sminshall 		    askedSGA = 1;
23832377Sminshall 		    if (!hisopts[TELOPT_SGA]) {
23932377Sminshall 			willoption(TELOPT_SGA, 0);
24032377Sminshall 		    }
24132377Sminshall 		}
24232377Sminshall 	    }
24332377Sminshall 		/* Fall through */
24432377Sminshall 	case TELOPT_EOR:
24532377Sminshall 	case TELOPT_BINARY:
24632377Sminshall #endif	/* defined(TN3270) */
2476000Sroot 	case TELOPT_SGA:
24827110Sminshall 		settimer(modenegotiated);
2496000Sroot 		hisopts[option] = 1;
2506000Sroot 		fmt = doopt;
25127110Sminshall 		setconnmode();		/* possibly set new tty mode */
2526000Sroot 		break;
2536000Sroot 
2546000Sroot 	case TELOPT_TM:
25527110Sminshall 		return;			/* Never reply to TM will's/wont's */
2566000Sroot 
2576000Sroot 	default:
2586000Sroot 		fmt = dont;
2596000Sroot 		break;
2606000Sroot 	}
26132554Sminshall 	printring(&netoring, fmt, option);
26227676Sminshall 	if (reply)
26332377Sminshall 		printoption(">SENT", fmt, option, reply);
26427676Sminshall 	else
26532377Sminshall 		printoption("<SENT", fmt, option, reply);
2666000Sroot }
2676000Sroot 
26832377Sminshall void
26927676Sminshall wontoption(option, reply)
27027676Sminshall 	int option, reply;
2716000Sroot {
2726000Sroot 	char *fmt;
2736000Sroot 
2746000Sroot 	switch (option) {
2756000Sroot 
2766000Sroot 	case TELOPT_ECHO:
2776000Sroot 	case TELOPT_SGA:
27827110Sminshall 		settimer(modenegotiated);
2796000Sroot 		hisopts[option] = 0;
2806000Sroot 		fmt = dont;
28127110Sminshall 		setconnmode();			/* Set new tty mode */
2826000Sroot 		break;
2836000Sroot 
28427110Sminshall 	case TELOPT_TM:
28527110Sminshall 		return;		/* Never reply to TM will's/wont's */
28627110Sminshall 
2876000Sroot 	default:
28836466Sminshall 		hisopts[option] = 0;
2896000Sroot 		fmt = dont;
2906000Sroot 	}
29132554Sminshall 	printring(&netoring, fmt, option);
29227676Sminshall 	if (reply)
29332377Sminshall 		printoption(">SENT", fmt, option, reply);
29427676Sminshall 	else
29532377Sminshall 		printoption("<SENT", fmt, option, reply);
2966000Sroot }
2976000Sroot 
29832377Sminshall static void
2996000Sroot dooption(option)
3006000Sroot 	int option;
3016000Sroot {
3026000Sroot 	char *fmt;
3036000Sroot 
3046000Sroot 	switch (option) {
3056000Sroot 
3066000Sroot 	case TELOPT_TM:
30713231Ssam 		fmt = will;
30813231Ssam 		break;
30913231Ssam 
31032377Sminshall #	if defined(TN3270)
311*37219Sminshall 	case TELOPT_EOR:		/* end of record */
312*37219Sminshall 	case TELOPT_BINARY:		/* binary mode */
31332377Sminshall #	endif	/* defined(TN3270) */
314*37219Sminshall 	case TELOPT_NAWS:		/* window size */
315*37219Sminshall 	case TELOPT_TSPEED:		/* terminal speed */
316*37219Sminshall 	case TELOPT_LFLOW:		/* local flow control */
31727676Sminshall 	case TELOPT_TTYPE:		/* terminal type option */
31827110Sminshall 	case TELOPT_SGA:		/* no big deal */
3196000Sroot 		fmt = will;
32027110Sminshall 		myopts[option] = 1;
3216000Sroot 		break;
3226000Sroot 
32327110Sminshall 	case TELOPT_ECHO:		/* We're never going to echo... */
3246000Sroot 	default:
3256000Sroot 		fmt = wont;
3266000Sroot 		break;
3276000Sroot 	}
32832554Sminshall 	printring(&netoring, fmt, option);
32932377Sminshall 	printoption(">SENT", fmt, option, 0);
3306000Sroot }
33127676Sminshall 
33227676Sminshall /*
33327676Sminshall  * suboption()
33427676Sminshall  *
33527676Sminshall  *	Look at the sub-option buffer, and try to be helpful to the other
33627676Sminshall  * side.
33727676Sminshall  *
33827676Sminshall  *	Currently we recognize:
33927676Sminshall  *
34027676Sminshall  *		Terminal type, send request.
341*37219Sminshall  *		Terminal speed (send request).
342*37219Sminshall  *		Local flow control (is request).
34327676Sminshall  */
34427676Sminshall 
34532377Sminshall static void
34627676Sminshall suboption()
34727676Sminshall {
34832377Sminshall     printsub("<", subbuffer, subend-subbuffer+1);
34927676Sminshall     switch (subbuffer[0]&0xff) {
35027676Sminshall     case TELOPT_TTYPE:
35127676Sminshall 	if ((subbuffer[1]&0xff) != TELQUAL_SEND) {
35227676Sminshall 	    ;
35327676Sminshall 	} else {
35427676Sminshall 	    char *name;
35527676Sminshall 	    char namebuf[41];
35632377Sminshall 	    extern char *getenv();
35727676Sminshall 	    int len;
35827676Sminshall 
35932377Sminshall #if	defined(TN3270)
36032531Sminshall 	    if (tn3270_ttype()) {
36132377Sminshall 		return;
36232377Sminshall 	    }
36332377Sminshall #endif	/* defined(TN3270) */
36427676Sminshall 	    name = getenv("TERM");
36527676Sminshall 	    if ((name == 0) || ((len = strlen(name)) > 40)) {
36627676Sminshall 		name = "UNKNOWN";
36733492Sminshall 		len = strlen(name);
36827676Sminshall 	    }
36927676Sminshall 	    if ((len + 4+2) < NETROOM()) {
37027676Sminshall 		strcpy(namebuf, name);
37127676Sminshall 		upcase(namebuf);
37232554Sminshall 		printring(&netoring, "%c%c%c%c%s%c%c", IAC, SB, TELOPT_TTYPE,
37327676Sminshall 				    TELQUAL_IS, namebuf, IAC, SE);
37432381Sminshall 		/* XXX */
37532381Sminshall 		/* printsub(">", nfrontp+2, 4+strlen(namebuf)+2-2-2); */
37632377Sminshall 	    } else {
37732381Sminshall 		ExitString("No room in buffer for terminal type.\n",
37832377Sminshall 							1);
37932377Sminshall 		/*NOTREACHED*/
38027676Sminshall 	    }
38127676Sminshall 	}
382*37219Sminshall 	break;
383*37219Sminshall     case TELOPT_TSPEED:
384*37219Sminshall 	if ((subbuffer[1]&0xff) == TELQUAL_SEND) {
385*37219Sminshall 	    long *ospeed,*ispeed;
386*37219Sminshall 	    char speedbuf[41];
387*37219Sminshall 	    char *getenv();
388*37219Sminshall 	    int len;
38927676Sminshall 
390*37219Sminshall 	    TerminalSpeeds(&ispeed, &ospeed);
391*37219Sminshall 
392*37219Sminshall 	    sprintf(speedbuf, "%d,%d", ospeed, ispeed);
393*37219Sminshall 	    len = strlen(speedbuf);
394*37219Sminshall 
395*37219Sminshall 	    if ((len + 4+2) < NETROOM()) {
396*37219Sminshall 		printring(&netoring, "%c%c%c%c%s%c%c", IAC, SB, TELOPT_TSPEED,
397*37219Sminshall 		    TELQUAL_IS, speedbuf, IAC, SE);
398*37219Sminshall 	    }
399*37219Sminshall 	}
400*37219Sminshall 	break;
401*37219Sminshall     case TELOPT_LFLOW:
402*37219Sminshall 	if ((subbuffer[1]&0xff) == 1) {
403*37219Sminshall 	    localflow = 1;
404*37219Sminshall 	} else if ((subbuffer[1]&0xff) == 0) {
405*37219Sminshall 	    localflow = 0;
406*37219Sminshall 	}
407*37219Sminshall 	setcommandmode();
408*37219Sminshall 	setconnmode();
409*37219Sminshall 	break;
41027676Sminshall     default:
41127676Sminshall 	break;
41227676Sminshall     }
41327676Sminshall }
41432377Sminshall 
41527088Sminshall 
41633804Sminshall int
41732377Sminshall telrcv()
41827110Sminshall {
41932377Sminshall     register int c;
42032385Sminshall     register int scc;
42132385Sminshall     register char *sbp;
42232385Sminshall     int count;
42332385Sminshall     int returnValue = 0;
42427088Sminshall 
42532385Sminshall     scc = 0;
42632385Sminshall     count = 0;
42732385Sminshall     while (TTYROOM() > 2) {
42832385Sminshall 	if (scc == 0) {
42932385Sminshall 	    if (count) {
43032528Sminshall 		ring_consumed(&netiring, count);
43132385Sminshall 		returnValue = 1;
43232385Sminshall 		count = 0;
43332385Sminshall 	    }
43432528Sminshall 	    sbp = netiring.consume;
43532528Sminshall 	    scc = ring_full_consecutive(&netiring);
43632385Sminshall 	    if (scc == 0) {
43732385Sminshall 		/* No more data coming in */
43832385Sminshall 		break;
43932385Sminshall 	    }
44032385Sminshall 	}
44132385Sminshall 
44232385Sminshall 	c = *sbp++ & 0xff, scc--; count++;
44332385Sminshall 
44432377Sminshall 	switch (telrcv_state) {
44527110Sminshall 
44632377Sminshall 	case TS_CR:
44732377Sminshall 	    telrcv_state = TS_DATA;
44835518Sminshall 	    if (c == '\0') {
44935518Sminshall 		break;	/* Ignore \0 after CR */
45035518Sminshall 	    } else if ((c == '\n') && (!hisopts[TELOPT_ECHO]) && !crmod) {
45135518Sminshall 		TTYADD(c);
45235518Sminshall 		break;
45332377Sminshall 	    }
45435518Sminshall 	    /* Else, fall through */
45527088Sminshall 
45632377Sminshall 	case TS_DATA:
45732377Sminshall 	    if (c == IAC) {
45832377Sminshall 		telrcv_state = TS_IAC;
45933804Sminshall 		break;
46032377Sminshall 	    }
46132377Sminshall #	    if defined(TN3270)
46232377Sminshall 	    if (In3270) {
46332377Sminshall 		*Ifrontp++ = c;
46432385Sminshall 		while (scc > 0) {
46532385Sminshall 		    c = *sbp++ & 0377, scc--; count++;
46632377Sminshall 		    if (c == IAC) {
46732377Sminshall 			telrcv_state = TS_IAC;
46834304Sminshall 			break;
46932377Sminshall 		    }
47032377Sminshall 		    *Ifrontp++ = c;
47132377Sminshall 		}
47232377Sminshall 	    } else
47332377Sminshall #	    endif /* defined(TN3270) */
47435518Sminshall 		    /*
47535518Sminshall 		     * The 'crmod' hack (see following) is needed
47635518Sminshall 		     * since we can't * set CRMOD on output only.
47735518Sminshall 		     * Machines like MULTICS like to send \r without
47835518Sminshall 		     * \n; since we must turn off CRMOD to get proper
47935518Sminshall 		     * input, the mapping is done here (sigh).
48035518Sminshall 		     */
48132377Sminshall 	    if ((c == '\r') && !hisopts[TELOPT_BINARY]) {
48235518Sminshall 		if (scc > 0) {
48335518Sminshall 		    c = *sbp&0xff;
48435518Sminshall 		    if (c == 0) {
48535518Sminshall 			sbp++, scc--; count++;
48635518Sminshall 			/* a "true" CR */
48732377Sminshall 			TTYADD('\r');
48835518Sminshall 		    } else if (!hisopts[TELOPT_ECHO] &&
48935518Sminshall 					(c == '\n')) {
49035518Sminshall 			sbp++, scc--; count++;
49132377Sminshall 			TTYADD('\n');
49235518Sminshall 		    } else {
49335518Sminshall 			TTYADD('\r');
49435518Sminshall 			if (crmod) {
49535518Sminshall 				TTYADD('\n');
49632377Sminshall 			}
49732377Sminshall 		    }
49835518Sminshall 		} else {
49935518Sminshall 		    telrcv_state = TS_CR;
50035518Sminshall 		    TTYADD('\r');
50135518Sminshall 		    if (crmod) {
50235518Sminshall 			    TTYADD('\n');
50335518Sminshall 		    }
50432377Sminshall 		}
50532377Sminshall 	    } else {
50632377Sminshall 		TTYADD(c);
50732377Sminshall 	    }
50832377Sminshall 	    continue;
50927088Sminshall 
51032377Sminshall 	case TS_IAC:
51132377Sminshall 	    switch (c) {
51232377Sminshall 
51332377Sminshall 	    case WILL:
51432377Sminshall 		telrcv_state = TS_WILL;
51532377Sminshall 		continue;
51627261Sminshall 
51732377Sminshall 	    case WONT:
51832377Sminshall 		telrcv_state = TS_WONT;
51932377Sminshall 		continue;
52027261Sminshall 
52132377Sminshall 	    case DO:
52232377Sminshall 		telrcv_state = TS_DO;
52332377Sminshall 		continue;
52427261Sminshall 
52532377Sminshall 	    case DONT:
52632377Sminshall 		telrcv_state = TS_DONT;
52732377Sminshall 		continue;
52827261Sminshall 
52932377Sminshall 	    case DM:
53032377Sminshall 		    /*
53132377Sminshall 		     * We may have missed an urgent notification,
53232377Sminshall 		     * so make sure we flush whatever is in the
53332377Sminshall 		     * buffer currently.
53432377Sminshall 		     */
53532377Sminshall 		SYNCHing = 1;
53632377Sminshall 		ttyflush(1);
53732554Sminshall 		SYNCHing = stilloob();
53832377Sminshall 		settimer(gotDM);
53932377Sminshall 		break;
54027088Sminshall 
54132377Sminshall 	    case NOP:
54232377Sminshall 	    case GA:
54332377Sminshall 		break;
54427088Sminshall 
54532377Sminshall 	    case SB:
54632377Sminshall 		SB_CLEAR();
54732377Sminshall 		telrcv_state = TS_SB;
54832377Sminshall 		continue;
54927261Sminshall 
55032377Sminshall #	    if defined(TN3270)
55132377Sminshall 	    case EOR:
55232377Sminshall 		if (In3270) {
55332377Sminshall 		    Ibackp += DataFromNetwork(Ibackp, Ifrontp-Ibackp, 1);
55432377Sminshall 		    if (Ibackp == Ifrontp) {
55532377Sminshall 			Ibackp = Ifrontp = Ibuf;
55632377Sminshall 			ISend = 0;	/* should have been! */
55732377Sminshall 		    } else {
55832377Sminshall 			ISend = 1;
55927088Sminshall 		    }
56027088Sminshall 		}
56127088Sminshall 		break;
56232377Sminshall #	    endif /* defined(TN3270) */
56332377Sminshall 
56432377Sminshall 	    case IAC:
56532377Sminshall #	    if !defined(TN3270)
56632377Sminshall 		TTYADD(IAC);
56732377Sminshall #	    else /* !defined(TN3270) */
56832377Sminshall 		if (In3270) {
56932377Sminshall 		    *Ifrontp++ = IAC;
57032377Sminshall 		} else {
57132377Sminshall 		    TTYADD(IAC);
57232377Sminshall 		}
57332377Sminshall #	    endif /* !defined(TN3270) */
57427088Sminshall 		break;
57532377Sminshall 
57627088Sminshall 	    default:
57727088Sminshall 		break;
57827088Sminshall 	    }
57932377Sminshall 	    telrcv_state = TS_DATA;
58032377Sminshall 	    continue;
58127088Sminshall 
58232377Sminshall 	case TS_WILL:
58332377Sminshall 	    printoption(">RCVD", will, c, !hisopts[c]);
58432377Sminshall 	    if (c == TELOPT_TM) {
58532377Sminshall 		if (flushout) {
58632377Sminshall 		    flushout = 0;
58732377Sminshall 		}
58832377Sminshall 	    } else if (!hisopts[c]) {
58932377Sminshall 		willoption(c, 1);
59032377Sminshall 	    }
59132377Sminshall 	    SetIn3270();
59232377Sminshall 	    telrcv_state = TS_DATA;
59332377Sminshall 	    continue;
59427110Sminshall 
59532377Sminshall 	case TS_WONT:
59632377Sminshall 	    printoption(">RCVD", wont, c, hisopts[c]);
59732377Sminshall 	    if (c == TELOPT_TM) {
59832377Sminshall 		if (flushout) {
59932377Sminshall 		    flushout = 0;
60032377Sminshall 		}
60132377Sminshall 	    } else if (hisopts[c]) {
60232377Sminshall 		wontoption(c, 1);
60332377Sminshall 	    }
60432377Sminshall 	    SetIn3270();
60532377Sminshall 	    telrcv_state = TS_DATA;
60632377Sminshall 	    continue;
60727088Sminshall 
60832377Sminshall 	case TS_DO:
60932377Sminshall 	    printoption(">RCVD", doopt, c, !myopts[c]);
61032377Sminshall 	    if (!myopts[c])
61132377Sminshall 		dooption(c);
61232377Sminshall 	    SetIn3270();
613*37219Sminshall 	    if (c == TELOPT_NAWS) {
614*37219Sminshall 		sendnaws();
615*37219Sminshall 	    } else if (c == TELOPT_LFLOW) {
616*37219Sminshall 		localflow = 1;
617*37219Sminshall 		setcommandmode();
618*37219Sminshall 		setconnmode();
619*37219Sminshall 	    }
62032377Sminshall 	    telrcv_state = TS_DATA;
62132377Sminshall 	    continue;
62227088Sminshall 
62332377Sminshall 	case TS_DONT:
62432377Sminshall 	    printoption(">RCVD", dont, c, myopts[c]);
62532377Sminshall 	    if (myopts[c]) {
62632377Sminshall 		myopts[c] = 0;
62732554Sminshall 		printring(&netoring, wont, c);
62832377Sminshall 		flushline = 1;
62932377Sminshall 		setconnmode();	/* set new tty mode (maybe) */
63032377Sminshall 		printoption(">SENT", wont, c, 0);
63132377Sminshall 	    }
63232377Sminshall 	    SetIn3270();
63332377Sminshall 	    telrcv_state = TS_DATA;
63432377Sminshall 	    continue;
63527088Sminshall 
63632377Sminshall 	case TS_SB:
63732377Sminshall 	    if (c == IAC) {
63832377Sminshall 		telrcv_state = TS_SE;
63932377Sminshall 	    } else {
64032377Sminshall 		SB_ACCUM(c);
64132377Sminshall 	    }
64232377Sminshall 	    continue;
64327088Sminshall 
64432377Sminshall 	case TS_SE:
64532377Sminshall 	    if (c != SE) {
64632377Sminshall 		if (c != IAC) {
64732377Sminshall 		    SB_ACCUM(IAC);
64832377Sminshall 		}
64932377Sminshall 		SB_ACCUM(c);
65032377Sminshall 		telrcv_state = TS_SB;
65132377Sminshall 	    } else {
65232377Sminshall 		SB_TERM();
65332377Sminshall 		suboption();	/* handle sub-option */
65432377Sminshall 		SetIn3270();
65532377Sminshall 		telrcv_state = TS_DATA;
65632377Sminshall 	    }
65727088Sminshall 	}
65827088Sminshall     }
65932667Sminshall     if (count)
66032667Sminshall 	ring_consumed(&netiring, count);
66132385Sminshall     return returnValue||count;
66227088Sminshall }
66332385Sminshall 
66432385Sminshall static int
66532554Sminshall telsnd()
66632385Sminshall {
66732385Sminshall     int tcc;
66832385Sminshall     int count;
66932385Sminshall     int returnValue = 0;
67032385Sminshall     char *tbp;
67132385Sminshall 
67232385Sminshall     tcc = 0;
67332385Sminshall     count = 0;
67432385Sminshall     while (NETROOM() > 2) {
67532385Sminshall 	register int sc;
67632385Sminshall 	register int c;
67732385Sminshall 
67832385Sminshall 	if (tcc == 0) {
67932385Sminshall 	    if (count) {
68032528Sminshall 		ring_consumed(&ttyiring, count);
68132385Sminshall 		returnValue = 1;
68232385Sminshall 		count = 0;
68332385Sminshall 	    }
68432528Sminshall 	    tbp = ttyiring.consume;
68532528Sminshall 	    tcc = ring_full_consecutive(&ttyiring);
68632385Sminshall 	    if (tcc == 0) {
68732385Sminshall 		break;
68832385Sminshall 	    }
68932385Sminshall 	}
69032385Sminshall 	c = *tbp++ & 0xff, sc = strip(c), tcc--; count++;
69132385Sminshall 	if (sc == escape) {
69232385Sminshall 	    command(0);
69332385Sminshall 	    tcc = 0;
69432385Sminshall 	    flushline = 1;
69532385Sminshall 	    break;
69632385Sminshall 	} else if (MODE_LINE(globalmode) && (sc == echoc)) {
69732385Sminshall 	    if (tcc > 0 && strip(*tbp) == echoc) {
69832385Sminshall 		tcc--; tbp++; count++;
69932385Sminshall 	    } else {
70032385Sminshall 		dontlecho = !dontlecho;
70132385Sminshall 		settimer(echotoggle);
70232385Sminshall 		setconnmode();
70332385Sminshall 		flushline = 1;
70432385Sminshall 		break;
70532385Sminshall 	    }
70632385Sminshall 	}
70732385Sminshall 	if (localchars) {
70832385Sminshall 	    if (TerminalSpecialChars(sc) == 0) {
70932385Sminshall 		break;
71032385Sminshall 	    }
71132385Sminshall 	}
71232385Sminshall 	if (!myopts[TELOPT_BINARY]) {
71332385Sminshall 	    switch (c) {
71432385Sminshall 	    case '\n':
71532385Sminshall 		    /*
71632385Sminshall 		     * If we are in CRMOD mode (\r ==> \n)
71732385Sminshall 		     * on our local machine, then probably
71832385Sminshall 		     * a newline (unix) is CRLF (TELNET).
71932385Sminshall 		     */
72032385Sminshall 		if (MODE_LOCAL_CHARS(globalmode)) {
72132385Sminshall 		    NETADD('\r');
72232385Sminshall 		}
72332385Sminshall 		NETADD('\n');
72432385Sminshall 		flushline = 1;
72532385Sminshall 		break;
72632385Sminshall 	    case '\r':
72732385Sminshall 		if (!crlf) {
72832385Sminshall 		    NET2ADD('\r', '\0');
72932385Sminshall 		} else {
73032385Sminshall 		    NET2ADD('\r', '\n');
73132385Sminshall 		}
73232385Sminshall 		flushline = 1;
73332385Sminshall 		break;
73432385Sminshall 	    case IAC:
73532385Sminshall 		NET2ADD(IAC, IAC);
73632385Sminshall 		break;
73732385Sminshall 	    default:
73832385Sminshall 		NETADD(c);
73932385Sminshall 		break;
74032385Sminshall 	    }
74132385Sminshall 	} else if (c == IAC) {
74232385Sminshall 	    NET2ADD(IAC, IAC);
74332385Sminshall 	} else {
74432385Sminshall 	    NETADD(c);
74532385Sminshall 	}
74632385Sminshall     }
74732667Sminshall     if (count)
74832667Sminshall 	ring_consumed(&ttyiring, count);
74932385Sminshall     return returnValue||count;		/* Non-zero if we did anything */
75032385Sminshall }
75132377Sminshall 
75227088Sminshall /*
75332377Sminshall  * Scheduler()
75432377Sminshall  *
75532377Sminshall  * Try to do something.
75632377Sminshall  *
75732377Sminshall  * If we do something useful, return 1; else return 0.
75832377Sminshall  *
75927110Sminshall  */
76027110Sminshall 
76127110Sminshall 
76232377Sminshall int
76332377Sminshall Scheduler(block)
76432377Sminshall int	block;			/* should we block in the select ? */
76527110Sminshall {
76632377Sminshall 		/* One wants to be a bit careful about setting returnValue
76732377Sminshall 		 * to one, since a one implies we did some useful work,
76832377Sminshall 		 * and therefore probably won't be called to block next
76932377Sminshall 		 * time (TN3270 mode only).
77032377Sminshall 		 */
77132531Sminshall     int returnValue;
77232531Sminshall     int netin, netout, netex, ttyin, ttyout;
77327110Sminshall 
77432531Sminshall     /* Decide which rings should be processed */
77532531Sminshall 
77632531Sminshall     netout = ring_full_count(&netoring) &&
77732531Sminshall 	    (!MODE_LINE(globalmode) || flushline || myopts[TELOPT_BINARY]);
77832531Sminshall     ttyout = ring_full_count(&ttyoring);
77932531Sminshall 
78032377Sminshall #if	defined(TN3270)
78132531Sminshall     ttyin = ring_empty_count(&ttyiring) && (shell_active == 0);
78232377Sminshall #else	/* defined(TN3270) */
78332531Sminshall     ttyin = ring_empty_count(&ttyiring);
78432377Sminshall #endif	/* defined(TN3270) */
78532531Sminshall 
78632531Sminshall #if	defined(TN3270)
78732531Sminshall     netin = ring_empty_count(&netiring);
78832377Sminshall #   else /* !defined(TN3270) */
78932531Sminshall     netin = !ISend && ring_empty_count(&netiring);
79032377Sminshall #   endif /* !defined(TN3270) */
79132531Sminshall 
79232531Sminshall     netex = !SYNCHing;
79332531Sminshall 
79432531Sminshall     /* If we have seen a signal recently, reset things */
79532377Sminshall #   if defined(TN3270) && defined(unix)
79632377Sminshall     if (HaveInput) {
79732377Sminshall 	HaveInput = 0;
79832377Sminshall 	signal(SIGIO, inputAvailable);
79932377Sminshall     }
80032377Sminshall #endif	/* defined(TN3270) && defined(unix) */
80132377Sminshall 
80232531Sminshall     /* Call to system code to process rings */
80327178Sminshall 
80432531Sminshall     returnValue = process_rings(netin, netout, netex, ttyin, ttyout, !block);
80527178Sminshall 
80632531Sminshall     /* Now, look at the input rings, looking for work to do. */
80732377Sminshall 
80832531Sminshall     if (ring_full_count(&ttyiring)) {
80932377Sminshall #   if defined(TN3270)
81032377Sminshall 	if (In3270) {
81134848Sminshall 	    int c;
81234848Sminshall 
81333804Sminshall 	    c = DataFromTerminal(ttyiring.consume,
81432528Sminshall 					ring_full_consecutive(&ttyiring));
81532377Sminshall 	    if (c) {
81632377Sminshall 		returnValue = 1;
81732667Sminshall 	        ring_consumed(&ttyiring, c);
81832377Sminshall 	    }
81932377Sminshall 	} else {
82032377Sminshall #   endif /* defined(TN3270) */
82132554Sminshall 	    returnValue |= telsnd();
82232377Sminshall #   if defined(TN3270)
82327178Sminshall 	}
82432531Sminshall #   endif /* defined(TN3270) */
82527178Sminshall     }
82632377Sminshall 
82732528Sminshall     if (ring_full_count(&netiring)) {
82832377Sminshall #	if !defined(TN3270)
82932385Sminshall 	returnValue |= telrcv();
83032377Sminshall #	else /* !defined(TN3270) */
83132377Sminshall 	returnValue = Push3270();
83232377Sminshall #	endif /* !defined(TN3270) */
83332377Sminshall     }
83432377Sminshall     return returnValue;
83527178Sminshall }
83627178Sminshall 
83727178Sminshall /*
83832377Sminshall  * Select from tty and network...
83927088Sminshall  */
84032377Sminshall void
84132377Sminshall telnet()
84227088Sminshall {
84332531Sminshall     sys_telnet_init();
84427088Sminshall 
84532377Sminshall #   if !defined(TN3270)
84632377Sminshall     if (telnetport) {
84732377Sminshall 	if (!hisopts[TELOPT_SGA]) {
84832377Sminshall 	    willoption(TELOPT_SGA, 0);
84927110Sminshall 	}
85032377Sminshall 	if (!myopts[TELOPT_TTYPE]) {
85134848Sminshall 	    dooption(TELOPT_TTYPE);
85232377Sminshall 	}
853*37219Sminshall 	if (!myopts[TELOPT_NAWS]) {
854*37219Sminshall 	    dooption(TELOPT_NAWS);
855*37219Sminshall 	}
856*37219Sminshall 	if (!myopts[TELOPT_TSPEED]) {
857*37219Sminshall 	    dooption(TELOPT_TSPEED);
858*37219Sminshall 	}
859*37219Sminshall 	if (!myopts[TELOPT_LFLOW]) {
860*37219Sminshall 	    dooption(TELOPT_LFLOW);
861*37219Sminshall 	}
86227178Sminshall     }
86332377Sminshall #   endif /* !defined(TN3270) */
86427088Sminshall 
86532377Sminshall #   if !defined(TN3270)
86632377Sminshall     for (;;) {
86732385Sminshall 	int schedValue;
86832385Sminshall 
86932385Sminshall 	while ((schedValue = Scheduler(0)) != 0) {
87032385Sminshall 	    if (schedValue == -1) {
87132385Sminshall 		setcommandmode();
87232385Sminshall 		return;
87332385Sminshall 	    }
87432385Sminshall 	}
87532385Sminshall 
87632531Sminshall 	if (Scheduler(1) == -1) {
87732377Sminshall 	    setcommandmode();
87832377Sminshall 	    return;
87932377Sminshall 	}
88032377Sminshall     }
88132377Sminshall #   else /* !defined(TN3270) */
88232377Sminshall     for (;;) {
88332377Sminshall 	int schedValue;
88427088Sminshall 
88532377Sminshall 	while (!In3270 && !shell_active) {
88632531Sminshall 	    if (Scheduler(1) == -1) {
88732377Sminshall 		setcommandmode();
88832377Sminshall 		return;
88932377Sminshall 	    }
89027088Sminshall 	}
89132377Sminshall 
89232377Sminshall 	while ((schedValue = Scheduler(0)) != 0) {
89332377Sminshall 	    if (schedValue == -1) {
89432377Sminshall 		setcommandmode();
89532377Sminshall 		return;
89632377Sminshall 	    }
89727088Sminshall 	}
89832377Sminshall 		/* If there is data waiting to go out to terminal, don't
89932377Sminshall 		 * schedule any more data for the terminal.
90032377Sminshall 		 */
90134304Sminshall 	if (ring_full_count(&ttyoring)) {
90232377Sminshall 	    schedValue = 1;
90327088Sminshall 	} else {
90432377Sminshall 	    if (shell_active) {
90532377Sminshall 		if (shell_continue() == 0) {
90632377Sminshall 		    ConnectScreen();
90727088Sminshall 		}
90832377Sminshall 	    } else if (In3270) {
90932377Sminshall 		schedValue = DoTerminalOutput();
91032377Sminshall 	    }
91127088Sminshall 	}
91232377Sminshall 	if (schedValue && (shell_active == 0)) {
91332531Sminshall 	    if (Scheduler(1) == -1) {
91432377Sminshall 		setcommandmode();
91532377Sminshall 		return;
91632377Sminshall 	    }
91727088Sminshall 	}
91832377Sminshall     }
91932377Sminshall #   endif /* !defined(TN3270) */
92027088Sminshall }
92132377Sminshall 
92234848Sminshall #if	0	/* XXX - this not being in is a bug */
92327088Sminshall /*
92432554Sminshall  * nextitem()
92532554Sminshall  *
92632554Sminshall  *	Return the address of the next "item" in the TELNET data
92732554Sminshall  * stream.  This will be the address of the next character if
92832554Sminshall  * the current address is a user data character, or it will
92932554Sminshall  * be the address of the character following the TELNET command
93032554Sminshall  * if the current address is a TELNET IAC ("I Am a Command")
93132554Sminshall  * character.
93232554Sminshall  */
93332554Sminshall 
93432554Sminshall static char *
93532554Sminshall nextitem(current)
93632554Sminshall char	*current;
93732554Sminshall {
93832554Sminshall     if ((*current&0xff) != IAC) {
93932554Sminshall 	return current+1;
94032554Sminshall     }
94132554Sminshall     switch (*(current+1)&0xff) {
94232554Sminshall     case DO:
94332554Sminshall     case DONT:
94432554Sminshall     case WILL:
94532554Sminshall     case WONT:
94632554Sminshall 	return current+3;
94732554Sminshall     case SB:		/* loop forever looking for the SE */
94832554Sminshall 	{
94932554Sminshall 	    register char *look = current+2;
95032554Sminshall 
95132554Sminshall 	    for (;;) {
95232554Sminshall 		if ((*look++&0xff) == IAC) {
95332554Sminshall 		    if ((*look++&0xff) == SE) {
95432554Sminshall 			return look;
95532554Sminshall 		    }
95632554Sminshall 		}
95732554Sminshall 	    }
95832554Sminshall 	}
95932554Sminshall     default:
96032554Sminshall 	return current+2;
96132554Sminshall     }
96232554Sminshall }
96334848Sminshall #endif	/* 0 */
96432554Sminshall 
96532554Sminshall /*
96632554Sminshall  * netclear()
96732554Sminshall  *
96832554Sminshall  *	We are about to do a TELNET SYNCH operation.  Clear
96932554Sminshall  * the path to the network.
97032554Sminshall  *
97132554Sminshall  *	Things are a bit tricky since we may have sent the first
97232554Sminshall  * byte or so of a previous TELNET command into the network.
97332554Sminshall  * So, we have to scan the network buffer from the beginning
97432554Sminshall  * until we are up to where we want to be.
97532554Sminshall  *
97632554Sminshall  *	A side effect of what we do, just to keep things
97732554Sminshall  * simple, is to clear the urgent data pointer.  The principal
97832554Sminshall  * caller should be setting the urgent data pointer AFTER calling
97932554Sminshall  * us in any case.
98032554Sminshall  */
98132554Sminshall 
98232554Sminshall static void
98332554Sminshall netclear()
98432554Sminshall {
98532554Sminshall #if	0	/* XXX */
98632554Sminshall     register char *thisitem, *next;
98732554Sminshall     char *good;
98832554Sminshall #define	wewant(p)	((nfrontp > p) && ((*p&0xff) == IAC) && \
98932554Sminshall 				((*(p+1)&0xff) != EC) && ((*(p+1)&0xff) != EL))
99032554Sminshall 
99132554Sminshall     thisitem = netobuf;
99232554Sminshall 
99332554Sminshall     while ((next = nextitem(thisitem)) <= netobuf.send) {
99432554Sminshall 	thisitem = next;
99532554Sminshall     }
99632554Sminshall 
99732554Sminshall     /* Now, thisitem is first before/at boundary. */
99832554Sminshall 
99932554Sminshall     good = netobuf;	/* where the good bytes go */
100032554Sminshall 
100132554Sminshall     while (netoring.add > thisitem) {
100232554Sminshall 	if (wewant(thisitem)) {
100332554Sminshall 	    int length;
100432554Sminshall 
100532554Sminshall 	    next = thisitem;
100632554Sminshall 	    do {
100732554Sminshall 		next = nextitem(next);
100832554Sminshall 	    } while (wewant(next) && (nfrontp > next));
100932554Sminshall 	    length = next-thisitem;
101032554Sminshall 	    memcpy(good, thisitem, length);
101132554Sminshall 	    good += length;
101232554Sminshall 	    thisitem = next;
101332554Sminshall 	} else {
101432554Sminshall 	    thisitem = nextitem(thisitem);
101532554Sminshall 	}
101632554Sminshall     }
101732554Sminshall 
101832554Sminshall #endif	/* 0 */
101932554Sminshall }
102032554Sminshall 
102132554Sminshall /*
102232377Sminshall  * These routines add various telnet commands to the data stream.
102327088Sminshall  */
102432377Sminshall 
102532554Sminshall static void
102632554Sminshall doflush()
102732554Sminshall {
102832554Sminshall     NET2ADD(IAC, DO);
102932554Sminshall     NETADD(TELOPT_TM);
103032554Sminshall     flushline = 1;
103132554Sminshall     flushout = 1;
103232554Sminshall     ttyflush(1);			/* Flush/drop output */
103332554Sminshall     /* do printoption AFTER flush, otherwise the output gets tossed... */
103432554Sminshall     printoption("<SENT", doopt, TELOPT_TM, 0);
103532554Sminshall }
103632554Sminshall 
103732377Sminshall void
103832377Sminshall xmitAO()
103927088Sminshall {
104032377Sminshall     NET2ADD(IAC, AO);
104132377Sminshall     if (autoflush) {
104232377Sminshall 	doflush();
104332377Sminshall     }
104432377Sminshall }
104527088Sminshall 
104632377Sminshall 
104732377Sminshall void
104832377Sminshall xmitEL()
104927088Sminshall {
105032377Sminshall     NET2ADD(IAC, EL);
105127088Sminshall }
105227088Sminshall 
105332377Sminshall void
105432377Sminshall xmitEC()
105527088Sminshall {
105632377Sminshall     NET2ADD(IAC, EC);
105727088Sminshall }
105827088Sminshall 
105932377Sminshall 
106032377Sminshall #if	defined(NOT43)
106132377Sminshall int
106232377Sminshall #else	/* defined(NOT43) */
106332377Sminshall void
106432377Sminshall #endif	/* defined(NOT43) */
106532377Sminshall dosynch()
106627088Sminshall {
106732377Sminshall     netclear();			/* clear the path to the network */
106833294Sminshall     NETADD(IAC);
106933294Sminshall     setneturg();
107033294Sminshall     NETADD(DM);
107127088Sminshall 
107232377Sminshall #if	defined(NOT43)
107332377Sminshall     return 0;
107432377Sminshall #endif	/* defined(NOT43) */
107527088Sminshall }
107627088Sminshall 
107732377Sminshall void
107832377Sminshall intp()
107927088Sminshall {
108032377Sminshall     NET2ADD(IAC, IP);
108132377Sminshall     flushline = 1;
108232377Sminshall     if (autoflush) {
108332377Sminshall 	doflush();
108432377Sminshall     }
108532377Sminshall     if (autosynch) {
108632377Sminshall 	dosynch();
108732377Sminshall     }
108827088Sminshall }
108927186Sminshall 
109032377Sminshall void
109132377Sminshall sendbrk()
109227186Sminshall {
109332377Sminshall     NET2ADD(IAC, BREAK);
109432377Sminshall     flushline = 1;
109532377Sminshall     if (autoflush) {
109632377Sminshall 	doflush();
109732377Sminshall     }
109832377Sminshall     if (autosynch) {
109932377Sminshall 	dosynch();
110032377Sminshall     }
110127186Sminshall }
1102*37219Sminshall /*
1103*37219Sminshall  * Send a window size update to the remote system.
1104*37219Sminshall  */
1105*37219Sminshall 
1106*37219Sminshall void
1107*37219Sminshall sendnaws()
1108*37219Sminshall {
1109*37219Sminshall     long rows, cols;
1110*37219Sminshall 
1111*37219Sminshall #define        NETADDCHAR(x) \
1112*37219Sminshall     { \
1113*37219Sminshall 	if (((x) & 0xff) == 0xff) { \
1114*37219Sminshall 	    NET2ADD(IAC, IAC) \
1115*37219Sminshall 	} else { \
1116*37219Sminshall 	    NETADD(x) \
1117*37219Sminshall 	} \
1118*37219Sminshall     }
1119*37219Sminshall #define        NETADDSHORT(x)  { NETADDCHAR(x >> 8); NETADDCHAR(x & 0xff) }
1120*37219Sminshall 
1121*37219Sminshall     if (TerminalWindowSize(&rows, &cols) == 0) {	/* Failed */
1122*37219Sminshall 	return;
1123*37219Sminshall     }
1124*37219Sminshall 
1125*37219Sminshall     if (NETROOM() >= 3 + 8 + 2) {
1126*37219Sminshall 	NET2ADD(IAC, SB);
1127*37219Sminshall 	NETADD(TELOPT_NAWS);
1128*37219Sminshall 	NETADDSHORT(cols);
1129*37219Sminshall 	NETADDSHORT(rows);
1130*37219Sminshall 	NET2ADD(IAC, SE);
1131*37219Sminshall     }
1132*37219Sminshall }
1133