xref: /csrg-svn/usr.bin/telnet/telnet.c (revision 47608)
133685Sbostic /*
245232Sborman  * Copyright (c) 1988, 1990 Regents of the University of California.
333685Sbostic  * All rights reserved.
433685Sbostic  *
542770Sbostic  * %sccs.include.redist.c%
633685Sbostic  */
711758Ssam 
821580Sdist #ifndef lint
9*47608Sdab static char sccsid[] = "@(#)telnet.c	5.53 (Berkeley) 03/22/91";
1033685Sbostic #endif /* not lint */
1121580Sdist 
129217Ssam #include <sys/types.h>
139217Ssam 
1432377Sminshall #if	defined(unix)
1533804Sminshall #include <signal.h>
1632377Sminshall /* By the way, we need to include curses.h before telnet.h since,
1732377Sminshall  * among other things, telnet.h #defines 'DO', which is a variable
1832377Sminshall  * declared in curses.h.
1932377Sminshall  */
2032377Sminshall #endif	/* defined(unix) */
2132377Sminshall 
2212212Ssam #include <arpa/telnet.h>
2332377Sminshall 
2438908Sborman #include <ctype.h>
2538908Sborman 
2632381Sminshall #include "ring.h"
2732381Sminshall 
2832377Sminshall #include "defines.h"
2932377Sminshall #include "externs.h"
3032377Sminshall #include "types.h"
3132377Sminshall #include "general.h"
3227178Sminshall 
3327178Sminshall 
3427228Sminshall #define	strip(x)	((x)&0x7f)
356000Sroot 
3646808Sdab static unsigned char	subbuffer[SUBBUFSIZE],
3746808Sdab 			*subpointer, *subend;	 /* buffer for sub-options */
3827676Sminshall #define	SB_CLEAR()	subpointer = subbuffer;
3946808Sdab #define	SB_TERM()	{ subend = subpointer; SB_CLEAR(); }
4027676Sminshall #define	SB_ACCUM(c)	if (subpointer < (subbuffer+sizeof subbuffer)) { \
4127676Sminshall 				*subpointer++ = (c); \
4227676Sminshall 			}
4327676Sminshall 
4446808Sdab #define	SB_GET()	((*subpointer++)&0xff)
4546808Sdab #define	SB_PEEK()	((*subpointer)&0xff)
4646808Sdab #define	SB_EOF()	(subpointer >= subend)
4746808Sdab #define	SB_LEN()	(subend - subpointer)
4846808Sdab 
4937226Sminshall char	options[256];		/* The combined options */
5038689Sborman char	do_dont_resp[256];
5138689Sborman char	will_wont_resp[256];
526000Sroot 
5332377Sminshall int
5446808Sdab 	eight = 0,
5546808Sdab 	autologin = 0,	/* Autologin anyone? */
56*47608Sdab 	skiprc = 0,
5732377Sminshall 	connected,
5832377Sminshall 	showoptions,
5932377Sminshall 	In3270,		/* Are we in 3270 mode? */
6032377Sminshall 	ISend,		/* trying to send network data in */
6132377Sminshall 	debug = 0,
6232377Sminshall 	crmod,
6332377Sminshall 	netdata,	/* Print out network data flow */
6432377Sminshall 	crlf,		/* Should '\r' be mapped to <CR><LF> (or <CR><NUL>)? */
6534848Sminshall #if	defined(TN3270)
6636241Sminshall 	noasynchtty = 0,/* User specified "-noasynch" on command line */
6736241Sminshall 	noasynchnet = 0,/* User specified "-noasynch" on command line */
6832377Sminshall 	askedSGA = 0,	/* We have talked about suppress go ahead */
6934848Sminshall #endif	/* defined(TN3270) */
7033286Sminshall 	telnetport,
7132531Sminshall 	SYNCHing,	/* we are in TELNET SYNCH mode */
7232531Sminshall 	flushout,	/* flush output */
7332531Sminshall 	autoflush = 0,	/* flush output when interrupting? */
7432531Sminshall 	autosynch,	/* send interrupt characters with SYNCH? */
7537219Sminshall 	localflow,	/* we handle flow control locally */
7632531Sminshall 	localchars,	/* we recognize interrupt/quit */
7732531Sminshall 	donelclchars,	/* the user has set "localchars" */
7832531Sminshall 	donebinarytoggle,	/* the user has put us in binary */
7932531Sminshall 	dontlecho,	/* do we suppress local echoing right now? */
8032531Sminshall 	globalmode;
8127088Sminshall 
8244360Sborman char *prompt = 0;
836000Sroot 
8444360Sborman cc_t escape;
8546808Sdab cc_t rlogin;
8644360Sborman #ifdef	KLUDGELINEMODE
8744360Sborman cc_t echoc;
8844360Sborman #endif
8927186Sminshall 
9027186Sminshall /*
916000Sroot  * Telnet receiver states for fsm
926000Sroot  */
936000Sroot #define	TS_DATA		0
946000Sroot #define	TS_IAC		1
956000Sroot #define	TS_WILL		2
966000Sroot #define	TS_WONT		3
976000Sroot #define	TS_DO		4
986000Sroot #define	TS_DONT		5
9927021Sminshall #define	TS_CR		6
10027676Sminshall #define	TS_SB		7		/* sub-option collection */
10127676Sminshall #define	TS_SE		8		/* looking for sub-option end */
1026000Sroot 
10332377Sminshall static int	telrcv_state;
1046000Sroot 
10532377Sminshall jmp_buf	toplevel = { 0 };
10632377Sminshall jmp_buf	peerdied;
1076000Sroot 
10832377Sminshall int	flushline;
10938811Sborman int	linemode;
11027021Sminshall 
11138689Sborman #ifdef	KLUDGELINEMODE
11238689Sborman int	kludgelinemode = 1;
11338689Sborman #endif
11438689Sborman 
11532377Sminshall /*
11632377Sminshall  * The following are some clocks used to decide how to interpret
11732377Sminshall  * the relationship between various variables.
11832377Sminshall  */
1196000Sroot 
12032377Sminshall Clocks clocks;
12132377Sminshall 
12238689Sborman #ifdef	notdef
12332377Sminshall Modelist modelist[] = {
12432377Sminshall 	{ "telnet command mode", COMMAND_LINE },
12532377Sminshall 	{ "character-at-a-time mode", 0 },
12632377Sminshall 	{ "character-at-a-time mode (local echo)", LOCAL_ECHO|LOCAL_CHARS },
12732377Sminshall 	{ "line-by-line mode (remote echo)", LINE | LOCAL_CHARS },
12832377Sminshall 	{ "line-by-line mode", LINE | LOCAL_ECHO | LOCAL_CHARS },
12932377Sminshall 	{ "line-by-line mode (local echoing suppressed)", LINE | LOCAL_CHARS },
13032377Sminshall 	{ "3270 mode", 0 },
13132377Sminshall };
13238689Sborman #endif
1336000Sroot 
13432377Sminshall 
13532377Sminshall /*
13632377Sminshall  * Initialize telnet environment.
13732377Sminshall  */
1386000Sroot 
13946808Sdab     void
14032377Sminshall init_telnet()
14132377Sminshall {
14244360Sborman     env_init();
14344360Sborman 
14432377Sminshall     SB_CLEAR();
14537226Sminshall     ClearArray(options);
1466000Sroot 
14737219Sminshall     connected = In3270 = ISend = localflow = donebinarytoggle = 0;
14846808Sdab #if	defined(ENCRYPT) || defined(AUTHENTICATE)
14946808Sdab     auth_encrypt_connect(connected);
15046808Sdab #endif
1516000Sroot 
15232377Sminshall     SYNCHing = 0;
1536000Sroot 
15432377Sminshall     /* Don't change NetTrace */
1556000Sroot 
15632377Sminshall     escape = CONTROL(']');
15746808Sdab     rlogin = _POSIX_VDISABLE;
15844360Sborman #ifdef	KLUDGELINEMODE
15932377Sminshall     echoc = CONTROL('E');
16044360Sborman #endif
1616000Sroot 
16232377Sminshall     flushline = 1;
16332377Sminshall     telrcv_state = TS_DATA;
16432377Sminshall }
16532554Sminshall 
1666000Sroot 
16744360Sborman #ifdef	notdef
16832554Sminshall #include <varargs.h>
1696000Sroot 
17046808Sdab     /*VARARGS*/
17146808Sdab     static void
17232554Sminshall printring(va_alist)
17346808Sdab     va_dcl
17432554Sminshall {
17532554Sminshall     va_list ap;
17632554Sminshall     char buffer[100];		/* where things go */
17732554Sminshall     char *ptr;
17832554Sminshall     char *format;
17932554Sminshall     char *string;
18032554Sminshall     Ring *ring;
18132554Sminshall     int i;
18232554Sminshall 
18332554Sminshall     va_start(ap);
18432554Sminshall 
18532554Sminshall     ring = va_arg(ap, Ring *);
18632554Sminshall     format = va_arg(ap, char *);
18732554Sminshall     ptr = buffer;
18832554Sminshall 
18932554Sminshall     while ((i = *format++) != 0) {
19032554Sminshall 	if (i == '%') {
19132554Sminshall 	    i = *format++;
19232554Sminshall 	    switch (i) {
19332554Sminshall 	    case 'c':
19432554Sminshall 		*ptr++ = va_arg(ap, int);
19532554Sminshall 		break;
19632554Sminshall 	    case 's':
19732554Sminshall 		string = va_arg(ap, char *);
19832554Sminshall 		ring_supply_data(ring, buffer, ptr-buffer);
19932554Sminshall 		ring_supply_data(ring, string, strlen(string));
20032554Sminshall 		ptr = buffer;
20132554Sminshall 		break;
20232554Sminshall 	    case 0:
20332554Sminshall 		ExitString("printring: trailing %%.\n", 1);
20432554Sminshall 		/*NOTREACHED*/
20532554Sminshall 	    default:
20632554Sminshall 		ExitString("printring: unknown format character.\n", 1);
20732554Sminshall 		/*NOTREACHED*/
20832554Sminshall 	    }
20932554Sminshall 	} else {
21032554Sminshall 	    *ptr++ = i;
21132554Sminshall 	}
21232554Sminshall     }
21332554Sminshall     ring_supply_data(ring, buffer, ptr-buffer);
21432554Sminshall }
21544360Sborman #endif
21632554Sminshall 
21737226Sminshall /*
21837226Sminshall  * These routines are in charge of sending option negotiations
21937226Sminshall  * to the other side.
22037226Sminshall  *
22137226Sminshall  * The basic idea is that we send the negotiation if either side
22237226Sminshall  * is in disagreement as to what the current state should be.
22337226Sminshall  */
22432554Sminshall 
22546808Sdab     void
22638689Sborman send_do(c, init)
22746808Sdab     register int c, init;
2286000Sroot {
22938689Sborman     if (init) {
23038689Sborman 	if (((do_dont_resp[c] == 0) && my_state_is_do(c)) ||
23138689Sborman 				my_want_state_is_do(c))
23238689Sborman 	    return;
23338689Sborman 	set_my_want_state_do(c);
23438689Sborman 	do_dont_resp[c]++;
23537226Sminshall     }
23638689Sborman     NET2ADD(IAC, DO);
23738689Sborman     NETADD(c);
23846808Sdab     printoption("SENT", DO, c);
23937226Sminshall }
24037226Sminshall 
24146808Sdab     void
24238689Sborman send_dont(c, init)
24346808Sdab     register int c, init;
24437226Sminshall {
24538689Sborman     if (init) {
24638689Sborman 	if (((do_dont_resp[c] == 0) && my_state_is_dont(c)) ||
24738689Sborman 				my_want_state_is_dont(c))
24838689Sborman 	    return;
24938689Sborman 	set_my_want_state_dont(c);
25038689Sborman 	do_dont_resp[c]++;
25137226Sminshall     }
25238689Sborman     NET2ADD(IAC, DONT);
25338689Sborman     NETADD(c);
25446808Sdab     printoption("SENT", DONT, c);
25537226Sminshall }
25637226Sminshall 
25746808Sdab     void
25838689Sborman send_will(c, init)
25946808Sdab     register int c, init;
26037226Sminshall {
26138689Sborman     if (init) {
26238689Sborman 	if (((will_wont_resp[c] == 0) && my_state_is_will(c)) ||
26338689Sborman 				my_want_state_is_will(c))
26438689Sborman 	    return;
26538689Sborman 	set_my_want_state_will(c);
26638689Sborman 	will_wont_resp[c]++;
26737226Sminshall     }
26838689Sborman     NET2ADD(IAC, WILL);
26938689Sborman     NETADD(c);
27046808Sdab     printoption("SENT", WILL, c);
27137226Sminshall }
27237226Sminshall 
27346808Sdab     void
27438689Sborman send_wont(c, init)
27546808Sdab     register int c, init;
27637226Sminshall {
27738689Sborman     if (init) {
27838689Sborman 	if (((will_wont_resp[c] == 0) && my_state_is_wont(c)) ||
27938689Sborman 				my_want_state_is_wont(c))
28038689Sborman 	    return;
28138689Sborman 	set_my_want_state_wont(c);
28238689Sborman 	will_wont_resp[c]++;
28337226Sminshall     }
28438689Sborman     NET2ADD(IAC, WONT);
28538689Sborman     NETADD(c);
28646808Sdab     printoption("SENT", WONT, c);
28737226Sminshall }
28837226Sminshall 
28937226Sminshall 
29046808Sdab 	void
29137226Sminshall willoption(option)
29237226Sminshall 	int option;
29337226Sminshall {
29438689Sborman 	int new_state_ok = 0;
2956000Sroot 
29638689Sborman 	if (do_dont_resp[option]) {
29738689Sborman 	    --do_dont_resp[option];
29838689Sborman 	    if (do_dont_resp[option] && my_state_is_do(option))
29938689Sborman 		--do_dont_resp[option];
30038689Sborman 	}
30137226Sminshall 
30238689Sborman 	if ((do_dont_resp[option] == 0) && my_want_state_is_dont(option)) {
3036000Sroot 
30438689Sborman 	    switch (option) {
30538689Sborman 
30638689Sborman 	    case TELOPT_ECHO:
30738689Sborman #	    if defined(TN3270)
30838689Sborman 		/*
30938689Sborman 		 * The following is a pain in the rear-end.
31038689Sborman 		 * Various IBM servers (some versions of Wiscnet,
31138689Sborman 		 * possibly Fibronics/Spartacus, and who knows who
31238689Sborman 		 * else) will NOT allow us to send "DO SGA" too early
31338689Sborman 		 * in the setup proceedings.  On the other hand,
31438689Sborman 		 * 4.2 servers (telnetd) won't set SGA correctly.
31538689Sborman 		 * So, we are stuck.  Empirically (but, based on
31638689Sborman 		 * a VERY small sample), the IBM servers don't send
31738689Sborman 		 * out anything about ECHO, so we postpone our sending
31838689Sborman 		 * "DO SGA" until we see "WILL ECHO" (which 4.2 servers
31938689Sborman 		 * DO send).
32038689Sborman 		  */
32138689Sborman 		{
32238689Sborman 		    if (askedSGA == 0) {
32338689Sborman 			askedSGA = 1;
32438689Sborman 			if (my_want_state_is_dont(TELOPT_SGA))
32538689Sborman 			    send_do(TELOPT_SGA, 1);
32632377Sminshall 		    }
32732377Sminshall 		}
32838689Sborman 		    /* Fall through */
32938689Sborman 	    case TELOPT_EOR:
33038908Sborman #endif	    /* defined(TN3270) */
33138689Sborman 	    case TELOPT_BINARY:
33238689Sborman 	    case TELOPT_SGA:
33327110Sminshall 		settimer(modenegotiated);
33438908Sborman 		/* FALL THROUGH */
33538908Sborman 	    case TELOPT_STATUS:
33646808Sdab #if	defined(AUTHENTICATE)
33746808Sdab 	    case TELOPT_AUTHENTICATION:
33846808Sdab #endif
33946808Sdab #if	defined(ENCRYPT)
34046808Sdab 	    case TELOPT_ENCRYPT:
34146808Sdab #endif
34238689Sborman 		new_state_ok = 1;
3436000Sroot 		break;
3446000Sroot 
34538689Sborman 	    case TELOPT_TM:
34638689Sborman 		if (flushout)
34738689Sborman 		    flushout = 0;
34838689Sborman 		/*
34938689Sborman 		 * Special case for TM.  If we get back a WILL,
35038689Sborman 		 * pretend we got back a WONT.
35138689Sborman 		 */
35238689Sborman 		set_my_want_state_dont(option);
35338689Sborman 		set_my_state_dont(option);
35427110Sminshall 		return;			/* Never reply to TM will's/wont's */
3556000Sroot 
35638689Sborman 	    case TELOPT_LINEMODE:
35738689Sborman 	    default:
3586000Sroot 		break;
35938689Sborman 	    }
36038689Sborman 
36138689Sborman 	    if (new_state_ok) {
36238689Sborman 		set_my_want_state_do(option);
36338689Sborman 		send_do(option, 0);
36438689Sborman 		setconnmode(0);		/* possibly set new tty mode */
36538689Sborman 	    } else {
36638689Sborman 		do_dont_resp[option]++;
36738689Sborman 		send_dont(option, 0);
36838689Sborman 	    }
3696000Sroot 	}
37038689Sborman 	set_my_state_do(option);
37146808Sdab #if	defined(ENCRYPT)
37246808Sdab 	if (option == TELOPT_ENCRYPT)
37346808Sdab 		encrypt_send_support();
37446808Sdab #endif
3756000Sroot }
3766000Sroot 
37746808Sdab 	void
37837226Sminshall wontoption(option)
37937226Sminshall 	int option;
3806000Sroot {
38138689Sborman 	if (do_dont_resp[option]) {
38238689Sborman 	    --do_dont_resp[option];
38338689Sborman 	    if (do_dont_resp[option] && my_state_is_dont(option))
38438689Sborman 		--do_dont_resp[option];
38538689Sborman 	}
38637226Sminshall 
38738689Sborman 	if ((do_dont_resp[option] == 0) && my_want_state_is_do(option)) {
3886000Sroot 
38938689Sborman 	    switch (option) {
39038689Sborman 
39138689Sborman #ifdef	KLUDGELINEMODE
39238689Sborman 	    case TELOPT_SGA:
39338689Sborman 		if (!kludgelinemode)
39438689Sborman 		    break;
39538689Sborman 		/* FALL THROUGH */
39638689Sborman #endif
39738689Sborman 	    case TELOPT_ECHO:
39827110Sminshall 		settimer(modenegotiated);
3996000Sroot 		break;
4006000Sroot 
40138689Sborman 	    case TELOPT_TM:
40238689Sborman 		if (flushout)
40338689Sborman 		    flushout = 0;
40438689Sborman 		set_my_want_state_dont(option);
40538689Sborman 		set_my_state_dont(option);
40627110Sminshall 		return;		/* Never reply to TM will's/wont's */
40727110Sminshall 
40838689Sborman 	    default:
40938689Sborman 		break;
41038689Sborman 	    }
41138689Sborman 	    set_my_want_state_dont(option);
41244360Sborman 	    if (my_state_is_do(option))
41344360Sborman 		send_dont(option, 0);
41438689Sborman 	    setconnmode(0);			/* Set new tty mode */
41538689Sborman 	} else if (option == TELOPT_TM) {
41638689Sborman 	    /*
41738689Sborman 	     * Special case for TM.
41838689Sborman 	     */
41938689Sborman 	    if (flushout)
42038689Sborman 		flushout = 0;
42138689Sborman 	    set_my_want_state_dont(option);
4226000Sroot 	}
42338689Sborman 	set_my_state_dont(option);
4246000Sroot }
4256000Sroot 
42646808Sdab 	static void
4276000Sroot dooption(option)
4286000Sroot 	int option;
4296000Sroot {
43038689Sborman 	int new_state_ok = 0;
4316000Sroot 
43238689Sborman 	if (will_wont_resp[option]) {
43338689Sborman 	    --will_wont_resp[option];
43438689Sborman 	    if (will_wont_resp[option] && my_state_is_will(option))
43538689Sborman 		--will_wont_resp[option];
43638689Sborman 	}
43737226Sminshall 
43838689Sborman 	if (will_wont_resp[option] == 0) {
43938689Sborman 	  if (my_want_state_is_wont(option)) {
4406000Sroot 
44138689Sborman 	    switch (option) {
44238689Sborman 
44338689Sborman 	    case TELOPT_TM:
44438689Sborman 		/*
44538689Sborman 		 * Special case for TM.  We send a WILL, but pretend
44638689Sborman 		 * we sent WONT.
44738689Sborman 		 */
44838689Sborman 		send_will(option, 0);
44938689Sborman 		set_my_want_state_wont(TELOPT_TM);
45038689Sborman 		set_my_state_wont(TELOPT_TM);
45138689Sborman 		return;
45238689Sborman 
45332377Sminshall #	if defined(TN3270)
45438689Sborman 	    case TELOPT_EOR:		/* end of record */
45538908Sborman #	endif	/* defined(TN3270) */
45638689Sborman 	    case TELOPT_BINARY:		/* binary mode */
45738689Sborman 	    case TELOPT_NAWS:		/* window size */
45838689Sborman 	    case TELOPT_TSPEED:		/* terminal speed */
45938689Sborman 	    case TELOPT_LFLOW:		/* local flow control */
46038689Sborman 	    case TELOPT_TTYPE:		/* terminal type option */
46138689Sborman 	    case TELOPT_SGA:		/* no big deal */
46244360Sborman 	    case TELOPT_ENVIRON:	/* environment variable option */
46346808Sdab #if	defined(ENCRYPT)
46446808Sdab 	    case TELOPT_ENCRYPT:	/* encryption variable option */
46546808Sdab #endif
46638689Sborman 		new_state_ok = 1;
4676000Sroot 		break;
46846808Sdab #if	defined(AUTHENTICATE)
46946808Sdab 	    case TELOPT_AUTHENTICATION:
47046808Sdab 		if (autologin)
47146808Sdab 			new_state_ok = 1;
47246808Sdab 		break;
47346808Sdab #endif
4746000Sroot 
47544360Sborman 	    case TELOPT_XDISPLOC:	/* X Display location */
47646808Sdab 		if (env_getvalue((unsigned char *)"DISPLAY"))
47744360Sborman 		    new_state_ok = 1;
47844360Sborman 		break;
47944360Sborman 
48038689Sborman 	    case TELOPT_LINEMODE:
48138689Sborman #ifdef	KLUDGELINEMODE
48238689Sborman 		kludgelinemode = 0;
48344360Sborman 		send_do(TELOPT_SGA, 1);
48438689Sborman #endif
48538689Sborman 		set_my_want_state_will(TELOPT_LINEMODE);
48638689Sborman 		send_will(option, 0);
48738689Sborman 		set_my_state_will(TELOPT_LINEMODE);
48838689Sborman 		slc_init();
48938689Sborman 		return;
49038689Sborman 
49138689Sborman 	    case TELOPT_ECHO:		/* We're never going to echo... */
49238689Sborman 	    default:
4936000Sroot 		break;
49438689Sborman 	    }
49538689Sborman 
49638689Sborman 	    if (new_state_ok) {
49738689Sborman 		set_my_want_state_will(option);
49838689Sborman 		send_will(option, 0);
49945232Sborman 		setconnmode(0);			/* Set new tty mode */
50038689Sborman 	    } else {
50138689Sborman 		will_wont_resp[option]++;
50238689Sborman 		send_wont(option, 0);
50338689Sborman 	    }
50438689Sborman 	  } else {
50538689Sborman 	    /*
50638689Sborman 	     * Handle options that need more things done after the
50738689Sborman 	     * other side has acknowledged the option.
50838689Sborman 	     */
50938689Sborman 	    switch (option) {
51038689Sborman 	    case TELOPT_LINEMODE:
51138689Sborman #ifdef	KLUDGELINEMODE
51238689Sborman 		kludgelinemode = 0;
51344360Sborman 		send_do(TELOPT_SGA, 1);
51438689Sborman #endif
51538689Sborman 		set_my_state_will(option);
51638689Sborman 		slc_init();
51744360Sborman 		send_do(TELOPT_SGA, 0);
51838689Sborman 		return;
51938689Sborman 	    }
52038689Sborman 	  }
5216000Sroot 	}
52238689Sborman 	set_my_state_will(option);
5236000Sroot }
52427676Sminshall 
52546808Sdab 	static void
52638689Sborman dontoption(option)
52738689Sborman 	int option;
52838689Sborman {
52938689Sborman 
53038689Sborman 	if (will_wont_resp[option]) {
53138689Sborman 	    --will_wont_resp[option];
53238689Sborman 	    if (will_wont_resp[option] && my_state_is_wont(option))
53338689Sborman 		--will_wont_resp[option];
53438689Sborman 	}
53538689Sborman 
53638689Sborman 	if ((will_wont_resp[option] == 0) && my_want_state_is_will(option)) {
53738811Sborman 	    switch (option) {
53838811Sborman 	    case TELOPT_LINEMODE:
53938811Sborman 		linemode = 0;	/* put us back to the default state */
54038811Sborman 		break;
54138811Sborman 	    }
54238689Sborman 	    /* we always accept a DONT */
54338689Sborman 	    set_my_want_state_wont(option);
54444360Sborman 	    if (my_state_is_will(option))
54544360Sborman 		send_wont(option, 0);
54639529Sborman 	    setconnmode(0);			/* Set new tty mode */
54738689Sborman 	}
54838689Sborman 	set_my_state_wont(option);
54938689Sborman }
55038689Sborman 
55127676Sminshall /*
55238908Sborman  * Given a buffer returned by tgetent(), this routine will turn
55338908Sborman  * the pipe seperated list of names in the buffer into an array
55438908Sborman  * of pointers to null terminated names.  We toss out any bad,
55538908Sborman  * duplicate, or verbose names (names with spaces).
55638908Sborman  */
55738908Sborman 
55846808Sdab static char *name_unknown = "UNKNOWN";
55946808Sdab static char *unknown[] = { 0, 0 };
56038908Sborman 
56146808Sdab 	char **
56238908Sborman mklist(buf, name)
56346808Sdab 	char *buf, *name;
56438908Sborman {
56538908Sborman 	register int n;
56646808Sdab 	register char c, *cp, **argvp, *cp2, **argv, **avt;
56738908Sborman 
56838908Sborman 	if (name) {
56946808Sdab 		if (strlen(name) > 40) {
57038908Sborman 			name = 0;
57146808Sdab 			unknown[0] = name_unknown;
57246808Sdab 		} else {
57338908Sborman 			unknown[0] = name;
57438908Sborman 			upcase(name);
57538908Sborman 		}
57646808Sdab 	} else
57746808Sdab 		unknown[0] = name_unknown;
57838908Sborman 	/*
57938908Sborman 	 * Count up the number of names.
58038908Sborman 	 */
58138908Sborman 	for (n = 1, cp = buf; *cp && *cp != ':'; cp++) {
58238908Sborman 		if (*cp == '|')
58338908Sborman 			n++;
58438908Sborman 	}
58538908Sborman 	/*
58638908Sborman 	 * Allocate an array to put the name pointers into
58738908Sborman 	 */
58838908Sborman 	argv = (char **)malloc((n+3)*sizeof(char *));
58938908Sborman 	if (argv == 0)
59038908Sborman 		return(unknown);
59138908Sborman 
59238908Sborman 	/*
59338908Sborman 	 * Fill up the array of pointers to names.
59438908Sborman 	 */
59538908Sborman 	*argv = 0;
59638908Sborman 	argvp = argv+1;
59738908Sborman 	n = 0;
59838908Sborman 	for (cp = cp2 = buf; (c = *cp);  cp++) {
59938908Sborman 		if (c == '|' || c == ':') {
60038908Sborman 			*cp++ = '\0';
60138908Sborman 			/*
60238908Sborman 			 * Skip entries that have spaces or are over 40
60338908Sborman 			 * characters long.  If this is our environment
60438908Sborman 			 * name, then put it up front.  Otherwise, as
60538908Sborman 			 * long as this is not a duplicate name (case
60638908Sborman 			 * insensitive) add it to the list.
60738908Sborman 			 */
60838908Sborman 			if (n || (cp - cp2 > 41))
60938908Sborman 				;
61038908Sborman 			else if (name && (strncasecmp(name, cp2, cp-cp2) == 0))
61138908Sborman 				*argv = cp2;
61238908Sborman 			else if (is_unique(cp2, argv+1, argvp))
61338908Sborman 				*argvp++ = cp2;
61438908Sborman 			if (c == ':')
61538908Sborman 				break;
61638908Sborman 			/*
61738908Sborman 			 * Skip multiple delimiters. Reset cp2 to
61838908Sborman 			 * the beginning of the next name. Reset n,
61938908Sborman 			 * the flag for names with spaces.
62038908Sborman 			 */
62138908Sborman 			while ((c = *cp) == '|')
62238908Sborman 				cp++;
62338908Sborman 			cp2 = cp;
62438908Sborman 			n = 0;
62538908Sborman 		}
62638908Sborman 		/*
62738908Sborman 		 * Skip entries with spaces or non-ascii values.
62838908Sborman 		 * Convert lower case letters to upper case.
62938908Sborman 		 */
63038908Sborman 		if ((c == ' ') || !isascii(c))
63138908Sborman 			n = 1;
63238908Sborman 		else if (islower(c))
63338908Sborman 			*cp = toupper(c);
63438908Sborman 	}
63538908Sborman 
63638908Sborman 	/*
63738908Sborman 	 * Check for an old V6 2 character name.  If the second
63838908Sborman 	 * name points to the beginning of the buffer, and is
63938908Sborman 	 * only 2 characters long, move it to the end of the array.
64038908Sborman 	 */
64138908Sborman 	if ((argv[1] == buf) && (strlen(argv[1]) == 2)) {
64246808Sdab 		--argvp;
64346808Sdab 		for (avt = &argv[1]; avt < argvp; avt++)
64446808Sdab 			*avt = *(avt+1);
64538908Sborman 		*argvp++ = buf;
64638908Sborman 	}
64738908Sborman 
64838908Sborman 	/*
64938908Sborman 	 * Duplicate last name, for TTYPE option, and null
65038908Sborman 	 * terminate the array.  If we didn't find a match on
65138908Sborman 	 * our terminal name, put that name at the beginning.
65238908Sborman 	 */
65338908Sborman 	cp = *(argvp-1);
65438908Sborman 	*argvp++ = cp;
65538908Sborman 	*argvp = 0;
65638908Sborman 
65738908Sborman 	if (*argv == 0) {
65838908Sborman 		if (name)
65938908Sborman 			*argv = name;
66046808Sdab 		else {
66146808Sdab 			--argvp;
66246808Sdab 			for (avt = argv; avt < argvp; avt++)
66346808Sdab 				*avt = *(avt+1);
66446808Sdab 		}
66538908Sborman 	}
66638908Sborman 	if (*argv)
66738908Sborman 		return(argv);
66838908Sborman 	else
66938908Sborman 		return(unknown);
67038908Sborman }
67138908Sborman 
67246808Sdab 	int
67338908Sborman is_unique(name, as, ae)
67446808Sdab 	register char *name, **as, **ae;
67538908Sborman {
67638908Sborman 	register char **ap;
67738908Sborman 	register int n;
67838908Sborman 
67938908Sborman 	n = strlen(name) + 1;
68038908Sborman 	for (ap = as; ap < ae; ap++)
68138908Sborman 		if (strncasecmp(*ap, name, n) == 0)
68238908Sborman 			return(0);
68338908Sborman 	return (1);
68438908Sborman }
68538908Sborman 
68638908Sborman #ifdef	TERMCAP
68739529Sborman char termbuf[1024];
68846808Sdab 
68946808Sdab 	/*ARGSUSED*/
69046808Sdab 	int
69138908Sborman setupterm(tname, fd, errp)
69246808Sdab 	char *tname;
69346808Sdab 	int fd, *errp;
69438908Sborman {
69539529Sborman 	if (tgetent(termbuf, tname) == 1) {
69639529Sborman 		termbuf[1023] = '\0';
69738908Sborman 		if (errp)
69838908Sborman 			*errp = 1;
69938908Sborman 		return(0);
70038908Sborman 	}
70138908Sborman 	if (errp)
70238908Sborman 		*errp = 0;
70338908Sborman 	return(-1);
70438908Sborman }
70539529Sborman #else
70639529Sborman #define	termbuf	ttytype
70739529Sborman extern char ttytype[];
70838908Sborman #endif
70938908Sborman 
71046808Sdab int resettermname = 1;
71146808Sdab 
71246808Sdab 	char *
71338908Sborman gettermname()
71438908Sborman {
71538908Sborman 	char *tname;
71646808Sdab 	static char **tnamep = 0;
71738908Sborman 	static char **next;
71838908Sborman 	int err;
71938908Sborman 
72046808Sdab 	if (resettermname) {
72146808Sdab 		resettermname = 0;
72246808Sdab 		if (tnamep && tnamep != unknown)
72346808Sdab 			free(tnamep);
72446808Sdab 		if ((tname = (char *)env_getvalue((unsigned char *)"TERM")) &&
72538908Sborman 				(setupterm(tname, 1, &err) == 0)) {
72639529Sborman 			tnamep = mklist(termbuf, tname);
72738908Sborman 		} else {
72838908Sborman 			if (tname && (strlen(tname) <= 40)) {
72938908Sborman 				unknown[0] = tname;
73038908Sborman 				upcase(tname);
73146808Sdab 			} else
73246808Sdab 				unknown[0] = name_unknown;
73338908Sborman 			tnamep = unknown;
73438908Sborman 		}
73538908Sborman 		next = tnamep;
73638908Sborman 	}
73738908Sborman 	if (*next == 0)
73838908Sborman 		next = tnamep;
73938908Sborman 	return(*next++);
74038908Sborman }
74138908Sborman /*
74227676Sminshall  * suboption()
74327676Sminshall  *
74427676Sminshall  *	Look at the sub-option buffer, and try to be helpful to the other
74527676Sminshall  * side.
74627676Sminshall  *
74727676Sminshall  *	Currently we recognize:
74827676Sminshall  *
74927676Sminshall  *		Terminal type, send request.
75037219Sminshall  *		Terminal speed (send request).
75137219Sminshall  *		Local flow control (is request).
75238689Sborman  *		Linemode
75327676Sminshall  */
75427676Sminshall 
75546808Sdab     static void
75627676Sminshall suboption()
75727676Sminshall {
75846808Sdab     printsub('<', subbuffer, SB_LEN()+2);
75946808Sdab     switch (SB_GET()) {
76027676Sminshall     case TELOPT_TTYPE:
76138689Sborman 	if (my_want_state_is_wont(TELOPT_TTYPE))
76238689Sborman 	    return;
76346808Sdab 	if (SB_EOF() || SB_GET() != TELQUAL_SEND) {
76446808Sdab 	    return;
76527676Sminshall 	} else {
76627676Sminshall 	    char *name;
76746808Sdab 	    unsigned char temp[50];
76827676Sminshall 	    int len;
76927676Sminshall 
77032377Sminshall #if	defined(TN3270)
77132531Sminshall 	    if (tn3270_ttype()) {
77232377Sminshall 		return;
77332377Sminshall 	    }
77432377Sminshall #endif	/* defined(TN3270) */
77538908Sborman 	    name = gettermname();
77638908Sborman 	    len = strlen(name) + 4 + 2;
77738908Sborman 	    if (len < NETROOM()) {
77846808Sdab 		sprintf((char *)temp, "%c%c%c%c%s%c%c", IAC, SB, TELOPT_TTYPE,
77938908Sborman 				TELQUAL_IS, name, IAC, SE);
78038689Sborman 		ring_supply_data(&netoring, temp, len);
78138908Sborman 		printsub('>', &temp[2], len-2);
78232377Sminshall 	    } else {
78337226Sminshall 		ExitString("No room in buffer for terminal type.\n", 1);
78432377Sminshall 		/*NOTREACHED*/
78527676Sminshall 	    }
78627676Sminshall 	}
78737219Sminshall 	break;
78837219Sminshall     case TELOPT_TSPEED:
78938689Sborman 	if (my_want_state_is_wont(TELOPT_TSPEED))
79038689Sborman 	    return;
79146808Sdab 	if (SB_EOF())
79246808Sdab 	    return;
79346808Sdab 	if (SB_GET() == TELQUAL_SEND) {
79445232Sborman 	    long ospeed, ispeed;
79546808Sdab 	    unsigned char temp[50];
79637219Sminshall 	    int len;
79727676Sminshall 
79837219Sminshall 	    TerminalSpeeds(&ispeed, &ospeed);
79937219Sminshall 
80046808Sdab 	    sprintf((char *)temp, "%c%c%c%c%d,%d%c%c", IAC, SB, TELOPT_TSPEED,
80138689Sborman 		    TELQUAL_IS, ospeed, ispeed, IAC, SE);
80246808Sdab 	    len = strlen((char *)temp+4) + 4;	/* temp[3] is 0 ... */
80337219Sminshall 
80438689Sborman 	    if (len < NETROOM()) {
80538689Sborman 		ring_supply_data(&netoring, temp, len);
80638689Sborman 		printsub('>', temp+2, len - 2);
80737219Sminshall 	    }
80844360Sborman /*@*/	    else printf("lm_will: not enough room in buffer\n");
80937219Sminshall 	}
81037219Sminshall 	break;
81137219Sminshall     case TELOPT_LFLOW:
81238689Sborman 	if (my_want_state_is_wont(TELOPT_LFLOW))
81338689Sborman 	    return;
81446808Sdab 	if (SB_EOF())
81546808Sdab 	    return;
81646808Sdab 	switch(SB_GET()) {
81746808Sdab 	case 1:
81837219Sminshall 	    localflow = 1;
81946808Sdab 	    break;
82046808Sdab 	case 0:
82137219Sminshall 	    localflow = 0;
82246808Sdab 	    break;
82346808Sdab 	default:
82446808Sdab 	    return;
82537219Sminshall 	}
82637219Sminshall 	setcommandmode();
82738689Sborman 	setconnmode(0);
82837219Sminshall 	break;
82938689Sborman 
83038689Sborman     case TELOPT_LINEMODE:
83138689Sborman 	if (my_want_state_is_wont(TELOPT_LINEMODE))
83238689Sborman 	    return;
83346808Sdab 	if (SB_EOF())
83446808Sdab 	    return;
83546808Sdab 	switch (SB_GET()) {
83638689Sborman 	case WILL:
83746808Sdab 	    lm_will(subpointer, SB_LEN());
83838689Sborman 	    break;
83938689Sborman 	case WONT:
84046808Sdab 	    lm_wont(subpointer, SB_LEN());
84138689Sborman 	    break;
84238689Sborman 	case DO:
84346808Sdab 	    lm_do(subpointer, SB_LEN());
84438689Sborman 	    break;
84538689Sborman 	case DONT:
84646808Sdab 	    lm_dont(subpointer, SB_LEN());
84738689Sborman 	    break;
84838689Sborman 	case LM_SLC:
84946808Sdab 	    slc(subpointer, SB_LEN());
85038689Sborman 	    break;
85138689Sborman 	case LM_MODE:
85246808Sdab 	    lm_mode(subpointer, SB_LEN(), 0);
85338689Sborman 	    break;
85438689Sborman 	default:
85544360Sborman 	    break;
85644360Sborman 	}
85744360Sborman 	break;
85844360Sborman 
85944360Sborman     case TELOPT_ENVIRON:
86046808Sdab 	if (SB_EOF())
86146808Sdab 	    return;
86246808Sdab 	switch(SB_PEEK()) {
86344360Sborman 	case TELQUAL_IS:
86444360Sborman 	case TELQUAL_INFO:
86544360Sborman 	    if (my_want_state_is_dont(TELOPT_ENVIRON))
86644360Sborman 		return;
86744360Sborman 	    break;
86844360Sborman 	case TELQUAL_SEND:
86944360Sborman 	    if (my_want_state_is_wont(TELOPT_ENVIRON)) {
87044360Sborman 		return;
87144360Sborman 	    }
87244360Sborman 	    break;
87344360Sborman 	default:
87444360Sborman 	    return;
87544360Sborman 	}
87646808Sdab 	env_opt(subpointer, SB_LEN());
87744360Sborman 	break;
87844360Sborman 
87944360Sborman     case TELOPT_XDISPLOC:
88044360Sborman 	if (my_want_state_is_wont(TELOPT_XDISPLOC))
88144360Sborman 	    return;
88246808Sdab 	if (SB_EOF())
88346808Sdab 	    return;
88446808Sdab 	if (SB_GET() == TELQUAL_SEND) {
88546808Sdab 	    unsigned char temp[50], *dp;
88644360Sborman 	    int len;
88744360Sborman 
88846808Sdab 	    if ((dp = env_getvalue((unsigned char *)"DISPLAY")) == NULL) {
88944360Sborman 		/*
89044360Sborman 		 * Something happened, we no longer have a DISPLAY
89144360Sborman 		 * variable.  So, turn off the option.
89244360Sborman 		 */
89344360Sborman 		send_wont(TELOPT_XDISPLOC, 1);
89438689Sborman 		break;
89544360Sborman 	    }
89646808Sdab 	    sprintf((char *)temp, "%c%c%c%c%s%c%c", IAC, SB, TELOPT_XDISPLOC,
89744360Sborman 		    TELQUAL_IS, dp, IAC, SE);
89846808Sdab 	    len = strlen((char *)temp+4) + 4;	/* temp[3] is 0 ... */
89944360Sborman 
90044360Sborman 	    if (len < NETROOM()) {
90144360Sborman 		ring_supply_data(&netoring, temp, len);
90244360Sborman 		printsub('>', temp+2, len - 2);
90344360Sborman 	    }
90444360Sborman /*@*/	    else printf("lm_will: not enough room in buffer\n");
90538689Sborman 	}
90644360Sborman 	break;
90743319Skfall 
90846808Sdab #if	defined(AUTHENTICATE)
90946808Sdab 	case TELOPT_AUTHENTICATION: {
91046808Sdab 		if (!autologin)
91146808Sdab 			break;
91246808Sdab 		if (SB_EOF())
91346808Sdab 			return;
91446808Sdab 		switch(SB_GET()) {
91546808Sdab 		case TELQUAL_IS:
91646808Sdab 			if (my_want_state_is_dont(TELOPT_AUTHENTICATION))
91746808Sdab 				return;
91846808Sdab 			auth_is(subpointer, SB_LEN());
91946808Sdab 			break;
92046808Sdab 		case TELQUAL_SEND:
92146808Sdab 			if (my_want_state_is_wont(TELOPT_AUTHENTICATION))
92246808Sdab 				return;
92346808Sdab 			auth_send(subpointer, SB_LEN());
92446808Sdab 			break;
92546808Sdab 		case TELQUAL_REPLY:
92646808Sdab 			if (my_want_state_is_wont(TELOPT_AUTHENTICATION))
92746808Sdab 				return;
92846808Sdab 			auth_reply(subpointer, SB_LEN());
92946808Sdab 			break;
930*47608Sdab 		case TELQUAL_NAME:
931*47608Sdab 			if (my_want_state_is_dont(TELOPT_AUTHENTICATION))
932*47608Sdab 				return;
933*47608Sdab 			auth_name(subpointer, SB_LEN());
934*47608Sdab 			break;
93543319Skfall 		}
93646808Sdab 	}
93746808Sdab 	break;
93843319Skfall #endif
93946808Sdab #if	defined(ENCRYPT)
94046808Sdab 	case TELOPT_ENCRYPT:
94146808Sdab 		if (SB_EOF())
94246808Sdab 			return;
94346808Sdab 		switch(SB_GET()) {
94446808Sdab 		case ENCRYPT_START:
94546808Sdab 			if (my_want_state_is_dont(TELOPT_ENCRYPT))
94646808Sdab 				return;
947*47608Sdab 			encrypt_start(subpointer, SB_LEN());
94846808Sdab 			break;
94946808Sdab 		case ENCRYPT_END:
95046808Sdab 			if (my_want_state_is_dont(TELOPT_ENCRYPT))
95146808Sdab 				return;
95246808Sdab 			encrypt_end();
95346808Sdab 			break;
95446808Sdab 		case ENCRYPT_SUPPORT:
95546808Sdab 			if (my_want_state_is_wont(TELOPT_ENCRYPT))
95646808Sdab 				return;
95746808Sdab 			encrypt_support(subpointer, SB_LEN());
95846808Sdab 			break;
95946808Sdab 		case ENCRYPT_REQSTART:
96046808Sdab 			if (my_want_state_is_wont(TELOPT_ENCRYPT))
96146808Sdab 				return;
962*47608Sdab 			encrypt_request_start(subpointer, SB_LEN());
96346808Sdab 			break;
96446808Sdab 		case ENCRYPT_REQEND:
96546808Sdab 			if (my_want_state_is_wont(TELOPT_ENCRYPT))
96646808Sdab 				return;
96746808Sdab 			/*
96846808Sdab 			 * We can always send an REQEND so that we cannot
96946808Sdab 			 * get stuck encrypting.  We should only get this
97046808Sdab 			 * if we have been able to get in the correct mode
97146808Sdab 			 * anyhow.
97246808Sdab 			 */
97346808Sdab 			encrypt_request_end();
97446808Sdab 			break;
97546808Sdab 		case ENCRYPT_IS:
97646808Sdab 			if (my_want_state_is_dont(TELOPT_ENCRYPT))
97746808Sdab 				return;
97846808Sdab 			encrypt_is(subpointer, SB_LEN());
97946808Sdab 			break;
98046808Sdab 		case ENCRYPT_REPLY:
98146808Sdab 			if (my_want_state_is_wont(TELOPT_ENCRYPT))
98246808Sdab 				return;
98346808Sdab 			encrypt_reply(subpointer, SB_LEN());
98446808Sdab 			break;
985*47608Sdab 		case ENCRYPT_ENC_KEYID:
986*47608Sdab 			if (my_want_state_is_dont(TELOPT_ENCRYPT))
987*47608Sdab 				return;
988*47608Sdab 			encrypt_enc_keyid(subpointer, SB_LEN());
989*47608Sdab 			break;
990*47608Sdab 		case ENCRYPT_DEC_KEYID:
991*47608Sdab 			if (my_want_state_is_wont(TELOPT_ENCRYPT))
992*47608Sdab 				return;
993*47608Sdab 			encrypt_dec_keyid(subpointer, SB_LEN());
994*47608Sdab 			break;
99546808Sdab 		default:
99646808Sdab 			break;
99746808Sdab 		}
99846808Sdab 		break;
99943319Skfall #endif
100027676Sminshall     default:
100127676Sminshall 	break;
100227676Sminshall     }
100327676Sminshall }
100438689Sborman 
100546808Sdab static unsigned char str_lm[] = { IAC, SB, TELOPT_LINEMODE, 0, 0, IAC, SE };
100638689Sborman 
100746808Sdab     void
100838689Sborman lm_will(cmd, len)
100946808Sdab     unsigned char *cmd;
101046808Sdab     int len;
101138689Sborman {
101244360Sborman     if (len < 1) {
101344360Sborman /*@*/	printf("lm_will: no command!!!\n");	/* Should not happen... */
101444360Sborman 	return;
101544360Sborman     }
101638689Sborman     switch(cmd[0]) {
101738689Sborman     case LM_FORWARDMASK:	/* We shouldn't ever get this... */
101838689Sborman     default:
101938689Sborman 	str_lm[3] = DONT;
102038689Sborman 	str_lm[4] = cmd[0];
102138689Sborman 	if (NETROOM() > sizeof(str_lm)) {
102238689Sborman 	    ring_supply_data(&netoring, str_lm, sizeof(str_lm));
102338689Sborman 	    printsub('>', &str_lm[2], sizeof(str_lm)-2);
102438689Sborman 	}
102538689Sborman /*@*/	else printf("lm_will: not enough room in buffer\n");
102638689Sborman 	break;
102738689Sborman     }
102838689Sborman }
102938689Sborman 
103046808Sdab     void
103138689Sborman lm_wont(cmd, len)
103246808Sdab     unsigned char *cmd;
103346808Sdab     int len;
103438689Sborman {
103544360Sborman     if (len < 1) {
103644360Sborman /*@*/	printf("lm_wont: no command!!!\n");	/* Should not happen... */
103744360Sborman 	return;
103844360Sborman     }
103938689Sborman     switch(cmd[0]) {
104038689Sborman     case LM_FORWARDMASK:	/* We shouldn't ever get this... */
104138689Sborman     default:
104238689Sborman 	/* We are always DONT, so don't respond */
104338689Sborman 	return;
104438689Sborman     }
104538689Sborman }
104638689Sborman 
104746808Sdab     void
104838689Sborman lm_do(cmd, len)
104946808Sdab     unsigned char *cmd;
105046808Sdab     int len;
105138689Sborman {
105244360Sborman     if (len < 1) {
105344360Sborman /*@*/	printf("lm_do: no command!!!\n");	/* Should not happen... */
105444360Sborman 	return;
105544360Sborman     }
105638689Sborman     switch(cmd[0]) {
105738689Sborman     case LM_FORWARDMASK:
105838689Sborman     default:
105938689Sborman 	str_lm[3] = WONT;
106038689Sborman 	str_lm[4] = cmd[0];
106138689Sborman 	if (NETROOM() > sizeof(str_lm)) {
106238689Sborman 	    ring_supply_data(&netoring, str_lm, sizeof(str_lm));
106338689Sborman 	    printsub('>', &str_lm[2], sizeof(str_lm)-2);
106438689Sborman 	}
106538689Sborman /*@*/	else printf("lm_do: not enough room in buffer\n");
106638689Sborman 	break;
106738689Sborman     }
106838689Sborman }
106938689Sborman 
107046808Sdab     void
107138689Sborman lm_dont(cmd, len)
107246808Sdab     unsigned char *cmd;
107346808Sdab     int len;
107438689Sborman {
107544360Sborman     if (len < 1) {
107644360Sborman /*@*/	printf("lm_dont: no command!!!\n");	/* Should not happen... */
107744360Sborman 	return;
107844360Sborman     }
107938689Sborman     switch(cmd[0]) {
108038689Sborman     case LM_FORWARDMASK:
108138689Sborman     default:
108238689Sborman 	/* we are always WONT, so don't respond */
108338689Sborman 	break;
108438689Sborman     }
108538689Sborman }
108638689Sborman 
108746808Sdab static unsigned char str_lm_mode[] = {
108846808Sdab 	IAC, SB, TELOPT_LINEMODE, LM_MODE, 0, IAC, SE
108946808Sdab };
109038689Sborman 
109146808Sdab 	void
109238689Sborman lm_mode(cmd, len, init)
109346808Sdab 	unsigned char *cmd;
109446808Sdab 	int len, init;
109538689Sborman {
109638689Sborman 	if (len != 1)
109738689Sborman 		return;
109844360Sborman 	if ((linemode&MODE_MASK&~MODE_ACK) == *cmd)
109938689Sborman 		return;
110038689Sborman 	if (*cmd&MODE_ACK)
110138689Sborman 		return;
110244360Sborman 	linemode = *cmd&(MODE_MASK&~MODE_ACK);
110338689Sborman 	str_lm_mode[4] = linemode;
110438689Sborman 	if (!init)
110538689Sborman 	    str_lm_mode[4] |= MODE_ACK;
110638689Sborman 	if (NETROOM() > sizeof(str_lm_mode)) {
110738689Sborman 	    ring_supply_data(&netoring, str_lm_mode, sizeof(str_lm_mode));
110838689Sborman 	    printsub('>', &str_lm_mode[2], sizeof(str_lm_mode)-2);
110938689Sborman 	}
111038689Sborman /*@*/	else printf("lm_mode: not enough room in buffer\n");
111138689Sborman 	setconnmode(0);	/* set changed mode */
111238689Sborman }
111338689Sborman 
111432377Sminshall 
111527088Sminshall 
111638689Sborman /*
111738689Sborman  * slc()
111838689Sborman  * Handle special character suboption of LINEMODE.
111938689Sborman  */
112038689Sborman 
112138689Sborman struct spc {
112240245Sborman 	cc_t val;
112340245Sborman 	cc_t *valp;
112438689Sborman 	char flags;	/* Current flags & level */
112538689Sborman 	char mylevel;	/* Maximum level & flags */
112638689Sborman } spc_data[NSLC+1];
112738689Sborman 
112838689Sborman #define SLC_IMPORT	0
112938689Sborman #define	SLC_EXPORT	1
113038689Sborman #define SLC_RVALUE	2
113138689Sborman static int slc_mode = SLC_EXPORT;
113238689Sborman 
113346808Sdab 	void
113438689Sborman slc_init()
113538689Sborman {
113638689Sborman 	register struct spc *spcp;
113738689Sborman 
113838689Sborman 	localchars = 1;
113938689Sborman 	for (spcp = spc_data; spcp < &spc_data[NSLC+1]; spcp++) {
114038689Sborman 		spcp->val = 0;
114138689Sborman 		spcp->valp = 0;
114238689Sborman 		spcp->flags = spcp->mylevel = SLC_NOSUPPORT;
114338689Sborman 	}
114438689Sborman 
114538689Sborman #define	initfunc(func, flags) { \
114638689Sborman 					spcp = &spc_data[func]; \
114738689Sborman 					if (spcp->valp = tcval(func)) { \
114838689Sborman 					    spcp->val = *spcp->valp; \
114938689Sborman 					    spcp->mylevel = SLC_VARIABLE|flags; \
115038689Sborman 					} else { \
115138689Sborman 					    spcp->val = 0; \
115238689Sborman 					    spcp->mylevel = SLC_DEFAULT; \
115338689Sborman 					} \
115438689Sborman 				    }
115538689Sborman 
115638689Sborman 	initfunc(SLC_SYNCH, 0);
115738689Sborman 	/* No BRK */
115838689Sborman 	initfunc(SLC_AO, 0);
115938689Sborman 	initfunc(SLC_AYT, 0);
116038689Sborman 	/* No EOR */
116138689Sborman 	initfunc(SLC_ABORT, SLC_FLUSHIN|SLC_FLUSHOUT);
116238689Sborman 	initfunc(SLC_EOF, 0);
116339529Sborman #ifndef	SYSV_TERMIO
116438689Sborman 	initfunc(SLC_SUSP, SLC_FLUSHIN);
116538689Sborman #endif
116638689Sborman 	initfunc(SLC_EC, 0);
116738689Sborman 	initfunc(SLC_EL, 0);
116839529Sborman #ifndef	SYSV_TERMIO
116938689Sborman 	initfunc(SLC_EW, 0);
117038689Sborman 	initfunc(SLC_RP, 0);
117138689Sborman 	initfunc(SLC_LNEXT, 0);
117238689Sborman #endif
117338689Sborman 	initfunc(SLC_XON, 0);
117438689Sborman 	initfunc(SLC_XOFF, 0);
117539529Sborman #ifdef	SYSV_TERMIO
117638689Sborman 	spc_data[SLC_XON].mylevel = SLC_CANTCHANGE;
117738689Sborman 	spc_data[SLC_XOFF].mylevel = SLC_CANTCHANGE;
117838689Sborman #endif
117944360Sborman 	initfunc(SLC_FORW1, 0);
118044360Sborman #ifdef	USE_TERMIO
118144360Sborman 	initfunc(SLC_FORW2, 0);
118238689Sborman 	/* No FORW2 */
118344360Sborman #endif
118438689Sborman 
118538689Sborman 	initfunc(SLC_IP, SLC_FLUSHIN|SLC_FLUSHOUT);
118638689Sborman #undef	initfunc
118738689Sborman 
118838689Sborman 	if (slc_mode == SLC_EXPORT)
118938689Sborman 		slc_export();
119038689Sborman 	else
119138689Sborman 		slc_import(1);
119238689Sborman 
119338689Sborman }
119438689Sborman 
119546808Sdab     void
119638689Sborman slcstate()
119738689Sborman {
119838689Sborman     printf("Special characters are %s values\n",
119938689Sborman 		slc_mode == SLC_IMPORT ? "remote default" :
120038689Sborman 		slc_mode == SLC_EXPORT ? "local" :
120138689Sborman 					 "remote");
120238689Sborman }
120338689Sborman 
120446808Sdab     void
120538689Sborman slc_mode_export()
120638689Sborman {
120738689Sborman     slc_mode = SLC_EXPORT;
120838689Sborman     if (my_state_is_will(TELOPT_LINEMODE))
120938689Sborman 	slc_export();
121038689Sborman }
121138689Sborman 
121246808Sdab     void
121338689Sborman slc_mode_import(def)
121446808Sdab     int def;
121538689Sborman {
121638689Sborman     slc_mode = def ? SLC_IMPORT : SLC_RVALUE;
121738689Sborman     if (my_state_is_will(TELOPT_LINEMODE))
121838689Sborman 	slc_import(def);
121938689Sborman }
122038689Sborman 
122146808Sdab unsigned char slc_import_val[] = {
122238689Sborman 	IAC, SB, TELOPT_LINEMODE, LM_SLC, 0, SLC_VARIABLE, 0, IAC, SE
122338689Sborman };
122446808Sdab unsigned char slc_import_def[] = {
122538689Sborman 	IAC, SB, TELOPT_LINEMODE, LM_SLC, 0, SLC_DEFAULT, 0, IAC, SE
122638689Sborman };
122738689Sborman 
122846808Sdab     void
122938689Sborman slc_import(def)
123046808Sdab     int def;
123138689Sborman {
123238689Sborman     if (NETROOM() > sizeof(slc_import_val)) {
123338689Sborman 	if (def) {
123438689Sborman 	    ring_supply_data(&netoring, slc_import_def, sizeof(slc_import_def));
123538689Sborman 	    printsub('>', &slc_import_def[2], sizeof(slc_import_def)-2);
123638689Sborman 	} else {
123738689Sborman 	    ring_supply_data(&netoring, slc_import_val, sizeof(slc_import_val));
123838689Sborman 	    printsub('>', &slc_import_val[2], sizeof(slc_import_val)-2);
123938689Sborman 	}
124038689Sborman     }
124138689Sborman /*@*/ else printf("slc_import: not enough room\n");
124238689Sborman }
124338689Sborman 
124446808Sdab     void
124538689Sborman slc_export()
124638689Sborman {
124738689Sborman     register struct spc *spcp;
124838689Sborman 
124938689Sborman     TerminalDefaultChars();
125038689Sborman 
125138689Sborman     slc_start_reply();
125238689Sborman     for (spcp = &spc_data[1]; spcp < &spc_data[NSLC+1]; spcp++) {
125338689Sborman 	if (spcp->mylevel != SLC_NOSUPPORT) {
125445232Sborman 	    if (spcp->val == (cc_t)(_POSIX_VDISABLE))
125545232Sborman 		spcp->flags = SLC_NOSUPPORT;
125645232Sborman 	    else
125745232Sborman 		spcp->flags = spcp->mylevel;
125838689Sborman 	    if (spcp->valp)
125938689Sborman 		spcp->val = *spcp->valp;
126045232Sborman 	    slc_add_reply(spcp - spc_data, spcp->flags, spcp->val);
126138689Sborman 	}
126238689Sborman     }
126338689Sborman     slc_end_reply();
126446808Sdab     (void)slc_update();
126546808Sdab     setconnmode(1);	/* Make sure the character values are set */
126638689Sborman }
126738689Sborman 
126846808Sdab 	void
126938689Sborman slc(cp, len)
127046808Sdab 	register unsigned char *cp;
127146808Sdab 	int len;
127238689Sborman {
127338689Sborman 	register struct spc *spcp;
127438689Sborman 	register int func,level;
127538689Sborman 
127638689Sborman 	slc_start_reply();
127738689Sborman 
127838689Sborman 	for (; len >= 3; len -=3, cp +=3) {
127938689Sborman 
128038689Sborman 		func = cp[SLC_FUNC];
128138689Sborman 
128238689Sborman 		if (func == 0) {
128338689Sborman 			/*
128438689Sborman 			 * Client side: always ignore 0 function.
128538689Sborman 			 */
128638689Sborman 			continue;
128738689Sborman 		}
128838689Sborman 		if (func > NSLC) {
128945232Sborman 			if ((cp[SLC_FLAGS] & SLC_LEVELBITS) != SLC_NOSUPPORT)
129038689Sborman 				slc_add_reply(func, SLC_NOSUPPORT, 0);
129138689Sborman 			continue;
129238689Sborman 		}
129338689Sborman 
129438689Sborman 		spcp = &spc_data[func];
129538689Sborman 
129638689Sborman 		level = cp[SLC_FLAGS]&(SLC_LEVELBITS|SLC_ACK);
129738689Sborman 
129840245Sborman 		if ((cp[SLC_VALUE] == (unsigned char)spcp->val) &&
129938689Sborman 		    ((level&SLC_LEVELBITS) == (spcp->flags&SLC_LEVELBITS))) {
130038689Sborman 			continue;
130138689Sborman 		}
130238689Sborman 
130338689Sborman 		if (level == (SLC_DEFAULT|SLC_ACK)) {
130438689Sborman 			/*
130538689Sborman 			 * This is an error condition, the SLC_ACK
130638689Sborman 			 * bit should never be set for the SLC_DEFAULT
130738689Sborman 			 * level.  Our best guess to recover is to
130838689Sborman 			 * ignore the SLC_ACK bit.
130938689Sborman 			 */
131038689Sborman 			cp[SLC_FLAGS] &= ~SLC_ACK;
131138689Sborman 		}
131238689Sborman 
131338689Sborman 		if (level == ((spcp->flags&SLC_LEVELBITS)|SLC_ACK)) {
131440245Sborman 			spcp->val = (cc_t)cp[SLC_VALUE];
131538689Sborman 			spcp->flags = cp[SLC_FLAGS];	/* include SLC_ACK */
131638689Sborman 			continue;
131738689Sborman 		}
131838689Sborman 
131938689Sborman 		level &= ~SLC_ACK;
132038689Sborman 
132138689Sborman 		if (level <= (spcp->mylevel&SLC_LEVELBITS)) {
132238689Sborman 			spcp->flags = cp[SLC_FLAGS]|SLC_ACK;
132340245Sborman 			spcp->val = (cc_t)cp[SLC_VALUE];
132438689Sborman 		}
132538689Sborman 		if (level == SLC_DEFAULT) {
132638689Sborman 			if ((spcp->mylevel&SLC_LEVELBITS) != SLC_DEFAULT)
132738689Sborman 				spcp->flags = spcp->mylevel;
132838689Sborman 			else
132938689Sborman 				spcp->flags = SLC_NOSUPPORT;
133038689Sborman 		}
133138689Sborman 		slc_add_reply(func, spcp->flags, spcp->val);
133238689Sborman 	}
133338689Sborman 	slc_end_reply();
133438689Sborman 	if (slc_update())
133538689Sborman 		setconnmode(1);	/* set the  new character values */
133638689Sborman }
133738689Sborman 
133846808Sdab     void
133938689Sborman slc_check()
134038689Sborman {
134138689Sborman     register struct spc *spcp;
134238689Sborman 
134338689Sborman     slc_start_reply();
134438689Sborman     for (spcp = &spc_data[1]; spcp < &spc_data[NSLC+1]; spcp++) {
134538689Sborman 	if (spcp->valp && spcp->val != *spcp->valp) {
134638689Sborman 	    spcp->val = *spcp->valp;
134745232Sborman 	    if (spcp->val == (cc_t)(_POSIX_VDISABLE))
134845232Sborman 		spcp->flags = SLC_NOSUPPORT;
134945232Sborman 	    else
135045232Sborman 		spcp->flags = spcp->mylevel;
135145232Sborman 	    slc_add_reply(spcp - spc_data, spcp->flags, spcp->val);
135238689Sborman 	}
135338689Sborman     }
135438689Sborman     slc_end_reply();
135538689Sborman     setconnmode(1);
135638689Sborman }
135738689Sborman 
135838689Sborman 
135938689Sborman unsigned char slc_reply[128];
136038689Sborman unsigned char *slc_replyp;
136146808Sdab 
136246808Sdab 	void
136338689Sborman slc_start_reply()
136438689Sborman {
136538689Sborman 	slc_replyp = slc_reply;
136638689Sborman 	*slc_replyp++ = IAC;
136738689Sborman 	*slc_replyp++ = SB;
136838689Sborman 	*slc_replyp++ = TELOPT_LINEMODE;
136938689Sborman 	*slc_replyp++ = LM_SLC;
137038689Sborman }
137138689Sborman 
137246808Sdab 	void
137338689Sborman slc_add_reply(func, flags, value)
137446808Sdab 	unsigned char func;
137546808Sdab 	unsigned char flags;
137646808Sdab 	cc_t value;
137738689Sborman {
137838689Sborman 	if ((*slc_replyp++ = func) == IAC)
137938689Sborman 		*slc_replyp++ = IAC;
138038689Sborman 	if ((*slc_replyp++ = flags) == IAC)
138138689Sborman 		*slc_replyp++ = IAC;
138240245Sborman 	if ((*slc_replyp++ = (unsigned char)value) == IAC)
138338689Sborman 		*slc_replyp++ = IAC;
138438689Sborman }
138538689Sborman 
138646808Sdab     void
138738689Sborman slc_end_reply()
138838689Sborman {
138938689Sborman     register int len;
139038689Sborman 
139138689Sborman     *slc_replyp++ = IAC;
139238689Sborman     *slc_replyp++ = SE;
139338689Sborman     len = slc_replyp - slc_reply;
139438689Sborman     if (len <= 6)
139538689Sborman 	return;
139638689Sborman     if (NETROOM() > len) {
139738689Sborman 	ring_supply_data(&netoring, slc_reply, slc_replyp - slc_reply);
139838689Sborman 	printsub('>', &slc_reply[2], slc_replyp - slc_reply - 2);
139938689Sborman     }
140038689Sborman /*@*/else printf("slc_end_reply: not enough room\n");
140138689Sborman }
140238689Sborman 
140346808Sdab 	int
140438689Sborman slc_update()
140538689Sborman {
140638689Sborman 	register struct spc *spcp;
140738689Sborman 	int need_update = 0;
140838689Sborman 
140938689Sborman 	for (spcp = &spc_data[1]; spcp < &spc_data[NSLC+1]; spcp++) {
141038689Sborman 		if (!(spcp->flags&SLC_ACK))
141138689Sborman 			continue;
141238689Sborman 		spcp->flags &= ~SLC_ACK;
141338689Sborman 		if (spcp->valp && (*spcp->valp != spcp->val)) {
141438689Sborman 			*spcp->valp = spcp->val;
141538689Sborman 			need_update = 1;
141638689Sborman 		}
141738689Sborman 	}
141838689Sborman 	return(need_update);
141938689Sborman }
142038689Sborman 
142146808Sdab 	void
142244360Sborman env_opt(buf, len)
142346808Sdab 	register unsigned char *buf;
142446808Sdab 	register int len;
142544360Sborman {
142646808Sdab 	register unsigned char *ep = 0, *epc = 0;
142744360Sborman 	register int i;
142844360Sborman 
142945232Sborman 	switch(buf[0]&0xff) {
143044360Sborman 	case TELQUAL_SEND:
143144360Sborman 		env_opt_start();
143244360Sborman 		if (len == 1) {
143344360Sborman 			env_opt_add(NULL);
143444360Sborman 		} else for (i = 1; i < len; i++) {
143545232Sborman 			switch (buf[i]&0xff) {
143644360Sborman 			case ENV_VALUE:
143744360Sborman 				if (ep) {
143844360Sborman 					*epc = 0;
143944360Sborman 					env_opt_add(ep);
144044360Sborman 				}
144144360Sborman 				ep = epc = &buf[i+1];
144244360Sborman 				break;
144344360Sborman 			case ENV_ESC:
144444360Sborman 				i++;
144544360Sborman 				/*FALL THROUGH*/
144644360Sborman 			default:
144744360Sborman 				if (epc)
144844360Sborman 					*epc++ = buf[i];
144944360Sborman 				break;
145044360Sborman 			}
145144360Sborman 			if (ep) {
145244360Sborman 				*epc = 0;
145344360Sborman 				env_opt_add(ep);
145444360Sborman 			}
145544360Sborman 		}
145644360Sborman 		env_opt_end(1);
145744360Sborman 		break;
145844360Sborman 
145944360Sborman 	case TELQUAL_IS:
146044360Sborman 	case TELQUAL_INFO:
146144360Sborman 		/* Ignore for now.  We shouldn't get it anyway. */
146244360Sborman 		break;
146344360Sborman 
146444360Sborman 	default:
146544360Sborman 		break;
146644360Sborman 	}
146744360Sborman }
146844360Sborman 
146944360Sborman #define	OPT_REPLY_SIZE	256
147044360Sborman unsigned char *opt_reply;
147144360Sborman unsigned char *opt_replyp;
147244360Sborman unsigned char *opt_replyend;
147344360Sborman 
147446808Sdab 	void
147544360Sborman env_opt_start()
147644360Sborman {
147744360Sborman 	if (opt_reply)
147844360Sborman 		opt_reply = (unsigned char *)realloc(opt_reply, OPT_REPLY_SIZE);
147944360Sborman 	else
148044360Sborman 		opt_reply = (unsigned char *)malloc(OPT_REPLY_SIZE);
148144360Sborman 	if (opt_reply == NULL) {
148244360Sborman /*@*/		printf("env_opt_start: malloc()/realloc() failed!!!\n");
148344360Sborman 		opt_reply = opt_replyp = opt_replyend = NULL;
148444360Sborman 		return;
148544360Sborman 	}
148644360Sborman 	opt_replyp = opt_reply;
148744360Sborman 	opt_replyend = opt_reply + OPT_REPLY_SIZE;
148844360Sborman 	*opt_replyp++ = IAC;
148944360Sborman 	*opt_replyp++ = SB;
149044360Sborman 	*opt_replyp++ = TELOPT_ENVIRON;
149144360Sborman 	*opt_replyp++ = TELQUAL_IS;
149244360Sborman }
149344360Sborman 
149446808Sdab 	void
149544360Sborman env_opt_start_info()
149644360Sborman {
149744360Sborman 	env_opt_start();
149844360Sborman 	if (opt_replyp)
149944360Sborman 	    opt_replyp[-1] = TELQUAL_INFO;
150044360Sborman }
150144360Sborman 
150246808Sdab 	void
150344360Sborman env_opt_add(ep)
150446808Sdab 	register unsigned char *ep;
150544360Sborman {
150646808Sdab 	register unsigned char *vp, c;
150744360Sborman 
150844360Sborman 	if (opt_reply == NULL)		/*XXX*/
150944360Sborman 		return;			/*XXX*/
151044360Sborman 
151144360Sborman 	if (ep == NULL || *ep == '\0') {
151244360Sborman 		env_default(1);
151344360Sborman 		while (ep = env_default(0))
151444360Sborman 			env_opt_add(ep);
151544360Sborman 		return;
151644360Sborman 	}
151744360Sborman 	vp = env_getvalue(ep);
151846808Sdab 	if (opt_replyp + (vp ? strlen((char *)vp) : 0) +
151946808Sdab 				strlen((char *)ep) + 6 > opt_replyend)
152046808Sdab 	{
152144360Sborman 		register int len;
152244360Sborman 		opt_replyend += OPT_REPLY_SIZE;
152344360Sborman 		len = opt_replyend - opt_reply;
152444360Sborman 		opt_reply = (unsigned char *)realloc(opt_reply, len);
152544360Sborman 		if (opt_reply == NULL) {
152644360Sborman /*@*/			printf("env_opt_add: realloc() failed!!!\n");
152744360Sborman 			opt_reply = opt_replyp = opt_replyend = NULL;
152844360Sborman 			return;
152944360Sborman 		}
153044360Sborman 		opt_replyp = opt_reply + len - (opt_replyend - opt_replyp);
153144360Sborman 		opt_replyend = opt_reply + len;
153244360Sborman 	}
153344360Sborman 	*opt_replyp++ = ENV_VAR;
153444360Sborman 	for (;;) {
153544360Sborman 		while (c = *ep++) {
153645232Sborman 			switch(c&0xff) {
153744360Sborman 			case IAC:
153844360Sborman 				*opt_replyp++ = IAC;
153944360Sborman 				break;
154044360Sborman 			case ENV_VALUE:
154144360Sborman 			case ENV_VAR:
154244360Sborman 			case ENV_ESC:
154344360Sborman 				*opt_replyp++ = ENV_ESC;
154444360Sborman 				break;
154544360Sborman 			}
154644360Sborman 			*opt_replyp++ = c;
154744360Sborman 		}
154844360Sborman 		if (ep = vp) {
154944360Sborman 			*opt_replyp++ = ENV_VALUE;
155044360Sborman 			vp = NULL;
155144360Sborman 		} else
155244360Sborman 			break;
155344360Sborman 	}
155444360Sborman }
155544360Sborman 
155646808Sdab 	void
155744360Sborman env_opt_end(emptyok)
155846808Sdab 	register int emptyok;
155944360Sborman {
156044360Sborman 	register int len;
156144360Sborman 
156244360Sborman 	len = opt_replyp - opt_reply + 2;
156344360Sborman 	if (emptyok || len > 6) {
156444360Sborman 		*opt_replyp++ = IAC;
156544360Sborman 		*opt_replyp++ = SE;
156644360Sborman 		if (NETROOM() > len) {
156744360Sborman 			ring_supply_data(&netoring, opt_reply, len);
156844360Sborman 			printsub('>', &opt_reply[2], len - 2);
156944360Sborman 		}
157044360Sborman /*@*/		else printf("slc_end_reply: not enough room\n");
157144360Sborman 	}
157244360Sborman 	if (opt_reply) {
157344360Sborman 		free(opt_reply);
157444360Sborman 		opt_reply = opt_replyp = opt_replyend = NULL;
157544360Sborman 	}
157644360Sborman }
157744360Sborman 
157838689Sborman 
157938689Sborman 
158046808Sdab     int
158132377Sminshall telrcv()
158227110Sminshall {
158332377Sminshall     register int c;
158432385Sminshall     register int scc;
158546808Sdab     register unsigned char *sbp;
158632385Sminshall     int count;
158732385Sminshall     int returnValue = 0;
158827088Sminshall 
158932385Sminshall     scc = 0;
159032385Sminshall     count = 0;
159132385Sminshall     while (TTYROOM() > 2) {
159232385Sminshall 	if (scc == 0) {
159332385Sminshall 	    if (count) {
159432528Sminshall 		ring_consumed(&netiring, count);
159532385Sminshall 		returnValue = 1;
159632385Sminshall 		count = 0;
159732385Sminshall 	    }
159832528Sminshall 	    sbp = netiring.consume;
159932528Sminshall 	    scc = ring_full_consecutive(&netiring);
160032385Sminshall 	    if (scc == 0) {
160132385Sminshall 		/* No more data coming in */
160232385Sminshall 		break;
160332385Sminshall 	    }
160432385Sminshall 	}
160532385Sminshall 
160632385Sminshall 	c = *sbp++ & 0xff, scc--; count++;
160746808Sdab #if	defined(ENCRYPT)
160846808Sdab 	if (decrypt_input)
160946808Sdab 		c = (*decrypt_input)(c);
161046808Sdab #endif
161132385Sminshall 
161232377Sminshall 	switch (telrcv_state) {
161327110Sminshall 
161432377Sminshall 	case TS_CR:
161532377Sminshall 	    telrcv_state = TS_DATA;
161635518Sminshall 	    if (c == '\0') {
161735518Sminshall 		break;	/* Ignore \0 after CR */
161839529Sborman 	    }
161939529Sborman 	    else if ((c == '\n') && my_want_state_is_dont(TELOPT_ECHO) && !crmod) {
162035518Sminshall 		TTYADD(c);
162135518Sminshall 		break;
162232377Sminshall 	    }
162335518Sminshall 	    /* Else, fall through */
162427088Sminshall 
162532377Sminshall 	case TS_DATA:
162632377Sminshall 	    if (c == IAC) {
162732377Sminshall 		telrcv_state = TS_IAC;
162833804Sminshall 		break;
162932377Sminshall 	    }
163032377Sminshall #	    if defined(TN3270)
163132377Sminshall 	    if (In3270) {
163232377Sminshall 		*Ifrontp++ = c;
163332385Sminshall 		while (scc > 0) {
163432385Sminshall 		    c = *sbp++ & 0377, scc--; count++;
163546808Sdab #if	defined(ENCRYPT)
163646808Sdab 		    if (decrypt_input)
163746808Sdab 			c = (*decrypt_input)(c);
163846808Sdab #endif
163932377Sminshall 		    if (c == IAC) {
164032377Sminshall 			telrcv_state = TS_IAC;
164134304Sminshall 			break;
164232377Sminshall 		    }
164332377Sminshall 		    *Ifrontp++ = c;
164432377Sminshall 		}
164532377Sminshall 	    } else
164632377Sminshall #	    endif /* defined(TN3270) */
164735518Sminshall 		    /*
164835518Sminshall 		     * The 'crmod' hack (see following) is needed
164935518Sminshall 		     * since we can't * set CRMOD on output only.
165035518Sminshall 		     * Machines like MULTICS like to send \r without
165135518Sminshall 		     * \n; since we must turn off CRMOD to get proper
165235518Sminshall 		     * input, the mapping is done here (sigh).
165335518Sminshall 		     */
165438689Sborman 	    if ((c == '\r') && my_want_state_is_dont(TELOPT_BINARY)) {
165535518Sminshall 		if (scc > 0) {
165635518Sminshall 		    c = *sbp&0xff;
165746808Sdab #if	defined(ENCRYPT)
165846808Sdab 		    if (decrypt_input)
165946808Sdab 			c = (*decrypt_input)(c);
166046808Sdab #endif
166135518Sminshall 		    if (c == 0) {
166235518Sminshall 			sbp++, scc--; count++;
166335518Sminshall 			/* a "true" CR */
166432377Sminshall 			TTYADD('\r');
166538689Sborman 		    } else if (my_want_state_is_dont(TELOPT_ECHO) &&
166635518Sminshall 					(c == '\n')) {
166735518Sminshall 			sbp++, scc--; count++;
166832377Sminshall 			TTYADD('\n');
166935518Sminshall 		    } else {
167046808Sdab #if	defined(ENCRYPT)
167146808Sdab 		        if (decrypt_input)
167246808Sdab 			    (*decrypt_input)(-1);
167346808Sdab #endif
167446808Sdab 
167535518Sminshall 			TTYADD('\r');
167635518Sminshall 			if (crmod) {
167735518Sminshall 				TTYADD('\n');
167832377Sminshall 			}
167932377Sminshall 		    }
168035518Sminshall 		} else {
168135518Sminshall 		    telrcv_state = TS_CR;
168235518Sminshall 		    TTYADD('\r');
168335518Sminshall 		    if (crmod) {
168435518Sminshall 			    TTYADD('\n');
168535518Sminshall 		    }
168632377Sminshall 		}
168732377Sminshall 	    } else {
168832377Sminshall 		TTYADD(c);
168932377Sminshall 	    }
169032377Sminshall 	    continue;
169127088Sminshall 
169232377Sminshall 	case TS_IAC:
169338689Sborman process_iac:
169432377Sminshall 	    switch (c) {
169532377Sminshall 
169632377Sminshall 	    case WILL:
169732377Sminshall 		telrcv_state = TS_WILL;
169832377Sminshall 		continue;
169927261Sminshall 
170032377Sminshall 	    case WONT:
170132377Sminshall 		telrcv_state = TS_WONT;
170232377Sminshall 		continue;
170327261Sminshall 
170432377Sminshall 	    case DO:
170532377Sminshall 		telrcv_state = TS_DO;
170632377Sminshall 		continue;
170727261Sminshall 
170832377Sminshall 	    case DONT:
170932377Sminshall 		telrcv_state = TS_DONT;
171032377Sminshall 		continue;
171127261Sminshall 
171232377Sminshall 	    case DM:
171332377Sminshall 		    /*
171432377Sminshall 		     * We may have missed an urgent notification,
171532377Sminshall 		     * so make sure we flush whatever is in the
171632377Sminshall 		     * buffer currently.
171732377Sminshall 		     */
171846808Sdab 		printoption("RCVD", IAC, DM);
171932377Sminshall 		SYNCHing = 1;
172044360Sborman 		(void) ttyflush(1);
172132554Sminshall 		SYNCHing = stilloob();
172232377Sminshall 		settimer(gotDM);
172332377Sminshall 		break;
172427088Sminshall 
172532377Sminshall 	    case SB:
172632377Sminshall 		SB_CLEAR();
172732377Sminshall 		telrcv_state = TS_SB;
172832377Sminshall 		continue;
172927261Sminshall 
173032377Sminshall #	    if defined(TN3270)
173132377Sminshall 	    case EOR:
173232377Sminshall 		if (In3270) {
173332377Sminshall 		    if (Ibackp == Ifrontp) {
173432377Sminshall 			Ibackp = Ifrontp = Ibuf;
173532377Sminshall 			ISend = 0;	/* should have been! */
173632377Sminshall 		    } else {
173744360Sborman 			Ibackp += DataFromNetwork(Ibackp, Ifrontp-Ibackp, 1);
173832377Sminshall 			ISend = 1;
173927088Sminshall 		    }
174027088Sminshall 		}
174146808Sdab 		printoption("RCVD", IAC, EOR);
174227088Sminshall 		break;
174332377Sminshall #	    endif /* defined(TN3270) */
174432377Sminshall 
174532377Sminshall 	    case IAC:
174632377Sminshall #	    if !defined(TN3270)
174732377Sminshall 		TTYADD(IAC);
174832377Sminshall #	    else /* !defined(TN3270) */
174932377Sminshall 		if (In3270) {
175032377Sminshall 		    *Ifrontp++ = IAC;
175132377Sminshall 		} else {
175232377Sminshall 		    TTYADD(IAC);
175332377Sminshall 		}
175432377Sminshall #	    endif /* !defined(TN3270) */
175527088Sminshall 		break;
175632377Sminshall 
175744360Sborman 	    case NOP:
175844360Sborman 	    case GA:
175927088Sminshall 	    default:
176046808Sdab 		printoption("RCVD", IAC, c);
176127088Sminshall 		break;
176227088Sminshall 	    }
176332377Sminshall 	    telrcv_state = TS_DATA;
176432377Sminshall 	    continue;
176527088Sminshall 
176632377Sminshall 	case TS_WILL:
176746808Sdab 	    printoption("RCVD", WILL, c);
176838689Sborman 	    willoption(c);
176932377Sminshall 	    SetIn3270();
177032377Sminshall 	    telrcv_state = TS_DATA;
177132377Sminshall 	    continue;
177227110Sminshall 
177332377Sminshall 	case TS_WONT:
177446808Sdab 	    printoption("RCVD", WONT, c);
177538689Sborman 	    wontoption(c);
177632377Sminshall 	    SetIn3270();
177732377Sminshall 	    telrcv_state = TS_DATA;
177832377Sminshall 	    continue;
177927088Sminshall 
178032377Sminshall 	case TS_DO:
178146808Sdab 	    printoption("RCVD", DO, c);
178237226Sminshall 	    dooption(c);
178332377Sminshall 	    SetIn3270();
178437219Sminshall 	    if (c == TELOPT_NAWS) {
178537219Sminshall 		sendnaws();
178637219Sminshall 	    } else if (c == TELOPT_LFLOW) {
178737219Sminshall 		localflow = 1;
178837219Sminshall 		setcommandmode();
178938689Sborman 		setconnmode(0);
179037219Sminshall 	    }
179132377Sminshall 	    telrcv_state = TS_DATA;
179232377Sminshall 	    continue;
179327088Sminshall 
179432377Sminshall 	case TS_DONT:
179546808Sdab 	    printoption("RCVD", DONT, c);
179638689Sborman 	    dontoption(c);
179737226Sminshall 	    flushline = 1;
179838689Sborman 	    setconnmode(0);	/* set new tty mode (maybe) */
179932377Sminshall 	    SetIn3270();
180032377Sminshall 	    telrcv_state = TS_DATA;
180132377Sminshall 	    continue;
180227088Sminshall 
180332377Sminshall 	case TS_SB:
180432377Sminshall 	    if (c == IAC) {
180532377Sminshall 		telrcv_state = TS_SE;
180632377Sminshall 	    } else {
180732377Sminshall 		SB_ACCUM(c);
180832377Sminshall 	    }
180932377Sminshall 	    continue;
181027088Sminshall 
181132377Sminshall 	case TS_SE:
181232377Sminshall 	    if (c != SE) {
181332377Sminshall 		if (c != IAC) {
181438689Sborman 		    /*
181538689Sborman 		     * This is an error.  We only expect to get
181638689Sborman 		     * "IAC IAC" or "IAC SE".  Several things may
181738689Sborman 		     * have happend.  An IAC was not doubled, the
181838689Sborman 		     * IAC SE was left off, or another option got
181938689Sborman 		     * inserted into the suboption are all possibilities.
182038689Sborman 		     * If we assume that the IAC was not doubled,
182138689Sborman 		     * and really the IAC SE was left off, we could
182238689Sborman 		     * get into an infinate loop here.  So, instead,
182338689Sborman 		     * we terminate the suboption, and process the
182438689Sborman 		     * partial suboption if we can.
182538689Sborman 		     */
182632377Sminshall 		    SB_ACCUM(IAC);
182738689Sborman 		    SB_ACCUM(c);
182846808Sdab 		    subpointer -= 2;
182946808Sdab 		    SB_TERM();
183046808Sdab 
183146808Sdab 		    printoption("In SUBOPTION processing, RCVD", IAC, c);
183238689Sborman 		    suboption();	/* handle sub-option */
183338689Sborman 		    SetIn3270();
183438689Sborman 		    telrcv_state = TS_IAC;
183538689Sborman 		    goto process_iac;
183632377Sminshall 		}
183732377Sminshall 		SB_ACCUM(c);
183832377Sminshall 		telrcv_state = TS_SB;
183932377Sminshall 	    } else {
184038689Sborman 		SB_ACCUM(IAC);
184138689Sborman 		SB_ACCUM(SE);
184246808Sdab 		subpointer -= 2;
184346808Sdab 		SB_TERM();
184432377Sminshall 		suboption();	/* handle sub-option */
184532377Sminshall 		SetIn3270();
184632377Sminshall 		telrcv_state = TS_DATA;
184732377Sminshall 	    }
184827088Sminshall 	}
184927088Sminshall     }
185032667Sminshall     if (count)
185132667Sminshall 	ring_consumed(&netiring, count);
185232385Sminshall     return returnValue||count;
185327088Sminshall }
185432385Sminshall 
185546808Sdab static int bol = 1, local = 0;
185646808Sdab 
185746808Sdab     int
185846808Sdab rlogin_susp()
185946808Sdab {
186046808Sdab     if (local) {
186146808Sdab 	local = 0;
186246808Sdab 	bol = 1;
186346808Sdab 	command(0, "z\n", 2);
186446808Sdab 	return(1);
186546808Sdab     }
186646808Sdab     return(0);
186746808Sdab }
186846808Sdab 
186946808Sdab     static int
187032554Sminshall telsnd()
187132385Sminshall {
187232385Sminshall     int tcc;
187332385Sminshall     int count;
187432385Sminshall     int returnValue = 0;
187546808Sdab     unsigned char *tbp;
187632385Sminshall 
187732385Sminshall     tcc = 0;
187832385Sminshall     count = 0;
187932385Sminshall     while (NETROOM() > 2) {
188032385Sminshall 	register int sc;
188132385Sminshall 	register int c;
188232385Sminshall 
188332385Sminshall 	if (tcc == 0) {
188432385Sminshall 	    if (count) {
188532528Sminshall 		ring_consumed(&ttyiring, count);
188632385Sminshall 		returnValue = 1;
188732385Sminshall 		count = 0;
188832385Sminshall 	    }
188932528Sminshall 	    tbp = ttyiring.consume;
189032528Sminshall 	    tcc = ring_full_consecutive(&ttyiring);
189132385Sminshall 	    if (tcc == 0) {
189232385Sminshall 		break;
189332385Sminshall 	    }
189432385Sminshall 	}
189532385Sminshall 	c = *tbp++ & 0xff, sc = strip(c), tcc--; count++;
189646808Sdab 	if (rlogin != _POSIX_VDISABLE) {
189746808Sdab 		if (bol) {
189846808Sdab 			bol = 0;
189946808Sdab 			if (sc == rlogin) {
190046808Sdab 				local = 1;
190146808Sdab 				continue;
190246808Sdab 			}
190346808Sdab 		} else if (local) {
190446808Sdab 			local = 0;
190546808Sdab 			if (sc == '.' || c == termEofChar) {
190646808Sdab 				bol = 1;
190746808Sdab 				command(0, "close\n", 6);
190846808Sdab 				continue;
190946808Sdab 			}
191046808Sdab 			if (sc == termSuspChar) {
191146808Sdab 				bol = 1;
191246808Sdab 				command(0, "z\n", 2);
191346808Sdab 				continue;
191446808Sdab 			}
191546808Sdab 			if (sc == escape) {
191646808Sdab 				command(0, (char *)tbp, tcc);
191746808Sdab 				bol = 1;
191846808Sdab 				count += tcc;
191946808Sdab 				tcc = 0;
192046808Sdab 				flushline = 1;
192146808Sdab 				break;
192246808Sdab 			}
192346808Sdab 			if (sc != rlogin) {
192446808Sdab 				++tcc;
192546808Sdab 				--tbp;
192646808Sdab 				--count;
192746808Sdab 				c = sc = rlogin;
192846808Sdab 			}
192946808Sdab 		}
193046808Sdab 		if ((sc == '\n') || (sc == '\r'))
193146808Sdab 			bol = 1;
193246808Sdab 	} else if (sc == escape) {
193338689Sborman 	    /*
193438689Sborman 	     * Double escape is a pass through of a single escape character.
193538689Sborman 	     */
193638689Sborman 	    if (tcc && strip(*tbp) == escape) {
193738689Sborman 		tbp++;
193838689Sborman 		tcc--;
193938689Sborman 		count++;
194046808Sdab 		bol = 0;
194138689Sborman 	    } else {
194246808Sdab 		command(0, (char *)tbp, tcc);
194346808Sdab 		bol = 1;
194438689Sborman 		count += tcc;
194538689Sborman 		tcc = 0;
194638689Sborman 		flushline = 1;
194738689Sborman 		break;
194838689Sborman 	    }
194946808Sdab 	} else
195046808Sdab 	    bol = 0;
195138689Sborman #ifdef	KLUDGELINEMODE
195238689Sborman 	if (kludgelinemode && (globalmode&MODE_EDIT) && (sc == echoc)) {
195332385Sminshall 	    if (tcc > 0 && strip(*tbp) == echoc) {
195432385Sminshall 		tcc--; tbp++; count++;
195532385Sminshall 	    } else {
195632385Sminshall 		dontlecho = !dontlecho;
195732385Sminshall 		settimer(echotoggle);
195838689Sborman 		setconnmode(0);
195932385Sminshall 		flushline = 1;
196032385Sminshall 		break;
196132385Sminshall 	    }
196232385Sminshall 	}
196338689Sborman #endif
196438689Sborman 	if (MODE_LOCAL_CHARS(globalmode)) {
196532385Sminshall 	    if (TerminalSpecialChars(sc) == 0) {
196646808Sdab 		bol = 1;
196732385Sminshall 		break;
196832385Sminshall 	    }
196932385Sminshall 	}
197038689Sborman 	if (my_want_state_is_wont(TELOPT_BINARY)) {
197132385Sminshall 	    switch (c) {
197232385Sminshall 	    case '\n':
197332385Sminshall 		    /*
197432385Sminshall 		     * If we are in CRMOD mode (\r ==> \n)
197532385Sminshall 		     * on our local machine, then probably
197632385Sminshall 		     * a newline (unix) is CRLF (TELNET).
197732385Sminshall 		     */
197832385Sminshall 		if (MODE_LOCAL_CHARS(globalmode)) {
197932385Sminshall 		    NETADD('\r');
198032385Sminshall 		}
198132385Sminshall 		NETADD('\n');
198246808Sdab 		bol = flushline = 1;
198332385Sminshall 		break;
198432385Sminshall 	    case '\r':
198532385Sminshall 		if (!crlf) {
198632385Sminshall 		    NET2ADD('\r', '\0');
198732385Sminshall 		} else {
198832385Sminshall 		    NET2ADD('\r', '\n');
198932385Sminshall 		}
199046808Sdab 		bol = flushline = 1;
199132385Sminshall 		break;
199232385Sminshall 	    case IAC:
199332385Sminshall 		NET2ADD(IAC, IAC);
199432385Sminshall 		break;
199532385Sminshall 	    default:
199632385Sminshall 		NETADD(c);
199732385Sminshall 		break;
199832385Sminshall 	    }
199932385Sminshall 	} else if (c == IAC) {
200032385Sminshall 	    NET2ADD(IAC, IAC);
200132385Sminshall 	} else {
200232385Sminshall 	    NETADD(c);
200332385Sminshall 	}
200432385Sminshall     }
200532667Sminshall     if (count)
200632667Sminshall 	ring_consumed(&ttyiring, count);
200732385Sminshall     return returnValue||count;		/* Non-zero if we did anything */
200832385Sminshall }
200932377Sminshall 
201027088Sminshall /*
201132377Sminshall  * Scheduler()
201232377Sminshall  *
201332377Sminshall  * Try to do something.
201432377Sminshall  *
201532377Sminshall  * If we do something useful, return 1; else return 0.
201632377Sminshall  *
201727110Sminshall  */
201827110Sminshall 
201927110Sminshall 
202046808Sdab     int
202132377Sminshall Scheduler(block)
202246808Sdab     int	block;			/* should we block in the select ? */
202327110Sminshall {
202432377Sminshall 		/* One wants to be a bit careful about setting returnValue
202532377Sminshall 		 * to one, since a one implies we did some useful work,
202632377Sminshall 		 * and therefore probably won't be called to block next
202732377Sminshall 		 * time (TN3270 mode only).
202832377Sminshall 		 */
202932531Sminshall     int returnValue;
203032531Sminshall     int netin, netout, netex, ttyin, ttyout;
203127110Sminshall 
203232531Sminshall     /* Decide which rings should be processed */
203332531Sminshall 
203432531Sminshall     netout = ring_full_count(&netoring) &&
203538689Sborman 	    (flushline ||
203638689Sborman 		(my_want_state_is_wont(TELOPT_LINEMODE)
203738689Sborman #ifdef	KLUDGELINEMODE
203838689Sborman 			&& (!kludgelinemode || my_want_state_is_do(TELOPT_SGA))
203938689Sborman #endif
204038689Sborman 		) ||
204138689Sborman 			my_want_state_is_will(TELOPT_BINARY));
204232531Sminshall     ttyout = ring_full_count(&ttyoring);
204332531Sminshall 
204432377Sminshall #if	defined(TN3270)
204532531Sminshall     ttyin = ring_empty_count(&ttyiring) && (shell_active == 0);
204632377Sminshall #else	/* defined(TN3270) */
204732531Sminshall     ttyin = ring_empty_count(&ttyiring);
204832377Sminshall #endif	/* defined(TN3270) */
204932531Sminshall 
205032531Sminshall #if	defined(TN3270)
205132531Sminshall     netin = ring_empty_count(&netiring);
205232377Sminshall #   else /* !defined(TN3270) */
205332531Sminshall     netin = !ISend && ring_empty_count(&netiring);
205432377Sminshall #   endif /* !defined(TN3270) */
205532531Sminshall 
205632531Sminshall     netex = !SYNCHing;
205732531Sminshall 
205832531Sminshall     /* If we have seen a signal recently, reset things */
205932377Sminshall #   if defined(TN3270) && defined(unix)
206032377Sminshall     if (HaveInput) {
206132377Sminshall 	HaveInput = 0;
206244360Sborman 	(void) signal(SIGIO, inputAvailable);
206332377Sminshall     }
206432377Sminshall #endif	/* defined(TN3270) && defined(unix) */
206532377Sminshall 
206632531Sminshall     /* Call to system code to process rings */
206727178Sminshall 
206832531Sminshall     returnValue = process_rings(netin, netout, netex, ttyin, ttyout, !block);
206927178Sminshall 
207032531Sminshall     /* Now, look at the input rings, looking for work to do. */
207132377Sminshall 
207232531Sminshall     if (ring_full_count(&ttyiring)) {
207332377Sminshall #   if defined(TN3270)
207432377Sminshall 	if (In3270) {
207534848Sminshall 	    int c;
207634848Sminshall 
207733804Sminshall 	    c = DataFromTerminal(ttyiring.consume,
207832528Sminshall 					ring_full_consecutive(&ttyiring));
207932377Sminshall 	    if (c) {
208032377Sminshall 		returnValue = 1;
208132667Sminshall 	        ring_consumed(&ttyiring, c);
208232377Sminshall 	    }
208332377Sminshall 	} else {
208432377Sminshall #   endif /* defined(TN3270) */
208532554Sminshall 	    returnValue |= telsnd();
208632377Sminshall #   if defined(TN3270)
208727178Sminshall 	}
208832531Sminshall #   endif /* defined(TN3270) */
208927178Sminshall     }
209032377Sminshall 
209132528Sminshall     if (ring_full_count(&netiring)) {
209232377Sminshall #	if !defined(TN3270)
209332385Sminshall 	returnValue |= telrcv();
209432377Sminshall #	else /* !defined(TN3270) */
209532377Sminshall 	returnValue = Push3270();
209632377Sminshall #	endif /* !defined(TN3270) */
209732377Sminshall     }
209832377Sminshall     return returnValue;
209927178Sminshall }
210027178Sminshall 
210127178Sminshall /*
210232377Sminshall  * Select from tty and network...
210327088Sminshall  */
210446808Sdab     void
210546808Sdab telnet(user)
210646808Sdab     char *user;
210727088Sminshall {
210832531Sminshall     sys_telnet_init();
210927088Sminshall 
211046808Sdab #if defined(ENCRYPT) || defined(AUTHENTICATE)
211146808Sdab     {
211246808Sdab 	static char local_host[256] = { 0 };
211346808Sdab 	int len = sizeof(local_host);
211446808Sdab 
211546808Sdab 	if (!local_host[0]) {
211646808Sdab 		gethostname(local_host, &len);
211746808Sdab 		local_host[sizeof(local_host)-1] = 0;
211846808Sdab 	}
211946808Sdab 	auth_encrypt_init(local_host, hostname, "TELNET", 0);
212046808Sdab 	auth_encrypt_user(user);
212146808Sdab     }
212246808Sdab #endif
212332377Sminshall #   if !defined(TN3270)
212432377Sminshall     if (telnetport) {
212546808Sdab #if	defined(AUTHENTICATE)
212646808Sdab 	if (autologin)
212746808Sdab 		send_will(TELOPT_AUTHENTICATION, 1);
212846808Sdab #endif
212946808Sdab #if	defined(ENCRYPT)
213046808Sdab 	send_do(TELOPT_ENCRYPT, 1);
213146808Sdab 	send_will(TELOPT_ENCRYPT, 1);
213246808Sdab #endif
213338689Sborman 	send_do(TELOPT_SGA, 1);
213438689Sborman 	send_will(TELOPT_TTYPE, 1);
213538689Sborman 	send_will(TELOPT_NAWS, 1);
213638689Sborman 	send_will(TELOPT_TSPEED, 1);
213738689Sborman 	send_will(TELOPT_LFLOW, 1);
213838689Sborman 	send_will(TELOPT_LINEMODE, 1);
213946808Sdab 	send_will(TELOPT_ENVIRON, 1);
214038908Sborman 	send_do(TELOPT_STATUS, 1);
214146808Sdab 	if (env_getvalue((unsigned char *)"DISPLAY"))
214244360Sborman 	    send_will(TELOPT_XDISPLOC, 1);
214346808Sdab 	if (eight)
214446808Sdab 	    tel_enter_binary(eight);
214527178Sminshall     }
214632377Sminshall #   endif /* !defined(TN3270) */
214727088Sminshall 
214832377Sminshall #   if !defined(TN3270)
214932377Sminshall     for (;;) {
215032385Sminshall 	int schedValue;
215132385Sminshall 
215232385Sminshall 	while ((schedValue = Scheduler(0)) != 0) {
215332385Sminshall 	    if (schedValue == -1) {
215432385Sminshall 		setcommandmode();
215532385Sminshall 		return;
215632385Sminshall 	    }
215732385Sminshall 	}
215832385Sminshall 
215932531Sminshall 	if (Scheduler(1) == -1) {
216032377Sminshall 	    setcommandmode();
216132377Sminshall 	    return;
216232377Sminshall 	}
216332377Sminshall     }
216432377Sminshall #   else /* !defined(TN3270) */
216532377Sminshall     for (;;) {
216632377Sminshall 	int schedValue;
216727088Sminshall 
216832377Sminshall 	while (!In3270 && !shell_active) {
216932531Sminshall 	    if (Scheduler(1) == -1) {
217032377Sminshall 		setcommandmode();
217132377Sminshall 		return;
217232377Sminshall 	    }
217327088Sminshall 	}
217432377Sminshall 
217532377Sminshall 	while ((schedValue = Scheduler(0)) != 0) {
217632377Sminshall 	    if (schedValue == -1) {
217732377Sminshall 		setcommandmode();
217832377Sminshall 		return;
217932377Sminshall 	    }
218027088Sminshall 	}
218132377Sminshall 		/* If there is data waiting to go out to terminal, don't
218232377Sminshall 		 * schedule any more data for the terminal.
218332377Sminshall 		 */
218434304Sminshall 	if (ring_full_count(&ttyoring)) {
218532377Sminshall 	    schedValue = 1;
218627088Sminshall 	} else {
218732377Sminshall 	    if (shell_active) {
218832377Sminshall 		if (shell_continue() == 0) {
218932377Sminshall 		    ConnectScreen();
219027088Sminshall 		}
219132377Sminshall 	    } else if (In3270) {
219232377Sminshall 		schedValue = DoTerminalOutput();
219332377Sminshall 	    }
219427088Sminshall 	}
219532377Sminshall 	if (schedValue && (shell_active == 0)) {
219632531Sminshall 	    if (Scheduler(1) == -1) {
219732377Sminshall 		setcommandmode();
219832377Sminshall 		return;
219932377Sminshall 	    }
220027088Sminshall 	}
220132377Sminshall     }
220232377Sminshall #   endif /* !defined(TN3270) */
220327088Sminshall }
220432377Sminshall 
220534848Sminshall #if	0	/* XXX - this not being in is a bug */
220627088Sminshall /*
220732554Sminshall  * nextitem()
220832554Sminshall  *
220932554Sminshall  *	Return the address of the next "item" in the TELNET data
221032554Sminshall  * stream.  This will be the address of the next character if
221132554Sminshall  * the current address is a user data character, or it will
221232554Sminshall  * be the address of the character following the TELNET command
221332554Sminshall  * if the current address is a TELNET IAC ("I Am a Command")
221432554Sminshall  * character.
221532554Sminshall  */
221632554Sminshall 
221746808Sdab     static char *
221832554Sminshall nextitem(current)
221946808Sdab     char *current;
222032554Sminshall {
222132554Sminshall     if ((*current&0xff) != IAC) {
222232554Sminshall 	return current+1;
222332554Sminshall     }
222432554Sminshall     switch (*(current+1)&0xff) {
222532554Sminshall     case DO:
222632554Sminshall     case DONT:
222732554Sminshall     case WILL:
222832554Sminshall     case WONT:
222932554Sminshall 	return current+3;
223032554Sminshall     case SB:		/* loop forever looking for the SE */
223132554Sminshall 	{
223232554Sminshall 	    register char *look = current+2;
223332554Sminshall 
223432554Sminshall 	    for (;;) {
223532554Sminshall 		if ((*look++&0xff) == IAC) {
223632554Sminshall 		    if ((*look++&0xff) == SE) {
223732554Sminshall 			return look;
223832554Sminshall 		    }
223932554Sminshall 		}
224032554Sminshall 	    }
224132554Sminshall 	}
224232554Sminshall     default:
224332554Sminshall 	return current+2;
224432554Sminshall     }
224532554Sminshall }
224634848Sminshall #endif	/* 0 */
224732554Sminshall 
224832554Sminshall /*
224932554Sminshall  * netclear()
225032554Sminshall  *
225132554Sminshall  *	We are about to do a TELNET SYNCH operation.  Clear
225232554Sminshall  * the path to the network.
225332554Sminshall  *
225432554Sminshall  *	Things are a bit tricky since we may have sent the first
225532554Sminshall  * byte or so of a previous TELNET command into the network.
225632554Sminshall  * So, we have to scan the network buffer from the beginning
225732554Sminshall  * until we are up to where we want to be.
225832554Sminshall  *
225932554Sminshall  *	A side effect of what we do, just to keep things
226032554Sminshall  * simple, is to clear the urgent data pointer.  The principal
226132554Sminshall  * caller should be setting the urgent data pointer AFTER calling
226232554Sminshall  * us in any case.
226332554Sminshall  */
226432554Sminshall 
226546808Sdab     static void
226632554Sminshall netclear()
226732554Sminshall {
226832554Sminshall #if	0	/* XXX */
226932554Sminshall     register char *thisitem, *next;
227032554Sminshall     char *good;
227132554Sminshall #define	wewant(p)	((nfrontp > p) && ((*p&0xff) == IAC) && \
227232554Sminshall 				((*(p+1)&0xff) != EC) && ((*(p+1)&0xff) != EL))
227332554Sminshall 
227432554Sminshall     thisitem = netobuf;
227532554Sminshall 
227632554Sminshall     while ((next = nextitem(thisitem)) <= netobuf.send) {
227732554Sminshall 	thisitem = next;
227832554Sminshall     }
227932554Sminshall 
228032554Sminshall     /* Now, thisitem is first before/at boundary. */
228132554Sminshall 
228232554Sminshall     good = netobuf;	/* where the good bytes go */
228332554Sminshall 
228432554Sminshall     while (netoring.add > thisitem) {
228532554Sminshall 	if (wewant(thisitem)) {
228632554Sminshall 	    int length;
228732554Sminshall 
228832554Sminshall 	    next = thisitem;
228932554Sminshall 	    do {
229032554Sminshall 		next = nextitem(next);
229132554Sminshall 	    } while (wewant(next) && (nfrontp > next));
229232554Sminshall 	    length = next-thisitem;
229332554Sminshall 	    memcpy(good, thisitem, length);
229432554Sminshall 	    good += length;
229532554Sminshall 	    thisitem = next;
229632554Sminshall 	} else {
229732554Sminshall 	    thisitem = nextitem(thisitem);
229832554Sminshall 	}
229932554Sminshall     }
230032554Sminshall 
230132554Sminshall #endif	/* 0 */
230232554Sminshall }
230332554Sminshall 
230432554Sminshall /*
230532377Sminshall  * These routines add various telnet commands to the data stream.
230627088Sminshall  */
230732377Sminshall 
230846808Sdab     static void
230932554Sminshall doflush()
231032554Sminshall {
231132554Sminshall     NET2ADD(IAC, DO);
231232554Sminshall     NETADD(TELOPT_TM);
231332554Sminshall     flushline = 1;
231432554Sminshall     flushout = 1;
231544360Sborman     (void) ttyflush(1);			/* Flush/drop output */
231632554Sminshall     /* do printoption AFTER flush, otherwise the output gets tossed... */
231746808Sdab     printoption("SENT", DO, TELOPT_TM);
231832554Sminshall }
231932554Sminshall 
232046808Sdab     void
232132377Sminshall xmitAO()
232227088Sminshall {
232332377Sminshall     NET2ADD(IAC, AO);
232446808Sdab     printoption("SENT", IAC, AO);
232532377Sminshall     if (autoflush) {
232632377Sminshall 	doflush();
232732377Sminshall     }
232832377Sminshall }
232927088Sminshall 
233032377Sminshall 
233146808Sdab     void
233232377Sminshall xmitEL()
233327088Sminshall {
233432377Sminshall     NET2ADD(IAC, EL);
233546808Sdab     printoption("SENT", IAC, EL);
233627088Sminshall }
233727088Sminshall 
233846808Sdab     void
233932377Sminshall xmitEC()
234027088Sminshall {
234132377Sminshall     NET2ADD(IAC, EC);
234246808Sdab     printoption("SENT", IAC, EC);
234327088Sminshall }
234427088Sminshall 
234532377Sminshall 
234646808Sdab     int
234732377Sminshall dosynch()
234827088Sminshall {
234932377Sminshall     netclear();			/* clear the path to the network */
235033294Sminshall     NETADD(IAC);
235133294Sminshall     setneturg();
235233294Sminshall     NETADD(DM);
235346808Sdab     printoption("SENT", IAC, DM);
235446808Sdab     return 1;
235527088Sminshall }
235627088Sminshall 
235746808Sdab int want_status_response = 0;
235846808Sdab 
235946808Sdab     int
236038908Sborman get_status()
236138908Sborman {
236246808Sdab     unsigned char tmp[16];
236346808Sdab     register unsigned char *cp;
236438908Sborman 
236538908Sborman     if (my_want_state_is_dont(TELOPT_STATUS)) {
236638908Sborman 	printf("Remote side does not support STATUS option\n");
236746808Sdab 	return 0;
236838908Sborman     }
236938908Sborman     cp = tmp;
237038908Sborman 
237138908Sborman     *cp++ = IAC;
237238908Sborman     *cp++ = SB;
237338908Sborman     *cp++ = TELOPT_STATUS;
237438908Sborman     *cp++ = TELQUAL_SEND;
237538908Sborman     *cp++ = IAC;
237638908Sborman     *cp++ = SE;
237738908Sborman     if (NETROOM() >= cp - tmp) {
237838908Sborman 	ring_supply_data(&netoring, tmp, cp-tmp);
237938908Sborman 	printsub('>', tmp+2, cp - tmp - 2);
238038908Sborman     }
238146808Sdab     ++want_status_response;
238246808Sdab     return 1;
238338908Sborman }
238438908Sborman 
238546808Sdab     void
238632377Sminshall intp()
238727088Sminshall {
238832377Sminshall     NET2ADD(IAC, IP);
238946808Sdab     printoption("SENT", IAC, IP);
239032377Sminshall     flushline = 1;
239132377Sminshall     if (autoflush) {
239232377Sminshall 	doflush();
239332377Sminshall     }
239432377Sminshall     if (autosynch) {
239532377Sminshall 	dosynch();
239632377Sminshall     }
239727088Sminshall }
239827186Sminshall 
239946808Sdab     void
240032377Sminshall sendbrk()
240127186Sminshall {
240232377Sminshall     NET2ADD(IAC, BREAK);
240346808Sdab     printoption("SENT", IAC, BREAK);
240432377Sminshall     flushline = 1;
240532377Sminshall     if (autoflush) {
240632377Sminshall 	doflush();
240732377Sminshall     }
240832377Sminshall     if (autosynch) {
240932377Sminshall 	dosynch();
241032377Sminshall     }
241127186Sminshall }
241238689Sborman 
241346808Sdab     void
241438689Sborman sendabort()
241538689Sborman {
241638689Sborman     NET2ADD(IAC, ABORT);
241746808Sdab     printoption("SENT", IAC, ABORT);
241838689Sborman     flushline = 1;
241938689Sborman     if (autoflush) {
242038689Sborman 	doflush();
242138689Sborman     }
242238689Sborman     if (autosynch) {
242338689Sborman 	dosynch();
242438689Sborman     }
242538689Sborman }
242638689Sborman 
242746808Sdab     void
242838689Sborman sendsusp()
242938689Sborman {
243038689Sborman     NET2ADD(IAC, SUSP);
243146808Sdab     printoption("SENT", IAC, SUSP);
243238689Sborman     flushline = 1;
243338689Sborman     if (autoflush) {
243438689Sborman 	doflush();
243538689Sborman     }
243638689Sborman     if (autosynch) {
243738689Sborman 	dosynch();
243838689Sborman     }
243938689Sborman }
244038689Sborman 
244146808Sdab     void
244238689Sborman sendeof()
244338689Sborman {
244438908Sborman     NET2ADD(IAC, xEOF);
244546808Sdab     printoption("SENT", IAC, xEOF);
244638689Sborman }
244738689Sborman 
244846808Sdab     void
244945232Sborman sendayt()
245045232Sborman {
245145232Sborman     NET2ADD(IAC, AYT);
245246808Sdab     printoption("SENT", IAC, AYT);
245345232Sborman }
245445232Sborman 
245537219Sminshall /*
245637219Sminshall  * Send a window size update to the remote system.
245737219Sminshall  */
245837219Sminshall 
245946808Sdab     void
246037219Sminshall sendnaws()
246137219Sminshall {
246237219Sminshall     long rows, cols;
246338689Sborman     unsigned char tmp[16];
246438689Sborman     register unsigned char *cp;
246537219Sminshall 
246638689Sborman     if (my_state_is_wont(TELOPT_NAWS))
246738689Sborman 	return;
246837219Sminshall 
246938689Sborman #define	PUTSHORT(cp, x) { if ((*cp++ = ((x)>>8)&0xff) == IAC) *cp++ = IAC; \
247038689Sborman 			    if ((*cp++ = ((x))&0xff) == IAC) *cp++ = IAC; }
247138689Sborman 
247237219Sminshall     if (TerminalWindowSize(&rows, &cols) == 0) {	/* Failed */
247337219Sminshall 	return;
247437219Sminshall     }
247537219Sminshall 
247638689Sborman     cp = tmp;
247738689Sborman 
247838689Sborman     *cp++ = IAC;
247938689Sborman     *cp++ = SB;
248038689Sborman     *cp++ = TELOPT_NAWS;
248138689Sborman     PUTSHORT(cp, cols);
248238689Sborman     PUTSHORT(cp, rows);
248338689Sborman     *cp++ = IAC;
248438689Sborman     *cp++ = SE;
248538689Sborman     if (NETROOM() >= cp - tmp) {
248638689Sborman 	ring_supply_data(&netoring, tmp, cp-tmp);
248738689Sborman 	printsub('>', tmp+2, cp - tmp - 2);
248837219Sminshall     }
248937219Sminshall }
249037226Sminshall 
249146808Sdab     void
249238908Sborman tel_enter_binary(rw)
249346808Sdab     int rw;
249437226Sminshall {
249538908Sborman     if (rw&1)
249638908Sborman 	send_do(TELOPT_BINARY, 1);
249738908Sborman     if (rw&2)
249838908Sborman 	send_will(TELOPT_BINARY, 1);
249937226Sminshall }
250037226Sminshall 
250146808Sdab     void
250238908Sborman tel_leave_binary(rw)
250346808Sdab     int rw;
250437226Sminshall {
250538908Sborman     if (rw&1)
250638908Sborman 	send_dont(TELOPT_BINARY, 1);
250738908Sborman     if (rw&2)
250838908Sborman 	send_wont(TELOPT_BINARY, 1);
250937226Sminshall }
2510