xref: /csrg-svn/usr.bin/telnet/telnet.c (revision 38811)
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*38811Sborman static char sccsid[] = "@(#)telnet.c	5.42 (Berkeley) 08/28/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 
6037226Sminshall char	options[256];		/* The combined options */
6138689Sborman char	do_dont_resp[256];
6238689Sborman char	will_wont_resp[256];
636000Sroot 
6432377Sminshall int
6532377Sminshall 	connected,
6632377Sminshall 	showoptions,
6732377Sminshall 	In3270,		/* Are we in 3270 mode? */
6832377Sminshall 	ISend,		/* trying to send network data in */
6932377Sminshall 	debug = 0,
7032377Sminshall 	crmod,
7132377Sminshall 	netdata,	/* Print out network data flow */
7232377Sminshall 	crlf,		/* Should '\r' be mapped to <CR><LF> (or <CR><NUL>)? */
7334848Sminshall #if	defined(TN3270)
7436241Sminshall 	noasynchtty = 0,/* User specified "-noasynch" on command line */
7536241Sminshall 	noasynchnet = 0,/* User specified "-noasynch" on command line */
7632377Sminshall 	askedSGA = 0,	/* We have talked about suppress go ahead */
7734848Sminshall #endif	/* defined(TN3270) */
7833286Sminshall 	telnetport,
7932531Sminshall 	SYNCHing,	/* we are in TELNET SYNCH mode */
8032531Sminshall 	flushout,	/* flush output */
8132531Sminshall 	autoflush = 0,	/* flush output when interrupting? */
8232531Sminshall 	autosynch,	/* send interrupt characters with SYNCH? */
8337219Sminshall 	localflow,	/* we handle flow control locally */
8432531Sminshall 	localchars,	/* we recognize interrupt/quit */
8532531Sminshall 	donelclchars,	/* the user has set "localchars" */
8632531Sminshall 	donebinarytoggle,	/* the user has put us in binary */
8732531Sminshall 	dontlecho,	/* do we suppress local echoing right now? */
8832531Sminshall 	globalmode;
8927088Sminshall 
9032377Sminshall #define	CONTROL(x)	((x)&0x1f)		/* CTRL(x) is not portable */
916000Sroot 
9232377Sminshall char
9332377Sminshall 	*prompt = 0,
9432377Sminshall 	escape,
9532377Sminshall 	echoc;
9627186Sminshall 
9727186Sminshall /*
986000Sroot  * Telnet receiver states for fsm
996000Sroot  */
1006000Sroot #define	TS_DATA		0
1016000Sroot #define	TS_IAC		1
1026000Sroot #define	TS_WILL		2
1036000Sroot #define	TS_WONT		3
1046000Sroot #define	TS_DO		4
1056000Sroot #define	TS_DONT		5
10627021Sminshall #define	TS_CR		6
10727676Sminshall #define	TS_SB		7		/* sub-option collection */
10827676Sminshall #define	TS_SE		8		/* looking for sub-option end */
1096000Sroot 
11032377Sminshall static int	telrcv_state;
1116000Sroot 
11232377Sminshall jmp_buf	toplevel = { 0 };
11332377Sminshall jmp_buf	peerdied;
1146000Sroot 
11532377Sminshall int	flushline;
116*38811Sborman int	linemode;
11727021Sminshall 
11838689Sborman #ifdef	KLUDGELINEMODE
11938689Sborman int	kludgelinemode = 1;
12038689Sborman #endif
12138689Sborman 
12232377Sminshall /*
12332377Sminshall  * The following are some clocks used to decide how to interpret
12432377Sminshall  * the relationship between various variables.
12532377Sminshall  */
1266000Sroot 
12732377Sminshall Clocks clocks;
12832377Sminshall 
12938689Sborman #ifdef	notdef
13032377Sminshall Modelist modelist[] = {
13132377Sminshall 	{ "telnet command mode", COMMAND_LINE },
13232377Sminshall 	{ "character-at-a-time mode", 0 },
13332377Sminshall 	{ "character-at-a-time mode (local echo)", LOCAL_ECHO|LOCAL_CHARS },
13432377Sminshall 	{ "line-by-line mode (remote echo)", LINE | LOCAL_CHARS },
13532377Sminshall 	{ "line-by-line mode", LINE | LOCAL_ECHO | LOCAL_CHARS },
13632377Sminshall 	{ "line-by-line mode (local echoing suppressed)", LINE | LOCAL_CHARS },
13732377Sminshall 	{ "3270 mode", 0 },
13832377Sminshall };
13938689Sborman #endif
1406000Sroot 
14132377Sminshall 
14232377Sminshall /*
14332377Sminshall  * Initialize telnet environment.
14432377Sminshall  */
1456000Sroot 
14632377Sminshall init_telnet()
14732377Sminshall {
14832377Sminshall     SB_CLEAR();
14937226Sminshall     ClearArray(options);
1506000Sroot 
15137219Sminshall     connected = In3270 = ISend = localflow = donebinarytoggle = 0;
1526000Sroot 
15332377Sminshall     SYNCHing = 0;
1546000Sroot 
15532377Sminshall     /* Don't change NetTrace */
1566000Sroot 
15732377Sminshall     escape = CONTROL(']');
15832377Sminshall     echoc = CONTROL('E');
1596000Sroot 
16032377Sminshall     flushline = 1;
16132377Sminshall     telrcv_state = TS_DATA;
16232377Sminshall }
16332554Sminshall 
1646000Sroot 
16532554Sminshall #include <varargs.h>
1666000Sroot 
16734848Sminshall /*VARARGS*/
16832554Sminshall static void
16932554Sminshall printring(va_alist)
17032554Sminshall va_dcl
17132554Sminshall {
17232554Sminshall     va_list ap;
17332554Sminshall     char buffer[100];		/* where things go */
17432554Sminshall     char *ptr;
17532554Sminshall     char *format;
17632554Sminshall     char *string;
17732554Sminshall     Ring *ring;
17832554Sminshall     int i;
17932554Sminshall 
18032554Sminshall     va_start(ap);
18132554Sminshall 
18232554Sminshall     ring = va_arg(ap, Ring *);
18332554Sminshall     format = va_arg(ap, char *);
18432554Sminshall     ptr = buffer;
18532554Sminshall 
18632554Sminshall     while ((i = *format++) != 0) {
18732554Sminshall 	if (i == '%') {
18832554Sminshall 	    i = *format++;
18932554Sminshall 	    switch (i) {
19032554Sminshall 	    case 'c':
19132554Sminshall 		*ptr++ = va_arg(ap, int);
19232554Sminshall 		break;
19332554Sminshall 	    case 's':
19432554Sminshall 		string = va_arg(ap, char *);
19532554Sminshall 		ring_supply_data(ring, buffer, ptr-buffer);
19632554Sminshall 		ring_supply_data(ring, string, strlen(string));
19732554Sminshall 		ptr = buffer;
19832554Sminshall 		break;
19932554Sminshall 	    case 0:
20032554Sminshall 		ExitString("printring: trailing %%.\n", 1);
20132554Sminshall 		/*NOTREACHED*/
20232554Sminshall 	    default:
20332554Sminshall 		ExitString("printring: unknown format character.\n", 1);
20432554Sminshall 		/*NOTREACHED*/
20532554Sminshall 	    }
20632554Sminshall 	} else {
20732554Sminshall 	    *ptr++ = i;
20832554Sminshall 	}
20932554Sminshall     }
21032554Sminshall     ring_supply_data(ring, buffer, ptr-buffer);
21132554Sminshall }
21232554Sminshall 
21337226Sminshall /*
21437226Sminshall  * These routines are in charge of sending option negotiations
21537226Sminshall  * to the other side.
21637226Sminshall  *
21737226Sminshall  * The basic idea is that we send the negotiation if either side
21837226Sminshall  * is in disagreement as to what the current state should be.
21937226Sminshall  */
22032554Sminshall 
22138689Sborman send_do(c, init)
22238689Sborman register int c, init;
2236000Sroot {
22438689Sborman     if (init) {
22538689Sborman 	if (((do_dont_resp[c] == 0) && my_state_is_do(c)) ||
22638689Sborman 				my_want_state_is_do(c))
22738689Sborman 	    return;
22838689Sborman 	set_my_want_state_do(c);
22938689Sborman 	do_dont_resp[c]++;
23037226Sminshall     }
23138689Sborman     NET2ADD(IAC, DO);
23238689Sborman     NETADD(c);
23338689Sborman     printoption("SENT", "do", c);
23437226Sminshall }
23537226Sminshall 
23637226Sminshall void
23738689Sborman send_dont(c, init)
23838689Sborman register int c, init;
23937226Sminshall {
24038689Sborman     if (init) {
24138689Sborman 	if (((do_dont_resp[c] == 0) && my_state_is_dont(c)) ||
24238689Sborman 				my_want_state_is_dont(c))
24338689Sborman 	    return;
24438689Sborman 	set_my_want_state_dont(c);
24538689Sborman 	do_dont_resp[c]++;
24637226Sminshall     }
24738689Sborman     NET2ADD(IAC, DONT);
24838689Sborman     NETADD(c);
24938689Sborman     printoption("SENT", "dont", c);
25037226Sminshall }
25137226Sminshall 
25237226Sminshall void
25338689Sborman send_will(c, init)
25438689Sborman register int c, init;
25537226Sminshall {
25638689Sborman     if (init) {
25738689Sborman 	if (((will_wont_resp[c] == 0) && my_state_is_will(c)) ||
25838689Sborman 				my_want_state_is_will(c))
25938689Sborman 	    return;
26038689Sborman 	set_my_want_state_will(c);
26138689Sborman 	will_wont_resp[c]++;
26237226Sminshall     }
26338689Sborman     NET2ADD(IAC, WILL);
26438689Sborman     NETADD(c);
26538689Sborman     printoption("SENT", "will", c);
26637226Sminshall }
26737226Sminshall 
26837226Sminshall void
26938689Sborman send_wont(c, init)
27038689Sborman register int c, init;
27137226Sminshall {
27238689Sborman     if (init) {
27338689Sborman 	if (((will_wont_resp[c] == 0) && my_state_is_wont(c)) ||
27438689Sborman 				my_want_state_is_wont(c))
27538689Sborman 	    return;
27638689Sborman 	set_my_want_state_wont(c);
27738689Sborman 	will_wont_resp[c]++;
27837226Sminshall     }
27938689Sborman     NET2ADD(IAC, WONT);
28038689Sborman     NETADD(c);
28138689Sborman     printoption("SENT", "wont", c);
28237226Sminshall }
28337226Sminshall 
28437226Sminshall 
28537226Sminshall void
28637226Sminshall willoption(option)
28737226Sminshall 	int option;
28837226Sminshall {
2896000Sroot 	char *fmt;
29038689Sborman 	int new_state_ok = 0;
2916000Sroot 
29238689Sborman 	if (do_dont_resp[option]) {
29338689Sborman 	    --do_dont_resp[option];
29438689Sborman 	    if (do_dont_resp[option] && my_state_is_do(option))
29538689Sborman 		--do_dont_resp[option];
29638689Sborman 	}
29737226Sminshall 
29838689Sborman 	if ((do_dont_resp[option] == 0) && my_want_state_is_dont(option)) {
2996000Sroot 
30038689Sborman 	    switch (option) {
30138689Sborman 
30238689Sborman 	    case TELOPT_ECHO:
30338689Sborman #	    if defined(TN3270)
30438689Sborman 		/*
30538689Sborman 		 * The following is a pain in the rear-end.
30638689Sborman 		 * Various IBM servers (some versions of Wiscnet,
30738689Sborman 		 * possibly Fibronics/Spartacus, and who knows who
30838689Sborman 		 * else) will NOT allow us to send "DO SGA" too early
30938689Sborman 		 * in the setup proceedings.  On the other hand,
31038689Sborman 		 * 4.2 servers (telnetd) won't set SGA correctly.
31138689Sborman 		 * So, we are stuck.  Empirically (but, based on
31238689Sborman 		 * a VERY small sample), the IBM servers don't send
31338689Sborman 		 * out anything about ECHO, so we postpone our sending
31438689Sborman 		 * "DO SGA" until we see "WILL ECHO" (which 4.2 servers
31538689Sborman 		 * DO send).
31638689Sborman 		  */
31738689Sborman 		{
31838689Sborman 		    if (askedSGA == 0) {
31938689Sborman 			askedSGA = 1;
32038689Sborman 			if (my_want_state_is_dont(TELOPT_SGA))
32138689Sborman 			    send_do(TELOPT_SGA, 1);
32232377Sminshall 		    }
32332377Sminshall 		}
32438689Sborman 		    /* Fall through */
32538689Sborman 	    case TELOPT_EOR:
32638689Sborman 	    case TELOPT_BINARY:
32738689Sborman #endif	    /* defined(TN3270) */
32838689Sborman 	    case TELOPT_SGA:
32927110Sminshall 		settimer(modenegotiated);
33038689Sborman 		new_state_ok = 1;
3316000Sroot 		break;
3326000Sroot 
33338689Sborman 	    case TELOPT_TM:
33438689Sborman 		if (flushout)
33538689Sborman 		    flushout = 0;
33638689Sborman 		/*
33738689Sborman 		 * Special case for TM.  If we get back a WILL,
33838689Sborman 		 * pretend we got back a WONT.
33938689Sborman 		 */
34038689Sborman 		set_my_want_state_dont(option);
34138689Sborman 		set_my_state_dont(option);
34227110Sminshall 		return;			/* Never reply to TM will's/wont's */
3436000Sroot 
34438689Sborman 	    case TELOPT_LINEMODE:
34538689Sborman 	    default:
3466000Sroot 		break;
34738689Sborman 	    }
34838689Sborman 
34938689Sborman 	    if (new_state_ok) {
35038689Sborman 		set_my_want_state_do(option);
35138689Sborman 		send_do(option, 0);
35238689Sborman 		setconnmode(0);		/* possibly set new tty mode */
35338689Sborman 	    } else {
35438689Sborman 		do_dont_resp[option]++;
35538689Sborman 		send_dont(option, 0);
35638689Sborman 	    }
3576000Sroot 	}
35838689Sborman 	set_my_state_do(option);
3596000Sroot }
3606000Sroot 
36132377Sminshall void
36237226Sminshall wontoption(option)
36337226Sminshall 	int option;
3646000Sroot {
3656000Sroot 	char *fmt;
3666000Sroot 
36738689Sborman 	if (do_dont_resp[option]) {
36838689Sborman 	    --do_dont_resp[option];
36938689Sborman 	    if (do_dont_resp[option] && my_state_is_dont(option))
37038689Sborman 		--do_dont_resp[option];
37138689Sborman 	}
37237226Sminshall 
37338689Sborman 	if ((do_dont_resp[option] == 0) && my_want_state_is_do(option)) {
3746000Sroot 
37538689Sborman 	    switch (option) {
37638689Sborman 
37738689Sborman #ifdef	KLUDGELINEMODE
37838689Sborman 	    case TELOPT_SGA:
37938689Sborman 		if (!kludgelinemode)
38038689Sborman 		    break;
38138689Sborman 		/* FALL THROUGH */
38238689Sborman #endif
38338689Sborman 	    case TELOPT_ECHO:
38427110Sminshall 		settimer(modenegotiated);
3856000Sroot 		break;
3866000Sroot 
38738689Sborman 	    case TELOPT_TM:
38838689Sborman 		if (flushout)
38938689Sborman 		    flushout = 0;
39038689Sborman 		set_my_want_state_dont(option);
39138689Sborman 		set_my_state_dont(option);
39227110Sminshall 		return;		/* Never reply to TM will's/wont's */
39327110Sminshall 
39438689Sborman 	    default:
39538689Sborman 		break;
39638689Sborman 	    }
39738689Sborman 	    set_my_want_state_dont(option);
39838689Sborman 	    send_dont(option, 0);
39938689Sborman 	    setconnmode(0);			/* Set new tty mode */
40038689Sborman 	} else if (option == TELOPT_TM) {
40138689Sborman 	    /*
40238689Sborman 	     * Special case for TM.
40338689Sborman 	     */
40438689Sborman 	    if (flushout)
40538689Sborman 		flushout = 0;
40638689Sborman 	    set_my_want_state_dont(option);
4076000Sroot 	}
40838689Sborman 	set_my_state_dont(option);
4096000Sroot }
4106000Sroot 
41132377Sminshall static void
4126000Sroot dooption(option)
4136000Sroot 	int option;
4146000Sroot {
4156000Sroot 	char *fmt;
41638689Sborman 	int new_state_ok = 0;
4176000Sroot 
41838689Sborman 	if (will_wont_resp[option]) {
41938689Sborman 	    --will_wont_resp[option];
42038689Sborman 	    if (will_wont_resp[option] && my_state_is_will(option))
42138689Sborman 		--will_wont_resp[option];
42238689Sborman 	}
42337226Sminshall 
42438689Sborman 	if (will_wont_resp[option] == 0) {
42538689Sborman 	  if (my_want_state_is_wont(option)) {
4266000Sroot 
42738689Sborman 	    switch (option) {
42838689Sborman 
42938689Sborman 	    case TELOPT_TM:
43038689Sborman 		/*
43138689Sborman 		 * Special case for TM.  We send a WILL, but pretend
43238689Sborman 		 * we sent WONT.
43338689Sborman 		 */
43438689Sborman 		send_will(option, 0);
43538689Sborman 		set_my_want_state_wont(TELOPT_TM);
43638689Sborman 		set_my_state_wont(TELOPT_TM);
43738689Sborman 		return;
43838689Sborman 
43932377Sminshall #	if defined(TN3270)
44038689Sborman 	    case TELOPT_EOR:		/* end of record */
44138689Sborman 	    case TELOPT_BINARY:		/* binary mode */
44232377Sminshall #	endif	/* defined(TN3270) */
44338689Sborman 	    case TELOPT_NAWS:		/* window size */
44438689Sborman 	    case TELOPT_TSPEED:		/* terminal speed */
44538689Sborman 	    case TELOPT_LFLOW:		/* local flow control */
44638689Sborman 	    case TELOPT_TTYPE:		/* terminal type option */
44738689Sborman 	    case TELOPT_SGA:		/* no big deal */
44838689Sborman 		new_state_ok = 1;
4496000Sroot 		break;
4506000Sroot 
45138689Sborman 	    case TELOPT_LINEMODE:
45238689Sborman #ifdef	KLUDGELINEMODE
45338689Sborman 		kludgelinemode = 0;
45438689Sborman #endif
45538689Sborman 		set_my_want_state_will(TELOPT_LINEMODE);
45638689Sborman 		send_will(option, 0);
45738689Sborman 		set_my_state_will(TELOPT_LINEMODE);
45838689Sborman 		slc_init();
45938689Sborman 		return;
46038689Sborman 
46138689Sborman 	    case TELOPT_ECHO:		/* We're never going to echo... */
46238689Sborman 	    default:
4636000Sroot 		break;
46438689Sborman 	    }
46538689Sborman 
46638689Sborman 	    if (new_state_ok) {
46738689Sborman 		set_my_want_state_will(option);
46838689Sborman 		send_will(option, 0);
46938689Sborman 	    } else {
47038689Sborman 		will_wont_resp[option]++;
47138689Sborman 		send_wont(option, 0);
47238689Sborman 	    }
47338689Sborman 	  } else {
47438689Sborman 	    /*
47538689Sborman 	     * Handle options that need more things done after the
47638689Sborman 	     * other side has acknowledged the option.
47738689Sborman 	     */
47838689Sborman 	    switch (option) {
47938689Sborman 	    case TELOPT_LINEMODE:
48038689Sborman #ifdef	KLUDGELINEMODE
48138689Sborman 		kludgelinemode = 0;
48238689Sborman #endif
48338689Sborman 		set_my_state_will(option);
48438689Sborman 		slc_init();
48538689Sborman 		return;
48638689Sborman 	    }
48738689Sborman 	  }
4886000Sroot 	}
48938689Sborman 	set_my_state_will(option);
4906000Sroot }
49127676Sminshall 
49238689Sborman static void
49338689Sborman dontoption(option)
49438689Sborman 	int option;
49538689Sborman {
49638689Sborman 
49738689Sborman 	if (will_wont_resp[option]) {
49838689Sborman 	    --will_wont_resp[option];
49938689Sborman 	    if (will_wont_resp[option] && my_state_is_wont(option))
50038689Sborman 		--will_wont_resp[option];
50138689Sborman 	}
50238689Sborman 
50338689Sborman 	if ((will_wont_resp[option] == 0) && my_want_state_is_will(option)) {
504*38811Sborman 	    switch (option) {
505*38811Sborman 	    case TELOPT_LINEMODE:
506*38811Sborman 		linemode = 0;	/* put us back to the default state */
507*38811Sborman 		break;
508*38811Sborman 	    }
50938689Sborman 	    /* we always accept a DONT */
51038689Sborman 	    set_my_want_state_wont(option);
51138689Sborman 	    send_wont(option, 0);
51238689Sborman 	}
51338689Sborman 	set_my_state_wont(option);
51438689Sborman }
51538689Sborman 
51627676Sminshall /*
51727676Sminshall  * suboption()
51827676Sminshall  *
51927676Sminshall  *	Look at the sub-option buffer, and try to be helpful to the other
52027676Sminshall  * side.
52127676Sminshall  *
52227676Sminshall  *	Currently we recognize:
52327676Sminshall  *
52427676Sminshall  *		Terminal type, send request.
52537219Sminshall  *		Terminal speed (send request).
52637219Sminshall  *		Local flow control (is request).
52738689Sborman  *		Linemode
52827676Sminshall  */
52927676Sminshall 
53038689Sborman static char tty1[] = { IAC, SB, TELOPT_TTYPE, TELQUAL_IS, 0 };
53138689Sborman static char tty2[] = { IAC, SE, 0 };
53238689Sborman 
53332377Sminshall static void
53427676Sminshall suboption()
53527676Sminshall {
53638689Sborman     printsub('<', subbuffer, subend-subbuffer+2);
53727676Sminshall     switch (subbuffer[0]&0xff) {
53827676Sminshall     case TELOPT_TTYPE:
53938689Sborman 	if (my_want_state_is_wont(TELOPT_TTYPE))
54038689Sborman 	    return;
54127676Sminshall 	if ((subbuffer[1]&0xff) != TELQUAL_SEND) {
54227676Sminshall 	    ;
54327676Sminshall 	} else {
54427676Sminshall 	    char *name;
54532377Sminshall 	    extern char *getenv();
54627676Sminshall 	    int len;
54727676Sminshall 
54832377Sminshall #if	defined(TN3270)
54932531Sminshall 	    if (tn3270_ttype()) {
55032377Sminshall 		return;
55132377Sminshall 	    }
55232377Sminshall #endif	/* defined(TN3270) */
55327676Sminshall 	    name = getenv("TERM");
55427676Sminshall 	    if ((name == 0) || ((len = strlen(name)) > 40)) {
55527676Sminshall 		name = "UNKNOWN";
55633492Sminshall 		len = strlen(name);
55727676Sminshall 	    }
55827676Sminshall 	    if ((len + 4+2) < NETROOM()) {
55937226Sminshall 		char temp[50];
56037226Sminshall 
56138689Sborman 		strcpy(temp, tty1);
56238689Sborman 		strcpy(&temp[4], name);
56338689Sborman 		upcase(&temp[4]);
56438689Sborman 		strcpy(&temp[4+len], tty2);
56538689Sborman 		len += 6;
56638689Sborman 		ring_supply_data(&netoring, temp, len);
56738689Sborman 		printsub('>', temp+2, len-2);
56832377Sminshall 	    } else {
56937226Sminshall 		ExitString("No room in buffer for terminal type.\n", 1);
57032377Sminshall 		/*NOTREACHED*/
57127676Sminshall 	    }
57227676Sminshall 	}
57337219Sminshall 	break;
57437219Sminshall     case TELOPT_TSPEED:
57538689Sborman 	if (my_want_state_is_wont(TELOPT_TSPEED))
57638689Sborman 	    return;
57737219Sminshall 	if ((subbuffer[1]&0xff) == TELQUAL_SEND) {
57838689Sborman 	    long ospeed,ispeed;
57938689Sborman 	    char temp[50];
58037219Sminshall 	    int len;
58127676Sminshall 
58237219Sminshall 	    TerminalSpeeds(&ispeed, &ospeed);
58337219Sminshall 
58438689Sborman 	    sprintf(temp, "%c%c%c%c%d,%d%c%c", IAC, SB, TELOPT_TSPEED,
58538689Sborman 		    TELQUAL_IS, ospeed, ispeed, IAC, SE);
58638689Sborman 	    len = strlen(temp+4) + 4;	/* temp[3] is 0 ... */
58737219Sminshall 
58838689Sborman 	    if (len < NETROOM()) {
58938689Sborman 		ring_supply_data(&netoring, temp, len);
59038689Sborman 		printsub('>', temp+2, len - 2);
59137219Sminshall 	    }
59237219Sminshall 	}
59337219Sminshall 	break;
59437219Sminshall     case TELOPT_LFLOW:
59538689Sborman 	if (my_want_state_is_wont(TELOPT_LFLOW))
59638689Sborman 	    return;
59737219Sminshall 	if ((subbuffer[1]&0xff) == 1) {
59837219Sminshall 	    localflow = 1;
59937219Sminshall 	} else if ((subbuffer[1]&0xff) == 0) {
60037219Sminshall 	    localflow = 0;
60137219Sminshall 	}
60237219Sminshall 	setcommandmode();
60338689Sborman 	setconnmode(0);
60437219Sminshall 	break;
60538689Sborman 
60638689Sborman     case TELOPT_LINEMODE:
60738689Sborman 	if (my_want_state_is_wont(TELOPT_LINEMODE))
60838689Sborman 	    return;
60938689Sborman 	switch (subbuffer[1]&0xff) {
61038689Sborman 	case WILL:
61138689Sborman 	    lm_will(&subbuffer[2], subend - &subbuffer[2]);
61238689Sborman 	    break;
61338689Sborman 	case WONT:
61438689Sborman 	    lm_wont(&subbuffer[2], subend - &subbuffer[2]);
61538689Sborman 	    break;
61638689Sborman 	case DO:
61738689Sborman 	    lm_do(&subbuffer[2], subend - &subbuffer[2]);
61838689Sborman 	    break;
61938689Sborman 	case DONT:
62038689Sborman 	    lm_dont(&subbuffer[2], subend - &subbuffer[2]);
62138689Sborman 	    break;
62238689Sborman 	case LM_SLC:
62338689Sborman 	    slc(&subbuffer[2], subend - &subbuffer[2]);
62438689Sborman 	    break;
62538689Sborman 	case LM_MODE:
62638689Sborman 	    lm_mode(&subbuffer[2], subend - &subbuffer[2], 0);
62738689Sborman 	    break;
62838689Sborman 	default:
62938689Sborman 		break;
63038689Sborman 	}
63138689Sborman 	break;
63227676Sminshall     default:
63327676Sminshall 	break;
63427676Sminshall     }
63527676Sminshall }
63638689Sborman 
63738689Sborman static char str_lm[] = { IAC, SB, TELOPT_LINEMODE, 0, 0, IAC, SE };
63838689Sborman 
63938689Sborman lm_will(cmd, len)
64038689Sborman char *cmd;
64138689Sborman {
64238689Sborman     switch(cmd[0]) {
64338689Sborman     case LM_FORWARDMASK:	/* We shouldn't ever get this... */
64438689Sborman     default:
64538689Sborman 	str_lm[3] = DONT;
64638689Sborman 	str_lm[4] = cmd[0];
64738689Sborman 	if (NETROOM() > sizeof(str_lm)) {
64838689Sborman 	    ring_supply_data(&netoring, str_lm, sizeof(str_lm));
64938689Sborman 	    printsub('>', &str_lm[2], sizeof(str_lm)-2);
65038689Sborman 	}
65138689Sborman /*@*/	else printf("lm_will: not enough room in buffer\n");
65238689Sborman 	break;
65338689Sborman     }
65438689Sborman }
65538689Sborman 
65638689Sborman lm_wont(cmd, len)
65738689Sborman char *cmd;
65838689Sborman {
65938689Sborman     switch(cmd[0]) {
66038689Sborman     case LM_FORWARDMASK:	/* We shouldn't ever get this... */
66138689Sborman     default:
66238689Sborman 	/* We are always DONT, so don't respond */
66338689Sborman 	return;
66438689Sborman     }
66538689Sborman }
66638689Sborman 
66738689Sborman lm_do(cmd, len)
66838689Sborman char *cmd;
66938689Sborman {
67038689Sborman     switch(cmd[0]) {
67138689Sborman     case LM_FORWARDMASK:
67238689Sborman     default:
67338689Sborman 	str_lm[3] = WONT;
67438689Sborman 	str_lm[4] = cmd[0];
67538689Sborman 	if (NETROOM() > sizeof(str_lm)) {
67638689Sborman 	    ring_supply_data(&netoring, str_lm, sizeof(str_lm));
67738689Sborman 	    printsub('>', &str_lm[2], sizeof(str_lm)-2);
67838689Sborman 	}
67938689Sborman /*@*/	else printf("lm_do: not enough room in buffer\n");
68038689Sborman 	break;
68138689Sborman     }
68238689Sborman }
68338689Sborman 
68438689Sborman lm_dont(cmd, len)
68538689Sborman char *cmd;
68638689Sborman {
68738689Sborman     switch(cmd[0]) {
68838689Sborman     case LM_FORWARDMASK:
68938689Sborman     default:
69038689Sborman 	/* we are always WONT, so don't respond */
69138689Sborman 	break;
69238689Sborman     }
69338689Sborman }
69438689Sborman 
69538689Sborman static char str_lm_mode[] = { IAC, SB, TELOPT_LINEMODE, LM_MODE, 0, IAC, SE };
69638689Sborman 
69738689Sborman lm_mode(cmd, len, init)
69838689Sborman char *cmd;
69938689Sborman int len, init;
70038689Sborman {
70138689Sborman 	if (len != 1)
70238689Sborman 		return;
70338689Sborman 	if ((linemode&(MODE_EDIT|MODE_TRAPSIG)) == *cmd)
70438689Sborman 		return;
70538689Sborman 	if (*cmd&MODE_ACK)
70638689Sborman 		return;
70738689Sborman 	linemode = (*cmd&(MODE_EDIT|MODE_TRAPSIG));
70838689Sborman 	str_lm_mode[4] = linemode;
70938689Sborman 	if (!init)
71038689Sborman 	    str_lm_mode[4] |= MODE_ACK;
71138689Sborman 	if (NETROOM() > sizeof(str_lm_mode)) {
71238689Sborman 	    ring_supply_data(&netoring, str_lm_mode, sizeof(str_lm_mode));
71338689Sborman 	    printsub('>', &str_lm_mode[2], sizeof(str_lm_mode)-2);
71438689Sborman 	}
71538689Sborman /*@*/	else printf("lm_mode: not enough room in buffer\n");
71638689Sborman 	setconnmode(0);	/* set changed mode */
71738689Sborman }
71838689Sborman 
71932377Sminshall 
72027088Sminshall 
72138689Sborman /*
72238689Sborman  * slc()
72338689Sborman  * Handle special character suboption of LINEMODE.
72438689Sborman  */
72538689Sborman 
72638689Sborman struct spc {
72738689Sborman 	char val;
72838689Sborman 	char *valp;
72938689Sborman 	char flags;	/* Current flags & level */
73038689Sborman 	char mylevel;	/* Maximum level & flags */
73138689Sborman } spc_data[NSLC+1];
73238689Sborman 
73338689Sborman #define SLC_IMPORT	0
73438689Sborman #define	SLC_EXPORT	1
73538689Sborman #define SLC_RVALUE	2
73638689Sborman static int slc_mode = SLC_EXPORT;
73738689Sborman 
73838689Sborman slc_init()
73938689Sborman {
74038689Sborman 	register struct spc *spcp;
74138689Sborman 	extern char *tcval();
74238689Sborman 
74338689Sborman 	localchars = 1;
74438689Sborman 	for (spcp = spc_data; spcp < &spc_data[NSLC+1]; spcp++) {
74538689Sborman 		spcp->val = 0;
74638689Sborman 		spcp->valp = 0;
74738689Sborman 		spcp->flags = spcp->mylevel = SLC_NOSUPPORT;
74838689Sborman 	}
74938689Sborman 
75038689Sborman #define	initfunc(func, flags) { \
75138689Sborman 					spcp = &spc_data[func]; \
75238689Sborman 					if (spcp->valp = tcval(func)) { \
75338689Sborman 					    spcp->val = *spcp->valp; \
75438689Sborman 					    spcp->mylevel = SLC_VARIABLE|flags; \
75538689Sborman 					} else { \
75638689Sborman 					    spcp->val = 0; \
75738689Sborman 					    spcp->mylevel = SLC_DEFAULT; \
75838689Sborman 					} \
75938689Sborman 				    }
76038689Sborman 
76138689Sborman 	initfunc(SLC_SYNCH, 0);
76238689Sborman 	/* No BRK */
76338689Sborman 	initfunc(SLC_AO, 0);
76438689Sborman 	initfunc(SLC_AYT, 0);
76538689Sborman 	/* No EOR */
76638689Sborman 	initfunc(SLC_ABORT, SLC_FLUSHIN|SLC_FLUSHOUT);
76738689Sborman 	initfunc(SLC_EOF, 0);
76838689Sborman #ifndef	CRAY
76938689Sborman 	initfunc(SLC_SUSP, SLC_FLUSHIN);
77038689Sborman #endif
77138689Sborman 	initfunc(SLC_EC, 0);
77238689Sborman 	initfunc(SLC_EL, 0);
77338689Sborman #ifndef	CRAY
77438689Sborman 	initfunc(SLC_EW, 0);
77538689Sborman 	initfunc(SLC_RP, 0);
77638689Sborman 	initfunc(SLC_LNEXT, 0);
77738689Sborman #endif
77838689Sborman 	initfunc(SLC_XON, 0);
77938689Sborman 	initfunc(SLC_XOFF, 0);
78038689Sborman #ifdef	CRAY
78138689Sborman 	spc_data[SLC_XON].mylevel = SLC_CANTCHANGE;
78238689Sborman 	spc_data[SLC_XOFF].mylevel = SLC_CANTCHANGE;
78338689Sborman #endif
78438689Sborman 	/* No FORW1 */
78538689Sborman 	/* No FORW2 */
78638689Sborman 
78738689Sborman 	initfunc(SLC_IP, SLC_FLUSHIN|SLC_FLUSHOUT);
78838689Sborman #undef	initfunc
78938689Sborman 
79038689Sborman 	if (slc_mode == SLC_EXPORT)
79138689Sborman 		slc_export();
79238689Sborman 	else
79338689Sborman 		slc_import(1);
79438689Sborman 
79538689Sborman }
79638689Sborman 
79738689Sborman slcstate()
79838689Sborman {
79938689Sborman     printf("Special characters are %s values\n",
80038689Sborman 		slc_mode == SLC_IMPORT ? "remote default" :
80138689Sborman 		slc_mode == SLC_EXPORT ? "local" :
80238689Sborman 					 "remote");
80338689Sborman }
80438689Sborman 
80538689Sborman slc_mode_export()
80638689Sborman {
80738689Sborman     slc_mode = SLC_EXPORT;
80838689Sborman     if (my_state_is_will(TELOPT_LINEMODE))
80938689Sborman 	slc_export();
81038689Sborman }
81138689Sborman 
81238689Sborman slc_mode_import(def)
81338689Sborman {
81438689Sborman     slc_mode = def ? SLC_IMPORT : SLC_RVALUE;
81538689Sborman     if (my_state_is_will(TELOPT_LINEMODE))
81638689Sborman 	slc_import(def);
81738689Sborman }
81838689Sborman 
81938689Sborman char slc_import_val[] = {
82038689Sborman 	IAC, SB, TELOPT_LINEMODE, LM_SLC, 0, SLC_VARIABLE, 0, IAC, SE
82138689Sborman };
82238689Sborman char slc_import_def[] = {
82338689Sborman 	IAC, SB, TELOPT_LINEMODE, LM_SLC, 0, SLC_DEFAULT, 0, IAC, SE
82438689Sborman };
82538689Sborman 
82638689Sborman slc_import(def)
82738689Sborman int def;
82838689Sborman {
82938689Sborman     if (NETROOM() > sizeof(slc_import_val)) {
83038689Sborman 	if (def) {
83138689Sborman 	    ring_supply_data(&netoring, slc_import_def, sizeof(slc_import_def));
83238689Sborman 	    printsub('>', &slc_import_def[2], sizeof(slc_import_def)-2);
83338689Sborman 	} else {
83438689Sborman 	    ring_supply_data(&netoring, slc_import_val, sizeof(slc_import_val));
83538689Sborman 	    printsub('>', &slc_import_val[2], sizeof(slc_import_val)-2);
83638689Sborman 	}
83738689Sborman     }
83838689Sborman /*@*/ else printf("slc_import: not enough room\n");
83938689Sborman }
84038689Sborman 
84138689Sborman slc_export()
84238689Sborman {
84338689Sborman     register struct spc *spcp;
84438689Sborman 
84538689Sborman     TerminalDefaultChars();
84638689Sborman 
84738689Sborman     slc_start_reply();
84838689Sborman     for (spcp = &spc_data[1]; spcp < &spc_data[NSLC+1]; spcp++) {
84938689Sborman 	if (spcp->mylevel != SLC_NOSUPPORT) {
85038689Sborman 	    spcp->flags = spcp->mylevel;
85138689Sborman 	    if (spcp->valp)
85238689Sborman 		spcp->val = *spcp->valp;
85338689Sborman 	    slc_add_reply(spcp - spc_data, spcp->mylevel, spcp->val);
85438689Sborman 	}
85538689Sborman     }
85638689Sborman     slc_end_reply();
85738689Sborman     if (slc_update())
85838689Sborman 	setconnmode(1);	/* set the  new character values */
85938689Sborman }
86038689Sborman 
86138689Sborman slc(cp, len)
86238689Sborman register char *cp;
86338689Sborman int len;
86438689Sborman {
86538689Sborman 	register struct spc *spcp;
86638689Sborman 	register int func,level;
86738689Sborman 
86838689Sborman 	slc_start_reply();
86938689Sborman 
87038689Sborman 	for (; len >= 3; len -=3, cp +=3) {
87138689Sborman 
87238689Sborman 		func = cp[SLC_FUNC];
87338689Sborman 
87438689Sborman 		if (func == 0) {
87538689Sborman 			/*
87638689Sborman 			 * Client side: always ignore 0 function.
87738689Sborman 			 */
87838689Sborman 			continue;
87938689Sborman 		}
88038689Sborman 		if (func > NSLC) {
88138689Sborman 			if (cp[SLC_FLAGS] & SLC_LEVELBITS != SLC_NOSUPPORT)
88238689Sborman 				slc_add_reply(func, SLC_NOSUPPORT, 0);
88338689Sborman 			continue;
88438689Sborman 		}
88538689Sborman 
88638689Sborman 		spcp = &spc_data[func];
88738689Sborman 
88838689Sborman 		level = cp[SLC_FLAGS]&(SLC_LEVELBITS|SLC_ACK);
88938689Sborman 
89038689Sborman 		if ((cp[SLC_VALUE] == spcp->val) &&
89138689Sborman 		    ((level&SLC_LEVELBITS) == (spcp->flags&SLC_LEVELBITS))) {
89238689Sborman 			continue;
89338689Sborman 		}
89438689Sborman 
89538689Sborman 		if (level == (SLC_DEFAULT|SLC_ACK)) {
89638689Sborman 			/*
89738689Sborman 			 * This is an error condition, the SLC_ACK
89838689Sborman 			 * bit should never be set for the SLC_DEFAULT
89938689Sborman 			 * level.  Our best guess to recover is to
90038689Sborman 			 * ignore the SLC_ACK bit.
90138689Sborman 			 */
90238689Sborman 			cp[SLC_FLAGS] &= ~SLC_ACK;
90338689Sborman 		}
90438689Sborman 
90538689Sborman 		if (level == ((spcp->flags&SLC_LEVELBITS)|SLC_ACK)) {
90638689Sborman 			spcp->val = cp[SLC_VALUE];
90738689Sborman 			spcp->flags = cp[SLC_FLAGS];	/* include SLC_ACK */
90838689Sborman 			continue;
90938689Sborman 		}
91038689Sborman 
91138689Sborman 		level &= ~SLC_ACK;
91238689Sborman 
91338689Sborman 		if (level <= (spcp->mylevel&SLC_LEVELBITS)) {
91438689Sborman 			spcp->flags = cp[SLC_FLAGS]|SLC_ACK;
91538689Sborman 			spcp->val = cp[SLC_VALUE];
91638689Sborman 		}
91738689Sborman 		if (level == SLC_DEFAULT) {
91838689Sborman 			if ((spcp->mylevel&SLC_LEVELBITS) != SLC_DEFAULT)
91938689Sborman 				spcp->flags = spcp->mylevel;
92038689Sborman 			else
92138689Sborman 				spcp->flags = SLC_NOSUPPORT;
92238689Sborman 		}
92338689Sborman 		slc_add_reply(func, spcp->flags, spcp->val);
92438689Sborman 	}
92538689Sborman 	slc_end_reply();
92638689Sborman 	if (slc_update())
92738689Sborman 		setconnmode(1);	/* set the  new character values */
92838689Sborman }
92938689Sborman 
93038689Sborman slc_check()
93138689Sborman {
93238689Sborman     register struct spc *spcp;
93338689Sborman 
93438689Sborman     slc_start_reply();
93538689Sborman     for (spcp = &spc_data[1]; spcp < &spc_data[NSLC+1]; spcp++) {
93638689Sborman 	if (spcp->valp && spcp->val != *spcp->valp) {
93738689Sborman 	    spcp->val = *spcp->valp;
93838689Sborman 	    slc_add_reply(spcp - spc_data, spcp->mylevel, spcp->val);
93938689Sborman 	}
94038689Sborman     }
94138689Sborman     slc_end_reply();
94238689Sborman     setconnmode(1);
94338689Sborman }
94438689Sborman 
94538689Sborman 
94638689Sborman unsigned char slc_reply[128];
94738689Sborman unsigned char *slc_replyp;
94838689Sborman slc_start_reply()
94938689Sborman {
95038689Sborman 	slc_replyp = slc_reply;
95138689Sborman 	*slc_replyp++ = IAC;
95238689Sborman 	*slc_replyp++ = SB;
95338689Sborman 	*slc_replyp++ = TELOPT_LINEMODE;
95438689Sborman 	*slc_replyp++ = LM_SLC;
95538689Sborman }
95638689Sborman 
95738689Sborman slc_add_reply(func, flags, value)
95838689Sborman char func;
95938689Sborman char flags;
96038689Sborman char value;
96138689Sborman {
96238689Sborman 	if ((*slc_replyp++ = func) == IAC)
96338689Sborman 		*slc_replyp++ = IAC;
96438689Sborman 	if ((*slc_replyp++ = flags) == IAC)
96538689Sborman 		*slc_replyp++ = IAC;
96638689Sborman 	if ((*slc_replyp++ = value) == IAC)
96738689Sborman 		*slc_replyp++ = IAC;
96838689Sborman }
96938689Sborman 
97038689Sborman slc_end_reply()
97138689Sborman {
97238689Sborman     register char *cp;
97338689Sborman     register int len;
97438689Sborman 
97538689Sborman     *slc_replyp++ = IAC;
97638689Sborman     *slc_replyp++ = SE;
97738689Sborman     len = slc_replyp - slc_reply;
97838689Sborman     if (len <= 6)
97938689Sborman 	return;
98038689Sborman     if (NETROOM() > len) {
98138689Sborman 	ring_supply_data(&netoring, slc_reply, slc_replyp - slc_reply);
98238689Sborman 	printsub('>', &slc_reply[2], slc_replyp - slc_reply - 2);
98338689Sborman     }
98438689Sborman /*@*/else printf("slc_end_reply: not enough room\n");
98538689Sborman }
98638689Sborman 
98738689Sborman slc_update()
98838689Sborman {
98938689Sborman 	register struct spc *spcp;
99038689Sborman 	int need_update = 0;
99138689Sborman 
99238689Sborman 	for (spcp = &spc_data[1]; spcp < &spc_data[NSLC+1]; spcp++) {
99338689Sborman 		if (!(spcp->flags&SLC_ACK))
99438689Sborman 			continue;
99538689Sborman 		spcp->flags &= ~SLC_ACK;
99638689Sborman 		if (spcp->valp && (*spcp->valp != spcp->val)) {
99738689Sborman 			*spcp->valp = spcp->val;
99838689Sborman 			need_update = 1;
99938689Sborman 		}
100038689Sborman 	}
100138689Sborman 	return(need_update);
100238689Sborman }
100338689Sborman 
100438689Sborman 
100538689Sborman 
100633804Sminshall int
100732377Sminshall telrcv()
100827110Sminshall {
100932377Sminshall     register int c;
101032385Sminshall     register int scc;
101132385Sminshall     register char *sbp;
101232385Sminshall     int count;
101332385Sminshall     int returnValue = 0;
101427088Sminshall 
101532385Sminshall     scc = 0;
101632385Sminshall     count = 0;
101732385Sminshall     while (TTYROOM() > 2) {
101832385Sminshall 	if (scc == 0) {
101932385Sminshall 	    if (count) {
102032528Sminshall 		ring_consumed(&netiring, count);
102132385Sminshall 		returnValue = 1;
102232385Sminshall 		count = 0;
102332385Sminshall 	    }
102432528Sminshall 	    sbp = netiring.consume;
102532528Sminshall 	    scc = ring_full_consecutive(&netiring);
102632385Sminshall 	    if (scc == 0) {
102732385Sminshall 		/* No more data coming in */
102832385Sminshall 		break;
102932385Sminshall 	    }
103032385Sminshall 	}
103132385Sminshall 
103232385Sminshall 	c = *sbp++ & 0xff, scc--; count++;
103332385Sminshall 
103432377Sminshall 	switch (telrcv_state) {
103527110Sminshall 
103632377Sminshall 	case TS_CR:
103732377Sminshall 	    telrcv_state = TS_DATA;
103835518Sminshall 	    if (c == '\0') {
103935518Sminshall 		break;	/* Ignore \0 after CR */
104038689Sborman 	    } else if ((c == '\n') && my_want_state_is_dont(TELOPT_ECHO) && !crmod) {
104135518Sminshall 		TTYADD(c);
104235518Sminshall 		break;
104332377Sminshall 	    }
104435518Sminshall 	    /* Else, fall through */
104527088Sminshall 
104632377Sminshall 	case TS_DATA:
104732377Sminshall 	    if (c == IAC) {
104832377Sminshall 		telrcv_state = TS_IAC;
104933804Sminshall 		break;
105032377Sminshall 	    }
105132377Sminshall #	    if defined(TN3270)
105232377Sminshall 	    if (In3270) {
105332377Sminshall 		*Ifrontp++ = c;
105432385Sminshall 		while (scc > 0) {
105532385Sminshall 		    c = *sbp++ & 0377, scc--; count++;
105632377Sminshall 		    if (c == IAC) {
105732377Sminshall 			telrcv_state = TS_IAC;
105834304Sminshall 			break;
105932377Sminshall 		    }
106032377Sminshall 		    *Ifrontp++ = c;
106132377Sminshall 		}
106232377Sminshall 	    } else
106332377Sminshall #	    endif /* defined(TN3270) */
106435518Sminshall 		    /*
106535518Sminshall 		     * The 'crmod' hack (see following) is needed
106635518Sminshall 		     * since we can't * set CRMOD on output only.
106735518Sminshall 		     * Machines like MULTICS like to send \r without
106835518Sminshall 		     * \n; since we must turn off CRMOD to get proper
106935518Sminshall 		     * input, the mapping is done here (sigh).
107035518Sminshall 		     */
107138689Sborman 	    if ((c == '\r') && my_want_state_is_dont(TELOPT_BINARY)) {
107235518Sminshall 		if (scc > 0) {
107335518Sminshall 		    c = *sbp&0xff;
107435518Sminshall 		    if (c == 0) {
107535518Sminshall 			sbp++, scc--; count++;
107635518Sminshall 			/* a "true" CR */
107732377Sminshall 			TTYADD('\r');
107838689Sborman 		    } else if (my_want_state_is_dont(TELOPT_ECHO) &&
107935518Sminshall 					(c == '\n')) {
108035518Sminshall 			sbp++, scc--; count++;
108132377Sminshall 			TTYADD('\n');
108235518Sminshall 		    } else {
108335518Sminshall 			TTYADD('\r');
108435518Sminshall 			if (crmod) {
108535518Sminshall 				TTYADD('\n');
108632377Sminshall 			}
108732377Sminshall 		    }
108835518Sminshall 		} else {
108935518Sminshall 		    telrcv_state = TS_CR;
109035518Sminshall 		    TTYADD('\r');
109135518Sminshall 		    if (crmod) {
109235518Sminshall 			    TTYADD('\n');
109335518Sminshall 		    }
109432377Sminshall 		}
109532377Sminshall 	    } else {
109632377Sminshall 		TTYADD(c);
109732377Sminshall 	    }
109832377Sminshall 	    continue;
109927088Sminshall 
110032377Sminshall 	case TS_IAC:
110138689Sborman process_iac:
110232377Sminshall 	    switch (c) {
110332377Sminshall 
110432377Sminshall 	    case WILL:
110532377Sminshall 		telrcv_state = TS_WILL;
110632377Sminshall 		continue;
110727261Sminshall 
110832377Sminshall 	    case WONT:
110932377Sminshall 		telrcv_state = TS_WONT;
111032377Sminshall 		continue;
111127261Sminshall 
111232377Sminshall 	    case DO:
111332377Sminshall 		telrcv_state = TS_DO;
111432377Sminshall 		continue;
111527261Sminshall 
111632377Sminshall 	    case DONT:
111732377Sminshall 		telrcv_state = TS_DONT;
111832377Sminshall 		continue;
111927261Sminshall 
112032377Sminshall 	    case DM:
112132377Sminshall 		    /*
112232377Sminshall 		     * We may have missed an urgent notification,
112332377Sminshall 		     * so make sure we flush whatever is in the
112432377Sminshall 		     * buffer currently.
112532377Sminshall 		     */
112632377Sminshall 		SYNCHing = 1;
112732377Sminshall 		ttyflush(1);
112832554Sminshall 		SYNCHing = stilloob();
112932377Sminshall 		settimer(gotDM);
113032377Sminshall 		break;
113127088Sminshall 
113232377Sminshall 	    case NOP:
113332377Sminshall 	    case GA:
113432377Sminshall 		break;
113527088Sminshall 
113632377Sminshall 	    case SB:
113732377Sminshall 		SB_CLEAR();
113832377Sminshall 		telrcv_state = TS_SB;
113938689Sborman 		printoption("RCVD", "IAC", SB);
114032377Sminshall 		continue;
114127261Sminshall 
114232377Sminshall #	    if defined(TN3270)
114332377Sminshall 	    case EOR:
114432377Sminshall 		if (In3270) {
114532377Sminshall 		    Ibackp += DataFromNetwork(Ibackp, Ifrontp-Ibackp, 1);
114632377Sminshall 		    if (Ibackp == Ifrontp) {
114732377Sminshall 			Ibackp = Ifrontp = Ibuf;
114832377Sminshall 			ISend = 0;	/* should have been! */
114932377Sminshall 		    } else {
115032377Sminshall 			ISend = 1;
115127088Sminshall 		    }
115227088Sminshall 		}
115327088Sminshall 		break;
115432377Sminshall #	    endif /* defined(TN3270) */
115532377Sminshall 
115632377Sminshall 	    case IAC:
115732377Sminshall #	    if !defined(TN3270)
115832377Sminshall 		TTYADD(IAC);
115932377Sminshall #	    else /* !defined(TN3270) */
116032377Sminshall 		if (In3270) {
116132377Sminshall 		    *Ifrontp++ = IAC;
116232377Sminshall 		} else {
116332377Sminshall 		    TTYADD(IAC);
116432377Sminshall 		}
116532377Sminshall #	    endif /* !defined(TN3270) */
116627088Sminshall 		break;
116732377Sminshall 
116827088Sminshall 	    default:
116927088Sminshall 		break;
117027088Sminshall 	    }
117132377Sminshall 	    telrcv_state = TS_DATA;
117232377Sminshall 	    continue;
117327088Sminshall 
117432377Sminshall 	case TS_WILL:
117537226Sminshall 	    printoption("RCVD", "will", c);
117638689Sborman 	    willoption(c);
117732377Sminshall 	    SetIn3270();
117832377Sminshall 	    telrcv_state = TS_DATA;
117932377Sminshall 	    continue;
118027110Sminshall 
118132377Sminshall 	case TS_WONT:
118237226Sminshall 	    printoption("RCVD", "wont", c);
118338689Sborman 	    wontoption(c);
118432377Sminshall 	    SetIn3270();
118532377Sminshall 	    telrcv_state = TS_DATA;
118632377Sminshall 	    continue;
118727088Sminshall 
118832377Sminshall 	case TS_DO:
118937226Sminshall 	    printoption("RCVD", "do", c);
119037226Sminshall 	    dooption(c);
119132377Sminshall 	    SetIn3270();
119237219Sminshall 	    if (c == TELOPT_NAWS) {
119337219Sminshall 		sendnaws();
119437219Sminshall 	    } else if (c == TELOPT_LFLOW) {
119537219Sminshall 		localflow = 1;
119637219Sminshall 		setcommandmode();
119738689Sborman 		setconnmode(0);
119837219Sminshall 	    }
119932377Sminshall 	    telrcv_state = TS_DATA;
120032377Sminshall 	    continue;
120127088Sminshall 
120232377Sminshall 	case TS_DONT:
120337226Sminshall 	    printoption("RCVD", "dont", c);
120438689Sborman 	    dontoption(c);
120537226Sminshall 	    flushline = 1;
120638689Sborman 	    setconnmode(0);	/* set new tty mode (maybe) */
120732377Sminshall 	    SetIn3270();
120832377Sminshall 	    telrcv_state = TS_DATA;
120932377Sminshall 	    continue;
121027088Sminshall 
121132377Sminshall 	case TS_SB:
121232377Sminshall 	    if (c == IAC) {
121332377Sminshall 		telrcv_state = TS_SE;
121432377Sminshall 	    } else {
121532377Sminshall 		SB_ACCUM(c);
121632377Sminshall 	    }
121732377Sminshall 	    continue;
121827088Sminshall 
121932377Sminshall 	case TS_SE:
122032377Sminshall 	    if (c != SE) {
122132377Sminshall 		if (c != IAC) {
122238689Sborman 		    /*
122338689Sborman 		     * This is an error.  We only expect to get
122438689Sborman 		     * "IAC IAC" or "IAC SE".  Several things may
122538689Sborman 		     * have happend.  An IAC was not doubled, the
122638689Sborman 		     * IAC SE was left off, or another option got
122738689Sborman 		     * inserted into the suboption are all possibilities.
122838689Sborman 		     * If we assume that the IAC was not doubled,
122938689Sborman 		     * and really the IAC SE was left off, we could
123038689Sborman 		     * get into an infinate loop here.  So, instead,
123138689Sborman 		     * we terminate the suboption, and process the
123238689Sborman 		     * partial suboption if we can.
123338689Sborman 		     */
123438689Sborman 		    SB_TERM();
123532377Sminshall 		    SB_ACCUM(IAC);
123638689Sborman 		    SB_ACCUM(c);
123738689Sborman 		    printoption("In SUBOPTION processing, RCVD", "IAC", c);
123838689Sborman 		    suboption();	/* handle sub-option */
123938689Sborman 		    SetIn3270();
124038689Sborman 		    telrcv_state = TS_IAC;
124138689Sborman 		    goto process_iac;
124232377Sminshall 		}
124332377Sminshall 		SB_ACCUM(c);
124432377Sminshall 		telrcv_state = TS_SB;
124532377Sminshall 	    } else {
124632377Sminshall 		SB_TERM();
124738689Sborman 		SB_ACCUM(IAC);
124838689Sborman 		SB_ACCUM(SE);
124932377Sminshall 		suboption();	/* handle sub-option */
125032377Sminshall 		SetIn3270();
125132377Sminshall 		telrcv_state = TS_DATA;
125232377Sminshall 	    }
125327088Sminshall 	}
125427088Sminshall     }
125532667Sminshall     if (count)
125632667Sminshall 	ring_consumed(&netiring, count);
125732385Sminshall     return returnValue||count;
125827088Sminshall }
125932385Sminshall 
126032385Sminshall static int
126132554Sminshall telsnd()
126232385Sminshall {
126332385Sminshall     int tcc;
126432385Sminshall     int count;
126532385Sminshall     int returnValue = 0;
126632385Sminshall     char *tbp;
126732385Sminshall 
126832385Sminshall     tcc = 0;
126932385Sminshall     count = 0;
127032385Sminshall     while (NETROOM() > 2) {
127132385Sminshall 	register int sc;
127232385Sminshall 	register int c;
127332385Sminshall 
127432385Sminshall 	if (tcc == 0) {
127532385Sminshall 	    if (count) {
127632528Sminshall 		ring_consumed(&ttyiring, count);
127732385Sminshall 		returnValue = 1;
127832385Sminshall 		count = 0;
127932385Sminshall 	    }
128032528Sminshall 	    tbp = ttyiring.consume;
128132528Sminshall 	    tcc = ring_full_consecutive(&ttyiring);
128232385Sminshall 	    if (tcc == 0) {
128332385Sminshall 		break;
128432385Sminshall 	    }
128532385Sminshall 	}
128632385Sminshall 	c = *tbp++ & 0xff, sc = strip(c), tcc--; count++;
128732385Sminshall 	if (sc == escape) {
128838689Sborman 	    /*
128938689Sborman 	     * Double escape is a pass through of a single escape character.
129038689Sborman 	     */
129138689Sborman 	    if (tcc && strip(*tbp) == escape) {
129238689Sborman 		tbp++;
129338689Sborman 		tcc--;
129438689Sborman 		count++;
129538689Sborman 	    } else {
129638689Sborman 		command(0, tbp, tcc);
129738689Sborman 		count += tcc;
129838689Sborman 		tcc = 0;
129938689Sborman 		flushline = 1;
130038689Sborman 		break;
130138689Sborman 	    }
130238689Sborman 	}
130338689Sborman #ifdef	KLUDGELINEMODE
130438689Sborman 	if (kludgelinemode && (globalmode&MODE_EDIT) && (sc == echoc)) {
130532385Sminshall 	    if (tcc > 0 && strip(*tbp) == echoc) {
130632385Sminshall 		tcc--; tbp++; count++;
130732385Sminshall 	    } else {
130832385Sminshall 		dontlecho = !dontlecho;
130932385Sminshall 		settimer(echotoggle);
131038689Sborman 		setconnmode(0);
131132385Sminshall 		flushline = 1;
131232385Sminshall 		break;
131332385Sminshall 	    }
131432385Sminshall 	}
131538689Sborman #endif
131638689Sborman 	if (MODE_LOCAL_CHARS(globalmode)) {
131732385Sminshall 	    if (TerminalSpecialChars(sc) == 0) {
131832385Sminshall 		break;
131932385Sminshall 	    }
132032385Sminshall 	}
132138689Sborman 	if (my_want_state_is_wont(TELOPT_BINARY)) {
132232385Sminshall 	    switch (c) {
132332385Sminshall 	    case '\n':
132432385Sminshall 		    /*
132532385Sminshall 		     * If we are in CRMOD mode (\r ==> \n)
132632385Sminshall 		     * on our local machine, then probably
132732385Sminshall 		     * a newline (unix) is CRLF (TELNET).
132832385Sminshall 		     */
132932385Sminshall 		if (MODE_LOCAL_CHARS(globalmode)) {
133032385Sminshall 		    NETADD('\r');
133132385Sminshall 		}
133232385Sminshall 		NETADD('\n');
133332385Sminshall 		flushline = 1;
133432385Sminshall 		break;
133532385Sminshall 	    case '\r':
133632385Sminshall 		if (!crlf) {
133732385Sminshall 		    NET2ADD('\r', '\0');
133832385Sminshall 		} else {
133932385Sminshall 		    NET2ADD('\r', '\n');
134032385Sminshall 		}
134132385Sminshall 		flushline = 1;
134232385Sminshall 		break;
134332385Sminshall 	    case IAC:
134432385Sminshall 		NET2ADD(IAC, IAC);
134532385Sminshall 		break;
134632385Sminshall 	    default:
134732385Sminshall 		NETADD(c);
134832385Sminshall 		break;
134932385Sminshall 	    }
135032385Sminshall 	} else if (c == IAC) {
135132385Sminshall 	    NET2ADD(IAC, IAC);
135232385Sminshall 	} else {
135332385Sminshall 	    NETADD(c);
135432385Sminshall 	}
135532385Sminshall     }
135632667Sminshall     if (count)
135732667Sminshall 	ring_consumed(&ttyiring, count);
135832385Sminshall     return returnValue||count;		/* Non-zero if we did anything */
135932385Sminshall }
136032377Sminshall 
136127088Sminshall /*
136232377Sminshall  * Scheduler()
136332377Sminshall  *
136432377Sminshall  * Try to do something.
136532377Sminshall  *
136632377Sminshall  * If we do something useful, return 1; else return 0.
136732377Sminshall  *
136827110Sminshall  */
136927110Sminshall 
137027110Sminshall 
137132377Sminshall int
137232377Sminshall Scheduler(block)
137332377Sminshall int	block;			/* should we block in the select ? */
137427110Sminshall {
137532377Sminshall 		/* One wants to be a bit careful about setting returnValue
137632377Sminshall 		 * to one, since a one implies we did some useful work,
137732377Sminshall 		 * and therefore probably won't be called to block next
137832377Sminshall 		 * time (TN3270 mode only).
137932377Sminshall 		 */
138032531Sminshall     int returnValue;
138132531Sminshall     int netin, netout, netex, ttyin, ttyout;
138227110Sminshall 
138332531Sminshall     /* Decide which rings should be processed */
138432531Sminshall 
138532531Sminshall     netout = ring_full_count(&netoring) &&
138638689Sborman 	    (flushline ||
138738689Sborman 		(my_want_state_is_wont(TELOPT_LINEMODE)
138838689Sborman #ifdef	KLUDGELINEMODE
138938689Sborman 			&& (!kludgelinemode || my_want_state_is_do(TELOPT_SGA))
139038689Sborman #endif
139138689Sborman 		) ||
139238689Sborman 			my_want_state_is_will(TELOPT_BINARY));
139332531Sminshall     ttyout = ring_full_count(&ttyoring);
139432531Sminshall 
139532377Sminshall #if	defined(TN3270)
139632531Sminshall     ttyin = ring_empty_count(&ttyiring) && (shell_active == 0);
139732377Sminshall #else	/* defined(TN3270) */
139832531Sminshall     ttyin = ring_empty_count(&ttyiring);
139932377Sminshall #endif	/* defined(TN3270) */
140032531Sminshall 
140132531Sminshall #if	defined(TN3270)
140232531Sminshall     netin = ring_empty_count(&netiring);
140332377Sminshall #   else /* !defined(TN3270) */
140432531Sminshall     netin = !ISend && ring_empty_count(&netiring);
140532377Sminshall #   endif /* !defined(TN3270) */
140632531Sminshall 
140732531Sminshall     netex = !SYNCHing;
140832531Sminshall 
140932531Sminshall     /* If we have seen a signal recently, reset things */
141032377Sminshall #   if defined(TN3270) && defined(unix)
141132377Sminshall     if (HaveInput) {
141232377Sminshall 	HaveInput = 0;
141332377Sminshall 	signal(SIGIO, inputAvailable);
141432377Sminshall     }
141532377Sminshall #endif	/* defined(TN3270) && defined(unix) */
141632377Sminshall 
141732531Sminshall     /* Call to system code to process rings */
141827178Sminshall 
141932531Sminshall     returnValue = process_rings(netin, netout, netex, ttyin, ttyout, !block);
142027178Sminshall 
142132531Sminshall     /* Now, look at the input rings, looking for work to do. */
142232377Sminshall 
142332531Sminshall     if (ring_full_count(&ttyiring)) {
142432377Sminshall #   if defined(TN3270)
142532377Sminshall 	if (In3270) {
142634848Sminshall 	    int c;
142734848Sminshall 
142833804Sminshall 	    c = DataFromTerminal(ttyiring.consume,
142932528Sminshall 					ring_full_consecutive(&ttyiring));
143032377Sminshall 	    if (c) {
143132377Sminshall 		returnValue = 1;
143232667Sminshall 	        ring_consumed(&ttyiring, c);
143332377Sminshall 	    }
143432377Sminshall 	} else {
143532377Sminshall #   endif /* defined(TN3270) */
143632554Sminshall 	    returnValue |= telsnd();
143732377Sminshall #   if defined(TN3270)
143827178Sminshall 	}
143932531Sminshall #   endif /* defined(TN3270) */
144027178Sminshall     }
144132377Sminshall 
144232528Sminshall     if (ring_full_count(&netiring)) {
144332377Sminshall #	if !defined(TN3270)
144432385Sminshall 	returnValue |= telrcv();
144532377Sminshall #	else /* !defined(TN3270) */
144632377Sminshall 	returnValue = Push3270();
144732377Sminshall #	endif /* !defined(TN3270) */
144832377Sminshall     }
144932377Sminshall     return returnValue;
145027178Sminshall }
145127178Sminshall 
145227178Sminshall /*
145332377Sminshall  * Select from tty and network...
145427088Sminshall  */
145532377Sminshall void
145632377Sminshall telnet()
145727088Sminshall {
145832531Sminshall     sys_telnet_init();
145927088Sminshall 
146032377Sminshall #   if !defined(TN3270)
146132377Sminshall     if (telnetport) {
146238689Sborman 	send_do(TELOPT_SGA, 1);
146338689Sborman 	send_will(TELOPT_TTYPE, 1);
146438689Sborman 	send_will(TELOPT_NAWS, 1);
146538689Sborman 	send_will(TELOPT_TSPEED, 1);
146638689Sborman 	send_will(TELOPT_LFLOW, 1);
146738689Sborman 	send_will(TELOPT_LINEMODE, 1);
146827178Sminshall     }
146932377Sminshall #   endif /* !defined(TN3270) */
147027088Sminshall 
147132377Sminshall #   if !defined(TN3270)
147232377Sminshall     for (;;) {
147332385Sminshall 	int schedValue;
147432385Sminshall 
147532385Sminshall 	while ((schedValue = Scheduler(0)) != 0) {
147632385Sminshall 	    if (schedValue == -1) {
147732385Sminshall 		setcommandmode();
147832385Sminshall 		return;
147932385Sminshall 	    }
148032385Sminshall 	}
148132385Sminshall 
148232531Sminshall 	if (Scheduler(1) == -1) {
148332377Sminshall 	    setcommandmode();
148432377Sminshall 	    return;
148532377Sminshall 	}
148632377Sminshall     }
148732377Sminshall #   else /* !defined(TN3270) */
148832377Sminshall     for (;;) {
148932377Sminshall 	int schedValue;
149027088Sminshall 
149132377Sminshall 	while (!In3270 && !shell_active) {
149232531Sminshall 	    if (Scheduler(1) == -1) {
149332377Sminshall 		setcommandmode();
149432377Sminshall 		return;
149532377Sminshall 	    }
149627088Sminshall 	}
149732377Sminshall 
149832377Sminshall 	while ((schedValue = Scheduler(0)) != 0) {
149932377Sminshall 	    if (schedValue == -1) {
150032377Sminshall 		setcommandmode();
150132377Sminshall 		return;
150232377Sminshall 	    }
150327088Sminshall 	}
150432377Sminshall 		/* If there is data waiting to go out to terminal, don't
150532377Sminshall 		 * schedule any more data for the terminal.
150632377Sminshall 		 */
150734304Sminshall 	if (ring_full_count(&ttyoring)) {
150832377Sminshall 	    schedValue = 1;
150927088Sminshall 	} else {
151032377Sminshall 	    if (shell_active) {
151132377Sminshall 		if (shell_continue() == 0) {
151232377Sminshall 		    ConnectScreen();
151327088Sminshall 		}
151432377Sminshall 	    } else if (In3270) {
151532377Sminshall 		schedValue = DoTerminalOutput();
151632377Sminshall 	    }
151727088Sminshall 	}
151832377Sminshall 	if (schedValue && (shell_active == 0)) {
151932531Sminshall 	    if (Scheduler(1) == -1) {
152032377Sminshall 		setcommandmode();
152132377Sminshall 		return;
152232377Sminshall 	    }
152327088Sminshall 	}
152432377Sminshall     }
152532377Sminshall #   endif /* !defined(TN3270) */
152627088Sminshall }
152732377Sminshall 
152834848Sminshall #if	0	/* XXX - this not being in is a bug */
152927088Sminshall /*
153032554Sminshall  * nextitem()
153132554Sminshall  *
153232554Sminshall  *	Return the address of the next "item" in the TELNET data
153332554Sminshall  * stream.  This will be the address of the next character if
153432554Sminshall  * the current address is a user data character, or it will
153532554Sminshall  * be the address of the character following the TELNET command
153632554Sminshall  * if the current address is a TELNET IAC ("I Am a Command")
153732554Sminshall  * character.
153832554Sminshall  */
153932554Sminshall 
154032554Sminshall static char *
154132554Sminshall nextitem(current)
154232554Sminshall char	*current;
154332554Sminshall {
154432554Sminshall     if ((*current&0xff) != IAC) {
154532554Sminshall 	return current+1;
154632554Sminshall     }
154732554Sminshall     switch (*(current+1)&0xff) {
154832554Sminshall     case DO:
154932554Sminshall     case DONT:
155032554Sminshall     case WILL:
155132554Sminshall     case WONT:
155232554Sminshall 	return current+3;
155332554Sminshall     case SB:		/* loop forever looking for the SE */
155432554Sminshall 	{
155532554Sminshall 	    register char *look = current+2;
155632554Sminshall 
155732554Sminshall 	    for (;;) {
155832554Sminshall 		if ((*look++&0xff) == IAC) {
155932554Sminshall 		    if ((*look++&0xff) == SE) {
156032554Sminshall 			return look;
156132554Sminshall 		    }
156232554Sminshall 		}
156332554Sminshall 	    }
156432554Sminshall 	}
156532554Sminshall     default:
156632554Sminshall 	return current+2;
156732554Sminshall     }
156832554Sminshall }
156934848Sminshall #endif	/* 0 */
157032554Sminshall 
157132554Sminshall /*
157232554Sminshall  * netclear()
157332554Sminshall  *
157432554Sminshall  *	We are about to do a TELNET SYNCH operation.  Clear
157532554Sminshall  * the path to the network.
157632554Sminshall  *
157732554Sminshall  *	Things are a bit tricky since we may have sent the first
157832554Sminshall  * byte or so of a previous TELNET command into the network.
157932554Sminshall  * So, we have to scan the network buffer from the beginning
158032554Sminshall  * until we are up to where we want to be.
158132554Sminshall  *
158232554Sminshall  *	A side effect of what we do, just to keep things
158332554Sminshall  * simple, is to clear the urgent data pointer.  The principal
158432554Sminshall  * caller should be setting the urgent data pointer AFTER calling
158532554Sminshall  * us in any case.
158632554Sminshall  */
158732554Sminshall 
158832554Sminshall static void
158932554Sminshall netclear()
159032554Sminshall {
159132554Sminshall #if	0	/* XXX */
159232554Sminshall     register char *thisitem, *next;
159332554Sminshall     char *good;
159432554Sminshall #define	wewant(p)	((nfrontp > p) && ((*p&0xff) == IAC) && \
159532554Sminshall 				((*(p+1)&0xff) != EC) && ((*(p+1)&0xff) != EL))
159632554Sminshall 
159732554Sminshall     thisitem = netobuf;
159832554Sminshall 
159932554Sminshall     while ((next = nextitem(thisitem)) <= netobuf.send) {
160032554Sminshall 	thisitem = next;
160132554Sminshall     }
160232554Sminshall 
160332554Sminshall     /* Now, thisitem is first before/at boundary. */
160432554Sminshall 
160532554Sminshall     good = netobuf;	/* where the good bytes go */
160632554Sminshall 
160732554Sminshall     while (netoring.add > thisitem) {
160832554Sminshall 	if (wewant(thisitem)) {
160932554Sminshall 	    int length;
161032554Sminshall 
161132554Sminshall 	    next = thisitem;
161232554Sminshall 	    do {
161332554Sminshall 		next = nextitem(next);
161432554Sminshall 	    } while (wewant(next) && (nfrontp > next));
161532554Sminshall 	    length = next-thisitem;
161632554Sminshall 	    memcpy(good, thisitem, length);
161732554Sminshall 	    good += length;
161832554Sminshall 	    thisitem = next;
161932554Sminshall 	} else {
162032554Sminshall 	    thisitem = nextitem(thisitem);
162132554Sminshall 	}
162232554Sminshall     }
162332554Sminshall 
162432554Sminshall #endif	/* 0 */
162532554Sminshall }
162632554Sminshall 
162732554Sminshall /*
162832377Sminshall  * These routines add various telnet commands to the data stream.
162927088Sminshall  */
163032377Sminshall 
163132554Sminshall static void
163232554Sminshall doflush()
163332554Sminshall {
163432554Sminshall     NET2ADD(IAC, DO);
163532554Sminshall     NETADD(TELOPT_TM);
163632554Sminshall     flushline = 1;
163732554Sminshall     flushout = 1;
163832554Sminshall     ttyflush(1);			/* Flush/drop output */
163932554Sminshall     /* do printoption AFTER flush, otherwise the output gets tossed... */
164037226Sminshall     printoption("SENT", "do", TELOPT_TM);
164132554Sminshall }
164232554Sminshall 
164332377Sminshall void
164432377Sminshall xmitAO()
164527088Sminshall {
164632377Sminshall     NET2ADD(IAC, AO);
164732377Sminshall     if (autoflush) {
164832377Sminshall 	doflush();
164932377Sminshall     }
165032377Sminshall }
165127088Sminshall 
165232377Sminshall 
165332377Sminshall void
165432377Sminshall xmitEL()
165527088Sminshall {
165632377Sminshall     NET2ADD(IAC, EL);
165727088Sminshall }
165827088Sminshall 
165932377Sminshall void
166032377Sminshall xmitEC()
166127088Sminshall {
166232377Sminshall     NET2ADD(IAC, EC);
166327088Sminshall }
166427088Sminshall 
166532377Sminshall 
166632377Sminshall #if	defined(NOT43)
166732377Sminshall int
166832377Sminshall #else	/* defined(NOT43) */
166932377Sminshall void
167032377Sminshall #endif	/* defined(NOT43) */
167132377Sminshall dosynch()
167227088Sminshall {
167332377Sminshall     netclear();			/* clear the path to the network */
167433294Sminshall     NETADD(IAC);
167533294Sminshall     setneturg();
167633294Sminshall     NETADD(DM);
167727088Sminshall 
167832377Sminshall #if	defined(NOT43)
167932377Sminshall     return 0;
168032377Sminshall #endif	/* defined(NOT43) */
168127088Sminshall }
168227088Sminshall 
168332377Sminshall void
168432377Sminshall intp()
168527088Sminshall {
168632377Sminshall     NET2ADD(IAC, IP);
168732377Sminshall     flushline = 1;
168832377Sminshall     if (autoflush) {
168932377Sminshall 	doflush();
169032377Sminshall     }
169132377Sminshall     if (autosynch) {
169232377Sminshall 	dosynch();
169332377Sminshall     }
169427088Sminshall }
169527186Sminshall 
169632377Sminshall void
169732377Sminshall sendbrk()
169827186Sminshall {
169932377Sminshall     NET2ADD(IAC, BREAK);
170032377Sminshall     flushline = 1;
170132377Sminshall     if (autoflush) {
170232377Sminshall 	doflush();
170332377Sminshall     }
170432377Sminshall     if (autosynch) {
170532377Sminshall 	dosynch();
170632377Sminshall     }
170727186Sminshall }
170838689Sborman 
170938689Sborman void
171038689Sborman sendabort()
171138689Sborman {
171238689Sborman     NET2ADD(IAC, ABORT);
171338689Sborman     flushline = 1;
171438689Sborman     if (autoflush) {
171538689Sborman 	doflush();
171638689Sborman     }
171738689Sborman     if (autosynch) {
171838689Sborman 	dosynch();
171938689Sborman     }
172038689Sborman }
172138689Sborman 
172238689Sborman void
172338689Sborman sendsusp()
172438689Sborman {
172538689Sborman     NET2ADD(IAC, SUSP);
172638689Sborman     flushline = 1;
172738689Sborman     if (autoflush) {
172838689Sborman 	doflush();
172938689Sborman     }
173038689Sborman     if (autosynch) {
173138689Sborman 	dosynch();
173238689Sborman     }
173338689Sborman }
173438689Sborman 
173538689Sborman void
173638689Sborman sendeof()
173738689Sborman {
173838689Sborman    NET2ADD(IAC, xEOF);
173938689Sborman }
174038689Sborman 
174137219Sminshall /*
174237219Sminshall  * Send a window size update to the remote system.
174337219Sminshall  */
174437219Sminshall 
174537219Sminshall void
174637219Sminshall sendnaws()
174737219Sminshall {
174837219Sminshall     long rows, cols;
174938689Sborman     unsigned char tmp[16];
175038689Sborman     register unsigned char *cp;
175137219Sminshall 
175238689Sborman     if (my_state_is_wont(TELOPT_NAWS))
175338689Sborman 	return;
175437219Sminshall 
175538689Sborman #define	PUTSHORT(cp, x) { if ((*cp++ = ((x)>>8)&0xff) == IAC) *cp++ = IAC; \
175638689Sborman 			    if ((*cp++ = ((x))&0xff) == IAC) *cp++ = IAC; }
175738689Sborman 
175837219Sminshall     if (TerminalWindowSize(&rows, &cols) == 0) {	/* Failed */
175937219Sminshall 	return;
176037219Sminshall     }
176137219Sminshall 
176238689Sborman     cp = tmp;
176338689Sborman 
176438689Sborman     *cp++ = IAC;
176538689Sborman     *cp++ = SB;
176638689Sborman     *cp++ = TELOPT_NAWS;
176738689Sborman     PUTSHORT(cp, cols);
176838689Sborman     PUTSHORT(cp, rows);
176938689Sborman     *cp++ = IAC;
177038689Sborman     *cp++ = SE;
177138689Sborman     if (NETROOM() >= cp - tmp) {
177238689Sborman 	ring_supply_data(&netoring, tmp, cp-tmp);
177338689Sborman 	printsub('>', tmp+2, cp - tmp - 2);
177437219Sminshall     }
177537219Sminshall }
177637226Sminshall 
177737226Sminshall tel_enter_binary()
177837226Sminshall {
177938689Sborman     send_do(TELOPT_BINARY, 1);
178038689Sborman     send_will(TELOPT_BINARY, 1);
178137226Sminshall }
178237226Sminshall 
178337226Sminshall tel_leave_binary()
178437226Sminshall {
178538689Sborman     send_dont(TELOPT_BINARY, 1);
178638689Sborman     send_wont(TELOPT_BINARY, 1);
178737226Sminshall }
1788