113e3f4d6SMark Murray /*
213e3f4d6SMark Murray  * Copyright (c) 1988, 1990, 1993
313e3f4d6SMark Murray  *	The Regents of the University of California.  All rights reserved.
413e3f4d6SMark Murray  *
513e3f4d6SMark Murray  * Redistribution and use in source and binary forms, with or without
613e3f4d6SMark Murray  * modification, are permitted provided that the following conditions
713e3f4d6SMark Murray  * are met:
813e3f4d6SMark Murray  * 1. Redistributions of source code must retain the above copyright
913e3f4d6SMark Murray  *    notice, this list of conditions and the following disclaimer.
1013e3f4d6SMark Murray  * 2. Redistributions in binary form must reproduce the above copyright
1113e3f4d6SMark Murray  *    notice, this list of conditions and the following disclaimer in the
1213e3f4d6SMark Murray  *    documentation and/or other materials provided with the distribution.
1313e3f4d6SMark Murray  * 3. All advertising materials mentioning features or use of this software
1413e3f4d6SMark Murray  *    must display the following acknowledgement:
1513e3f4d6SMark Murray  *	This product includes software developed by the University of
1613e3f4d6SMark Murray  *	California, Berkeley and its contributors.
1713e3f4d6SMark Murray  * 4. Neither the name of the University nor the names of its contributors
1813e3f4d6SMark Murray  *    may be used to endorse or promote products derived from this software
1913e3f4d6SMark Murray  *    without specific prior written permission.
2013e3f4d6SMark Murray  *
2113e3f4d6SMark Murray  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
2213e3f4d6SMark Murray  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
2313e3f4d6SMark Murray  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
2413e3f4d6SMark Murray  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
2513e3f4d6SMark Murray  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2613e3f4d6SMark Murray  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2713e3f4d6SMark Murray  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2813e3f4d6SMark Murray  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2913e3f4d6SMark Murray  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
3013e3f4d6SMark Murray  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
3113e3f4d6SMark Murray  * SUCH DAMAGE.
3213e3f4d6SMark Murray  */
3313e3f4d6SMark Murray 
3413e3f4d6SMark Murray #include "telnet_locl.h"
3513e3f4d6SMark Murray 
36c19800e8SDoug Rabson RCSID("$Id$");
3713e3f4d6SMark Murray 
3813e3f4d6SMark Murray #define	strip(x) (eight ? (x) : ((x) & 0x7f))
3913e3f4d6SMark Murray 
4013e3f4d6SMark Murray static unsigned char	subbuffer[SUBBUFSIZE],
4113e3f4d6SMark Murray 			*subpointer, *subend;	 /* buffer for sub-options */
4213e3f4d6SMark Murray #define	SB_CLEAR()	subpointer = subbuffer;
4313e3f4d6SMark Murray #define	SB_TERM()	{ subend = subpointer; SB_CLEAR(); }
4413e3f4d6SMark Murray #define	SB_ACCUM(c)	if (subpointer < (subbuffer+sizeof subbuffer)) { \
4513e3f4d6SMark Murray 				*subpointer++ = (c); \
4613e3f4d6SMark Murray 			}
4713e3f4d6SMark Murray 
4813e3f4d6SMark Murray #define	SB_GET()	((*subpointer++)&0xff)
4913e3f4d6SMark Murray #define	SB_PEEK()	((*subpointer)&0xff)
5013e3f4d6SMark Murray #define	SB_EOF()	(subpointer >= subend)
5113e3f4d6SMark Murray #define	SB_LEN()	(subend - subpointer)
5213e3f4d6SMark Murray 
5313e3f4d6SMark Murray char	options[256];		/* The combined options */
5413e3f4d6SMark Murray char	do_dont_resp[256];
5513e3f4d6SMark Murray char	will_wont_resp[256];
5613e3f4d6SMark Murray 
5713e3f4d6SMark Murray int
5813e3f4d6SMark Murray 	eight = 3,
5913e3f4d6SMark Murray 	binary = 0,
6013e3f4d6SMark Murray 	autologin = 0,	/* Autologin anyone? */
6113e3f4d6SMark Murray 	skiprc = 0,
6213e3f4d6SMark Murray 	connected,
6313e3f4d6SMark Murray 	showoptions,
6413e3f4d6SMark Murray 	ISend,		/* trying to send network data in */
6513e3f4d6SMark Murray 	debug = 0,
6613e3f4d6SMark Murray 	crmod,
6713e3f4d6SMark Murray 	netdata,	/* Print out network data flow */
6813e3f4d6SMark Murray 	crlf,		/* Should '\r' be mapped to <CR><LF> (or <CR><NUL>)? */
6913e3f4d6SMark Murray 	telnetport,
704137ff4cSJacques Vidrine         wantencryption = 0,
7113e3f4d6SMark Murray 	SYNCHing,	/* we are in TELNET SYNCH mode */
7213e3f4d6SMark Murray 	flushout,	/* flush output */
7313e3f4d6SMark Murray 	autoflush = 0,	/* flush output when interrupting? */
7413e3f4d6SMark Murray 	autosynch,	/* send interrupt characters with SYNCH? */
7513e3f4d6SMark Murray 	localflow,	/* we handle flow control locally */
7613e3f4d6SMark Murray 	restartany,	/* if flow control enabled, restart on any character */
7713e3f4d6SMark Murray 	localchars,	/* we recognize interrupt/quit */
7813e3f4d6SMark Murray 	donelclchars,	/* the user has set "localchars" */
7913e3f4d6SMark Murray 	donebinarytoggle,	/* the user has put us in binary */
8013e3f4d6SMark Murray 	dontlecho,	/* do we suppress local echoing right now? */
8113e3f4d6SMark Murray 	globalmode;
8213e3f4d6SMark Murray 
8313e3f4d6SMark Murray char *prompt = 0;
8413e3f4d6SMark Murray 
854137ff4cSJacques Vidrine int scheduler_lockout_tty = 0;
864137ff4cSJacques Vidrine 
8713e3f4d6SMark Murray cc_t escape;
8813e3f4d6SMark Murray cc_t rlogin;
8913e3f4d6SMark Murray #ifdef	KLUDGELINEMODE
9013e3f4d6SMark Murray cc_t echoc;
9113e3f4d6SMark Murray #endif
9213e3f4d6SMark Murray 
9313e3f4d6SMark Murray /*
9413e3f4d6SMark Murray  * Telnet receiver states for fsm
9513e3f4d6SMark Murray  */
9613e3f4d6SMark Murray #define	TS_DATA		0
9713e3f4d6SMark Murray #define	TS_IAC		1
9813e3f4d6SMark Murray #define	TS_WILL		2
9913e3f4d6SMark Murray #define	TS_WONT		3
10013e3f4d6SMark Murray #define	TS_DO		4
10113e3f4d6SMark Murray #define	TS_DONT		5
10213e3f4d6SMark Murray #define	TS_CR		6
10313e3f4d6SMark Murray #define	TS_SB		7		/* sub-option collection */
10413e3f4d6SMark Murray #define	TS_SE		8		/* looking for sub-option end */
10513e3f4d6SMark Murray 
10613e3f4d6SMark Murray static int	telrcv_state;
10713e3f4d6SMark Murray #ifdef	OLD_ENVIRON
10813e3f4d6SMark Murray unsigned char telopt_environ = TELOPT_NEW_ENVIRON;
10913e3f4d6SMark Murray #else
11013e3f4d6SMark Murray # define telopt_environ TELOPT_NEW_ENVIRON
11113e3f4d6SMark Murray #endif
11213e3f4d6SMark Murray 
11313e3f4d6SMark Murray jmp_buf	toplevel;
11413e3f4d6SMark Murray jmp_buf	peerdied;
11513e3f4d6SMark Murray 
11613e3f4d6SMark Murray int	flushline;
11713e3f4d6SMark Murray int	linemode;
11813e3f4d6SMark Murray 
11913e3f4d6SMark Murray #ifdef	KLUDGELINEMODE
12013e3f4d6SMark Murray int	kludgelinemode = 1;
12113e3f4d6SMark Murray #endif
12213e3f4d6SMark Murray 
12313e3f4d6SMark Murray /*
12413e3f4d6SMark Murray  * The following are some clocks used to decide how to interpret
12513e3f4d6SMark Murray  * the relationship between various variables.
12613e3f4d6SMark Murray  */
12713e3f4d6SMark Murray 
12813e3f4d6SMark Murray Clocks clocks;
12913e3f4d6SMark Murray 
13013e3f4d6SMark Murray static int is_unique(char *name, char **as, char **ae);
13113e3f4d6SMark Murray 
13213e3f4d6SMark Murray 
13313e3f4d6SMark Murray /*
13413e3f4d6SMark Murray  * Initialize telnet environment.
13513e3f4d6SMark Murray  */
13613e3f4d6SMark Murray 
13713e3f4d6SMark Murray void
init_telnet(void)13813e3f4d6SMark Murray init_telnet(void)
13913e3f4d6SMark Murray {
14013e3f4d6SMark Murray     env_init();
14113e3f4d6SMark Murray 
14213e3f4d6SMark Murray     SB_CLEAR();
14313e3f4d6SMark Murray     memset(options, 0, sizeof options);
14413e3f4d6SMark Murray 
14513e3f4d6SMark Murray     connected = ISend = localflow = donebinarytoggle = 0;
14613e3f4d6SMark Murray #if	defined(AUTHENTICATION) || defined(ENCRYPTION)
14713e3f4d6SMark Murray     auth_encrypt_connect(connected);
14813e3f4d6SMark Murray #endif	/* defined(AUTHENTICATION) || defined(ENCRYPTION)  */
14913e3f4d6SMark Murray     restartany = -1;
15013e3f4d6SMark Murray 
15113e3f4d6SMark Murray     SYNCHing = 0;
15213e3f4d6SMark Murray 
15313e3f4d6SMark Murray     /* Don't change NetTrace */
15413e3f4d6SMark Murray 
15513e3f4d6SMark Murray     escape = CONTROL(']');
15613e3f4d6SMark Murray     rlogin = _POSIX_VDISABLE;
15713e3f4d6SMark Murray #ifdef	KLUDGELINEMODE
15813e3f4d6SMark Murray     echoc = CONTROL('E');
15913e3f4d6SMark Murray #endif
16013e3f4d6SMark Murray 
16113e3f4d6SMark Murray     flushline = 1;
16213e3f4d6SMark Murray     telrcv_state = TS_DATA;
16313e3f4d6SMark Murray }
16413e3f4d6SMark Murray 
16513e3f4d6SMark Murray 
16613e3f4d6SMark Murray /*
16713e3f4d6SMark Murray  * These routines are in charge of sending option negotiations
16813e3f4d6SMark Murray  * to the other side.
16913e3f4d6SMark Murray  *
17013e3f4d6SMark Murray  * The basic idea is that we send the negotiation if either side
17113e3f4d6SMark Murray  * is in disagreement as to what the current state should be.
17213e3f4d6SMark Murray  */
17313e3f4d6SMark Murray 
17413e3f4d6SMark Murray void
send_do(int c,int init)17513e3f4d6SMark Murray send_do(int c, int init)
17613e3f4d6SMark Murray {
17713e3f4d6SMark Murray     if (init) {
17813e3f4d6SMark Murray 	if (((do_dont_resp[c] == 0) && my_state_is_do(c)) ||
17913e3f4d6SMark Murray 				my_want_state_is_do(c))
18013e3f4d6SMark Murray 	    return;
18113e3f4d6SMark Murray 	set_my_want_state_do(c);
18213e3f4d6SMark Murray 	do_dont_resp[c]++;
18313e3f4d6SMark Murray     }
18413e3f4d6SMark Murray     NET2ADD(IAC, DO);
18513e3f4d6SMark Murray     NETADD(c);
18613e3f4d6SMark Murray     printoption("SENT", DO, c);
18713e3f4d6SMark Murray }
18813e3f4d6SMark Murray 
18913e3f4d6SMark Murray void
send_dont(int c,int init)19013e3f4d6SMark Murray send_dont(int c, int init)
19113e3f4d6SMark Murray {
19213e3f4d6SMark Murray     if (init) {
19313e3f4d6SMark Murray 	if (((do_dont_resp[c] == 0) && my_state_is_dont(c)) ||
19413e3f4d6SMark Murray 				my_want_state_is_dont(c))
19513e3f4d6SMark Murray 	    return;
19613e3f4d6SMark Murray 	set_my_want_state_dont(c);
19713e3f4d6SMark Murray 	do_dont_resp[c]++;
19813e3f4d6SMark Murray     }
19913e3f4d6SMark Murray     NET2ADD(IAC, DONT);
20013e3f4d6SMark Murray     NETADD(c);
20113e3f4d6SMark Murray     printoption("SENT", DONT, c);
20213e3f4d6SMark Murray }
20313e3f4d6SMark Murray 
20413e3f4d6SMark Murray void
send_will(int c,int init)20513e3f4d6SMark Murray send_will(int c, int init)
20613e3f4d6SMark Murray {
20713e3f4d6SMark Murray     if (init) {
20813e3f4d6SMark Murray 	if (((will_wont_resp[c] == 0) && my_state_is_will(c)) ||
20913e3f4d6SMark Murray 				my_want_state_is_will(c))
21013e3f4d6SMark Murray 	    return;
21113e3f4d6SMark Murray 	set_my_want_state_will(c);
21213e3f4d6SMark Murray 	will_wont_resp[c]++;
21313e3f4d6SMark Murray     }
21413e3f4d6SMark Murray     NET2ADD(IAC, WILL);
21513e3f4d6SMark Murray     NETADD(c);
21613e3f4d6SMark Murray     printoption("SENT", WILL, c);
21713e3f4d6SMark Murray }
21813e3f4d6SMark Murray 
21913e3f4d6SMark Murray void
send_wont(int c,int init)22013e3f4d6SMark Murray send_wont(int c, int init)
22113e3f4d6SMark Murray {
22213e3f4d6SMark Murray     if (init) {
22313e3f4d6SMark Murray 	if (((will_wont_resp[c] == 0) && my_state_is_wont(c)) ||
22413e3f4d6SMark Murray 				my_want_state_is_wont(c))
22513e3f4d6SMark Murray 	    return;
22613e3f4d6SMark Murray 	set_my_want_state_wont(c);
22713e3f4d6SMark Murray 	will_wont_resp[c]++;
22813e3f4d6SMark Murray     }
22913e3f4d6SMark Murray     NET2ADD(IAC, WONT);
23013e3f4d6SMark Murray     NETADD(c);
23113e3f4d6SMark Murray     printoption("SENT", WONT, c);
23213e3f4d6SMark Murray }
23313e3f4d6SMark Murray 
23413e3f4d6SMark Murray 
23513e3f4d6SMark Murray void
willoption(int option)23613e3f4d6SMark Murray willoption(int option)
23713e3f4d6SMark Murray {
23813e3f4d6SMark Murray 	int new_state_ok = 0;
23913e3f4d6SMark Murray 
24013e3f4d6SMark Murray 	if (do_dont_resp[option]) {
24113e3f4d6SMark Murray 	    --do_dont_resp[option];
24213e3f4d6SMark Murray 	    if (do_dont_resp[option] && my_state_is_do(option))
24313e3f4d6SMark Murray 		--do_dont_resp[option];
24413e3f4d6SMark Murray 	}
24513e3f4d6SMark Murray 
24613e3f4d6SMark Murray 	if ((do_dont_resp[option] == 0) && my_want_state_is_dont(option)) {
24713e3f4d6SMark Murray 
24813e3f4d6SMark Murray 	    switch (option) {
24913e3f4d6SMark Murray 
25013e3f4d6SMark Murray 	    case TELOPT_ECHO:
25113e3f4d6SMark Murray 	    case TELOPT_BINARY:
25213e3f4d6SMark Murray 	    case TELOPT_SGA:
25313e3f4d6SMark Murray 		settimer(modenegotiated);
25413e3f4d6SMark Murray 		/* FALL THROUGH */
25513e3f4d6SMark Murray 	    case TELOPT_STATUS:
25613e3f4d6SMark Murray #if	defined(AUTHENTICATION)
25713e3f4d6SMark Murray 	    case TELOPT_AUTHENTICATION:
25813e3f4d6SMark Murray #endif
25913e3f4d6SMark Murray #if	defined(ENCRYPTION)
26013e3f4d6SMark Murray 	    case TELOPT_ENCRYPT:
26113e3f4d6SMark Murray #endif
26213e3f4d6SMark Murray 		new_state_ok = 1;
26313e3f4d6SMark Murray 		break;
26413e3f4d6SMark Murray 
26513e3f4d6SMark Murray 	    case TELOPT_TM:
26613e3f4d6SMark Murray 		if (flushout)
26713e3f4d6SMark Murray 		    flushout = 0;
26813e3f4d6SMark Murray 		/*
26913e3f4d6SMark Murray 		 * Special case for TM.  If we get back a WILL,
27013e3f4d6SMark Murray 		 * pretend we got back a WONT.
27113e3f4d6SMark Murray 		 */
27213e3f4d6SMark Murray 		set_my_want_state_dont(option);
27313e3f4d6SMark Murray 		set_my_state_dont(option);
27413e3f4d6SMark Murray 		return;			/* Never reply to TM will's/wont's */
27513e3f4d6SMark Murray 
27613e3f4d6SMark Murray 	    case TELOPT_LINEMODE:
27713e3f4d6SMark Murray 	    default:
27813e3f4d6SMark Murray 		break;
27913e3f4d6SMark Murray 	    }
28013e3f4d6SMark Murray 
28113e3f4d6SMark Murray 	    if (new_state_ok) {
28213e3f4d6SMark Murray 		set_my_want_state_do(option);
28313e3f4d6SMark Murray 		send_do(option, 0);
28413e3f4d6SMark Murray 		setconnmode(0);		/* possibly set new tty mode */
28513e3f4d6SMark Murray 	    } else {
28613e3f4d6SMark Murray 		do_dont_resp[option]++;
28713e3f4d6SMark Murray 		send_dont(option, 0);
28813e3f4d6SMark Murray 	    }
28913e3f4d6SMark Murray 	}
29013e3f4d6SMark Murray 	set_my_state_do(option);
29113e3f4d6SMark Murray #if	defined(ENCRYPTION)
29213e3f4d6SMark Murray 	if (option == TELOPT_ENCRYPT)
29313e3f4d6SMark Murray 		encrypt_send_support();
29413e3f4d6SMark Murray #endif
29513e3f4d6SMark Murray }
29613e3f4d6SMark Murray 
29713e3f4d6SMark Murray void
wontoption(int option)29813e3f4d6SMark Murray wontoption(int option)
29913e3f4d6SMark Murray {
30013e3f4d6SMark Murray 	if (do_dont_resp[option]) {
30113e3f4d6SMark Murray 	    --do_dont_resp[option];
30213e3f4d6SMark Murray 	    if (do_dont_resp[option] && my_state_is_dont(option))
30313e3f4d6SMark Murray 		--do_dont_resp[option];
30413e3f4d6SMark Murray 	}
30513e3f4d6SMark Murray 
30613e3f4d6SMark Murray 	if ((do_dont_resp[option] == 0) && my_want_state_is_do(option)) {
30713e3f4d6SMark Murray 
30813e3f4d6SMark Murray 	    switch (option) {
30913e3f4d6SMark Murray 
31013e3f4d6SMark Murray #ifdef	KLUDGELINEMODE
31113e3f4d6SMark Murray 	    case TELOPT_SGA:
31213e3f4d6SMark Murray 		if (!kludgelinemode)
31313e3f4d6SMark Murray 		    break;
31413e3f4d6SMark Murray 		/* FALL THROUGH */
31513e3f4d6SMark Murray #endif
31613e3f4d6SMark Murray 	    case TELOPT_ECHO:
31713e3f4d6SMark Murray 		settimer(modenegotiated);
31813e3f4d6SMark Murray 		break;
31913e3f4d6SMark Murray 
32013e3f4d6SMark Murray 	    case TELOPT_TM:
32113e3f4d6SMark Murray 		if (flushout)
32213e3f4d6SMark Murray 		    flushout = 0;
32313e3f4d6SMark Murray 		set_my_want_state_dont(option);
32413e3f4d6SMark Murray 		set_my_state_dont(option);
32513e3f4d6SMark Murray 		return;		/* Never reply to TM will's/wont's */
32613e3f4d6SMark Murray 
32713e3f4d6SMark Murray #ifdef ENCRYPTION
32813e3f4d6SMark Murray   	    case TELOPT_ENCRYPT:
32913e3f4d6SMark Murray 	      encrypt_not();
33013e3f4d6SMark Murray 	      break;
33113e3f4d6SMark Murray #endif
33213e3f4d6SMark Murray 	    default:
33313e3f4d6SMark Murray 		break;
33413e3f4d6SMark Murray 	    }
33513e3f4d6SMark Murray 	    set_my_want_state_dont(option);
33613e3f4d6SMark Murray 	    if (my_state_is_do(option))
33713e3f4d6SMark Murray 		send_dont(option, 0);
33813e3f4d6SMark Murray 	    setconnmode(0);			/* Set new tty mode */
33913e3f4d6SMark Murray 	} else if (option == TELOPT_TM) {
34013e3f4d6SMark Murray 	    /*
34113e3f4d6SMark Murray 	     * Special case for TM.
34213e3f4d6SMark Murray 	     */
34313e3f4d6SMark Murray 	    if (flushout)
34413e3f4d6SMark Murray 		flushout = 0;
34513e3f4d6SMark Murray 	    set_my_want_state_dont(option);
34613e3f4d6SMark Murray 	}
34713e3f4d6SMark Murray 	set_my_state_dont(option);
34813e3f4d6SMark Murray }
34913e3f4d6SMark Murray 
35013e3f4d6SMark Murray static void
dooption(int option)35113e3f4d6SMark Murray dooption(int option)
35213e3f4d6SMark Murray {
35313e3f4d6SMark Murray 	int new_state_ok = 0;
35413e3f4d6SMark Murray 
35513e3f4d6SMark Murray 	if (will_wont_resp[option]) {
35613e3f4d6SMark Murray 	    --will_wont_resp[option];
35713e3f4d6SMark Murray 	    if (will_wont_resp[option] && my_state_is_will(option))
35813e3f4d6SMark Murray 		--will_wont_resp[option];
35913e3f4d6SMark Murray 	}
36013e3f4d6SMark Murray 
36113e3f4d6SMark Murray 	if (will_wont_resp[option] == 0) {
36213e3f4d6SMark Murray 	  if (my_want_state_is_wont(option)) {
36313e3f4d6SMark Murray 
36413e3f4d6SMark Murray 	    switch (option) {
36513e3f4d6SMark Murray 
36613e3f4d6SMark Murray 	    case TELOPT_TM:
36713e3f4d6SMark Murray 		/*
36813e3f4d6SMark Murray 		 * Special case for TM.  We send a WILL, but pretend
36913e3f4d6SMark Murray 		 * we sent WONT.
37013e3f4d6SMark Murray 		 */
37113e3f4d6SMark Murray 		send_will(option, 0);
37213e3f4d6SMark Murray 		set_my_want_state_wont(TELOPT_TM);
37313e3f4d6SMark Murray 		set_my_state_wont(TELOPT_TM);
37413e3f4d6SMark Murray 		return;
37513e3f4d6SMark Murray 
37613e3f4d6SMark Murray 	    case TELOPT_BINARY:		/* binary mode */
37713e3f4d6SMark Murray 	    case TELOPT_NAWS:		/* window size */
37813e3f4d6SMark Murray 	    case TELOPT_TSPEED:		/* terminal speed */
37913e3f4d6SMark Murray 	    case TELOPT_LFLOW:		/* local flow control */
38013e3f4d6SMark Murray 	    case TELOPT_TTYPE:		/* terminal type option */
38113e3f4d6SMark Murray 	    case TELOPT_SGA:		/* no big deal */
38213e3f4d6SMark Murray #if	defined(ENCRYPTION)
38313e3f4d6SMark Murray 	    case TELOPT_ENCRYPT:	/* encryption variable option */
38413e3f4d6SMark Murray #endif
38513e3f4d6SMark Murray 		new_state_ok = 1;
38613e3f4d6SMark Murray 		break;
38713e3f4d6SMark Murray 
38813e3f4d6SMark Murray 	    case TELOPT_NEW_ENVIRON:	/* New environment variable option */
38913e3f4d6SMark Murray #ifdef	OLD_ENVIRON
39013e3f4d6SMark Murray 		if (my_state_is_will(TELOPT_OLD_ENVIRON))
39113e3f4d6SMark Murray 			send_wont(TELOPT_OLD_ENVIRON, 1); /* turn off the old */
39213e3f4d6SMark Murray 		goto env_common;
39313e3f4d6SMark Murray 	    case TELOPT_OLD_ENVIRON:	/* Old environment variable option */
39413e3f4d6SMark Murray 		if (my_state_is_will(TELOPT_NEW_ENVIRON))
39513e3f4d6SMark Murray 			break;		/* Don't enable if new one is in use! */
39613e3f4d6SMark Murray 	    env_common:
39713e3f4d6SMark Murray 		telopt_environ = option;
39813e3f4d6SMark Murray #endif
39913e3f4d6SMark Murray 		new_state_ok = 1;
40013e3f4d6SMark Murray 		break;
40113e3f4d6SMark Murray 
40213e3f4d6SMark Murray #if	defined(AUTHENTICATION)
40313e3f4d6SMark Murray 	    case TELOPT_AUTHENTICATION:
40413e3f4d6SMark Murray 		if (autologin)
40513e3f4d6SMark Murray 			new_state_ok = 1;
40613e3f4d6SMark Murray 		break;
40713e3f4d6SMark Murray #endif
40813e3f4d6SMark Murray 
40913e3f4d6SMark Murray 	    case TELOPT_XDISPLOC:	/* X Display location */
41013e3f4d6SMark Murray 		if (env_getvalue((unsigned char *)"DISPLAY"))
41113e3f4d6SMark Murray 		    new_state_ok = 1;
41213e3f4d6SMark Murray 		break;
41313e3f4d6SMark Murray 
41413e3f4d6SMark Murray 	    case TELOPT_LINEMODE:
41513e3f4d6SMark Murray #ifdef	KLUDGELINEMODE
41613e3f4d6SMark Murray 		kludgelinemode = 0;
41713e3f4d6SMark Murray 		send_do(TELOPT_SGA, 1);
41813e3f4d6SMark Murray #endif
41913e3f4d6SMark Murray 		set_my_want_state_will(TELOPT_LINEMODE);
42013e3f4d6SMark Murray 		send_will(option, 0);
42113e3f4d6SMark Murray 		set_my_state_will(TELOPT_LINEMODE);
42213e3f4d6SMark Murray 		slc_init();
42313e3f4d6SMark Murray 		return;
42413e3f4d6SMark Murray 
42513e3f4d6SMark Murray 	    case TELOPT_ECHO:		/* We're never going to echo... */
42613e3f4d6SMark Murray 	    default:
42713e3f4d6SMark Murray 		break;
42813e3f4d6SMark Murray 	    }
42913e3f4d6SMark Murray 
43013e3f4d6SMark Murray 	    if (new_state_ok) {
43113e3f4d6SMark Murray 		set_my_want_state_will(option);
43213e3f4d6SMark Murray 		send_will(option, 0);
43313e3f4d6SMark Murray 		setconnmode(0);			/* Set new tty mode */
43413e3f4d6SMark Murray 	    } else {
43513e3f4d6SMark Murray 		will_wont_resp[option]++;
43613e3f4d6SMark Murray 		send_wont(option, 0);
43713e3f4d6SMark Murray 	    }
43813e3f4d6SMark Murray 	  } else {
43913e3f4d6SMark Murray 	    /*
44013e3f4d6SMark Murray 	     * Handle options that need more things done after the
44113e3f4d6SMark Murray 	     * other side has acknowledged the option.
44213e3f4d6SMark Murray 	     */
44313e3f4d6SMark Murray 	    switch (option) {
44413e3f4d6SMark Murray 	    case TELOPT_LINEMODE:
44513e3f4d6SMark Murray #ifdef	KLUDGELINEMODE
44613e3f4d6SMark Murray 		kludgelinemode = 0;
44713e3f4d6SMark Murray 		send_do(TELOPT_SGA, 1);
44813e3f4d6SMark Murray #endif
44913e3f4d6SMark Murray 		set_my_state_will(option);
45013e3f4d6SMark Murray 		slc_init();
45113e3f4d6SMark Murray 		send_do(TELOPT_SGA, 0);
45213e3f4d6SMark Murray 		return;
45313e3f4d6SMark Murray 	    }
45413e3f4d6SMark Murray 	  }
45513e3f4d6SMark Murray 	}
45613e3f4d6SMark Murray 	set_my_state_will(option);
45713e3f4d6SMark Murray }
45813e3f4d6SMark Murray 
45913e3f4d6SMark Murray static void
dontoption(int option)46013e3f4d6SMark Murray dontoption(int option)
46113e3f4d6SMark Murray {
46213e3f4d6SMark Murray 
46313e3f4d6SMark Murray 	if (will_wont_resp[option]) {
46413e3f4d6SMark Murray 	    --will_wont_resp[option];
46513e3f4d6SMark Murray 	    if (will_wont_resp[option] && my_state_is_wont(option))
46613e3f4d6SMark Murray 		--will_wont_resp[option];
46713e3f4d6SMark Murray 	}
46813e3f4d6SMark Murray 
46913e3f4d6SMark Murray 	if ((will_wont_resp[option] == 0) && my_want_state_is_will(option)) {
47013e3f4d6SMark Murray 	    switch (option) {
47113e3f4d6SMark Murray 	    case TELOPT_LINEMODE:
47213e3f4d6SMark Murray 		linemode = 0;	/* put us back to the default state */
47313e3f4d6SMark Murray 		break;
47413e3f4d6SMark Murray #ifdef	OLD_ENVIRON
47513e3f4d6SMark Murray 	    case TELOPT_NEW_ENVIRON:
47613e3f4d6SMark Murray 		/*
47713e3f4d6SMark Murray 		 * The new environ option wasn't recognized, try
47813e3f4d6SMark Murray 		 * the old one.
47913e3f4d6SMark Murray 		 */
48013e3f4d6SMark Murray 		send_will(TELOPT_OLD_ENVIRON, 1);
48113e3f4d6SMark Murray 		telopt_environ = TELOPT_OLD_ENVIRON;
48213e3f4d6SMark Murray 		break;
48313e3f4d6SMark Murray #endif
48413e3f4d6SMark Murray #if 0
48513e3f4d6SMark Murray #ifdef ENCRYPTION
48613e3f4d6SMark Murray 	    case TELOPT_ENCRYPT:
48713e3f4d6SMark Murray 	      encrypt_not();
48813e3f4d6SMark Murray 	      break;
48913e3f4d6SMark Murray #endif
49013e3f4d6SMark Murray #endif
49113e3f4d6SMark Murray 	    }
49213e3f4d6SMark Murray 	    /* we always accept a DONT */
49313e3f4d6SMark Murray 	    set_my_want_state_wont(option);
49413e3f4d6SMark Murray 	    if (my_state_is_will(option))
49513e3f4d6SMark Murray 		send_wont(option, 0);
49613e3f4d6SMark Murray 	    setconnmode(0);			/* Set new tty mode */
49713e3f4d6SMark Murray 	}
49813e3f4d6SMark Murray 	set_my_state_wont(option);
49913e3f4d6SMark Murray }
50013e3f4d6SMark Murray 
50113e3f4d6SMark Murray /*
50213e3f4d6SMark Murray  * Given a buffer returned by tgetent(), this routine will turn
503c19800e8SDoug Rabson  * the pipe separated list of names in the buffer into an array
50413e3f4d6SMark Murray  * of pointers to null terminated names.  We toss out any bad,
50513e3f4d6SMark Murray  * duplicate, or verbose names (names with spaces).
50613e3f4d6SMark Murray  */
50713e3f4d6SMark Murray 
50813e3f4d6SMark Murray static char *name_unknown = "UNKNOWN";
50913e3f4d6SMark Murray static char *unknown[] = { 0, 0 };
51013e3f4d6SMark Murray 
51113e3f4d6SMark Murray static char **
mklist(char * buf,char * name)51213e3f4d6SMark Murray mklist(char *buf, char *name)
51313e3f4d6SMark Murray {
51413e3f4d6SMark Murray 	int n;
51513e3f4d6SMark Murray 	char c, *cp, **argvp, *cp2, **argv, **avt;
51613e3f4d6SMark Murray 
51713e3f4d6SMark Murray 	if (name) {
51813e3f4d6SMark Murray 		if ((int)strlen(name) > 40) {
51913e3f4d6SMark Murray 			name = 0;
52013e3f4d6SMark Murray 			unknown[0] = name_unknown;
52113e3f4d6SMark Murray 		} else {
52213e3f4d6SMark Murray 			unknown[0] = name;
52313e3f4d6SMark Murray 			strupr(name);
52413e3f4d6SMark Murray 		}
52513e3f4d6SMark Murray 	} else
52613e3f4d6SMark Murray 		unknown[0] = name_unknown;
52713e3f4d6SMark Murray 	/*
52813e3f4d6SMark Murray 	 * Count up the number of names.
52913e3f4d6SMark Murray 	 */
53013e3f4d6SMark Murray 	for (n = 1, cp = buf; *cp && *cp != ':'; cp++) {
53113e3f4d6SMark Murray 		if (*cp == '|')
53213e3f4d6SMark Murray 			n++;
53313e3f4d6SMark Murray 	}
53413e3f4d6SMark Murray 	/*
53513e3f4d6SMark Murray 	 * Allocate an array to put the name pointers into
53613e3f4d6SMark Murray 	 */
53713e3f4d6SMark Murray 	argv = (char **)malloc((n+3)*sizeof(char *));
53813e3f4d6SMark Murray 	if (argv == 0)
53913e3f4d6SMark Murray 		return(unknown);
54013e3f4d6SMark Murray 
54113e3f4d6SMark Murray 	/*
54213e3f4d6SMark Murray 	 * Fill up the array of pointers to names.
54313e3f4d6SMark Murray 	 */
54413e3f4d6SMark Murray 	*argv = 0;
54513e3f4d6SMark Murray 	argvp = argv+1;
54613e3f4d6SMark Murray 	n = 0;
54713e3f4d6SMark Murray 	for (cp = cp2 = buf; (c = *cp);  cp++) {
54813e3f4d6SMark Murray 		if (c == '|' || c == ':') {
54913e3f4d6SMark Murray 			*cp++ = '\0';
55013e3f4d6SMark Murray 			/*
55113e3f4d6SMark Murray 			 * Skip entries that have spaces or are over 40
55213e3f4d6SMark Murray 			 * characters long.  If this is our environment
55313e3f4d6SMark Murray 			 * name, then put it up front.  Otherwise, as
55413e3f4d6SMark Murray 			 * long as this is not a duplicate name (case
55513e3f4d6SMark Murray 			 * insensitive) add it to the list.
55613e3f4d6SMark Murray 			 */
55713e3f4d6SMark Murray 			if (n || (cp - cp2 > 41))
55813e3f4d6SMark Murray 				;
55913e3f4d6SMark Murray 			else if (name && (strncasecmp(name, cp2, cp-cp2) == 0))
56013e3f4d6SMark Murray 				*argv = cp2;
56113e3f4d6SMark Murray 			else if (is_unique(cp2, argv+1, argvp))
56213e3f4d6SMark Murray 				*argvp++ = cp2;
56313e3f4d6SMark Murray 			if (c == ':')
56413e3f4d6SMark Murray 				break;
56513e3f4d6SMark Murray 			/*
56613e3f4d6SMark Murray 			 * Skip multiple delimiters. Reset cp2 to
56713e3f4d6SMark Murray 			 * the beginning of the next name. Reset n,
56813e3f4d6SMark Murray 			 * the flag for names with spaces.
56913e3f4d6SMark Murray 			 */
57013e3f4d6SMark Murray 			while ((c = *cp) == '|')
57113e3f4d6SMark Murray 				cp++;
57213e3f4d6SMark Murray 			cp2 = cp;
57313e3f4d6SMark Murray 			n = 0;
57413e3f4d6SMark Murray 		}
57513e3f4d6SMark Murray 		/*
57613e3f4d6SMark Murray 		 * Skip entries with spaces or non-ascii values.
57713e3f4d6SMark Murray 		 * Convert lower case letters to upper case.
57813e3f4d6SMark Murray 		 */
579c19800e8SDoug Rabson #undef ISASCII
58013e3f4d6SMark Murray #define ISASCII(c) (!((c)&0x80))
58113e3f4d6SMark Murray 		if ((c == ' ') || !ISASCII(c))
58213e3f4d6SMark Murray 			n = 1;
5834137ff4cSJacques Vidrine 		else if (islower((unsigned char)c))
584c19800e8SDoug Rabson 			*cp = toupper((unsigned char)c);
58513e3f4d6SMark Murray 	}
58613e3f4d6SMark Murray 
58713e3f4d6SMark Murray 	/*
58813e3f4d6SMark Murray 	 * Check for an old V6 2 character name.  If the second
58913e3f4d6SMark Murray 	 * name points to the beginning of the buffer, and is
59013e3f4d6SMark Murray 	 * only 2 characters long, move it to the end of the array.
59113e3f4d6SMark Murray 	 */
59213e3f4d6SMark Murray 	if ((argv[1] == buf) && (strlen(argv[1]) == 2)) {
59313e3f4d6SMark Murray 		--argvp;
59413e3f4d6SMark Murray 		for (avt = &argv[1]; avt < argvp; avt++)
59513e3f4d6SMark Murray 			*avt = *(avt+1);
59613e3f4d6SMark Murray 		*argvp++ = buf;
59713e3f4d6SMark Murray 	}
59813e3f4d6SMark Murray 
59913e3f4d6SMark Murray 	/*
60013e3f4d6SMark Murray 	 * Duplicate last name, for TTYPE option, and null
60113e3f4d6SMark Murray 	 * terminate the array.  If we didn't find a match on
60213e3f4d6SMark Murray 	 * our terminal name, put that name at the beginning.
60313e3f4d6SMark Murray 	 */
60413e3f4d6SMark Murray 	cp = *(argvp-1);
60513e3f4d6SMark Murray 	*argvp++ = cp;
60613e3f4d6SMark Murray 	*argvp = 0;
60713e3f4d6SMark Murray 
60813e3f4d6SMark Murray 	if (*argv == 0) {
60913e3f4d6SMark Murray 		if (name)
61013e3f4d6SMark Murray 			*argv = name;
61113e3f4d6SMark Murray 		else {
61213e3f4d6SMark Murray 			--argvp;
61313e3f4d6SMark Murray 			for (avt = argv; avt < argvp; avt++)
61413e3f4d6SMark Murray 				*avt = *(avt+1);
61513e3f4d6SMark Murray 		}
61613e3f4d6SMark Murray 	}
61713e3f4d6SMark Murray 	if (*argv)
61813e3f4d6SMark Murray 		return(argv);
61913e3f4d6SMark Murray 	else
62013e3f4d6SMark Murray 		return(unknown);
62113e3f4d6SMark Murray }
62213e3f4d6SMark Murray 
62313e3f4d6SMark Murray static int
is_unique(char * name,char ** as,char ** ae)62413e3f4d6SMark Murray is_unique(char *name, char **as, char **ae)
62513e3f4d6SMark Murray {
62613e3f4d6SMark Murray 	char **ap;
62713e3f4d6SMark Murray 	int n;
62813e3f4d6SMark Murray 
62913e3f4d6SMark Murray 	n = strlen(name) + 1;
63013e3f4d6SMark Murray 	for (ap = as; ap < ae; ap++)
63113e3f4d6SMark Murray 		if (strncasecmp(*ap, name, n) == 0)
63213e3f4d6SMark Murray 			return(0);
63313e3f4d6SMark Murray 	return (1);
63413e3f4d6SMark Murray }
63513e3f4d6SMark Murray 
63613e3f4d6SMark Murray static char termbuf[1024];
63713e3f4d6SMark Murray 
63813e3f4d6SMark Murray static int
telnet_setupterm(const char * tname,int fd,int * errp)63913e3f4d6SMark Murray telnet_setupterm(const char *tname, int fd, int *errp)
64013e3f4d6SMark Murray {
6415e9cd1aeSAssar Westerlund #ifdef HAVE_TGETENT
64213e3f4d6SMark Murray     if (tgetent(termbuf, tname) == 1) {
64313e3f4d6SMark Murray 	termbuf[1023] = '\0';
64413e3f4d6SMark Murray 	if (errp)
64513e3f4d6SMark Murray 	    *errp = 1;
64613e3f4d6SMark Murray 	return(0);
64713e3f4d6SMark Murray     }
64813e3f4d6SMark Murray     if (errp)
64913e3f4d6SMark Murray 	*errp = 0;
65013e3f4d6SMark Murray     return(-1);
6515e9cd1aeSAssar Westerlund #else
6525e9cd1aeSAssar Westerlund     strlcpy(termbuf, tname, sizeof(termbuf));
6535e9cd1aeSAssar Westerlund     if(errp) *errp = 1;
6545e9cd1aeSAssar Westerlund     return 0;
6555e9cd1aeSAssar Westerlund #endif
65613e3f4d6SMark Murray }
65713e3f4d6SMark Murray 
65813e3f4d6SMark Murray int resettermname = 1;
65913e3f4d6SMark Murray 
66013e3f4d6SMark Murray static char *
gettermname()66113e3f4d6SMark Murray gettermname()
66213e3f4d6SMark Murray {
66313e3f4d6SMark Murray 	char *tname;
66413e3f4d6SMark Murray 	static char **tnamep = 0;
66513e3f4d6SMark Murray 	static char **next;
66613e3f4d6SMark Murray 	int err;
66713e3f4d6SMark Murray 
66813e3f4d6SMark Murray 	if (resettermname) {
66913e3f4d6SMark Murray 		resettermname = 0;
67013e3f4d6SMark Murray 		if (tnamep && tnamep != unknown)
67113e3f4d6SMark Murray 			free(tnamep);
67213e3f4d6SMark Murray 		if ((tname = (char *)env_getvalue((unsigned char *)"TERM")) &&
67313e3f4d6SMark Murray 				telnet_setupterm(tname, 1, &err) == 0) {
67413e3f4d6SMark Murray 			tnamep = mklist(termbuf, tname);
67513e3f4d6SMark Murray 		} else {
67613e3f4d6SMark Murray 			if (tname && ((int)strlen(tname) <= 40)) {
67713e3f4d6SMark Murray 				unknown[0] = tname;
67813e3f4d6SMark Murray 				strupr(tname);
67913e3f4d6SMark Murray 			} else
68013e3f4d6SMark Murray 				unknown[0] = name_unknown;
68113e3f4d6SMark Murray 			tnamep = unknown;
68213e3f4d6SMark Murray 		}
68313e3f4d6SMark Murray 		next = tnamep;
68413e3f4d6SMark Murray 	}
68513e3f4d6SMark Murray 	if (*next == 0)
68613e3f4d6SMark Murray 		next = tnamep;
68713e3f4d6SMark Murray 	return(*next++);
68813e3f4d6SMark Murray }
68913e3f4d6SMark Murray /*
69013e3f4d6SMark Murray  * suboption()
69113e3f4d6SMark Murray  *
69213e3f4d6SMark Murray  *	Look at the sub-option buffer, and try to be helpful to the other
69313e3f4d6SMark Murray  * side.
69413e3f4d6SMark Murray  *
69513e3f4d6SMark Murray  *	Currently we recognize:
69613e3f4d6SMark Murray  *
69713e3f4d6SMark Murray  *		Terminal type, send request.
69813e3f4d6SMark Murray  *		Terminal speed (send request).
69913e3f4d6SMark Murray  *		Local flow control (is request).
70013e3f4d6SMark Murray  *		Linemode
70113e3f4d6SMark Murray  */
70213e3f4d6SMark Murray 
70313e3f4d6SMark Murray static void
suboption()70413e3f4d6SMark Murray suboption()
70513e3f4d6SMark Murray {
70613e3f4d6SMark Murray     unsigned char subchar;
70713e3f4d6SMark Murray 
70813e3f4d6SMark Murray     printsub('<', subbuffer, SB_LEN()+2);
70913e3f4d6SMark Murray     switch (subchar = SB_GET()) {
71013e3f4d6SMark Murray     case TELOPT_TTYPE:
71113e3f4d6SMark Murray 	if (my_want_state_is_wont(TELOPT_TTYPE))
71213e3f4d6SMark Murray 	    return;
71313e3f4d6SMark Murray 	if (SB_EOF() || SB_GET() != TELQUAL_SEND) {
71413e3f4d6SMark Murray 	    return;
71513e3f4d6SMark Murray 	} else {
71613e3f4d6SMark Murray 	    char *name;
71713e3f4d6SMark Murray 	    unsigned char temp[50];
71813e3f4d6SMark Murray 	    int len;
71913e3f4d6SMark Murray 
72013e3f4d6SMark Murray 	    name = gettermname();
72113e3f4d6SMark Murray 	    len = strlen(name) + 4 + 2;
72213e3f4d6SMark Murray 	    if (len < NETROOM()) {
72313e3f4d6SMark Murray 		snprintf((char *)temp, sizeof(temp),
72413e3f4d6SMark Murray 			 "%c%c%c%c%s%c%c", IAC, SB, TELOPT_TTYPE,
72513e3f4d6SMark Murray 			 TELQUAL_IS, name, IAC, SE);
72613e3f4d6SMark Murray 		ring_supply_data(&netoring, temp, len);
72713e3f4d6SMark Murray 		printsub('>', &temp[2], len-2);
72813e3f4d6SMark Murray 	    } else {
72913e3f4d6SMark Murray 		ExitString("No room in buffer for terminal type.\n", 1);
73013e3f4d6SMark Murray 		/*NOTREACHED*/
73113e3f4d6SMark Murray 	    }
73213e3f4d6SMark Murray 	}
73313e3f4d6SMark Murray 	break;
73413e3f4d6SMark Murray     case TELOPT_TSPEED:
73513e3f4d6SMark Murray 	if (my_want_state_is_wont(TELOPT_TSPEED))
73613e3f4d6SMark Murray 	    return;
73713e3f4d6SMark Murray 	if (SB_EOF())
73813e3f4d6SMark Murray 	    return;
73913e3f4d6SMark Murray 	if (SB_GET() == TELQUAL_SEND) {
74013e3f4d6SMark Murray 	    long output_speed, input_speed;
74113e3f4d6SMark Murray 	    unsigned char temp[50];
74213e3f4d6SMark Murray 	    int len;
74313e3f4d6SMark Murray 
74413e3f4d6SMark Murray 	    TerminalSpeeds(&input_speed, &output_speed);
74513e3f4d6SMark Murray 
74613e3f4d6SMark Murray 	    snprintf((char *)temp, sizeof(temp),
74713e3f4d6SMark Murray 		     "%c%c%c%c%u,%u%c%c", IAC, SB, TELOPT_TSPEED,
74813e3f4d6SMark Murray 		     TELQUAL_IS,
74913e3f4d6SMark Murray 		     (unsigned)output_speed,
75013e3f4d6SMark Murray 		     (unsigned)input_speed, IAC, SE);
75113e3f4d6SMark Murray 	    len = strlen((char *)temp+4) + 4;	/* temp[3] is 0 ... */
75213e3f4d6SMark Murray 
75313e3f4d6SMark Murray 	    if (len < NETROOM()) {
75413e3f4d6SMark Murray 		ring_supply_data(&netoring, temp, len);
75513e3f4d6SMark Murray 		printsub('>', temp+2, len - 2);
75613e3f4d6SMark Murray 	    }
75713e3f4d6SMark Murray /*@*/	    else printf("lm_will: not enough room in buffer\n");
75813e3f4d6SMark Murray 	}
75913e3f4d6SMark Murray 	break;
76013e3f4d6SMark Murray     case TELOPT_LFLOW:
76113e3f4d6SMark Murray 	if (my_want_state_is_wont(TELOPT_LFLOW))
76213e3f4d6SMark Murray 	    return;
76313e3f4d6SMark Murray 	if (SB_EOF())
76413e3f4d6SMark Murray 	    return;
76513e3f4d6SMark Murray 	switch(SB_GET()) {
76613e3f4d6SMark Murray 	case LFLOW_RESTART_ANY:
76713e3f4d6SMark Murray 	    restartany = 1;
76813e3f4d6SMark Murray 	    break;
76913e3f4d6SMark Murray 	case LFLOW_RESTART_XON:
77013e3f4d6SMark Murray 	    restartany = 0;
77113e3f4d6SMark Murray 	    break;
77213e3f4d6SMark Murray 	case LFLOW_ON:
77313e3f4d6SMark Murray 	    localflow = 1;
77413e3f4d6SMark Murray 	    break;
77513e3f4d6SMark Murray 	case LFLOW_OFF:
77613e3f4d6SMark Murray 	    localflow = 0;
77713e3f4d6SMark Murray 	    break;
77813e3f4d6SMark Murray 	default:
77913e3f4d6SMark Murray 	    return;
78013e3f4d6SMark Murray 	}
78113e3f4d6SMark Murray 	setcommandmode();
78213e3f4d6SMark Murray 	setconnmode(0);
78313e3f4d6SMark Murray 	break;
78413e3f4d6SMark Murray 
78513e3f4d6SMark Murray     case TELOPT_LINEMODE:
78613e3f4d6SMark Murray 	if (my_want_state_is_wont(TELOPT_LINEMODE))
78713e3f4d6SMark Murray 	    return;
78813e3f4d6SMark Murray 	if (SB_EOF())
78913e3f4d6SMark Murray 	    return;
79013e3f4d6SMark Murray 	switch (SB_GET()) {
79113e3f4d6SMark Murray 	case WILL:
79213e3f4d6SMark Murray 	    lm_will(subpointer, SB_LEN());
79313e3f4d6SMark Murray 	    break;
79413e3f4d6SMark Murray 	case WONT:
79513e3f4d6SMark Murray 	    lm_wont(subpointer, SB_LEN());
79613e3f4d6SMark Murray 	    break;
79713e3f4d6SMark Murray 	case DO:
79813e3f4d6SMark Murray 	    lm_do(subpointer, SB_LEN());
79913e3f4d6SMark Murray 	    break;
80013e3f4d6SMark Murray 	case DONT:
80113e3f4d6SMark Murray 	    lm_dont(subpointer, SB_LEN());
80213e3f4d6SMark Murray 	    break;
80313e3f4d6SMark Murray 	case LM_SLC:
80413e3f4d6SMark Murray 	    slc(subpointer, SB_LEN());
80513e3f4d6SMark Murray 	    break;
80613e3f4d6SMark Murray 	case LM_MODE:
80713e3f4d6SMark Murray 	    lm_mode(subpointer, SB_LEN(), 0);
80813e3f4d6SMark Murray 	    break;
80913e3f4d6SMark Murray 	default:
81013e3f4d6SMark Murray 	    break;
81113e3f4d6SMark Murray 	}
81213e3f4d6SMark Murray 	break;
81313e3f4d6SMark Murray 
81413e3f4d6SMark Murray #ifdef	OLD_ENVIRON
81513e3f4d6SMark Murray     case TELOPT_OLD_ENVIRON:
81613e3f4d6SMark Murray #endif
81713e3f4d6SMark Murray     case TELOPT_NEW_ENVIRON:
81813e3f4d6SMark Murray 	if (SB_EOF())
81913e3f4d6SMark Murray 	    return;
82013e3f4d6SMark Murray 	switch(SB_PEEK()) {
82113e3f4d6SMark Murray 	case TELQUAL_IS:
82213e3f4d6SMark Murray 	case TELQUAL_INFO:
82313e3f4d6SMark Murray 	    if (my_want_state_is_dont(subchar))
82413e3f4d6SMark Murray 		return;
82513e3f4d6SMark Murray 	    break;
82613e3f4d6SMark Murray 	case TELQUAL_SEND:
82713e3f4d6SMark Murray 	    if (my_want_state_is_wont(subchar)) {
82813e3f4d6SMark Murray 		return;
82913e3f4d6SMark Murray 	    }
83013e3f4d6SMark Murray 	    break;
83113e3f4d6SMark Murray 	default:
83213e3f4d6SMark Murray 	    return;
83313e3f4d6SMark Murray 	}
83413e3f4d6SMark Murray 	env_opt(subpointer, SB_LEN());
83513e3f4d6SMark Murray 	break;
83613e3f4d6SMark Murray 
83713e3f4d6SMark Murray     case TELOPT_XDISPLOC:
83813e3f4d6SMark Murray 	if (my_want_state_is_wont(TELOPT_XDISPLOC))
83913e3f4d6SMark Murray 	    return;
84013e3f4d6SMark Murray 	if (SB_EOF())
84113e3f4d6SMark Murray 	    return;
84213e3f4d6SMark Murray 	if (SB_GET() == TELQUAL_SEND) {
84313e3f4d6SMark Murray 	    unsigned char temp[50], *dp;
84413e3f4d6SMark Murray 	    int len;
84513e3f4d6SMark Murray 
84613e3f4d6SMark Murray 	    if ((dp = env_getvalue((unsigned char *)"DISPLAY")) == NULL) {
84713e3f4d6SMark Murray 		/*
84813e3f4d6SMark Murray 		 * Something happened, we no longer have a DISPLAY
84913e3f4d6SMark Murray 		 * variable.  So, turn off the option.
85013e3f4d6SMark Murray 		 */
85113e3f4d6SMark Murray 		send_wont(TELOPT_XDISPLOC, 1);
85213e3f4d6SMark Murray 		break;
85313e3f4d6SMark Murray 	    }
85413e3f4d6SMark Murray 	    snprintf((char *)temp, sizeof(temp),
85513e3f4d6SMark Murray 		     "%c%c%c%c%s%c%c", IAC, SB, TELOPT_XDISPLOC,
85613e3f4d6SMark Murray 		     TELQUAL_IS, dp, IAC, SE);
85713e3f4d6SMark Murray 	    len = strlen((char *)temp+4) + 4;	/* temp[3] is 0 ... */
85813e3f4d6SMark Murray 
85913e3f4d6SMark Murray 	    if (len < NETROOM()) {
86013e3f4d6SMark Murray 		ring_supply_data(&netoring, temp, len);
86113e3f4d6SMark Murray 		printsub('>', temp+2, len - 2);
86213e3f4d6SMark Murray 	    }
86313e3f4d6SMark Murray /*@*/	    else printf("lm_will: not enough room in buffer\n");
86413e3f4d6SMark Murray 	}
86513e3f4d6SMark Murray 	break;
86613e3f4d6SMark Murray 
86713e3f4d6SMark Murray #if	defined(AUTHENTICATION)
86813e3f4d6SMark Murray 	case TELOPT_AUTHENTICATION: {
86913e3f4d6SMark Murray 		if (!autologin)
87013e3f4d6SMark Murray 			break;
87113e3f4d6SMark Murray 		if (SB_EOF())
87213e3f4d6SMark Murray 			return;
87313e3f4d6SMark Murray 		switch(SB_GET()) {
87413e3f4d6SMark Murray 		case TELQUAL_IS:
87513e3f4d6SMark Murray 			if (my_want_state_is_dont(TELOPT_AUTHENTICATION))
87613e3f4d6SMark Murray 				return;
87713e3f4d6SMark Murray 			auth_is(subpointer, SB_LEN());
87813e3f4d6SMark Murray 			break;
87913e3f4d6SMark Murray 		case TELQUAL_SEND:
88013e3f4d6SMark Murray 			if (my_want_state_is_wont(TELOPT_AUTHENTICATION))
88113e3f4d6SMark Murray 				return;
88213e3f4d6SMark Murray 			auth_send(subpointer, SB_LEN());
88313e3f4d6SMark Murray 			break;
88413e3f4d6SMark Murray 		case TELQUAL_REPLY:
88513e3f4d6SMark Murray 			if (my_want_state_is_wont(TELOPT_AUTHENTICATION))
88613e3f4d6SMark Murray 				return;
88713e3f4d6SMark Murray 			auth_reply(subpointer, SB_LEN());
88813e3f4d6SMark Murray 			break;
88913e3f4d6SMark Murray 		case TELQUAL_NAME:
89013e3f4d6SMark Murray 			if (my_want_state_is_dont(TELOPT_AUTHENTICATION))
89113e3f4d6SMark Murray 				return;
89213e3f4d6SMark Murray 			auth_name(subpointer, SB_LEN());
89313e3f4d6SMark Murray 			break;
89413e3f4d6SMark Murray 		}
89513e3f4d6SMark Murray 	}
89613e3f4d6SMark Murray 	break;
89713e3f4d6SMark Murray #endif
89813e3f4d6SMark Murray #if	defined(ENCRYPTION)
89913e3f4d6SMark Murray 	case TELOPT_ENCRYPT:
90013e3f4d6SMark Murray 		if (SB_EOF())
90113e3f4d6SMark Murray 			return;
90213e3f4d6SMark Murray 		switch(SB_GET()) {
90313e3f4d6SMark Murray 		case ENCRYPT_START:
90413e3f4d6SMark Murray 			if (my_want_state_is_dont(TELOPT_ENCRYPT))
90513e3f4d6SMark Murray 				return;
90613e3f4d6SMark Murray 			encrypt_start(subpointer, SB_LEN());
90713e3f4d6SMark Murray 			break;
90813e3f4d6SMark Murray 		case ENCRYPT_END:
90913e3f4d6SMark Murray 			if (my_want_state_is_dont(TELOPT_ENCRYPT))
91013e3f4d6SMark Murray 				return;
91113e3f4d6SMark Murray 			encrypt_end();
91213e3f4d6SMark Murray 			break;
91313e3f4d6SMark Murray 		case ENCRYPT_SUPPORT:
91413e3f4d6SMark Murray 			if (my_want_state_is_wont(TELOPT_ENCRYPT))
91513e3f4d6SMark Murray 				return;
91613e3f4d6SMark Murray 			encrypt_support(subpointer, SB_LEN());
91713e3f4d6SMark Murray 			break;
91813e3f4d6SMark Murray 		case ENCRYPT_REQSTART:
91913e3f4d6SMark Murray 			if (my_want_state_is_wont(TELOPT_ENCRYPT))
92013e3f4d6SMark Murray 				return;
92113e3f4d6SMark Murray 			encrypt_request_start(subpointer, SB_LEN());
92213e3f4d6SMark Murray 			break;
92313e3f4d6SMark Murray 		case ENCRYPT_REQEND:
92413e3f4d6SMark Murray 			if (my_want_state_is_wont(TELOPT_ENCRYPT))
92513e3f4d6SMark Murray 				return;
92613e3f4d6SMark Murray 			/*
92713e3f4d6SMark Murray 			 * We can always send an REQEND so that we cannot
92813e3f4d6SMark Murray 			 * get stuck encrypting.  We should only get this
92913e3f4d6SMark Murray 			 * if we have been able to get in the correct mode
93013e3f4d6SMark Murray 			 * anyhow.
93113e3f4d6SMark Murray 			 */
93213e3f4d6SMark Murray 			encrypt_request_end();
93313e3f4d6SMark Murray 			break;
93413e3f4d6SMark Murray 		case ENCRYPT_IS:
93513e3f4d6SMark Murray 			if (my_want_state_is_dont(TELOPT_ENCRYPT))
93613e3f4d6SMark Murray 				return;
93713e3f4d6SMark Murray 			encrypt_is(subpointer, SB_LEN());
93813e3f4d6SMark Murray 			break;
93913e3f4d6SMark Murray 		case ENCRYPT_REPLY:
94013e3f4d6SMark Murray 			if (my_want_state_is_wont(TELOPT_ENCRYPT))
94113e3f4d6SMark Murray 				return;
94213e3f4d6SMark Murray 			encrypt_reply(subpointer, SB_LEN());
94313e3f4d6SMark Murray 			break;
94413e3f4d6SMark Murray 		case ENCRYPT_ENC_KEYID:
94513e3f4d6SMark Murray 			if (my_want_state_is_dont(TELOPT_ENCRYPT))
94613e3f4d6SMark Murray 				return;
94713e3f4d6SMark Murray 			encrypt_enc_keyid(subpointer, SB_LEN());
94813e3f4d6SMark Murray 			break;
94913e3f4d6SMark Murray 		case ENCRYPT_DEC_KEYID:
95013e3f4d6SMark Murray 			if (my_want_state_is_wont(TELOPT_ENCRYPT))
95113e3f4d6SMark Murray 				return;
95213e3f4d6SMark Murray 			encrypt_dec_keyid(subpointer, SB_LEN());
95313e3f4d6SMark Murray 			break;
95413e3f4d6SMark Murray 		default:
95513e3f4d6SMark Murray 			break;
95613e3f4d6SMark Murray 		}
95713e3f4d6SMark Murray 		break;
95813e3f4d6SMark Murray #endif
95913e3f4d6SMark Murray     default:
96013e3f4d6SMark Murray 	break;
96113e3f4d6SMark Murray     }
96213e3f4d6SMark Murray }
96313e3f4d6SMark Murray 
96413e3f4d6SMark Murray static unsigned char str_lm[] = { IAC, SB, TELOPT_LINEMODE, 0, 0, IAC, SE };
96513e3f4d6SMark Murray 
96613e3f4d6SMark Murray void
lm_will(unsigned char * cmd,int len)96713e3f4d6SMark Murray lm_will(unsigned char *cmd, int len)
96813e3f4d6SMark Murray {
96913e3f4d6SMark Murray     if (len < 1) {
97013e3f4d6SMark Murray /*@*/	printf("lm_will: no command!!!\n");	/* Should not happen... */
97113e3f4d6SMark Murray 	return;
97213e3f4d6SMark Murray     }
97313e3f4d6SMark Murray     switch(cmd[0]) {
97413e3f4d6SMark Murray     case LM_FORWARDMASK:	/* We shouldn't ever get this... */
97513e3f4d6SMark Murray     default:
97613e3f4d6SMark Murray 	str_lm[3] = DONT;
97713e3f4d6SMark Murray 	str_lm[4] = cmd[0];
97813e3f4d6SMark Murray 	if (NETROOM() > sizeof(str_lm)) {
97913e3f4d6SMark Murray 	    ring_supply_data(&netoring, str_lm, sizeof(str_lm));
98013e3f4d6SMark Murray 	    printsub('>', &str_lm[2], sizeof(str_lm)-2);
98113e3f4d6SMark Murray 	}
98213e3f4d6SMark Murray /*@*/	else printf("lm_will: not enough room in buffer\n");
98313e3f4d6SMark Murray 	break;
98413e3f4d6SMark Murray     }
98513e3f4d6SMark Murray }
98613e3f4d6SMark Murray 
98713e3f4d6SMark Murray void
lm_wont(unsigned char * cmd,int len)98813e3f4d6SMark Murray lm_wont(unsigned char *cmd, int len)
98913e3f4d6SMark Murray {
99013e3f4d6SMark Murray     if (len < 1) {
99113e3f4d6SMark Murray /*@*/	printf("lm_wont: no command!!!\n");	/* Should not happen... */
99213e3f4d6SMark Murray 	return;
99313e3f4d6SMark Murray     }
99413e3f4d6SMark Murray     switch(cmd[0]) {
99513e3f4d6SMark Murray     case LM_FORWARDMASK:	/* We shouldn't ever get this... */
99613e3f4d6SMark Murray     default:
99713e3f4d6SMark Murray 	/* We are always DONT, so don't respond */
99813e3f4d6SMark Murray 	return;
99913e3f4d6SMark Murray     }
100013e3f4d6SMark Murray }
100113e3f4d6SMark Murray 
100213e3f4d6SMark Murray void
lm_do(unsigned char * cmd,int len)100313e3f4d6SMark Murray lm_do(unsigned char *cmd, int len)
100413e3f4d6SMark Murray {
100513e3f4d6SMark Murray     if (len < 1) {
100613e3f4d6SMark Murray /*@*/	printf("lm_do: no command!!!\n");	/* Should not happen... */
100713e3f4d6SMark Murray 	return;
100813e3f4d6SMark Murray     }
100913e3f4d6SMark Murray     switch(cmd[0]) {
101013e3f4d6SMark Murray     case LM_FORWARDMASK:
101113e3f4d6SMark Murray     default:
101213e3f4d6SMark Murray 	str_lm[3] = WONT;
101313e3f4d6SMark Murray 	str_lm[4] = cmd[0];
101413e3f4d6SMark Murray 	if (NETROOM() > sizeof(str_lm)) {
101513e3f4d6SMark Murray 	    ring_supply_data(&netoring, str_lm, sizeof(str_lm));
101613e3f4d6SMark Murray 	    printsub('>', &str_lm[2], sizeof(str_lm)-2);
101713e3f4d6SMark Murray 	}
101813e3f4d6SMark Murray /*@*/	else printf("lm_do: not enough room in buffer\n");
101913e3f4d6SMark Murray 	break;
102013e3f4d6SMark Murray     }
102113e3f4d6SMark Murray }
102213e3f4d6SMark Murray 
102313e3f4d6SMark Murray void
lm_dont(unsigned char * cmd,int len)102413e3f4d6SMark Murray lm_dont(unsigned char *cmd, int len)
102513e3f4d6SMark Murray {
102613e3f4d6SMark Murray     if (len < 1) {
102713e3f4d6SMark Murray /*@*/	printf("lm_dont: no command!!!\n");	/* Should not happen... */
102813e3f4d6SMark Murray 	return;
102913e3f4d6SMark Murray     }
103013e3f4d6SMark Murray     switch(cmd[0]) {
103113e3f4d6SMark Murray     case LM_FORWARDMASK:
103213e3f4d6SMark Murray     default:
103313e3f4d6SMark Murray 	/* we are always WONT, so don't respond */
103413e3f4d6SMark Murray 	break;
103513e3f4d6SMark Murray     }
103613e3f4d6SMark Murray }
103713e3f4d6SMark Murray 
103813e3f4d6SMark Murray static unsigned char str_lm_mode[] = {
103913e3f4d6SMark Murray 	IAC, SB, TELOPT_LINEMODE, LM_MODE, 0, IAC, SE
104013e3f4d6SMark Murray };
104113e3f4d6SMark Murray 
104213e3f4d6SMark Murray void
lm_mode(unsigned char * cmd,int len,int init)104313e3f4d6SMark Murray lm_mode(unsigned char *cmd, int len, int init)
104413e3f4d6SMark Murray {
104513e3f4d6SMark Murray 	if (len != 1)
104613e3f4d6SMark Murray 		return;
104713e3f4d6SMark Murray 	if ((linemode&MODE_MASK&~MODE_ACK) == *cmd)
104813e3f4d6SMark Murray 		return;
104913e3f4d6SMark Murray 	if (*cmd&MODE_ACK)
105013e3f4d6SMark Murray 		return;
105113e3f4d6SMark Murray 	linemode = *cmd&(MODE_MASK&~MODE_ACK);
105213e3f4d6SMark Murray 	str_lm_mode[4] = linemode;
105313e3f4d6SMark Murray 	if (!init)
105413e3f4d6SMark Murray 	    str_lm_mode[4] |= MODE_ACK;
105513e3f4d6SMark Murray 	if (NETROOM() > sizeof(str_lm_mode)) {
105613e3f4d6SMark Murray 	    ring_supply_data(&netoring, str_lm_mode, sizeof(str_lm_mode));
105713e3f4d6SMark Murray 	    printsub('>', &str_lm_mode[2], sizeof(str_lm_mode)-2);
105813e3f4d6SMark Murray 	}
105913e3f4d6SMark Murray /*@*/	else printf("lm_mode: not enough room in buffer\n");
106013e3f4d6SMark Murray 	setconnmode(0);	/* set changed mode */
106113e3f4d6SMark Murray }
106213e3f4d6SMark Murray 
106313e3f4d6SMark Murray 
106413e3f4d6SMark Murray 
106513e3f4d6SMark Murray /*
106613e3f4d6SMark Murray  * slc()
106713e3f4d6SMark Murray  * Handle special character suboption of LINEMODE.
106813e3f4d6SMark Murray  */
106913e3f4d6SMark Murray 
107013e3f4d6SMark Murray struct spc {
107113e3f4d6SMark Murray 	cc_t val;
107213e3f4d6SMark Murray 	cc_t *valp;
107313e3f4d6SMark Murray 	char flags;	/* Current flags & level */
107413e3f4d6SMark Murray 	char mylevel;	/* Maximum level & flags */
107513e3f4d6SMark Murray } spc_data[NSLC+1];
107613e3f4d6SMark Murray 
107713e3f4d6SMark Murray #define SLC_IMPORT	0
107813e3f4d6SMark Murray #define	SLC_EXPORT	1
107913e3f4d6SMark Murray #define SLC_RVALUE	2
108013e3f4d6SMark Murray static int slc_mode = SLC_EXPORT;
108113e3f4d6SMark Murray 
108213e3f4d6SMark Murray void
slc_init()108313e3f4d6SMark Murray slc_init()
108413e3f4d6SMark Murray {
108513e3f4d6SMark Murray 	struct spc *spcp;
108613e3f4d6SMark Murray 
108713e3f4d6SMark Murray 	localchars = 1;
108813e3f4d6SMark Murray 	for (spcp = spc_data; spcp < &spc_data[NSLC+1]; spcp++) {
108913e3f4d6SMark Murray 		spcp->val = 0;
109013e3f4d6SMark Murray 		spcp->valp = 0;
109113e3f4d6SMark Murray 		spcp->flags = spcp->mylevel = SLC_NOSUPPORT;
109213e3f4d6SMark Murray 	}
109313e3f4d6SMark Murray 
109413e3f4d6SMark Murray #define	initfunc(func, flags) { \
109513e3f4d6SMark Murray 					spcp = &spc_data[func]; \
109613e3f4d6SMark Murray 					if ((spcp->valp = tcval(func))) { \
109713e3f4d6SMark Murray 					    spcp->val = *spcp->valp; \
109813e3f4d6SMark Murray 					    spcp->mylevel = SLC_VARIABLE|flags; \
109913e3f4d6SMark Murray 					} else { \
110013e3f4d6SMark Murray 					    spcp->val = 0; \
110113e3f4d6SMark Murray 					    spcp->mylevel = SLC_DEFAULT; \
110213e3f4d6SMark Murray 					} \
110313e3f4d6SMark Murray 				    }
110413e3f4d6SMark Murray 
110513e3f4d6SMark Murray 	initfunc(SLC_SYNCH, 0);
110613e3f4d6SMark Murray 	/* No BRK */
110713e3f4d6SMark Murray 	initfunc(SLC_AO, 0);
110813e3f4d6SMark Murray 	initfunc(SLC_AYT, 0);
110913e3f4d6SMark Murray 	/* No EOR */
111013e3f4d6SMark Murray 	initfunc(SLC_ABORT, SLC_FLUSHIN|SLC_FLUSHOUT);
111113e3f4d6SMark Murray 	initfunc(SLC_EOF, 0);
111213e3f4d6SMark Murray 	initfunc(SLC_SUSP, SLC_FLUSHIN);
111313e3f4d6SMark Murray 	initfunc(SLC_EC, 0);
111413e3f4d6SMark Murray 	initfunc(SLC_EL, 0);
111513e3f4d6SMark Murray 	initfunc(SLC_EW, 0);
111613e3f4d6SMark Murray 	initfunc(SLC_RP, 0);
111713e3f4d6SMark Murray 	initfunc(SLC_LNEXT, 0);
111813e3f4d6SMark Murray 	initfunc(SLC_XON, 0);
111913e3f4d6SMark Murray 	initfunc(SLC_XOFF, 0);
112013e3f4d6SMark Murray 	initfunc(SLC_FORW1, 0);
112113e3f4d6SMark Murray 	initfunc(SLC_FORW2, 0);
112213e3f4d6SMark Murray 	/* No FORW2 */
112313e3f4d6SMark Murray 
112413e3f4d6SMark Murray 	initfunc(SLC_IP, SLC_FLUSHIN|SLC_FLUSHOUT);
112513e3f4d6SMark Murray #undef	initfunc
112613e3f4d6SMark Murray 
112713e3f4d6SMark Murray 	if (slc_mode == SLC_EXPORT)
112813e3f4d6SMark Murray 		slc_export();
112913e3f4d6SMark Murray 	else
113013e3f4d6SMark Murray 		slc_import(1);
113113e3f4d6SMark Murray 
113213e3f4d6SMark Murray }
113313e3f4d6SMark Murray 
113413e3f4d6SMark Murray void
slcstate()113513e3f4d6SMark Murray slcstate()
113613e3f4d6SMark Murray {
113713e3f4d6SMark Murray     printf("Special characters are %s values\n",
113813e3f4d6SMark Murray 		slc_mode == SLC_IMPORT ? "remote default" :
113913e3f4d6SMark Murray 		slc_mode == SLC_EXPORT ? "local" :
114013e3f4d6SMark Murray 					 "remote");
114113e3f4d6SMark Murray }
114213e3f4d6SMark Murray 
114313e3f4d6SMark Murray void
slc_mode_export()114413e3f4d6SMark Murray slc_mode_export()
114513e3f4d6SMark Murray {
114613e3f4d6SMark Murray     slc_mode = SLC_EXPORT;
114713e3f4d6SMark Murray     if (my_state_is_will(TELOPT_LINEMODE))
114813e3f4d6SMark Murray 	slc_export();
114913e3f4d6SMark Murray }
115013e3f4d6SMark Murray 
115113e3f4d6SMark Murray void
slc_mode_import(int def)115213e3f4d6SMark Murray slc_mode_import(int def)
115313e3f4d6SMark Murray {
115413e3f4d6SMark Murray     slc_mode = def ? SLC_IMPORT : SLC_RVALUE;
115513e3f4d6SMark Murray     if (my_state_is_will(TELOPT_LINEMODE))
115613e3f4d6SMark Murray 	slc_import(def);
115713e3f4d6SMark Murray }
115813e3f4d6SMark Murray 
115913e3f4d6SMark Murray unsigned char slc_import_val[] = {
116013e3f4d6SMark Murray 	IAC, SB, TELOPT_LINEMODE, LM_SLC, 0, SLC_VARIABLE, 0, IAC, SE
116113e3f4d6SMark Murray };
116213e3f4d6SMark Murray unsigned char slc_import_def[] = {
116313e3f4d6SMark Murray 	IAC, SB, TELOPT_LINEMODE, LM_SLC, 0, SLC_DEFAULT, 0, IAC, SE
116413e3f4d6SMark Murray };
116513e3f4d6SMark Murray 
116613e3f4d6SMark Murray void
slc_import(int def)116713e3f4d6SMark Murray slc_import(int def)
116813e3f4d6SMark Murray {
116913e3f4d6SMark Murray     if (NETROOM() > sizeof(slc_import_val)) {
117013e3f4d6SMark Murray 	if (def) {
117113e3f4d6SMark Murray 	    ring_supply_data(&netoring, slc_import_def, sizeof(slc_import_def));
117213e3f4d6SMark Murray 	    printsub('>', &slc_import_def[2], sizeof(slc_import_def)-2);
117313e3f4d6SMark Murray 	} else {
117413e3f4d6SMark Murray 	    ring_supply_data(&netoring, slc_import_val, sizeof(slc_import_val));
117513e3f4d6SMark Murray 	    printsub('>', &slc_import_val[2], sizeof(slc_import_val)-2);
117613e3f4d6SMark Murray 	}
117713e3f4d6SMark Murray     }
117813e3f4d6SMark Murray /*@*/ else printf("slc_import: not enough room\n");
117913e3f4d6SMark Murray }
118013e3f4d6SMark Murray 
118113e3f4d6SMark Murray void
slc_export()118213e3f4d6SMark Murray slc_export()
118313e3f4d6SMark Murray {
118413e3f4d6SMark Murray     struct spc *spcp;
118513e3f4d6SMark Murray 
118613e3f4d6SMark Murray     TerminalDefaultChars();
118713e3f4d6SMark Murray 
118813e3f4d6SMark Murray     slc_start_reply();
118913e3f4d6SMark Murray     for (spcp = &spc_data[1]; spcp < &spc_data[NSLC+1]; spcp++) {
119013e3f4d6SMark Murray 	if (spcp->mylevel != SLC_NOSUPPORT) {
119113e3f4d6SMark Murray 	    if (spcp->val == (cc_t)(_POSIX_VDISABLE))
119213e3f4d6SMark Murray 		spcp->flags = SLC_NOSUPPORT;
119313e3f4d6SMark Murray 	    else
119413e3f4d6SMark Murray 		spcp->flags = spcp->mylevel;
119513e3f4d6SMark Murray 	    if (spcp->valp)
119613e3f4d6SMark Murray 		spcp->val = *spcp->valp;
119713e3f4d6SMark Murray 	    slc_add_reply(spcp - spc_data, spcp->flags, spcp->val);
119813e3f4d6SMark Murray 	}
119913e3f4d6SMark Murray     }
120013e3f4d6SMark Murray     slc_end_reply();
120113e3f4d6SMark Murray     slc_update();
120213e3f4d6SMark Murray     setconnmode(1);	/* Make sure the character values are set */
120313e3f4d6SMark Murray }
120413e3f4d6SMark Murray 
120513e3f4d6SMark Murray void
slc(unsigned char * cp,int len)120613e3f4d6SMark Murray slc(unsigned char *cp, int len)
120713e3f4d6SMark Murray {
120813e3f4d6SMark Murray 	struct spc *spcp;
120913e3f4d6SMark Murray 	int func,level;
121013e3f4d6SMark Murray 
121113e3f4d6SMark Murray 	slc_start_reply();
121213e3f4d6SMark Murray 
121313e3f4d6SMark Murray 	for (; len >= 3; len -=3, cp +=3) {
121413e3f4d6SMark Murray 
121513e3f4d6SMark Murray 		func = cp[SLC_FUNC];
121613e3f4d6SMark Murray 
121713e3f4d6SMark Murray 		if (func == 0) {
121813e3f4d6SMark Murray 			/*
121913e3f4d6SMark Murray 			 * Client side: always ignore 0 function.
122013e3f4d6SMark Murray 			 */
122113e3f4d6SMark Murray 			continue;
122213e3f4d6SMark Murray 		}
122313e3f4d6SMark Murray 		if (func > NSLC) {
122413e3f4d6SMark Murray 			if ((cp[SLC_FLAGS] & SLC_LEVELBITS) != SLC_NOSUPPORT)
122513e3f4d6SMark Murray 				slc_add_reply(func, SLC_NOSUPPORT, 0);
122613e3f4d6SMark Murray 			continue;
122713e3f4d6SMark Murray 		}
122813e3f4d6SMark Murray 
122913e3f4d6SMark Murray 		spcp = &spc_data[func];
123013e3f4d6SMark Murray 
123113e3f4d6SMark Murray 		level = cp[SLC_FLAGS]&(SLC_LEVELBITS|SLC_ACK);
123213e3f4d6SMark Murray 
123313e3f4d6SMark Murray 		if ((cp[SLC_VALUE] == (unsigned char)spcp->val) &&
123413e3f4d6SMark Murray 		    ((level&SLC_LEVELBITS) == (spcp->flags&SLC_LEVELBITS))) {
123513e3f4d6SMark Murray 			continue;
123613e3f4d6SMark Murray 		}
123713e3f4d6SMark Murray 
123813e3f4d6SMark Murray 		if (level == (SLC_DEFAULT|SLC_ACK)) {
123913e3f4d6SMark Murray 			/*
124013e3f4d6SMark Murray 			 * This is an error condition, the SLC_ACK
124113e3f4d6SMark Murray 			 * bit should never be set for the SLC_DEFAULT
124213e3f4d6SMark Murray 			 * level.  Our best guess to recover is to
124313e3f4d6SMark Murray 			 * ignore the SLC_ACK bit.
124413e3f4d6SMark Murray 			 */
124513e3f4d6SMark Murray 			cp[SLC_FLAGS] &= ~SLC_ACK;
124613e3f4d6SMark Murray 		}
124713e3f4d6SMark Murray 
124813e3f4d6SMark Murray 		if (level == ((spcp->flags&SLC_LEVELBITS)|SLC_ACK)) {
124913e3f4d6SMark Murray 			spcp->val = (cc_t)cp[SLC_VALUE];
125013e3f4d6SMark Murray 			spcp->flags = cp[SLC_FLAGS];	/* include SLC_ACK */
125113e3f4d6SMark Murray 			continue;
125213e3f4d6SMark Murray 		}
125313e3f4d6SMark Murray 
125413e3f4d6SMark Murray 		level &= ~SLC_ACK;
125513e3f4d6SMark Murray 
125613e3f4d6SMark Murray 		if (level <= (spcp->mylevel&SLC_LEVELBITS)) {
125713e3f4d6SMark Murray 			spcp->flags = cp[SLC_FLAGS]|SLC_ACK;
125813e3f4d6SMark Murray 			spcp->val = (cc_t)cp[SLC_VALUE];
125913e3f4d6SMark Murray 		}
126013e3f4d6SMark Murray 		if (level == SLC_DEFAULT) {
126113e3f4d6SMark Murray 			if ((spcp->mylevel&SLC_LEVELBITS) != SLC_DEFAULT)
126213e3f4d6SMark Murray 				spcp->flags = spcp->mylevel;
126313e3f4d6SMark Murray 			else
126413e3f4d6SMark Murray 				spcp->flags = SLC_NOSUPPORT;
126513e3f4d6SMark Murray 		}
126613e3f4d6SMark Murray 		slc_add_reply(func, spcp->flags, spcp->val);
126713e3f4d6SMark Murray 	}
126813e3f4d6SMark Murray 	slc_end_reply();
126913e3f4d6SMark Murray 	if (slc_update())
127013e3f4d6SMark Murray 		setconnmode(1);	/* set the  new character values */
127113e3f4d6SMark Murray }
127213e3f4d6SMark Murray 
127313e3f4d6SMark Murray void
slc_check()127413e3f4d6SMark Murray slc_check()
127513e3f4d6SMark Murray {
127613e3f4d6SMark Murray     struct spc *spcp;
127713e3f4d6SMark Murray 
127813e3f4d6SMark Murray     slc_start_reply();
127913e3f4d6SMark Murray     for (spcp = &spc_data[1]; spcp < &spc_data[NSLC+1]; spcp++) {
128013e3f4d6SMark Murray 	if (spcp->valp && spcp->val != *spcp->valp) {
128113e3f4d6SMark Murray 	    spcp->val = *spcp->valp;
128213e3f4d6SMark Murray 	    if (spcp->val == (cc_t)(_POSIX_VDISABLE))
128313e3f4d6SMark Murray 		spcp->flags = SLC_NOSUPPORT;
128413e3f4d6SMark Murray 	    else
128513e3f4d6SMark Murray 		spcp->flags = spcp->mylevel;
128613e3f4d6SMark Murray 	    slc_add_reply(spcp - spc_data, spcp->flags, spcp->val);
128713e3f4d6SMark Murray 	}
128813e3f4d6SMark Murray     }
128913e3f4d6SMark Murray     slc_end_reply();
129013e3f4d6SMark Murray     setconnmode(1);
129113e3f4d6SMark Murray }
129213e3f4d6SMark Murray 
129313e3f4d6SMark Murray 
129413e3f4d6SMark Murray unsigned char slc_reply[128];
1295c19800e8SDoug Rabson unsigned char const * const slc_reply_eom = &slc_reply[sizeof(slc_reply)];
129613e3f4d6SMark Murray unsigned char *slc_replyp;
129713e3f4d6SMark Murray 
129813e3f4d6SMark Murray void
slc_start_reply()129913e3f4d6SMark Murray slc_start_reply()
130013e3f4d6SMark Murray {
130113e3f4d6SMark Murray 	slc_replyp = slc_reply;
130213e3f4d6SMark Murray 	*slc_replyp++ = IAC;
130313e3f4d6SMark Murray 	*slc_replyp++ = SB;
130413e3f4d6SMark Murray 	*slc_replyp++ = TELOPT_LINEMODE;
130513e3f4d6SMark Murray 	*slc_replyp++ = LM_SLC;
130613e3f4d6SMark Murray }
130713e3f4d6SMark Murray 
130813e3f4d6SMark Murray void
slc_add_reply(unsigned char func,unsigned char flags,cc_t value)130913e3f4d6SMark Murray slc_add_reply(unsigned char func, unsigned char flags, cc_t value)
131013e3f4d6SMark Murray {
1311c19800e8SDoug Rabson 	/* A sequence of up to 6 bytes my be written for this member of the SLC
1312c19800e8SDoug Rabson 	 * suboption list by this function.  The end of negotiation command,
1313c19800e8SDoug Rabson 	 * which is written by slc_end_reply(), will require 2 additional
1314c19800e8SDoug Rabson 	 * bytes.  Do not proceed unless there is sufficient space for these
1315c19800e8SDoug Rabson 	 * items.
1316c19800e8SDoug Rabson 	 */
1317c19800e8SDoug Rabson 	if (&slc_replyp[6+2] > slc_reply_eom)
1318c19800e8SDoug Rabson 		return;
131913e3f4d6SMark Murray 	if ((*slc_replyp++ = func) == IAC)
132013e3f4d6SMark Murray 		*slc_replyp++ = IAC;
132113e3f4d6SMark Murray 	if ((*slc_replyp++ = flags) == IAC)
132213e3f4d6SMark Murray 		*slc_replyp++ = IAC;
132313e3f4d6SMark Murray 	if ((*slc_replyp++ = (unsigned char)value) == IAC)
132413e3f4d6SMark Murray 		*slc_replyp++ = IAC;
132513e3f4d6SMark Murray }
132613e3f4d6SMark Murray 
132713e3f4d6SMark Murray void
slc_end_reply()132813e3f4d6SMark Murray slc_end_reply()
132913e3f4d6SMark Murray {
133013e3f4d6SMark Murray     int len;
133113e3f4d6SMark Murray 
1332c19800e8SDoug Rabson     /* The end of negotiation command requires 2 bytes. */
1333c19800e8SDoug Rabson     if (&slc_replyp[2] > slc_reply_eom)
1334c19800e8SDoug Rabson             return;
133513e3f4d6SMark Murray     *slc_replyp++ = IAC;
133613e3f4d6SMark Murray     *slc_replyp++ = SE;
133713e3f4d6SMark Murray     len = slc_replyp - slc_reply;
133813e3f4d6SMark Murray     if (len <= 6)
133913e3f4d6SMark Murray 	return;
134013e3f4d6SMark Murray     if (NETROOM() > len) {
134113e3f4d6SMark Murray 	ring_supply_data(&netoring, slc_reply, slc_replyp - slc_reply);
134213e3f4d6SMark Murray 	printsub('>', &slc_reply[2], slc_replyp - slc_reply - 2);
134313e3f4d6SMark Murray     }
134413e3f4d6SMark Murray /*@*/else printf("slc_end_reply: not enough room\n");
134513e3f4d6SMark Murray }
134613e3f4d6SMark Murray 
134713e3f4d6SMark Murray int
slc_update()134813e3f4d6SMark Murray slc_update()
134913e3f4d6SMark Murray {
135013e3f4d6SMark Murray 	struct spc *spcp;
135113e3f4d6SMark Murray 	int need_update = 0;
135213e3f4d6SMark Murray 
135313e3f4d6SMark Murray 	for (spcp = &spc_data[1]; spcp < &spc_data[NSLC+1]; spcp++) {
135413e3f4d6SMark Murray 		if (!(spcp->flags&SLC_ACK))
135513e3f4d6SMark Murray 			continue;
135613e3f4d6SMark Murray 		spcp->flags &= ~SLC_ACK;
135713e3f4d6SMark Murray 		if (spcp->valp && (*spcp->valp != spcp->val)) {
135813e3f4d6SMark Murray 			*spcp->valp = spcp->val;
135913e3f4d6SMark Murray 			need_update = 1;
136013e3f4d6SMark Murray 		}
136113e3f4d6SMark Murray 	}
136213e3f4d6SMark Murray 	return(need_update);
136313e3f4d6SMark Murray }
136413e3f4d6SMark Murray 
136513e3f4d6SMark Murray #ifdef	OLD_ENVIRON
136613e3f4d6SMark Murray #  define old_env_var OLD_ENV_VAR
136713e3f4d6SMark Murray #  define old_env_value OLD_ENV_VALUE
136813e3f4d6SMark Murray #endif
136913e3f4d6SMark Murray 
137013e3f4d6SMark Murray void
env_opt(unsigned char * buf,int len)137113e3f4d6SMark Murray env_opt(unsigned char *buf, int len)
137213e3f4d6SMark Murray {
137313e3f4d6SMark Murray 	unsigned char *ep = 0, *epc = 0;
137413e3f4d6SMark Murray 	int i;
137513e3f4d6SMark Murray 
137613e3f4d6SMark Murray 	switch(buf[0]&0xff) {
137713e3f4d6SMark Murray 	case TELQUAL_SEND:
137813e3f4d6SMark Murray 		env_opt_start();
137913e3f4d6SMark Murray 		if (len == 1) {
138013e3f4d6SMark Murray 			env_opt_add(NULL);
138113e3f4d6SMark Murray 		} else for (i = 1; i < len; i++) {
138213e3f4d6SMark Murray 			switch (buf[i]&0xff) {
138313e3f4d6SMark Murray #ifdef	OLD_ENVIRON
138413e3f4d6SMark Murray 			case OLD_ENV_VAR:
138513e3f4d6SMark Murray 			case OLD_ENV_VALUE:
138613e3f4d6SMark Murray 				/*
138713e3f4d6SMark Murray 				 * Although OLD_ENV_VALUE is not legal, we will
138813e3f4d6SMark Murray 				 * still recognize it, just in case it is an
138913e3f4d6SMark Murray 				 * old server that has VAR & VALUE mixed up...
139013e3f4d6SMark Murray 				 */
139113e3f4d6SMark Murray 				/* FALL THROUGH */
139213e3f4d6SMark Murray #else
139313e3f4d6SMark Murray 			case NEW_ENV_VAR:
139413e3f4d6SMark Murray #endif
139513e3f4d6SMark Murray 			case ENV_USERVAR:
139613e3f4d6SMark Murray 				if (ep) {
139713e3f4d6SMark Murray 					*epc = 0;
139813e3f4d6SMark Murray 					env_opt_add(ep);
139913e3f4d6SMark Murray 				}
140013e3f4d6SMark Murray 				ep = epc = &buf[i+1];
140113e3f4d6SMark Murray 				break;
140213e3f4d6SMark Murray 			case ENV_ESC:
140313e3f4d6SMark Murray 				i++;
140413e3f4d6SMark Murray 				/*FALL THROUGH*/
140513e3f4d6SMark Murray 			default:
140613e3f4d6SMark Murray 				if (epc)
140713e3f4d6SMark Murray 					*epc++ = buf[i];
140813e3f4d6SMark Murray 				break;
140913e3f4d6SMark Murray 			}
141013e3f4d6SMark Murray 		}
141113e3f4d6SMark Murray 		if (ep) {
141213e3f4d6SMark Murray 			*epc = 0;
141313e3f4d6SMark Murray 			env_opt_add(ep);
141413e3f4d6SMark Murray 		}
141513e3f4d6SMark Murray 		env_opt_end(1);
141613e3f4d6SMark Murray 		break;
141713e3f4d6SMark Murray 
141813e3f4d6SMark Murray 	case TELQUAL_IS:
141913e3f4d6SMark Murray 	case TELQUAL_INFO:
142013e3f4d6SMark Murray 		/* Ignore for now.  We shouldn't get it anyway. */
142113e3f4d6SMark Murray 		break;
142213e3f4d6SMark Murray 
142313e3f4d6SMark Murray 	default:
142413e3f4d6SMark Murray 		break;
142513e3f4d6SMark Murray 	}
142613e3f4d6SMark Murray }
142713e3f4d6SMark Murray 
1428c19800e8SDoug Rabson #define	OPT_REPLY_SIZE	(2 * SUBBUFSIZE)
142913e3f4d6SMark Murray unsigned char *opt_reply;
143013e3f4d6SMark Murray unsigned char *opt_replyp;
143113e3f4d6SMark Murray unsigned char *opt_replyend;
143213e3f4d6SMark Murray 
143313e3f4d6SMark Murray void
env_opt_start()143413e3f4d6SMark Murray env_opt_start()
143513e3f4d6SMark Murray {
143613e3f4d6SMark Murray 	if (opt_reply) {
143713e3f4d6SMark Murray 		void *tmp = realloc (opt_reply, OPT_REPLY_SIZE);
143813e3f4d6SMark Murray 		if (tmp != NULL) {
143913e3f4d6SMark Murray 			opt_reply = tmp;
144013e3f4d6SMark Murray 		} else {
144113e3f4d6SMark Murray 			free (opt_reply);
144213e3f4d6SMark Murray 			opt_reply = NULL;
144313e3f4d6SMark Murray 		}
144413e3f4d6SMark Murray 	} else
144513e3f4d6SMark Murray 		opt_reply = (unsigned char *)malloc(OPT_REPLY_SIZE);
144613e3f4d6SMark Murray 	if (opt_reply == NULL) {
144713e3f4d6SMark Murray /*@*/		printf("env_opt_start: malloc()/realloc() failed!!!\n");
144813e3f4d6SMark Murray 		opt_reply = opt_replyp = opt_replyend = NULL;
144913e3f4d6SMark Murray 		return;
145013e3f4d6SMark Murray 	}
145113e3f4d6SMark Murray 	opt_replyp = opt_reply;
145213e3f4d6SMark Murray 	opt_replyend = opt_reply + OPT_REPLY_SIZE;
145313e3f4d6SMark Murray 	*opt_replyp++ = IAC;
145413e3f4d6SMark Murray 	*opt_replyp++ = SB;
145513e3f4d6SMark Murray 	*opt_replyp++ = telopt_environ;
145613e3f4d6SMark Murray 	*opt_replyp++ = TELQUAL_IS;
145713e3f4d6SMark Murray }
145813e3f4d6SMark Murray 
145913e3f4d6SMark Murray void
env_opt_start_info()146013e3f4d6SMark Murray env_opt_start_info()
146113e3f4d6SMark Murray {
146213e3f4d6SMark Murray 	env_opt_start();
146313e3f4d6SMark Murray 	if (opt_replyp)
146413e3f4d6SMark Murray 	    opt_replyp[-1] = TELQUAL_INFO;
146513e3f4d6SMark Murray }
146613e3f4d6SMark Murray 
146713e3f4d6SMark Murray void
env_opt_add(unsigned char * ep)146813e3f4d6SMark Murray env_opt_add(unsigned char *ep)
146913e3f4d6SMark Murray {
147013e3f4d6SMark Murray 	unsigned char *vp, c;
147113e3f4d6SMark Murray 
147213e3f4d6SMark Murray 	if (opt_reply == NULL)		/*XXX*/
147313e3f4d6SMark Murray 		return;			/*XXX*/
147413e3f4d6SMark Murray 
147513e3f4d6SMark Murray 	if (ep == NULL || *ep == '\0') {
147613e3f4d6SMark Murray 		/* Send user defined variables first. */
147713e3f4d6SMark Murray 		env_default(1, 0);
147813e3f4d6SMark Murray 		while ((ep = env_default(0, 0)))
147913e3f4d6SMark Murray 			env_opt_add(ep);
148013e3f4d6SMark Murray 
148113e3f4d6SMark Murray 		/* Now add the list of well know variables.  */
148213e3f4d6SMark Murray 		env_default(1, 1);
148313e3f4d6SMark Murray 		while ((ep = env_default(0, 1)))
148413e3f4d6SMark Murray 			env_opt_add(ep);
148513e3f4d6SMark Murray 		return;
148613e3f4d6SMark Murray 	}
148713e3f4d6SMark Murray 	vp = env_getvalue(ep);
1488c19800e8SDoug Rabson         if (opt_replyp + (vp ? 2 * strlen((char *)vp) : 0) +
1489c19800e8SDoug Rabson                                 2 * strlen((char *)ep) + 6 > opt_replyend)
149013e3f4d6SMark Murray         {
149113e3f4d6SMark Murray 		int len;
149213e3f4d6SMark Murray 		void *tmp;
149313e3f4d6SMark Murray 		opt_replyend += OPT_REPLY_SIZE;
149413e3f4d6SMark Murray 		len = opt_replyend - opt_reply;
149513e3f4d6SMark Murray 		tmp = realloc(opt_reply, len);
149613e3f4d6SMark Murray 		if (tmp == NULL) {
149713e3f4d6SMark Murray /*@*/			printf("env_opt_add: realloc() failed!!!\n");
149813e3f4d6SMark Murray 			opt_reply = opt_replyp = opt_replyend = NULL;
149913e3f4d6SMark Murray 			return;
150013e3f4d6SMark Murray 		}
150113e3f4d6SMark Murray 		opt_reply = tmp;
150213e3f4d6SMark Murray 		opt_replyp = opt_reply + len - (opt_replyend - opt_replyp);
150313e3f4d6SMark Murray 		opt_replyend = opt_reply + len;
150413e3f4d6SMark Murray 	}
150513e3f4d6SMark Murray 	if (opt_welldefined((char *)ep)) {
150613e3f4d6SMark Murray #ifdef	OLD_ENVIRON
150713e3f4d6SMark Murray 		if (telopt_environ == TELOPT_OLD_ENVIRON)
150813e3f4d6SMark Murray 			*opt_replyp++ = old_env_var;
150913e3f4d6SMark Murray 		else
151013e3f4d6SMark Murray #endif
151113e3f4d6SMark Murray 			*opt_replyp++ = NEW_ENV_VAR;
151213e3f4d6SMark Murray 	} else
151313e3f4d6SMark Murray 		*opt_replyp++ = ENV_USERVAR;
151413e3f4d6SMark Murray 	for (;;) {
151513e3f4d6SMark Murray 		while ((c = *ep++)) {
1516c19800e8SDoug Rabson 			if (opt_replyp + (2 + 2) > opt_replyend)
1517c19800e8SDoug Rabson 				return;
151813e3f4d6SMark Murray 			switch(c&0xff) {
151913e3f4d6SMark Murray 			case IAC:
152013e3f4d6SMark Murray 				*opt_replyp++ = IAC;
152113e3f4d6SMark Murray 				break;
152213e3f4d6SMark Murray 			case NEW_ENV_VAR:
152313e3f4d6SMark Murray 			case NEW_ENV_VALUE:
152413e3f4d6SMark Murray 			case ENV_ESC:
152513e3f4d6SMark Murray 			case ENV_USERVAR:
152613e3f4d6SMark Murray 				*opt_replyp++ = ENV_ESC;
152713e3f4d6SMark Murray 				break;
152813e3f4d6SMark Murray 			}
152913e3f4d6SMark Murray 			*opt_replyp++ = c;
153013e3f4d6SMark Murray 		}
153113e3f4d6SMark Murray 		if ((ep = vp)) {
1532c19800e8SDoug Rabson 			if (opt_replyp + (1 + 2 + 2) > opt_replyend)
1533c19800e8SDoug Rabson 				return;
153413e3f4d6SMark Murray #ifdef	OLD_ENVIRON
153513e3f4d6SMark Murray 			if (telopt_environ == TELOPT_OLD_ENVIRON)
153613e3f4d6SMark Murray 				*opt_replyp++ = old_env_value;
153713e3f4d6SMark Murray 			else
153813e3f4d6SMark Murray #endif
153913e3f4d6SMark Murray 				*opt_replyp++ = NEW_ENV_VALUE;
154013e3f4d6SMark Murray 			vp = NULL;
154113e3f4d6SMark Murray 		} else
154213e3f4d6SMark Murray 			break;
154313e3f4d6SMark Murray 	}
154413e3f4d6SMark Murray }
154513e3f4d6SMark Murray 
154613e3f4d6SMark Murray int
opt_welldefined(char * ep)154713e3f4d6SMark Murray opt_welldefined(char *ep)
154813e3f4d6SMark Murray {
154913e3f4d6SMark Murray 	if ((strcmp(ep, "USER") == 0) ||
155013e3f4d6SMark Murray 	    (strcmp(ep, "DISPLAY") == 0) ||
155113e3f4d6SMark Murray 	    (strcmp(ep, "PRINTER") == 0) ||
155213e3f4d6SMark Murray 	    (strcmp(ep, "SYSTEMTYPE") == 0) ||
155313e3f4d6SMark Murray 	    (strcmp(ep, "JOB") == 0) ||
155413e3f4d6SMark Murray 	    (strcmp(ep, "ACCT") == 0))
155513e3f4d6SMark Murray 		return(1);
155613e3f4d6SMark Murray 	return(0);
155713e3f4d6SMark Murray }
155813e3f4d6SMark Murray 
155913e3f4d6SMark Murray void
env_opt_end(int emptyok)156013e3f4d6SMark Murray env_opt_end(int emptyok)
156113e3f4d6SMark Murray {
156213e3f4d6SMark Murray 	int len;
156313e3f4d6SMark Murray 
1564c19800e8SDoug Rabson 	if (opt_replyp + 2 > opt_replyend)
1565c19800e8SDoug Rabson 		return;
1566c19800e8SDoug Rabson 	len = opt_replyp + 2 - opt_reply;
156713e3f4d6SMark Murray 	if (emptyok || len > 6) {
156813e3f4d6SMark Murray 		*opt_replyp++ = IAC;
156913e3f4d6SMark Murray 		*opt_replyp++ = SE;
157013e3f4d6SMark Murray 		if (NETROOM() > len) {
157113e3f4d6SMark Murray 			ring_supply_data(&netoring, opt_reply, len);
157213e3f4d6SMark Murray 			printsub('>', &opt_reply[2], len - 2);
157313e3f4d6SMark Murray 		}
157413e3f4d6SMark Murray /*@*/		else printf("slc_end_reply: not enough room\n");
157513e3f4d6SMark Murray 	}
157613e3f4d6SMark Murray 	if (opt_reply) {
157713e3f4d6SMark Murray 		free(opt_reply);
157813e3f4d6SMark Murray 		opt_reply = opt_replyp = opt_replyend = NULL;
157913e3f4d6SMark Murray 	}
158013e3f4d6SMark Murray }
158113e3f4d6SMark Murray 
158213e3f4d6SMark Murray 
158313e3f4d6SMark Murray 
158413e3f4d6SMark Murray int
telrcv(void)158513e3f4d6SMark Murray telrcv(void)
158613e3f4d6SMark Murray {
158713e3f4d6SMark Murray     int c;
158813e3f4d6SMark Murray     int scc;
158913e3f4d6SMark Murray     unsigned char *sbp = NULL;
159013e3f4d6SMark Murray     int count;
159113e3f4d6SMark Murray     int returnValue = 0;
159213e3f4d6SMark Murray 
159313e3f4d6SMark Murray     scc = 0;
159413e3f4d6SMark Murray     count = 0;
159513e3f4d6SMark Murray     while (TTYROOM() > 2) {
159613e3f4d6SMark Murray 	if (scc == 0) {
159713e3f4d6SMark Murray 	    if (count) {
159813e3f4d6SMark Murray 		ring_consumed(&netiring, count);
159913e3f4d6SMark Murray 		returnValue = 1;
160013e3f4d6SMark Murray 		count = 0;
160113e3f4d6SMark Murray 	    }
160213e3f4d6SMark Murray 	    sbp = netiring.consume;
160313e3f4d6SMark Murray 	    scc = ring_full_consecutive(&netiring);
160413e3f4d6SMark Murray 	    if (scc == 0) {
160513e3f4d6SMark Murray 		/* No more data coming in */
160613e3f4d6SMark Murray 		break;
160713e3f4d6SMark Murray 	    }
160813e3f4d6SMark Murray 	}
160913e3f4d6SMark Murray 
161013e3f4d6SMark Murray 	c = *sbp++ & 0xff, scc--; count++;
161113e3f4d6SMark Murray #if	defined(ENCRYPTION)
161213e3f4d6SMark Murray 	if (decrypt_input)
161313e3f4d6SMark Murray 		c = (*decrypt_input)(c);
161413e3f4d6SMark Murray #endif
161513e3f4d6SMark Murray 
161613e3f4d6SMark Murray 	switch (telrcv_state) {
161713e3f4d6SMark Murray 
161813e3f4d6SMark Murray 	case TS_CR:
161913e3f4d6SMark Murray 	    telrcv_state = TS_DATA;
162013e3f4d6SMark Murray 	    if (c == '\0') {
162113e3f4d6SMark Murray 		break;	/* Ignore \0 after CR */
162213e3f4d6SMark Murray 	    }
162313e3f4d6SMark Murray 	    else if ((c == '\n') && my_want_state_is_dont(TELOPT_ECHO) && !crmod) {
162413e3f4d6SMark Murray 		TTYADD(c);
162513e3f4d6SMark Murray 		break;
162613e3f4d6SMark Murray 	    }
162713e3f4d6SMark Murray 	    /* Else, fall through */
162813e3f4d6SMark Murray 
162913e3f4d6SMark Murray 	case TS_DATA:
163013e3f4d6SMark Murray 	    if (c == IAC) {
163113e3f4d6SMark Murray 		telrcv_state = TS_IAC;
163213e3f4d6SMark Murray 		break;
163313e3f4d6SMark Murray 	    }
163413e3f4d6SMark Murray 		    /*
163513e3f4d6SMark Murray 		     * The 'crmod' hack (see following) is needed
163613e3f4d6SMark Murray 		     * since we can't set CRMOD on output only.
163713e3f4d6SMark Murray 		     * Machines like MULTICS like to send \r without
163813e3f4d6SMark Murray 		     * \n; since we must turn off CRMOD to get proper
163913e3f4d6SMark Murray 		     * input, the mapping is done here (sigh).
164013e3f4d6SMark Murray 		     */
164113e3f4d6SMark Murray 	    if ((c == '\r') && my_want_state_is_dont(TELOPT_BINARY)) {
164213e3f4d6SMark Murray 		if (scc > 0) {
164313e3f4d6SMark Murray 		    c = *sbp&0xff;
164413e3f4d6SMark Murray #if	defined(ENCRYPTION)
164513e3f4d6SMark Murray 		    if (decrypt_input)
164613e3f4d6SMark Murray 			c = (*decrypt_input)(c);
164713e3f4d6SMark Murray #endif
164813e3f4d6SMark Murray 		    if (c == 0) {
164913e3f4d6SMark Murray 			sbp++, scc--; count++;
165013e3f4d6SMark Murray 			/* a "true" CR */
165113e3f4d6SMark Murray 			TTYADD('\r');
165213e3f4d6SMark Murray 		    } else if (my_want_state_is_dont(TELOPT_ECHO) &&
165313e3f4d6SMark Murray 					(c == '\n')) {
165413e3f4d6SMark Murray 			sbp++, scc--; count++;
165513e3f4d6SMark Murray 			TTYADD('\n');
165613e3f4d6SMark Murray 		    } else {
165713e3f4d6SMark Murray #if	defined(ENCRYPTION)
165813e3f4d6SMark Murray 		        if (decrypt_input)
165913e3f4d6SMark Murray 			    (*decrypt_input)(-1);
166013e3f4d6SMark Murray #endif
166113e3f4d6SMark Murray 
166213e3f4d6SMark Murray 			TTYADD('\r');
166313e3f4d6SMark Murray 			if (crmod) {
166413e3f4d6SMark Murray 				TTYADD('\n');
166513e3f4d6SMark Murray 			}
166613e3f4d6SMark Murray 		    }
166713e3f4d6SMark Murray 		} else {
166813e3f4d6SMark Murray 		    telrcv_state = TS_CR;
166913e3f4d6SMark Murray 		    TTYADD('\r');
167013e3f4d6SMark Murray 		    if (crmod) {
167113e3f4d6SMark Murray 			    TTYADD('\n');
167213e3f4d6SMark Murray 		    }
167313e3f4d6SMark Murray 		}
167413e3f4d6SMark Murray 	    } else {
167513e3f4d6SMark Murray 		TTYADD(c);
167613e3f4d6SMark Murray 	    }
167713e3f4d6SMark Murray 	    continue;
167813e3f4d6SMark Murray 
167913e3f4d6SMark Murray 	case TS_IAC:
168013e3f4d6SMark Murray process_iac:
168113e3f4d6SMark Murray 	    switch (c) {
168213e3f4d6SMark Murray 
168313e3f4d6SMark Murray 	    case WILL:
168413e3f4d6SMark Murray 		telrcv_state = TS_WILL;
168513e3f4d6SMark Murray 		continue;
168613e3f4d6SMark Murray 
168713e3f4d6SMark Murray 	    case WONT:
168813e3f4d6SMark Murray 		telrcv_state = TS_WONT;
168913e3f4d6SMark Murray 		continue;
169013e3f4d6SMark Murray 
169113e3f4d6SMark Murray 	    case DO:
169213e3f4d6SMark Murray 		telrcv_state = TS_DO;
169313e3f4d6SMark Murray 		continue;
169413e3f4d6SMark Murray 
169513e3f4d6SMark Murray 	    case DONT:
169613e3f4d6SMark Murray 		telrcv_state = TS_DONT;
169713e3f4d6SMark Murray 		continue;
169813e3f4d6SMark Murray 
169913e3f4d6SMark Murray 	    case DM:
170013e3f4d6SMark Murray 		    /*
170113e3f4d6SMark Murray 		     * We may have missed an urgent notification,
170213e3f4d6SMark Murray 		     * so make sure we flush whatever is in the
170313e3f4d6SMark Murray 		     * buffer currently.
170413e3f4d6SMark Murray 		     */
170513e3f4d6SMark Murray 		printoption("RCVD", IAC, DM);
170613e3f4d6SMark Murray 		SYNCHing = 1;
170713e3f4d6SMark Murray 		ttyflush(1);
170813e3f4d6SMark Murray 		SYNCHing = stilloob();
170913e3f4d6SMark Murray 		settimer(gotDM);
171013e3f4d6SMark Murray 		break;
171113e3f4d6SMark Murray 
171213e3f4d6SMark Murray 	    case SB:
171313e3f4d6SMark Murray 		SB_CLEAR();
171413e3f4d6SMark Murray 		telrcv_state = TS_SB;
171513e3f4d6SMark Murray 		continue;
171613e3f4d6SMark Murray 
171713e3f4d6SMark Murray 
171813e3f4d6SMark Murray 	    case IAC:
171913e3f4d6SMark Murray 		TTYADD(IAC);
172013e3f4d6SMark Murray 		break;
172113e3f4d6SMark Murray 
172213e3f4d6SMark Murray 	    case NOP:
172313e3f4d6SMark Murray 	    case GA:
172413e3f4d6SMark Murray 	    default:
172513e3f4d6SMark Murray 		printoption("RCVD", IAC, c);
172613e3f4d6SMark Murray 		break;
172713e3f4d6SMark Murray 	    }
172813e3f4d6SMark Murray 	    telrcv_state = TS_DATA;
172913e3f4d6SMark Murray 	    continue;
173013e3f4d6SMark Murray 
173113e3f4d6SMark Murray 	case TS_WILL:
173213e3f4d6SMark Murray 	    printoption("RCVD", WILL, c);
173313e3f4d6SMark Murray 	    willoption(c);
173413e3f4d6SMark Murray 	    telrcv_state = TS_DATA;
173513e3f4d6SMark Murray 	    continue;
173613e3f4d6SMark Murray 
173713e3f4d6SMark Murray 	case TS_WONT:
173813e3f4d6SMark Murray 	    printoption("RCVD", WONT, c);
173913e3f4d6SMark Murray 	    wontoption(c);
174013e3f4d6SMark Murray 	    telrcv_state = TS_DATA;
174113e3f4d6SMark Murray 	    continue;
174213e3f4d6SMark Murray 
174313e3f4d6SMark Murray 	case TS_DO:
174413e3f4d6SMark Murray 	    printoption("RCVD", DO, c);
174513e3f4d6SMark Murray 	    dooption(c);
174613e3f4d6SMark Murray 	    if (c == TELOPT_NAWS) {
174713e3f4d6SMark Murray 		sendnaws();
174813e3f4d6SMark Murray 	    } else if (c == TELOPT_LFLOW) {
174913e3f4d6SMark Murray 		localflow = 1;
175013e3f4d6SMark Murray 		setcommandmode();
175113e3f4d6SMark Murray 		setconnmode(0);
175213e3f4d6SMark Murray 	    }
175313e3f4d6SMark Murray 	    telrcv_state = TS_DATA;
175413e3f4d6SMark Murray 	    continue;
175513e3f4d6SMark Murray 
175613e3f4d6SMark Murray 	case TS_DONT:
175713e3f4d6SMark Murray 	    printoption("RCVD", DONT, c);
175813e3f4d6SMark Murray 	    dontoption(c);
175913e3f4d6SMark Murray 	    flushline = 1;
176013e3f4d6SMark Murray 	    setconnmode(0);	/* set new tty mode (maybe) */
176113e3f4d6SMark Murray 	    telrcv_state = TS_DATA;
176213e3f4d6SMark Murray 	    continue;
176313e3f4d6SMark Murray 
176413e3f4d6SMark Murray 	case TS_SB:
176513e3f4d6SMark Murray 	    if (c == IAC) {
176613e3f4d6SMark Murray 		telrcv_state = TS_SE;
176713e3f4d6SMark Murray 	    } else {
176813e3f4d6SMark Murray 		SB_ACCUM(c);
176913e3f4d6SMark Murray 	    }
177013e3f4d6SMark Murray 	    continue;
177113e3f4d6SMark Murray 
177213e3f4d6SMark Murray 	case TS_SE:
177313e3f4d6SMark Murray 	    if (c != SE) {
177413e3f4d6SMark Murray 		if (c != IAC) {
177513e3f4d6SMark Murray 		    /*
177613e3f4d6SMark Murray 		     * This is an error.  We only expect to get
177713e3f4d6SMark Murray 		     * "IAC IAC" or "IAC SE".  Several things may
1778c19800e8SDoug Rabson 		     * have happened.  An IAC was not doubled, the
177913e3f4d6SMark Murray 		     * IAC SE was left off, or another option got
178013e3f4d6SMark Murray 		     * inserted into the suboption are all possibilities.
178113e3f4d6SMark Murray 		     * If we assume that the IAC was not doubled,
178213e3f4d6SMark Murray 		     * and really the IAC SE was left off, we could
1783c19800e8SDoug Rabson 		     * get into an infinite loop here.  So, instead,
178413e3f4d6SMark Murray 		     * we terminate the suboption, and process the
178513e3f4d6SMark Murray 		     * partial suboption if we can.
178613e3f4d6SMark Murray 		     */
178713e3f4d6SMark Murray 		    SB_ACCUM(IAC);
178813e3f4d6SMark Murray 		    SB_ACCUM(c);
178913e3f4d6SMark Murray 		    subpointer -= 2;
179013e3f4d6SMark Murray 		    SB_TERM();
179113e3f4d6SMark Murray 
179213e3f4d6SMark Murray 		    printoption("In SUBOPTION processing, RCVD", IAC, c);
179313e3f4d6SMark Murray 		    suboption();	/* handle sub-option */
179413e3f4d6SMark Murray 		    telrcv_state = TS_IAC;
179513e3f4d6SMark Murray 		    goto process_iac;
179613e3f4d6SMark Murray 		}
179713e3f4d6SMark Murray 		SB_ACCUM(c);
179813e3f4d6SMark Murray 		telrcv_state = TS_SB;
179913e3f4d6SMark Murray 	    } else {
180013e3f4d6SMark Murray 		SB_ACCUM(IAC);
180113e3f4d6SMark Murray 		SB_ACCUM(SE);
180213e3f4d6SMark Murray 		subpointer -= 2;
180313e3f4d6SMark Murray 		SB_TERM();
180413e3f4d6SMark Murray 		suboption();	/* handle sub-option */
180513e3f4d6SMark Murray 		telrcv_state = TS_DATA;
180613e3f4d6SMark Murray 	    }
180713e3f4d6SMark Murray 	}
180813e3f4d6SMark Murray     }
180913e3f4d6SMark Murray     if (count)
181013e3f4d6SMark Murray 	ring_consumed(&netiring, count);
181113e3f4d6SMark Murray     return returnValue||count;
181213e3f4d6SMark Murray }
181313e3f4d6SMark Murray 
181413e3f4d6SMark Murray static int bol = 1, local = 0;
181513e3f4d6SMark Murray 
181613e3f4d6SMark Murray int
rlogin_susp(void)181713e3f4d6SMark Murray rlogin_susp(void)
181813e3f4d6SMark Murray {
181913e3f4d6SMark Murray     if (local) {
182013e3f4d6SMark Murray 	local = 0;
182113e3f4d6SMark Murray 	bol = 1;
182213e3f4d6SMark Murray 	command(0, "z\n", 2);
182313e3f4d6SMark Murray 	return(1);
182413e3f4d6SMark Murray     }
182513e3f4d6SMark Murray     return(0);
182613e3f4d6SMark Murray }
182713e3f4d6SMark Murray 
182813e3f4d6SMark Murray static int
telsnd()182913e3f4d6SMark Murray telsnd()
183013e3f4d6SMark Murray {
183113e3f4d6SMark Murray     int tcc;
183213e3f4d6SMark Murray     int count;
183313e3f4d6SMark Murray     int returnValue = 0;
183413e3f4d6SMark Murray     unsigned char *tbp = NULL;
183513e3f4d6SMark Murray 
183613e3f4d6SMark Murray     tcc = 0;
183713e3f4d6SMark Murray     count = 0;
183813e3f4d6SMark Murray     while (NETROOM() > 2) {
183913e3f4d6SMark Murray 	int sc;
184013e3f4d6SMark Murray 	int c;
184113e3f4d6SMark Murray 
184213e3f4d6SMark Murray 	if (tcc == 0) {
184313e3f4d6SMark Murray 	    if (count) {
184413e3f4d6SMark Murray 		ring_consumed(&ttyiring, count);
184513e3f4d6SMark Murray 		returnValue = 1;
184613e3f4d6SMark Murray 		count = 0;
184713e3f4d6SMark Murray 	    }
184813e3f4d6SMark Murray 	    tbp = ttyiring.consume;
184913e3f4d6SMark Murray 	    tcc = ring_full_consecutive(&ttyiring);
185013e3f4d6SMark Murray 	    if (tcc == 0) {
185113e3f4d6SMark Murray 		break;
185213e3f4d6SMark Murray 	    }
185313e3f4d6SMark Murray 	}
185413e3f4d6SMark Murray 	c = *tbp++ & 0xff, sc = strip(c), tcc--; count++;
185513e3f4d6SMark Murray 	if (rlogin != _POSIX_VDISABLE) {
185613e3f4d6SMark Murray 		if (bol) {
185713e3f4d6SMark Murray 			bol = 0;
185813e3f4d6SMark Murray 			if (sc == rlogin) {
185913e3f4d6SMark Murray 				local = 1;
186013e3f4d6SMark Murray 				continue;
186113e3f4d6SMark Murray 			}
186213e3f4d6SMark Murray 		} else if (local) {
186313e3f4d6SMark Murray 			local = 0;
186413e3f4d6SMark Murray 			if (sc == '.' || c == termEofChar) {
186513e3f4d6SMark Murray 				bol = 1;
186613e3f4d6SMark Murray 				command(0, "close\n", 6);
186713e3f4d6SMark Murray 				continue;
186813e3f4d6SMark Murray 			}
186913e3f4d6SMark Murray 			if (sc == termSuspChar) {
187013e3f4d6SMark Murray 				bol = 1;
187113e3f4d6SMark Murray 				command(0, "z\n", 2);
187213e3f4d6SMark Murray 				continue;
187313e3f4d6SMark Murray 			}
187413e3f4d6SMark Murray 			if (sc == escape) {
187513e3f4d6SMark Murray 				command(0, (char *)tbp, tcc);
187613e3f4d6SMark Murray 				bol = 1;
187713e3f4d6SMark Murray 				count += tcc;
187813e3f4d6SMark Murray 				tcc = 0;
187913e3f4d6SMark Murray 				flushline = 1;
188013e3f4d6SMark Murray 				break;
188113e3f4d6SMark Murray 			}
188213e3f4d6SMark Murray 			if (sc != rlogin) {
188313e3f4d6SMark Murray 				++tcc;
188413e3f4d6SMark Murray 				--tbp;
188513e3f4d6SMark Murray 				--count;
188613e3f4d6SMark Murray 				c = sc = rlogin;
188713e3f4d6SMark Murray 			}
188813e3f4d6SMark Murray 		}
188913e3f4d6SMark Murray 		if ((sc == '\n') || (sc == '\r'))
189013e3f4d6SMark Murray 			bol = 1;
189113e3f4d6SMark Murray 	} else if (sc == escape) {
189213e3f4d6SMark Murray 	    /*
189313e3f4d6SMark Murray 	     * Double escape is a pass through of a single escape character.
189413e3f4d6SMark Murray 	     */
189513e3f4d6SMark Murray 	    if (tcc && strip(*tbp) == escape) {
189613e3f4d6SMark Murray 		tbp++;
189713e3f4d6SMark Murray 		tcc--;
189813e3f4d6SMark Murray 		count++;
189913e3f4d6SMark Murray 		bol = 0;
190013e3f4d6SMark Murray 	    } else {
190113e3f4d6SMark Murray 		command(0, (char *)tbp, tcc);
190213e3f4d6SMark Murray 		bol = 1;
190313e3f4d6SMark Murray 		count += tcc;
190413e3f4d6SMark Murray 		tcc = 0;
190513e3f4d6SMark Murray 		flushline = 1;
190613e3f4d6SMark Murray 		break;
190713e3f4d6SMark Murray 	    }
190813e3f4d6SMark Murray 	} else
190913e3f4d6SMark Murray 	    bol = 0;
191013e3f4d6SMark Murray #ifdef	KLUDGELINEMODE
191113e3f4d6SMark Murray 	if (kludgelinemode && (globalmode&MODE_EDIT) && (sc == echoc)) {
191213e3f4d6SMark Murray 	    if (tcc > 0 && strip(*tbp) == echoc) {
191313e3f4d6SMark Murray 		tcc--; tbp++; count++;
191413e3f4d6SMark Murray 	    } else {
191513e3f4d6SMark Murray 		dontlecho = !dontlecho;
191613e3f4d6SMark Murray 		settimer(echotoggle);
191713e3f4d6SMark Murray 		setconnmode(0);
191813e3f4d6SMark Murray 		flushline = 1;
191913e3f4d6SMark Murray 		break;
192013e3f4d6SMark Murray 	    }
192113e3f4d6SMark Murray 	}
192213e3f4d6SMark Murray #endif
192313e3f4d6SMark Murray 	if (MODE_LOCAL_CHARS(globalmode)) {
192413e3f4d6SMark Murray 	    if (TerminalSpecialChars(sc) == 0) {
192513e3f4d6SMark Murray 		bol = 1;
192613e3f4d6SMark Murray 		break;
192713e3f4d6SMark Murray 	    }
192813e3f4d6SMark Murray 	}
192913e3f4d6SMark Murray 	if (my_want_state_is_wont(TELOPT_BINARY)) {
193013e3f4d6SMark Murray 	    switch (c) {
193113e3f4d6SMark Murray 	    case '\n':
193213e3f4d6SMark Murray 		    /*
193313e3f4d6SMark Murray 		     * If we are in CRMOD mode (\r ==> \n)
193413e3f4d6SMark Murray 		     * on our local machine, then probably
193513e3f4d6SMark Murray 		     * a newline (unix) is CRLF (TELNET).
193613e3f4d6SMark Murray 		     */
193713e3f4d6SMark Murray 		if (MODE_LOCAL_CHARS(globalmode)) {
193813e3f4d6SMark Murray 		    NETADD('\r');
193913e3f4d6SMark Murray 		}
194013e3f4d6SMark Murray 		NETADD('\n');
194113e3f4d6SMark Murray 		bol = flushline = 1;
194213e3f4d6SMark Murray 		break;
194313e3f4d6SMark Murray 	    case '\r':
194413e3f4d6SMark Murray 		if (!crlf) {
194513e3f4d6SMark Murray 		    NET2ADD('\r', '\0');
194613e3f4d6SMark Murray 		} else {
194713e3f4d6SMark Murray 		    NET2ADD('\r', '\n');
194813e3f4d6SMark Murray 		}
194913e3f4d6SMark Murray 		bol = flushline = 1;
195013e3f4d6SMark Murray 		break;
195113e3f4d6SMark Murray 	    case IAC:
195213e3f4d6SMark Murray 		NET2ADD(IAC, IAC);
195313e3f4d6SMark Murray 		break;
195413e3f4d6SMark Murray 	    default:
195513e3f4d6SMark Murray 		NETADD(c);
195613e3f4d6SMark Murray 		break;
195713e3f4d6SMark Murray 	    }
195813e3f4d6SMark Murray 	} else if (c == IAC) {
195913e3f4d6SMark Murray 	    NET2ADD(IAC, IAC);
196013e3f4d6SMark Murray 	} else {
196113e3f4d6SMark Murray 	    NETADD(c);
196213e3f4d6SMark Murray 	}
196313e3f4d6SMark Murray     }
196413e3f4d6SMark Murray     if (count)
196513e3f4d6SMark Murray 	ring_consumed(&ttyiring, count);
196613e3f4d6SMark Murray     return returnValue||count;		/* Non-zero if we did anything */
196713e3f4d6SMark Murray }
196813e3f4d6SMark Murray 
196913e3f4d6SMark Murray /*
197013e3f4d6SMark Murray  * Scheduler()
197113e3f4d6SMark Murray  *
197213e3f4d6SMark Murray  * Try to do something.
197313e3f4d6SMark Murray  *
197413e3f4d6SMark Murray  * If we do something useful, return 1; else return 0.
197513e3f4d6SMark Murray  *
197613e3f4d6SMark Murray  */
197713e3f4d6SMark Murray 
197813e3f4d6SMark Murray 
19794137ff4cSJacques Vidrine     int
Scheduler(int block)198013e3f4d6SMark Murray Scheduler(int block) /* should we block in the select ? */
198113e3f4d6SMark Murray {
198213e3f4d6SMark Murray 		/* One wants to be a bit careful about setting returnValue
198313e3f4d6SMark Murray 		 * to one, since a one implies we did some useful work,
198413e3f4d6SMark Murray 		 * and therefore probably won't be called to block next
198513e3f4d6SMark Murray 		 * time (TN3270 mode only).
198613e3f4d6SMark Murray 		 */
198713e3f4d6SMark Murray     int returnValue;
198813e3f4d6SMark Murray     int netin, netout, netex, ttyin, ttyout;
198913e3f4d6SMark Murray 
199013e3f4d6SMark Murray     /* Decide which rings should be processed */
199113e3f4d6SMark Murray 
199213e3f4d6SMark Murray     netout = ring_full_count(&netoring) &&
199313e3f4d6SMark Murray 	    (flushline ||
199413e3f4d6SMark Murray 		(my_want_state_is_wont(TELOPT_LINEMODE)
199513e3f4d6SMark Murray #ifdef	KLUDGELINEMODE
199613e3f4d6SMark Murray 			&& (!kludgelinemode || my_want_state_is_do(TELOPT_SGA))
199713e3f4d6SMark Murray #endif
199813e3f4d6SMark Murray 		) ||
199913e3f4d6SMark Murray 			my_want_state_is_will(TELOPT_BINARY));
200013e3f4d6SMark Murray     ttyout = ring_full_count(&ttyoring);
200113e3f4d6SMark Murray 
200213e3f4d6SMark Murray     ttyin = ring_empty_count(&ttyiring);
200313e3f4d6SMark Murray 
200413e3f4d6SMark Murray     netin = !ISend && ring_empty_count(&netiring);
200513e3f4d6SMark Murray 
200613e3f4d6SMark Murray     netex = !SYNCHing;
200713e3f4d6SMark Murray 
200813e3f4d6SMark Murray     /* If we have seen a signal recently, reset things */
200913e3f4d6SMark Murray 
20104137ff4cSJacques Vidrine     if (scheduler_lockout_tty) {
20114137ff4cSJacques Vidrine         ttyin = ttyout = 0;
20124137ff4cSJacques Vidrine     }
20134137ff4cSJacques Vidrine 
201413e3f4d6SMark Murray     /* Call to system code to process rings */
201513e3f4d6SMark Murray 
201613e3f4d6SMark Murray     returnValue = process_rings(netin, netout, netex, ttyin, ttyout, !block);
201713e3f4d6SMark Murray 
201813e3f4d6SMark Murray     /* Now, look at the input rings, looking for work to do. */
201913e3f4d6SMark Murray 
202013e3f4d6SMark Murray     if (ring_full_count(&ttyiring)) {
202113e3f4d6SMark Murray 	    returnValue |= telsnd();
202213e3f4d6SMark Murray     }
202313e3f4d6SMark Murray 
202413e3f4d6SMark Murray     if (ring_full_count(&netiring)) {
202513e3f4d6SMark Murray 	returnValue |= telrcv();
202613e3f4d6SMark Murray     }
202713e3f4d6SMark Murray     return returnValue;
202813e3f4d6SMark Murray }
202913e3f4d6SMark Murray 
2030c19800e8SDoug Rabson extern int auth_has_failed; /* XXX should be somewhere else */
2031c19800e8SDoug Rabson 
203213e3f4d6SMark Murray /*
203313e3f4d6SMark Murray  * Select from tty and network...
203413e3f4d6SMark Murray  */
203513e3f4d6SMark Murray void
my_telnet(char * user)203613e3f4d6SMark Murray my_telnet(char *user)
203713e3f4d6SMark Murray {
20384137ff4cSJacques Vidrine     int printed_encrypt = 0;
20394137ff4cSJacques Vidrine 
204013e3f4d6SMark Murray     sys_telnet_init();
204113e3f4d6SMark Murray 
204213e3f4d6SMark Murray #if	defined(AUTHENTICATION) || defined(ENCRYPTION)
204313e3f4d6SMark Murray     {
204413e3f4d6SMark Murray 	static char local_host[256] = { 0 };
204513e3f4d6SMark Murray 
204613e3f4d6SMark Murray 	if (!local_host[0]) {
204713e3f4d6SMark Murray 		/* XXX - should be k_gethostname? */
204813e3f4d6SMark Murray 		gethostname(local_host, sizeof(local_host));
204913e3f4d6SMark Murray 		local_host[sizeof(local_host)-1] = 0;
205013e3f4d6SMark Murray 	}
205113e3f4d6SMark Murray 	auth_encrypt_init(local_host, hostname, "TELNET", 0);
205213e3f4d6SMark Murray 	auth_encrypt_user(user);
205313e3f4d6SMark Murray     }
205413e3f4d6SMark Murray #endif
205513e3f4d6SMark Murray     if (telnetport) {
205613e3f4d6SMark Murray #if	defined(AUTHENTICATION)
205713e3f4d6SMark Murray 	if (autologin)
205813e3f4d6SMark Murray 		send_will(TELOPT_AUTHENTICATION, 1);
205913e3f4d6SMark Murray #endif
206013e3f4d6SMark Murray #if	defined(ENCRYPTION)
206113e3f4d6SMark Murray 	send_do(TELOPT_ENCRYPT, 1);
206213e3f4d6SMark Murray 	send_will(TELOPT_ENCRYPT, 1);
206313e3f4d6SMark Murray #endif
206413e3f4d6SMark Murray 	send_do(TELOPT_SGA, 1);
206513e3f4d6SMark Murray 	send_will(TELOPT_TTYPE, 1);
206613e3f4d6SMark Murray 	send_will(TELOPT_NAWS, 1);
206713e3f4d6SMark Murray 	send_will(TELOPT_TSPEED, 1);
206813e3f4d6SMark Murray 	send_will(TELOPT_LFLOW, 1);
206913e3f4d6SMark Murray 	send_will(TELOPT_LINEMODE, 1);
207013e3f4d6SMark Murray 	send_will(TELOPT_NEW_ENVIRON, 1);
207113e3f4d6SMark Murray 	send_do(TELOPT_STATUS, 1);
207213e3f4d6SMark Murray 	if (env_getvalue((unsigned char *)"DISPLAY"))
207313e3f4d6SMark Murray 	    send_will(TELOPT_XDISPLOC, 1);
207413e3f4d6SMark Murray 	if (binary)
207513e3f4d6SMark Murray 	    tel_enter_binary(binary);
207613e3f4d6SMark Murray     }
207713e3f4d6SMark Murray 
20784137ff4cSJacques Vidrine #ifdef ENCRYPTION
20794137ff4cSJacques Vidrine     /*
20804137ff4cSJacques Vidrine      * Note: we assume a tie to the authentication option here.  This
20814137ff4cSJacques Vidrine      * is necessary so that authentication fails, we don't spin
20824137ff4cSJacques Vidrine      * forever.
20834137ff4cSJacques Vidrine      */
20848373020dSJacques Vidrine     if (telnetport && wantencryption) {
20854137ff4cSJacques Vidrine 	time_t timeout = time(0) + 60;
20864137ff4cSJacques Vidrine 
20874137ff4cSJacques Vidrine 	send_do(TELOPT_ENCRYPT, 1);
20884137ff4cSJacques Vidrine 	send_will(TELOPT_ENCRYPT, 1);
20894137ff4cSJacques Vidrine 	while (1) {
20904137ff4cSJacques Vidrine 	    if (my_want_state_is_wont(TELOPT_AUTHENTICATION)) {
20918373020dSJacques Vidrine 		if (wantencryption == -1) {
20928373020dSJacques Vidrine 		    break;
20938373020dSJacques Vidrine 		} else {
20944137ff4cSJacques Vidrine 		    printf("\nServer refused to negotiate authentication,\n");
20954137ff4cSJacques Vidrine 		    printf("which is required for encryption.\n");
20964137ff4cSJacques Vidrine 		    Exit(1);
20974137ff4cSJacques Vidrine 		}
20988373020dSJacques Vidrine 	    }
20994137ff4cSJacques Vidrine 	    if (auth_has_failed) {
2100c19800e8SDoug Rabson 		printf("\nAuthentication negotiation has failed,\n");
21014137ff4cSJacques Vidrine 		printf("which is required for encryption.\n");
21024137ff4cSJacques Vidrine 		Exit(1);
21034137ff4cSJacques Vidrine 	    }
21044137ff4cSJacques Vidrine 	    if (my_want_state_is_dont(TELOPT_ENCRYPT) ||
21054137ff4cSJacques Vidrine 		my_want_state_is_wont(TELOPT_ENCRYPT)) {
21064137ff4cSJacques Vidrine 		printf("\nServer refused to negotiate encryption.\n");
21074137ff4cSJacques Vidrine 		Exit(1);
21084137ff4cSJacques Vidrine 	    }
21094137ff4cSJacques Vidrine 	    if (encrypt_is_encrypting())
21104137ff4cSJacques Vidrine 		break;
21114137ff4cSJacques Vidrine 	    if (time(0) > timeout) {
21124137ff4cSJacques Vidrine 		printf("\nEncryption could not be enabled.\n");
21134137ff4cSJacques Vidrine 		Exit(1);
21144137ff4cSJacques Vidrine 	    }
21154137ff4cSJacques Vidrine 	    if (printed_encrypt == 0) {
21164137ff4cSJacques Vidrine 		    printed_encrypt = 1;
21174137ff4cSJacques Vidrine 		    printf("Waiting for encryption to be negotiated...\n");
21184137ff4cSJacques Vidrine 		    /*
21194137ff4cSJacques Vidrine 		     * Turn on MODE_TRAPSIG and then turn off localchars
21204137ff4cSJacques Vidrine 		     * so that ^C will cause telnet to exit.
21214137ff4cSJacques Vidrine 		     */
21224137ff4cSJacques Vidrine 		    TerminalNewMode(getconnmode()|MODE_TRAPSIG);
21234137ff4cSJacques Vidrine 		    intr_waiting = 1;
21244137ff4cSJacques Vidrine 	    }
21254137ff4cSJacques Vidrine 	    if (intr_happened) {
21264137ff4cSJacques Vidrine 		    printf("\nUser interrupt.\n");
21274137ff4cSJacques Vidrine 		    Exit(1);
21284137ff4cSJacques Vidrine 	    }
2129c19800e8SDoug Rabson 	    if (telnet_spin()) {
2130c19800e8SDoug Rabson 		    printf("\nServer disconnected.\n");
2131c19800e8SDoug Rabson 		    Exit(1);
2132c19800e8SDoug Rabson 	    }
2133c19800e8SDoug Rabson 
21344137ff4cSJacques Vidrine 	}
21354137ff4cSJacques Vidrine 	if (printed_encrypt) {
21368373020dSJacques Vidrine 		printf("Encryption negotiated.\n");
21374137ff4cSJacques Vidrine 		intr_waiting = 0;
21384137ff4cSJacques Vidrine 		setconnmode(0);
21394137ff4cSJacques Vidrine 	}
21404137ff4cSJacques Vidrine     }
21414137ff4cSJacques Vidrine #endif
21424137ff4cSJacques Vidrine 
214313e3f4d6SMark Murray     for (;;) {
214413e3f4d6SMark Murray 	int schedValue;
214513e3f4d6SMark Murray 
214613e3f4d6SMark Murray 	while ((schedValue = Scheduler(0)) != 0) {
214713e3f4d6SMark Murray 	    if (schedValue == -1) {
214813e3f4d6SMark Murray 		setcommandmode();
214913e3f4d6SMark Murray 		return;
215013e3f4d6SMark Murray 	    }
215113e3f4d6SMark Murray 	}
215213e3f4d6SMark Murray 
215313e3f4d6SMark Murray 	if (Scheduler(1) == -1) {
215413e3f4d6SMark Murray 	    setcommandmode();
215513e3f4d6SMark Murray 	    return;
215613e3f4d6SMark Murray 	}
215713e3f4d6SMark Murray     }
215813e3f4d6SMark Murray }
215913e3f4d6SMark Murray 
216013e3f4d6SMark Murray /*
216113e3f4d6SMark Murray  * netclear()
216213e3f4d6SMark Murray  *
216313e3f4d6SMark Murray  *	We are about to do a TELNET SYNCH operation.  Clear
216413e3f4d6SMark Murray  * the path to the network.
216513e3f4d6SMark Murray  *
216613e3f4d6SMark Murray  *	Things are a bit tricky since we may have sent the first
216713e3f4d6SMark Murray  * byte or so of a previous TELNET command into the network.
216813e3f4d6SMark Murray  * So, we have to scan the network buffer from the beginning
216913e3f4d6SMark Murray  * until we are up to where we want to be.
217013e3f4d6SMark Murray  *
217113e3f4d6SMark Murray  *	A side effect of what we do, just to keep things
217213e3f4d6SMark Murray  * simple, is to clear the urgent data pointer.  The principal
217313e3f4d6SMark Murray  * caller should be setting the urgent data pointer AFTER calling
217413e3f4d6SMark Murray  * us in any case.
217513e3f4d6SMark Murray  */
217613e3f4d6SMark Murray 
217713e3f4d6SMark Murray static void
netclear()217813e3f4d6SMark Murray netclear()
217913e3f4d6SMark Murray {
218013e3f4d6SMark Murray #if	0	/* XXX */
218113e3f4d6SMark Murray     char *thisitem, *next;
218213e3f4d6SMark Murray     char *good;
218313e3f4d6SMark Murray #define	wewant(p)	((nfrontp > p) && ((*p&0xff) == IAC) && \
218413e3f4d6SMark Murray 				((*(p+1)&0xff) != EC) && ((*(p+1)&0xff) != EL))
218513e3f4d6SMark Murray 
218613e3f4d6SMark Murray     thisitem = netobuf;
218713e3f4d6SMark Murray 
218813e3f4d6SMark Murray     while ((next = nextitem(thisitem)) <= netobuf.send) {
218913e3f4d6SMark Murray 	thisitem = next;
219013e3f4d6SMark Murray     }
219113e3f4d6SMark Murray 
219213e3f4d6SMark Murray     /* Now, thisitem is first before/at boundary. */
219313e3f4d6SMark Murray 
219413e3f4d6SMark Murray     good = netobuf;	/* where the good bytes go */
219513e3f4d6SMark Murray 
219613e3f4d6SMark Murray     while (netoring.add > thisitem) {
219713e3f4d6SMark Murray 	if (wewant(thisitem)) {
219813e3f4d6SMark Murray 	    int length;
219913e3f4d6SMark Murray 
220013e3f4d6SMark Murray 	    next = thisitem;
220113e3f4d6SMark Murray 	    do {
220213e3f4d6SMark Murray 		next = nextitem(next);
220313e3f4d6SMark Murray 	    } while (wewant(next) && (nfrontp > next));
220413e3f4d6SMark Murray 	    length = next-thisitem;
220513e3f4d6SMark Murray 	    memmove(good, thisitem, length);
220613e3f4d6SMark Murray 	    good += length;
220713e3f4d6SMark Murray 	    thisitem = next;
220813e3f4d6SMark Murray 	} else {
220913e3f4d6SMark Murray 	    thisitem = nextitem(thisitem);
221013e3f4d6SMark Murray 	}
221113e3f4d6SMark Murray     }
221213e3f4d6SMark Murray 
221313e3f4d6SMark Murray #endif	/* 0 */
221413e3f4d6SMark Murray }
221513e3f4d6SMark Murray 
221613e3f4d6SMark Murray /*
221713e3f4d6SMark Murray  * These routines add various telnet commands to the data stream.
221813e3f4d6SMark Murray  */
221913e3f4d6SMark Murray 
222013e3f4d6SMark Murray static void
doflush()222113e3f4d6SMark Murray doflush()
222213e3f4d6SMark Murray {
222313e3f4d6SMark Murray     NET2ADD(IAC, DO);
222413e3f4d6SMark Murray     NETADD(TELOPT_TM);
222513e3f4d6SMark Murray     flushline = 1;
222613e3f4d6SMark Murray     flushout = 1;
222713e3f4d6SMark Murray     ttyflush(1);			/* Flush/drop output */
222813e3f4d6SMark Murray     /* do printoption AFTER flush, otherwise the output gets tossed... */
222913e3f4d6SMark Murray     printoption("SENT", DO, TELOPT_TM);
223013e3f4d6SMark Murray }
223113e3f4d6SMark Murray 
223213e3f4d6SMark Murray void
xmitAO(void)223313e3f4d6SMark Murray xmitAO(void)
223413e3f4d6SMark Murray {
223513e3f4d6SMark Murray     NET2ADD(IAC, AO);
223613e3f4d6SMark Murray     printoption("SENT", IAC, AO);
223713e3f4d6SMark Murray     if (autoflush) {
223813e3f4d6SMark Murray 	doflush();
223913e3f4d6SMark Murray     }
224013e3f4d6SMark Murray }
224113e3f4d6SMark Murray 
224213e3f4d6SMark Murray 
224313e3f4d6SMark Murray void
xmitEL(void)224413e3f4d6SMark Murray xmitEL(void)
224513e3f4d6SMark Murray {
224613e3f4d6SMark Murray     NET2ADD(IAC, EL);
224713e3f4d6SMark Murray     printoption("SENT", IAC, EL);
224813e3f4d6SMark Murray }
224913e3f4d6SMark Murray 
225013e3f4d6SMark Murray void
xmitEC(void)225113e3f4d6SMark Murray xmitEC(void)
225213e3f4d6SMark Murray {
225313e3f4d6SMark Murray     NET2ADD(IAC, EC);
225413e3f4d6SMark Murray     printoption("SENT", IAC, EC);
225513e3f4d6SMark Murray }
225613e3f4d6SMark Murray 
225713e3f4d6SMark Murray 
225813e3f4d6SMark Murray int
dosynch()225913e3f4d6SMark Murray dosynch()
226013e3f4d6SMark Murray {
226113e3f4d6SMark Murray     netclear();			/* clear the path to the network */
226213e3f4d6SMark Murray     NETADD(IAC);
226313e3f4d6SMark Murray     setneturg();
226413e3f4d6SMark Murray     NETADD(DM);
226513e3f4d6SMark Murray     printoption("SENT", IAC, DM);
226613e3f4d6SMark Murray     return 1;
226713e3f4d6SMark Murray }
226813e3f4d6SMark Murray 
226913e3f4d6SMark Murray int want_status_response = 0;
227013e3f4d6SMark Murray 
227113e3f4d6SMark Murray int
get_status()227213e3f4d6SMark Murray get_status()
227313e3f4d6SMark Murray {
227413e3f4d6SMark Murray     unsigned char tmp[16];
227513e3f4d6SMark Murray     unsigned char *cp;
227613e3f4d6SMark Murray 
227713e3f4d6SMark Murray     if (my_want_state_is_dont(TELOPT_STATUS)) {
227813e3f4d6SMark Murray 	printf("Remote side does not support STATUS option\n");
227913e3f4d6SMark Murray 	return 0;
228013e3f4d6SMark Murray     }
228113e3f4d6SMark Murray     cp = tmp;
228213e3f4d6SMark Murray 
228313e3f4d6SMark Murray     *cp++ = IAC;
228413e3f4d6SMark Murray     *cp++ = SB;
228513e3f4d6SMark Murray     *cp++ = TELOPT_STATUS;
228613e3f4d6SMark Murray     *cp++ = TELQUAL_SEND;
228713e3f4d6SMark Murray     *cp++ = IAC;
228813e3f4d6SMark Murray     *cp++ = SE;
228913e3f4d6SMark Murray     if (NETROOM() >= cp - tmp) {
229013e3f4d6SMark Murray 	ring_supply_data(&netoring, tmp, cp-tmp);
229113e3f4d6SMark Murray 	printsub('>', tmp+2, cp - tmp - 2);
229213e3f4d6SMark Murray     }
229313e3f4d6SMark Murray     ++want_status_response;
229413e3f4d6SMark Murray     return 1;
229513e3f4d6SMark Murray }
229613e3f4d6SMark Murray 
229713e3f4d6SMark Murray void
intp(void)229813e3f4d6SMark Murray intp(void)
229913e3f4d6SMark Murray {
230013e3f4d6SMark Murray     NET2ADD(IAC, IP);
230113e3f4d6SMark Murray     printoption("SENT", IAC, IP);
230213e3f4d6SMark Murray     flushline = 1;
230313e3f4d6SMark Murray     if (autoflush) {
230413e3f4d6SMark Murray 	doflush();
230513e3f4d6SMark Murray     }
230613e3f4d6SMark Murray     if (autosynch) {
230713e3f4d6SMark Murray 	dosynch();
230813e3f4d6SMark Murray     }
230913e3f4d6SMark Murray }
231013e3f4d6SMark Murray 
231113e3f4d6SMark Murray void
sendbrk(void)231213e3f4d6SMark Murray sendbrk(void)
231313e3f4d6SMark Murray {
231413e3f4d6SMark Murray     NET2ADD(IAC, BREAK);
231513e3f4d6SMark Murray     printoption("SENT", IAC, BREAK);
231613e3f4d6SMark Murray     flushline = 1;
231713e3f4d6SMark Murray     if (autoflush) {
231813e3f4d6SMark Murray 	doflush();
231913e3f4d6SMark Murray     }
232013e3f4d6SMark Murray     if (autosynch) {
232113e3f4d6SMark Murray 	dosynch();
232213e3f4d6SMark Murray     }
232313e3f4d6SMark Murray }
232413e3f4d6SMark Murray 
232513e3f4d6SMark Murray void
sendabort(void)232613e3f4d6SMark Murray sendabort(void)
232713e3f4d6SMark Murray {
232813e3f4d6SMark Murray     NET2ADD(IAC, ABORT);
232913e3f4d6SMark Murray     printoption("SENT", IAC, ABORT);
233013e3f4d6SMark Murray     flushline = 1;
233113e3f4d6SMark Murray     if (autoflush) {
233213e3f4d6SMark Murray 	doflush();
233313e3f4d6SMark Murray     }
233413e3f4d6SMark Murray     if (autosynch) {
233513e3f4d6SMark Murray 	dosynch();
233613e3f4d6SMark Murray     }
233713e3f4d6SMark Murray }
233813e3f4d6SMark Murray 
233913e3f4d6SMark Murray void
sendsusp(void)234013e3f4d6SMark Murray sendsusp(void)
234113e3f4d6SMark Murray {
234213e3f4d6SMark Murray     NET2ADD(IAC, SUSP);
234313e3f4d6SMark Murray     printoption("SENT", IAC, SUSP);
234413e3f4d6SMark Murray     flushline = 1;
234513e3f4d6SMark Murray     if (autoflush) {
234613e3f4d6SMark Murray 	doflush();
234713e3f4d6SMark Murray     }
234813e3f4d6SMark Murray     if (autosynch) {
234913e3f4d6SMark Murray 	dosynch();
235013e3f4d6SMark Murray     }
235113e3f4d6SMark Murray }
235213e3f4d6SMark Murray 
235313e3f4d6SMark Murray void
sendeof(void)235413e3f4d6SMark Murray sendeof(void)
235513e3f4d6SMark Murray {
235613e3f4d6SMark Murray     NET2ADD(IAC, xEOF);
235713e3f4d6SMark Murray     printoption("SENT", IAC, xEOF);
235813e3f4d6SMark Murray }
235913e3f4d6SMark Murray 
236013e3f4d6SMark Murray void
sendayt(void)236113e3f4d6SMark Murray sendayt(void)
236213e3f4d6SMark Murray {
236313e3f4d6SMark Murray     NET2ADD(IAC, AYT);
236413e3f4d6SMark Murray     printoption("SENT", IAC, AYT);
236513e3f4d6SMark Murray }
236613e3f4d6SMark Murray 
236713e3f4d6SMark Murray /*
236813e3f4d6SMark Murray  * Send a window size update to the remote system.
236913e3f4d6SMark Murray  */
237013e3f4d6SMark Murray 
237113e3f4d6SMark Murray void
sendnaws()237213e3f4d6SMark Murray sendnaws()
237313e3f4d6SMark Murray {
237413e3f4d6SMark Murray     long rows, cols;
237513e3f4d6SMark Murray     unsigned char tmp[16];
237613e3f4d6SMark Murray     unsigned char *cp;
237713e3f4d6SMark Murray 
237813e3f4d6SMark Murray     if (my_state_is_wont(TELOPT_NAWS))
237913e3f4d6SMark Murray 	return;
238013e3f4d6SMark Murray 
23814137ff4cSJacques Vidrine #undef PUTSHORT
238213e3f4d6SMark Murray #define	PUTSHORT(cp, x) { if ((*cp++ = ((x)>>8)&0xff) == IAC) *cp++ = IAC; \
238313e3f4d6SMark Murray 			    if ((*cp++ = ((x))&0xff) == IAC) *cp++ = IAC; }
238413e3f4d6SMark Murray 
238513e3f4d6SMark Murray     if (TerminalWindowSize(&rows, &cols) == 0) {	/* Failed */
238613e3f4d6SMark Murray 	return;
238713e3f4d6SMark Murray     }
238813e3f4d6SMark Murray 
238913e3f4d6SMark Murray     cp = tmp;
239013e3f4d6SMark Murray 
239113e3f4d6SMark Murray     *cp++ = IAC;
239213e3f4d6SMark Murray     *cp++ = SB;
239313e3f4d6SMark Murray     *cp++ = TELOPT_NAWS;
239413e3f4d6SMark Murray     PUTSHORT(cp, cols);
239513e3f4d6SMark Murray     PUTSHORT(cp, rows);
239613e3f4d6SMark Murray     *cp++ = IAC;
239713e3f4d6SMark Murray     *cp++ = SE;
239813e3f4d6SMark Murray     if (NETROOM() >= cp - tmp) {
239913e3f4d6SMark Murray 	ring_supply_data(&netoring, tmp, cp-tmp);
240013e3f4d6SMark Murray 	printsub('>', tmp+2, cp - tmp - 2);
240113e3f4d6SMark Murray     }
240213e3f4d6SMark Murray }
240313e3f4d6SMark Murray 
240413e3f4d6SMark Murray void
tel_enter_binary(int rw)240513e3f4d6SMark Murray tel_enter_binary(int rw)
240613e3f4d6SMark Murray {
240713e3f4d6SMark Murray     if (rw&1)
240813e3f4d6SMark Murray 	send_do(TELOPT_BINARY, 1);
240913e3f4d6SMark Murray     if (rw&2)
241013e3f4d6SMark Murray 	send_will(TELOPT_BINARY, 1);
241113e3f4d6SMark Murray }
241213e3f4d6SMark Murray 
241313e3f4d6SMark Murray void
tel_leave_binary(int rw)241413e3f4d6SMark Murray tel_leave_binary(int rw)
241513e3f4d6SMark Murray {
241613e3f4d6SMark Murray     if (rw&1)
241713e3f4d6SMark Murray 	send_dont(TELOPT_BINARY, 1);
241813e3f4d6SMark Murray     if (rw&2)
241913e3f4d6SMark Murray 	send_wont(TELOPT_BINARY, 1);
242013e3f4d6SMark Murray }
2421