17c478bd9Sstevel@tonic-gate /*
27c478bd9Sstevel@tonic-gate  * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
37c478bd9Sstevel@tonic-gate  * Use is subject to license terms.
47c478bd9Sstevel@tonic-gate  */
57c478bd9Sstevel@tonic-gate 
67c478bd9Sstevel@tonic-gate /*
77c478bd9Sstevel@tonic-gate  * Copyright (c) 1988, 1990, 1993
87c478bd9Sstevel@tonic-gate  *	The Regents of the University of California.  All rights reserved.
97c478bd9Sstevel@tonic-gate  *
107c478bd9Sstevel@tonic-gate  * Redistribution and use in source and binary forms, with or without
117c478bd9Sstevel@tonic-gate  * modification, are permitted provided that the following conditions
127c478bd9Sstevel@tonic-gate  * are met:
137c478bd9Sstevel@tonic-gate  * 1. Redistributions of source code must retain the above copyright
147c478bd9Sstevel@tonic-gate  *    notice, this list of conditions and the following disclaimer.
157c478bd9Sstevel@tonic-gate  * 2. Redistributions in binary form must reproduce the above copyright
167c478bd9Sstevel@tonic-gate  *    notice, this list of conditions and the following disclaimer in the
177c478bd9Sstevel@tonic-gate  *    documentation and/or other materials provided with the distribution.
187c478bd9Sstevel@tonic-gate  * 3. All advertising materials mentioning features or use of this software
197c478bd9Sstevel@tonic-gate  *    must display the following acknowledgement:
207c478bd9Sstevel@tonic-gate  *	This product includes software developed by the University of
217c478bd9Sstevel@tonic-gate  *	California, Berkeley and its contributors.
227c478bd9Sstevel@tonic-gate  * 4. Neither the name of the University nor the names of its contributors
237c478bd9Sstevel@tonic-gate  *    may be used to endorse or promote products derived from this software
247c478bd9Sstevel@tonic-gate  *    without specific prior written permission.
257c478bd9Sstevel@tonic-gate  *
267c478bd9Sstevel@tonic-gate  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
277c478bd9Sstevel@tonic-gate  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
287c478bd9Sstevel@tonic-gate  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
297c478bd9Sstevel@tonic-gate  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
307c478bd9Sstevel@tonic-gate  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
317c478bd9Sstevel@tonic-gate  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
327c478bd9Sstevel@tonic-gate  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
337c478bd9Sstevel@tonic-gate  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
347c478bd9Sstevel@tonic-gate  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
357c478bd9Sstevel@tonic-gate  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
367c478bd9Sstevel@tonic-gate  * SUCH DAMAGE.
377c478bd9Sstevel@tonic-gate  */
387c478bd9Sstevel@tonic-gate 
397c478bd9Sstevel@tonic-gate #ifndef lint
407c478bd9Sstevel@tonic-gate static char sccsid[] = "@(#)telnet.c	8.1 (Berkeley) 6/6/93";
417c478bd9Sstevel@tonic-gate #endif /* not lint */
427c478bd9Sstevel@tonic-gate 
437c478bd9Sstevel@tonic-gate #include <netdb.h>
447c478bd9Sstevel@tonic-gate #include <sys/types.h>
457c478bd9Sstevel@tonic-gate 
467c478bd9Sstevel@tonic-gate #include <curses.h>
477c478bd9Sstevel@tonic-gate #include <signal.h>
487c478bd9Sstevel@tonic-gate /*
497c478bd9Sstevel@tonic-gate  * By the way, we need to include curses.h before telnet.h since,
507c478bd9Sstevel@tonic-gate  * among other things, telnet.h #defines 'DO', which is a variable
517c478bd9Sstevel@tonic-gate  * declared in curses.h.
527c478bd9Sstevel@tonic-gate  */
537c478bd9Sstevel@tonic-gate 
547c478bd9Sstevel@tonic-gate #include <arpa/telnet.h>
557c478bd9Sstevel@tonic-gate 
567c478bd9Sstevel@tonic-gate #include <ctype.h>
577c478bd9Sstevel@tonic-gate 
587c478bd9Sstevel@tonic-gate #include "ring.h"
597c478bd9Sstevel@tonic-gate 
607c478bd9Sstevel@tonic-gate #include "defines.h"
617c478bd9Sstevel@tonic-gate #include "externs.h"
627c478bd9Sstevel@tonic-gate #include "types.h"
637c478bd9Sstevel@tonic-gate #include "general.h"
647c478bd9Sstevel@tonic-gate 
657c478bd9Sstevel@tonic-gate #include "auth.h"
667c478bd9Sstevel@tonic-gate #include "encrypt.h"
677c478bd9Sstevel@tonic-gate 
687c478bd9Sstevel@tonic-gate #define	strip(x)	((x)&0x7f)
697c478bd9Sstevel@tonic-gate 
707c478bd9Sstevel@tonic-gate /* Buffer for sub-options */
717c478bd9Sstevel@tonic-gate static unsigned char	subbuffer[SUBBUFSIZE];
727c478bd9Sstevel@tonic-gate static unsigned char	*subpointer;
737c478bd9Sstevel@tonic-gate static unsigned char	*subend;
747c478bd9Sstevel@tonic-gate 
757c478bd9Sstevel@tonic-gate #define	SB_CLEAR()	subpointer = subbuffer;
767c478bd9Sstevel@tonic-gate #define	SB_TERM()	{ subend = subpointer; SB_CLEAR(); }
777c478bd9Sstevel@tonic-gate #define	SB_ACCUM(c)	if (subpointer < (subbuffer+sizeof (subbuffer))) { \
787c478bd9Sstevel@tonic-gate 				*subpointer++ = (c); \
797c478bd9Sstevel@tonic-gate 			}
807c478bd9Sstevel@tonic-gate 
817c478bd9Sstevel@tonic-gate #define	SB_GET()	((*subpointer++)&0xff)
827c478bd9Sstevel@tonic-gate #define	SB_PEEK()	((*subpointer)&0xff)
837c478bd9Sstevel@tonic-gate #define	SB_EOF()	(subpointer >= subend)
847c478bd9Sstevel@tonic-gate #define	SB_LEN()	(subend - subpointer)
857c478bd9Sstevel@tonic-gate 
867c478bd9Sstevel@tonic-gate char	options[SUBBUFSIZE];		/* The combined options */
877c478bd9Sstevel@tonic-gate char	do_dont_resp[SUBBUFSIZE];
887c478bd9Sstevel@tonic-gate char	will_wont_resp[SUBBUFSIZE];
897c478bd9Sstevel@tonic-gate 
907c478bd9Sstevel@tonic-gate int eight = 0;
917c478bd9Sstevel@tonic-gate int autologin = 0;	/* Autologin anyone? */
927c478bd9Sstevel@tonic-gate int skiprc = 0;
937c478bd9Sstevel@tonic-gate int connected;
947c478bd9Sstevel@tonic-gate int showoptions;
957c478bd9Sstevel@tonic-gate static int ISend;	/* trying to send network data in */
967c478bd9Sstevel@tonic-gate int debug = 0;
977c478bd9Sstevel@tonic-gate int crmod;
987c478bd9Sstevel@tonic-gate int netdata;		/* Print out network data flow */
997c478bd9Sstevel@tonic-gate int crlf;		/* Should '\r' be mapped to <CR><LF> (or <CR><NUL>)? */
1007c478bd9Sstevel@tonic-gate int telnetport;
1017c478bd9Sstevel@tonic-gate int SYNCHing;		/* we are in TELNET SYNCH mode */
1027c478bd9Sstevel@tonic-gate int flushout;		/* flush output */
1037c478bd9Sstevel@tonic-gate int autoflush = 0;	/* flush output when interrupting? */
1047c478bd9Sstevel@tonic-gate int autosynch;		/* send interrupt characters with SYNCH? */
1057c478bd9Sstevel@tonic-gate int localflow;		/* we handle flow control locally */
1067c478bd9Sstevel@tonic-gate int restartany;		/* if flow control enabled, restart on any character */
1077c478bd9Sstevel@tonic-gate int localchars;		/* we recognize interrupt/quit */
1087c478bd9Sstevel@tonic-gate int donelclchars;	/* the user has set "localchars" */
1097c478bd9Sstevel@tonic-gate int donebinarytoggle;	/* the user has put us in binary */
1107c478bd9Sstevel@tonic-gate int dontlecho;		/* do we suppress local echoing right now? */
1117c478bd9Sstevel@tonic-gate int eof_pending = 0;	/* we received a genuine EOF on input, send IAC-EOF */
1127c478bd9Sstevel@tonic-gate int globalmode;
1137c478bd9Sstevel@tonic-gate 
1147c478bd9Sstevel@tonic-gate /* spin while waiting for authentication */
1157c478bd9Sstevel@tonic-gate boolean_t scheduler_lockout_tty = B_FALSE;
1167c478bd9Sstevel@tonic-gate int encrypt_flag = 0;
1177c478bd9Sstevel@tonic-gate int forwardable_flag = 0;
1187c478bd9Sstevel@tonic-gate int forward_flag = 0;
1197c478bd9Sstevel@tonic-gate boolean_t wantencryption = B_FALSE;
1207c478bd9Sstevel@tonic-gate 
1217c478bd9Sstevel@tonic-gate char *prompt = 0;
1227c478bd9Sstevel@tonic-gate 
1237c478bd9Sstevel@tonic-gate cc_t escape;
1247c478bd9Sstevel@tonic-gate cc_t rlogin;
1257c478bd9Sstevel@tonic-gate boolean_t escape_valid = B_TRUE;
1267c478bd9Sstevel@tonic-gate #ifdef	KLUDGELINEMODE
1277c478bd9Sstevel@tonic-gate cc_t echoc;
1287c478bd9Sstevel@tonic-gate #endif
1297c478bd9Sstevel@tonic-gate 
1307c478bd9Sstevel@tonic-gate /*
1317c478bd9Sstevel@tonic-gate  * Telnet receiver states for fsm
1327c478bd9Sstevel@tonic-gate  */
1337c478bd9Sstevel@tonic-gate #define	TS_DATA		0
1347c478bd9Sstevel@tonic-gate #define	TS_IAC		1
1357c478bd9Sstevel@tonic-gate #define	TS_WILL		2
1367c478bd9Sstevel@tonic-gate #define	TS_WONT		3
1377c478bd9Sstevel@tonic-gate #define	TS_DO		4
1387c478bd9Sstevel@tonic-gate #define	TS_DONT		5
1397c478bd9Sstevel@tonic-gate #define	TS_CR		6
1407c478bd9Sstevel@tonic-gate #define	TS_SB		7		/* sub-option collection */
1417c478bd9Sstevel@tonic-gate #define	TS_SE		8		/* looking for sub-option end */
1427c478bd9Sstevel@tonic-gate 
1437c478bd9Sstevel@tonic-gate static int	telrcv_state;
1447c478bd9Sstevel@tonic-gate #ifdef	OLD_ENVIRON
1457c478bd9Sstevel@tonic-gate static	unsigned char telopt_environ = TELOPT_NEW_ENVIRON;
1467c478bd9Sstevel@tonic-gate #else
1477c478bd9Sstevel@tonic-gate #define	telopt_environ	TELOPT_NEW_ENVIRON
1487c478bd9Sstevel@tonic-gate #endif
1497c478bd9Sstevel@tonic-gate 
1507c478bd9Sstevel@tonic-gate jmp_buf	toplevel = { 0 };
1517c478bd9Sstevel@tonic-gate jmp_buf	peerdied;
1527c478bd9Sstevel@tonic-gate 
1537c478bd9Sstevel@tonic-gate static int flushline;
1547c478bd9Sstevel@tonic-gate int	linemode;
1557c478bd9Sstevel@tonic-gate 
1567c478bd9Sstevel@tonic-gate int	reqd_linemode = 0; /* Set if either new or old line mode in */
1577c478bd9Sstevel@tonic-gate 			/* effect since before initial negotiations */
1587c478bd9Sstevel@tonic-gate 
1597c478bd9Sstevel@tonic-gate #ifdef	KLUDGELINEMODE
1607c478bd9Sstevel@tonic-gate int	kludgelinemode = 1;
1617c478bd9Sstevel@tonic-gate #endif
1627c478bd9Sstevel@tonic-gate 
1637c478bd9Sstevel@tonic-gate /*
1647c478bd9Sstevel@tonic-gate  * The following are some clocks used to decide how to interpret
1657c478bd9Sstevel@tonic-gate  * the relationship between various variables.
1667c478bd9Sstevel@tonic-gate  */
1677c478bd9Sstevel@tonic-gate 
1687c478bd9Sstevel@tonic-gate Clocks clocks;
1697c478bd9Sstevel@tonic-gate 
1707c478bd9Sstevel@tonic-gate #ifdef	notdef
1717c478bd9Sstevel@tonic-gate Modelist modelist[] = {
1727c478bd9Sstevel@tonic-gate 	{ "telnet command mode", COMMAND_LINE },
1737c478bd9Sstevel@tonic-gate 	{ "character-at-a-time mode", 0 },
1747c478bd9Sstevel@tonic-gate 	{ "character-at-a-time mode (local echo)", LOCAL_ECHO|LOCAL_CHARS },
1757c478bd9Sstevel@tonic-gate 	{ "line-by-line mode (remote echo)", LINE | LOCAL_CHARS },
1767c478bd9Sstevel@tonic-gate 	{ "line-by-line mode", LINE | LOCAL_ECHO | LOCAL_CHARS },
1777c478bd9Sstevel@tonic-gate 	{ "line-by-line mode (local echoing suppressed)", LINE | LOCAL_CHARS },
1787c478bd9Sstevel@tonic-gate 	{ "3270 mode", 0 },
1797c478bd9Sstevel@tonic-gate };
1807c478bd9Sstevel@tonic-gate #endif
1817c478bd9Sstevel@tonic-gate 
1827c478bd9Sstevel@tonic-gate static void willoption(int);
1837c478bd9Sstevel@tonic-gate static void wontoption(int);
1847c478bd9Sstevel@tonic-gate static void lm_will(unsigned char *, int);
1857c478bd9Sstevel@tonic-gate static void lm_wont(unsigned char *, int);
1867c478bd9Sstevel@tonic-gate static void lm_do(unsigned char *, int);
1877c478bd9Sstevel@tonic-gate static void lm_dont(unsigned char *, int);
1887c478bd9Sstevel@tonic-gate static void slc_init(void);
1897c478bd9Sstevel@tonic-gate static void slc_import(int);
1907c478bd9Sstevel@tonic-gate static void slc_export(void);
1917c478bd9Sstevel@tonic-gate static void slc_start_reply(size_t);
1927c478bd9Sstevel@tonic-gate static void slc_add_reply(unsigned char, unsigned char, cc_t);
1937c478bd9Sstevel@tonic-gate static void slc_end_reply(void);
1947c478bd9Sstevel@tonic-gate static void slc(unsigned char *, int);
1957c478bd9Sstevel@tonic-gate static int slc_update(void);
1967c478bd9Sstevel@tonic-gate static void env_opt(unsigned char *, int);
1977c478bd9Sstevel@tonic-gate static void env_opt_start(void);
1987c478bd9Sstevel@tonic-gate static void sendeof(void);
1997c478bd9Sstevel@tonic-gate static int is_unique(register char *, register char **, register char **);
2007c478bd9Sstevel@tonic-gate 
2017c478bd9Sstevel@tonic-gate /*
2027c478bd9Sstevel@tonic-gate  * Initialize telnet environment.
2037c478bd9Sstevel@tonic-gate  */
2047c478bd9Sstevel@tonic-gate 
2057c478bd9Sstevel@tonic-gate int
init_telnet()2067c478bd9Sstevel@tonic-gate init_telnet()
2077c478bd9Sstevel@tonic-gate {
2087c478bd9Sstevel@tonic-gate 	if (env_init() == 0)
2097c478bd9Sstevel@tonic-gate 		return (0);
2107c478bd9Sstevel@tonic-gate 
2117c478bd9Sstevel@tonic-gate 	SB_CLEAR();
2127c478bd9Sstevel@tonic-gate 	ClearArray(options);
2137c478bd9Sstevel@tonic-gate 
2147c478bd9Sstevel@tonic-gate 	connected = ISend = localflow = donebinarytoggle = 0;
2157c478bd9Sstevel@tonic-gate 	restartany = -1;
2167c478bd9Sstevel@tonic-gate 
2177c478bd9Sstevel@tonic-gate 	SYNCHing = 0;
2187c478bd9Sstevel@tonic-gate 
2197c478bd9Sstevel@tonic-gate 	/* Don't change NetTrace */
2207c478bd9Sstevel@tonic-gate 
2217c478bd9Sstevel@tonic-gate 	escape = CONTROL(']');
2227c478bd9Sstevel@tonic-gate 	rlogin = _POSIX_VDISABLE;
2237c478bd9Sstevel@tonic-gate #ifdef	KLUDGELINEMODE
2247c478bd9Sstevel@tonic-gate 	echoc = CONTROL('E');
2257c478bd9Sstevel@tonic-gate #endif
2267c478bd9Sstevel@tonic-gate 
2277c478bd9Sstevel@tonic-gate 	flushline = 1;
2287c478bd9Sstevel@tonic-gate 	telrcv_state = TS_DATA;
2297c478bd9Sstevel@tonic-gate 
2307c478bd9Sstevel@tonic-gate 	return (1);
2317c478bd9Sstevel@tonic-gate }
2327c478bd9Sstevel@tonic-gate 
2337c478bd9Sstevel@tonic-gate 
2347c478bd9Sstevel@tonic-gate #ifdef	notdef
2357c478bd9Sstevel@tonic-gate #include <varargs.h>
2367c478bd9Sstevel@tonic-gate 
2377c478bd9Sstevel@tonic-gate /*VARARGS*/
2387c478bd9Sstevel@tonic-gate static void
printring(va_alist)2397c478bd9Sstevel@tonic-gate printring(va_alist)
2407c478bd9Sstevel@tonic-gate 	va_dcl
2417c478bd9Sstevel@tonic-gate {
2427c478bd9Sstevel@tonic-gate 	va_list ap;
2437c478bd9Sstevel@tonic-gate 	char buffer[100];		/* where things go */
2447c478bd9Sstevel@tonic-gate 	char *ptr;
2457c478bd9Sstevel@tonic-gate 	char *format;
2467c478bd9Sstevel@tonic-gate 	char *string;
2477c478bd9Sstevel@tonic-gate 	Ring *ring;
2487c478bd9Sstevel@tonic-gate 	int i;
2497c478bd9Sstevel@tonic-gate 
2507c478bd9Sstevel@tonic-gate 	va_start(ap);
2517c478bd9Sstevel@tonic-gate 
2527c478bd9Sstevel@tonic-gate 	ring = va_arg(ap, Ring *);
2537c478bd9Sstevel@tonic-gate 	format = va_arg(ap, char *);
2547c478bd9Sstevel@tonic-gate 	ptr = buffer;
2557c478bd9Sstevel@tonic-gate 
2567c478bd9Sstevel@tonic-gate 	while ((i = *format++) != 0) {
2577c478bd9Sstevel@tonic-gate 		if (i == '%') {
2587c478bd9Sstevel@tonic-gate 			i = *format++;
2597c478bd9Sstevel@tonic-gate 			switch (i) {
2607c478bd9Sstevel@tonic-gate 			case 'c':
2617c478bd9Sstevel@tonic-gate 				*ptr++ = va_arg(ap, int);
2627c478bd9Sstevel@tonic-gate 				break;
2637c478bd9Sstevel@tonic-gate 			case 's':
2647c478bd9Sstevel@tonic-gate 				string = va_arg(ap, char *);
2657c478bd9Sstevel@tonic-gate 				ring_supply_data(ring, buffer, ptr-buffer);
2667c478bd9Sstevel@tonic-gate 				ring_supply_data(ring, string, strlen(string));
2677c478bd9Sstevel@tonic-gate 				ptr = buffer;
2687c478bd9Sstevel@tonic-gate 				break;
2697c478bd9Sstevel@tonic-gate 			case 0:
2707c478bd9Sstevel@tonic-gate 				ExitString("printring: trailing %%.\n",
2717c478bd9Sstevel@tonic-gate 				    EXIT_FAILURE);
2727c478bd9Sstevel@tonic-gate 				/*NOTREACHED*/
2737c478bd9Sstevel@tonic-gate 			default:
2747c478bd9Sstevel@tonic-gate 				ExitString("printring: unknown format "
2757c478bd9Sstevel@tonic-gate 				    "character.\n", EXIT_FAILURE);
2767c478bd9Sstevel@tonic-gate 				/*NOTREACHED*/
2777c478bd9Sstevel@tonic-gate 			}
2787c478bd9Sstevel@tonic-gate 		} else {
2797c478bd9Sstevel@tonic-gate 			*ptr++ = i;
2807c478bd9Sstevel@tonic-gate 		}
2817c478bd9Sstevel@tonic-gate 	}
2827c478bd9Sstevel@tonic-gate 	ring_supply_data(ring, buffer, ptr-buffer);
2837c478bd9Sstevel@tonic-gate }
2847c478bd9Sstevel@tonic-gate #endif
2857c478bd9Sstevel@tonic-gate 
2867c478bd9Sstevel@tonic-gate /*
2877c478bd9Sstevel@tonic-gate  * These routines are in charge of sending option negotiations
2887c478bd9Sstevel@tonic-gate  * to the other side.
2897c478bd9Sstevel@tonic-gate  *
2907c478bd9Sstevel@tonic-gate  * The basic idea is that we send the negotiation if either side
2917c478bd9Sstevel@tonic-gate  * is in disagreement as to what the current state should be.
2927c478bd9Sstevel@tonic-gate  */
2937c478bd9Sstevel@tonic-gate 
2947c478bd9Sstevel@tonic-gate void
send_do(c,init)2957c478bd9Sstevel@tonic-gate send_do(c, init)
2967c478bd9Sstevel@tonic-gate 	register int c, init;
2977c478bd9Sstevel@tonic-gate {
2987c478bd9Sstevel@tonic-gate 	if (init) {
2997c478bd9Sstevel@tonic-gate 		if (((do_dont_resp[c] == 0) && my_state_is_do(c)) ||
3007c478bd9Sstevel@tonic-gate 		    my_want_state_is_do(c))
3017c478bd9Sstevel@tonic-gate 			return;
3027c478bd9Sstevel@tonic-gate 		set_my_want_state_do(c);
3037c478bd9Sstevel@tonic-gate 		do_dont_resp[c]++;
3047c478bd9Sstevel@tonic-gate 	}
3057c478bd9Sstevel@tonic-gate 	NET2ADD(IAC, DO);
3067c478bd9Sstevel@tonic-gate 	NETADD(c);
3077c478bd9Sstevel@tonic-gate 	printoption("SENT", DO, c);
3087c478bd9Sstevel@tonic-gate }
3097c478bd9Sstevel@tonic-gate 
3107c478bd9Sstevel@tonic-gate void
send_dont(c,init)3117c478bd9Sstevel@tonic-gate send_dont(c, init)
3127c478bd9Sstevel@tonic-gate 	register int c, init;
3137c478bd9Sstevel@tonic-gate {
3147c478bd9Sstevel@tonic-gate 	if (init) {
3157c478bd9Sstevel@tonic-gate 		if (((do_dont_resp[c] == 0) && my_state_is_dont(c)) ||
3167c478bd9Sstevel@tonic-gate 		    my_want_state_is_dont(c))
3177c478bd9Sstevel@tonic-gate 			return;
3187c478bd9Sstevel@tonic-gate 		set_my_want_state_dont(c);
3197c478bd9Sstevel@tonic-gate 		do_dont_resp[c]++;
3207c478bd9Sstevel@tonic-gate 	}
3217c478bd9Sstevel@tonic-gate 	NET2ADD(IAC, DONT);
3227c478bd9Sstevel@tonic-gate 	NETADD(c);
3237c478bd9Sstevel@tonic-gate 	printoption("SENT", DONT, c);
3247c478bd9Sstevel@tonic-gate }
3257c478bd9Sstevel@tonic-gate 
3267c478bd9Sstevel@tonic-gate void
send_will(c,init)3277c478bd9Sstevel@tonic-gate send_will(c, init)
3287c478bd9Sstevel@tonic-gate 	register int c, init;
3297c478bd9Sstevel@tonic-gate {
3307c478bd9Sstevel@tonic-gate 	if (init) {
3317c478bd9Sstevel@tonic-gate 		if (((will_wont_resp[c] == 0) && my_state_is_will(c)) ||
3327c478bd9Sstevel@tonic-gate 		    my_want_state_is_will(c))
3337c478bd9Sstevel@tonic-gate 			return;
3347c478bd9Sstevel@tonic-gate 		set_my_want_state_will(c);
3357c478bd9Sstevel@tonic-gate 		will_wont_resp[c]++;
3367c478bd9Sstevel@tonic-gate 	}
3377c478bd9Sstevel@tonic-gate 	NET2ADD(IAC, WILL);
3387c478bd9Sstevel@tonic-gate 	NETADD(c);
3397c478bd9Sstevel@tonic-gate 	printoption("SENT", WILL, c);
3407c478bd9Sstevel@tonic-gate }
3417c478bd9Sstevel@tonic-gate 
3427c478bd9Sstevel@tonic-gate void
send_wont(c,init)3437c478bd9Sstevel@tonic-gate send_wont(c, init)
3447c478bd9Sstevel@tonic-gate 	register int c, init;
3457c478bd9Sstevel@tonic-gate {
3467c478bd9Sstevel@tonic-gate 	if (init) {
3477c478bd9Sstevel@tonic-gate 		if (((will_wont_resp[c] == 0) && my_state_is_wont(c)) ||
3487c478bd9Sstevel@tonic-gate 		    my_want_state_is_wont(c))
3497c478bd9Sstevel@tonic-gate 			return;
3507c478bd9Sstevel@tonic-gate 		set_my_want_state_wont(c);
3517c478bd9Sstevel@tonic-gate 		will_wont_resp[c]++;
3527c478bd9Sstevel@tonic-gate 	}
3537c478bd9Sstevel@tonic-gate 	NET2ADD(IAC, WONT);
3547c478bd9Sstevel@tonic-gate 	NETADD(c);
3557c478bd9Sstevel@tonic-gate 	printoption("SENT", WONT, c);
3567c478bd9Sstevel@tonic-gate }
3577c478bd9Sstevel@tonic-gate 
3587c478bd9Sstevel@tonic-gate 
3597c478bd9Sstevel@tonic-gate static void
willoption(option)3607c478bd9Sstevel@tonic-gate willoption(option)
3617c478bd9Sstevel@tonic-gate 	int option;
3627c478bd9Sstevel@tonic-gate {
3637c478bd9Sstevel@tonic-gate 	int new_state_ok = 0;
3647c478bd9Sstevel@tonic-gate 
3657c478bd9Sstevel@tonic-gate 	if (do_dont_resp[option]) {
3667c478bd9Sstevel@tonic-gate 	    --do_dont_resp[option];
3677c478bd9Sstevel@tonic-gate 	    if (do_dont_resp[option] && my_state_is_do(option))
3687c478bd9Sstevel@tonic-gate 		--do_dont_resp[option];
3697c478bd9Sstevel@tonic-gate 	}
3707c478bd9Sstevel@tonic-gate 
3717c478bd9Sstevel@tonic-gate 	if ((do_dont_resp[option] == 0) && my_want_state_is_dont(option)) {
3727c478bd9Sstevel@tonic-gate 
3737c478bd9Sstevel@tonic-gate 	    switch (option) {
3747c478bd9Sstevel@tonic-gate 
3757c478bd9Sstevel@tonic-gate 	    case TELOPT_ECHO:
3767c478bd9Sstevel@tonic-gate 	    case TELOPT_SGA:
3777c478bd9Sstevel@tonic-gate 		if (reqd_linemode && my_state_is_dont(option)) {
3787c478bd9Sstevel@tonic-gate 		    break;
3797c478bd9Sstevel@tonic-gate 		}
3807c478bd9Sstevel@tonic-gate 		/* FALLTHROUGH */
3817c478bd9Sstevel@tonic-gate 	    case TELOPT_BINARY:
3827c478bd9Sstevel@tonic-gate 		settimer(modenegotiated);
3837c478bd9Sstevel@tonic-gate 		/* FALLTHROUGH */
3847c478bd9Sstevel@tonic-gate 	    case TELOPT_STATUS:
3857c478bd9Sstevel@tonic-gate 	    case TELOPT_AUTHENTICATION:
3867c478bd9Sstevel@tonic-gate 		/* FALLTHROUGH */
3877c478bd9Sstevel@tonic-gate 	    case TELOPT_ENCRYPT:
3887c478bd9Sstevel@tonic-gate 		new_state_ok = 1;
3897c478bd9Sstevel@tonic-gate 		break;
3907c478bd9Sstevel@tonic-gate 
3917c478bd9Sstevel@tonic-gate 	    case TELOPT_TM:
3927c478bd9Sstevel@tonic-gate 		if (flushout)
3937c478bd9Sstevel@tonic-gate 		    flushout = 0;
3947c478bd9Sstevel@tonic-gate 		/*
3957c478bd9Sstevel@tonic-gate 		 * Special case for TM.  If we get back a WILL,
3967c478bd9Sstevel@tonic-gate 		 * pretend we got back a WONT.
3977c478bd9Sstevel@tonic-gate 		 */
3987c478bd9Sstevel@tonic-gate 		set_my_want_state_dont(option);
3997c478bd9Sstevel@tonic-gate 		set_my_state_dont(option);
4007c478bd9Sstevel@tonic-gate 		return;			/* Never reply to TM will's/wont's */
4017c478bd9Sstevel@tonic-gate 
4027c478bd9Sstevel@tonic-gate 	    case TELOPT_LINEMODE:
4037c478bd9Sstevel@tonic-gate 	    default:
4047c478bd9Sstevel@tonic-gate 		break;
4057c478bd9Sstevel@tonic-gate 	    }
4067c478bd9Sstevel@tonic-gate 
4077c478bd9Sstevel@tonic-gate 	    if (new_state_ok) {
4087c478bd9Sstevel@tonic-gate 		set_my_want_state_do(option);
4097c478bd9Sstevel@tonic-gate 		send_do(option, 0);
4107c478bd9Sstevel@tonic-gate 		setconnmode(0);		/* possibly set new tty mode */
4117c478bd9Sstevel@tonic-gate 	    } else {
4127c478bd9Sstevel@tonic-gate 		do_dont_resp[option]++;
4137c478bd9Sstevel@tonic-gate 		send_dont(option, 0);
4147c478bd9Sstevel@tonic-gate 	    }
4157c478bd9Sstevel@tonic-gate 	}
4167c478bd9Sstevel@tonic-gate 	set_my_state_do(option);
4177c478bd9Sstevel@tonic-gate 	if (option == TELOPT_ENCRYPT)
4187c478bd9Sstevel@tonic-gate 		encrypt_send_support();
4197c478bd9Sstevel@tonic-gate }
4207c478bd9Sstevel@tonic-gate 
4217c478bd9Sstevel@tonic-gate static void
wontoption(option)4227c478bd9Sstevel@tonic-gate wontoption(option)
4237c478bd9Sstevel@tonic-gate 	int option;
4247c478bd9Sstevel@tonic-gate {
4257c478bd9Sstevel@tonic-gate 	if (do_dont_resp[option]) {
4267c478bd9Sstevel@tonic-gate 		--do_dont_resp[option];
4277c478bd9Sstevel@tonic-gate 		if (do_dont_resp[option] && my_state_is_dont(option))
4287c478bd9Sstevel@tonic-gate 			--do_dont_resp[option];
4297c478bd9Sstevel@tonic-gate 	}
4307c478bd9Sstevel@tonic-gate 
4317c478bd9Sstevel@tonic-gate 	if ((do_dont_resp[option] == 0) && my_want_state_is_do(option)) {
4327c478bd9Sstevel@tonic-gate 
4337c478bd9Sstevel@tonic-gate 		switch (option) {
4347c478bd9Sstevel@tonic-gate 
4357c478bd9Sstevel@tonic-gate #ifdef	KLUDGELINEMODE
4367c478bd9Sstevel@tonic-gate 		case TELOPT_SGA:
4377c478bd9Sstevel@tonic-gate 			if (!kludgelinemode)
4387c478bd9Sstevel@tonic-gate 				break;
4397c478bd9Sstevel@tonic-gate 			/* FALLTHROUGH */
4407c478bd9Sstevel@tonic-gate #endif
4417c478bd9Sstevel@tonic-gate 		case TELOPT_ECHO:
4427c478bd9Sstevel@tonic-gate 			settimer(modenegotiated);
4437c478bd9Sstevel@tonic-gate 			break;
4447c478bd9Sstevel@tonic-gate 
4457c478bd9Sstevel@tonic-gate 		case TELOPT_TM:
4467c478bd9Sstevel@tonic-gate 			if (flushout)
4477c478bd9Sstevel@tonic-gate 				flushout = 0;
4487c478bd9Sstevel@tonic-gate 			set_my_want_state_dont(option);
4497c478bd9Sstevel@tonic-gate 			set_my_state_dont(option);
4507c478bd9Sstevel@tonic-gate 			return;		/* Never reply to TM will's/wont's */
4517c478bd9Sstevel@tonic-gate 
4527c478bd9Sstevel@tonic-gate 		default:
4537c478bd9Sstevel@tonic-gate 			break;
4547c478bd9Sstevel@tonic-gate 		}
4557c478bd9Sstevel@tonic-gate 		set_my_want_state_dont(option);
4567c478bd9Sstevel@tonic-gate 		if (my_state_is_do(option))
4577c478bd9Sstevel@tonic-gate 			send_dont(option, 0);
4587c478bd9Sstevel@tonic-gate 		setconnmode(0);			/* Set new tty mode */
4597c478bd9Sstevel@tonic-gate 	} else if (option == TELOPT_TM) {
4607c478bd9Sstevel@tonic-gate 		/*
4617c478bd9Sstevel@tonic-gate 		 * Special case for TM.
4627c478bd9Sstevel@tonic-gate 		 */
4637c478bd9Sstevel@tonic-gate 		if (flushout)
4647c478bd9Sstevel@tonic-gate 			flushout = 0;
4657c478bd9Sstevel@tonic-gate 		set_my_want_state_dont(option);
4667c478bd9Sstevel@tonic-gate 	}
4677c478bd9Sstevel@tonic-gate 	set_my_state_dont(option);
4687c478bd9Sstevel@tonic-gate }
4697c478bd9Sstevel@tonic-gate 
4707c478bd9Sstevel@tonic-gate static void
dooption(option)4717c478bd9Sstevel@tonic-gate dooption(option)
4727c478bd9Sstevel@tonic-gate 	int option;
4737c478bd9Sstevel@tonic-gate {
4747c478bd9Sstevel@tonic-gate 	int new_state_ok = 0;
4757c478bd9Sstevel@tonic-gate 
4767c478bd9Sstevel@tonic-gate 	if (will_wont_resp[option]) {
4777c478bd9Sstevel@tonic-gate 		--will_wont_resp[option];
4787c478bd9Sstevel@tonic-gate 		if (will_wont_resp[option] && my_state_is_will(option))
4797c478bd9Sstevel@tonic-gate 			--will_wont_resp[option];
4807c478bd9Sstevel@tonic-gate 	}
4817c478bd9Sstevel@tonic-gate 
4827c478bd9Sstevel@tonic-gate 	if (will_wont_resp[option] == 0) {
4837c478bd9Sstevel@tonic-gate 		if (my_want_state_is_wont(option)) {
4847c478bd9Sstevel@tonic-gate 
4857c478bd9Sstevel@tonic-gate 			switch (option) {
4867c478bd9Sstevel@tonic-gate 
4877c478bd9Sstevel@tonic-gate 			case TELOPT_TM:
4887c478bd9Sstevel@tonic-gate 				/*
4897c478bd9Sstevel@tonic-gate 				 * Special case for TM.  We send a WILL,
4907c478bd9Sstevel@tonic-gate 				 * but pretend we sent WONT.
4917c478bd9Sstevel@tonic-gate 				 */
4927c478bd9Sstevel@tonic-gate 				send_will(option, 0);
4937c478bd9Sstevel@tonic-gate 				set_my_want_state_wont(TELOPT_TM);
4947c478bd9Sstevel@tonic-gate 				set_my_state_wont(TELOPT_TM);
4957c478bd9Sstevel@tonic-gate 				return;
4967c478bd9Sstevel@tonic-gate 
4977c478bd9Sstevel@tonic-gate 			case TELOPT_BINARY:	/* binary mode */
4987c478bd9Sstevel@tonic-gate 			case TELOPT_NAWS:	/* window size */
4997c478bd9Sstevel@tonic-gate 			case TELOPT_TSPEED:	/* terminal speed */
5007c478bd9Sstevel@tonic-gate 			case TELOPT_LFLOW:	/* local flow control */
5017c478bd9Sstevel@tonic-gate 			case TELOPT_TTYPE:	/* terminal type option */
5027c478bd9Sstevel@tonic-gate 			case TELOPT_SGA:	/* no big deal */
5037c478bd9Sstevel@tonic-gate 			case TELOPT_ENCRYPT:	/* encryption variable option */
5047c478bd9Sstevel@tonic-gate 				new_state_ok = 1;
5057c478bd9Sstevel@tonic-gate 				break;
5067c478bd9Sstevel@tonic-gate 
5077c478bd9Sstevel@tonic-gate 			case TELOPT_NEW_ENVIRON:
5087c478bd9Sstevel@tonic-gate 				/* New environment variable option */
5097c478bd9Sstevel@tonic-gate #ifdef	OLD_ENVIRON
5107c478bd9Sstevel@tonic-gate 				if (my_state_is_will(TELOPT_OLD_ENVIRON))
5117c478bd9Sstevel@tonic-gate 					/* turn off the old */
5127c478bd9Sstevel@tonic-gate 					send_wont(TELOPT_OLD_ENVIRON, 1);
5137c478bd9Sstevel@tonic-gate goto env_common;
5147c478bd9Sstevel@tonic-gate 			case TELOPT_OLD_ENVIRON:
5157c478bd9Sstevel@tonic-gate 				/* Old environment variable option */
5167c478bd9Sstevel@tonic-gate 				if (my_state_is_will(TELOPT_NEW_ENVIRON))
5177c478bd9Sstevel@tonic-gate 					/* Don't enable if new one is in use! */
5187c478bd9Sstevel@tonic-gate 					break;
5197c478bd9Sstevel@tonic-gate env_common:
5207c478bd9Sstevel@tonic-gate 				telopt_environ = option;
5217c478bd9Sstevel@tonic-gate #endif
5227c478bd9Sstevel@tonic-gate 				new_state_ok = 1;
5237c478bd9Sstevel@tonic-gate 				break;
5247c478bd9Sstevel@tonic-gate 
5257c478bd9Sstevel@tonic-gate 			case TELOPT_AUTHENTICATION:
5267c478bd9Sstevel@tonic-gate 				if (autologin)
5277c478bd9Sstevel@tonic-gate 					new_state_ok = 1;
5287c478bd9Sstevel@tonic-gate 				break;
5297c478bd9Sstevel@tonic-gate 
5307c478bd9Sstevel@tonic-gate 			case TELOPT_XDISPLOC:	/* X Display location */
5317c478bd9Sstevel@tonic-gate 				if (env_getvalue((unsigned char *)"DISPLAY"))
5327c478bd9Sstevel@tonic-gate 					new_state_ok = 1;
5337c478bd9Sstevel@tonic-gate 				break;
5347c478bd9Sstevel@tonic-gate 
5357c478bd9Sstevel@tonic-gate 			case TELOPT_LINEMODE:
5367c478bd9Sstevel@tonic-gate #ifdef	KLUDGELINEMODE
5377c478bd9Sstevel@tonic-gate 				kludgelinemode = 0;
5387c478bd9Sstevel@tonic-gate 				send_do(TELOPT_SGA, 1);
5397c478bd9Sstevel@tonic-gate #endif
5407c478bd9Sstevel@tonic-gate 				set_my_want_state_will(TELOPT_LINEMODE);
5417c478bd9Sstevel@tonic-gate 				send_will(option, 0);
5427c478bd9Sstevel@tonic-gate 				set_my_state_will(TELOPT_LINEMODE);
5437c478bd9Sstevel@tonic-gate 				slc_init();
5447c478bd9Sstevel@tonic-gate 				return;
5457c478bd9Sstevel@tonic-gate 
5467c478bd9Sstevel@tonic-gate 			case TELOPT_ECHO: /* We're never going to echo... */
5477c478bd9Sstevel@tonic-gate 			default:
5487c478bd9Sstevel@tonic-gate 				break;
5497c478bd9Sstevel@tonic-gate 			}
5507c478bd9Sstevel@tonic-gate 
5517c478bd9Sstevel@tonic-gate 			if (new_state_ok) {
5527c478bd9Sstevel@tonic-gate 				set_my_want_state_will(option);
5537c478bd9Sstevel@tonic-gate 				send_will(option, 0);
5547c478bd9Sstevel@tonic-gate 				setconnmode(0);		/* Set new tty mode */
5557c478bd9Sstevel@tonic-gate 			} else {
5567c478bd9Sstevel@tonic-gate 				will_wont_resp[option]++;
5577c478bd9Sstevel@tonic-gate 				send_wont(option, 0);
5587c478bd9Sstevel@tonic-gate 			}
5597c478bd9Sstevel@tonic-gate 		} else {
5607c478bd9Sstevel@tonic-gate 			/*
5617c478bd9Sstevel@tonic-gate 			 * Handle options that need more things done after the
5627c478bd9Sstevel@tonic-gate 			 * other side has acknowledged the option.
5637c478bd9Sstevel@tonic-gate 			 */
5647c478bd9Sstevel@tonic-gate 			switch (option) {
5657c478bd9Sstevel@tonic-gate 			case TELOPT_LINEMODE:
5667c478bd9Sstevel@tonic-gate #ifdef	KLUDGELINEMODE
5677c478bd9Sstevel@tonic-gate 				kludgelinemode = 0;
5687c478bd9Sstevel@tonic-gate 				send_do(TELOPT_SGA, 1);
5697c478bd9Sstevel@tonic-gate #endif
5707c478bd9Sstevel@tonic-gate 				set_my_state_will(option);
5717c478bd9Sstevel@tonic-gate 				slc_init();
5727c478bd9Sstevel@tonic-gate 				send_do(TELOPT_SGA, 0);
5737c478bd9Sstevel@tonic-gate 				return;
5747c478bd9Sstevel@tonic-gate 			}
5757c478bd9Sstevel@tonic-gate 		}
5767c478bd9Sstevel@tonic-gate 	}
5777c478bd9Sstevel@tonic-gate 	set_my_state_will(option);
5787c478bd9Sstevel@tonic-gate }
5797c478bd9Sstevel@tonic-gate 
5807c478bd9Sstevel@tonic-gate 	static void
dontoption(option)5817c478bd9Sstevel@tonic-gate dontoption(option)
5827c478bd9Sstevel@tonic-gate 	int option;
5837c478bd9Sstevel@tonic-gate {
5847c478bd9Sstevel@tonic-gate 
5857c478bd9Sstevel@tonic-gate 	if (will_wont_resp[option]) {
5867c478bd9Sstevel@tonic-gate 	    --will_wont_resp[option];
5877c478bd9Sstevel@tonic-gate 	    if (will_wont_resp[option] && my_state_is_wont(option))
5887c478bd9Sstevel@tonic-gate 		--will_wont_resp[option];
5897c478bd9Sstevel@tonic-gate 	}
5907c478bd9Sstevel@tonic-gate 
5917c478bd9Sstevel@tonic-gate 	if ((will_wont_resp[option] == 0) && my_want_state_is_will(option)) {
5927c478bd9Sstevel@tonic-gate 	    switch (option) {
5937c478bd9Sstevel@tonic-gate 	    case TELOPT_LINEMODE:
5947c478bd9Sstevel@tonic-gate 		linemode = 0;	/* put us back to the default state */
5957c478bd9Sstevel@tonic-gate 		break;
5967c478bd9Sstevel@tonic-gate #ifdef	OLD_ENVIRON
5977c478bd9Sstevel@tonic-gate 	    case TELOPT_NEW_ENVIRON:
5987c478bd9Sstevel@tonic-gate 		/*
5997c478bd9Sstevel@tonic-gate 		 * The new environ option wasn't recognized, try
6007c478bd9Sstevel@tonic-gate 		 * the old one.
6017c478bd9Sstevel@tonic-gate 		 */
6027c478bd9Sstevel@tonic-gate 		send_will(TELOPT_OLD_ENVIRON, 1);
6037c478bd9Sstevel@tonic-gate 		telopt_environ = TELOPT_OLD_ENVIRON;
6047c478bd9Sstevel@tonic-gate 		break;
6057c478bd9Sstevel@tonic-gate #endif
6067c478bd9Sstevel@tonic-gate 	    }
6077c478bd9Sstevel@tonic-gate 	    /* we always accept a DONT */
6087c478bd9Sstevel@tonic-gate 	    set_my_want_state_wont(option);
6097c478bd9Sstevel@tonic-gate 	    if (my_state_is_will(option))
6107c478bd9Sstevel@tonic-gate 		send_wont(option, 0);
6117c478bd9Sstevel@tonic-gate 	    setconnmode(0);			/* Set new tty mode */
6127c478bd9Sstevel@tonic-gate 	}
6137c478bd9Sstevel@tonic-gate 	set_my_state_wont(option);
6147c478bd9Sstevel@tonic-gate }
6157c478bd9Sstevel@tonic-gate 
6167c478bd9Sstevel@tonic-gate /*
6177c478bd9Sstevel@tonic-gate  * Given a buffer returned by tgetent(), this routine will turn
6187c478bd9Sstevel@tonic-gate  * the pipe seperated list of names in the buffer into an array
6197c478bd9Sstevel@tonic-gate  * of pointers to null terminated names.  We toss out any bad,
6207c478bd9Sstevel@tonic-gate  * duplicate, or verbose names (names with spaces).
6217c478bd9Sstevel@tonic-gate  */
6227c478bd9Sstevel@tonic-gate 
6237c478bd9Sstevel@tonic-gate static char *name_unknown = "UNKNOWN";
6247c478bd9Sstevel@tonic-gate static char *unknown[] = { 0, 0 };
6257c478bd9Sstevel@tonic-gate 
6267c478bd9Sstevel@tonic-gate static char **
mklist(buf,name)6277c478bd9Sstevel@tonic-gate mklist(buf, name)
6287c478bd9Sstevel@tonic-gate 	char *buf, *name;
6297c478bd9Sstevel@tonic-gate {
6307c478bd9Sstevel@tonic-gate 	register int n;
6317c478bd9Sstevel@tonic-gate 	register char c, *cp, **argvp, *cp2, **argv, **avt;
6327c478bd9Sstevel@tonic-gate 
6337c478bd9Sstevel@tonic-gate 	if (name) {
6347c478bd9Sstevel@tonic-gate 		if (strlen(name) > 40u) {
6357c478bd9Sstevel@tonic-gate 			name = 0;
6367c478bd9Sstevel@tonic-gate 			unknown[0] = name_unknown;
6377c478bd9Sstevel@tonic-gate 		} else {
6387c478bd9Sstevel@tonic-gate 			unknown[0] = name;
6397c478bd9Sstevel@tonic-gate 			upcase(name);
6407c478bd9Sstevel@tonic-gate 		}
6417c478bd9Sstevel@tonic-gate 	} else
6427c478bd9Sstevel@tonic-gate 		unknown[0] = name_unknown;
6437c478bd9Sstevel@tonic-gate 	/*
6447c478bd9Sstevel@tonic-gate 	 * Count up the number of names.
6457c478bd9Sstevel@tonic-gate 	 */
6467c478bd9Sstevel@tonic-gate 	for (n = 1, cp = buf; *cp && *cp != ':'; cp++) {
6477c478bd9Sstevel@tonic-gate 		if (*cp == '|')
6487c478bd9Sstevel@tonic-gate 			n++;
6497c478bd9Sstevel@tonic-gate 	}
6507c478bd9Sstevel@tonic-gate 	/*
6517c478bd9Sstevel@tonic-gate 	 * Allocate an array to put the name pointers into
6527c478bd9Sstevel@tonic-gate 	 */
6537c478bd9Sstevel@tonic-gate 	argv = malloc((n+3)*sizeof (char *));
6547c478bd9Sstevel@tonic-gate 	if (argv == 0)
6557c478bd9Sstevel@tonic-gate 		return (unknown);
6567c478bd9Sstevel@tonic-gate 
6577c478bd9Sstevel@tonic-gate 	/*
6587c478bd9Sstevel@tonic-gate 	 * Fill up the array of pointers to names.
6597c478bd9Sstevel@tonic-gate 	 */
6607c478bd9Sstevel@tonic-gate 	*argv = 0;
6617c478bd9Sstevel@tonic-gate 	argvp = argv+1;
6627c478bd9Sstevel@tonic-gate 	n = 0;
663*95c74518SToomas Soome 	for (cp = cp2 = buf; (c = *cp) != '\0';  cp++) {
6647c478bd9Sstevel@tonic-gate 		if (c == '|' || c == ':') {
6657c478bd9Sstevel@tonic-gate 			*cp++ = '\0';
6667c478bd9Sstevel@tonic-gate 			/*
6677c478bd9Sstevel@tonic-gate 			 * Skip entries that have spaces or are over 40
6687c478bd9Sstevel@tonic-gate 			 * characters long.  If this is our environment
6697c478bd9Sstevel@tonic-gate 			 * name, then put it up front.  Otherwise, as
6707c478bd9Sstevel@tonic-gate 			 * long as this is not a duplicate name (case
6717c478bd9Sstevel@tonic-gate 			 * insensitive) add it to the list.
6727c478bd9Sstevel@tonic-gate 			 */
6737c478bd9Sstevel@tonic-gate 			if (n || (cp - cp2 > 41))
6747c478bd9Sstevel@tonic-gate 				/* EMPTY */;
6757c478bd9Sstevel@tonic-gate 			else if (name && (strncasecmp(name, cp2, cp-cp2) == 0))
6767c478bd9Sstevel@tonic-gate 				*argv = cp2;
6777c478bd9Sstevel@tonic-gate 			else if (is_unique(cp2, argv+1, argvp))
6787c478bd9Sstevel@tonic-gate 				*argvp++ = cp2;
6797c478bd9Sstevel@tonic-gate 			if (c == ':')
6807c478bd9Sstevel@tonic-gate 				break;
6817c478bd9Sstevel@tonic-gate 			/*
6827c478bd9Sstevel@tonic-gate 			 * Skip multiple delimiters. Reset cp2 to
6837c478bd9Sstevel@tonic-gate 			 * the beginning of the next name. Reset n,
6847c478bd9Sstevel@tonic-gate 			 * the flag for names with spaces.
6857c478bd9Sstevel@tonic-gate 			 */
6867c478bd9Sstevel@tonic-gate 			while ((c = *cp) == '|')
6877c478bd9Sstevel@tonic-gate 				cp++;
6887c478bd9Sstevel@tonic-gate 			cp2 = cp;
6897c478bd9Sstevel@tonic-gate 			n = 0;
6907c478bd9Sstevel@tonic-gate 		}
6917c478bd9Sstevel@tonic-gate 		/*
6927c478bd9Sstevel@tonic-gate 		 * Skip entries with spaces or non-ascii values.
6937c478bd9Sstevel@tonic-gate 		 * Convert lower case letters to upper case.
6947c478bd9Sstevel@tonic-gate 		 */
6957c478bd9Sstevel@tonic-gate 		if ((c == ' ') || !isascii(c))
6967c478bd9Sstevel@tonic-gate 			n = 1;
6977c478bd9Sstevel@tonic-gate 		else if (islower(c))
6987c478bd9Sstevel@tonic-gate 			*cp = toupper(c);
6997c478bd9Sstevel@tonic-gate 	}
7007c478bd9Sstevel@tonic-gate 
7017c478bd9Sstevel@tonic-gate 	/*
7027c478bd9Sstevel@tonic-gate 	 * Check for an old V6 2 character name.  If the second
7037c478bd9Sstevel@tonic-gate 	 * name points to the beginning of the buffer, and is
7047c478bd9Sstevel@tonic-gate 	 * only 2 characters long, move it to the end of the array.
7057c478bd9Sstevel@tonic-gate 	 */
7067c478bd9Sstevel@tonic-gate 	if ((argv[1] == buf) && (strlen(argv[1]) == 2)) {
7077c478bd9Sstevel@tonic-gate 		--argvp;
7087c478bd9Sstevel@tonic-gate 		for (avt = &argv[1]; avt < argvp; avt++)
7097c478bd9Sstevel@tonic-gate 			*avt = *(avt+1);
7107c478bd9Sstevel@tonic-gate 		*argvp++ = buf;
7117c478bd9Sstevel@tonic-gate 	}
7127c478bd9Sstevel@tonic-gate 
7137c478bd9Sstevel@tonic-gate 	/*
7147c478bd9Sstevel@tonic-gate 	 * Duplicate last name, for TTYPE option, and null
7157c478bd9Sstevel@tonic-gate 	 * terminate the array.  If we didn't find a match on
7167c478bd9Sstevel@tonic-gate 	 * our terminal name, put that name at the beginning.
7177c478bd9Sstevel@tonic-gate 	 */
7187c478bd9Sstevel@tonic-gate 	cp = *(argvp-1);
7197c478bd9Sstevel@tonic-gate 	*argvp++ = cp;
7207c478bd9Sstevel@tonic-gate 	*argvp = 0;
7217c478bd9Sstevel@tonic-gate 
7227c478bd9Sstevel@tonic-gate 	if (*argv == 0) {
7237c478bd9Sstevel@tonic-gate 		if (name)
7247c478bd9Sstevel@tonic-gate 			*argv = name;
7257c478bd9Sstevel@tonic-gate 		else {
7267c478bd9Sstevel@tonic-gate 			--argvp;
7277c478bd9Sstevel@tonic-gate 			for (avt = argv; avt < argvp; avt++)
7287c478bd9Sstevel@tonic-gate 				*avt = *(avt+1);
7297c478bd9Sstevel@tonic-gate 		}
7307c478bd9Sstevel@tonic-gate 	}
7317c478bd9Sstevel@tonic-gate 	if (*argv)
7327c478bd9Sstevel@tonic-gate 		return (argv);
7337c478bd9Sstevel@tonic-gate 	else
7347c478bd9Sstevel@tonic-gate 		return (unknown);
7357c478bd9Sstevel@tonic-gate }
7367c478bd9Sstevel@tonic-gate 
7377c478bd9Sstevel@tonic-gate static int
is_unique(name,as,ae)7387c478bd9Sstevel@tonic-gate is_unique(name, as, ae)
7397c478bd9Sstevel@tonic-gate 	register char *name, **as, **ae;
7407c478bd9Sstevel@tonic-gate {
7417c478bd9Sstevel@tonic-gate 	register char **ap;
7427c478bd9Sstevel@tonic-gate 	register int n;
7437c478bd9Sstevel@tonic-gate 
7447c478bd9Sstevel@tonic-gate 	n = strlen(name) + 1;
7457c478bd9Sstevel@tonic-gate 	for (ap = as; ap < ae; ap++)
7467c478bd9Sstevel@tonic-gate 		if (strncasecmp(*ap, name, n) == 0)
7477c478bd9Sstevel@tonic-gate 			return (0);
7487c478bd9Sstevel@tonic-gate 	return (1);
7497c478bd9Sstevel@tonic-gate }
7507c478bd9Sstevel@tonic-gate 
7517c478bd9Sstevel@tonic-gate #define	termbuf	ttytype
7527c478bd9Sstevel@tonic-gate extern char ttytype[];
7537c478bd9Sstevel@tonic-gate 
7547c478bd9Sstevel@tonic-gate int resettermname = 1;
7557c478bd9Sstevel@tonic-gate 
7567c478bd9Sstevel@tonic-gate static char *
gettermname(void)7577c478bd9Sstevel@tonic-gate gettermname(void)
7587c478bd9Sstevel@tonic-gate {
7597c478bd9Sstevel@tonic-gate 	char *tname;
7607c478bd9Sstevel@tonic-gate 	static char **tnamep = 0;
7617c478bd9Sstevel@tonic-gate 	static char **next;
7627c478bd9Sstevel@tonic-gate 	int err;
7637c478bd9Sstevel@tonic-gate 
7647c478bd9Sstevel@tonic-gate 	if (resettermname) {
7657c478bd9Sstevel@tonic-gate 		resettermname = 0;
7667c478bd9Sstevel@tonic-gate 		if (tnamep && tnamep != unknown)
7677c478bd9Sstevel@tonic-gate 			free(tnamep);
7687c478bd9Sstevel@tonic-gate 		tname = (char *)env_getvalue((unsigned char *)"TERM");
7697c478bd9Sstevel@tonic-gate 		if ((tname != NULL) && (setupterm(tname, 1, &err) == 0)) {
7707c478bd9Sstevel@tonic-gate 			tnamep = mklist(termbuf, tname);
7717c478bd9Sstevel@tonic-gate 		} else {
7727c478bd9Sstevel@tonic-gate 			if (tname && (strlen(tname) <= 40u)) {
7737c478bd9Sstevel@tonic-gate 				unknown[0] = tname;
7747c478bd9Sstevel@tonic-gate 				upcase(tname);
7757c478bd9Sstevel@tonic-gate 			} else
7767c478bd9Sstevel@tonic-gate 				unknown[0] = name_unknown;
7777c478bd9Sstevel@tonic-gate 			tnamep = unknown;
7787c478bd9Sstevel@tonic-gate 		}
7797c478bd9Sstevel@tonic-gate 		next = tnamep;
7807c478bd9Sstevel@tonic-gate 	}
7817c478bd9Sstevel@tonic-gate 	if (*next == 0)
7827c478bd9Sstevel@tonic-gate 		next = tnamep;
7837c478bd9Sstevel@tonic-gate 	return (*next++);
7847c478bd9Sstevel@tonic-gate }
7857c478bd9Sstevel@tonic-gate /*
7867c478bd9Sstevel@tonic-gate  * suboption()
7877c478bd9Sstevel@tonic-gate  *
7887c478bd9Sstevel@tonic-gate  *	Look at the sub-option buffer, and try to be helpful to the other
7897c478bd9Sstevel@tonic-gate  * side.
7907c478bd9Sstevel@tonic-gate  *
7917c478bd9Sstevel@tonic-gate  *	Currently we recognize:
7927c478bd9Sstevel@tonic-gate  *
7937c478bd9Sstevel@tonic-gate  *		Terminal type, send request.
7947c478bd9Sstevel@tonic-gate  *		Terminal speed (send request).
7957c478bd9Sstevel@tonic-gate  *		Local flow control (is request).
7967c478bd9Sstevel@tonic-gate  *		Linemode
7977c478bd9Sstevel@tonic-gate  */
7987c478bd9Sstevel@tonic-gate 
7997c478bd9Sstevel@tonic-gate     static void
suboption()8007c478bd9Sstevel@tonic-gate suboption()
8017c478bd9Sstevel@tonic-gate {
8027c478bd9Sstevel@tonic-gate 	unsigned char subchar;
8037c478bd9Sstevel@tonic-gate 
8047c478bd9Sstevel@tonic-gate 	printsub('<', subbuffer, SB_LEN()+2);
8057c478bd9Sstevel@tonic-gate 	switch (subchar = SB_GET()) {
8067c478bd9Sstevel@tonic-gate 	case TELOPT_TTYPE:
8077c478bd9Sstevel@tonic-gate 		if (my_want_state_is_wont(TELOPT_TTYPE))
8087c478bd9Sstevel@tonic-gate 			return;
8097c478bd9Sstevel@tonic-gate 		if (SB_EOF() || SB_GET() != TELQUAL_SEND) {
8107c478bd9Sstevel@tonic-gate 			return;
8117c478bd9Sstevel@tonic-gate 		} else {
8127c478bd9Sstevel@tonic-gate 			char *name;
8137c478bd9Sstevel@tonic-gate 			unsigned char temp[50];
8147c478bd9Sstevel@tonic-gate 			int len, bytes;
8157c478bd9Sstevel@tonic-gate 
8167c478bd9Sstevel@tonic-gate 			name = gettermname();
8177c478bd9Sstevel@tonic-gate 			len = strlen(name) + 4 + 2;
8187c478bd9Sstevel@tonic-gate 			bytes = snprintf((char *)temp, sizeof (temp),
8197c478bd9Sstevel@tonic-gate 				"%c%c%c%c%s%c%c", IAC, SB,
8207c478bd9Sstevel@tonic-gate 				TELOPT_TTYPE, TELQUAL_IS, name, IAC, SE);
8217c478bd9Sstevel@tonic-gate 			if ((len < NETROOM()) && (bytes < sizeof (temp))) {
8227c478bd9Sstevel@tonic-gate 					ring_supply_data(&netoring, temp, len);
8237c478bd9Sstevel@tonic-gate 					printsub('>', &temp[2], len-2);
8247c478bd9Sstevel@tonic-gate 			} else {
8257c478bd9Sstevel@tonic-gate 				ExitString("No room in buffer for "
8267c478bd9Sstevel@tonic-gate 				    "terminal type.\n", EXIT_FAILURE);
8277c478bd9Sstevel@tonic-gate 				/*NOTREACHED*/
8287c478bd9Sstevel@tonic-gate 			}
8297c478bd9Sstevel@tonic-gate 		}
8307c478bd9Sstevel@tonic-gate 		break;
8317c478bd9Sstevel@tonic-gate 	case TELOPT_TSPEED:
8327c478bd9Sstevel@tonic-gate 		if (my_want_state_is_wont(TELOPT_TSPEED))
8337c478bd9Sstevel@tonic-gate 			return;
8347c478bd9Sstevel@tonic-gate 		if (SB_EOF())
8357c478bd9Sstevel@tonic-gate 			return;
8367c478bd9Sstevel@tonic-gate 		if (SB_GET() == TELQUAL_SEND) {
8377c478bd9Sstevel@tonic-gate 			int ospeed, ispeed;
8387c478bd9Sstevel@tonic-gate 			unsigned char temp[50];
8397c478bd9Sstevel@tonic-gate 			int len, bytes;
8407c478bd9Sstevel@tonic-gate 
8417c478bd9Sstevel@tonic-gate 			TerminalSpeeds(&ispeed, &ospeed);
8427c478bd9Sstevel@tonic-gate 
8437c478bd9Sstevel@tonic-gate 			bytes = snprintf((char *)temp, sizeof (temp),
8447c478bd9Sstevel@tonic-gate 			    "%c%c%c%c%d,%d%c%c", IAC, SB,
8457c478bd9Sstevel@tonic-gate 			    TELOPT_TSPEED, TELQUAL_IS, ospeed, ispeed, IAC, SE);
8467c478bd9Sstevel@tonic-gate 			len = strlen((char *)temp+4) + 4; /* temp[3] is 0 ... */
8477c478bd9Sstevel@tonic-gate 
8487c478bd9Sstevel@tonic-gate 			if ((len < NETROOM()) && (bytes < sizeof (temp))) {
8497c478bd9Sstevel@tonic-gate 				ring_supply_data(&netoring, temp, len);
8507c478bd9Sstevel@tonic-gate 				printsub('>', temp+2, len - 2);
8517c478bd9Sstevel@tonic-gate 			}
8527c478bd9Sstevel@tonic-gate 			else
8537c478bd9Sstevel@tonic-gate 				(void) printf(
8547c478bd9Sstevel@tonic-gate 				    "telnet: not enough room in buffer "
8557c478bd9Sstevel@tonic-gate 				    "for terminal speed option reply\n");
8567c478bd9Sstevel@tonic-gate 		}
8577c478bd9Sstevel@tonic-gate 		break;
8587c478bd9Sstevel@tonic-gate 	case TELOPT_LFLOW:
8597c478bd9Sstevel@tonic-gate 		if (my_want_state_is_wont(TELOPT_LFLOW))
8607c478bd9Sstevel@tonic-gate 			return;
8617c478bd9Sstevel@tonic-gate 		if (SB_EOF())
8627c478bd9Sstevel@tonic-gate 			return;
8637c478bd9Sstevel@tonic-gate 		switch (SB_GET()) {
8647c478bd9Sstevel@tonic-gate 		case LFLOW_RESTART_ANY:
8657c478bd9Sstevel@tonic-gate 			restartany = 1;
8667c478bd9Sstevel@tonic-gate 			break;
8677c478bd9Sstevel@tonic-gate 		case LFLOW_RESTART_XON:
8687c478bd9Sstevel@tonic-gate 			restartany = 0;
8697c478bd9Sstevel@tonic-gate 			break;
8707c478bd9Sstevel@tonic-gate 		case LFLOW_ON:
8717c478bd9Sstevel@tonic-gate 			localflow = 1;
8727c478bd9Sstevel@tonic-gate 			break;
8737c478bd9Sstevel@tonic-gate 		case LFLOW_OFF:
8747c478bd9Sstevel@tonic-gate 			localflow = 0;
8757c478bd9Sstevel@tonic-gate 			break;
8767c478bd9Sstevel@tonic-gate 		default:
8777c478bd9Sstevel@tonic-gate 			return;
8787c478bd9Sstevel@tonic-gate 		}
8797c478bd9Sstevel@tonic-gate 		setcommandmode();
8807c478bd9Sstevel@tonic-gate 		setconnmode(0);
8817c478bd9Sstevel@tonic-gate 		break;
8827c478bd9Sstevel@tonic-gate 
8837c478bd9Sstevel@tonic-gate 	case TELOPT_LINEMODE:
8847c478bd9Sstevel@tonic-gate 		if (my_want_state_is_wont(TELOPT_LINEMODE))
8857c478bd9Sstevel@tonic-gate 			return;
8867c478bd9Sstevel@tonic-gate 		if (SB_EOF())
8877c478bd9Sstevel@tonic-gate 			return;
8887c478bd9Sstevel@tonic-gate 		switch (SB_GET()) {
8897c478bd9Sstevel@tonic-gate 		case WILL:
8907c478bd9Sstevel@tonic-gate 			lm_will(subpointer, SB_LEN());
8917c478bd9Sstevel@tonic-gate 			break;
8927c478bd9Sstevel@tonic-gate 		case WONT:
8937c478bd9Sstevel@tonic-gate 			lm_wont(subpointer, SB_LEN());
8947c478bd9Sstevel@tonic-gate 			break;
8957c478bd9Sstevel@tonic-gate 		case DO:
8967c478bd9Sstevel@tonic-gate 			lm_do(subpointer, SB_LEN());
8977c478bd9Sstevel@tonic-gate 			break;
8987c478bd9Sstevel@tonic-gate 		case DONT:
8997c478bd9Sstevel@tonic-gate 			lm_dont(subpointer, SB_LEN());
9007c478bd9Sstevel@tonic-gate 			break;
9017c478bd9Sstevel@tonic-gate 		case LM_SLC:
9027c478bd9Sstevel@tonic-gate 			slc(subpointer, SB_LEN());
9037c478bd9Sstevel@tonic-gate 			break;
9047c478bd9Sstevel@tonic-gate 		case LM_MODE:
9057c478bd9Sstevel@tonic-gate 			lm_mode(subpointer, SB_LEN(), 0);
9067c478bd9Sstevel@tonic-gate 			break;
9077c478bd9Sstevel@tonic-gate 		default:
9087c478bd9Sstevel@tonic-gate 			break;
9097c478bd9Sstevel@tonic-gate 		}
9107c478bd9Sstevel@tonic-gate 		break;
9117c478bd9Sstevel@tonic-gate 
9127c478bd9Sstevel@tonic-gate #ifdef	OLD_ENVIRON
9137c478bd9Sstevel@tonic-gate 	case TELOPT_OLD_ENVIRON:
9147c478bd9Sstevel@tonic-gate #endif
9157c478bd9Sstevel@tonic-gate 	case TELOPT_NEW_ENVIRON:
9167c478bd9Sstevel@tonic-gate 		if (SB_EOF())
9177c478bd9Sstevel@tonic-gate 			return;
9187c478bd9Sstevel@tonic-gate 		switch (SB_PEEK()) {
9197c478bd9Sstevel@tonic-gate 		case TELQUAL_IS:
9207c478bd9Sstevel@tonic-gate 		case TELQUAL_INFO:
9217c478bd9Sstevel@tonic-gate 			if (my_want_state_is_dont(subchar))
9227c478bd9Sstevel@tonic-gate 				return;
9237c478bd9Sstevel@tonic-gate 			break;
9247c478bd9Sstevel@tonic-gate 		case TELQUAL_SEND:
9257c478bd9Sstevel@tonic-gate 			if (my_want_state_is_wont(subchar)) {
9267c478bd9Sstevel@tonic-gate 				return;
9277c478bd9Sstevel@tonic-gate 			}
9287c478bd9Sstevel@tonic-gate 			break;
9297c478bd9Sstevel@tonic-gate 		default:
9307c478bd9Sstevel@tonic-gate 			return;
9317c478bd9Sstevel@tonic-gate 		}
9327c478bd9Sstevel@tonic-gate 		env_opt(subpointer, SB_LEN());
9337c478bd9Sstevel@tonic-gate 		break;
9347c478bd9Sstevel@tonic-gate 
9357c478bd9Sstevel@tonic-gate 	case TELOPT_XDISPLOC:
9367c478bd9Sstevel@tonic-gate 		if (my_want_state_is_wont(TELOPT_XDISPLOC))
9377c478bd9Sstevel@tonic-gate 			return;
9387c478bd9Sstevel@tonic-gate 		if (SB_EOF())
9397c478bd9Sstevel@tonic-gate 			return;
9407c478bd9Sstevel@tonic-gate 		if (SB_GET() == TELQUAL_SEND) {
9417c478bd9Sstevel@tonic-gate 			unsigned char temp[50], *dp;
9427c478bd9Sstevel@tonic-gate 			int len, bytes;
9437c478bd9Sstevel@tonic-gate 
9447c478bd9Sstevel@tonic-gate 			if ((dp = env_getvalue((unsigned char *)"DISPLAY")) ==
9457c478bd9Sstevel@tonic-gate 			    NULL) {
9467c478bd9Sstevel@tonic-gate 				/*
9477c478bd9Sstevel@tonic-gate 				 * Something happened, we no longer have a
9487c478bd9Sstevel@tonic-gate 				 * DISPLAY variable.  So, turn off the option.
9497c478bd9Sstevel@tonic-gate 				 */
9507c478bd9Sstevel@tonic-gate 				send_wont(TELOPT_XDISPLOC, 1);
9517c478bd9Sstevel@tonic-gate 				break;
9527c478bd9Sstevel@tonic-gate 			}
9537c478bd9Sstevel@tonic-gate 			bytes = snprintf((char *)temp, sizeof (temp),
9547c478bd9Sstevel@tonic-gate 			    "%c%c%c%c%s%c%c", IAC, SB,
9557c478bd9Sstevel@tonic-gate 			    TELOPT_XDISPLOC, TELQUAL_IS, dp, IAC, SE);
9567c478bd9Sstevel@tonic-gate 			len = strlen((char *)temp+4) + 4; /* temp[3] is 0 ... */
9577c478bd9Sstevel@tonic-gate 
9587c478bd9Sstevel@tonic-gate 			if ((len < NETROOM()) && (bytes < sizeof (temp))) {
9597c478bd9Sstevel@tonic-gate 				ring_supply_data(&netoring, temp, len);
9607c478bd9Sstevel@tonic-gate 				printsub('>', temp+2, len - 2);
9617c478bd9Sstevel@tonic-gate 			}
9627c478bd9Sstevel@tonic-gate 			else
9637c478bd9Sstevel@tonic-gate 				(void) printf(
9647c478bd9Sstevel@tonic-gate 				    "telnet: not enough room in buffer"
9657c478bd9Sstevel@tonic-gate 				    " for display location option reply\n");
9667c478bd9Sstevel@tonic-gate 		}
9677c478bd9Sstevel@tonic-gate 		break;
9687c478bd9Sstevel@tonic-gate 
9697c478bd9Sstevel@tonic-gate 	case TELOPT_AUTHENTICATION: {
9707c478bd9Sstevel@tonic-gate 		if (!autologin)
9717c478bd9Sstevel@tonic-gate 			break;
9727c478bd9Sstevel@tonic-gate 		if (SB_EOF())
9737c478bd9Sstevel@tonic-gate 			return;
9747c478bd9Sstevel@tonic-gate 		switch (SB_GET()) {
9757c478bd9Sstevel@tonic-gate 		case TELQUAL_SEND:
9767c478bd9Sstevel@tonic-gate 			if (my_want_state_is_wont(TELOPT_AUTHENTICATION))
9777c478bd9Sstevel@tonic-gate 				return;
9787c478bd9Sstevel@tonic-gate 			auth_send(subpointer, SB_LEN());
9797c478bd9Sstevel@tonic-gate 			break;
9807c478bd9Sstevel@tonic-gate 		case TELQUAL_REPLY:
9817c478bd9Sstevel@tonic-gate 			if (my_want_state_is_wont(TELOPT_AUTHENTICATION))
9827c478bd9Sstevel@tonic-gate 				return;
9837c478bd9Sstevel@tonic-gate 			auth_reply(subpointer, SB_LEN());
9847c478bd9Sstevel@tonic-gate 			break;
9857c478bd9Sstevel@tonic-gate 		}
9867c478bd9Sstevel@tonic-gate 	}
9877c478bd9Sstevel@tonic-gate 	break;
9887c478bd9Sstevel@tonic-gate 
9897c478bd9Sstevel@tonic-gate 	case TELOPT_ENCRYPT:
9907c478bd9Sstevel@tonic-gate 		if (SB_EOF())
9917c478bd9Sstevel@tonic-gate 			return;
9927c478bd9Sstevel@tonic-gate 		switch (SB_GET()) {
9937c478bd9Sstevel@tonic-gate 		case ENCRYPT_START:
9947c478bd9Sstevel@tonic-gate 			if (my_want_state_is_dont(TELOPT_ENCRYPT))
9957c478bd9Sstevel@tonic-gate 				return;
9967c478bd9Sstevel@tonic-gate 			encrypt_start(subpointer, SB_LEN());
9977c478bd9Sstevel@tonic-gate 			break;
9987c478bd9Sstevel@tonic-gate 		case ENCRYPT_END:
9997c478bd9Sstevel@tonic-gate 			if (my_want_state_is_dont(TELOPT_ENCRYPT))
10007c478bd9Sstevel@tonic-gate 				return;
10017c478bd9Sstevel@tonic-gate 			encrypt_end();
10027c478bd9Sstevel@tonic-gate 			break;
10037c478bd9Sstevel@tonic-gate 		case ENCRYPT_SUPPORT:
10047c478bd9Sstevel@tonic-gate 			if (my_want_state_is_wont(TELOPT_ENCRYPT))
10057c478bd9Sstevel@tonic-gate 				return;
10067c478bd9Sstevel@tonic-gate 			encrypt_support(subpointer, SB_LEN());
10077c478bd9Sstevel@tonic-gate 			break;
10087c478bd9Sstevel@tonic-gate 		case ENCRYPT_REQSTART:
10097c478bd9Sstevel@tonic-gate 			if (my_want_state_is_wont(TELOPT_ENCRYPT))
10107c478bd9Sstevel@tonic-gate 				return;
10117c478bd9Sstevel@tonic-gate 			encrypt_request_start(subpointer, SB_LEN());
10127c478bd9Sstevel@tonic-gate 			break;
10137c478bd9Sstevel@tonic-gate 		case ENCRYPT_REQEND:
10147c478bd9Sstevel@tonic-gate 			if (my_want_state_is_wont(TELOPT_ENCRYPT))
10157c478bd9Sstevel@tonic-gate 				return;
10167c478bd9Sstevel@tonic-gate 			/*
10177c478bd9Sstevel@tonic-gate 			 * We can always send an REQEND so that we cannot
10187c478bd9Sstevel@tonic-gate 			 * get stuck encrypting.  We should only get this
10197c478bd9Sstevel@tonic-gate 			 * if we have been able to get in the correct mode
10207c478bd9Sstevel@tonic-gate 			 * anyhow.
10217c478bd9Sstevel@tonic-gate 			 */
10227c478bd9Sstevel@tonic-gate 			encrypt_request_end();
10237c478bd9Sstevel@tonic-gate 			break;
10247c478bd9Sstevel@tonic-gate 		case ENCRYPT_IS:
10257c478bd9Sstevel@tonic-gate 			if (my_want_state_is_dont(TELOPT_ENCRYPT))
10267c478bd9Sstevel@tonic-gate 				return;
10277c478bd9Sstevel@tonic-gate 			encrypt_is(subpointer, SB_LEN());
10287c478bd9Sstevel@tonic-gate 			break;
10297c478bd9Sstevel@tonic-gate 		case ENCRYPT_REPLY:
10307c478bd9Sstevel@tonic-gate 			if (my_want_state_is_wont(TELOPT_ENCRYPT))
10317c478bd9Sstevel@tonic-gate 				return;
10327c478bd9Sstevel@tonic-gate 			encrypt_reply(subpointer, SB_LEN());
10337c478bd9Sstevel@tonic-gate 			break;
10347c478bd9Sstevel@tonic-gate 		case ENCRYPT_ENC_KEYID:
10357c478bd9Sstevel@tonic-gate 			if (my_want_state_is_dont(TELOPT_ENCRYPT))
10367c478bd9Sstevel@tonic-gate 				return;
10377c478bd9Sstevel@tonic-gate 			encrypt_enc_keyid(subpointer, SB_LEN());
10387c478bd9Sstevel@tonic-gate 			break;
10397c478bd9Sstevel@tonic-gate 		case ENCRYPT_DEC_KEYID:
10407c478bd9Sstevel@tonic-gate 			if (my_want_state_is_wont(TELOPT_ENCRYPT))
10417c478bd9Sstevel@tonic-gate 				return;
10427c478bd9Sstevel@tonic-gate 			encrypt_dec_keyid(subpointer, SB_LEN());
10437c478bd9Sstevel@tonic-gate 			break;
10447c478bd9Sstevel@tonic-gate 		default:
10457c478bd9Sstevel@tonic-gate 			break;
10467c478bd9Sstevel@tonic-gate 		}
10477c478bd9Sstevel@tonic-gate 		break;
10487c478bd9Sstevel@tonic-gate 	default:
10497c478bd9Sstevel@tonic-gate 		break;
10507c478bd9Sstevel@tonic-gate 	}
10517c478bd9Sstevel@tonic-gate }
10527c478bd9Sstevel@tonic-gate 
10537c478bd9Sstevel@tonic-gate static unsigned char str_lm[] = { IAC, SB, TELOPT_LINEMODE, 0, 0, IAC, SE };
10547c478bd9Sstevel@tonic-gate 
10557c478bd9Sstevel@tonic-gate static void
lm_will(cmd,len)10567c478bd9Sstevel@tonic-gate lm_will(cmd, len)
10577c478bd9Sstevel@tonic-gate 	unsigned char *cmd;
10587c478bd9Sstevel@tonic-gate 	int len;
10597c478bd9Sstevel@tonic-gate {
10607c478bd9Sstevel@tonic-gate 	if (len < 1) {
10617c478bd9Sstevel@tonic-gate 		/* Should not happen... */
10627c478bd9Sstevel@tonic-gate 		(void) printf(
10637c478bd9Sstevel@tonic-gate 		    "telnet: command missing from linemode WILL request\n");
10647c478bd9Sstevel@tonic-gate 		return;
10657c478bd9Sstevel@tonic-gate 	}
10667c478bd9Sstevel@tonic-gate 	switch (cmd[0]) {
10677c478bd9Sstevel@tonic-gate 	case LM_FORWARDMASK:	/* We shouldn't ever get this... */
10687c478bd9Sstevel@tonic-gate 	default:
10697c478bd9Sstevel@tonic-gate 		str_lm[3] = DONT;
10707c478bd9Sstevel@tonic-gate 		str_lm[4] = cmd[0];
10717c478bd9Sstevel@tonic-gate 		if (NETROOM() > sizeof (str_lm)) {
10727c478bd9Sstevel@tonic-gate 			ring_supply_data(&netoring, str_lm, sizeof (str_lm));
10737c478bd9Sstevel@tonic-gate 			printsub('>', &str_lm[2], sizeof (str_lm)-2);
10747c478bd9Sstevel@tonic-gate 		}
10757c478bd9Sstevel@tonic-gate 		else
10767c478bd9Sstevel@tonic-gate 			(void) printf("telnet: not enough room in buffer for"
10777c478bd9Sstevel@tonic-gate 			    "reply to linemode WILL request\n");
10787c478bd9Sstevel@tonic-gate 		break;
10797c478bd9Sstevel@tonic-gate 	}
10807c478bd9Sstevel@tonic-gate }
10817c478bd9Sstevel@tonic-gate 
10827c478bd9Sstevel@tonic-gate static void
lm_wont(cmd,len)10837c478bd9Sstevel@tonic-gate lm_wont(cmd, len)
10847c478bd9Sstevel@tonic-gate 	unsigned char *cmd;
10857c478bd9Sstevel@tonic-gate 	int len;
10867c478bd9Sstevel@tonic-gate {
10877c478bd9Sstevel@tonic-gate 	if (len < 1) {
10887c478bd9Sstevel@tonic-gate 		/* Should not happen... */
10897c478bd9Sstevel@tonic-gate 		(void) printf(
10907c478bd9Sstevel@tonic-gate 		    "telnet: command missing from linemode WONT request\n");
10917c478bd9Sstevel@tonic-gate 		return;
10927c478bd9Sstevel@tonic-gate 	}
10937c478bd9Sstevel@tonic-gate 	switch (cmd[0]) {
10947c478bd9Sstevel@tonic-gate 	case LM_FORWARDMASK:	/* We shouldn't ever get this... */
10957c478bd9Sstevel@tonic-gate 	default:
10967c478bd9Sstevel@tonic-gate 		/* We are always DONT, so don't respond */
10977c478bd9Sstevel@tonic-gate 		return;
10987c478bd9Sstevel@tonic-gate 	}
10997c478bd9Sstevel@tonic-gate }
11007c478bd9Sstevel@tonic-gate 
11017c478bd9Sstevel@tonic-gate static void
lm_do(cmd,len)11027c478bd9Sstevel@tonic-gate lm_do(cmd, len)
11037c478bd9Sstevel@tonic-gate 	unsigned char *cmd;
11047c478bd9Sstevel@tonic-gate 	int len;
11057c478bd9Sstevel@tonic-gate {
11067c478bd9Sstevel@tonic-gate 	if (len < 1) {
11077c478bd9Sstevel@tonic-gate 		/* Should not happen... */
11087c478bd9Sstevel@tonic-gate 		(void) printf(
11097c478bd9Sstevel@tonic-gate 		    "telnet: command missing from linemode DO request\n");
11107c478bd9Sstevel@tonic-gate 		return;
11117c478bd9Sstevel@tonic-gate 	}
11127c478bd9Sstevel@tonic-gate 	switch (cmd[0]) {
11137c478bd9Sstevel@tonic-gate 	case LM_FORWARDMASK:
11147c478bd9Sstevel@tonic-gate 	default:
11157c478bd9Sstevel@tonic-gate 		str_lm[3] = WONT;
11167c478bd9Sstevel@tonic-gate 		str_lm[4] = cmd[0];
11177c478bd9Sstevel@tonic-gate 		if (NETROOM() > sizeof (str_lm)) {
11187c478bd9Sstevel@tonic-gate 			ring_supply_data(&netoring, str_lm, sizeof (str_lm));
11197c478bd9Sstevel@tonic-gate 			printsub('>', &str_lm[2], sizeof (str_lm)-2);
11207c478bd9Sstevel@tonic-gate 		}
11217c478bd9Sstevel@tonic-gate 		else
11227c478bd9Sstevel@tonic-gate 			(void) printf("telnet: not enough room in buffer for"
11237c478bd9Sstevel@tonic-gate 			    "reply to linemode DO request\n");
11247c478bd9Sstevel@tonic-gate 		break;
11257c478bd9Sstevel@tonic-gate 	}
11267c478bd9Sstevel@tonic-gate }
11277c478bd9Sstevel@tonic-gate 
11287c478bd9Sstevel@tonic-gate static void
lm_dont(cmd,len)11297c478bd9Sstevel@tonic-gate lm_dont(cmd, len)
11307c478bd9Sstevel@tonic-gate 	unsigned char *cmd;
11317c478bd9Sstevel@tonic-gate 	int len;
11327c478bd9Sstevel@tonic-gate {
11337c478bd9Sstevel@tonic-gate 	if (len < 1) {
11347c478bd9Sstevel@tonic-gate 		/* Should not happen... */
11357c478bd9Sstevel@tonic-gate 		(void) printf(
11367c478bd9Sstevel@tonic-gate 		    "telnet: command missing from linemode DONT request\n");
11377c478bd9Sstevel@tonic-gate 		return;
11387c478bd9Sstevel@tonic-gate 	}
11397c478bd9Sstevel@tonic-gate 	switch (cmd[0]) {
11407c478bd9Sstevel@tonic-gate 	case LM_FORWARDMASK:
11417c478bd9Sstevel@tonic-gate 	default:
11427c478bd9Sstevel@tonic-gate 		/* we are always WONT, so don't respond */
11437c478bd9Sstevel@tonic-gate 		break;
11447c478bd9Sstevel@tonic-gate 	}
11457c478bd9Sstevel@tonic-gate }
11467c478bd9Sstevel@tonic-gate 
11477c478bd9Sstevel@tonic-gate static unsigned char str_lm_mode[] = {
11487c478bd9Sstevel@tonic-gate 	IAC, SB, TELOPT_LINEMODE, LM_MODE, 0, IAC, SE
11497c478bd9Sstevel@tonic-gate };
11507c478bd9Sstevel@tonic-gate 
11517c478bd9Sstevel@tonic-gate 	void
lm_mode(cmd,len,init)11527c478bd9Sstevel@tonic-gate lm_mode(cmd, len, init)
11537c478bd9Sstevel@tonic-gate 	unsigned char *cmd;
11547c478bd9Sstevel@tonic-gate 	int len, init;
11557c478bd9Sstevel@tonic-gate {
11567c478bd9Sstevel@tonic-gate 	if (len != 1)
11577c478bd9Sstevel@tonic-gate 		return;
11587c478bd9Sstevel@tonic-gate 	if ((linemode&MODE_MASK&~MODE_ACK) == *cmd)
11597c478bd9Sstevel@tonic-gate 		return;
11607c478bd9Sstevel@tonic-gate 	linemode = *cmd&(MODE_MASK&~MODE_ACK);
11617c478bd9Sstevel@tonic-gate 	str_lm_mode[4] = linemode;
11627c478bd9Sstevel@tonic-gate 	if (!init)
11637c478bd9Sstevel@tonic-gate 		str_lm_mode[4] |= MODE_ACK;
11647c478bd9Sstevel@tonic-gate 	if (NETROOM() > sizeof (str_lm_mode)) {
11657c478bd9Sstevel@tonic-gate 		ring_supply_data(&netoring, str_lm_mode, sizeof (str_lm_mode));
11667c478bd9Sstevel@tonic-gate 		printsub('>', &str_lm_mode[2], sizeof (str_lm_mode)-2);
11677c478bd9Sstevel@tonic-gate 	}
11687c478bd9Sstevel@tonic-gate 	else
11697c478bd9Sstevel@tonic-gate 		(void) printf("telnet: not enough room in buffer for"
11707c478bd9Sstevel@tonic-gate 		    "reply to linemode request\n");
11717c478bd9Sstevel@tonic-gate 	setconnmode(0);	/* set changed mode */
11727c478bd9Sstevel@tonic-gate }
11737c478bd9Sstevel@tonic-gate 
11747c478bd9Sstevel@tonic-gate 
11757c478bd9Sstevel@tonic-gate 
11767c478bd9Sstevel@tonic-gate /*
11777c478bd9Sstevel@tonic-gate  * slc()
11787c478bd9Sstevel@tonic-gate  * Handle special character suboption of LINEMODE.
11797c478bd9Sstevel@tonic-gate  */
11807c478bd9Sstevel@tonic-gate 
11817c478bd9Sstevel@tonic-gate static struct spc {
11827c478bd9Sstevel@tonic-gate 	cc_t val;
11837c478bd9Sstevel@tonic-gate 	cc_t *valp;
11847c478bd9Sstevel@tonic-gate 	char flags;	/* Current flags & level */
11857c478bd9Sstevel@tonic-gate 	char mylevel;	/* Maximum level & flags */
11867c478bd9Sstevel@tonic-gate } spc_data[NSLC+1];
11877c478bd9Sstevel@tonic-gate 
11887c478bd9Sstevel@tonic-gate #define	SLC_IMPORT	0
11897c478bd9Sstevel@tonic-gate #define	SLC_EXPORT	1
11907c478bd9Sstevel@tonic-gate #define	SLC_RVALUE	2
11917c478bd9Sstevel@tonic-gate static int slc_mode = SLC_EXPORT;
11927c478bd9Sstevel@tonic-gate 
11937c478bd9Sstevel@tonic-gate static void
slc_init()11947c478bd9Sstevel@tonic-gate slc_init()
11957c478bd9Sstevel@tonic-gate {
11967c478bd9Sstevel@tonic-gate 	register struct spc *spcp;
11977c478bd9Sstevel@tonic-gate 
11987c478bd9Sstevel@tonic-gate 	localchars = 1;
11997c478bd9Sstevel@tonic-gate 	for (spcp = spc_data; spcp < &spc_data[NSLC+1]; spcp++) {
12007c478bd9Sstevel@tonic-gate 		spcp->val = 0;
12017c478bd9Sstevel@tonic-gate 		spcp->valp = 0;
12027c478bd9Sstevel@tonic-gate 		spcp->flags = spcp->mylevel = SLC_NOSUPPORT;
12037c478bd9Sstevel@tonic-gate 	}
12047c478bd9Sstevel@tonic-gate 
12057c478bd9Sstevel@tonic-gate #define	initfunc(func, flags) { \
12067c478bd9Sstevel@tonic-gate 				spcp = &spc_data[func]; \
12077c478bd9Sstevel@tonic-gate 				if (spcp->valp = tcval(func)) { \
12087c478bd9Sstevel@tonic-gate 				    spcp->val = *spcp->valp; \
12097c478bd9Sstevel@tonic-gate 				    spcp->mylevel = SLC_VARIABLE|(flags);\
12107c478bd9Sstevel@tonic-gate 				} else { \
12117c478bd9Sstevel@tonic-gate 				    spcp->val = 0; \
12127c478bd9Sstevel@tonic-gate 				    spcp->mylevel = SLC_DEFAULT; \
12137c478bd9Sstevel@tonic-gate 				} \
12147c478bd9Sstevel@tonic-gate 			    }
12157c478bd9Sstevel@tonic-gate 
12167c478bd9Sstevel@tonic-gate 	initfunc(SLC_SYNCH, 0);
12177c478bd9Sstevel@tonic-gate 	/* No BRK */
12187c478bd9Sstevel@tonic-gate 	initfunc(SLC_AO, 0);
12197c478bd9Sstevel@tonic-gate 	initfunc(SLC_AYT, 0);
12207c478bd9Sstevel@tonic-gate 	/* No EOR */
12217c478bd9Sstevel@tonic-gate 	initfunc(SLC_ABORT, SLC_FLUSHIN|SLC_FLUSHOUT);
12227c478bd9Sstevel@tonic-gate 	initfunc(SLC_EOF, 0);
12237c478bd9Sstevel@tonic-gate 	initfunc(SLC_SUSP, SLC_FLUSHIN);
12247c478bd9Sstevel@tonic-gate 	initfunc(SLC_EC, 0);
12257c478bd9Sstevel@tonic-gate 	initfunc(SLC_EL, 0);
12267c478bd9Sstevel@tonic-gate 	initfunc(SLC_EW, 0);
12277c478bd9Sstevel@tonic-gate 	initfunc(SLC_RP, 0);
12287c478bd9Sstevel@tonic-gate 	initfunc(SLC_LNEXT, 0);
12297c478bd9Sstevel@tonic-gate 	initfunc(SLC_XON, 0);
12307c478bd9Sstevel@tonic-gate 	initfunc(SLC_XOFF, 0);
12317c478bd9Sstevel@tonic-gate 	initfunc(SLC_FORW1, 0);
12327c478bd9Sstevel@tonic-gate #ifdef	USE_TERMIO
12337c478bd9Sstevel@tonic-gate 	initfunc(SLC_FORW2, 0);
12347c478bd9Sstevel@tonic-gate 	/* No FORW2 */
12357c478bd9Sstevel@tonic-gate #endif
12367c478bd9Sstevel@tonic-gate 
12377c478bd9Sstevel@tonic-gate 	initfunc(SLC_IP, SLC_FLUSHIN|SLC_FLUSHOUT);
12387c478bd9Sstevel@tonic-gate #undef	initfunc
12397c478bd9Sstevel@tonic-gate 
12407c478bd9Sstevel@tonic-gate 	if (slc_mode == SLC_EXPORT)
12417c478bd9Sstevel@tonic-gate 		slc_export();
12427c478bd9Sstevel@tonic-gate 	else
12437c478bd9Sstevel@tonic-gate 		slc_import(1);
12447c478bd9Sstevel@tonic-gate 
12457c478bd9Sstevel@tonic-gate }
12467c478bd9Sstevel@tonic-gate 
12477c478bd9Sstevel@tonic-gate void
slcstate()12487c478bd9Sstevel@tonic-gate slcstate()
12497c478bd9Sstevel@tonic-gate {
12507c478bd9Sstevel@tonic-gate 	(void) printf("Special characters are %s values\n",
12517c478bd9Sstevel@tonic-gate 		slc_mode == SLC_IMPORT ? "remote default" :
12527c478bd9Sstevel@tonic-gate 		slc_mode == SLC_EXPORT ? "local" :
12537c478bd9Sstevel@tonic-gate 					"remote");
12547c478bd9Sstevel@tonic-gate }
12557c478bd9Sstevel@tonic-gate 
12567c478bd9Sstevel@tonic-gate void
slc_mode_export()12577c478bd9Sstevel@tonic-gate slc_mode_export()
12587c478bd9Sstevel@tonic-gate {
12597c478bd9Sstevel@tonic-gate 	slc_mode = SLC_EXPORT;
12607c478bd9Sstevel@tonic-gate 	if (my_state_is_will(TELOPT_LINEMODE))
12617c478bd9Sstevel@tonic-gate 		slc_export();
12627c478bd9Sstevel@tonic-gate }
12637c478bd9Sstevel@tonic-gate 
12647c478bd9Sstevel@tonic-gate void
slc_mode_import(def)12657c478bd9Sstevel@tonic-gate slc_mode_import(def)
12667c478bd9Sstevel@tonic-gate     int def;
12677c478bd9Sstevel@tonic-gate {
12687c478bd9Sstevel@tonic-gate     slc_mode = def ? SLC_IMPORT : SLC_RVALUE;
12697c478bd9Sstevel@tonic-gate     if (my_state_is_will(TELOPT_LINEMODE))
12707c478bd9Sstevel@tonic-gate 	slc_import(def);
12717c478bd9Sstevel@tonic-gate }
12727c478bd9Sstevel@tonic-gate 
12737c478bd9Sstevel@tonic-gate static unsigned char slc_import_val[] = {
12747c478bd9Sstevel@tonic-gate 	IAC, SB, TELOPT_LINEMODE, LM_SLC, 0, SLC_VARIABLE, 0, IAC, SE
12757c478bd9Sstevel@tonic-gate };
12767c478bd9Sstevel@tonic-gate static unsigned char slc_import_def[] = {
12777c478bd9Sstevel@tonic-gate 	IAC, SB, TELOPT_LINEMODE, LM_SLC, 0, SLC_DEFAULT, 0, IAC, SE
12787c478bd9Sstevel@tonic-gate };
12797c478bd9Sstevel@tonic-gate 
12807c478bd9Sstevel@tonic-gate static void
slc_import(def)12817c478bd9Sstevel@tonic-gate slc_import(def)
12827c478bd9Sstevel@tonic-gate 	int def;
12837c478bd9Sstevel@tonic-gate {
12847c478bd9Sstevel@tonic-gate 	if (NETROOM() > sizeof (slc_import_val)) {
12857c478bd9Sstevel@tonic-gate 		if (def) {
12867c478bd9Sstevel@tonic-gate 			ring_supply_data(&netoring, slc_import_def,
12877c478bd9Sstevel@tonic-gate 			    sizeof (slc_import_def));
12887c478bd9Sstevel@tonic-gate 			printsub('>', &slc_import_def[2],
12897c478bd9Sstevel@tonic-gate 			    sizeof (slc_import_def)-2);
12907c478bd9Sstevel@tonic-gate 		} else {
12917c478bd9Sstevel@tonic-gate 			ring_supply_data(&netoring, slc_import_val,
12927c478bd9Sstevel@tonic-gate 			    sizeof (slc_import_val));
12937c478bd9Sstevel@tonic-gate 			printsub('>', &slc_import_val[2],
12947c478bd9Sstevel@tonic-gate 			    sizeof (slc_import_val)-2);
12957c478bd9Sstevel@tonic-gate 		}
12967c478bd9Sstevel@tonic-gate 	}
12977c478bd9Sstevel@tonic-gate 	else
12987c478bd9Sstevel@tonic-gate 		(void) printf(
12997c478bd9Sstevel@tonic-gate 		    "telnet: not enough room in buffer for slc import"
13007c478bd9Sstevel@tonic-gate 		    " request\n");
13017c478bd9Sstevel@tonic-gate }
13027c478bd9Sstevel@tonic-gate 
13037c478bd9Sstevel@tonic-gate static uchar_t *slc_reply = NULL;
13047c478bd9Sstevel@tonic-gate static uchar_t *slc_replyp = NULL;
13057c478bd9Sstevel@tonic-gate /*
13067c478bd9Sstevel@tonic-gate  * The SLC reply consists of: IAC, SB, TELOPT_LINEMODE, LM_SLC,
13077c478bd9Sstevel@tonic-gate  * SLC triplets[], IAC, SE. i.e. it has a 'wrapper' of 6 control characters.
13087c478bd9Sstevel@tonic-gate  */
13097c478bd9Sstevel@tonic-gate #define	SLC_WRAPPER_SIZE 6
13107c478bd9Sstevel@tonic-gate 
13117c478bd9Sstevel@tonic-gate static void
slc_export()13127c478bd9Sstevel@tonic-gate slc_export()
13137c478bd9Sstevel@tonic-gate {
13147c478bd9Sstevel@tonic-gate 	register struct spc *spcp;
13157c478bd9Sstevel@tonic-gate 
13167c478bd9Sstevel@tonic-gate 	TerminalDefaultChars();
13177c478bd9Sstevel@tonic-gate 
13187c478bd9Sstevel@tonic-gate 	slc_start_reply(NSLC * 3);	/* 3 bytes needed per triplet */
13197c478bd9Sstevel@tonic-gate 	for (spcp = &spc_data[1]; spcp < &spc_data[NSLC+1]; spcp++) {
13207c478bd9Sstevel@tonic-gate 		if (spcp->mylevel != SLC_NOSUPPORT) {
13217c478bd9Sstevel@tonic-gate 			if (spcp->val == (cc_t)(_POSIX_VDISABLE))
13227c478bd9Sstevel@tonic-gate 				spcp->flags = SLC_NOSUPPORT;
13237c478bd9Sstevel@tonic-gate 			else
13247c478bd9Sstevel@tonic-gate 				spcp->flags = spcp->mylevel;
13257c478bd9Sstevel@tonic-gate 			if (spcp->valp)
13267c478bd9Sstevel@tonic-gate 				spcp->val = *spcp->valp;
13277c478bd9Sstevel@tonic-gate 			slc_add_reply(spcp - spc_data, spcp->flags, spcp->val);
13287c478bd9Sstevel@tonic-gate 		}
13297c478bd9Sstevel@tonic-gate 	}
13307c478bd9Sstevel@tonic-gate 	slc_end_reply();
13317c478bd9Sstevel@tonic-gate 	(void) slc_update();
13327c478bd9Sstevel@tonic-gate 	setconnmode(1);	/* Make sure the character values are set */
13337c478bd9Sstevel@tonic-gate }
13347c478bd9Sstevel@tonic-gate 
13357c478bd9Sstevel@tonic-gate static void
slc(cp,len)13367c478bd9Sstevel@tonic-gate slc(cp, len)
13377c478bd9Sstevel@tonic-gate 	register unsigned char *cp;
13387c478bd9Sstevel@tonic-gate 	int len;
13397c478bd9Sstevel@tonic-gate {
13407c478bd9Sstevel@tonic-gate 	register struct spc *spcp;
13417c478bd9Sstevel@tonic-gate 	register int func, level;
13427c478bd9Sstevel@tonic-gate 
13437c478bd9Sstevel@tonic-gate 	slc_start_reply(len);
13447c478bd9Sstevel@tonic-gate 
13457c478bd9Sstevel@tonic-gate 	for (; len >= 3; len -= 3, cp += 3) {
13467c478bd9Sstevel@tonic-gate 
13477c478bd9Sstevel@tonic-gate 		func = cp[SLC_FUNC];
13487c478bd9Sstevel@tonic-gate 
13497c478bd9Sstevel@tonic-gate 		if (func == 0) {
13507c478bd9Sstevel@tonic-gate 			/*
13517c478bd9Sstevel@tonic-gate 			 * Client side: always ignore 0 function.
13527c478bd9Sstevel@tonic-gate 			 */
13537c478bd9Sstevel@tonic-gate 			continue;
13547c478bd9Sstevel@tonic-gate 		}
13557c478bd9Sstevel@tonic-gate 		if (func > NSLC) {
13567c478bd9Sstevel@tonic-gate 			if ((cp[SLC_FLAGS] & SLC_LEVELBITS) != SLC_NOSUPPORT)
13577c478bd9Sstevel@tonic-gate 				slc_add_reply(func, SLC_NOSUPPORT, 0);
13587c478bd9Sstevel@tonic-gate 			continue;
13597c478bd9Sstevel@tonic-gate 		}
13607c478bd9Sstevel@tonic-gate 
13617c478bd9Sstevel@tonic-gate 		spcp = &spc_data[func];
13627c478bd9Sstevel@tonic-gate 
13637c478bd9Sstevel@tonic-gate 		level = cp[SLC_FLAGS]&(SLC_LEVELBITS|SLC_ACK);
13647c478bd9Sstevel@tonic-gate 
13657c478bd9Sstevel@tonic-gate 		if ((cp[SLC_VALUE] == (unsigned char)spcp->val) &&
13667c478bd9Sstevel@tonic-gate 		    ((level&SLC_LEVELBITS) == (spcp->flags&SLC_LEVELBITS))) {
13677c478bd9Sstevel@tonic-gate 			continue;
13687c478bd9Sstevel@tonic-gate 		}
13697c478bd9Sstevel@tonic-gate 
13707c478bd9Sstevel@tonic-gate 		if (level == (SLC_DEFAULT|SLC_ACK)) {
13717c478bd9Sstevel@tonic-gate 			/*
13727c478bd9Sstevel@tonic-gate 			 * This is an error condition, the SLC_ACK
13737c478bd9Sstevel@tonic-gate 			 * bit should never be set for the SLC_DEFAULT
13747c478bd9Sstevel@tonic-gate 			 * level.  Our best guess to recover is to
13757c478bd9Sstevel@tonic-gate 			 * ignore the SLC_ACK bit.
13767c478bd9Sstevel@tonic-gate 			 */
13777c478bd9Sstevel@tonic-gate 			cp[SLC_FLAGS] &= ~SLC_ACK;
13787c478bd9Sstevel@tonic-gate 		}
13797c478bd9Sstevel@tonic-gate 
13807c478bd9Sstevel@tonic-gate 		if (level == ((spcp->flags&SLC_LEVELBITS)|SLC_ACK)) {
13817c478bd9Sstevel@tonic-gate 			spcp->val = (cc_t)cp[SLC_VALUE];
13827c478bd9Sstevel@tonic-gate 			spcp->flags = cp[SLC_FLAGS];	/* include SLC_ACK */
13837c478bd9Sstevel@tonic-gate 			continue;
13847c478bd9Sstevel@tonic-gate 		}
13857c478bd9Sstevel@tonic-gate 
13867c478bd9Sstevel@tonic-gate 		level &= ~SLC_ACK;
13877c478bd9Sstevel@tonic-gate 
13887c478bd9Sstevel@tonic-gate 		if (level <= (spcp->mylevel&SLC_LEVELBITS)) {
13897c478bd9Sstevel@tonic-gate 			spcp->flags = cp[SLC_FLAGS]|SLC_ACK;
13907c478bd9Sstevel@tonic-gate 			spcp->val = (cc_t)cp[SLC_VALUE];
13917c478bd9Sstevel@tonic-gate 		}
13927c478bd9Sstevel@tonic-gate 		if (level == SLC_DEFAULT) {
13937c478bd9Sstevel@tonic-gate 			if ((spcp->mylevel&SLC_LEVELBITS) != SLC_DEFAULT)
13947c478bd9Sstevel@tonic-gate 				spcp->flags = spcp->mylevel;
13957c478bd9Sstevel@tonic-gate 			else
13967c478bd9Sstevel@tonic-gate 				spcp->flags = SLC_NOSUPPORT;
13977c478bd9Sstevel@tonic-gate 		}
13987c478bd9Sstevel@tonic-gate 		slc_add_reply(func, spcp->flags, spcp->val);
13997c478bd9Sstevel@tonic-gate 	}
14007c478bd9Sstevel@tonic-gate 	slc_end_reply();
14017c478bd9Sstevel@tonic-gate 	if (slc_update())
14027c478bd9Sstevel@tonic-gate 		setconnmode(1);	/* set the  new character values */
14037c478bd9Sstevel@tonic-gate }
14047c478bd9Sstevel@tonic-gate 
14057c478bd9Sstevel@tonic-gate void
slc_check()14067c478bd9Sstevel@tonic-gate slc_check()
14077c478bd9Sstevel@tonic-gate {
14087c478bd9Sstevel@tonic-gate 	register struct spc *spcp;
14097c478bd9Sstevel@tonic-gate 
14107c478bd9Sstevel@tonic-gate 	slc_start_reply(NSLC * 3);	/* 3 bytes needed per triplet */
14117c478bd9Sstevel@tonic-gate 	for (spcp = &spc_data[1]; spcp < &spc_data[NSLC+1]; spcp++) {
14127c478bd9Sstevel@tonic-gate 		if (spcp->valp && spcp->val != *spcp->valp) {
14137c478bd9Sstevel@tonic-gate 			spcp->val = *spcp->valp;
14147c478bd9Sstevel@tonic-gate 			if (spcp->val == (cc_t)(_POSIX_VDISABLE))
14157c478bd9Sstevel@tonic-gate 				spcp->flags = SLC_NOSUPPORT;
14167c478bd9Sstevel@tonic-gate 			else
14177c478bd9Sstevel@tonic-gate 				spcp->flags = spcp->mylevel;
14187c478bd9Sstevel@tonic-gate 			slc_add_reply(spcp - spc_data, spcp->flags, spcp->val);
14197c478bd9Sstevel@tonic-gate 		}
14207c478bd9Sstevel@tonic-gate 	}
14217c478bd9Sstevel@tonic-gate 	slc_end_reply();
14227c478bd9Sstevel@tonic-gate 	setconnmode(1);
14237c478bd9Sstevel@tonic-gate }
14247c478bd9Sstevel@tonic-gate 
14257c478bd9Sstevel@tonic-gate static void
slc_start_reply(size_t len)14267c478bd9Sstevel@tonic-gate slc_start_reply(size_t len)
14277c478bd9Sstevel@tonic-gate {
14287c478bd9Sstevel@tonic-gate 	/*
14297c478bd9Sstevel@tonic-gate 	 * SLC triplets may contain escaped characters, allow for
14307c478bd9Sstevel@tonic-gate 	 * worst case by allocating 2 bytes for every character.
14317c478bd9Sstevel@tonic-gate 	 */
14327c478bd9Sstevel@tonic-gate 	slc_reply = realloc(slc_reply, (len * 2) + SLC_WRAPPER_SIZE);
14337c478bd9Sstevel@tonic-gate 	if (slc_reply == NULL) {
14347c478bd9Sstevel@tonic-gate 		fprintf(stderr, "telnet: error allocating SLC reply memory\n");
14357c478bd9Sstevel@tonic-gate 		return;
14367c478bd9Sstevel@tonic-gate 	}
14377c478bd9Sstevel@tonic-gate 	slc_replyp = slc_reply;
14387c478bd9Sstevel@tonic-gate 	*slc_replyp++ = IAC;
14397c478bd9Sstevel@tonic-gate 	*slc_replyp++ = SB;
14407c478bd9Sstevel@tonic-gate 	*slc_replyp++ = TELOPT_LINEMODE;
14417c478bd9Sstevel@tonic-gate 	*slc_replyp++ = LM_SLC;
14427c478bd9Sstevel@tonic-gate }
14437c478bd9Sstevel@tonic-gate 
14447c478bd9Sstevel@tonic-gate static void
slc_add_reply(unsigned char func,unsigned char flags,cc_t value)14457c478bd9Sstevel@tonic-gate slc_add_reply(unsigned char func, unsigned char flags, cc_t value)
14467c478bd9Sstevel@tonic-gate {
14477c478bd9Sstevel@tonic-gate 	if ((*slc_replyp++ = func) == IAC)
14487c478bd9Sstevel@tonic-gate 		*slc_replyp++ = IAC;
14497c478bd9Sstevel@tonic-gate 	if ((*slc_replyp++ = flags) == IAC)
14507c478bd9Sstevel@tonic-gate 		*slc_replyp++ = IAC;
14517c478bd9Sstevel@tonic-gate 	if ((*slc_replyp++ = (unsigned char)value) == IAC)
14527c478bd9Sstevel@tonic-gate 		*slc_replyp++ = IAC;
14537c478bd9Sstevel@tonic-gate }
14547c478bd9Sstevel@tonic-gate 
14557c478bd9Sstevel@tonic-gate static void
slc_end_reply()14567c478bd9Sstevel@tonic-gate slc_end_reply()
14577c478bd9Sstevel@tonic-gate {
14587c478bd9Sstevel@tonic-gate 	register int len;
14597c478bd9Sstevel@tonic-gate 
14607c478bd9Sstevel@tonic-gate 	*slc_replyp++ = IAC;
14617c478bd9Sstevel@tonic-gate 	*slc_replyp++ = SE;
14627c478bd9Sstevel@tonic-gate 	len = slc_replyp - slc_reply;
14637c478bd9Sstevel@tonic-gate 	if (len <= SLC_WRAPPER_SIZE)
14647c478bd9Sstevel@tonic-gate 		return;
14657c478bd9Sstevel@tonic-gate 	if (NETROOM() > len) {
14667c478bd9Sstevel@tonic-gate 		ring_supply_data(&netoring, slc_reply, slc_replyp - slc_reply);
14677c478bd9Sstevel@tonic-gate 		printsub('>', &slc_reply[2], slc_replyp - slc_reply - 2);
14687c478bd9Sstevel@tonic-gate 	}
14697c478bd9Sstevel@tonic-gate 	else
14707c478bd9Sstevel@tonic-gate 		(void) printf("telnet: not enough room in buffer for slc end "
14717c478bd9Sstevel@tonic-gate 		    "reply\n");
14727c478bd9Sstevel@tonic-gate }
14737c478bd9Sstevel@tonic-gate 
14747c478bd9Sstevel@tonic-gate static int
slc_update()14757c478bd9Sstevel@tonic-gate slc_update()
14767c478bd9Sstevel@tonic-gate {
14777c478bd9Sstevel@tonic-gate 	register struct spc *spcp;
14787c478bd9Sstevel@tonic-gate 	int need_update = 0;
14797c478bd9Sstevel@tonic-gate 
14807c478bd9Sstevel@tonic-gate 	for (spcp = &spc_data[1]; spcp < &spc_data[NSLC+1]; spcp++) {
14817c478bd9Sstevel@tonic-gate 		if (!(spcp->flags&SLC_ACK))
14827c478bd9Sstevel@tonic-gate 			continue;
14837c478bd9Sstevel@tonic-gate 		spcp->flags &= ~SLC_ACK;
14847c478bd9Sstevel@tonic-gate 		if (spcp->valp && (*spcp->valp != spcp->val)) {
14857c478bd9Sstevel@tonic-gate 			*spcp->valp = spcp->val;
14867c478bd9Sstevel@tonic-gate 			need_update = 1;
14877c478bd9Sstevel@tonic-gate 		}
14887c478bd9Sstevel@tonic-gate 	}
14897c478bd9Sstevel@tonic-gate 	return (need_update);
14907c478bd9Sstevel@tonic-gate }
14917c478bd9Sstevel@tonic-gate 
14927c478bd9Sstevel@tonic-gate #ifdef	OLD_ENVIRON
14937c478bd9Sstevel@tonic-gate #ifdef	ENV_HACK
14947c478bd9Sstevel@tonic-gate /*
14957c478bd9Sstevel@tonic-gate  * Earlier version of telnet/telnetd from the BSD code had
14967c478bd9Sstevel@tonic-gate  * the definitions of VALUE and VAR reversed.  To ensure
14977c478bd9Sstevel@tonic-gate  * maximum interoperability, we assume that the server is
14987c478bd9Sstevel@tonic-gate  * an older BSD server, until proven otherwise.  The newer
14997c478bd9Sstevel@tonic-gate  * BSD servers should be able to handle either definition,
15007c478bd9Sstevel@tonic-gate  * so it is better to use the wrong values if we don't
15017c478bd9Sstevel@tonic-gate  * know what type of server it is.
15027c478bd9Sstevel@tonic-gate  */
15037c478bd9Sstevel@tonic-gate int env_auto = 1;
15047c478bd9Sstevel@tonic-gate int old_env_var = OLD_ENV_VAR;
15057c478bd9Sstevel@tonic-gate int old_env_value = OLD_ENV_VALUE;
15067c478bd9Sstevel@tonic-gate #else
15077c478bd9Sstevel@tonic-gate #define	old_env_var	OLD_ENV_VAR
15087c478bd9Sstevel@tonic-gate #define	old_env_value	OLD_ENV_VALUE
15097c478bd9Sstevel@tonic-gate #endif
15107c478bd9Sstevel@tonic-gate #endif
15117c478bd9Sstevel@tonic-gate 
15127c478bd9Sstevel@tonic-gate static void
env_opt(buf,len)15137c478bd9Sstevel@tonic-gate env_opt(buf, len)
15147c478bd9Sstevel@tonic-gate 	register unsigned char *buf;
15157c478bd9Sstevel@tonic-gate 	register int len;
15167c478bd9Sstevel@tonic-gate {
15177c478bd9Sstevel@tonic-gate 	register unsigned char *ep = 0, *epc = 0;
15187c478bd9Sstevel@tonic-gate 	register int i;
15197c478bd9Sstevel@tonic-gate 
15207c478bd9Sstevel@tonic-gate 	switch (buf[0]&0xff) {
15217c478bd9Sstevel@tonic-gate 	case TELQUAL_SEND:
15227c478bd9Sstevel@tonic-gate 		env_opt_start();
15237c478bd9Sstevel@tonic-gate 		if (len == 1) {
15247c478bd9Sstevel@tonic-gate 			env_opt_add(NULL);
15257c478bd9Sstevel@tonic-gate 		} else for (i = 1; i < len; i++) {
15267c478bd9Sstevel@tonic-gate 			switch (buf[i]&0xff) {
15277c478bd9Sstevel@tonic-gate #ifdef	OLD_ENVIRON
15287c478bd9Sstevel@tonic-gate 			case OLD_ENV_VAR:
15297c478bd9Sstevel@tonic-gate #ifdef	ENV_HACK
15307c478bd9Sstevel@tonic-gate 				if (telopt_environ == TELOPT_OLD_ENVIRON &&
15317c478bd9Sstevel@tonic-gate 				    env_auto) {
15327c478bd9Sstevel@tonic-gate 					/* Server has the same definitions */
15337c478bd9Sstevel@tonic-gate 					old_env_var = OLD_ENV_VAR;
15347c478bd9Sstevel@tonic-gate 					old_env_value = OLD_ENV_VALUE;
15357c478bd9Sstevel@tonic-gate 				}
15367c478bd9Sstevel@tonic-gate 				/* FALLTHROUGH */
15377c478bd9Sstevel@tonic-gate #endif
15387c478bd9Sstevel@tonic-gate 			case OLD_ENV_VALUE:
15397c478bd9Sstevel@tonic-gate 				/*
15407c478bd9Sstevel@tonic-gate 				 * Although OLD_ENV_VALUE is not legal, we will
15417c478bd9Sstevel@tonic-gate 				 * still recognize it, just in case it is an
15427c478bd9Sstevel@tonic-gate 				 * old server that has VAR & VALUE mixed up...
15437c478bd9Sstevel@tonic-gate 				 */
15447c478bd9Sstevel@tonic-gate 				/* FALLTHROUGH */
15457c478bd9Sstevel@tonic-gate #else
15467c478bd9Sstevel@tonic-gate 			case NEW_ENV_VAR:
15477c478bd9Sstevel@tonic-gate #endif
15487c478bd9Sstevel@tonic-gate 			case ENV_USERVAR:
15497c478bd9Sstevel@tonic-gate 				if (ep) {
15507c478bd9Sstevel@tonic-gate 					*epc = 0;
15517c478bd9Sstevel@tonic-gate 					env_opt_add(ep);
15527c478bd9Sstevel@tonic-gate 				}
15537c478bd9Sstevel@tonic-gate 				ep = epc = &buf[i+1];
15547c478bd9Sstevel@tonic-gate 				break;
15557c478bd9Sstevel@tonic-gate 			case ENV_ESC:
15567c478bd9Sstevel@tonic-gate 				i++;
15577c478bd9Sstevel@tonic-gate 				/*FALLTHROUGH*/
15587c478bd9Sstevel@tonic-gate 			default:
15597c478bd9Sstevel@tonic-gate 				if (epc)
15607c478bd9Sstevel@tonic-gate 					*epc++ = buf[i];
15617c478bd9Sstevel@tonic-gate 				break;
15627c478bd9Sstevel@tonic-gate 			}
15637c478bd9Sstevel@tonic-gate 		}
15647c478bd9Sstevel@tonic-gate 		if (ep) {
15657c478bd9Sstevel@tonic-gate 			*epc = 0;
15667c478bd9Sstevel@tonic-gate 			env_opt_add(ep);
15677c478bd9Sstevel@tonic-gate 		}
15687c478bd9Sstevel@tonic-gate 		env_opt_end(1);
15697c478bd9Sstevel@tonic-gate 		break;
15707c478bd9Sstevel@tonic-gate 
15717c478bd9Sstevel@tonic-gate 	case TELQUAL_IS:
15727c478bd9Sstevel@tonic-gate 	case TELQUAL_INFO:
15737c478bd9Sstevel@tonic-gate 		/* Ignore for now.  We shouldn't get it anyway. */
15747c478bd9Sstevel@tonic-gate 		break;
15757c478bd9Sstevel@tonic-gate 
15767c478bd9Sstevel@tonic-gate 	default:
15777c478bd9Sstevel@tonic-gate 		break;
15787c478bd9Sstevel@tonic-gate 	}
15797c478bd9Sstevel@tonic-gate }
15807c478bd9Sstevel@tonic-gate 
15817c478bd9Sstevel@tonic-gate static unsigned char *opt_reply;
15827c478bd9Sstevel@tonic-gate static unsigned char *opt_replyp;
15837c478bd9Sstevel@tonic-gate static unsigned char *opt_replyend;
15847c478bd9Sstevel@tonic-gate #define	OPT_REPLY_INITIAL_SIZE	256
15857c478bd9Sstevel@tonic-gate /*
15867c478bd9Sstevel@tonic-gate  * The opt reply consists of: IAC, SB, telopt_environ, TELQUAL_IS,
15877c478bd9Sstevel@tonic-gate  * value, IAC, SE. i.e. it has a 'wrapper' of 6 control characters.
15887c478bd9Sstevel@tonic-gate  */
15897c478bd9Sstevel@tonic-gate #define	OPT_WRAPPER_SIZE 6
15907c478bd9Sstevel@tonic-gate 
15917c478bd9Sstevel@tonic-gate static void
env_opt_start()15927c478bd9Sstevel@tonic-gate env_opt_start()
15937c478bd9Sstevel@tonic-gate {
15947c478bd9Sstevel@tonic-gate 	opt_reply = realloc(opt_reply, OPT_REPLY_INITIAL_SIZE);
15957c478bd9Sstevel@tonic-gate 	if (opt_reply == NULL) {
15967c478bd9Sstevel@tonic-gate 		(void) printf(
15977c478bd9Sstevel@tonic-gate 		    "telnet: error allocating environment option memory\n");
15987c478bd9Sstevel@tonic-gate 		opt_reply = opt_replyp = opt_replyend = NULL;
15997c478bd9Sstevel@tonic-gate 		return;
16007c478bd9Sstevel@tonic-gate 	}
16017c478bd9Sstevel@tonic-gate 	opt_replyp = opt_reply;
16027c478bd9Sstevel@tonic-gate 	opt_replyend = opt_reply + OPT_REPLY_INITIAL_SIZE;
16037c478bd9Sstevel@tonic-gate 	*opt_replyp++ = IAC;
16047c478bd9Sstevel@tonic-gate 	*opt_replyp++ = SB;
16057c478bd9Sstevel@tonic-gate 	*opt_replyp++ = telopt_environ;
16067c478bd9Sstevel@tonic-gate 	*opt_replyp++ = TELQUAL_IS;
16077c478bd9Sstevel@tonic-gate }
16087c478bd9Sstevel@tonic-gate 
16097c478bd9Sstevel@tonic-gate 	void
env_opt_start_info()16107c478bd9Sstevel@tonic-gate env_opt_start_info()
16117c478bd9Sstevel@tonic-gate {
16127c478bd9Sstevel@tonic-gate 	env_opt_start();
16137c478bd9Sstevel@tonic-gate 	if (opt_replyp)
16147c478bd9Sstevel@tonic-gate 	    opt_replyp[-1] = TELQUAL_INFO;
16157c478bd9Sstevel@tonic-gate }
16167c478bd9Sstevel@tonic-gate 
16177c478bd9Sstevel@tonic-gate 	void
env_opt_add(ep)16187c478bd9Sstevel@tonic-gate env_opt_add(ep)
16197c478bd9Sstevel@tonic-gate 	register unsigned char *ep;
16207c478bd9Sstevel@tonic-gate {
16217c478bd9Sstevel@tonic-gate 	register unsigned char *vp, c;
16227c478bd9Sstevel@tonic-gate 	int opt_reply_size;
16237c478bd9Sstevel@tonic-gate 	int opt_reply_used;
16247c478bd9Sstevel@tonic-gate 
16257c478bd9Sstevel@tonic-gate 	if (opt_reply == NULL)		/* XXX */
16267c478bd9Sstevel@tonic-gate 		return;			/* XXX */
16277c478bd9Sstevel@tonic-gate 
16287c478bd9Sstevel@tonic-gate 	if (ep == NULL || *ep == '\0') {
16297c478bd9Sstevel@tonic-gate 		/* Send user defined variables first. */
16307c478bd9Sstevel@tonic-gate 		(void) env_default(1, 0);
16317c478bd9Sstevel@tonic-gate 		while (ep = env_default(0, 0))
16327c478bd9Sstevel@tonic-gate 			env_opt_add(ep);
16337c478bd9Sstevel@tonic-gate 
16347c478bd9Sstevel@tonic-gate 		/* Now add the list of well know variables.  */
16357c478bd9Sstevel@tonic-gate 		(void) env_default(1, 1);
16367c478bd9Sstevel@tonic-gate 		while (ep = env_default(0, 1))
16377c478bd9Sstevel@tonic-gate 			env_opt_add(ep);
16387c478bd9Sstevel@tonic-gate 		return;
16397c478bd9Sstevel@tonic-gate 	}
16407c478bd9Sstevel@tonic-gate 	vp = env_getvalue(ep);
16417c478bd9Sstevel@tonic-gate 
16427c478bd9Sstevel@tonic-gate 	/*
16437c478bd9Sstevel@tonic-gate 	 * Calculate space required for opt_reply and allocate more if required.
16447c478bd9Sstevel@tonic-gate 	 * Assume worst case that every character is escaped, so needs 2 bytes.
16457c478bd9Sstevel@tonic-gate 	 */
16467c478bd9Sstevel@tonic-gate 	opt_reply_used = opt_replyp - opt_reply;	/* existing contents */
16477c478bd9Sstevel@tonic-gate 	opt_reply_size = opt_reply_used + OPT_WRAPPER_SIZE +
16487c478bd9Sstevel@tonic-gate 	    (2 * (strlen((char *)ep))) +
16497c478bd9Sstevel@tonic-gate 	    (vp == NULL ? 0 : (2 * strlen((char *)vp)));
16507c478bd9Sstevel@tonic-gate 
16517c478bd9Sstevel@tonic-gate 	if (opt_reply_size > (opt_replyend - opt_reply)) {
16527c478bd9Sstevel@tonic-gate 		opt_reply = realloc(opt_reply, opt_reply_size);
16537c478bd9Sstevel@tonic-gate 		if (opt_reply == NULL) {
16547c478bd9Sstevel@tonic-gate 			(void) printf(
16557c478bd9Sstevel@tonic-gate 			    "telnet: can't allocate environment option "
16567c478bd9Sstevel@tonic-gate 			    "reply\n");
16577c478bd9Sstevel@tonic-gate 			opt_reply = opt_replyp = opt_replyend = NULL;
16587c478bd9Sstevel@tonic-gate 			return;
16597c478bd9Sstevel@tonic-gate 		}
16607c478bd9Sstevel@tonic-gate 		opt_replyp = opt_reply + opt_reply_used;
16617c478bd9Sstevel@tonic-gate 		opt_replyend = opt_reply + opt_reply_size;
16627c478bd9Sstevel@tonic-gate 	}
16637c478bd9Sstevel@tonic-gate 
16647c478bd9Sstevel@tonic-gate 	if (opt_welldefined((char *)ep))
16657c478bd9Sstevel@tonic-gate #ifdef	OLD_ENVIRON
16667c478bd9Sstevel@tonic-gate 		if (telopt_environ == TELOPT_OLD_ENVIRON)
16677c478bd9Sstevel@tonic-gate 			*opt_replyp++ = old_env_var;
16687c478bd9Sstevel@tonic-gate 		else
16697c478bd9Sstevel@tonic-gate #endif
16707c478bd9Sstevel@tonic-gate 			*opt_replyp++ = NEW_ENV_VAR;
16717c478bd9Sstevel@tonic-gate 	else
16727c478bd9Sstevel@tonic-gate 		*opt_replyp++ = ENV_USERVAR;
16737c478bd9Sstevel@tonic-gate 	for (;;) {
1674*95c74518SToomas Soome 		while ((c = *ep++) != '\0') {
16757c478bd9Sstevel@tonic-gate 			switch (c&0xff) {
16767c478bd9Sstevel@tonic-gate 			case IAC:
16777c478bd9Sstevel@tonic-gate 				*opt_replyp++ = IAC;
16787c478bd9Sstevel@tonic-gate 				break;
16797c478bd9Sstevel@tonic-gate 			case NEW_ENV_VAR:
16807c478bd9Sstevel@tonic-gate 			case NEW_ENV_VALUE:
16817c478bd9Sstevel@tonic-gate 			case ENV_ESC:
16827c478bd9Sstevel@tonic-gate 			case ENV_USERVAR:
16837c478bd9Sstevel@tonic-gate 				*opt_replyp++ = ENV_ESC;
16847c478bd9Sstevel@tonic-gate 				break;
16857c478bd9Sstevel@tonic-gate 			}
16867c478bd9Sstevel@tonic-gate 			*opt_replyp++ = c;
16877c478bd9Sstevel@tonic-gate 		}
16887c478bd9Sstevel@tonic-gate 		if ((ep = vp) != NULL) {
16897c478bd9Sstevel@tonic-gate #ifdef	OLD_ENVIRON
16907c478bd9Sstevel@tonic-gate 			if (telopt_environ == TELOPT_OLD_ENVIRON)
16917c478bd9Sstevel@tonic-gate 				*opt_replyp++ = old_env_value;
16927c478bd9Sstevel@tonic-gate 			else
16937c478bd9Sstevel@tonic-gate #endif
16947c478bd9Sstevel@tonic-gate 				*opt_replyp++ = NEW_ENV_VALUE;
16957c478bd9Sstevel@tonic-gate 			vp = NULL;
16967c478bd9Sstevel@tonic-gate 		} else
16977c478bd9Sstevel@tonic-gate 			break;
16987c478bd9Sstevel@tonic-gate 	}
16997c478bd9Sstevel@tonic-gate }
17007c478bd9Sstevel@tonic-gate 
17017c478bd9Sstevel@tonic-gate 	int
opt_welldefined(ep)17027c478bd9Sstevel@tonic-gate opt_welldefined(ep)
17037c478bd9Sstevel@tonic-gate 	char *ep;
17047c478bd9Sstevel@tonic-gate {
17057c478bd9Sstevel@tonic-gate 	if ((strcmp(ep, "USER") == 0) ||
17067c478bd9Sstevel@tonic-gate 	    (strcmp(ep, "DISPLAY") == 0) ||
17077c478bd9Sstevel@tonic-gate 	    (strcmp(ep, "PRINTER") == 0) ||
17087c478bd9Sstevel@tonic-gate 	    (strcmp(ep, "SYSTEMTYPE") == 0) ||
17097c478bd9Sstevel@tonic-gate 	    (strcmp(ep, "JOB") == 0) ||
17107c478bd9Sstevel@tonic-gate 	    (strcmp(ep, "ACCT") == 0))
17117c478bd9Sstevel@tonic-gate 		return (1);
17127c478bd9Sstevel@tonic-gate 	return (0);
17137c478bd9Sstevel@tonic-gate }
17147c478bd9Sstevel@tonic-gate 	void
env_opt_end(emptyok)17157c478bd9Sstevel@tonic-gate env_opt_end(emptyok)
17167c478bd9Sstevel@tonic-gate 	register int emptyok;
17177c478bd9Sstevel@tonic-gate {
17187c478bd9Sstevel@tonic-gate 	register int len;
17197c478bd9Sstevel@tonic-gate 
17207c478bd9Sstevel@tonic-gate 	len = opt_replyp - opt_reply + 2;
17217c478bd9Sstevel@tonic-gate 	if (emptyok || len > OPT_WRAPPER_SIZE) {
17227c478bd9Sstevel@tonic-gate 		*opt_replyp++ = IAC;
17237c478bd9Sstevel@tonic-gate 		*opt_replyp++ = SE;
17247c478bd9Sstevel@tonic-gate 		if (NETROOM() > len) {
17257c478bd9Sstevel@tonic-gate 			ring_supply_data(&netoring, opt_reply, len);
17267c478bd9Sstevel@tonic-gate 			printsub('>', &opt_reply[2], len - 2);
17277c478bd9Sstevel@tonic-gate 		}
17287c478bd9Sstevel@tonic-gate 		else
17297c478bd9Sstevel@tonic-gate 			(void) printf("telnet: not enough room in buffer for "
17307c478bd9Sstevel@tonic-gate 			    "environment option end reply\n");
17317c478bd9Sstevel@tonic-gate 	}
17327c478bd9Sstevel@tonic-gate 	if (opt_reply) {
17337c478bd9Sstevel@tonic-gate 		free(opt_reply);
17347c478bd9Sstevel@tonic-gate 		opt_reply = opt_replyp = opt_replyend = NULL;
17357c478bd9Sstevel@tonic-gate 	}
17367c478bd9Sstevel@tonic-gate }
17377c478bd9Sstevel@tonic-gate 
17387c478bd9Sstevel@tonic-gate 
17397c478bd9Sstevel@tonic-gate 
17407c478bd9Sstevel@tonic-gate int
telrcv()17417c478bd9Sstevel@tonic-gate telrcv()
17427c478bd9Sstevel@tonic-gate {
17437c478bd9Sstevel@tonic-gate 	register int c;
17447c478bd9Sstevel@tonic-gate 	register int scc;
17457c478bd9Sstevel@tonic-gate 	register unsigned char *sbp;
17467c478bd9Sstevel@tonic-gate 	int count;
17477c478bd9Sstevel@tonic-gate 	int returnValue = 0;
17487c478bd9Sstevel@tonic-gate 	int min_room = 0;
17497c478bd9Sstevel@tonic-gate 
17507c478bd9Sstevel@tonic-gate 	scc = 0;
17517c478bd9Sstevel@tonic-gate 	count = 0;
17527c478bd9Sstevel@tonic-gate 	while (--min_room > 2 || (min_room = TTYROOM()) > 2) {
17537c478bd9Sstevel@tonic-gate 		if (scc == 0) {
17547c478bd9Sstevel@tonic-gate 			if (count) {
17557c478bd9Sstevel@tonic-gate 				ring_consumed(&netiring, count);
17567c478bd9Sstevel@tonic-gate 				returnValue = 1;
17577c478bd9Sstevel@tonic-gate 				count = 0;
17587c478bd9Sstevel@tonic-gate 			}
17597c478bd9Sstevel@tonic-gate 			sbp = netiring.consume;
17607c478bd9Sstevel@tonic-gate 			scc = ring_full_consecutive(&netiring);
17617c478bd9Sstevel@tonic-gate 			if (scc == 0) {
17627c478bd9Sstevel@tonic-gate 				/* No more data coming in */
17637c478bd9Sstevel@tonic-gate 				break;
17647c478bd9Sstevel@tonic-gate 			}
17657c478bd9Sstevel@tonic-gate 		}
17667c478bd9Sstevel@tonic-gate 
17677c478bd9Sstevel@tonic-gate 		c = *sbp++ & 0xff, scc--; count++;
17687c478bd9Sstevel@tonic-gate 
17697c478bd9Sstevel@tonic-gate 		if (decrypt_input)
17707c478bd9Sstevel@tonic-gate 			c = (*decrypt_input)(c);
17717c478bd9Sstevel@tonic-gate 
17727c478bd9Sstevel@tonic-gate 		switch (telrcv_state) {
17737c478bd9Sstevel@tonic-gate 
17747c478bd9Sstevel@tonic-gate 		case TS_CR:
17757c478bd9Sstevel@tonic-gate 			telrcv_state = TS_DATA;
17767c478bd9Sstevel@tonic-gate 			if (c == '\0') {
17777c478bd9Sstevel@tonic-gate 				break;	/* Ignore \0 after CR */
17787c478bd9Sstevel@tonic-gate 			} else if ((c == '\n') &&
17797c478bd9Sstevel@tonic-gate 			    my_want_state_is_dont(TELOPT_ECHO) && !crmod) {
17807c478bd9Sstevel@tonic-gate 				TTYADD(c);
17817c478bd9Sstevel@tonic-gate 				break;
17827c478bd9Sstevel@tonic-gate 			}
17837c478bd9Sstevel@tonic-gate 			/* FALLTHROUGH */
17847c478bd9Sstevel@tonic-gate 
17857c478bd9Sstevel@tonic-gate 		case TS_DATA:
17867c478bd9Sstevel@tonic-gate 			if (c == IAC) {
17877c478bd9Sstevel@tonic-gate 				telrcv_state = TS_IAC;
17887c478bd9Sstevel@tonic-gate 				break;
17897c478bd9Sstevel@tonic-gate 			}
17907c478bd9Sstevel@tonic-gate 			/*
17917c478bd9Sstevel@tonic-gate 			 * The 'crmod' hack (see following) is needed
17927c478bd9Sstevel@tonic-gate 			 * since we can't * set CRMOD on output only.
17937c478bd9Sstevel@tonic-gate 			 * Machines like MULTICS like to send \r without
17947c478bd9Sstevel@tonic-gate 			 * \n; since we must turn off CRMOD to get proper
17957c478bd9Sstevel@tonic-gate 			 * input, the mapping is done here (sigh).
17967c478bd9Sstevel@tonic-gate 			 */
17977c478bd9Sstevel@tonic-gate 			if ((c == '\r') &&
17987c478bd9Sstevel@tonic-gate 			    my_want_state_is_dont(TELOPT_BINARY)) {
17997c478bd9Sstevel@tonic-gate 				if (scc > 0) {
18007c478bd9Sstevel@tonic-gate 					c = *sbp&0xff;
18017c478bd9Sstevel@tonic-gate 
18027c478bd9Sstevel@tonic-gate 					if (decrypt_input)
18037c478bd9Sstevel@tonic-gate 						c = (*decrypt_input)(c);
18047c478bd9Sstevel@tonic-gate 
18057c478bd9Sstevel@tonic-gate 					if (c == 0) {
18067c478bd9Sstevel@tonic-gate 						sbp++, scc--; count++;
18077c478bd9Sstevel@tonic-gate 						/* a "true" CR */
18087c478bd9Sstevel@tonic-gate 						TTYADD('\r');
18097c478bd9Sstevel@tonic-gate 					} else if (my_want_state_is_dont(
18107c478bd9Sstevel@tonic-gate 					    TELOPT_ECHO) && (c == '\n')) {
18117c478bd9Sstevel@tonic-gate 						sbp++, scc--; count++;
18127c478bd9Sstevel@tonic-gate 						TTYADD('\n');
18137c478bd9Sstevel@tonic-gate 					} else {
18147c478bd9Sstevel@tonic-gate 
18157c478bd9Sstevel@tonic-gate 						if (decrypt_input)
18167c478bd9Sstevel@tonic-gate 							(*decrypt_input)(-1);
18177c478bd9Sstevel@tonic-gate 
18187c478bd9Sstevel@tonic-gate 						TTYADD('\r');
18197c478bd9Sstevel@tonic-gate 						if (crmod) {
18207c478bd9Sstevel@tonic-gate 							TTYADD('\n');
18217c478bd9Sstevel@tonic-gate 						}
18227c478bd9Sstevel@tonic-gate 					}
18237c478bd9Sstevel@tonic-gate 				} else {
18247c478bd9Sstevel@tonic-gate 					telrcv_state = TS_CR;
18257c478bd9Sstevel@tonic-gate 					TTYADD('\r');
18267c478bd9Sstevel@tonic-gate 					if (crmod) {
18277c478bd9Sstevel@tonic-gate 						TTYADD('\n');
18287c478bd9Sstevel@tonic-gate 					}
18297c478bd9Sstevel@tonic-gate 				}
18307c478bd9Sstevel@tonic-gate 			} else {
18317c478bd9Sstevel@tonic-gate 				TTYADD(c);
18327c478bd9Sstevel@tonic-gate 			}
18337c478bd9Sstevel@tonic-gate 			continue;
18347c478bd9Sstevel@tonic-gate 
18357c478bd9Sstevel@tonic-gate 		case TS_IAC:
18367c478bd9Sstevel@tonic-gate process_iac:
18377c478bd9Sstevel@tonic-gate 			switch (c) {
18387c478bd9Sstevel@tonic-gate 
18397c478bd9Sstevel@tonic-gate 			case WILL:
18407c478bd9Sstevel@tonic-gate 				telrcv_state = TS_WILL;
18417c478bd9Sstevel@tonic-gate 				continue;
18427c478bd9Sstevel@tonic-gate 
18437c478bd9Sstevel@tonic-gate 			case WONT:
18447c478bd9Sstevel@tonic-gate 				telrcv_state = TS_WONT;
18457c478bd9Sstevel@tonic-gate 				continue;
18467c478bd9Sstevel@tonic-gate 
18477c478bd9Sstevel@tonic-gate 			case DO:
18487c478bd9Sstevel@tonic-gate 				telrcv_state = TS_DO;
18497c478bd9Sstevel@tonic-gate 				continue;
18507c478bd9Sstevel@tonic-gate 
18517c478bd9Sstevel@tonic-gate 			case DONT:
18527c478bd9Sstevel@tonic-gate 				telrcv_state = TS_DONT;
18537c478bd9Sstevel@tonic-gate 				continue;
18547c478bd9Sstevel@tonic-gate 
18557c478bd9Sstevel@tonic-gate 			case DM:
18567c478bd9Sstevel@tonic-gate 				/*
18577c478bd9Sstevel@tonic-gate 				 * We may have missed an urgent notification,
18587c478bd9Sstevel@tonic-gate 				 * so make sure we flush whatever is in the
18597c478bd9Sstevel@tonic-gate 				 * buffer currently.
18607c478bd9Sstevel@tonic-gate 				 */
18617c478bd9Sstevel@tonic-gate 				printoption("RCVD", IAC, DM);
18627c478bd9Sstevel@tonic-gate 				SYNCHing = 1;
18637c478bd9Sstevel@tonic-gate 				if (ttyflush(1) == -2) {
18647c478bd9Sstevel@tonic-gate 					/* This will not return. */
18657c478bd9Sstevel@tonic-gate 					fatal_tty_error("write");
18667c478bd9Sstevel@tonic-gate 				}
18677c478bd9Sstevel@tonic-gate 				SYNCHing = stilloob();
18687c478bd9Sstevel@tonic-gate 				settimer(gotDM);
18697c478bd9Sstevel@tonic-gate 				break;
18707c478bd9Sstevel@tonic-gate 
18717c478bd9Sstevel@tonic-gate 			case SB:
18727c478bd9Sstevel@tonic-gate 				SB_CLEAR();
18737c478bd9Sstevel@tonic-gate 				telrcv_state = TS_SB;
18747c478bd9Sstevel@tonic-gate 				continue;
18757c478bd9Sstevel@tonic-gate 
18767c478bd9Sstevel@tonic-gate 			case IAC:
18777c478bd9Sstevel@tonic-gate 				TTYADD(IAC);
18787c478bd9Sstevel@tonic-gate 				break;
18797c478bd9Sstevel@tonic-gate 
18807c478bd9Sstevel@tonic-gate 			case NOP:
18817c478bd9Sstevel@tonic-gate 			case GA:
18827c478bd9Sstevel@tonic-gate 			default:
18837c478bd9Sstevel@tonic-gate 				printoption("RCVD", IAC, c);
18847c478bd9Sstevel@tonic-gate 				break;
18857c478bd9Sstevel@tonic-gate 			}
18867c478bd9Sstevel@tonic-gate 			telrcv_state = TS_DATA;
18877c478bd9Sstevel@tonic-gate 			continue;
18887c478bd9Sstevel@tonic-gate 
18897c478bd9Sstevel@tonic-gate 		case TS_WILL:
18907c478bd9Sstevel@tonic-gate 			printoption("RCVD", WILL, c);
18917c478bd9Sstevel@tonic-gate 			willoption(c);
18927c478bd9Sstevel@tonic-gate 			telrcv_state = TS_DATA;
18937c478bd9Sstevel@tonic-gate 			continue;
18947c478bd9Sstevel@tonic-gate 
18957c478bd9Sstevel@tonic-gate 		case TS_WONT:
18967c478bd9Sstevel@tonic-gate 			printoption("RCVD", WONT, c);
18977c478bd9Sstevel@tonic-gate 			wontoption(c);
18987c478bd9Sstevel@tonic-gate 			telrcv_state = TS_DATA;
18997c478bd9Sstevel@tonic-gate 			continue;
19007c478bd9Sstevel@tonic-gate 
19017c478bd9Sstevel@tonic-gate 		case TS_DO:
19027c478bd9Sstevel@tonic-gate 			printoption("RCVD", DO, c);
19037c478bd9Sstevel@tonic-gate 			dooption(c);
19047c478bd9Sstevel@tonic-gate 			if (c == TELOPT_NAWS) {
19057c478bd9Sstevel@tonic-gate 				sendnaws();
19067c478bd9Sstevel@tonic-gate 			} else if (c == TELOPT_LFLOW) {
19077c478bd9Sstevel@tonic-gate 				localflow = 1;
19087c478bd9Sstevel@tonic-gate 				setcommandmode();
19097c478bd9Sstevel@tonic-gate 				setconnmode(0);
19107c478bd9Sstevel@tonic-gate 			}
19117c478bd9Sstevel@tonic-gate 			telrcv_state = TS_DATA;
19127c478bd9Sstevel@tonic-gate 			continue;
19137c478bd9Sstevel@tonic-gate 
19147c478bd9Sstevel@tonic-gate 		case TS_DONT:
19157c478bd9Sstevel@tonic-gate 			printoption("RCVD", DONT, c);
19167c478bd9Sstevel@tonic-gate 			dontoption(c);
19177c478bd9Sstevel@tonic-gate 			flushline = 1;
19187c478bd9Sstevel@tonic-gate 			setconnmode(0);	/* set new tty mode (maybe) */
19197c478bd9Sstevel@tonic-gate 			telrcv_state = TS_DATA;
19207c478bd9Sstevel@tonic-gate 			continue;
19217c478bd9Sstevel@tonic-gate 
19227c478bd9Sstevel@tonic-gate 		case TS_SB:
19237c478bd9Sstevel@tonic-gate 			if (c == IAC) {
19247c478bd9Sstevel@tonic-gate 				telrcv_state = TS_SE;
19257c478bd9Sstevel@tonic-gate 			} else {
19267c478bd9Sstevel@tonic-gate 				SB_ACCUM(c);
19277c478bd9Sstevel@tonic-gate 			}
19287c478bd9Sstevel@tonic-gate 			continue;
19297c478bd9Sstevel@tonic-gate 
19307c478bd9Sstevel@tonic-gate 		case TS_SE:
19317c478bd9Sstevel@tonic-gate 			if (c != SE) {
19327c478bd9Sstevel@tonic-gate 				if (c != IAC) {
19337c478bd9Sstevel@tonic-gate 			/*
19347c478bd9Sstevel@tonic-gate 			 * This is an error.  We only expect to get
19357c478bd9Sstevel@tonic-gate 			 * "IAC IAC" or "IAC SE".  Several things may
19367c478bd9Sstevel@tonic-gate 			 * have happend.  An IAC was not doubled, the
19377c478bd9Sstevel@tonic-gate 			 * IAC SE was left off, or another option got
19387c478bd9Sstevel@tonic-gate 			 * inserted into the suboption are all possibilities.
19397c478bd9Sstevel@tonic-gate 			 * If we assume that the IAC was not doubled,
19407c478bd9Sstevel@tonic-gate 			 * and really the IAC SE was left off, we could
19417c478bd9Sstevel@tonic-gate 			 * get into an infinate loop here.  So, instead,
19427c478bd9Sstevel@tonic-gate 			 * we terminate the suboption, and process the
19437c478bd9Sstevel@tonic-gate 			 * partial suboption if we can.
19447c478bd9Sstevel@tonic-gate 			 */
19457c478bd9Sstevel@tonic-gate 					SB_ACCUM(IAC);
19467c478bd9Sstevel@tonic-gate 					SB_ACCUM(c);
19477c478bd9Sstevel@tonic-gate 					subpointer -= 2;
19487c478bd9Sstevel@tonic-gate 					SB_TERM();
19497c478bd9Sstevel@tonic-gate 
19507c478bd9Sstevel@tonic-gate 					printoption("In SUBOPTION processing, "
19517c478bd9Sstevel@tonic-gate 					    "RCVD", IAC, c);
19527c478bd9Sstevel@tonic-gate 					suboption();	/* handle sub-option */
19537c478bd9Sstevel@tonic-gate 					telrcv_state = TS_IAC;
19547c478bd9Sstevel@tonic-gate 					goto process_iac;
19557c478bd9Sstevel@tonic-gate 				}
19567c478bd9Sstevel@tonic-gate 				SB_ACCUM(c);
19577c478bd9Sstevel@tonic-gate 				telrcv_state = TS_SB;
19587c478bd9Sstevel@tonic-gate 			} else {
19597c478bd9Sstevel@tonic-gate 				SB_ACCUM(IAC);
19607c478bd9Sstevel@tonic-gate 				SB_ACCUM(SE);
19617c478bd9Sstevel@tonic-gate 				subpointer -= 2;
19627c478bd9Sstevel@tonic-gate 				SB_TERM();
19637c478bd9Sstevel@tonic-gate 				suboption();	/* handle sub-option */
19647c478bd9Sstevel@tonic-gate 				telrcv_state = TS_DATA;
19657c478bd9Sstevel@tonic-gate 			}
19667c478bd9Sstevel@tonic-gate 		}
19677c478bd9Sstevel@tonic-gate 	}
19687c478bd9Sstevel@tonic-gate 	if (count)
19697c478bd9Sstevel@tonic-gate 		ring_consumed(&netiring, count);
19707c478bd9Sstevel@tonic-gate 	return (returnValue||count);
19717c478bd9Sstevel@tonic-gate }
19727c478bd9Sstevel@tonic-gate 
19737c478bd9Sstevel@tonic-gate static int bol = 1, local = 0;
19747c478bd9Sstevel@tonic-gate 
19757c478bd9Sstevel@tonic-gate int
rlogin_susp()19767c478bd9Sstevel@tonic-gate rlogin_susp()
19777c478bd9Sstevel@tonic-gate {
19787c478bd9Sstevel@tonic-gate 	if (local) {
19797c478bd9Sstevel@tonic-gate 		local = 0;
19807c478bd9Sstevel@tonic-gate 		bol = 1;
19817c478bd9Sstevel@tonic-gate 		command(0, "z\n", 2);
19827c478bd9Sstevel@tonic-gate 		return (1);
19837c478bd9Sstevel@tonic-gate 	}
19847c478bd9Sstevel@tonic-gate 	return (0);
19857c478bd9Sstevel@tonic-gate }
19867c478bd9Sstevel@tonic-gate 
19877c478bd9Sstevel@tonic-gate static int
telsnd()19887c478bd9Sstevel@tonic-gate telsnd()
19897c478bd9Sstevel@tonic-gate {
19907c478bd9Sstevel@tonic-gate 	int tcc;
19917c478bd9Sstevel@tonic-gate 	int count;
19927c478bd9Sstevel@tonic-gate 	int returnValue = 0;
19937c478bd9Sstevel@tonic-gate 	unsigned char *tbp;
19947c478bd9Sstevel@tonic-gate 
19957c478bd9Sstevel@tonic-gate 	tcc = 0;
19967c478bd9Sstevel@tonic-gate 	count = 0;
19977c478bd9Sstevel@tonic-gate 	while (NETROOM() > 2) {
19987c478bd9Sstevel@tonic-gate 		register int sc;
19997c478bd9Sstevel@tonic-gate 		register int c;
20007c478bd9Sstevel@tonic-gate 
20017c478bd9Sstevel@tonic-gate 		if (tcc == 0) {
20027c478bd9Sstevel@tonic-gate 			if (count) {
20037c478bd9Sstevel@tonic-gate 				ring_consumed(&ttyiring, count);
20047c478bd9Sstevel@tonic-gate 				returnValue = 1;
20057c478bd9Sstevel@tonic-gate 				count = 0;
20067c478bd9Sstevel@tonic-gate 			}
20077c478bd9Sstevel@tonic-gate 			tbp = ttyiring.consume;
20087c478bd9Sstevel@tonic-gate 			tcc = ring_full_consecutive(&ttyiring);
20097c478bd9Sstevel@tonic-gate 			if (tcc == 0) {
20107c478bd9Sstevel@tonic-gate 				break;
20117c478bd9Sstevel@tonic-gate 			}
20127c478bd9Sstevel@tonic-gate 		}
20137c478bd9Sstevel@tonic-gate 		c = *tbp++ & 0xff, sc = strip(c), tcc--; count++;
20147c478bd9Sstevel@tonic-gate 		if (rlogin != _POSIX_VDISABLE) {
20157c478bd9Sstevel@tonic-gate 			if (bol) {
20167c478bd9Sstevel@tonic-gate 				bol = 0;
20177c478bd9Sstevel@tonic-gate 				if (sc == rlogin) {
20187c478bd9Sstevel@tonic-gate 					local = 1;
20197c478bd9Sstevel@tonic-gate 					continue;
20207c478bd9Sstevel@tonic-gate 				}
20217c478bd9Sstevel@tonic-gate 			} else if (local) {
20227c478bd9Sstevel@tonic-gate 				local = 0;
20237c478bd9Sstevel@tonic-gate 				if (sc == '.' || c == termEofChar) {
20247c478bd9Sstevel@tonic-gate 					bol = 1;
20257c478bd9Sstevel@tonic-gate 					command(0, "close\n", 6);
20267c478bd9Sstevel@tonic-gate 					continue;
20277c478bd9Sstevel@tonic-gate 				}
20287c478bd9Sstevel@tonic-gate 				if (sc == termSuspChar) {
20297c478bd9Sstevel@tonic-gate 					bol = 1;
20307c478bd9Sstevel@tonic-gate 					command(0, "z\n", 2);
20317c478bd9Sstevel@tonic-gate 					continue;
20327c478bd9Sstevel@tonic-gate 				}
20337c478bd9Sstevel@tonic-gate 				if (sc == escape) {
20347c478bd9Sstevel@tonic-gate 					command(0, (char *)tbp, tcc);
20357c478bd9Sstevel@tonic-gate 					bol = 1;
20367c478bd9Sstevel@tonic-gate 					count += tcc;
20377c478bd9Sstevel@tonic-gate 					tcc = 0;
20387c478bd9Sstevel@tonic-gate 					flushline = 1;
20397c478bd9Sstevel@tonic-gate 					break;
20407c478bd9Sstevel@tonic-gate 				}
20417c478bd9Sstevel@tonic-gate 				if (sc != rlogin) {
20427c478bd9Sstevel@tonic-gate 					++tcc;
20437c478bd9Sstevel@tonic-gate 					--tbp;
20447c478bd9Sstevel@tonic-gate 					--count;
20457c478bd9Sstevel@tonic-gate 					c = sc = rlogin;
20467c478bd9Sstevel@tonic-gate 				}
20477c478bd9Sstevel@tonic-gate 			}
20487c478bd9Sstevel@tonic-gate 			if ((sc == '\n') || (sc == '\r'))
20497c478bd9Sstevel@tonic-gate 				bol = 1;
20507c478bd9Sstevel@tonic-gate 		} else if (sc == escape && escape_valid) {
20517c478bd9Sstevel@tonic-gate 			/*
20527c478bd9Sstevel@tonic-gate 			 * Double escape is a pass through of a single
20537c478bd9Sstevel@tonic-gate 			 * escape character.
20547c478bd9Sstevel@tonic-gate 			 */
20557c478bd9Sstevel@tonic-gate 			if (tcc && strip(*tbp) == escape) {
20567c478bd9Sstevel@tonic-gate 				tbp++;
20577c478bd9Sstevel@tonic-gate 				tcc--;
20587c478bd9Sstevel@tonic-gate 				count++;
20597c478bd9Sstevel@tonic-gate 				bol = 0;
20607c478bd9Sstevel@tonic-gate 			} else {
20617c478bd9Sstevel@tonic-gate 				command(0, (char *)tbp, tcc);
20627c478bd9Sstevel@tonic-gate 				bol = 1;
20637c478bd9Sstevel@tonic-gate 				count += tcc;
20647c478bd9Sstevel@tonic-gate 				tcc = 0;
20657c478bd9Sstevel@tonic-gate 				flushline = 1;
20667c478bd9Sstevel@tonic-gate 				break;
20677c478bd9Sstevel@tonic-gate 			}
20687c478bd9Sstevel@tonic-gate 		} else
20697c478bd9Sstevel@tonic-gate 			bol = 0;
20707c478bd9Sstevel@tonic-gate #ifdef	KLUDGELINEMODE
20717c478bd9Sstevel@tonic-gate 		if (kludgelinemode && (globalmode&MODE_EDIT) && (sc == echoc)) {
20727c478bd9Sstevel@tonic-gate 			if (tcc > 0 && strip(*tbp) == echoc) {
20737c478bd9Sstevel@tonic-gate 				tcc--; tbp++; count++;
20747c478bd9Sstevel@tonic-gate 			} else {
20757c478bd9Sstevel@tonic-gate 				dontlecho = !dontlecho;
20767c478bd9Sstevel@tonic-gate 				settimer(echotoggle);
20777c478bd9Sstevel@tonic-gate 				setconnmode(0);
20787c478bd9Sstevel@tonic-gate 				flushline = 1;
20797c478bd9Sstevel@tonic-gate 				break;
20807c478bd9Sstevel@tonic-gate 			}
20817c478bd9Sstevel@tonic-gate 		}
20827c478bd9Sstevel@tonic-gate #endif
20837c478bd9Sstevel@tonic-gate 		if (MODE_LOCAL_CHARS(globalmode)) {
20847c478bd9Sstevel@tonic-gate 			if (TerminalSpecialChars(sc) == 0) {
20857c478bd9Sstevel@tonic-gate 				bol = 1;
20867c478bd9Sstevel@tonic-gate 				break;
20877c478bd9Sstevel@tonic-gate 			}
20887c478bd9Sstevel@tonic-gate 		}
20897c478bd9Sstevel@tonic-gate 		if (my_want_state_is_wont(TELOPT_BINARY)) {
20907c478bd9Sstevel@tonic-gate 			switch (c) {
20917c478bd9Sstevel@tonic-gate 			case '\n':
20927c478bd9Sstevel@tonic-gate 				/*
20937c478bd9Sstevel@tonic-gate 				 * If we are in CRMOD mode (\r ==> \n)
20947c478bd9Sstevel@tonic-gate 				 * on our local machine, then probably
20957c478bd9Sstevel@tonic-gate 				 * a newline (unix) is CRLF (TELNET).
20967c478bd9Sstevel@tonic-gate 				 */
20977c478bd9Sstevel@tonic-gate 				if (MODE_LOCAL_CHARS(globalmode)) {
20987c478bd9Sstevel@tonic-gate 					NETADD('\r');
20997c478bd9Sstevel@tonic-gate 				}
21007c478bd9Sstevel@tonic-gate 				NETADD('\n');
21017c478bd9Sstevel@tonic-gate 				bol = flushline = 1;
21027c478bd9Sstevel@tonic-gate 				break;
21037c478bd9Sstevel@tonic-gate 			case '\r':
21047c478bd9Sstevel@tonic-gate 				if (!crlf) {
21057c478bd9Sstevel@tonic-gate 					NET2ADD('\r', '\0');
21067c478bd9Sstevel@tonic-gate 				} else {
21077c478bd9Sstevel@tonic-gate 					NET2ADD('\r', '\n');
21087c478bd9Sstevel@tonic-gate 				}
21097c478bd9Sstevel@tonic-gate 				bol = flushline = 1;
21107c478bd9Sstevel@tonic-gate 				break;
21117c478bd9Sstevel@tonic-gate 			case IAC:
21127c478bd9Sstevel@tonic-gate 				NET2ADD(IAC, IAC);
21137c478bd9Sstevel@tonic-gate 				break;
21147c478bd9Sstevel@tonic-gate 			default:
21157c478bd9Sstevel@tonic-gate 				NETADD(c);
21167c478bd9Sstevel@tonic-gate 				break;
21177c478bd9Sstevel@tonic-gate 			}
21187c478bd9Sstevel@tonic-gate 		} else if (c == IAC) {
21197c478bd9Sstevel@tonic-gate 			NET2ADD(IAC, IAC);
21207c478bd9Sstevel@tonic-gate 		} else {
21217c478bd9Sstevel@tonic-gate 			NETADD(c);
21227c478bd9Sstevel@tonic-gate 		}
21237c478bd9Sstevel@tonic-gate 	}
21247c478bd9Sstevel@tonic-gate 	if (count)
21257c478bd9Sstevel@tonic-gate 		ring_consumed(&ttyiring, count);
21267c478bd9Sstevel@tonic-gate 	return (returnValue||count);	/* Non-zero if we did anything */
21277c478bd9Sstevel@tonic-gate }
21287c478bd9Sstevel@tonic-gate 
21297c478bd9Sstevel@tonic-gate /*
21307c478bd9Sstevel@tonic-gate  * Scheduler()
21317c478bd9Sstevel@tonic-gate  *
21327c478bd9Sstevel@tonic-gate  * Try to do something.
21337c478bd9Sstevel@tonic-gate  *
21347c478bd9Sstevel@tonic-gate  * If we do something useful, return 1; else return 0.
21357c478bd9Sstevel@tonic-gate  *
21367c478bd9Sstevel@tonic-gate  */
21377c478bd9Sstevel@tonic-gate 
21387c478bd9Sstevel@tonic-gate 
21397c478bd9Sstevel@tonic-gate int
Scheduler(block)21407c478bd9Sstevel@tonic-gate Scheduler(block)
21417c478bd9Sstevel@tonic-gate 	int	block;		/* should we block in the select ? */
21427c478bd9Sstevel@tonic-gate {
21437c478bd9Sstevel@tonic-gate 	/*
21447c478bd9Sstevel@tonic-gate 	 * One wants to be a bit careful about setting returnValue
21457c478bd9Sstevel@tonic-gate 	 * to one, since a one implies we did some useful work,
21467c478bd9Sstevel@tonic-gate 	 * and therefore probably won't be called to block next
21477c478bd9Sstevel@tonic-gate 	 * time (TN3270 mode only).
21487c478bd9Sstevel@tonic-gate 	 */
21497c478bd9Sstevel@tonic-gate 	int returnValue;
21507c478bd9Sstevel@tonic-gate 	int netin, netout, netex, ttyin, ttyout;
21517c478bd9Sstevel@tonic-gate 
21527c478bd9Sstevel@tonic-gate 	/* Decide which rings should be processed */
21537c478bd9Sstevel@tonic-gate 
21547c478bd9Sstevel@tonic-gate 	netout = ring_full_count(&netoring) &&
21557c478bd9Sstevel@tonic-gate 	    (flushline ||
21567c478bd9Sstevel@tonic-gate 	    (my_want_state_is_wont(TELOPT_LINEMODE)
21577c478bd9Sstevel@tonic-gate #ifdef	KLUDGELINEMODE
21587c478bd9Sstevel@tonic-gate 	    /* X */ && (!kludgelinemode || my_want_state_is_do(TELOPT_SGA))
21597c478bd9Sstevel@tonic-gate #endif
21607c478bd9Sstevel@tonic-gate 	    /* XXX */) ||
21617c478bd9Sstevel@tonic-gate 	    my_want_state_is_will(TELOPT_BINARY));
21627c478bd9Sstevel@tonic-gate 	ttyout = ring_full_count(&ttyoring);
21637c478bd9Sstevel@tonic-gate 
21647c478bd9Sstevel@tonic-gate 	ttyin = (ring_empty_count(&ttyiring) && !eof_pending);
21657c478bd9Sstevel@tonic-gate 
21667c478bd9Sstevel@tonic-gate 	netin = !ISend && ring_empty_count(&netiring);
21677c478bd9Sstevel@tonic-gate 
21687c478bd9Sstevel@tonic-gate 	netex = !SYNCHing;
21697c478bd9Sstevel@tonic-gate 
21707c478bd9Sstevel@tonic-gate 	if (scheduler_lockout_tty) {
21717c478bd9Sstevel@tonic-gate 		ttyin = ttyout = 0;
21727c478bd9Sstevel@tonic-gate 	}
21737c478bd9Sstevel@tonic-gate 
21747c478bd9Sstevel@tonic-gate 	/* Call to system code to process rings */
21757c478bd9Sstevel@tonic-gate 
21767c478bd9Sstevel@tonic-gate 	returnValue = process_rings(netin, netout, netex, ttyin, ttyout,
21777c478bd9Sstevel@tonic-gate 	    !block);
21787c478bd9Sstevel@tonic-gate 
21797c478bd9Sstevel@tonic-gate 	/* Now, look at the input rings, looking for work to do. */
21807c478bd9Sstevel@tonic-gate 
21817c478bd9Sstevel@tonic-gate 	if (ring_full_count(&ttyiring)) {
21827c478bd9Sstevel@tonic-gate 		returnValue |= telsnd();
21837c478bd9Sstevel@tonic-gate 	} else {
21847c478bd9Sstevel@tonic-gate 		/*
21857c478bd9Sstevel@tonic-gate 		 * If ttyiring is empty, check to see if there is a real EOF
21867c478bd9Sstevel@tonic-gate 		 * pending.  If so, we can maybe do the EOF write now.
21877c478bd9Sstevel@tonic-gate 		 */
21887c478bd9Sstevel@tonic-gate 		if (eof_pending) {
21897c478bd9Sstevel@tonic-gate 			eof_pending = 0;
21907c478bd9Sstevel@tonic-gate 			sendeof();
21917c478bd9Sstevel@tonic-gate 		}
21927c478bd9Sstevel@tonic-gate 	}
21937c478bd9Sstevel@tonic-gate 
21947c478bd9Sstevel@tonic-gate 	if (ring_full_count(&netiring)) {
21957c478bd9Sstevel@tonic-gate 		returnValue |= telrcv();
21967c478bd9Sstevel@tonic-gate 	}
21977c478bd9Sstevel@tonic-gate 	return (returnValue);
21987c478bd9Sstevel@tonic-gate }
21997c478bd9Sstevel@tonic-gate 
22007c478bd9Sstevel@tonic-gate /*
22017c478bd9Sstevel@tonic-gate  * Select from tty and network...
22027c478bd9Sstevel@tonic-gate  */
22037c478bd9Sstevel@tonic-gate void
telnet(user)22047c478bd9Sstevel@tonic-gate telnet(user)
22057c478bd9Sstevel@tonic-gate 	char *user;
22067c478bd9Sstevel@tonic-gate {
22077c478bd9Sstevel@tonic-gate 	sys_telnet_init();
22087c478bd9Sstevel@tonic-gate 
22097c478bd9Sstevel@tonic-gate 	{
22107c478bd9Sstevel@tonic-gate 		static char local_host[MAXHOSTNAMELEN] = { 0 };
22117c478bd9Sstevel@tonic-gate 
22127c478bd9Sstevel@tonic-gate 		if (!local_host[0]) {
22137c478bd9Sstevel@tonic-gate 			(void) gethostname(local_host, sizeof (local_host));
22147c478bd9Sstevel@tonic-gate 			local_host[sizeof (local_host)-1] = 0;
22157c478bd9Sstevel@tonic-gate 		}
22167c478bd9Sstevel@tonic-gate 		auth_encrypt_init(local_host, hostname, "TELNET");
22177c478bd9Sstevel@tonic-gate 		auth_encrypt_user(user);
22187c478bd9Sstevel@tonic-gate 	}
22197c478bd9Sstevel@tonic-gate 
22207c478bd9Sstevel@tonic-gate 	if (autologin)
22217c478bd9Sstevel@tonic-gate 		send_will(TELOPT_AUTHENTICATION, 1);
22227c478bd9Sstevel@tonic-gate 
22237c478bd9Sstevel@tonic-gate 	if (telnetport || wantencryption) {
22247c478bd9Sstevel@tonic-gate 		send_do(TELOPT_ENCRYPT, 1);
22257c478bd9Sstevel@tonic-gate 		send_will(TELOPT_ENCRYPT, 1);
22267c478bd9Sstevel@tonic-gate 	}
22277c478bd9Sstevel@tonic-gate 
22287c478bd9Sstevel@tonic-gate 	if (telnetport) {
22297c478bd9Sstevel@tonic-gate 		if (!reqd_linemode)
22307c478bd9Sstevel@tonic-gate 		    send_do(TELOPT_SGA, 1);
22317c478bd9Sstevel@tonic-gate 		send_will(TELOPT_TTYPE, 1);
22327c478bd9Sstevel@tonic-gate 		send_will(TELOPT_NAWS, 1);
22337c478bd9Sstevel@tonic-gate 		send_will(TELOPT_TSPEED, 1);
22347c478bd9Sstevel@tonic-gate 		send_will(TELOPT_LFLOW, 1);
22357c478bd9Sstevel@tonic-gate 		if (!reqd_linemode)
22367c478bd9Sstevel@tonic-gate 		    send_will(TELOPT_LINEMODE, 1);
22377c478bd9Sstevel@tonic-gate 		send_will(TELOPT_NEW_ENVIRON, 1);
22387c478bd9Sstevel@tonic-gate 		send_do(TELOPT_STATUS, 1);
22397c478bd9Sstevel@tonic-gate 		if (env_getvalue((unsigned char *)"DISPLAY"))
22407c478bd9Sstevel@tonic-gate 			send_will(TELOPT_XDISPLOC, 1);
22417c478bd9Sstevel@tonic-gate 		if (eight)
22427c478bd9Sstevel@tonic-gate 			tel_enter_binary(eight);
22437c478bd9Sstevel@tonic-gate 	}
22447c478bd9Sstevel@tonic-gate 
22457c478bd9Sstevel@tonic-gate 	/*
22467c478bd9Sstevel@tonic-gate 	 * Note: we assume a tie to the authentication option here.  This
22477c478bd9Sstevel@tonic-gate 	 * is necessary so that authentication fails, we don't spin
22487c478bd9Sstevel@tonic-gate 	 * forever.
22497c478bd9Sstevel@tonic-gate 	 */
22507c478bd9Sstevel@tonic-gate 	if (wantencryption) {
22517c478bd9Sstevel@tonic-gate 		boolean_t printed_encrypt = B_FALSE;
22527c478bd9Sstevel@tonic-gate 		extern boolean_t auth_has_failed;
22537c478bd9Sstevel@tonic-gate 		time_t timeout = time(0) + 60;
22547c478bd9Sstevel@tonic-gate 
22557c478bd9Sstevel@tonic-gate 		send_do(TELOPT_ENCRYPT, 1);
22567c478bd9Sstevel@tonic-gate 		send_will(TELOPT_ENCRYPT, 1);
22577c478bd9Sstevel@tonic-gate 		for (;;) {
22587c478bd9Sstevel@tonic-gate 		    if (my_want_state_is_wont(TELOPT_AUTHENTICATION)) {
22597c478bd9Sstevel@tonic-gate 			(void) printf(gettext(
22607c478bd9Sstevel@tonic-gate 				"\nServer refused to negotiate "
22617c478bd9Sstevel@tonic-gate 				"authentication, which is required\n"
22627c478bd9Sstevel@tonic-gate 				"for encryption.  Good-bye.\n\r"));
22637c478bd9Sstevel@tonic-gate 			Exit(EXIT_FAILURE);
22647c478bd9Sstevel@tonic-gate 		    }
22657c478bd9Sstevel@tonic-gate 		    if (auth_has_failed) {
22667c478bd9Sstevel@tonic-gate 			(void) printf(gettext(
22677c478bd9Sstevel@tonic-gate 			    "\nAuthentication negotation has failed, "
22687c478bd9Sstevel@tonic-gate 			    "which is required for\n"
22697c478bd9Sstevel@tonic-gate 			    "encryption.  Good-bye.\n\r"));
22707c478bd9Sstevel@tonic-gate 			Exit(EXIT_FAILURE);
22717c478bd9Sstevel@tonic-gate 		    }
22727c478bd9Sstevel@tonic-gate 		    if (my_want_state_is_dont(TELOPT_ENCRYPT) ||
22737c478bd9Sstevel@tonic-gate 			my_want_state_is_wont(TELOPT_ENCRYPT)) {
22747c478bd9Sstevel@tonic-gate 			    (void) printf(gettext(
22757c478bd9Sstevel@tonic-gate 				"\nServer refused to negotiate encryption.  "
22767c478bd9Sstevel@tonic-gate 				"Good-bye.\n\r"));
22777c478bd9Sstevel@tonic-gate 			    Exit(EXIT_FAILURE);
22787c478bd9Sstevel@tonic-gate 		    }
22797c478bd9Sstevel@tonic-gate 		    if (encrypt_is_encrypting())
22807c478bd9Sstevel@tonic-gate 			break;
22817c478bd9Sstevel@tonic-gate 
22827c478bd9Sstevel@tonic-gate 		    if (time(0) > timeout) {
22837c478bd9Sstevel@tonic-gate 			(void) printf(gettext(
22847c478bd9Sstevel@tonic-gate 				"\nEncryption could not be enabled.  "
22857c478bd9Sstevel@tonic-gate 				"Good-bye.\n\r"));
22867c478bd9Sstevel@tonic-gate 			Exit(EXIT_FAILURE);
22877c478bd9Sstevel@tonic-gate 		    }
22887c478bd9Sstevel@tonic-gate 		    if (printed_encrypt == B_FALSE) {
22897c478bd9Sstevel@tonic-gate 			printed_encrypt = B_TRUE;
22907c478bd9Sstevel@tonic-gate 			(void) printf(gettext(
22917c478bd9Sstevel@tonic-gate 			    "Waiting for encryption to be negotiated...\n"));
22927c478bd9Sstevel@tonic-gate 			/*
22937c478bd9Sstevel@tonic-gate 			 * Turn on MODE_TRAPSIG and then turn off localchars
22947c478bd9Sstevel@tonic-gate 			 * so that ^C will cause telnet to exit.
22957c478bd9Sstevel@tonic-gate 			 */
22967c478bd9Sstevel@tonic-gate 			TerminalNewMode(getconnmode()|MODE_TRAPSIG);
22977c478bd9Sstevel@tonic-gate 			intr_waiting = 1;
22987c478bd9Sstevel@tonic-gate 		    }
22997c478bd9Sstevel@tonic-gate 		    if (intr_happened) {
23007c478bd9Sstevel@tonic-gate 			(void) printf(gettext(
23017c478bd9Sstevel@tonic-gate 			    "\nUser requested an interrupt.  Good-bye.\n\r"));
23027c478bd9Sstevel@tonic-gate 			Exit(EXIT_FAILURE);
23037c478bd9Sstevel@tonic-gate 		    }
23047c478bd9Sstevel@tonic-gate 		    telnet_spin();
23057c478bd9Sstevel@tonic-gate 		}
23067c478bd9Sstevel@tonic-gate 		if (printed_encrypt) {
23077c478bd9Sstevel@tonic-gate 			(void) printf(gettext("done.\n"));
23087c478bd9Sstevel@tonic-gate 			intr_waiting = 0;
23097c478bd9Sstevel@tonic-gate 			setconnmode(0);
23107c478bd9Sstevel@tonic-gate 		}
23117c478bd9Sstevel@tonic-gate 	}
23127c478bd9Sstevel@tonic-gate 
23137c478bd9Sstevel@tonic-gate 	for (;;) {
23147c478bd9Sstevel@tonic-gate 		int schedValue;
23157c478bd9Sstevel@tonic-gate 
23167c478bd9Sstevel@tonic-gate 		while ((schedValue = Scheduler(0)) != 0) {
23177c478bd9Sstevel@tonic-gate 			if (schedValue == -1) {
23187c478bd9Sstevel@tonic-gate 				setcommandmode();
23197c478bd9Sstevel@tonic-gate 				return;
23207c478bd9Sstevel@tonic-gate 			}
23217c478bd9Sstevel@tonic-gate 		}
23227c478bd9Sstevel@tonic-gate 
23237c478bd9Sstevel@tonic-gate 		if (Scheduler(1) == -1) {
23247c478bd9Sstevel@tonic-gate 			setcommandmode();
23257c478bd9Sstevel@tonic-gate 			return;
23267c478bd9Sstevel@tonic-gate 		}
23277c478bd9Sstevel@tonic-gate 	}
23287c478bd9Sstevel@tonic-gate }
23297c478bd9Sstevel@tonic-gate 
23307c478bd9Sstevel@tonic-gate #if	0	/* XXX - this not being in is a bug */
23317c478bd9Sstevel@tonic-gate /*
23327c478bd9Sstevel@tonic-gate  * nextitem()
23337c478bd9Sstevel@tonic-gate  *
23347c478bd9Sstevel@tonic-gate  *	Return the address of the next "item" in the TELNET data
23357c478bd9Sstevel@tonic-gate  * stream.  This will be the address of the next character if
23367c478bd9Sstevel@tonic-gate  * the current address is a user data character, or it will
23377c478bd9Sstevel@tonic-gate  * be the address of the character following the TELNET command
23387c478bd9Sstevel@tonic-gate  * if the current address is a TELNET IAC ("I Am a Command")
23397c478bd9Sstevel@tonic-gate  * character.
23407c478bd9Sstevel@tonic-gate  */
23417c478bd9Sstevel@tonic-gate 
23427c478bd9Sstevel@tonic-gate static char *
23437c478bd9Sstevel@tonic-gate nextitem(current)
23447c478bd9Sstevel@tonic-gate 	char *current;
23457c478bd9Sstevel@tonic-gate {
23467c478bd9Sstevel@tonic-gate 	if ((*current&0xff) != IAC) {
23477c478bd9Sstevel@tonic-gate 		return (current+1);
23487c478bd9Sstevel@tonic-gate 	}
23497c478bd9Sstevel@tonic-gate 	switch (*(current+1)&0xff) {
23507c478bd9Sstevel@tonic-gate 	case DO:
23517c478bd9Sstevel@tonic-gate 	case DONT:
23527c478bd9Sstevel@tonic-gate 	case WILL:
23537c478bd9Sstevel@tonic-gate 	case WONT:
23547c478bd9Sstevel@tonic-gate 		return (current+3);
23557c478bd9Sstevel@tonic-gate 	case SB:		/* loop forever looking for the SE */
23567c478bd9Sstevel@tonic-gate 	{
23577c478bd9Sstevel@tonic-gate 		register char *look = current+2;
23587c478bd9Sstevel@tonic-gate 
23597c478bd9Sstevel@tonic-gate 		for (;;) {
23607c478bd9Sstevel@tonic-gate 			if ((*look++&0xff) == IAC) {
23617c478bd9Sstevel@tonic-gate 				if ((*look++&0xff) == SE) {
23627c478bd9Sstevel@tonic-gate 					return (look);
23637c478bd9Sstevel@tonic-gate 				}
23647c478bd9Sstevel@tonic-gate 			}
23657c478bd9Sstevel@tonic-gate 		}
23667c478bd9Sstevel@tonic-gate 	}
23677c478bd9Sstevel@tonic-gate 	default:
23687c478bd9Sstevel@tonic-gate 		return (current+2);
23697c478bd9Sstevel@tonic-gate 	}
23707c478bd9Sstevel@tonic-gate }
23717c478bd9Sstevel@tonic-gate #endif	/* 0 */
23727c478bd9Sstevel@tonic-gate 
23737c478bd9Sstevel@tonic-gate /*
23747c478bd9Sstevel@tonic-gate  * netclear()
23757c478bd9Sstevel@tonic-gate  *
23767c478bd9Sstevel@tonic-gate  *	We are about to do a TELNET SYNCH operation.  Clear
23777c478bd9Sstevel@tonic-gate  * the path to the network.
23787c478bd9Sstevel@tonic-gate  *
23797c478bd9Sstevel@tonic-gate  *	Things are a bit tricky since we may have sent the first
23807c478bd9Sstevel@tonic-gate  * byte or so of a previous TELNET command into the network.
23817c478bd9Sstevel@tonic-gate  * So, we have to scan the network buffer from the beginning
23827c478bd9Sstevel@tonic-gate  * until we are up to where we want to be.
23837c478bd9Sstevel@tonic-gate  *
23847c478bd9Sstevel@tonic-gate  *	A side effect of what we do, just to keep things
23857c478bd9Sstevel@tonic-gate  * simple, is to clear the urgent data pointer.  The principal
23867c478bd9Sstevel@tonic-gate  * caller should be setting the urgent data pointer AFTER calling
23877c478bd9Sstevel@tonic-gate  * us in any case.
23887c478bd9Sstevel@tonic-gate  */
23897c478bd9Sstevel@tonic-gate 
23907c478bd9Sstevel@tonic-gate static void
netclear()23917c478bd9Sstevel@tonic-gate netclear()
23927c478bd9Sstevel@tonic-gate {
23937c478bd9Sstevel@tonic-gate #if	0	/* XXX */
23947c478bd9Sstevel@tonic-gate 	register char *thisitem, *next;
23957c478bd9Sstevel@tonic-gate 	char *good;
23967c478bd9Sstevel@tonic-gate #define	wewant(p)	((nfrontp > p) && ((*p&0xff) == IAC) && \
23977c478bd9Sstevel@tonic-gate 				((*(p+1)&0xff) != EC) && ((*(p+1)&0xff) != EL))
23987c478bd9Sstevel@tonic-gate 
23997c478bd9Sstevel@tonic-gate 	thisitem = netobuf;
24007c478bd9Sstevel@tonic-gate 
24017c478bd9Sstevel@tonic-gate 	while ((next = nextitem(thisitem)) <= netobuf.send) {
24027c478bd9Sstevel@tonic-gate 		thisitem = next;
24037c478bd9Sstevel@tonic-gate 	}
24047c478bd9Sstevel@tonic-gate 
24057c478bd9Sstevel@tonic-gate 	/* Now, thisitem is first before/at boundary. */
24067c478bd9Sstevel@tonic-gate 
24077c478bd9Sstevel@tonic-gate 	good = netobuf;	/* where the good bytes go */
24087c478bd9Sstevel@tonic-gate 
24097c478bd9Sstevel@tonic-gate 	while (netoring.add > thisitem) {
24107c478bd9Sstevel@tonic-gate 		if (wewant(thisitem)) {
24117c478bd9Sstevel@tonic-gate 			int length;
24127c478bd9Sstevel@tonic-gate 
24137c478bd9Sstevel@tonic-gate 			next = thisitem;
24147c478bd9Sstevel@tonic-gate 			do {
24157c478bd9Sstevel@tonic-gate 				next = nextitem(next);
24167c478bd9Sstevel@tonic-gate 			} while (wewant(next) && (nfrontp > next));
24177c478bd9Sstevel@tonic-gate 			length = next-thisitem;
24187c478bd9Sstevel@tonic-gate 			memcpy(good, thisitem, length);
24197c478bd9Sstevel@tonic-gate 			good += length;
24207c478bd9Sstevel@tonic-gate 			thisitem = next;
24217c478bd9Sstevel@tonic-gate 		} else {
24227c478bd9Sstevel@tonic-gate 			thisitem = nextitem(thisitem);
24237c478bd9Sstevel@tonic-gate 		}
24247c478bd9Sstevel@tonic-gate 	}
24257c478bd9Sstevel@tonic-gate 
24267c478bd9Sstevel@tonic-gate #endif	/* 0 */
24277c478bd9Sstevel@tonic-gate }
24287c478bd9Sstevel@tonic-gate 
24297c478bd9Sstevel@tonic-gate /*
24307c478bd9Sstevel@tonic-gate  * These routines add various telnet commands to the data stream.
24317c478bd9Sstevel@tonic-gate  */
24327c478bd9Sstevel@tonic-gate 
24337c478bd9Sstevel@tonic-gate /*
24347c478bd9Sstevel@tonic-gate  * doflush -  Send do timing mark (for network connection flush) & then
24357c478bd9Sstevel@tonic-gate  * get rid of anything in the output buffer.  Return -1 if there was a
24367c478bd9Sstevel@tonic-gate  * non-EWOULDBLOCK error on the tty flush, and otherwise return 0.
24377c478bd9Sstevel@tonic-gate  */
24387c478bd9Sstevel@tonic-gate static int
doflush()24397c478bd9Sstevel@tonic-gate doflush()
24407c478bd9Sstevel@tonic-gate {
24417c478bd9Sstevel@tonic-gate 	NET2ADD(IAC, DO);
24427c478bd9Sstevel@tonic-gate 	NETADD(TELOPT_TM);
24437c478bd9Sstevel@tonic-gate 	flushline = 1;
24447c478bd9Sstevel@tonic-gate 	flushout = 1;
24457c478bd9Sstevel@tonic-gate 
24467c478bd9Sstevel@tonic-gate 	/* Drop pending tty output */
24477c478bd9Sstevel@tonic-gate 	if (ttyflush(1) == -2)
24487c478bd9Sstevel@tonic-gate 		return (-1);
24497c478bd9Sstevel@tonic-gate 
24507c478bd9Sstevel@tonic-gate 	/* do printoption AFTER flush, otherwise the output gets tossed... */
24517c478bd9Sstevel@tonic-gate 	printoption("SENT", DO, TELOPT_TM);
24527c478bd9Sstevel@tonic-gate 	return (0);
24537c478bd9Sstevel@tonic-gate }
24547c478bd9Sstevel@tonic-gate 
24557c478bd9Sstevel@tonic-gate int
xmitAO()24567c478bd9Sstevel@tonic-gate xmitAO()
24577c478bd9Sstevel@tonic-gate {
24587c478bd9Sstevel@tonic-gate 	NET2ADD(IAC, AO);
24597c478bd9Sstevel@tonic-gate 	printoption("SENT", IAC, AO);
24607c478bd9Sstevel@tonic-gate 	if (autoflush) {
24617c478bd9Sstevel@tonic-gate 		if (doflush() == -1)
24627c478bd9Sstevel@tonic-gate 			return (-1);
24637c478bd9Sstevel@tonic-gate 	}
24647c478bd9Sstevel@tonic-gate 	return (0);
24657c478bd9Sstevel@tonic-gate }
24667c478bd9Sstevel@tonic-gate 
24677c478bd9Sstevel@tonic-gate 
24687c478bd9Sstevel@tonic-gate void
xmitEL()24697c478bd9Sstevel@tonic-gate xmitEL()
24707c478bd9Sstevel@tonic-gate {
24717c478bd9Sstevel@tonic-gate 	NET2ADD(IAC, EL);
24727c478bd9Sstevel@tonic-gate 	printoption("SENT", IAC, EL);
24737c478bd9Sstevel@tonic-gate }
24747c478bd9Sstevel@tonic-gate 
24757c478bd9Sstevel@tonic-gate void
xmitEC()24767c478bd9Sstevel@tonic-gate xmitEC()
24777c478bd9Sstevel@tonic-gate {
24787c478bd9Sstevel@tonic-gate 	NET2ADD(IAC, EC);
24797c478bd9Sstevel@tonic-gate 	printoption("SENT", IAC, EC);
24807c478bd9Sstevel@tonic-gate }
24817c478bd9Sstevel@tonic-gate 
24827c478bd9Sstevel@tonic-gate 
24837c478bd9Sstevel@tonic-gate int
dosynch()24847c478bd9Sstevel@tonic-gate dosynch()
24857c478bd9Sstevel@tonic-gate {
24867c478bd9Sstevel@tonic-gate 	netclear();			/* clear the path to the network */
24877c478bd9Sstevel@tonic-gate 	NETADD(IAC);
24887c478bd9Sstevel@tonic-gate 	setneturg();
24897c478bd9Sstevel@tonic-gate 	NETADD(DM);
24907c478bd9Sstevel@tonic-gate 	printoption("SENT", IAC, DM);
24917c478bd9Sstevel@tonic-gate 	return (1);
24927c478bd9Sstevel@tonic-gate }
24937c478bd9Sstevel@tonic-gate 
24947c478bd9Sstevel@tonic-gate int want_status_response = 0;
24957c478bd9Sstevel@tonic-gate 
24967c478bd9Sstevel@tonic-gate int
get_status()24977c478bd9Sstevel@tonic-gate get_status()
24987c478bd9Sstevel@tonic-gate {
24997c478bd9Sstevel@tonic-gate 	unsigned char tmp[16];
25007c478bd9Sstevel@tonic-gate 	register unsigned char *cp;
25017c478bd9Sstevel@tonic-gate 
25027c478bd9Sstevel@tonic-gate 	if (my_want_state_is_dont(TELOPT_STATUS)) {
25037c478bd9Sstevel@tonic-gate 		(void) printf("Remote side does not support STATUS option\n");
25047c478bd9Sstevel@tonic-gate 		return (0);
25057c478bd9Sstevel@tonic-gate 	}
25067c478bd9Sstevel@tonic-gate 	cp = tmp;
25077c478bd9Sstevel@tonic-gate 
25087c478bd9Sstevel@tonic-gate 	*cp++ = IAC;
25097c478bd9Sstevel@tonic-gate 	*cp++ = SB;
25107c478bd9Sstevel@tonic-gate 	*cp++ = TELOPT_STATUS;
25117c478bd9Sstevel@tonic-gate 	*cp++ = TELQUAL_SEND;
25127c478bd9Sstevel@tonic-gate 	*cp++ = IAC;
25137c478bd9Sstevel@tonic-gate 	*cp++ = SE;
25147c478bd9Sstevel@tonic-gate 	if (NETROOM() >= cp - tmp) {
25157c478bd9Sstevel@tonic-gate 		ring_supply_data(&netoring, tmp, cp-tmp);
25167c478bd9Sstevel@tonic-gate 		printsub('>', tmp+2, cp - tmp - 2);
25177c478bd9Sstevel@tonic-gate 	}
25187c478bd9Sstevel@tonic-gate 	++want_status_response;
25197c478bd9Sstevel@tonic-gate 	return (1);
25207c478bd9Sstevel@tonic-gate }
25217c478bd9Sstevel@tonic-gate 
25227c478bd9Sstevel@tonic-gate void
intp()25237c478bd9Sstevel@tonic-gate intp()
25247c478bd9Sstevel@tonic-gate {
25257c478bd9Sstevel@tonic-gate 	NET2ADD(IAC, IP);
25267c478bd9Sstevel@tonic-gate 	printoption("SENT", IAC, IP);
25277c478bd9Sstevel@tonic-gate 	flushline = 1;
25287c478bd9Sstevel@tonic-gate 	if (autoflush) {
25297c478bd9Sstevel@tonic-gate 		/* Ignore return as we're ending off anyway. */
25307c478bd9Sstevel@tonic-gate 		(void) doflush();
25317c478bd9Sstevel@tonic-gate 	}
25327c478bd9Sstevel@tonic-gate 	if (autosynch) {
25337c478bd9Sstevel@tonic-gate 		(void) dosynch();
25347c478bd9Sstevel@tonic-gate 	}
25357c478bd9Sstevel@tonic-gate }
25367c478bd9Sstevel@tonic-gate 
25377c478bd9Sstevel@tonic-gate int
sendbrk()25387c478bd9Sstevel@tonic-gate sendbrk()
25397c478bd9Sstevel@tonic-gate {
25407c478bd9Sstevel@tonic-gate 	NET2ADD(IAC, BREAK);
25417c478bd9Sstevel@tonic-gate 	printoption("SENT", IAC, BREAK);
25427c478bd9Sstevel@tonic-gate 	flushline = 1;
25437c478bd9Sstevel@tonic-gate 	if (autoflush) {
25447c478bd9Sstevel@tonic-gate 		if (doflush() == -1)
25457c478bd9Sstevel@tonic-gate 			return (-1);
25467c478bd9Sstevel@tonic-gate 	}
25477c478bd9Sstevel@tonic-gate 	if (autosynch) {
25487c478bd9Sstevel@tonic-gate 		(void) dosynch();
25497c478bd9Sstevel@tonic-gate 	}
25507c478bd9Sstevel@tonic-gate 	return (0);
25517c478bd9Sstevel@tonic-gate }
25527c478bd9Sstevel@tonic-gate 
25537c478bd9Sstevel@tonic-gate void
sendabort()25547c478bd9Sstevel@tonic-gate sendabort()
25557c478bd9Sstevel@tonic-gate {
25567c478bd9Sstevel@tonic-gate 	NET2ADD(IAC, ABORT);
25577c478bd9Sstevel@tonic-gate 	printoption("SENT", IAC, ABORT);
25587c478bd9Sstevel@tonic-gate 	flushline = 1;
25597c478bd9Sstevel@tonic-gate 	if (autoflush) {
25607c478bd9Sstevel@tonic-gate 		/*
25617c478bd9Sstevel@tonic-gate 		 * Since sendabort() gets called while aborting,
25627c478bd9Sstevel@tonic-gate 		 * ignore the doflush() return
25637c478bd9Sstevel@tonic-gate 		 */
25647c478bd9Sstevel@tonic-gate 		(void) doflush();
25657c478bd9Sstevel@tonic-gate 	}
25667c478bd9Sstevel@tonic-gate 	if (autosynch) {
25677c478bd9Sstevel@tonic-gate 		(void) dosynch();
25687c478bd9Sstevel@tonic-gate 	}
25697c478bd9Sstevel@tonic-gate }
25707c478bd9Sstevel@tonic-gate 
25717c478bd9Sstevel@tonic-gate void
sendsusp()25727c478bd9Sstevel@tonic-gate sendsusp()
25737c478bd9Sstevel@tonic-gate {
25747c478bd9Sstevel@tonic-gate 	NET2ADD(IAC, SUSP);
25757c478bd9Sstevel@tonic-gate 	printoption("SENT", IAC, SUSP);
25767c478bd9Sstevel@tonic-gate 	flushline = 1;
25777c478bd9Sstevel@tonic-gate 	if (autoflush) {
25787c478bd9Sstevel@tonic-gate 		if (doflush() == -1) {
25797c478bd9Sstevel@tonic-gate 			/* The following will not return. */
25807c478bd9Sstevel@tonic-gate 			fatal_tty_error("write");
25817c478bd9Sstevel@tonic-gate 		}
25827c478bd9Sstevel@tonic-gate 	}
25837c478bd9Sstevel@tonic-gate 	if (autosynch) {
25847c478bd9Sstevel@tonic-gate 		(void) dosynch();
25857c478bd9Sstevel@tonic-gate 	}
25867c478bd9Sstevel@tonic-gate }
25877c478bd9Sstevel@tonic-gate 
25887c478bd9Sstevel@tonic-gate static void
sendeof()25897c478bd9Sstevel@tonic-gate sendeof()
25907c478bd9Sstevel@tonic-gate {
25917c478bd9Sstevel@tonic-gate 	NET2ADD(IAC, xEOF);
25927c478bd9Sstevel@tonic-gate 	printoption("SENT", IAC, xEOF);
25937c478bd9Sstevel@tonic-gate }
25947c478bd9Sstevel@tonic-gate 
25957c478bd9Sstevel@tonic-gate /*
25967c478bd9Sstevel@tonic-gate  * Send a window size update to the remote system.
25977c478bd9Sstevel@tonic-gate  */
25987c478bd9Sstevel@tonic-gate 
25997c478bd9Sstevel@tonic-gate void
sendnaws()26007c478bd9Sstevel@tonic-gate sendnaws()
26017c478bd9Sstevel@tonic-gate {
26027c478bd9Sstevel@tonic-gate 	unsigned short rows, cols;
26037c478bd9Sstevel@tonic-gate 	unsigned char tmp[16];
26047c478bd9Sstevel@tonic-gate 	register unsigned char *cp;
26057c478bd9Sstevel@tonic-gate 
26067c478bd9Sstevel@tonic-gate 	if (my_state_is_wont(TELOPT_NAWS))
26077c478bd9Sstevel@tonic-gate 		return;
26087c478bd9Sstevel@tonic-gate 
26097c478bd9Sstevel@tonic-gate #define	PUTSHORT(cp, x) { if ((*cp++ = ((x)>>8)&0xff) == IAC) *cp++ = IAC; \
26107c478bd9Sstevel@tonic-gate 			    if ((*cp++ = ((x))&0xff) == IAC) *cp++ = IAC; }
26117c478bd9Sstevel@tonic-gate 
26127c478bd9Sstevel@tonic-gate 	if (TerminalWindowSize(&rows, &cols) == 0) {	/* Failed */
26137c478bd9Sstevel@tonic-gate 		return;
26147c478bd9Sstevel@tonic-gate 	}
26157c478bd9Sstevel@tonic-gate 
26167c478bd9Sstevel@tonic-gate 	cp = tmp;
26177c478bd9Sstevel@tonic-gate 
26187c478bd9Sstevel@tonic-gate 	*cp++ = IAC;
26197c478bd9Sstevel@tonic-gate 	*cp++ = SB;
26207c478bd9Sstevel@tonic-gate 	*cp++ = TELOPT_NAWS;
26217c478bd9Sstevel@tonic-gate 	PUTSHORT(cp, cols);
26227c478bd9Sstevel@tonic-gate 	PUTSHORT(cp, rows);
26237c478bd9Sstevel@tonic-gate 	*cp++ = IAC;
26247c478bd9Sstevel@tonic-gate 	*cp++ = SE;
26257c478bd9Sstevel@tonic-gate 	if (NETROOM() >= cp - tmp) {
26267c478bd9Sstevel@tonic-gate 		ring_supply_data(&netoring, tmp, cp-tmp);
26277c478bd9Sstevel@tonic-gate 		printsub('>', tmp+2, cp - tmp - 2);
26287c478bd9Sstevel@tonic-gate 	}
26297c478bd9Sstevel@tonic-gate }
26307c478bd9Sstevel@tonic-gate 
26317c478bd9Sstevel@tonic-gate void
tel_enter_binary(rw)26327c478bd9Sstevel@tonic-gate tel_enter_binary(rw)
26337c478bd9Sstevel@tonic-gate 	int rw;
26347c478bd9Sstevel@tonic-gate {
26357c478bd9Sstevel@tonic-gate 	if (rw&1)
26367c478bd9Sstevel@tonic-gate 		send_do(TELOPT_BINARY, 1);
26377c478bd9Sstevel@tonic-gate 	if (rw&2)
26387c478bd9Sstevel@tonic-gate 		send_will(TELOPT_BINARY, 1);
26397c478bd9Sstevel@tonic-gate }
26407c478bd9Sstevel@tonic-gate 
26417c478bd9Sstevel@tonic-gate void
tel_leave_binary(rw)26427c478bd9Sstevel@tonic-gate tel_leave_binary(rw)
26437c478bd9Sstevel@tonic-gate 	int rw;
26447c478bd9Sstevel@tonic-gate {
26457c478bd9Sstevel@tonic-gate 	if (rw&1)
26467c478bd9Sstevel@tonic-gate 		send_dont(TELOPT_BINARY, 1);
26477c478bd9Sstevel@tonic-gate 	if (rw&2)
26487c478bd9Sstevel@tonic-gate 		send_wont(TELOPT_BINARY, 1);
26497c478bd9Sstevel@tonic-gate }
2650