xref: /onnv-gate/usr/src/cmd/cmd-inet/usr.bin/telnet/telnet.c (revision 0:68f95e015346)
1*0Sstevel@tonic-gate /*
2*0Sstevel@tonic-gate  * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
3*0Sstevel@tonic-gate  * Use is subject to license terms.
4*0Sstevel@tonic-gate  */
5*0Sstevel@tonic-gate 
6*0Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
7*0Sstevel@tonic-gate 
8*0Sstevel@tonic-gate /*
9*0Sstevel@tonic-gate  * Copyright (c) 1988, 1990, 1993
10*0Sstevel@tonic-gate  *	The Regents of the University of California.  All rights reserved.
11*0Sstevel@tonic-gate  *
12*0Sstevel@tonic-gate  * Redistribution and use in source and binary forms, with or without
13*0Sstevel@tonic-gate  * modification, are permitted provided that the following conditions
14*0Sstevel@tonic-gate  * are met:
15*0Sstevel@tonic-gate  * 1. Redistributions of source code must retain the above copyright
16*0Sstevel@tonic-gate  *    notice, this list of conditions and the following disclaimer.
17*0Sstevel@tonic-gate  * 2. Redistributions in binary form must reproduce the above copyright
18*0Sstevel@tonic-gate  *    notice, this list of conditions and the following disclaimer in the
19*0Sstevel@tonic-gate  *    documentation and/or other materials provided with the distribution.
20*0Sstevel@tonic-gate  * 3. All advertising materials mentioning features or use of this software
21*0Sstevel@tonic-gate  *    must display the following acknowledgement:
22*0Sstevel@tonic-gate  *	This product includes software developed by the University of
23*0Sstevel@tonic-gate  *	California, Berkeley and its contributors.
24*0Sstevel@tonic-gate  * 4. Neither the name of the University nor the names of its contributors
25*0Sstevel@tonic-gate  *    may be used to endorse or promote products derived from this software
26*0Sstevel@tonic-gate  *    without specific prior written permission.
27*0Sstevel@tonic-gate  *
28*0Sstevel@tonic-gate  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
29*0Sstevel@tonic-gate  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
30*0Sstevel@tonic-gate  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
31*0Sstevel@tonic-gate  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
32*0Sstevel@tonic-gate  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
33*0Sstevel@tonic-gate  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
34*0Sstevel@tonic-gate  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
35*0Sstevel@tonic-gate  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
36*0Sstevel@tonic-gate  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
37*0Sstevel@tonic-gate  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
38*0Sstevel@tonic-gate  * SUCH DAMAGE.
39*0Sstevel@tonic-gate  */
40*0Sstevel@tonic-gate 
41*0Sstevel@tonic-gate #ifndef lint
42*0Sstevel@tonic-gate static char sccsid[] = "@(#)telnet.c	8.1 (Berkeley) 6/6/93";
43*0Sstevel@tonic-gate #endif /* not lint */
44*0Sstevel@tonic-gate 
45*0Sstevel@tonic-gate #include <netdb.h>
46*0Sstevel@tonic-gate #include <sys/types.h>
47*0Sstevel@tonic-gate 
48*0Sstevel@tonic-gate #include <curses.h>
49*0Sstevel@tonic-gate #include <signal.h>
50*0Sstevel@tonic-gate /*
51*0Sstevel@tonic-gate  * By the way, we need to include curses.h before telnet.h since,
52*0Sstevel@tonic-gate  * among other things, telnet.h #defines 'DO', which is a variable
53*0Sstevel@tonic-gate  * declared in curses.h.
54*0Sstevel@tonic-gate  */
55*0Sstevel@tonic-gate 
56*0Sstevel@tonic-gate #include <arpa/telnet.h>
57*0Sstevel@tonic-gate 
58*0Sstevel@tonic-gate #include <ctype.h>
59*0Sstevel@tonic-gate 
60*0Sstevel@tonic-gate #include "ring.h"
61*0Sstevel@tonic-gate 
62*0Sstevel@tonic-gate #include "defines.h"
63*0Sstevel@tonic-gate #include "externs.h"
64*0Sstevel@tonic-gate #include "types.h"
65*0Sstevel@tonic-gate #include "general.h"
66*0Sstevel@tonic-gate 
67*0Sstevel@tonic-gate #include "auth.h"
68*0Sstevel@tonic-gate #include "encrypt.h"
69*0Sstevel@tonic-gate 
70*0Sstevel@tonic-gate #define	strip(x)	((x)&0x7f)
71*0Sstevel@tonic-gate 
72*0Sstevel@tonic-gate /* Buffer for sub-options */
73*0Sstevel@tonic-gate static unsigned char	subbuffer[SUBBUFSIZE];
74*0Sstevel@tonic-gate static unsigned char	*subpointer;
75*0Sstevel@tonic-gate static unsigned char	*subend;
76*0Sstevel@tonic-gate 
77*0Sstevel@tonic-gate #define	SB_CLEAR()	subpointer = subbuffer;
78*0Sstevel@tonic-gate #define	SB_TERM()	{ subend = subpointer; SB_CLEAR(); }
79*0Sstevel@tonic-gate #define	SB_ACCUM(c)	if (subpointer < (subbuffer+sizeof (subbuffer))) { \
80*0Sstevel@tonic-gate 				*subpointer++ = (c); \
81*0Sstevel@tonic-gate 			}
82*0Sstevel@tonic-gate 
83*0Sstevel@tonic-gate #define	SB_GET()	((*subpointer++)&0xff)
84*0Sstevel@tonic-gate #define	SB_PEEK()	((*subpointer)&0xff)
85*0Sstevel@tonic-gate #define	SB_EOF()	(subpointer >= subend)
86*0Sstevel@tonic-gate #define	SB_LEN()	(subend - subpointer)
87*0Sstevel@tonic-gate 
88*0Sstevel@tonic-gate char	options[SUBBUFSIZE];		/* The combined options */
89*0Sstevel@tonic-gate char	do_dont_resp[SUBBUFSIZE];
90*0Sstevel@tonic-gate char	will_wont_resp[SUBBUFSIZE];
91*0Sstevel@tonic-gate 
92*0Sstevel@tonic-gate int eight = 0;
93*0Sstevel@tonic-gate int autologin = 0;	/* Autologin anyone? */
94*0Sstevel@tonic-gate int skiprc = 0;
95*0Sstevel@tonic-gate int connected;
96*0Sstevel@tonic-gate int showoptions;
97*0Sstevel@tonic-gate static int ISend;	/* trying to send network data in */
98*0Sstevel@tonic-gate int debug = 0;
99*0Sstevel@tonic-gate int crmod;
100*0Sstevel@tonic-gate int netdata;		/* Print out network data flow */
101*0Sstevel@tonic-gate int crlf;		/* Should '\r' be mapped to <CR><LF> (or <CR><NUL>)? */
102*0Sstevel@tonic-gate int telnetport;
103*0Sstevel@tonic-gate int SYNCHing;		/* we are in TELNET SYNCH mode */
104*0Sstevel@tonic-gate int flushout;		/* flush output */
105*0Sstevel@tonic-gate int autoflush = 0;	/* flush output when interrupting? */
106*0Sstevel@tonic-gate int autosynch;		/* send interrupt characters with SYNCH? */
107*0Sstevel@tonic-gate int localflow;		/* we handle flow control locally */
108*0Sstevel@tonic-gate int restartany;		/* if flow control enabled, restart on any character */
109*0Sstevel@tonic-gate int localchars;		/* we recognize interrupt/quit */
110*0Sstevel@tonic-gate int donelclchars;	/* the user has set "localchars" */
111*0Sstevel@tonic-gate int donebinarytoggle;	/* the user has put us in binary */
112*0Sstevel@tonic-gate int dontlecho;		/* do we suppress local echoing right now? */
113*0Sstevel@tonic-gate int eof_pending = 0;	/* we received a genuine EOF on input, send IAC-EOF */
114*0Sstevel@tonic-gate int globalmode;
115*0Sstevel@tonic-gate 
116*0Sstevel@tonic-gate /* spin while waiting for authentication */
117*0Sstevel@tonic-gate boolean_t scheduler_lockout_tty = B_FALSE;
118*0Sstevel@tonic-gate int encrypt_flag = 0;
119*0Sstevel@tonic-gate int forwardable_flag = 0;
120*0Sstevel@tonic-gate int forward_flag = 0;
121*0Sstevel@tonic-gate boolean_t wantencryption = B_FALSE;
122*0Sstevel@tonic-gate 
123*0Sstevel@tonic-gate char *prompt = 0;
124*0Sstevel@tonic-gate 
125*0Sstevel@tonic-gate cc_t escape;
126*0Sstevel@tonic-gate cc_t rlogin;
127*0Sstevel@tonic-gate boolean_t escape_valid = B_TRUE;
128*0Sstevel@tonic-gate #ifdef	KLUDGELINEMODE
129*0Sstevel@tonic-gate cc_t echoc;
130*0Sstevel@tonic-gate #endif
131*0Sstevel@tonic-gate 
132*0Sstevel@tonic-gate /*
133*0Sstevel@tonic-gate  * Telnet receiver states for fsm
134*0Sstevel@tonic-gate  */
135*0Sstevel@tonic-gate #define	TS_DATA		0
136*0Sstevel@tonic-gate #define	TS_IAC		1
137*0Sstevel@tonic-gate #define	TS_WILL		2
138*0Sstevel@tonic-gate #define	TS_WONT		3
139*0Sstevel@tonic-gate #define	TS_DO		4
140*0Sstevel@tonic-gate #define	TS_DONT		5
141*0Sstevel@tonic-gate #define	TS_CR		6
142*0Sstevel@tonic-gate #define	TS_SB		7		/* sub-option collection */
143*0Sstevel@tonic-gate #define	TS_SE		8		/* looking for sub-option end */
144*0Sstevel@tonic-gate 
145*0Sstevel@tonic-gate static int	telrcv_state;
146*0Sstevel@tonic-gate #ifdef	OLD_ENVIRON
147*0Sstevel@tonic-gate static	unsigned char telopt_environ = TELOPT_NEW_ENVIRON;
148*0Sstevel@tonic-gate #else
149*0Sstevel@tonic-gate #define	telopt_environ	TELOPT_NEW_ENVIRON
150*0Sstevel@tonic-gate #endif
151*0Sstevel@tonic-gate 
152*0Sstevel@tonic-gate jmp_buf	toplevel = { 0 };
153*0Sstevel@tonic-gate jmp_buf	peerdied;
154*0Sstevel@tonic-gate 
155*0Sstevel@tonic-gate static int flushline;
156*0Sstevel@tonic-gate int	linemode;
157*0Sstevel@tonic-gate 
158*0Sstevel@tonic-gate int	reqd_linemode = 0; /* Set if either new or old line mode in */
159*0Sstevel@tonic-gate 			/* effect since before initial negotiations */
160*0Sstevel@tonic-gate 
161*0Sstevel@tonic-gate #ifdef	KLUDGELINEMODE
162*0Sstevel@tonic-gate int	kludgelinemode = 1;
163*0Sstevel@tonic-gate #endif
164*0Sstevel@tonic-gate 
165*0Sstevel@tonic-gate /*
166*0Sstevel@tonic-gate  * The following are some clocks used to decide how to interpret
167*0Sstevel@tonic-gate  * the relationship between various variables.
168*0Sstevel@tonic-gate  */
169*0Sstevel@tonic-gate 
170*0Sstevel@tonic-gate Clocks clocks;
171*0Sstevel@tonic-gate 
172*0Sstevel@tonic-gate #ifdef	notdef
173*0Sstevel@tonic-gate Modelist modelist[] = {
174*0Sstevel@tonic-gate 	{ "telnet command mode", COMMAND_LINE },
175*0Sstevel@tonic-gate 	{ "character-at-a-time mode", 0 },
176*0Sstevel@tonic-gate 	{ "character-at-a-time mode (local echo)", LOCAL_ECHO|LOCAL_CHARS },
177*0Sstevel@tonic-gate 	{ "line-by-line mode (remote echo)", LINE | LOCAL_CHARS },
178*0Sstevel@tonic-gate 	{ "line-by-line mode", LINE | LOCAL_ECHO | LOCAL_CHARS },
179*0Sstevel@tonic-gate 	{ "line-by-line mode (local echoing suppressed)", LINE | LOCAL_CHARS },
180*0Sstevel@tonic-gate 	{ "3270 mode", 0 },
181*0Sstevel@tonic-gate };
182*0Sstevel@tonic-gate #endif
183*0Sstevel@tonic-gate 
184*0Sstevel@tonic-gate static void willoption(int);
185*0Sstevel@tonic-gate static void wontoption(int);
186*0Sstevel@tonic-gate static void lm_will(unsigned char *, int);
187*0Sstevel@tonic-gate static void lm_wont(unsigned char *, int);
188*0Sstevel@tonic-gate static void lm_do(unsigned char *, int);
189*0Sstevel@tonic-gate static void lm_dont(unsigned char *, int);
190*0Sstevel@tonic-gate static void slc_init(void);
191*0Sstevel@tonic-gate static void slc_import(int);
192*0Sstevel@tonic-gate static void slc_export(void);
193*0Sstevel@tonic-gate static void slc_start_reply(size_t);
194*0Sstevel@tonic-gate static void slc_add_reply(unsigned char, unsigned char, cc_t);
195*0Sstevel@tonic-gate static void slc_end_reply(void);
196*0Sstevel@tonic-gate static void slc(unsigned char *, int);
197*0Sstevel@tonic-gate static int slc_update(void);
198*0Sstevel@tonic-gate static void env_opt(unsigned char *, int);
199*0Sstevel@tonic-gate static void env_opt_start(void);
200*0Sstevel@tonic-gate static void sendeof(void);
201*0Sstevel@tonic-gate static int is_unique(register char *, register char **, register char **);
202*0Sstevel@tonic-gate 
203*0Sstevel@tonic-gate /*
204*0Sstevel@tonic-gate  * Initialize telnet environment.
205*0Sstevel@tonic-gate  */
206*0Sstevel@tonic-gate 
207*0Sstevel@tonic-gate int
init_telnet()208*0Sstevel@tonic-gate init_telnet()
209*0Sstevel@tonic-gate {
210*0Sstevel@tonic-gate 	if (env_init() == 0)
211*0Sstevel@tonic-gate 		return (0);
212*0Sstevel@tonic-gate 
213*0Sstevel@tonic-gate 	SB_CLEAR();
214*0Sstevel@tonic-gate 	ClearArray(options);
215*0Sstevel@tonic-gate 
216*0Sstevel@tonic-gate 	connected = ISend = localflow = donebinarytoggle = 0;
217*0Sstevel@tonic-gate 	restartany = -1;
218*0Sstevel@tonic-gate 
219*0Sstevel@tonic-gate 	SYNCHing = 0;
220*0Sstevel@tonic-gate 
221*0Sstevel@tonic-gate 	/* Don't change NetTrace */
222*0Sstevel@tonic-gate 
223*0Sstevel@tonic-gate 	escape = CONTROL(']');
224*0Sstevel@tonic-gate 	rlogin = _POSIX_VDISABLE;
225*0Sstevel@tonic-gate #ifdef	KLUDGELINEMODE
226*0Sstevel@tonic-gate 	echoc = CONTROL('E');
227*0Sstevel@tonic-gate #endif
228*0Sstevel@tonic-gate 
229*0Sstevel@tonic-gate 	flushline = 1;
230*0Sstevel@tonic-gate 	telrcv_state = TS_DATA;
231*0Sstevel@tonic-gate 
232*0Sstevel@tonic-gate 	return (1);
233*0Sstevel@tonic-gate }
234*0Sstevel@tonic-gate 
235*0Sstevel@tonic-gate 
236*0Sstevel@tonic-gate #ifdef	notdef
237*0Sstevel@tonic-gate #include <varargs.h>
238*0Sstevel@tonic-gate 
239*0Sstevel@tonic-gate /*VARARGS*/
240*0Sstevel@tonic-gate static void
printring(va_alist)241*0Sstevel@tonic-gate printring(va_alist)
242*0Sstevel@tonic-gate 	va_dcl
243*0Sstevel@tonic-gate {
244*0Sstevel@tonic-gate 	va_list ap;
245*0Sstevel@tonic-gate 	char buffer[100];		/* where things go */
246*0Sstevel@tonic-gate 	char *ptr;
247*0Sstevel@tonic-gate 	char *format;
248*0Sstevel@tonic-gate 	char *string;
249*0Sstevel@tonic-gate 	Ring *ring;
250*0Sstevel@tonic-gate 	int i;
251*0Sstevel@tonic-gate 
252*0Sstevel@tonic-gate 	va_start(ap);
253*0Sstevel@tonic-gate 
254*0Sstevel@tonic-gate 	ring = va_arg(ap, Ring *);
255*0Sstevel@tonic-gate 	format = va_arg(ap, char *);
256*0Sstevel@tonic-gate 	ptr = buffer;
257*0Sstevel@tonic-gate 
258*0Sstevel@tonic-gate 	while ((i = *format++) != 0) {
259*0Sstevel@tonic-gate 		if (i == '%') {
260*0Sstevel@tonic-gate 			i = *format++;
261*0Sstevel@tonic-gate 			switch (i) {
262*0Sstevel@tonic-gate 			case 'c':
263*0Sstevel@tonic-gate 				*ptr++ = va_arg(ap, int);
264*0Sstevel@tonic-gate 				break;
265*0Sstevel@tonic-gate 			case 's':
266*0Sstevel@tonic-gate 				string = va_arg(ap, char *);
267*0Sstevel@tonic-gate 				ring_supply_data(ring, buffer, ptr-buffer);
268*0Sstevel@tonic-gate 				ring_supply_data(ring, string, strlen(string));
269*0Sstevel@tonic-gate 				ptr = buffer;
270*0Sstevel@tonic-gate 				break;
271*0Sstevel@tonic-gate 			case 0:
272*0Sstevel@tonic-gate 				ExitString("printring: trailing %%.\n",
273*0Sstevel@tonic-gate 				    EXIT_FAILURE);
274*0Sstevel@tonic-gate 				/*NOTREACHED*/
275*0Sstevel@tonic-gate 			default:
276*0Sstevel@tonic-gate 				ExitString("printring: unknown format "
277*0Sstevel@tonic-gate 				    "character.\n", EXIT_FAILURE);
278*0Sstevel@tonic-gate 				/*NOTREACHED*/
279*0Sstevel@tonic-gate 			}
280*0Sstevel@tonic-gate 		} else {
281*0Sstevel@tonic-gate 			*ptr++ = i;
282*0Sstevel@tonic-gate 		}
283*0Sstevel@tonic-gate 	}
284*0Sstevel@tonic-gate 	ring_supply_data(ring, buffer, ptr-buffer);
285*0Sstevel@tonic-gate }
286*0Sstevel@tonic-gate #endif
287*0Sstevel@tonic-gate 
288*0Sstevel@tonic-gate /*
289*0Sstevel@tonic-gate  * These routines are in charge of sending option negotiations
290*0Sstevel@tonic-gate  * to the other side.
291*0Sstevel@tonic-gate  *
292*0Sstevel@tonic-gate  * The basic idea is that we send the negotiation if either side
293*0Sstevel@tonic-gate  * is in disagreement as to what the current state should be.
294*0Sstevel@tonic-gate  */
295*0Sstevel@tonic-gate 
296*0Sstevel@tonic-gate void
send_do(c,init)297*0Sstevel@tonic-gate send_do(c, init)
298*0Sstevel@tonic-gate 	register int c, init;
299*0Sstevel@tonic-gate {
300*0Sstevel@tonic-gate 	if (init) {
301*0Sstevel@tonic-gate 		if (((do_dont_resp[c] == 0) && my_state_is_do(c)) ||
302*0Sstevel@tonic-gate 		    my_want_state_is_do(c))
303*0Sstevel@tonic-gate 			return;
304*0Sstevel@tonic-gate 		set_my_want_state_do(c);
305*0Sstevel@tonic-gate 		do_dont_resp[c]++;
306*0Sstevel@tonic-gate 	}
307*0Sstevel@tonic-gate 	NET2ADD(IAC, DO);
308*0Sstevel@tonic-gate 	NETADD(c);
309*0Sstevel@tonic-gate 	printoption("SENT", DO, c);
310*0Sstevel@tonic-gate }
311*0Sstevel@tonic-gate 
312*0Sstevel@tonic-gate void
send_dont(c,init)313*0Sstevel@tonic-gate send_dont(c, init)
314*0Sstevel@tonic-gate 	register int c, init;
315*0Sstevel@tonic-gate {
316*0Sstevel@tonic-gate 	if (init) {
317*0Sstevel@tonic-gate 		if (((do_dont_resp[c] == 0) && my_state_is_dont(c)) ||
318*0Sstevel@tonic-gate 		    my_want_state_is_dont(c))
319*0Sstevel@tonic-gate 			return;
320*0Sstevel@tonic-gate 		set_my_want_state_dont(c);
321*0Sstevel@tonic-gate 		do_dont_resp[c]++;
322*0Sstevel@tonic-gate 	}
323*0Sstevel@tonic-gate 	NET2ADD(IAC, DONT);
324*0Sstevel@tonic-gate 	NETADD(c);
325*0Sstevel@tonic-gate 	printoption("SENT", DONT, c);
326*0Sstevel@tonic-gate }
327*0Sstevel@tonic-gate 
328*0Sstevel@tonic-gate void
send_will(c,init)329*0Sstevel@tonic-gate send_will(c, init)
330*0Sstevel@tonic-gate 	register int c, init;
331*0Sstevel@tonic-gate {
332*0Sstevel@tonic-gate 	if (init) {
333*0Sstevel@tonic-gate 		if (((will_wont_resp[c] == 0) && my_state_is_will(c)) ||
334*0Sstevel@tonic-gate 		    my_want_state_is_will(c))
335*0Sstevel@tonic-gate 			return;
336*0Sstevel@tonic-gate 		set_my_want_state_will(c);
337*0Sstevel@tonic-gate 		will_wont_resp[c]++;
338*0Sstevel@tonic-gate 	}
339*0Sstevel@tonic-gate 	NET2ADD(IAC, WILL);
340*0Sstevel@tonic-gate 	NETADD(c);
341*0Sstevel@tonic-gate 	printoption("SENT", WILL, c);
342*0Sstevel@tonic-gate }
343*0Sstevel@tonic-gate 
344*0Sstevel@tonic-gate void
send_wont(c,init)345*0Sstevel@tonic-gate send_wont(c, init)
346*0Sstevel@tonic-gate 	register int c, init;
347*0Sstevel@tonic-gate {
348*0Sstevel@tonic-gate 	if (init) {
349*0Sstevel@tonic-gate 		if (((will_wont_resp[c] == 0) && my_state_is_wont(c)) ||
350*0Sstevel@tonic-gate 		    my_want_state_is_wont(c))
351*0Sstevel@tonic-gate 			return;
352*0Sstevel@tonic-gate 		set_my_want_state_wont(c);
353*0Sstevel@tonic-gate 		will_wont_resp[c]++;
354*0Sstevel@tonic-gate 	}
355*0Sstevel@tonic-gate 	NET2ADD(IAC, WONT);
356*0Sstevel@tonic-gate 	NETADD(c);
357*0Sstevel@tonic-gate 	printoption("SENT", WONT, c);
358*0Sstevel@tonic-gate }
359*0Sstevel@tonic-gate 
360*0Sstevel@tonic-gate 
361*0Sstevel@tonic-gate static void
willoption(option)362*0Sstevel@tonic-gate willoption(option)
363*0Sstevel@tonic-gate 	int option;
364*0Sstevel@tonic-gate {
365*0Sstevel@tonic-gate 	int new_state_ok = 0;
366*0Sstevel@tonic-gate 
367*0Sstevel@tonic-gate 	if (do_dont_resp[option]) {
368*0Sstevel@tonic-gate 	    --do_dont_resp[option];
369*0Sstevel@tonic-gate 	    if (do_dont_resp[option] && my_state_is_do(option))
370*0Sstevel@tonic-gate 		--do_dont_resp[option];
371*0Sstevel@tonic-gate 	}
372*0Sstevel@tonic-gate 
373*0Sstevel@tonic-gate 	if ((do_dont_resp[option] == 0) && my_want_state_is_dont(option)) {
374*0Sstevel@tonic-gate 
375*0Sstevel@tonic-gate 	    switch (option) {
376*0Sstevel@tonic-gate 
377*0Sstevel@tonic-gate 	    case TELOPT_ECHO:
378*0Sstevel@tonic-gate 	    case TELOPT_SGA:
379*0Sstevel@tonic-gate 		if (reqd_linemode && my_state_is_dont(option)) {
380*0Sstevel@tonic-gate 		    break;
381*0Sstevel@tonic-gate 		}
382*0Sstevel@tonic-gate 		/* FALLTHROUGH */
383*0Sstevel@tonic-gate 	    case TELOPT_BINARY:
384*0Sstevel@tonic-gate 		settimer(modenegotiated);
385*0Sstevel@tonic-gate 		/* FALLTHROUGH */
386*0Sstevel@tonic-gate 	    case TELOPT_STATUS:
387*0Sstevel@tonic-gate 	    case TELOPT_AUTHENTICATION:
388*0Sstevel@tonic-gate 		/* FALLTHROUGH */
389*0Sstevel@tonic-gate 	    case TELOPT_ENCRYPT:
390*0Sstevel@tonic-gate 		new_state_ok = 1;
391*0Sstevel@tonic-gate 		break;
392*0Sstevel@tonic-gate 
393*0Sstevel@tonic-gate 	    case TELOPT_TM:
394*0Sstevel@tonic-gate 		if (flushout)
395*0Sstevel@tonic-gate 		    flushout = 0;
396*0Sstevel@tonic-gate 		/*
397*0Sstevel@tonic-gate 		 * Special case for TM.  If we get back a WILL,
398*0Sstevel@tonic-gate 		 * pretend we got back a WONT.
399*0Sstevel@tonic-gate 		 */
400*0Sstevel@tonic-gate 		set_my_want_state_dont(option);
401*0Sstevel@tonic-gate 		set_my_state_dont(option);
402*0Sstevel@tonic-gate 		return;			/* Never reply to TM will's/wont's */
403*0Sstevel@tonic-gate 
404*0Sstevel@tonic-gate 	    case TELOPT_LINEMODE:
405*0Sstevel@tonic-gate 	    default:
406*0Sstevel@tonic-gate 		break;
407*0Sstevel@tonic-gate 	    }
408*0Sstevel@tonic-gate 
409*0Sstevel@tonic-gate 	    if (new_state_ok) {
410*0Sstevel@tonic-gate 		set_my_want_state_do(option);
411*0Sstevel@tonic-gate 		send_do(option, 0);
412*0Sstevel@tonic-gate 		setconnmode(0);		/* possibly set new tty mode */
413*0Sstevel@tonic-gate 	    } else {
414*0Sstevel@tonic-gate 		do_dont_resp[option]++;
415*0Sstevel@tonic-gate 		send_dont(option, 0);
416*0Sstevel@tonic-gate 	    }
417*0Sstevel@tonic-gate 	}
418*0Sstevel@tonic-gate 	set_my_state_do(option);
419*0Sstevel@tonic-gate 	if (option == TELOPT_ENCRYPT)
420*0Sstevel@tonic-gate 		encrypt_send_support();
421*0Sstevel@tonic-gate }
422*0Sstevel@tonic-gate 
423*0Sstevel@tonic-gate static void
wontoption(option)424*0Sstevel@tonic-gate wontoption(option)
425*0Sstevel@tonic-gate 	int option;
426*0Sstevel@tonic-gate {
427*0Sstevel@tonic-gate 	if (do_dont_resp[option]) {
428*0Sstevel@tonic-gate 		--do_dont_resp[option];
429*0Sstevel@tonic-gate 		if (do_dont_resp[option] && my_state_is_dont(option))
430*0Sstevel@tonic-gate 			--do_dont_resp[option];
431*0Sstevel@tonic-gate 	}
432*0Sstevel@tonic-gate 
433*0Sstevel@tonic-gate 	if ((do_dont_resp[option] == 0) && my_want_state_is_do(option)) {
434*0Sstevel@tonic-gate 
435*0Sstevel@tonic-gate 		switch (option) {
436*0Sstevel@tonic-gate 
437*0Sstevel@tonic-gate #ifdef	KLUDGELINEMODE
438*0Sstevel@tonic-gate 		case TELOPT_SGA:
439*0Sstevel@tonic-gate 			if (!kludgelinemode)
440*0Sstevel@tonic-gate 				break;
441*0Sstevel@tonic-gate 			/* FALLTHROUGH */
442*0Sstevel@tonic-gate #endif
443*0Sstevel@tonic-gate 		case TELOPT_ECHO:
444*0Sstevel@tonic-gate 			settimer(modenegotiated);
445*0Sstevel@tonic-gate 			break;
446*0Sstevel@tonic-gate 
447*0Sstevel@tonic-gate 		case TELOPT_TM:
448*0Sstevel@tonic-gate 			if (flushout)
449*0Sstevel@tonic-gate 				flushout = 0;
450*0Sstevel@tonic-gate 			set_my_want_state_dont(option);
451*0Sstevel@tonic-gate 			set_my_state_dont(option);
452*0Sstevel@tonic-gate 			return;		/* Never reply to TM will's/wont's */
453*0Sstevel@tonic-gate 
454*0Sstevel@tonic-gate 		default:
455*0Sstevel@tonic-gate 			break;
456*0Sstevel@tonic-gate 		}
457*0Sstevel@tonic-gate 		set_my_want_state_dont(option);
458*0Sstevel@tonic-gate 		if (my_state_is_do(option))
459*0Sstevel@tonic-gate 			send_dont(option, 0);
460*0Sstevel@tonic-gate 		setconnmode(0);			/* Set new tty mode */
461*0Sstevel@tonic-gate 	} else if (option == TELOPT_TM) {
462*0Sstevel@tonic-gate 		/*
463*0Sstevel@tonic-gate 		 * Special case for TM.
464*0Sstevel@tonic-gate 		 */
465*0Sstevel@tonic-gate 		if (flushout)
466*0Sstevel@tonic-gate 			flushout = 0;
467*0Sstevel@tonic-gate 		set_my_want_state_dont(option);
468*0Sstevel@tonic-gate 	}
469*0Sstevel@tonic-gate 	set_my_state_dont(option);
470*0Sstevel@tonic-gate }
471*0Sstevel@tonic-gate 
472*0Sstevel@tonic-gate static void
dooption(option)473*0Sstevel@tonic-gate dooption(option)
474*0Sstevel@tonic-gate 	int option;
475*0Sstevel@tonic-gate {
476*0Sstevel@tonic-gate 	int new_state_ok = 0;
477*0Sstevel@tonic-gate 
478*0Sstevel@tonic-gate 	if (will_wont_resp[option]) {
479*0Sstevel@tonic-gate 		--will_wont_resp[option];
480*0Sstevel@tonic-gate 		if (will_wont_resp[option] && my_state_is_will(option))
481*0Sstevel@tonic-gate 			--will_wont_resp[option];
482*0Sstevel@tonic-gate 	}
483*0Sstevel@tonic-gate 
484*0Sstevel@tonic-gate 	if (will_wont_resp[option] == 0) {
485*0Sstevel@tonic-gate 		if (my_want_state_is_wont(option)) {
486*0Sstevel@tonic-gate 
487*0Sstevel@tonic-gate 			switch (option) {
488*0Sstevel@tonic-gate 
489*0Sstevel@tonic-gate 			case TELOPT_TM:
490*0Sstevel@tonic-gate 				/*
491*0Sstevel@tonic-gate 				 * Special case for TM.  We send a WILL,
492*0Sstevel@tonic-gate 				 * but pretend we sent WONT.
493*0Sstevel@tonic-gate 				 */
494*0Sstevel@tonic-gate 				send_will(option, 0);
495*0Sstevel@tonic-gate 				set_my_want_state_wont(TELOPT_TM);
496*0Sstevel@tonic-gate 				set_my_state_wont(TELOPT_TM);
497*0Sstevel@tonic-gate 				return;
498*0Sstevel@tonic-gate 
499*0Sstevel@tonic-gate 			case TELOPT_BINARY:	/* binary mode */
500*0Sstevel@tonic-gate 			case TELOPT_NAWS:	/* window size */
501*0Sstevel@tonic-gate 			case TELOPT_TSPEED:	/* terminal speed */
502*0Sstevel@tonic-gate 			case TELOPT_LFLOW:	/* local flow control */
503*0Sstevel@tonic-gate 			case TELOPT_TTYPE:	/* terminal type option */
504*0Sstevel@tonic-gate 			case TELOPT_SGA:	/* no big deal */
505*0Sstevel@tonic-gate 			case TELOPT_ENCRYPT:	/* encryption variable option */
506*0Sstevel@tonic-gate 				new_state_ok = 1;
507*0Sstevel@tonic-gate 				break;
508*0Sstevel@tonic-gate 
509*0Sstevel@tonic-gate 			case TELOPT_NEW_ENVIRON:
510*0Sstevel@tonic-gate 				/* New environment variable option */
511*0Sstevel@tonic-gate #ifdef	OLD_ENVIRON
512*0Sstevel@tonic-gate 				if (my_state_is_will(TELOPT_OLD_ENVIRON))
513*0Sstevel@tonic-gate 					/* turn off the old */
514*0Sstevel@tonic-gate 					send_wont(TELOPT_OLD_ENVIRON, 1);
515*0Sstevel@tonic-gate goto env_common;
516*0Sstevel@tonic-gate 			case TELOPT_OLD_ENVIRON:
517*0Sstevel@tonic-gate 				/* Old environment variable option */
518*0Sstevel@tonic-gate 				if (my_state_is_will(TELOPT_NEW_ENVIRON))
519*0Sstevel@tonic-gate 					/* Don't enable if new one is in use! */
520*0Sstevel@tonic-gate 					break;
521*0Sstevel@tonic-gate env_common:
522*0Sstevel@tonic-gate 				telopt_environ = option;
523*0Sstevel@tonic-gate #endif
524*0Sstevel@tonic-gate 				new_state_ok = 1;
525*0Sstevel@tonic-gate 				break;
526*0Sstevel@tonic-gate 
527*0Sstevel@tonic-gate 			case TELOPT_AUTHENTICATION:
528*0Sstevel@tonic-gate 				if (autologin)
529*0Sstevel@tonic-gate 					new_state_ok = 1;
530*0Sstevel@tonic-gate 				break;
531*0Sstevel@tonic-gate 
532*0Sstevel@tonic-gate 			case TELOPT_XDISPLOC:	/* X Display location */
533*0Sstevel@tonic-gate 				if (env_getvalue((unsigned char *)"DISPLAY"))
534*0Sstevel@tonic-gate 					new_state_ok = 1;
535*0Sstevel@tonic-gate 				break;
536*0Sstevel@tonic-gate 
537*0Sstevel@tonic-gate 			case TELOPT_LINEMODE:
538*0Sstevel@tonic-gate #ifdef	KLUDGELINEMODE
539*0Sstevel@tonic-gate 				kludgelinemode = 0;
540*0Sstevel@tonic-gate 				send_do(TELOPT_SGA, 1);
541*0Sstevel@tonic-gate #endif
542*0Sstevel@tonic-gate 				set_my_want_state_will(TELOPT_LINEMODE);
543*0Sstevel@tonic-gate 				send_will(option, 0);
544*0Sstevel@tonic-gate 				set_my_state_will(TELOPT_LINEMODE);
545*0Sstevel@tonic-gate 				slc_init();
546*0Sstevel@tonic-gate 				return;
547*0Sstevel@tonic-gate 
548*0Sstevel@tonic-gate 			case TELOPT_ECHO: /* We're never going to echo... */
549*0Sstevel@tonic-gate 			default:
550*0Sstevel@tonic-gate 				break;
551*0Sstevel@tonic-gate 			}
552*0Sstevel@tonic-gate 
553*0Sstevel@tonic-gate 			if (new_state_ok) {
554*0Sstevel@tonic-gate 				set_my_want_state_will(option);
555*0Sstevel@tonic-gate 				send_will(option, 0);
556*0Sstevel@tonic-gate 				setconnmode(0);		/* Set new tty mode */
557*0Sstevel@tonic-gate 			} else {
558*0Sstevel@tonic-gate 				will_wont_resp[option]++;
559*0Sstevel@tonic-gate 				send_wont(option, 0);
560*0Sstevel@tonic-gate 			}
561*0Sstevel@tonic-gate 		} else {
562*0Sstevel@tonic-gate 			/*
563*0Sstevel@tonic-gate 			 * Handle options that need more things done after the
564*0Sstevel@tonic-gate 			 * other side has acknowledged the option.
565*0Sstevel@tonic-gate 			 */
566*0Sstevel@tonic-gate 			switch (option) {
567*0Sstevel@tonic-gate 			case TELOPT_LINEMODE:
568*0Sstevel@tonic-gate #ifdef	KLUDGELINEMODE
569*0Sstevel@tonic-gate 				kludgelinemode = 0;
570*0Sstevel@tonic-gate 				send_do(TELOPT_SGA, 1);
571*0Sstevel@tonic-gate #endif
572*0Sstevel@tonic-gate 				set_my_state_will(option);
573*0Sstevel@tonic-gate 				slc_init();
574*0Sstevel@tonic-gate 				send_do(TELOPT_SGA, 0);
575*0Sstevel@tonic-gate 				return;
576*0Sstevel@tonic-gate 			}
577*0Sstevel@tonic-gate 		}
578*0Sstevel@tonic-gate 	}
579*0Sstevel@tonic-gate 	set_my_state_will(option);
580*0Sstevel@tonic-gate }
581*0Sstevel@tonic-gate 
582*0Sstevel@tonic-gate 	static void
dontoption(option)583*0Sstevel@tonic-gate dontoption(option)
584*0Sstevel@tonic-gate 	int option;
585*0Sstevel@tonic-gate {
586*0Sstevel@tonic-gate 
587*0Sstevel@tonic-gate 	if (will_wont_resp[option]) {
588*0Sstevel@tonic-gate 	    --will_wont_resp[option];
589*0Sstevel@tonic-gate 	    if (will_wont_resp[option] && my_state_is_wont(option))
590*0Sstevel@tonic-gate 		--will_wont_resp[option];
591*0Sstevel@tonic-gate 	}
592*0Sstevel@tonic-gate 
593*0Sstevel@tonic-gate 	if ((will_wont_resp[option] == 0) && my_want_state_is_will(option)) {
594*0Sstevel@tonic-gate 	    switch (option) {
595*0Sstevel@tonic-gate 	    case TELOPT_LINEMODE:
596*0Sstevel@tonic-gate 		linemode = 0;	/* put us back to the default state */
597*0Sstevel@tonic-gate 		break;
598*0Sstevel@tonic-gate #ifdef	OLD_ENVIRON
599*0Sstevel@tonic-gate 	    case TELOPT_NEW_ENVIRON:
600*0Sstevel@tonic-gate 		/*
601*0Sstevel@tonic-gate 		 * The new environ option wasn't recognized, try
602*0Sstevel@tonic-gate 		 * the old one.
603*0Sstevel@tonic-gate 		 */
604*0Sstevel@tonic-gate 		send_will(TELOPT_OLD_ENVIRON, 1);
605*0Sstevel@tonic-gate 		telopt_environ = TELOPT_OLD_ENVIRON;
606*0Sstevel@tonic-gate 		break;
607*0Sstevel@tonic-gate #endif
608*0Sstevel@tonic-gate 	    }
609*0Sstevel@tonic-gate 	    /* we always accept a DONT */
610*0Sstevel@tonic-gate 	    set_my_want_state_wont(option);
611*0Sstevel@tonic-gate 	    if (my_state_is_will(option))
612*0Sstevel@tonic-gate 		send_wont(option, 0);
613*0Sstevel@tonic-gate 	    setconnmode(0);			/* Set new tty mode */
614*0Sstevel@tonic-gate 	}
615*0Sstevel@tonic-gate 	set_my_state_wont(option);
616*0Sstevel@tonic-gate }
617*0Sstevel@tonic-gate 
618*0Sstevel@tonic-gate /*
619*0Sstevel@tonic-gate  * Given a buffer returned by tgetent(), this routine will turn
620*0Sstevel@tonic-gate  * the pipe seperated list of names in the buffer into an array
621*0Sstevel@tonic-gate  * of pointers to null terminated names.  We toss out any bad,
622*0Sstevel@tonic-gate  * duplicate, or verbose names (names with spaces).
623*0Sstevel@tonic-gate  */
624*0Sstevel@tonic-gate 
625*0Sstevel@tonic-gate static char *name_unknown = "UNKNOWN";
626*0Sstevel@tonic-gate static char *unknown[] = { 0, 0 };
627*0Sstevel@tonic-gate 
628*0Sstevel@tonic-gate static char **
mklist(buf,name)629*0Sstevel@tonic-gate mklist(buf, name)
630*0Sstevel@tonic-gate 	char *buf, *name;
631*0Sstevel@tonic-gate {
632*0Sstevel@tonic-gate 	register int n;
633*0Sstevel@tonic-gate 	register char c, *cp, **argvp, *cp2, **argv, **avt;
634*0Sstevel@tonic-gate 
635*0Sstevel@tonic-gate 	if (name) {
636*0Sstevel@tonic-gate 		if (strlen(name) > 40u) {
637*0Sstevel@tonic-gate 			name = 0;
638*0Sstevel@tonic-gate 			unknown[0] = name_unknown;
639*0Sstevel@tonic-gate 		} else {
640*0Sstevel@tonic-gate 			unknown[0] = name;
641*0Sstevel@tonic-gate 			upcase(name);
642*0Sstevel@tonic-gate 		}
643*0Sstevel@tonic-gate 	} else
644*0Sstevel@tonic-gate 		unknown[0] = name_unknown;
645*0Sstevel@tonic-gate 	/*
646*0Sstevel@tonic-gate 	 * Count up the number of names.
647*0Sstevel@tonic-gate 	 */
648*0Sstevel@tonic-gate 	for (n = 1, cp = buf; *cp && *cp != ':'; cp++) {
649*0Sstevel@tonic-gate 		if (*cp == '|')
650*0Sstevel@tonic-gate 			n++;
651*0Sstevel@tonic-gate 	}
652*0Sstevel@tonic-gate 	/*
653*0Sstevel@tonic-gate 	 * Allocate an array to put the name pointers into
654*0Sstevel@tonic-gate 	 */
655*0Sstevel@tonic-gate 	argv = malloc((n+3)*sizeof (char *));
656*0Sstevel@tonic-gate 	if (argv == 0)
657*0Sstevel@tonic-gate 		return (unknown);
658*0Sstevel@tonic-gate 
659*0Sstevel@tonic-gate 	/*
660*0Sstevel@tonic-gate 	 * Fill up the array of pointers to names.
661*0Sstevel@tonic-gate 	 */
662*0Sstevel@tonic-gate 	*argv = 0;
663*0Sstevel@tonic-gate 	argvp = argv+1;
664*0Sstevel@tonic-gate 	n = 0;
665*0Sstevel@tonic-gate 	for (cp = cp2 = buf; (c = *cp) != NULL;  cp++) {
666*0Sstevel@tonic-gate 		if (c == '|' || c == ':') {
667*0Sstevel@tonic-gate 			*cp++ = '\0';
668*0Sstevel@tonic-gate 			/*
669*0Sstevel@tonic-gate 			 * Skip entries that have spaces or are over 40
670*0Sstevel@tonic-gate 			 * characters long.  If this is our environment
671*0Sstevel@tonic-gate 			 * name, then put it up front.  Otherwise, as
672*0Sstevel@tonic-gate 			 * long as this is not a duplicate name (case
673*0Sstevel@tonic-gate 			 * insensitive) add it to the list.
674*0Sstevel@tonic-gate 			 */
675*0Sstevel@tonic-gate 			if (n || (cp - cp2 > 41))
676*0Sstevel@tonic-gate 				/* EMPTY */;
677*0Sstevel@tonic-gate 			else if (name && (strncasecmp(name, cp2, cp-cp2) == 0))
678*0Sstevel@tonic-gate 				*argv = cp2;
679*0Sstevel@tonic-gate 			else if (is_unique(cp2, argv+1, argvp))
680*0Sstevel@tonic-gate 				*argvp++ = cp2;
681*0Sstevel@tonic-gate 			if (c == ':')
682*0Sstevel@tonic-gate 				break;
683*0Sstevel@tonic-gate 			/*
684*0Sstevel@tonic-gate 			 * Skip multiple delimiters. Reset cp2 to
685*0Sstevel@tonic-gate 			 * the beginning of the next name. Reset n,
686*0Sstevel@tonic-gate 			 * the flag for names with spaces.
687*0Sstevel@tonic-gate 			 */
688*0Sstevel@tonic-gate 			while ((c = *cp) == '|')
689*0Sstevel@tonic-gate 				cp++;
690*0Sstevel@tonic-gate 			cp2 = cp;
691*0Sstevel@tonic-gate 			n = 0;
692*0Sstevel@tonic-gate 		}
693*0Sstevel@tonic-gate 		/*
694*0Sstevel@tonic-gate 		 * Skip entries with spaces or non-ascii values.
695*0Sstevel@tonic-gate 		 * Convert lower case letters to upper case.
696*0Sstevel@tonic-gate 		 */
697*0Sstevel@tonic-gate 		if ((c == ' ') || !isascii(c))
698*0Sstevel@tonic-gate 			n = 1;
699*0Sstevel@tonic-gate 		else if (islower(c))
700*0Sstevel@tonic-gate 			*cp = toupper(c);
701*0Sstevel@tonic-gate 	}
702*0Sstevel@tonic-gate 
703*0Sstevel@tonic-gate 	/*
704*0Sstevel@tonic-gate 	 * Check for an old V6 2 character name.  If the second
705*0Sstevel@tonic-gate 	 * name points to the beginning of the buffer, and is
706*0Sstevel@tonic-gate 	 * only 2 characters long, move it to the end of the array.
707*0Sstevel@tonic-gate 	 */
708*0Sstevel@tonic-gate 	if ((argv[1] == buf) && (strlen(argv[1]) == 2)) {
709*0Sstevel@tonic-gate 		--argvp;
710*0Sstevel@tonic-gate 		for (avt = &argv[1]; avt < argvp; avt++)
711*0Sstevel@tonic-gate 			*avt = *(avt+1);
712*0Sstevel@tonic-gate 		*argvp++ = buf;
713*0Sstevel@tonic-gate 	}
714*0Sstevel@tonic-gate 
715*0Sstevel@tonic-gate 	/*
716*0Sstevel@tonic-gate 	 * Duplicate last name, for TTYPE option, and null
717*0Sstevel@tonic-gate 	 * terminate the array.  If we didn't find a match on
718*0Sstevel@tonic-gate 	 * our terminal name, put that name at the beginning.
719*0Sstevel@tonic-gate 	 */
720*0Sstevel@tonic-gate 	cp = *(argvp-1);
721*0Sstevel@tonic-gate 	*argvp++ = cp;
722*0Sstevel@tonic-gate 	*argvp = 0;
723*0Sstevel@tonic-gate 
724*0Sstevel@tonic-gate 	if (*argv == 0) {
725*0Sstevel@tonic-gate 		if (name)
726*0Sstevel@tonic-gate 			*argv = name;
727*0Sstevel@tonic-gate 		else {
728*0Sstevel@tonic-gate 			--argvp;
729*0Sstevel@tonic-gate 			for (avt = argv; avt < argvp; avt++)
730*0Sstevel@tonic-gate 				*avt = *(avt+1);
731*0Sstevel@tonic-gate 		}
732*0Sstevel@tonic-gate 	}
733*0Sstevel@tonic-gate 	if (*argv)
734*0Sstevel@tonic-gate 		return (argv);
735*0Sstevel@tonic-gate 	else
736*0Sstevel@tonic-gate 		return (unknown);
737*0Sstevel@tonic-gate }
738*0Sstevel@tonic-gate 
739*0Sstevel@tonic-gate static int
is_unique(name,as,ae)740*0Sstevel@tonic-gate is_unique(name, as, ae)
741*0Sstevel@tonic-gate 	register char *name, **as, **ae;
742*0Sstevel@tonic-gate {
743*0Sstevel@tonic-gate 	register char **ap;
744*0Sstevel@tonic-gate 	register int n;
745*0Sstevel@tonic-gate 
746*0Sstevel@tonic-gate 	n = strlen(name) + 1;
747*0Sstevel@tonic-gate 	for (ap = as; ap < ae; ap++)
748*0Sstevel@tonic-gate 		if (strncasecmp(*ap, name, n) == 0)
749*0Sstevel@tonic-gate 			return (0);
750*0Sstevel@tonic-gate 	return (1);
751*0Sstevel@tonic-gate }
752*0Sstevel@tonic-gate 
753*0Sstevel@tonic-gate #define	termbuf	ttytype
754*0Sstevel@tonic-gate extern char ttytype[];
755*0Sstevel@tonic-gate 
756*0Sstevel@tonic-gate int resettermname = 1;
757*0Sstevel@tonic-gate 
758*0Sstevel@tonic-gate static char *
gettermname(void)759*0Sstevel@tonic-gate gettermname(void)
760*0Sstevel@tonic-gate {
761*0Sstevel@tonic-gate 	char *tname;
762*0Sstevel@tonic-gate 	static char **tnamep = 0;
763*0Sstevel@tonic-gate 	static char **next;
764*0Sstevel@tonic-gate 	int err;
765*0Sstevel@tonic-gate 
766*0Sstevel@tonic-gate 	if (resettermname) {
767*0Sstevel@tonic-gate 		resettermname = 0;
768*0Sstevel@tonic-gate 		if (tnamep && tnamep != unknown)
769*0Sstevel@tonic-gate 			free(tnamep);
770*0Sstevel@tonic-gate 		tname = (char *)env_getvalue((unsigned char *)"TERM");
771*0Sstevel@tonic-gate 		if ((tname != NULL) && (setupterm(tname, 1, &err) == 0)) {
772*0Sstevel@tonic-gate 			tnamep = mklist(termbuf, tname);
773*0Sstevel@tonic-gate 		} else {
774*0Sstevel@tonic-gate 			if (tname && (strlen(tname) <= 40u)) {
775*0Sstevel@tonic-gate 				unknown[0] = tname;
776*0Sstevel@tonic-gate 				upcase(tname);
777*0Sstevel@tonic-gate 			} else
778*0Sstevel@tonic-gate 				unknown[0] = name_unknown;
779*0Sstevel@tonic-gate 			tnamep = unknown;
780*0Sstevel@tonic-gate 		}
781*0Sstevel@tonic-gate 		next = tnamep;
782*0Sstevel@tonic-gate 	}
783*0Sstevel@tonic-gate 	if (*next == 0)
784*0Sstevel@tonic-gate 		next = tnamep;
785*0Sstevel@tonic-gate 	return (*next++);
786*0Sstevel@tonic-gate }
787*0Sstevel@tonic-gate /*
788*0Sstevel@tonic-gate  * suboption()
789*0Sstevel@tonic-gate  *
790*0Sstevel@tonic-gate  *	Look at the sub-option buffer, and try to be helpful to the other
791*0Sstevel@tonic-gate  * side.
792*0Sstevel@tonic-gate  *
793*0Sstevel@tonic-gate  *	Currently we recognize:
794*0Sstevel@tonic-gate  *
795*0Sstevel@tonic-gate  *		Terminal type, send request.
796*0Sstevel@tonic-gate  *		Terminal speed (send request).
797*0Sstevel@tonic-gate  *		Local flow control (is request).
798*0Sstevel@tonic-gate  *		Linemode
799*0Sstevel@tonic-gate  */
800*0Sstevel@tonic-gate 
801*0Sstevel@tonic-gate     static void
suboption()802*0Sstevel@tonic-gate suboption()
803*0Sstevel@tonic-gate {
804*0Sstevel@tonic-gate 	unsigned char subchar;
805*0Sstevel@tonic-gate 
806*0Sstevel@tonic-gate 	printsub('<', subbuffer, SB_LEN()+2);
807*0Sstevel@tonic-gate 	switch (subchar = SB_GET()) {
808*0Sstevel@tonic-gate 	case TELOPT_TTYPE:
809*0Sstevel@tonic-gate 		if (my_want_state_is_wont(TELOPT_TTYPE))
810*0Sstevel@tonic-gate 			return;
811*0Sstevel@tonic-gate 		if (SB_EOF() || SB_GET() != TELQUAL_SEND) {
812*0Sstevel@tonic-gate 			return;
813*0Sstevel@tonic-gate 		} else {
814*0Sstevel@tonic-gate 			char *name;
815*0Sstevel@tonic-gate 			unsigned char temp[50];
816*0Sstevel@tonic-gate 			int len, bytes;
817*0Sstevel@tonic-gate 
818*0Sstevel@tonic-gate 			name = gettermname();
819*0Sstevel@tonic-gate 			len = strlen(name) + 4 + 2;
820*0Sstevel@tonic-gate 			bytes = snprintf((char *)temp, sizeof (temp),
821*0Sstevel@tonic-gate 				"%c%c%c%c%s%c%c", IAC, SB,
822*0Sstevel@tonic-gate 				TELOPT_TTYPE, TELQUAL_IS, name, IAC, SE);
823*0Sstevel@tonic-gate 			if ((len < NETROOM()) && (bytes < sizeof (temp))) {
824*0Sstevel@tonic-gate 					ring_supply_data(&netoring, temp, len);
825*0Sstevel@tonic-gate 					printsub('>', &temp[2], len-2);
826*0Sstevel@tonic-gate 			} else {
827*0Sstevel@tonic-gate 				ExitString("No room in buffer for "
828*0Sstevel@tonic-gate 				    "terminal type.\n", EXIT_FAILURE);
829*0Sstevel@tonic-gate 				/*NOTREACHED*/
830*0Sstevel@tonic-gate 			}
831*0Sstevel@tonic-gate 		}
832*0Sstevel@tonic-gate 		break;
833*0Sstevel@tonic-gate 	case TELOPT_TSPEED:
834*0Sstevel@tonic-gate 		if (my_want_state_is_wont(TELOPT_TSPEED))
835*0Sstevel@tonic-gate 			return;
836*0Sstevel@tonic-gate 		if (SB_EOF())
837*0Sstevel@tonic-gate 			return;
838*0Sstevel@tonic-gate 		if (SB_GET() == TELQUAL_SEND) {
839*0Sstevel@tonic-gate 			int ospeed, ispeed;
840*0Sstevel@tonic-gate 			unsigned char temp[50];
841*0Sstevel@tonic-gate 			int len, bytes;
842*0Sstevel@tonic-gate 
843*0Sstevel@tonic-gate 			TerminalSpeeds(&ispeed, &ospeed);
844*0Sstevel@tonic-gate 
845*0Sstevel@tonic-gate 			bytes = snprintf((char *)temp, sizeof (temp),
846*0Sstevel@tonic-gate 			    "%c%c%c%c%d,%d%c%c", IAC, SB,
847*0Sstevel@tonic-gate 			    TELOPT_TSPEED, TELQUAL_IS, ospeed, ispeed, IAC, SE);
848*0Sstevel@tonic-gate 			len = strlen((char *)temp+4) + 4; /* temp[3] is 0 ... */
849*0Sstevel@tonic-gate 
850*0Sstevel@tonic-gate 			if ((len < NETROOM()) && (bytes < sizeof (temp))) {
851*0Sstevel@tonic-gate 				ring_supply_data(&netoring, temp, len);
852*0Sstevel@tonic-gate 				printsub('>', temp+2, len - 2);
853*0Sstevel@tonic-gate 			}
854*0Sstevel@tonic-gate 			else
855*0Sstevel@tonic-gate 				(void) printf(
856*0Sstevel@tonic-gate 				    "telnet: not enough room in buffer "
857*0Sstevel@tonic-gate 				    "for terminal speed option reply\n");
858*0Sstevel@tonic-gate 		}
859*0Sstevel@tonic-gate 		break;
860*0Sstevel@tonic-gate 	case TELOPT_LFLOW:
861*0Sstevel@tonic-gate 		if (my_want_state_is_wont(TELOPT_LFLOW))
862*0Sstevel@tonic-gate 			return;
863*0Sstevel@tonic-gate 		if (SB_EOF())
864*0Sstevel@tonic-gate 			return;
865*0Sstevel@tonic-gate 		switch (SB_GET()) {
866*0Sstevel@tonic-gate 		case LFLOW_RESTART_ANY:
867*0Sstevel@tonic-gate 			restartany = 1;
868*0Sstevel@tonic-gate 			break;
869*0Sstevel@tonic-gate 		case LFLOW_RESTART_XON:
870*0Sstevel@tonic-gate 			restartany = 0;
871*0Sstevel@tonic-gate 			break;
872*0Sstevel@tonic-gate 		case LFLOW_ON:
873*0Sstevel@tonic-gate 			localflow = 1;
874*0Sstevel@tonic-gate 			break;
875*0Sstevel@tonic-gate 		case LFLOW_OFF:
876*0Sstevel@tonic-gate 			localflow = 0;
877*0Sstevel@tonic-gate 			break;
878*0Sstevel@tonic-gate 		default:
879*0Sstevel@tonic-gate 			return;
880*0Sstevel@tonic-gate 		}
881*0Sstevel@tonic-gate 		setcommandmode();
882*0Sstevel@tonic-gate 		setconnmode(0);
883*0Sstevel@tonic-gate 		break;
884*0Sstevel@tonic-gate 
885*0Sstevel@tonic-gate 	case TELOPT_LINEMODE:
886*0Sstevel@tonic-gate 		if (my_want_state_is_wont(TELOPT_LINEMODE))
887*0Sstevel@tonic-gate 			return;
888*0Sstevel@tonic-gate 		if (SB_EOF())
889*0Sstevel@tonic-gate 			return;
890*0Sstevel@tonic-gate 		switch (SB_GET()) {
891*0Sstevel@tonic-gate 		case WILL:
892*0Sstevel@tonic-gate 			lm_will(subpointer, SB_LEN());
893*0Sstevel@tonic-gate 			break;
894*0Sstevel@tonic-gate 		case WONT:
895*0Sstevel@tonic-gate 			lm_wont(subpointer, SB_LEN());
896*0Sstevel@tonic-gate 			break;
897*0Sstevel@tonic-gate 		case DO:
898*0Sstevel@tonic-gate 			lm_do(subpointer, SB_LEN());
899*0Sstevel@tonic-gate 			break;
900*0Sstevel@tonic-gate 		case DONT:
901*0Sstevel@tonic-gate 			lm_dont(subpointer, SB_LEN());
902*0Sstevel@tonic-gate 			break;
903*0Sstevel@tonic-gate 		case LM_SLC:
904*0Sstevel@tonic-gate 			slc(subpointer, SB_LEN());
905*0Sstevel@tonic-gate 			break;
906*0Sstevel@tonic-gate 		case LM_MODE:
907*0Sstevel@tonic-gate 			lm_mode(subpointer, SB_LEN(), 0);
908*0Sstevel@tonic-gate 			break;
909*0Sstevel@tonic-gate 		default:
910*0Sstevel@tonic-gate 			break;
911*0Sstevel@tonic-gate 		}
912*0Sstevel@tonic-gate 		break;
913*0Sstevel@tonic-gate 
914*0Sstevel@tonic-gate #ifdef	OLD_ENVIRON
915*0Sstevel@tonic-gate 	case TELOPT_OLD_ENVIRON:
916*0Sstevel@tonic-gate #endif
917*0Sstevel@tonic-gate 	case TELOPT_NEW_ENVIRON:
918*0Sstevel@tonic-gate 		if (SB_EOF())
919*0Sstevel@tonic-gate 			return;
920*0Sstevel@tonic-gate 		switch (SB_PEEK()) {
921*0Sstevel@tonic-gate 		case TELQUAL_IS:
922*0Sstevel@tonic-gate 		case TELQUAL_INFO:
923*0Sstevel@tonic-gate 			if (my_want_state_is_dont(subchar))
924*0Sstevel@tonic-gate 				return;
925*0Sstevel@tonic-gate 			break;
926*0Sstevel@tonic-gate 		case TELQUAL_SEND:
927*0Sstevel@tonic-gate 			if (my_want_state_is_wont(subchar)) {
928*0Sstevel@tonic-gate 				return;
929*0Sstevel@tonic-gate 			}
930*0Sstevel@tonic-gate 			break;
931*0Sstevel@tonic-gate 		default:
932*0Sstevel@tonic-gate 			return;
933*0Sstevel@tonic-gate 		}
934*0Sstevel@tonic-gate 		env_opt(subpointer, SB_LEN());
935*0Sstevel@tonic-gate 		break;
936*0Sstevel@tonic-gate 
937*0Sstevel@tonic-gate 	case TELOPT_XDISPLOC:
938*0Sstevel@tonic-gate 		if (my_want_state_is_wont(TELOPT_XDISPLOC))
939*0Sstevel@tonic-gate 			return;
940*0Sstevel@tonic-gate 		if (SB_EOF())
941*0Sstevel@tonic-gate 			return;
942*0Sstevel@tonic-gate 		if (SB_GET() == TELQUAL_SEND) {
943*0Sstevel@tonic-gate 			unsigned char temp[50], *dp;
944*0Sstevel@tonic-gate 			int len, bytes;
945*0Sstevel@tonic-gate 
946*0Sstevel@tonic-gate 			if ((dp = env_getvalue((unsigned char *)"DISPLAY")) ==
947*0Sstevel@tonic-gate 			    NULL) {
948*0Sstevel@tonic-gate 				/*
949*0Sstevel@tonic-gate 				 * Something happened, we no longer have a
950*0Sstevel@tonic-gate 				 * DISPLAY variable.  So, turn off the option.
951*0Sstevel@tonic-gate 				 */
952*0Sstevel@tonic-gate 				send_wont(TELOPT_XDISPLOC, 1);
953*0Sstevel@tonic-gate 				break;
954*0Sstevel@tonic-gate 			}
955*0Sstevel@tonic-gate 			bytes = snprintf((char *)temp, sizeof (temp),
956*0Sstevel@tonic-gate 			    "%c%c%c%c%s%c%c", IAC, SB,
957*0Sstevel@tonic-gate 			    TELOPT_XDISPLOC, TELQUAL_IS, dp, IAC, SE);
958*0Sstevel@tonic-gate 			len = strlen((char *)temp+4) + 4; /* temp[3] is 0 ... */
959*0Sstevel@tonic-gate 
960*0Sstevel@tonic-gate 			if ((len < NETROOM()) && (bytes < sizeof (temp))) {
961*0Sstevel@tonic-gate 				ring_supply_data(&netoring, temp, len);
962*0Sstevel@tonic-gate 				printsub('>', temp+2, len - 2);
963*0Sstevel@tonic-gate 			}
964*0Sstevel@tonic-gate 			else
965*0Sstevel@tonic-gate 				(void) printf(
966*0Sstevel@tonic-gate 				    "telnet: not enough room in buffer"
967*0Sstevel@tonic-gate 				    " for display location option reply\n");
968*0Sstevel@tonic-gate 		}
969*0Sstevel@tonic-gate 		break;
970*0Sstevel@tonic-gate 
971*0Sstevel@tonic-gate 	case TELOPT_AUTHENTICATION: {
972*0Sstevel@tonic-gate 		if (!autologin)
973*0Sstevel@tonic-gate 			break;
974*0Sstevel@tonic-gate 		if (SB_EOF())
975*0Sstevel@tonic-gate 			return;
976*0Sstevel@tonic-gate 		switch (SB_GET()) {
977*0Sstevel@tonic-gate 		case TELQUAL_SEND:
978*0Sstevel@tonic-gate 			if (my_want_state_is_wont(TELOPT_AUTHENTICATION))
979*0Sstevel@tonic-gate 				return;
980*0Sstevel@tonic-gate 			auth_send(subpointer, SB_LEN());
981*0Sstevel@tonic-gate 			break;
982*0Sstevel@tonic-gate 		case TELQUAL_REPLY:
983*0Sstevel@tonic-gate 			if (my_want_state_is_wont(TELOPT_AUTHENTICATION))
984*0Sstevel@tonic-gate 				return;
985*0Sstevel@tonic-gate 			auth_reply(subpointer, SB_LEN());
986*0Sstevel@tonic-gate 			break;
987*0Sstevel@tonic-gate 		}
988*0Sstevel@tonic-gate 	}
989*0Sstevel@tonic-gate 	break;
990*0Sstevel@tonic-gate 
991*0Sstevel@tonic-gate 	case TELOPT_ENCRYPT:
992*0Sstevel@tonic-gate 		if (SB_EOF())
993*0Sstevel@tonic-gate 			return;
994*0Sstevel@tonic-gate 		switch (SB_GET()) {
995*0Sstevel@tonic-gate 		case ENCRYPT_START:
996*0Sstevel@tonic-gate 			if (my_want_state_is_dont(TELOPT_ENCRYPT))
997*0Sstevel@tonic-gate 				return;
998*0Sstevel@tonic-gate 			encrypt_start(subpointer, SB_LEN());
999*0Sstevel@tonic-gate 			break;
1000*0Sstevel@tonic-gate 		case ENCRYPT_END:
1001*0Sstevel@tonic-gate 			if (my_want_state_is_dont(TELOPT_ENCRYPT))
1002*0Sstevel@tonic-gate 				return;
1003*0Sstevel@tonic-gate 			encrypt_end();
1004*0Sstevel@tonic-gate 			break;
1005*0Sstevel@tonic-gate 		case ENCRYPT_SUPPORT:
1006*0Sstevel@tonic-gate 			if (my_want_state_is_wont(TELOPT_ENCRYPT))
1007*0Sstevel@tonic-gate 				return;
1008*0Sstevel@tonic-gate 			encrypt_support(subpointer, SB_LEN());
1009*0Sstevel@tonic-gate 			break;
1010*0Sstevel@tonic-gate 		case ENCRYPT_REQSTART:
1011*0Sstevel@tonic-gate 			if (my_want_state_is_wont(TELOPT_ENCRYPT))
1012*0Sstevel@tonic-gate 				return;
1013*0Sstevel@tonic-gate 			encrypt_request_start(subpointer, SB_LEN());
1014*0Sstevel@tonic-gate 			break;
1015*0Sstevel@tonic-gate 		case ENCRYPT_REQEND:
1016*0Sstevel@tonic-gate 			if (my_want_state_is_wont(TELOPT_ENCRYPT))
1017*0Sstevel@tonic-gate 				return;
1018*0Sstevel@tonic-gate 			/*
1019*0Sstevel@tonic-gate 			 * We can always send an REQEND so that we cannot
1020*0Sstevel@tonic-gate 			 * get stuck encrypting.  We should only get this
1021*0Sstevel@tonic-gate 			 * if we have been able to get in the correct mode
1022*0Sstevel@tonic-gate 			 * anyhow.
1023*0Sstevel@tonic-gate 			 */
1024*0Sstevel@tonic-gate 			encrypt_request_end();
1025*0Sstevel@tonic-gate 			break;
1026*0Sstevel@tonic-gate 		case ENCRYPT_IS:
1027*0Sstevel@tonic-gate 			if (my_want_state_is_dont(TELOPT_ENCRYPT))
1028*0Sstevel@tonic-gate 				return;
1029*0Sstevel@tonic-gate 			encrypt_is(subpointer, SB_LEN());
1030*0Sstevel@tonic-gate 			break;
1031*0Sstevel@tonic-gate 		case ENCRYPT_REPLY:
1032*0Sstevel@tonic-gate 			if (my_want_state_is_wont(TELOPT_ENCRYPT))
1033*0Sstevel@tonic-gate 				return;
1034*0Sstevel@tonic-gate 			encrypt_reply(subpointer, SB_LEN());
1035*0Sstevel@tonic-gate 			break;
1036*0Sstevel@tonic-gate 		case ENCRYPT_ENC_KEYID:
1037*0Sstevel@tonic-gate 			if (my_want_state_is_dont(TELOPT_ENCRYPT))
1038*0Sstevel@tonic-gate 				return;
1039*0Sstevel@tonic-gate 			encrypt_enc_keyid(subpointer, SB_LEN());
1040*0Sstevel@tonic-gate 			break;
1041*0Sstevel@tonic-gate 		case ENCRYPT_DEC_KEYID:
1042*0Sstevel@tonic-gate 			if (my_want_state_is_wont(TELOPT_ENCRYPT))
1043*0Sstevel@tonic-gate 				return;
1044*0Sstevel@tonic-gate 			encrypt_dec_keyid(subpointer, SB_LEN());
1045*0Sstevel@tonic-gate 			break;
1046*0Sstevel@tonic-gate 		default:
1047*0Sstevel@tonic-gate 			break;
1048*0Sstevel@tonic-gate 		}
1049*0Sstevel@tonic-gate 		break;
1050*0Sstevel@tonic-gate 	default:
1051*0Sstevel@tonic-gate 		break;
1052*0Sstevel@tonic-gate 	}
1053*0Sstevel@tonic-gate }
1054*0Sstevel@tonic-gate 
1055*0Sstevel@tonic-gate static unsigned char str_lm[] = { IAC, SB, TELOPT_LINEMODE, 0, 0, IAC, SE };
1056*0Sstevel@tonic-gate 
1057*0Sstevel@tonic-gate static void
lm_will(cmd,len)1058*0Sstevel@tonic-gate lm_will(cmd, len)
1059*0Sstevel@tonic-gate 	unsigned char *cmd;
1060*0Sstevel@tonic-gate 	int len;
1061*0Sstevel@tonic-gate {
1062*0Sstevel@tonic-gate 	if (len < 1) {
1063*0Sstevel@tonic-gate 		/* Should not happen... */
1064*0Sstevel@tonic-gate 		(void) printf(
1065*0Sstevel@tonic-gate 		    "telnet: command missing from linemode WILL request\n");
1066*0Sstevel@tonic-gate 		return;
1067*0Sstevel@tonic-gate 	}
1068*0Sstevel@tonic-gate 	switch (cmd[0]) {
1069*0Sstevel@tonic-gate 	case LM_FORWARDMASK:	/* We shouldn't ever get this... */
1070*0Sstevel@tonic-gate 	default:
1071*0Sstevel@tonic-gate 		str_lm[3] = DONT;
1072*0Sstevel@tonic-gate 		str_lm[4] = cmd[0];
1073*0Sstevel@tonic-gate 		if (NETROOM() > sizeof (str_lm)) {
1074*0Sstevel@tonic-gate 			ring_supply_data(&netoring, str_lm, sizeof (str_lm));
1075*0Sstevel@tonic-gate 			printsub('>', &str_lm[2], sizeof (str_lm)-2);
1076*0Sstevel@tonic-gate 		}
1077*0Sstevel@tonic-gate 		else
1078*0Sstevel@tonic-gate 			(void) printf("telnet: not enough room in buffer for"
1079*0Sstevel@tonic-gate 			    "reply to linemode WILL request\n");
1080*0Sstevel@tonic-gate 		break;
1081*0Sstevel@tonic-gate 	}
1082*0Sstevel@tonic-gate }
1083*0Sstevel@tonic-gate 
1084*0Sstevel@tonic-gate static void
lm_wont(cmd,len)1085*0Sstevel@tonic-gate lm_wont(cmd, len)
1086*0Sstevel@tonic-gate 	unsigned char *cmd;
1087*0Sstevel@tonic-gate 	int len;
1088*0Sstevel@tonic-gate {
1089*0Sstevel@tonic-gate 	if (len < 1) {
1090*0Sstevel@tonic-gate 		/* Should not happen... */
1091*0Sstevel@tonic-gate 		(void) printf(
1092*0Sstevel@tonic-gate 		    "telnet: command missing from linemode WONT request\n");
1093*0Sstevel@tonic-gate 		return;
1094*0Sstevel@tonic-gate 	}
1095*0Sstevel@tonic-gate 	switch (cmd[0]) {
1096*0Sstevel@tonic-gate 	case LM_FORWARDMASK:	/* We shouldn't ever get this... */
1097*0Sstevel@tonic-gate 	default:
1098*0Sstevel@tonic-gate 		/* We are always DONT, so don't respond */
1099*0Sstevel@tonic-gate 		return;
1100*0Sstevel@tonic-gate 	}
1101*0Sstevel@tonic-gate }
1102*0Sstevel@tonic-gate 
1103*0Sstevel@tonic-gate static void
lm_do(cmd,len)1104*0Sstevel@tonic-gate lm_do(cmd, len)
1105*0Sstevel@tonic-gate 	unsigned char *cmd;
1106*0Sstevel@tonic-gate 	int len;
1107*0Sstevel@tonic-gate {
1108*0Sstevel@tonic-gate 	if (len < 1) {
1109*0Sstevel@tonic-gate 		/* Should not happen... */
1110*0Sstevel@tonic-gate 		(void) printf(
1111*0Sstevel@tonic-gate 		    "telnet: command missing from linemode DO request\n");
1112*0Sstevel@tonic-gate 		return;
1113*0Sstevel@tonic-gate 	}
1114*0Sstevel@tonic-gate 	switch (cmd[0]) {
1115*0Sstevel@tonic-gate 	case LM_FORWARDMASK:
1116*0Sstevel@tonic-gate 	default:
1117*0Sstevel@tonic-gate 		str_lm[3] = WONT;
1118*0Sstevel@tonic-gate 		str_lm[4] = cmd[0];
1119*0Sstevel@tonic-gate 		if (NETROOM() > sizeof (str_lm)) {
1120*0Sstevel@tonic-gate 			ring_supply_data(&netoring, str_lm, sizeof (str_lm));
1121*0Sstevel@tonic-gate 			printsub('>', &str_lm[2], sizeof (str_lm)-2);
1122*0Sstevel@tonic-gate 		}
1123*0Sstevel@tonic-gate 		else
1124*0Sstevel@tonic-gate 			(void) printf("telnet: not enough room in buffer for"
1125*0Sstevel@tonic-gate 			    "reply to linemode DO request\n");
1126*0Sstevel@tonic-gate 		break;
1127*0Sstevel@tonic-gate 	}
1128*0Sstevel@tonic-gate }
1129*0Sstevel@tonic-gate 
1130*0Sstevel@tonic-gate static void
lm_dont(cmd,len)1131*0Sstevel@tonic-gate lm_dont(cmd, len)
1132*0Sstevel@tonic-gate 	unsigned char *cmd;
1133*0Sstevel@tonic-gate 	int len;
1134*0Sstevel@tonic-gate {
1135*0Sstevel@tonic-gate 	if (len < 1) {
1136*0Sstevel@tonic-gate 		/* Should not happen... */
1137*0Sstevel@tonic-gate 		(void) printf(
1138*0Sstevel@tonic-gate 		    "telnet: command missing from linemode DONT request\n");
1139*0Sstevel@tonic-gate 		return;
1140*0Sstevel@tonic-gate 	}
1141*0Sstevel@tonic-gate 	switch (cmd[0]) {
1142*0Sstevel@tonic-gate 	case LM_FORWARDMASK:
1143*0Sstevel@tonic-gate 	default:
1144*0Sstevel@tonic-gate 		/* we are always WONT, so don't respond */
1145*0Sstevel@tonic-gate 		break;
1146*0Sstevel@tonic-gate 	}
1147*0Sstevel@tonic-gate }
1148*0Sstevel@tonic-gate 
1149*0Sstevel@tonic-gate static unsigned char str_lm_mode[] = {
1150*0Sstevel@tonic-gate 	IAC, SB, TELOPT_LINEMODE, LM_MODE, 0, IAC, SE
1151*0Sstevel@tonic-gate };
1152*0Sstevel@tonic-gate 
1153*0Sstevel@tonic-gate 	void
lm_mode(cmd,len,init)1154*0Sstevel@tonic-gate lm_mode(cmd, len, init)
1155*0Sstevel@tonic-gate 	unsigned char *cmd;
1156*0Sstevel@tonic-gate 	int len, init;
1157*0Sstevel@tonic-gate {
1158*0Sstevel@tonic-gate 	if (len != 1)
1159*0Sstevel@tonic-gate 		return;
1160*0Sstevel@tonic-gate 	if ((linemode&MODE_MASK&~MODE_ACK) == *cmd)
1161*0Sstevel@tonic-gate 		return;
1162*0Sstevel@tonic-gate 	linemode = *cmd&(MODE_MASK&~MODE_ACK);
1163*0Sstevel@tonic-gate 	str_lm_mode[4] = linemode;
1164*0Sstevel@tonic-gate 	if (!init)
1165*0Sstevel@tonic-gate 		str_lm_mode[4] |= MODE_ACK;
1166*0Sstevel@tonic-gate 	if (NETROOM() > sizeof (str_lm_mode)) {
1167*0Sstevel@tonic-gate 		ring_supply_data(&netoring, str_lm_mode, sizeof (str_lm_mode));
1168*0Sstevel@tonic-gate 		printsub('>', &str_lm_mode[2], sizeof (str_lm_mode)-2);
1169*0Sstevel@tonic-gate 	}
1170*0Sstevel@tonic-gate 	else
1171*0Sstevel@tonic-gate 		(void) printf("telnet: not enough room in buffer for"
1172*0Sstevel@tonic-gate 		    "reply to linemode request\n");
1173*0Sstevel@tonic-gate 	setconnmode(0);	/* set changed mode */
1174*0Sstevel@tonic-gate }
1175*0Sstevel@tonic-gate 
1176*0Sstevel@tonic-gate 
1177*0Sstevel@tonic-gate 
1178*0Sstevel@tonic-gate /*
1179*0Sstevel@tonic-gate  * slc()
1180*0Sstevel@tonic-gate  * Handle special character suboption of LINEMODE.
1181*0Sstevel@tonic-gate  */
1182*0Sstevel@tonic-gate 
1183*0Sstevel@tonic-gate static struct spc {
1184*0Sstevel@tonic-gate 	cc_t val;
1185*0Sstevel@tonic-gate 	cc_t *valp;
1186*0Sstevel@tonic-gate 	char flags;	/* Current flags & level */
1187*0Sstevel@tonic-gate 	char mylevel;	/* Maximum level & flags */
1188*0Sstevel@tonic-gate } spc_data[NSLC+1];
1189*0Sstevel@tonic-gate 
1190*0Sstevel@tonic-gate #define	SLC_IMPORT	0
1191*0Sstevel@tonic-gate #define	SLC_EXPORT	1
1192*0Sstevel@tonic-gate #define	SLC_RVALUE	2
1193*0Sstevel@tonic-gate static int slc_mode = SLC_EXPORT;
1194*0Sstevel@tonic-gate 
1195*0Sstevel@tonic-gate static void
slc_init()1196*0Sstevel@tonic-gate slc_init()
1197*0Sstevel@tonic-gate {
1198*0Sstevel@tonic-gate 	register struct spc *spcp;
1199*0Sstevel@tonic-gate 
1200*0Sstevel@tonic-gate 	localchars = 1;
1201*0Sstevel@tonic-gate 	for (spcp = spc_data; spcp < &spc_data[NSLC+1]; spcp++) {
1202*0Sstevel@tonic-gate 		spcp->val = 0;
1203*0Sstevel@tonic-gate 		spcp->valp = 0;
1204*0Sstevel@tonic-gate 		spcp->flags = spcp->mylevel = SLC_NOSUPPORT;
1205*0Sstevel@tonic-gate 	}
1206*0Sstevel@tonic-gate 
1207*0Sstevel@tonic-gate #define	initfunc(func, flags) { \
1208*0Sstevel@tonic-gate 				spcp = &spc_data[func]; \
1209*0Sstevel@tonic-gate 				if (spcp->valp = tcval(func)) { \
1210*0Sstevel@tonic-gate 				    spcp->val = *spcp->valp; \
1211*0Sstevel@tonic-gate 				    spcp->mylevel = SLC_VARIABLE|(flags);\
1212*0Sstevel@tonic-gate 				} else { \
1213*0Sstevel@tonic-gate 				    spcp->val = 0; \
1214*0Sstevel@tonic-gate 				    spcp->mylevel = SLC_DEFAULT; \
1215*0Sstevel@tonic-gate 				} \
1216*0Sstevel@tonic-gate 			    }
1217*0Sstevel@tonic-gate 
1218*0Sstevel@tonic-gate 	initfunc(SLC_SYNCH, 0);
1219*0Sstevel@tonic-gate 	/* No BRK */
1220*0Sstevel@tonic-gate 	initfunc(SLC_AO, 0);
1221*0Sstevel@tonic-gate 	initfunc(SLC_AYT, 0);
1222*0Sstevel@tonic-gate 	/* No EOR */
1223*0Sstevel@tonic-gate 	initfunc(SLC_ABORT, SLC_FLUSHIN|SLC_FLUSHOUT);
1224*0Sstevel@tonic-gate 	initfunc(SLC_EOF, 0);
1225*0Sstevel@tonic-gate 	initfunc(SLC_SUSP, SLC_FLUSHIN);
1226*0Sstevel@tonic-gate 	initfunc(SLC_EC, 0);
1227*0Sstevel@tonic-gate 	initfunc(SLC_EL, 0);
1228*0Sstevel@tonic-gate 	initfunc(SLC_EW, 0);
1229*0Sstevel@tonic-gate 	initfunc(SLC_RP, 0);
1230*0Sstevel@tonic-gate 	initfunc(SLC_LNEXT, 0);
1231*0Sstevel@tonic-gate 	initfunc(SLC_XON, 0);
1232*0Sstevel@tonic-gate 	initfunc(SLC_XOFF, 0);
1233*0Sstevel@tonic-gate 	initfunc(SLC_FORW1, 0);
1234*0Sstevel@tonic-gate #ifdef	USE_TERMIO
1235*0Sstevel@tonic-gate 	initfunc(SLC_FORW2, 0);
1236*0Sstevel@tonic-gate 	/* No FORW2 */
1237*0Sstevel@tonic-gate #endif
1238*0Sstevel@tonic-gate 
1239*0Sstevel@tonic-gate 	initfunc(SLC_IP, SLC_FLUSHIN|SLC_FLUSHOUT);
1240*0Sstevel@tonic-gate #undef	initfunc
1241*0Sstevel@tonic-gate 
1242*0Sstevel@tonic-gate 	if (slc_mode == SLC_EXPORT)
1243*0Sstevel@tonic-gate 		slc_export();
1244*0Sstevel@tonic-gate 	else
1245*0Sstevel@tonic-gate 		slc_import(1);
1246*0Sstevel@tonic-gate 
1247*0Sstevel@tonic-gate }
1248*0Sstevel@tonic-gate 
1249*0Sstevel@tonic-gate void
slcstate()1250*0Sstevel@tonic-gate slcstate()
1251*0Sstevel@tonic-gate {
1252*0Sstevel@tonic-gate 	(void) printf("Special characters are %s values\n",
1253*0Sstevel@tonic-gate 		slc_mode == SLC_IMPORT ? "remote default" :
1254*0Sstevel@tonic-gate 		slc_mode == SLC_EXPORT ? "local" :
1255*0Sstevel@tonic-gate 					"remote");
1256*0Sstevel@tonic-gate }
1257*0Sstevel@tonic-gate 
1258*0Sstevel@tonic-gate void
slc_mode_export()1259*0Sstevel@tonic-gate slc_mode_export()
1260*0Sstevel@tonic-gate {
1261*0Sstevel@tonic-gate 	slc_mode = SLC_EXPORT;
1262*0Sstevel@tonic-gate 	if (my_state_is_will(TELOPT_LINEMODE))
1263*0Sstevel@tonic-gate 		slc_export();
1264*0Sstevel@tonic-gate }
1265*0Sstevel@tonic-gate 
1266*0Sstevel@tonic-gate void
slc_mode_import(def)1267*0Sstevel@tonic-gate slc_mode_import(def)
1268*0Sstevel@tonic-gate     int def;
1269*0Sstevel@tonic-gate {
1270*0Sstevel@tonic-gate     slc_mode = def ? SLC_IMPORT : SLC_RVALUE;
1271*0Sstevel@tonic-gate     if (my_state_is_will(TELOPT_LINEMODE))
1272*0Sstevel@tonic-gate 	slc_import(def);
1273*0Sstevel@tonic-gate }
1274*0Sstevel@tonic-gate 
1275*0Sstevel@tonic-gate static unsigned char slc_import_val[] = {
1276*0Sstevel@tonic-gate 	IAC, SB, TELOPT_LINEMODE, LM_SLC, 0, SLC_VARIABLE, 0, IAC, SE
1277*0Sstevel@tonic-gate };
1278*0Sstevel@tonic-gate static unsigned char slc_import_def[] = {
1279*0Sstevel@tonic-gate 	IAC, SB, TELOPT_LINEMODE, LM_SLC, 0, SLC_DEFAULT, 0, IAC, SE
1280*0Sstevel@tonic-gate };
1281*0Sstevel@tonic-gate 
1282*0Sstevel@tonic-gate static void
slc_import(def)1283*0Sstevel@tonic-gate slc_import(def)
1284*0Sstevel@tonic-gate 	int def;
1285*0Sstevel@tonic-gate {
1286*0Sstevel@tonic-gate 	if (NETROOM() > sizeof (slc_import_val)) {
1287*0Sstevel@tonic-gate 		if (def) {
1288*0Sstevel@tonic-gate 			ring_supply_data(&netoring, slc_import_def,
1289*0Sstevel@tonic-gate 			    sizeof (slc_import_def));
1290*0Sstevel@tonic-gate 			printsub('>', &slc_import_def[2],
1291*0Sstevel@tonic-gate 			    sizeof (slc_import_def)-2);
1292*0Sstevel@tonic-gate 		} else {
1293*0Sstevel@tonic-gate 			ring_supply_data(&netoring, slc_import_val,
1294*0Sstevel@tonic-gate 			    sizeof (slc_import_val));
1295*0Sstevel@tonic-gate 			printsub('>', &slc_import_val[2],
1296*0Sstevel@tonic-gate 			    sizeof (slc_import_val)-2);
1297*0Sstevel@tonic-gate 		}
1298*0Sstevel@tonic-gate 	}
1299*0Sstevel@tonic-gate 	else
1300*0Sstevel@tonic-gate 		(void) printf(
1301*0Sstevel@tonic-gate 		    "telnet: not enough room in buffer for slc import"
1302*0Sstevel@tonic-gate 		    " request\n");
1303*0Sstevel@tonic-gate }
1304*0Sstevel@tonic-gate 
1305*0Sstevel@tonic-gate static uchar_t *slc_reply = NULL;
1306*0Sstevel@tonic-gate static uchar_t *slc_replyp = NULL;
1307*0Sstevel@tonic-gate /*
1308*0Sstevel@tonic-gate  * The SLC reply consists of: IAC, SB, TELOPT_LINEMODE, LM_SLC,
1309*0Sstevel@tonic-gate  * SLC triplets[], IAC, SE. i.e. it has a 'wrapper' of 6 control characters.
1310*0Sstevel@tonic-gate  */
1311*0Sstevel@tonic-gate #define	SLC_WRAPPER_SIZE 6
1312*0Sstevel@tonic-gate 
1313*0Sstevel@tonic-gate static void
slc_export()1314*0Sstevel@tonic-gate slc_export()
1315*0Sstevel@tonic-gate {
1316*0Sstevel@tonic-gate 	register struct spc *spcp;
1317*0Sstevel@tonic-gate 
1318*0Sstevel@tonic-gate 	TerminalDefaultChars();
1319*0Sstevel@tonic-gate 
1320*0Sstevel@tonic-gate 	slc_start_reply(NSLC * 3);	/* 3 bytes needed per triplet */
1321*0Sstevel@tonic-gate 	for (spcp = &spc_data[1]; spcp < &spc_data[NSLC+1]; spcp++) {
1322*0Sstevel@tonic-gate 		if (spcp->mylevel != SLC_NOSUPPORT) {
1323*0Sstevel@tonic-gate 			if (spcp->val == (cc_t)(_POSIX_VDISABLE))
1324*0Sstevel@tonic-gate 				spcp->flags = SLC_NOSUPPORT;
1325*0Sstevel@tonic-gate 			else
1326*0Sstevel@tonic-gate 				spcp->flags = spcp->mylevel;
1327*0Sstevel@tonic-gate 			if (spcp->valp)
1328*0Sstevel@tonic-gate 				spcp->val = *spcp->valp;
1329*0Sstevel@tonic-gate 			slc_add_reply(spcp - spc_data, spcp->flags, spcp->val);
1330*0Sstevel@tonic-gate 		}
1331*0Sstevel@tonic-gate 	}
1332*0Sstevel@tonic-gate 	slc_end_reply();
1333*0Sstevel@tonic-gate 	(void) slc_update();
1334*0Sstevel@tonic-gate 	setconnmode(1);	/* Make sure the character values are set */
1335*0Sstevel@tonic-gate }
1336*0Sstevel@tonic-gate 
1337*0Sstevel@tonic-gate static void
slc(cp,len)1338*0Sstevel@tonic-gate slc(cp, len)
1339*0Sstevel@tonic-gate 	register unsigned char *cp;
1340*0Sstevel@tonic-gate 	int len;
1341*0Sstevel@tonic-gate {
1342*0Sstevel@tonic-gate 	register struct spc *spcp;
1343*0Sstevel@tonic-gate 	register int func, level;
1344*0Sstevel@tonic-gate 
1345*0Sstevel@tonic-gate 	slc_start_reply(len);
1346*0Sstevel@tonic-gate 
1347*0Sstevel@tonic-gate 	for (; len >= 3; len -= 3, cp += 3) {
1348*0Sstevel@tonic-gate 
1349*0Sstevel@tonic-gate 		func = cp[SLC_FUNC];
1350*0Sstevel@tonic-gate 
1351*0Sstevel@tonic-gate 		if (func == 0) {
1352*0Sstevel@tonic-gate 			/*
1353*0Sstevel@tonic-gate 			 * Client side: always ignore 0 function.
1354*0Sstevel@tonic-gate 			 */
1355*0Sstevel@tonic-gate 			continue;
1356*0Sstevel@tonic-gate 		}
1357*0Sstevel@tonic-gate 		if (func > NSLC) {
1358*0Sstevel@tonic-gate 			if ((cp[SLC_FLAGS] & SLC_LEVELBITS) != SLC_NOSUPPORT)
1359*0Sstevel@tonic-gate 				slc_add_reply(func, SLC_NOSUPPORT, 0);
1360*0Sstevel@tonic-gate 			continue;
1361*0Sstevel@tonic-gate 		}
1362*0Sstevel@tonic-gate 
1363*0Sstevel@tonic-gate 		spcp = &spc_data[func];
1364*0Sstevel@tonic-gate 
1365*0Sstevel@tonic-gate 		level = cp[SLC_FLAGS]&(SLC_LEVELBITS|SLC_ACK);
1366*0Sstevel@tonic-gate 
1367*0Sstevel@tonic-gate 		if ((cp[SLC_VALUE] == (unsigned char)spcp->val) &&
1368*0Sstevel@tonic-gate 		    ((level&SLC_LEVELBITS) == (spcp->flags&SLC_LEVELBITS))) {
1369*0Sstevel@tonic-gate 			continue;
1370*0Sstevel@tonic-gate 		}
1371*0Sstevel@tonic-gate 
1372*0Sstevel@tonic-gate 		if (level == (SLC_DEFAULT|SLC_ACK)) {
1373*0Sstevel@tonic-gate 			/*
1374*0Sstevel@tonic-gate 			 * This is an error condition, the SLC_ACK
1375*0Sstevel@tonic-gate 			 * bit should never be set for the SLC_DEFAULT
1376*0Sstevel@tonic-gate 			 * level.  Our best guess to recover is to
1377*0Sstevel@tonic-gate 			 * ignore the SLC_ACK bit.
1378*0Sstevel@tonic-gate 			 */
1379*0Sstevel@tonic-gate 			cp[SLC_FLAGS] &= ~SLC_ACK;
1380*0Sstevel@tonic-gate 		}
1381*0Sstevel@tonic-gate 
1382*0Sstevel@tonic-gate 		if (level == ((spcp->flags&SLC_LEVELBITS)|SLC_ACK)) {
1383*0Sstevel@tonic-gate 			spcp->val = (cc_t)cp[SLC_VALUE];
1384*0Sstevel@tonic-gate 			spcp->flags = cp[SLC_FLAGS];	/* include SLC_ACK */
1385*0Sstevel@tonic-gate 			continue;
1386*0Sstevel@tonic-gate 		}
1387*0Sstevel@tonic-gate 
1388*0Sstevel@tonic-gate 		level &= ~SLC_ACK;
1389*0Sstevel@tonic-gate 
1390*0Sstevel@tonic-gate 		if (level <= (spcp->mylevel&SLC_LEVELBITS)) {
1391*0Sstevel@tonic-gate 			spcp->flags = cp[SLC_FLAGS]|SLC_ACK;
1392*0Sstevel@tonic-gate 			spcp->val = (cc_t)cp[SLC_VALUE];
1393*0Sstevel@tonic-gate 		}
1394*0Sstevel@tonic-gate 		if (level == SLC_DEFAULT) {
1395*0Sstevel@tonic-gate 			if ((spcp->mylevel&SLC_LEVELBITS) != SLC_DEFAULT)
1396*0Sstevel@tonic-gate 				spcp->flags = spcp->mylevel;
1397*0Sstevel@tonic-gate 			else
1398*0Sstevel@tonic-gate 				spcp->flags = SLC_NOSUPPORT;
1399*0Sstevel@tonic-gate 		}
1400*0Sstevel@tonic-gate 		slc_add_reply(func, spcp->flags, spcp->val);
1401*0Sstevel@tonic-gate 	}
1402*0Sstevel@tonic-gate 	slc_end_reply();
1403*0Sstevel@tonic-gate 	if (slc_update())
1404*0Sstevel@tonic-gate 		setconnmode(1);	/* set the  new character values */
1405*0Sstevel@tonic-gate }
1406*0Sstevel@tonic-gate 
1407*0Sstevel@tonic-gate void
slc_check()1408*0Sstevel@tonic-gate slc_check()
1409*0Sstevel@tonic-gate {
1410*0Sstevel@tonic-gate 	register struct spc *spcp;
1411*0Sstevel@tonic-gate 
1412*0Sstevel@tonic-gate 	slc_start_reply(NSLC * 3);	/* 3 bytes needed per triplet */
1413*0Sstevel@tonic-gate 	for (spcp = &spc_data[1]; spcp < &spc_data[NSLC+1]; spcp++) {
1414*0Sstevel@tonic-gate 		if (spcp->valp && spcp->val != *spcp->valp) {
1415*0Sstevel@tonic-gate 			spcp->val = *spcp->valp;
1416*0Sstevel@tonic-gate 			if (spcp->val == (cc_t)(_POSIX_VDISABLE))
1417*0Sstevel@tonic-gate 				spcp->flags = SLC_NOSUPPORT;
1418*0Sstevel@tonic-gate 			else
1419*0Sstevel@tonic-gate 				spcp->flags = spcp->mylevel;
1420*0Sstevel@tonic-gate 			slc_add_reply(spcp - spc_data, spcp->flags, spcp->val);
1421*0Sstevel@tonic-gate 		}
1422*0Sstevel@tonic-gate 	}
1423*0Sstevel@tonic-gate 	slc_end_reply();
1424*0Sstevel@tonic-gate 	setconnmode(1);
1425*0Sstevel@tonic-gate }
1426*0Sstevel@tonic-gate 
1427*0Sstevel@tonic-gate static void
slc_start_reply(size_t len)1428*0Sstevel@tonic-gate slc_start_reply(size_t len)
1429*0Sstevel@tonic-gate {
1430*0Sstevel@tonic-gate 	/*
1431*0Sstevel@tonic-gate 	 * SLC triplets may contain escaped characters, allow for
1432*0Sstevel@tonic-gate 	 * worst case by allocating 2 bytes for every character.
1433*0Sstevel@tonic-gate 	 */
1434*0Sstevel@tonic-gate 	slc_reply = realloc(slc_reply, (len * 2) + SLC_WRAPPER_SIZE);
1435*0Sstevel@tonic-gate 	if (slc_reply == NULL) {
1436*0Sstevel@tonic-gate 		fprintf(stderr, "telnet: error allocating SLC reply memory\n");
1437*0Sstevel@tonic-gate 		return;
1438*0Sstevel@tonic-gate 	}
1439*0Sstevel@tonic-gate 	slc_replyp = slc_reply;
1440*0Sstevel@tonic-gate 	*slc_replyp++ = IAC;
1441*0Sstevel@tonic-gate 	*slc_replyp++ = SB;
1442*0Sstevel@tonic-gate 	*slc_replyp++ = TELOPT_LINEMODE;
1443*0Sstevel@tonic-gate 	*slc_replyp++ = LM_SLC;
1444*0Sstevel@tonic-gate }
1445*0Sstevel@tonic-gate 
1446*0Sstevel@tonic-gate static void
slc_add_reply(unsigned char func,unsigned char flags,cc_t value)1447*0Sstevel@tonic-gate slc_add_reply(unsigned char func, unsigned char flags, cc_t value)
1448*0Sstevel@tonic-gate {
1449*0Sstevel@tonic-gate 	if ((*slc_replyp++ = func) == IAC)
1450*0Sstevel@tonic-gate 		*slc_replyp++ = IAC;
1451*0Sstevel@tonic-gate 	if ((*slc_replyp++ = flags) == IAC)
1452*0Sstevel@tonic-gate 		*slc_replyp++ = IAC;
1453*0Sstevel@tonic-gate 	if ((*slc_replyp++ = (unsigned char)value) == IAC)
1454*0Sstevel@tonic-gate 		*slc_replyp++ = IAC;
1455*0Sstevel@tonic-gate }
1456*0Sstevel@tonic-gate 
1457*0Sstevel@tonic-gate static void
slc_end_reply()1458*0Sstevel@tonic-gate slc_end_reply()
1459*0Sstevel@tonic-gate {
1460*0Sstevel@tonic-gate 	register int len;
1461*0Sstevel@tonic-gate 
1462*0Sstevel@tonic-gate 	*slc_replyp++ = IAC;
1463*0Sstevel@tonic-gate 	*slc_replyp++ = SE;
1464*0Sstevel@tonic-gate 	len = slc_replyp - slc_reply;
1465*0Sstevel@tonic-gate 	if (len <= SLC_WRAPPER_SIZE)
1466*0Sstevel@tonic-gate 		return;
1467*0Sstevel@tonic-gate 	if (NETROOM() > len) {
1468*0Sstevel@tonic-gate 		ring_supply_data(&netoring, slc_reply, slc_replyp - slc_reply);
1469*0Sstevel@tonic-gate 		printsub('>', &slc_reply[2], slc_replyp - slc_reply - 2);
1470*0Sstevel@tonic-gate 	}
1471*0Sstevel@tonic-gate 	else
1472*0Sstevel@tonic-gate 		(void) printf("telnet: not enough room in buffer for slc end "
1473*0Sstevel@tonic-gate 		    "reply\n");
1474*0Sstevel@tonic-gate }
1475*0Sstevel@tonic-gate 
1476*0Sstevel@tonic-gate static int
slc_update()1477*0Sstevel@tonic-gate slc_update()
1478*0Sstevel@tonic-gate {
1479*0Sstevel@tonic-gate 	register struct spc *spcp;
1480*0Sstevel@tonic-gate 	int need_update = 0;
1481*0Sstevel@tonic-gate 
1482*0Sstevel@tonic-gate 	for (spcp = &spc_data[1]; spcp < &spc_data[NSLC+1]; spcp++) {
1483*0Sstevel@tonic-gate 		if (!(spcp->flags&SLC_ACK))
1484*0Sstevel@tonic-gate 			continue;
1485*0Sstevel@tonic-gate 		spcp->flags &= ~SLC_ACK;
1486*0Sstevel@tonic-gate 		if (spcp->valp && (*spcp->valp != spcp->val)) {
1487*0Sstevel@tonic-gate 			*spcp->valp = spcp->val;
1488*0Sstevel@tonic-gate 			need_update = 1;
1489*0Sstevel@tonic-gate 		}
1490*0Sstevel@tonic-gate 	}
1491*0Sstevel@tonic-gate 	return (need_update);
1492*0Sstevel@tonic-gate }
1493*0Sstevel@tonic-gate 
1494*0Sstevel@tonic-gate #ifdef	OLD_ENVIRON
1495*0Sstevel@tonic-gate #ifdef	ENV_HACK
1496*0Sstevel@tonic-gate /*
1497*0Sstevel@tonic-gate  * Earlier version of telnet/telnetd from the BSD code had
1498*0Sstevel@tonic-gate  * the definitions of VALUE and VAR reversed.  To ensure
1499*0Sstevel@tonic-gate  * maximum interoperability, we assume that the server is
1500*0Sstevel@tonic-gate  * an older BSD server, until proven otherwise.  The newer
1501*0Sstevel@tonic-gate  * BSD servers should be able to handle either definition,
1502*0Sstevel@tonic-gate  * so it is better to use the wrong values if we don't
1503*0Sstevel@tonic-gate  * know what type of server it is.
1504*0Sstevel@tonic-gate  */
1505*0Sstevel@tonic-gate int env_auto = 1;
1506*0Sstevel@tonic-gate int old_env_var = OLD_ENV_VAR;
1507*0Sstevel@tonic-gate int old_env_value = OLD_ENV_VALUE;
1508*0Sstevel@tonic-gate #else
1509*0Sstevel@tonic-gate #define	old_env_var	OLD_ENV_VAR
1510*0Sstevel@tonic-gate #define	old_env_value	OLD_ENV_VALUE
1511*0Sstevel@tonic-gate #endif
1512*0Sstevel@tonic-gate #endif
1513*0Sstevel@tonic-gate 
1514*0Sstevel@tonic-gate static void
env_opt(buf,len)1515*0Sstevel@tonic-gate env_opt(buf, len)
1516*0Sstevel@tonic-gate 	register unsigned char *buf;
1517*0Sstevel@tonic-gate 	register int len;
1518*0Sstevel@tonic-gate {
1519*0Sstevel@tonic-gate 	register unsigned char *ep = 0, *epc = 0;
1520*0Sstevel@tonic-gate 	register int i;
1521*0Sstevel@tonic-gate 
1522*0Sstevel@tonic-gate 	switch (buf[0]&0xff) {
1523*0Sstevel@tonic-gate 	case TELQUAL_SEND:
1524*0Sstevel@tonic-gate 		env_opt_start();
1525*0Sstevel@tonic-gate 		if (len == 1) {
1526*0Sstevel@tonic-gate 			env_opt_add(NULL);
1527*0Sstevel@tonic-gate 		} else for (i = 1; i < len; i++) {
1528*0Sstevel@tonic-gate 			switch (buf[i]&0xff) {
1529*0Sstevel@tonic-gate #ifdef	OLD_ENVIRON
1530*0Sstevel@tonic-gate 			case OLD_ENV_VAR:
1531*0Sstevel@tonic-gate #ifdef	ENV_HACK
1532*0Sstevel@tonic-gate 				if (telopt_environ == TELOPT_OLD_ENVIRON &&
1533*0Sstevel@tonic-gate 				    env_auto) {
1534*0Sstevel@tonic-gate 					/* Server has the same definitions */
1535*0Sstevel@tonic-gate 					old_env_var = OLD_ENV_VAR;
1536*0Sstevel@tonic-gate 					old_env_value = OLD_ENV_VALUE;
1537*0Sstevel@tonic-gate 				}
1538*0Sstevel@tonic-gate 				/* FALLTHROUGH */
1539*0Sstevel@tonic-gate #endif
1540*0Sstevel@tonic-gate 			case OLD_ENV_VALUE:
1541*0Sstevel@tonic-gate 				/*
1542*0Sstevel@tonic-gate 				 * Although OLD_ENV_VALUE is not legal, we will
1543*0Sstevel@tonic-gate 				 * still recognize it, just in case it is an
1544*0Sstevel@tonic-gate 				 * old server that has VAR & VALUE mixed up...
1545*0Sstevel@tonic-gate 				 */
1546*0Sstevel@tonic-gate 				/* FALLTHROUGH */
1547*0Sstevel@tonic-gate #else
1548*0Sstevel@tonic-gate 			case NEW_ENV_VAR:
1549*0Sstevel@tonic-gate #endif
1550*0Sstevel@tonic-gate 			case ENV_USERVAR:
1551*0Sstevel@tonic-gate 				if (ep) {
1552*0Sstevel@tonic-gate 					*epc = 0;
1553*0Sstevel@tonic-gate 					env_opt_add(ep);
1554*0Sstevel@tonic-gate 				}
1555*0Sstevel@tonic-gate 				ep = epc = &buf[i+1];
1556*0Sstevel@tonic-gate 				break;
1557*0Sstevel@tonic-gate 			case ENV_ESC:
1558*0Sstevel@tonic-gate 				i++;
1559*0Sstevel@tonic-gate 				/*FALLTHROUGH*/
1560*0Sstevel@tonic-gate 			default:
1561*0Sstevel@tonic-gate 				if (epc)
1562*0Sstevel@tonic-gate 					*epc++ = buf[i];
1563*0Sstevel@tonic-gate 				break;
1564*0Sstevel@tonic-gate 			}
1565*0Sstevel@tonic-gate 		}
1566*0Sstevel@tonic-gate 		if (ep) {
1567*0Sstevel@tonic-gate 			*epc = 0;
1568*0Sstevel@tonic-gate 			env_opt_add(ep);
1569*0Sstevel@tonic-gate 		}
1570*0Sstevel@tonic-gate 		env_opt_end(1);
1571*0Sstevel@tonic-gate 		break;
1572*0Sstevel@tonic-gate 
1573*0Sstevel@tonic-gate 	case TELQUAL_IS:
1574*0Sstevel@tonic-gate 	case TELQUAL_INFO:
1575*0Sstevel@tonic-gate 		/* Ignore for now.  We shouldn't get it anyway. */
1576*0Sstevel@tonic-gate 		break;
1577*0Sstevel@tonic-gate 
1578*0Sstevel@tonic-gate 	default:
1579*0Sstevel@tonic-gate 		break;
1580*0Sstevel@tonic-gate 	}
1581*0Sstevel@tonic-gate }
1582*0Sstevel@tonic-gate 
1583*0Sstevel@tonic-gate static unsigned char *opt_reply;
1584*0Sstevel@tonic-gate static unsigned char *opt_replyp;
1585*0Sstevel@tonic-gate static unsigned char *opt_replyend;
1586*0Sstevel@tonic-gate #define	OPT_REPLY_INITIAL_SIZE	256
1587*0Sstevel@tonic-gate /*
1588*0Sstevel@tonic-gate  * The opt reply consists of: IAC, SB, telopt_environ, TELQUAL_IS,
1589*0Sstevel@tonic-gate  * value, IAC, SE. i.e. it has a 'wrapper' of 6 control characters.
1590*0Sstevel@tonic-gate  */
1591*0Sstevel@tonic-gate #define	OPT_WRAPPER_SIZE 6
1592*0Sstevel@tonic-gate 
1593*0Sstevel@tonic-gate static void
env_opt_start()1594*0Sstevel@tonic-gate env_opt_start()
1595*0Sstevel@tonic-gate {
1596*0Sstevel@tonic-gate 	opt_reply = realloc(opt_reply, OPT_REPLY_INITIAL_SIZE);
1597*0Sstevel@tonic-gate 	if (opt_reply == NULL) {
1598*0Sstevel@tonic-gate 		(void) printf(
1599*0Sstevel@tonic-gate 		    "telnet: error allocating environment option memory\n");
1600*0Sstevel@tonic-gate 		opt_reply = opt_replyp = opt_replyend = NULL;
1601*0Sstevel@tonic-gate 		return;
1602*0Sstevel@tonic-gate 	}
1603*0Sstevel@tonic-gate 	opt_replyp = opt_reply;
1604*0Sstevel@tonic-gate 	opt_replyend = opt_reply + OPT_REPLY_INITIAL_SIZE;
1605*0Sstevel@tonic-gate 	*opt_replyp++ = IAC;
1606*0Sstevel@tonic-gate 	*opt_replyp++ = SB;
1607*0Sstevel@tonic-gate 	*opt_replyp++ = telopt_environ;
1608*0Sstevel@tonic-gate 	*opt_replyp++ = TELQUAL_IS;
1609*0Sstevel@tonic-gate }
1610*0Sstevel@tonic-gate 
1611*0Sstevel@tonic-gate 	void
env_opt_start_info()1612*0Sstevel@tonic-gate env_opt_start_info()
1613*0Sstevel@tonic-gate {
1614*0Sstevel@tonic-gate 	env_opt_start();
1615*0Sstevel@tonic-gate 	if (opt_replyp)
1616*0Sstevel@tonic-gate 	    opt_replyp[-1] = TELQUAL_INFO;
1617*0Sstevel@tonic-gate }
1618*0Sstevel@tonic-gate 
1619*0Sstevel@tonic-gate 	void
env_opt_add(ep)1620*0Sstevel@tonic-gate env_opt_add(ep)
1621*0Sstevel@tonic-gate 	register unsigned char *ep;
1622*0Sstevel@tonic-gate {
1623*0Sstevel@tonic-gate 	register unsigned char *vp, c;
1624*0Sstevel@tonic-gate 	int opt_reply_size;
1625*0Sstevel@tonic-gate 	int opt_reply_used;
1626*0Sstevel@tonic-gate 
1627*0Sstevel@tonic-gate 	if (opt_reply == NULL)		/* XXX */
1628*0Sstevel@tonic-gate 		return;			/* XXX */
1629*0Sstevel@tonic-gate 
1630*0Sstevel@tonic-gate 	if (ep == NULL || *ep == '\0') {
1631*0Sstevel@tonic-gate 		/* Send user defined variables first. */
1632*0Sstevel@tonic-gate 		(void) env_default(1, 0);
1633*0Sstevel@tonic-gate 		while (ep = env_default(0, 0))
1634*0Sstevel@tonic-gate 			env_opt_add(ep);
1635*0Sstevel@tonic-gate 
1636*0Sstevel@tonic-gate 		/* Now add the list of well know variables.  */
1637*0Sstevel@tonic-gate 		(void) env_default(1, 1);
1638*0Sstevel@tonic-gate 		while (ep = env_default(0, 1))
1639*0Sstevel@tonic-gate 			env_opt_add(ep);
1640*0Sstevel@tonic-gate 		return;
1641*0Sstevel@tonic-gate 	}
1642*0Sstevel@tonic-gate 	vp = env_getvalue(ep);
1643*0Sstevel@tonic-gate 
1644*0Sstevel@tonic-gate 	/*
1645*0Sstevel@tonic-gate 	 * Calculate space required for opt_reply and allocate more if required.
1646*0Sstevel@tonic-gate 	 * Assume worst case that every character is escaped, so needs 2 bytes.
1647*0Sstevel@tonic-gate 	 */
1648*0Sstevel@tonic-gate 	opt_reply_used = opt_replyp - opt_reply;	/* existing contents */
1649*0Sstevel@tonic-gate 	opt_reply_size = opt_reply_used + OPT_WRAPPER_SIZE +
1650*0Sstevel@tonic-gate 	    (2 * (strlen((char *)ep))) +
1651*0Sstevel@tonic-gate 	    (vp == NULL ? 0 : (2 * strlen((char *)vp)));
1652*0Sstevel@tonic-gate 
1653*0Sstevel@tonic-gate 	if (opt_reply_size > (opt_replyend - opt_reply)) {
1654*0Sstevel@tonic-gate 		opt_reply = realloc(opt_reply, opt_reply_size);
1655*0Sstevel@tonic-gate 		if (opt_reply == NULL) {
1656*0Sstevel@tonic-gate 			(void) printf(
1657*0Sstevel@tonic-gate 			    "telnet: can't allocate environment option "
1658*0Sstevel@tonic-gate 			    "reply\n");
1659*0Sstevel@tonic-gate 			opt_reply = opt_replyp = opt_replyend = NULL;
1660*0Sstevel@tonic-gate 			return;
1661*0Sstevel@tonic-gate 		}
1662*0Sstevel@tonic-gate 		opt_replyp = opt_reply + opt_reply_used;
1663*0Sstevel@tonic-gate 		opt_replyend = opt_reply + opt_reply_size;
1664*0Sstevel@tonic-gate 	}
1665*0Sstevel@tonic-gate 
1666*0Sstevel@tonic-gate 	if (opt_welldefined((char *)ep))
1667*0Sstevel@tonic-gate #ifdef	OLD_ENVIRON
1668*0Sstevel@tonic-gate 		if (telopt_environ == TELOPT_OLD_ENVIRON)
1669*0Sstevel@tonic-gate 			*opt_replyp++ = old_env_var;
1670*0Sstevel@tonic-gate 		else
1671*0Sstevel@tonic-gate #endif
1672*0Sstevel@tonic-gate 			*opt_replyp++ = NEW_ENV_VAR;
1673*0Sstevel@tonic-gate 	else
1674*0Sstevel@tonic-gate 		*opt_replyp++ = ENV_USERVAR;
1675*0Sstevel@tonic-gate 	for (;;) {
1676*0Sstevel@tonic-gate 		while ((c = *ep++) != NULL) {
1677*0Sstevel@tonic-gate 			switch (c&0xff) {
1678*0Sstevel@tonic-gate 			case IAC:
1679*0Sstevel@tonic-gate 				*opt_replyp++ = IAC;
1680*0Sstevel@tonic-gate 				break;
1681*0Sstevel@tonic-gate 			case NEW_ENV_VAR:
1682*0Sstevel@tonic-gate 			case NEW_ENV_VALUE:
1683*0Sstevel@tonic-gate 			case ENV_ESC:
1684*0Sstevel@tonic-gate 			case ENV_USERVAR:
1685*0Sstevel@tonic-gate 				*opt_replyp++ = ENV_ESC;
1686*0Sstevel@tonic-gate 				break;
1687*0Sstevel@tonic-gate 			}
1688*0Sstevel@tonic-gate 			*opt_replyp++ = c;
1689*0Sstevel@tonic-gate 		}
1690*0Sstevel@tonic-gate 		if ((ep = vp) != NULL) {
1691*0Sstevel@tonic-gate #ifdef	OLD_ENVIRON
1692*0Sstevel@tonic-gate 			if (telopt_environ == TELOPT_OLD_ENVIRON)
1693*0Sstevel@tonic-gate 				*opt_replyp++ = old_env_value;
1694*0Sstevel@tonic-gate 			else
1695*0Sstevel@tonic-gate #endif
1696*0Sstevel@tonic-gate 				*opt_replyp++ = NEW_ENV_VALUE;
1697*0Sstevel@tonic-gate 			vp = NULL;
1698*0Sstevel@tonic-gate 		} else
1699*0Sstevel@tonic-gate 			break;
1700*0Sstevel@tonic-gate 	}
1701*0Sstevel@tonic-gate }
1702*0Sstevel@tonic-gate 
1703*0Sstevel@tonic-gate 	int
opt_welldefined(ep)1704*0Sstevel@tonic-gate opt_welldefined(ep)
1705*0Sstevel@tonic-gate 	char *ep;
1706*0Sstevel@tonic-gate {
1707*0Sstevel@tonic-gate 	if ((strcmp(ep, "USER") == 0) ||
1708*0Sstevel@tonic-gate 	    (strcmp(ep, "DISPLAY") == 0) ||
1709*0Sstevel@tonic-gate 	    (strcmp(ep, "PRINTER") == 0) ||
1710*0Sstevel@tonic-gate 	    (strcmp(ep, "SYSTEMTYPE") == 0) ||
1711*0Sstevel@tonic-gate 	    (strcmp(ep, "JOB") == 0) ||
1712*0Sstevel@tonic-gate 	    (strcmp(ep, "ACCT") == 0))
1713*0Sstevel@tonic-gate 		return (1);
1714*0Sstevel@tonic-gate 	return (0);
1715*0Sstevel@tonic-gate }
1716*0Sstevel@tonic-gate 	void
env_opt_end(emptyok)1717*0Sstevel@tonic-gate env_opt_end(emptyok)
1718*0Sstevel@tonic-gate 	register int emptyok;
1719*0Sstevel@tonic-gate {
1720*0Sstevel@tonic-gate 	register int len;
1721*0Sstevel@tonic-gate 
1722*0Sstevel@tonic-gate 	len = opt_replyp - opt_reply + 2;
1723*0Sstevel@tonic-gate 	if (emptyok || len > OPT_WRAPPER_SIZE) {
1724*0Sstevel@tonic-gate 		*opt_replyp++ = IAC;
1725*0Sstevel@tonic-gate 		*opt_replyp++ = SE;
1726*0Sstevel@tonic-gate 		if (NETROOM() > len) {
1727*0Sstevel@tonic-gate 			ring_supply_data(&netoring, opt_reply, len);
1728*0Sstevel@tonic-gate 			printsub('>', &opt_reply[2], len - 2);
1729*0Sstevel@tonic-gate 		}
1730*0Sstevel@tonic-gate 		else
1731*0Sstevel@tonic-gate 			(void) printf("telnet: not enough room in buffer for "
1732*0Sstevel@tonic-gate 			    "environment option end reply\n");
1733*0Sstevel@tonic-gate 	}
1734*0Sstevel@tonic-gate 	if (opt_reply) {
1735*0Sstevel@tonic-gate 		free(opt_reply);
1736*0Sstevel@tonic-gate 		opt_reply = opt_replyp = opt_replyend = NULL;
1737*0Sstevel@tonic-gate 	}
1738*0Sstevel@tonic-gate }
1739*0Sstevel@tonic-gate 
1740*0Sstevel@tonic-gate 
1741*0Sstevel@tonic-gate 
1742*0Sstevel@tonic-gate int
telrcv()1743*0Sstevel@tonic-gate telrcv()
1744*0Sstevel@tonic-gate {
1745*0Sstevel@tonic-gate 	register int c;
1746*0Sstevel@tonic-gate 	register int scc;
1747*0Sstevel@tonic-gate 	register unsigned char *sbp;
1748*0Sstevel@tonic-gate 	int count;
1749*0Sstevel@tonic-gate 	int returnValue = 0;
1750*0Sstevel@tonic-gate 	int min_room = 0;
1751*0Sstevel@tonic-gate 
1752*0Sstevel@tonic-gate 	scc = 0;
1753*0Sstevel@tonic-gate 	count = 0;
1754*0Sstevel@tonic-gate 	while (--min_room > 2 || (min_room = TTYROOM()) > 2) {
1755*0Sstevel@tonic-gate 		if (scc == 0) {
1756*0Sstevel@tonic-gate 			if (count) {
1757*0Sstevel@tonic-gate 				ring_consumed(&netiring, count);
1758*0Sstevel@tonic-gate 				returnValue = 1;
1759*0Sstevel@tonic-gate 				count = 0;
1760*0Sstevel@tonic-gate 			}
1761*0Sstevel@tonic-gate 			sbp = netiring.consume;
1762*0Sstevel@tonic-gate 			scc = ring_full_consecutive(&netiring);
1763*0Sstevel@tonic-gate 			if (scc == 0) {
1764*0Sstevel@tonic-gate 				/* No more data coming in */
1765*0Sstevel@tonic-gate 				break;
1766*0Sstevel@tonic-gate 			}
1767*0Sstevel@tonic-gate 		}
1768*0Sstevel@tonic-gate 
1769*0Sstevel@tonic-gate 		c = *sbp++ & 0xff, scc--; count++;
1770*0Sstevel@tonic-gate 
1771*0Sstevel@tonic-gate 		if (decrypt_input)
1772*0Sstevel@tonic-gate 			c = (*decrypt_input)(c);
1773*0Sstevel@tonic-gate 
1774*0Sstevel@tonic-gate 		switch (telrcv_state) {
1775*0Sstevel@tonic-gate 
1776*0Sstevel@tonic-gate 		case TS_CR:
1777*0Sstevel@tonic-gate 			telrcv_state = TS_DATA;
1778*0Sstevel@tonic-gate 			if (c == '\0') {
1779*0Sstevel@tonic-gate 				break;	/* Ignore \0 after CR */
1780*0Sstevel@tonic-gate 			} else if ((c == '\n') &&
1781*0Sstevel@tonic-gate 			    my_want_state_is_dont(TELOPT_ECHO) && !crmod) {
1782*0Sstevel@tonic-gate 				TTYADD(c);
1783*0Sstevel@tonic-gate 				break;
1784*0Sstevel@tonic-gate 			}
1785*0Sstevel@tonic-gate 			/* FALLTHROUGH */
1786*0Sstevel@tonic-gate 
1787*0Sstevel@tonic-gate 		case TS_DATA:
1788*0Sstevel@tonic-gate 			if (c == IAC) {
1789*0Sstevel@tonic-gate 				telrcv_state = TS_IAC;
1790*0Sstevel@tonic-gate 				break;
1791*0Sstevel@tonic-gate 			}
1792*0Sstevel@tonic-gate 			/*
1793*0Sstevel@tonic-gate 			 * The 'crmod' hack (see following) is needed
1794*0Sstevel@tonic-gate 			 * since we can't * set CRMOD on output only.
1795*0Sstevel@tonic-gate 			 * Machines like MULTICS like to send \r without
1796*0Sstevel@tonic-gate 			 * \n; since we must turn off CRMOD to get proper
1797*0Sstevel@tonic-gate 			 * input, the mapping is done here (sigh).
1798*0Sstevel@tonic-gate 			 */
1799*0Sstevel@tonic-gate 			if ((c == '\r') &&
1800*0Sstevel@tonic-gate 			    my_want_state_is_dont(TELOPT_BINARY)) {
1801*0Sstevel@tonic-gate 				if (scc > 0) {
1802*0Sstevel@tonic-gate 					c = *sbp&0xff;
1803*0Sstevel@tonic-gate 
1804*0Sstevel@tonic-gate 					if (decrypt_input)
1805*0Sstevel@tonic-gate 						c = (*decrypt_input)(c);
1806*0Sstevel@tonic-gate 
1807*0Sstevel@tonic-gate 					if (c == 0) {
1808*0Sstevel@tonic-gate 						sbp++, scc--; count++;
1809*0Sstevel@tonic-gate 						/* a "true" CR */
1810*0Sstevel@tonic-gate 						TTYADD('\r');
1811*0Sstevel@tonic-gate 					} else if (my_want_state_is_dont(
1812*0Sstevel@tonic-gate 					    TELOPT_ECHO) && (c == '\n')) {
1813*0Sstevel@tonic-gate 						sbp++, scc--; count++;
1814*0Sstevel@tonic-gate 						TTYADD('\n');
1815*0Sstevel@tonic-gate 					} else {
1816*0Sstevel@tonic-gate 
1817*0Sstevel@tonic-gate 						if (decrypt_input)
1818*0Sstevel@tonic-gate 							(*decrypt_input)(-1);
1819*0Sstevel@tonic-gate 
1820*0Sstevel@tonic-gate 						TTYADD('\r');
1821*0Sstevel@tonic-gate 						if (crmod) {
1822*0Sstevel@tonic-gate 							TTYADD('\n');
1823*0Sstevel@tonic-gate 						}
1824*0Sstevel@tonic-gate 					}
1825*0Sstevel@tonic-gate 				} else {
1826*0Sstevel@tonic-gate 					telrcv_state = TS_CR;
1827*0Sstevel@tonic-gate 					TTYADD('\r');
1828*0Sstevel@tonic-gate 					if (crmod) {
1829*0Sstevel@tonic-gate 						TTYADD('\n');
1830*0Sstevel@tonic-gate 					}
1831*0Sstevel@tonic-gate 				}
1832*0Sstevel@tonic-gate 			} else {
1833*0Sstevel@tonic-gate 				TTYADD(c);
1834*0Sstevel@tonic-gate 			}
1835*0Sstevel@tonic-gate 			continue;
1836*0Sstevel@tonic-gate 
1837*0Sstevel@tonic-gate 		case TS_IAC:
1838*0Sstevel@tonic-gate process_iac:
1839*0Sstevel@tonic-gate 			switch (c) {
1840*0Sstevel@tonic-gate 
1841*0Sstevel@tonic-gate 			case WILL:
1842*0Sstevel@tonic-gate 				telrcv_state = TS_WILL;
1843*0Sstevel@tonic-gate 				continue;
1844*0Sstevel@tonic-gate 
1845*0Sstevel@tonic-gate 			case WONT:
1846*0Sstevel@tonic-gate 				telrcv_state = TS_WONT;
1847*0Sstevel@tonic-gate 				continue;
1848*0Sstevel@tonic-gate 
1849*0Sstevel@tonic-gate 			case DO:
1850*0Sstevel@tonic-gate 				telrcv_state = TS_DO;
1851*0Sstevel@tonic-gate 				continue;
1852*0Sstevel@tonic-gate 
1853*0Sstevel@tonic-gate 			case DONT:
1854*0Sstevel@tonic-gate 				telrcv_state = TS_DONT;
1855*0Sstevel@tonic-gate 				continue;
1856*0Sstevel@tonic-gate 
1857*0Sstevel@tonic-gate 			case DM:
1858*0Sstevel@tonic-gate 				/*
1859*0Sstevel@tonic-gate 				 * We may have missed an urgent notification,
1860*0Sstevel@tonic-gate 				 * so make sure we flush whatever is in the
1861*0Sstevel@tonic-gate 				 * buffer currently.
1862*0Sstevel@tonic-gate 				 */
1863*0Sstevel@tonic-gate 				printoption("RCVD", IAC, DM);
1864*0Sstevel@tonic-gate 				SYNCHing = 1;
1865*0Sstevel@tonic-gate 				if (ttyflush(1) == -2) {
1866*0Sstevel@tonic-gate 					/* This will not return. */
1867*0Sstevel@tonic-gate 					fatal_tty_error("write");
1868*0Sstevel@tonic-gate 				}
1869*0Sstevel@tonic-gate 				SYNCHing = stilloob();
1870*0Sstevel@tonic-gate 				settimer(gotDM);
1871*0Sstevel@tonic-gate 				break;
1872*0Sstevel@tonic-gate 
1873*0Sstevel@tonic-gate 			case SB:
1874*0Sstevel@tonic-gate 				SB_CLEAR();
1875*0Sstevel@tonic-gate 				telrcv_state = TS_SB;
1876*0Sstevel@tonic-gate 				continue;
1877*0Sstevel@tonic-gate 
1878*0Sstevel@tonic-gate 			case IAC:
1879*0Sstevel@tonic-gate 				TTYADD(IAC);
1880*0Sstevel@tonic-gate 				break;
1881*0Sstevel@tonic-gate 
1882*0Sstevel@tonic-gate 			case NOP:
1883*0Sstevel@tonic-gate 			case GA:
1884*0Sstevel@tonic-gate 			default:
1885*0Sstevel@tonic-gate 				printoption("RCVD", IAC, c);
1886*0Sstevel@tonic-gate 				break;
1887*0Sstevel@tonic-gate 			}
1888*0Sstevel@tonic-gate 			telrcv_state = TS_DATA;
1889*0Sstevel@tonic-gate 			continue;
1890*0Sstevel@tonic-gate 
1891*0Sstevel@tonic-gate 		case TS_WILL:
1892*0Sstevel@tonic-gate 			printoption("RCVD", WILL, c);
1893*0Sstevel@tonic-gate 			willoption(c);
1894*0Sstevel@tonic-gate 			telrcv_state = TS_DATA;
1895*0Sstevel@tonic-gate 			continue;
1896*0Sstevel@tonic-gate 
1897*0Sstevel@tonic-gate 		case TS_WONT:
1898*0Sstevel@tonic-gate 			printoption("RCVD", WONT, c);
1899*0Sstevel@tonic-gate 			wontoption(c);
1900*0Sstevel@tonic-gate 			telrcv_state = TS_DATA;
1901*0Sstevel@tonic-gate 			continue;
1902*0Sstevel@tonic-gate 
1903*0Sstevel@tonic-gate 		case TS_DO:
1904*0Sstevel@tonic-gate 			printoption("RCVD", DO, c);
1905*0Sstevel@tonic-gate 			dooption(c);
1906*0Sstevel@tonic-gate 			if (c == TELOPT_NAWS) {
1907*0Sstevel@tonic-gate 				sendnaws();
1908*0Sstevel@tonic-gate 			} else if (c == TELOPT_LFLOW) {
1909*0Sstevel@tonic-gate 				localflow = 1;
1910*0Sstevel@tonic-gate 				setcommandmode();
1911*0Sstevel@tonic-gate 				setconnmode(0);
1912*0Sstevel@tonic-gate 			}
1913*0Sstevel@tonic-gate 			telrcv_state = TS_DATA;
1914*0Sstevel@tonic-gate 			continue;
1915*0Sstevel@tonic-gate 
1916*0Sstevel@tonic-gate 		case TS_DONT:
1917*0Sstevel@tonic-gate 			printoption("RCVD", DONT, c);
1918*0Sstevel@tonic-gate 			dontoption(c);
1919*0Sstevel@tonic-gate 			flushline = 1;
1920*0Sstevel@tonic-gate 			setconnmode(0);	/* set new tty mode (maybe) */
1921*0Sstevel@tonic-gate 			telrcv_state = TS_DATA;
1922*0Sstevel@tonic-gate 			continue;
1923*0Sstevel@tonic-gate 
1924*0Sstevel@tonic-gate 		case TS_SB:
1925*0Sstevel@tonic-gate 			if (c == IAC) {
1926*0Sstevel@tonic-gate 				telrcv_state = TS_SE;
1927*0Sstevel@tonic-gate 			} else {
1928*0Sstevel@tonic-gate 				SB_ACCUM(c);
1929*0Sstevel@tonic-gate 			}
1930*0Sstevel@tonic-gate 			continue;
1931*0Sstevel@tonic-gate 
1932*0Sstevel@tonic-gate 		case TS_SE:
1933*0Sstevel@tonic-gate 			if (c != SE) {
1934*0Sstevel@tonic-gate 				if (c != IAC) {
1935*0Sstevel@tonic-gate 			/*
1936*0Sstevel@tonic-gate 			 * This is an error.  We only expect to get
1937*0Sstevel@tonic-gate 			 * "IAC IAC" or "IAC SE".  Several things may
1938*0Sstevel@tonic-gate 			 * have happend.  An IAC was not doubled, the
1939*0Sstevel@tonic-gate 			 * IAC SE was left off, or another option got
1940*0Sstevel@tonic-gate 			 * inserted into the suboption are all possibilities.
1941*0Sstevel@tonic-gate 			 * If we assume that the IAC was not doubled,
1942*0Sstevel@tonic-gate 			 * and really the IAC SE was left off, we could
1943*0Sstevel@tonic-gate 			 * get into an infinate loop here.  So, instead,
1944*0Sstevel@tonic-gate 			 * we terminate the suboption, and process the
1945*0Sstevel@tonic-gate 			 * partial suboption if we can.
1946*0Sstevel@tonic-gate 			 */
1947*0Sstevel@tonic-gate 					SB_ACCUM(IAC);
1948*0Sstevel@tonic-gate 					SB_ACCUM(c);
1949*0Sstevel@tonic-gate 					subpointer -= 2;
1950*0Sstevel@tonic-gate 					SB_TERM();
1951*0Sstevel@tonic-gate 
1952*0Sstevel@tonic-gate 					printoption("In SUBOPTION processing, "
1953*0Sstevel@tonic-gate 					    "RCVD", IAC, c);
1954*0Sstevel@tonic-gate 					suboption();	/* handle sub-option */
1955*0Sstevel@tonic-gate 					telrcv_state = TS_IAC;
1956*0Sstevel@tonic-gate 					goto process_iac;
1957*0Sstevel@tonic-gate 				}
1958*0Sstevel@tonic-gate 				SB_ACCUM(c);
1959*0Sstevel@tonic-gate 				telrcv_state = TS_SB;
1960*0Sstevel@tonic-gate 			} else {
1961*0Sstevel@tonic-gate 				SB_ACCUM(IAC);
1962*0Sstevel@tonic-gate 				SB_ACCUM(SE);
1963*0Sstevel@tonic-gate 				subpointer -= 2;
1964*0Sstevel@tonic-gate 				SB_TERM();
1965*0Sstevel@tonic-gate 				suboption();	/* handle sub-option */
1966*0Sstevel@tonic-gate 				telrcv_state = TS_DATA;
1967*0Sstevel@tonic-gate 			}
1968*0Sstevel@tonic-gate 		}
1969*0Sstevel@tonic-gate 	}
1970*0Sstevel@tonic-gate 	if (count)
1971*0Sstevel@tonic-gate 		ring_consumed(&netiring, count);
1972*0Sstevel@tonic-gate 	return (returnValue||count);
1973*0Sstevel@tonic-gate }
1974*0Sstevel@tonic-gate 
1975*0Sstevel@tonic-gate static int bol = 1, local = 0;
1976*0Sstevel@tonic-gate 
1977*0Sstevel@tonic-gate int
rlogin_susp()1978*0Sstevel@tonic-gate rlogin_susp()
1979*0Sstevel@tonic-gate {
1980*0Sstevel@tonic-gate 	if (local) {
1981*0Sstevel@tonic-gate 		local = 0;
1982*0Sstevel@tonic-gate 		bol = 1;
1983*0Sstevel@tonic-gate 		command(0, "z\n", 2);
1984*0Sstevel@tonic-gate 		return (1);
1985*0Sstevel@tonic-gate 	}
1986*0Sstevel@tonic-gate 	return (0);
1987*0Sstevel@tonic-gate }
1988*0Sstevel@tonic-gate 
1989*0Sstevel@tonic-gate static int
telsnd()1990*0Sstevel@tonic-gate telsnd()
1991*0Sstevel@tonic-gate {
1992*0Sstevel@tonic-gate 	int tcc;
1993*0Sstevel@tonic-gate 	int count;
1994*0Sstevel@tonic-gate 	int returnValue = 0;
1995*0Sstevel@tonic-gate 	unsigned char *tbp;
1996*0Sstevel@tonic-gate 
1997*0Sstevel@tonic-gate 	tcc = 0;
1998*0Sstevel@tonic-gate 	count = 0;
1999*0Sstevel@tonic-gate 	while (NETROOM() > 2) {
2000*0Sstevel@tonic-gate 		register int sc;
2001*0Sstevel@tonic-gate 		register int c;
2002*0Sstevel@tonic-gate 
2003*0Sstevel@tonic-gate 		if (tcc == 0) {
2004*0Sstevel@tonic-gate 			if (count) {
2005*0Sstevel@tonic-gate 				ring_consumed(&ttyiring, count);
2006*0Sstevel@tonic-gate 				returnValue = 1;
2007*0Sstevel@tonic-gate 				count = 0;
2008*0Sstevel@tonic-gate 			}
2009*0Sstevel@tonic-gate 			tbp = ttyiring.consume;
2010*0Sstevel@tonic-gate 			tcc = ring_full_consecutive(&ttyiring);
2011*0Sstevel@tonic-gate 			if (tcc == 0) {
2012*0Sstevel@tonic-gate 				break;
2013*0Sstevel@tonic-gate 			}
2014*0Sstevel@tonic-gate 		}
2015*0Sstevel@tonic-gate 		c = *tbp++ & 0xff, sc = strip(c), tcc--; count++;
2016*0Sstevel@tonic-gate 		if (rlogin != _POSIX_VDISABLE) {
2017*0Sstevel@tonic-gate 			if (bol) {
2018*0Sstevel@tonic-gate 				bol = 0;
2019*0Sstevel@tonic-gate 				if (sc == rlogin) {
2020*0Sstevel@tonic-gate 					local = 1;
2021*0Sstevel@tonic-gate 					continue;
2022*0Sstevel@tonic-gate 				}
2023*0Sstevel@tonic-gate 			} else if (local) {
2024*0Sstevel@tonic-gate 				local = 0;
2025*0Sstevel@tonic-gate 				if (sc == '.' || c == termEofChar) {
2026*0Sstevel@tonic-gate 					bol = 1;
2027*0Sstevel@tonic-gate 					command(0, "close\n", 6);
2028*0Sstevel@tonic-gate 					continue;
2029*0Sstevel@tonic-gate 				}
2030*0Sstevel@tonic-gate 				if (sc == termSuspChar) {
2031*0Sstevel@tonic-gate 					bol = 1;
2032*0Sstevel@tonic-gate 					command(0, "z\n", 2);
2033*0Sstevel@tonic-gate 					continue;
2034*0Sstevel@tonic-gate 				}
2035*0Sstevel@tonic-gate 				if (sc == escape) {
2036*0Sstevel@tonic-gate 					command(0, (char *)tbp, tcc);
2037*0Sstevel@tonic-gate 					bol = 1;
2038*0Sstevel@tonic-gate 					count += tcc;
2039*0Sstevel@tonic-gate 					tcc = 0;
2040*0Sstevel@tonic-gate 					flushline = 1;
2041*0Sstevel@tonic-gate 					break;
2042*0Sstevel@tonic-gate 				}
2043*0Sstevel@tonic-gate 				if (sc != rlogin) {
2044*0Sstevel@tonic-gate 					++tcc;
2045*0Sstevel@tonic-gate 					--tbp;
2046*0Sstevel@tonic-gate 					--count;
2047*0Sstevel@tonic-gate 					c = sc = rlogin;
2048*0Sstevel@tonic-gate 				}
2049*0Sstevel@tonic-gate 			}
2050*0Sstevel@tonic-gate 			if ((sc == '\n') || (sc == '\r'))
2051*0Sstevel@tonic-gate 				bol = 1;
2052*0Sstevel@tonic-gate 		} else if (sc == escape && escape_valid) {
2053*0Sstevel@tonic-gate 			/*
2054*0Sstevel@tonic-gate 			 * Double escape is a pass through of a single
2055*0Sstevel@tonic-gate 			 * escape character.
2056*0Sstevel@tonic-gate 			 */
2057*0Sstevel@tonic-gate 			if (tcc && strip(*tbp) == escape) {
2058*0Sstevel@tonic-gate 				tbp++;
2059*0Sstevel@tonic-gate 				tcc--;
2060*0Sstevel@tonic-gate 				count++;
2061*0Sstevel@tonic-gate 				bol = 0;
2062*0Sstevel@tonic-gate 			} else {
2063*0Sstevel@tonic-gate 				command(0, (char *)tbp, tcc);
2064*0Sstevel@tonic-gate 				bol = 1;
2065*0Sstevel@tonic-gate 				count += tcc;
2066*0Sstevel@tonic-gate 				tcc = 0;
2067*0Sstevel@tonic-gate 				flushline = 1;
2068*0Sstevel@tonic-gate 				break;
2069*0Sstevel@tonic-gate 			}
2070*0Sstevel@tonic-gate 		} else
2071*0Sstevel@tonic-gate 			bol = 0;
2072*0Sstevel@tonic-gate #ifdef	KLUDGELINEMODE
2073*0Sstevel@tonic-gate 		if (kludgelinemode && (globalmode&MODE_EDIT) && (sc == echoc)) {
2074*0Sstevel@tonic-gate 			if (tcc > 0 && strip(*tbp) == echoc) {
2075*0Sstevel@tonic-gate 				tcc--; tbp++; count++;
2076*0Sstevel@tonic-gate 			} else {
2077*0Sstevel@tonic-gate 				dontlecho = !dontlecho;
2078*0Sstevel@tonic-gate 				settimer(echotoggle);
2079*0Sstevel@tonic-gate 				setconnmode(0);
2080*0Sstevel@tonic-gate 				flushline = 1;
2081*0Sstevel@tonic-gate 				break;
2082*0Sstevel@tonic-gate 			}
2083*0Sstevel@tonic-gate 		}
2084*0Sstevel@tonic-gate #endif
2085*0Sstevel@tonic-gate 		if (MODE_LOCAL_CHARS(globalmode)) {
2086*0Sstevel@tonic-gate 			if (TerminalSpecialChars(sc) == 0) {
2087*0Sstevel@tonic-gate 				bol = 1;
2088*0Sstevel@tonic-gate 				break;
2089*0Sstevel@tonic-gate 			}
2090*0Sstevel@tonic-gate 		}
2091*0Sstevel@tonic-gate 		if (my_want_state_is_wont(TELOPT_BINARY)) {
2092*0Sstevel@tonic-gate 			switch (c) {
2093*0Sstevel@tonic-gate 			case '\n':
2094*0Sstevel@tonic-gate 				/*
2095*0Sstevel@tonic-gate 				 * If we are in CRMOD mode (\r ==> \n)
2096*0Sstevel@tonic-gate 				 * on our local machine, then probably
2097*0Sstevel@tonic-gate 				 * a newline (unix) is CRLF (TELNET).
2098*0Sstevel@tonic-gate 				 */
2099*0Sstevel@tonic-gate 				if (MODE_LOCAL_CHARS(globalmode)) {
2100*0Sstevel@tonic-gate 					NETADD('\r');
2101*0Sstevel@tonic-gate 				}
2102*0Sstevel@tonic-gate 				NETADD('\n');
2103*0Sstevel@tonic-gate 				bol = flushline = 1;
2104*0Sstevel@tonic-gate 				break;
2105*0Sstevel@tonic-gate 			case '\r':
2106*0Sstevel@tonic-gate 				if (!crlf) {
2107*0Sstevel@tonic-gate 					NET2ADD('\r', '\0');
2108*0Sstevel@tonic-gate 				} else {
2109*0Sstevel@tonic-gate 					NET2ADD('\r', '\n');
2110*0Sstevel@tonic-gate 				}
2111*0Sstevel@tonic-gate 				bol = flushline = 1;
2112*0Sstevel@tonic-gate 				break;
2113*0Sstevel@tonic-gate 			case IAC:
2114*0Sstevel@tonic-gate 				NET2ADD(IAC, IAC);
2115*0Sstevel@tonic-gate 				break;
2116*0Sstevel@tonic-gate 			default:
2117*0Sstevel@tonic-gate 				NETADD(c);
2118*0Sstevel@tonic-gate 				break;
2119*0Sstevel@tonic-gate 			}
2120*0Sstevel@tonic-gate 		} else if (c == IAC) {
2121*0Sstevel@tonic-gate 			NET2ADD(IAC, IAC);
2122*0Sstevel@tonic-gate 		} else {
2123*0Sstevel@tonic-gate 			NETADD(c);
2124*0Sstevel@tonic-gate 		}
2125*0Sstevel@tonic-gate 	}
2126*0Sstevel@tonic-gate 	if (count)
2127*0Sstevel@tonic-gate 		ring_consumed(&ttyiring, count);
2128*0Sstevel@tonic-gate 	return (returnValue||count);	/* Non-zero if we did anything */
2129*0Sstevel@tonic-gate }
2130*0Sstevel@tonic-gate 
2131*0Sstevel@tonic-gate /*
2132*0Sstevel@tonic-gate  * Scheduler()
2133*0Sstevel@tonic-gate  *
2134*0Sstevel@tonic-gate  * Try to do something.
2135*0Sstevel@tonic-gate  *
2136*0Sstevel@tonic-gate  * If we do something useful, return 1; else return 0.
2137*0Sstevel@tonic-gate  *
2138*0Sstevel@tonic-gate  */
2139*0Sstevel@tonic-gate 
2140*0Sstevel@tonic-gate 
2141*0Sstevel@tonic-gate int
Scheduler(block)2142*0Sstevel@tonic-gate Scheduler(block)
2143*0Sstevel@tonic-gate 	int	block;		/* should we block in the select ? */
2144*0Sstevel@tonic-gate {
2145*0Sstevel@tonic-gate 	/*
2146*0Sstevel@tonic-gate 	 * One wants to be a bit careful about setting returnValue
2147*0Sstevel@tonic-gate 	 * to one, since a one implies we did some useful work,
2148*0Sstevel@tonic-gate 	 * and therefore probably won't be called to block next
2149*0Sstevel@tonic-gate 	 * time (TN3270 mode only).
2150*0Sstevel@tonic-gate 	 */
2151*0Sstevel@tonic-gate 	int returnValue;
2152*0Sstevel@tonic-gate 	int netin, netout, netex, ttyin, ttyout;
2153*0Sstevel@tonic-gate 
2154*0Sstevel@tonic-gate 	/* Decide which rings should be processed */
2155*0Sstevel@tonic-gate 
2156*0Sstevel@tonic-gate 	netout = ring_full_count(&netoring) &&
2157*0Sstevel@tonic-gate 	    (flushline ||
2158*0Sstevel@tonic-gate 	    (my_want_state_is_wont(TELOPT_LINEMODE)
2159*0Sstevel@tonic-gate #ifdef	KLUDGELINEMODE
2160*0Sstevel@tonic-gate 	    /* X */ && (!kludgelinemode || my_want_state_is_do(TELOPT_SGA))
2161*0Sstevel@tonic-gate #endif
2162*0Sstevel@tonic-gate 	    /* XXX */) ||
2163*0Sstevel@tonic-gate 	    my_want_state_is_will(TELOPT_BINARY));
2164*0Sstevel@tonic-gate 	ttyout = ring_full_count(&ttyoring);
2165*0Sstevel@tonic-gate 
2166*0Sstevel@tonic-gate 	ttyin = (ring_empty_count(&ttyiring) && !eof_pending);
2167*0Sstevel@tonic-gate 
2168*0Sstevel@tonic-gate 	netin = !ISend && ring_empty_count(&netiring);
2169*0Sstevel@tonic-gate 
2170*0Sstevel@tonic-gate 	netex = !SYNCHing;
2171*0Sstevel@tonic-gate 
2172*0Sstevel@tonic-gate 	if (scheduler_lockout_tty) {
2173*0Sstevel@tonic-gate 		ttyin = ttyout = 0;
2174*0Sstevel@tonic-gate 	}
2175*0Sstevel@tonic-gate 
2176*0Sstevel@tonic-gate 	/* Call to system code to process rings */
2177*0Sstevel@tonic-gate 
2178*0Sstevel@tonic-gate 	returnValue = process_rings(netin, netout, netex, ttyin, ttyout,
2179*0Sstevel@tonic-gate 	    !block);
2180*0Sstevel@tonic-gate 
2181*0Sstevel@tonic-gate 	/* Now, look at the input rings, looking for work to do. */
2182*0Sstevel@tonic-gate 
2183*0Sstevel@tonic-gate 	if (ring_full_count(&ttyiring)) {
2184*0Sstevel@tonic-gate 		returnValue |= telsnd();
2185*0Sstevel@tonic-gate 	} else {
2186*0Sstevel@tonic-gate 		/*
2187*0Sstevel@tonic-gate 		 * If ttyiring is empty, check to see if there is a real EOF
2188*0Sstevel@tonic-gate 		 * pending.  If so, we can maybe do the EOF write now.
2189*0Sstevel@tonic-gate 		 */
2190*0Sstevel@tonic-gate 		if (eof_pending) {
2191*0Sstevel@tonic-gate 			eof_pending = 0;
2192*0Sstevel@tonic-gate 			sendeof();
2193*0Sstevel@tonic-gate 		}
2194*0Sstevel@tonic-gate 	}
2195*0Sstevel@tonic-gate 
2196*0Sstevel@tonic-gate 	if (ring_full_count(&netiring)) {
2197*0Sstevel@tonic-gate 		returnValue |= telrcv();
2198*0Sstevel@tonic-gate 	}
2199*0Sstevel@tonic-gate 	return (returnValue);
2200*0Sstevel@tonic-gate }
2201*0Sstevel@tonic-gate 
2202*0Sstevel@tonic-gate /*
2203*0Sstevel@tonic-gate  * Select from tty and network...
2204*0Sstevel@tonic-gate  */
2205*0Sstevel@tonic-gate void
telnet(user)2206*0Sstevel@tonic-gate telnet(user)
2207*0Sstevel@tonic-gate 	char *user;
2208*0Sstevel@tonic-gate {
2209*0Sstevel@tonic-gate 	sys_telnet_init();
2210*0Sstevel@tonic-gate 
2211*0Sstevel@tonic-gate 	{
2212*0Sstevel@tonic-gate 		static char local_host[MAXHOSTNAMELEN] = { 0 };
2213*0Sstevel@tonic-gate 
2214*0Sstevel@tonic-gate 		if (!local_host[0]) {
2215*0Sstevel@tonic-gate 			(void) gethostname(local_host, sizeof (local_host));
2216*0Sstevel@tonic-gate 			local_host[sizeof (local_host)-1] = 0;
2217*0Sstevel@tonic-gate 		}
2218*0Sstevel@tonic-gate 		auth_encrypt_init(local_host, hostname, "TELNET");
2219*0Sstevel@tonic-gate 		auth_encrypt_user(user);
2220*0Sstevel@tonic-gate 	}
2221*0Sstevel@tonic-gate 
2222*0Sstevel@tonic-gate 	if (autologin)
2223*0Sstevel@tonic-gate 		send_will(TELOPT_AUTHENTICATION, 1);
2224*0Sstevel@tonic-gate 
2225*0Sstevel@tonic-gate 	if (telnetport || wantencryption) {
2226*0Sstevel@tonic-gate 		send_do(TELOPT_ENCRYPT, 1);
2227*0Sstevel@tonic-gate 		send_will(TELOPT_ENCRYPT, 1);
2228*0Sstevel@tonic-gate 	}
2229*0Sstevel@tonic-gate 
2230*0Sstevel@tonic-gate 	if (telnetport) {
2231*0Sstevel@tonic-gate 		if (!reqd_linemode)
2232*0Sstevel@tonic-gate 		    send_do(TELOPT_SGA, 1);
2233*0Sstevel@tonic-gate 		send_will(TELOPT_TTYPE, 1);
2234*0Sstevel@tonic-gate 		send_will(TELOPT_NAWS, 1);
2235*0Sstevel@tonic-gate 		send_will(TELOPT_TSPEED, 1);
2236*0Sstevel@tonic-gate 		send_will(TELOPT_LFLOW, 1);
2237*0Sstevel@tonic-gate 		if (!reqd_linemode)
2238*0Sstevel@tonic-gate 		    send_will(TELOPT_LINEMODE, 1);
2239*0Sstevel@tonic-gate 		send_will(TELOPT_NEW_ENVIRON, 1);
2240*0Sstevel@tonic-gate 		send_do(TELOPT_STATUS, 1);
2241*0Sstevel@tonic-gate 		if (env_getvalue((unsigned char *)"DISPLAY"))
2242*0Sstevel@tonic-gate 			send_will(TELOPT_XDISPLOC, 1);
2243*0Sstevel@tonic-gate 		if (eight)
2244*0Sstevel@tonic-gate 			tel_enter_binary(eight);
2245*0Sstevel@tonic-gate 	}
2246*0Sstevel@tonic-gate 
2247*0Sstevel@tonic-gate 	/*
2248*0Sstevel@tonic-gate 	 * Note: we assume a tie to the authentication option here.  This
2249*0Sstevel@tonic-gate 	 * is necessary so that authentication fails, we don't spin
2250*0Sstevel@tonic-gate 	 * forever.
2251*0Sstevel@tonic-gate 	 */
2252*0Sstevel@tonic-gate 	if (wantencryption) {
2253*0Sstevel@tonic-gate 		boolean_t printed_encrypt = B_FALSE;
2254*0Sstevel@tonic-gate 		extern boolean_t auth_has_failed;
2255*0Sstevel@tonic-gate 		time_t timeout = time(0) + 60;
2256*0Sstevel@tonic-gate 
2257*0Sstevel@tonic-gate 		send_do(TELOPT_ENCRYPT, 1);
2258*0Sstevel@tonic-gate 		send_will(TELOPT_ENCRYPT, 1);
2259*0Sstevel@tonic-gate 		for (;;) {
2260*0Sstevel@tonic-gate 		    if (my_want_state_is_wont(TELOPT_AUTHENTICATION)) {
2261*0Sstevel@tonic-gate 			(void) printf(gettext(
2262*0Sstevel@tonic-gate 				"\nServer refused to negotiate "
2263*0Sstevel@tonic-gate 				"authentication, which is required\n"
2264*0Sstevel@tonic-gate 				"for encryption.  Good-bye.\n\r"));
2265*0Sstevel@tonic-gate 			Exit(EXIT_FAILURE);
2266*0Sstevel@tonic-gate 		    }
2267*0Sstevel@tonic-gate 		    if (auth_has_failed) {
2268*0Sstevel@tonic-gate 			(void) printf(gettext(
2269*0Sstevel@tonic-gate 			    "\nAuthentication negotation has failed, "
2270*0Sstevel@tonic-gate 			    "which is required for\n"
2271*0Sstevel@tonic-gate 			    "encryption.  Good-bye.\n\r"));
2272*0Sstevel@tonic-gate 			Exit(EXIT_FAILURE);
2273*0Sstevel@tonic-gate 		    }
2274*0Sstevel@tonic-gate 		    if (my_want_state_is_dont(TELOPT_ENCRYPT) ||
2275*0Sstevel@tonic-gate 			my_want_state_is_wont(TELOPT_ENCRYPT)) {
2276*0Sstevel@tonic-gate 			    (void) printf(gettext(
2277*0Sstevel@tonic-gate 				"\nServer refused to negotiate encryption.  "
2278*0Sstevel@tonic-gate 				"Good-bye.\n\r"));
2279*0Sstevel@tonic-gate 			    Exit(EXIT_FAILURE);
2280*0Sstevel@tonic-gate 		    }
2281*0Sstevel@tonic-gate 		    if (encrypt_is_encrypting())
2282*0Sstevel@tonic-gate 			break;
2283*0Sstevel@tonic-gate 
2284*0Sstevel@tonic-gate 		    if (time(0) > timeout) {
2285*0Sstevel@tonic-gate 			(void) printf(gettext(
2286*0Sstevel@tonic-gate 				"\nEncryption could not be enabled.  "
2287*0Sstevel@tonic-gate 				"Good-bye.\n\r"));
2288*0Sstevel@tonic-gate 			Exit(EXIT_FAILURE);
2289*0Sstevel@tonic-gate 		    }
2290*0Sstevel@tonic-gate 		    if (printed_encrypt == B_FALSE) {
2291*0Sstevel@tonic-gate 			printed_encrypt = B_TRUE;
2292*0Sstevel@tonic-gate 			(void) printf(gettext(
2293*0Sstevel@tonic-gate 			    "Waiting for encryption to be negotiated...\n"));
2294*0Sstevel@tonic-gate 			/*
2295*0Sstevel@tonic-gate 			 * Turn on MODE_TRAPSIG and then turn off localchars
2296*0Sstevel@tonic-gate 			 * so that ^C will cause telnet to exit.
2297*0Sstevel@tonic-gate 			 */
2298*0Sstevel@tonic-gate 			TerminalNewMode(getconnmode()|MODE_TRAPSIG);
2299*0Sstevel@tonic-gate 			intr_waiting = 1;
2300*0Sstevel@tonic-gate 		    }
2301*0Sstevel@tonic-gate 		    if (intr_happened) {
2302*0Sstevel@tonic-gate 			(void) printf(gettext(
2303*0Sstevel@tonic-gate 			    "\nUser requested an interrupt.  Good-bye.\n\r"));
2304*0Sstevel@tonic-gate 			Exit(EXIT_FAILURE);
2305*0Sstevel@tonic-gate 		    }
2306*0Sstevel@tonic-gate 		    telnet_spin();
2307*0Sstevel@tonic-gate 		}
2308*0Sstevel@tonic-gate 		if (printed_encrypt) {
2309*0Sstevel@tonic-gate 			(void) printf(gettext("done.\n"));
2310*0Sstevel@tonic-gate 			intr_waiting = 0;
2311*0Sstevel@tonic-gate 			setconnmode(0);
2312*0Sstevel@tonic-gate 		}
2313*0Sstevel@tonic-gate 	}
2314*0Sstevel@tonic-gate 
2315*0Sstevel@tonic-gate 	for (;;) {
2316*0Sstevel@tonic-gate 		int schedValue;
2317*0Sstevel@tonic-gate 
2318*0Sstevel@tonic-gate 		while ((schedValue = Scheduler(0)) != 0) {
2319*0Sstevel@tonic-gate 			if (schedValue == -1) {
2320*0Sstevel@tonic-gate 				setcommandmode();
2321*0Sstevel@tonic-gate 				return;
2322*0Sstevel@tonic-gate 			}
2323*0Sstevel@tonic-gate 		}
2324*0Sstevel@tonic-gate 
2325*0Sstevel@tonic-gate 		if (Scheduler(1) == -1) {
2326*0Sstevel@tonic-gate 			setcommandmode();
2327*0Sstevel@tonic-gate 			return;
2328*0Sstevel@tonic-gate 		}
2329*0Sstevel@tonic-gate 	}
2330*0Sstevel@tonic-gate }
2331*0Sstevel@tonic-gate 
2332*0Sstevel@tonic-gate #if	0	/* XXX - this not being in is a bug */
2333*0Sstevel@tonic-gate /*
2334*0Sstevel@tonic-gate  * nextitem()
2335*0Sstevel@tonic-gate  *
2336*0Sstevel@tonic-gate  *	Return the address of the next "item" in the TELNET data
2337*0Sstevel@tonic-gate  * stream.  This will be the address of the next character if
2338*0Sstevel@tonic-gate  * the current address is a user data character, or it will
2339*0Sstevel@tonic-gate  * be the address of the character following the TELNET command
2340*0Sstevel@tonic-gate  * if the current address is a TELNET IAC ("I Am a Command")
2341*0Sstevel@tonic-gate  * character.
2342*0Sstevel@tonic-gate  */
2343*0Sstevel@tonic-gate 
2344*0Sstevel@tonic-gate static char *
2345*0Sstevel@tonic-gate nextitem(current)
2346*0Sstevel@tonic-gate 	char *current;
2347*0Sstevel@tonic-gate {
2348*0Sstevel@tonic-gate 	if ((*current&0xff) != IAC) {
2349*0Sstevel@tonic-gate 		return (current+1);
2350*0Sstevel@tonic-gate 	}
2351*0Sstevel@tonic-gate 	switch (*(current+1)&0xff) {
2352*0Sstevel@tonic-gate 	case DO:
2353*0Sstevel@tonic-gate 	case DONT:
2354*0Sstevel@tonic-gate 	case WILL:
2355*0Sstevel@tonic-gate 	case WONT:
2356*0Sstevel@tonic-gate 		return (current+3);
2357*0Sstevel@tonic-gate 	case SB:		/* loop forever looking for the SE */
2358*0Sstevel@tonic-gate 	{
2359*0Sstevel@tonic-gate 		register char *look = current+2;
2360*0Sstevel@tonic-gate 
2361*0Sstevel@tonic-gate 		for (;;) {
2362*0Sstevel@tonic-gate 			if ((*look++&0xff) == IAC) {
2363*0Sstevel@tonic-gate 				if ((*look++&0xff) == SE) {
2364*0Sstevel@tonic-gate 					return (look);
2365*0Sstevel@tonic-gate 				}
2366*0Sstevel@tonic-gate 			}
2367*0Sstevel@tonic-gate 		}
2368*0Sstevel@tonic-gate 	}
2369*0Sstevel@tonic-gate 	default:
2370*0Sstevel@tonic-gate 		return (current+2);
2371*0Sstevel@tonic-gate 	}
2372*0Sstevel@tonic-gate }
2373*0Sstevel@tonic-gate #endif	/* 0 */
2374*0Sstevel@tonic-gate 
2375*0Sstevel@tonic-gate /*
2376*0Sstevel@tonic-gate  * netclear()
2377*0Sstevel@tonic-gate  *
2378*0Sstevel@tonic-gate  *	We are about to do a TELNET SYNCH operation.  Clear
2379*0Sstevel@tonic-gate  * the path to the network.
2380*0Sstevel@tonic-gate  *
2381*0Sstevel@tonic-gate  *	Things are a bit tricky since we may have sent the first
2382*0Sstevel@tonic-gate  * byte or so of a previous TELNET command into the network.
2383*0Sstevel@tonic-gate  * So, we have to scan the network buffer from the beginning
2384*0Sstevel@tonic-gate  * until we are up to where we want to be.
2385*0Sstevel@tonic-gate  *
2386*0Sstevel@tonic-gate  *	A side effect of what we do, just to keep things
2387*0Sstevel@tonic-gate  * simple, is to clear the urgent data pointer.  The principal
2388*0Sstevel@tonic-gate  * caller should be setting the urgent data pointer AFTER calling
2389*0Sstevel@tonic-gate  * us in any case.
2390*0Sstevel@tonic-gate  */
2391*0Sstevel@tonic-gate 
2392*0Sstevel@tonic-gate static void
netclear()2393*0Sstevel@tonic-gate netclear()
2394*0Sstevel@tonic-gate {
2395*0Sstevel@tonic-gate #if	0	/* XXX */
2396*0Sstevel@tonic-gate 	register char *thisitem, *next;
2397*0Sstevel@tonic-gate 	char *good;
2398*0Sstevel@tonic-gate #define	wewant(p)	((nfrontp > p) && ((*p&0xff) == IAC) && \
2399*0Sstevel@tonic-gate 				((*(p+1)&0xff) != EC) && ((*(p+1)&0xff) != EL))
2400*0Sstevel@tonic-gate 
2401*0Sstevel@tonic-gate 	thisitem = netobuf;
2402*0Sstevel@tonic-gate 
2403*0Sstevel@tonic-gate 	while ((next = nextitem(thisitem)) <= netobuf.send) {
2404*0Sstevel@tonic-gate 		thisitem = next;
2405*0Sstevel@tonic-gate 	}
2406*0Sstevel@tonic-gate 
2407*0Sstevel@tonic-gate 	/* Now, thisitem is first before/at boundary. */
2408*0Sstevel@tonic-gate 
2409*0Sstevel@tonic-gate 	good = netobuf;	/* where the good bytes go */
2410*0Sstevel@tonic-gate 
2411*0Sstevel@tonic-gate 	while (netoring.add > thisitem) {
2412*0Sstevel@tonic-gate 		if (wewant(thisitem)) {
2413*0Sstevel@tonic-gate 			int length;
2414*0Sstevel@tonic-gate 
2415*0Sstevel@tonic-gate 			next = thisitem;
2416*0Sstevel@tonic-gate 			do {
2417*0Sstevel@tonic-gate 				next = nextitem(next);
2418*0Sstevel@tonic-gate 			} while (wewant(next) && (nfrontp > next));
2419*0Sstevel@tonic-gate 			length = next-thisitem;
2420*0Sstevel@tonic-gate 			memcpy(good, thisitem, length);
2421*0Sstevel@tonic-gate 			good += length;
2422*0Sstevel@tonic-gate 			thisitem = next;
2423*0Sstevel@tonic-gate 		} else {
2424*0Sstevel@tonic-gate 			thisitem = nextitem(thisitem);
2425*0Sstevel@tonic-gate 		}
2426*0Sstevel@tonic-gate 	}
2427*0Sstevel@tonic-gate 
2428*0Sstevel@tonic-gate #endif	/* 0 */
2429*0Sstevel@tonic-gate }
2430*0Sstevel@tonic-gate 
2431*0Sstevel@tonic-gate /*
2432*0Sstevel@tonic-gate  * These routines add various telnet commands to the data stream.
2433*0Sstevel@tonic-gate  */
2434*0Sstevel@tonic-gate 
2435*0Sstevel@tonic-gate /*
2436*0Sstevel@tonic-gate  * doflush -  Send do timing mark (for network connection flush) & then
2437*0Sstevel@tonic-gate  * get rid of anything in the output buffer.  Return -1 if there was a
2438*0Sstevel@tonic-gate  * non-EWOULDBLOCK error on the tty flush, and otherwise return 0.
2439*0Sstevel@tonic-gate  */
2440*0Sstevel@tonic-gate static int
doflush()2441*0Sstevel@tonic-gate doflush()
2442*0Sstevel@tonic-gate {
2443*0Sstevel@tonic-gate 	NET2ADD(IAC, DO);
2444*0Sstevel@tonic-gate 	NETADD(TELOPT_TM);
2445*0Sstevel@tonic-gate 	flushline = 1;
2446*0Sstevel@tonic-gate 	flushout = 1;
2447*0Sstevel@tonic-gate 
2448*0Sstevel@tonic-gate 	/* Drop pending tty output */
2449*0Sstevel@tonic-gate 	if (ttyflush(1) == -2)
2450*0Sstevel@tonic-gate 		return (-1);
2451*0Sstevel@tonic-gate 
2452*0Sstevel@tonic-gate 	/* do printoption AFTER flush, otherwise the output gets tossed... */
2453*0Sstevel@tonic-gate 	printoption("SENT", DO, TELOPT_TM);
2454*0Sstevel@tonic-gate 	return (0);
2455*0Sstevel@tonic-gate }
2456*0Sstevel@tonic-gate 
2457*0Sstevel@tonic-gate int
xmitAO()2458*0Sstevel@tonic-gate xmitAO()
2459*0Sstevel@tonic-gate {
2460*0Sstevel@tonic-gate 	NET2ADD(IAC, AO);
2461*0Sstevel@tonic-gate 	printoption("SENT", IAC, AO);
2462*0Sstevel@tonic-gate 	if (autoflush) {
2463*0Sstevel@tonic-gate 		if (doflush() == -1)
2464*0Sstevel@tonic-gate 			return (-1);
2465*0Sstevel@tonic-gate 	}
2466*0Sstevel@tonic-gate 	return (0);
2467*0Sstevel@tonic-gate }
2468*0Sstevel@tonic-gate 
2469*0Sstevel@tonic-gate 
2470*0Sstevel@tonic-gate void
xmitEL()2471*0Sstevel@tonic-gate xmitEL()
2472*0Sstevel@tonic-gate {
2473*0Sstevel@tonic-gate 	NET2ADD(IAC, EL);
2474*0Sstevel@tonic-gate 	printoption("SENT", IAC, EL);
2475*0Sstevel@tonic-gate }
2476*0Sstevel@tonic-gate 
2477*0Sstevel@tonic-gate void
xmitEC()2478*0Sstevel@tonic-gate xmitEC()
2479*0Sstevel@tonic-gate {
2480*0Sstevel@tonic-gate 	NET2ADD(IAC, EC);
2481*0Sstevel@tonic-gate 	printoption("SENT", IAC, EC);
2482*0Sstevel@tonic-gate }
2483*0Sstevel@tonic-gate 
2484*0Sstevel@tonic-gate 
2485*0Sstevel@tonic-gate int
dosynch()2486*0Sstevel@tonic-gate dosynch()
2487*0Sstevel@tonic-gate {
2488*0Sstevel@tonic-gate 	netclear();			/* clear the path to the network */
2489*0Sstevel@tonic-gate 	NETADD(IAC);
2490*0Sstevel@tonic-gate 	setneturg();
2491*0Sstevel@tonic-gate 	NETADD(DM);
2492*0Sstevel@tonic-gate 	printoption("SENT", IAC, DM);
2493*0Sstevel@tonic-gate 	return (1);
2494*0Sstevel@tonic-gate }
2495*0Sstevel@tonic-gate 
2496*0Sstevel@tonic-gate int want_status_response = 0;
2497*0Sstevel@tonic-gate 
2498*0Sstevel@tonic-gate int
get_status()2499*0Sstevel@tonic-gate get_status()
2500*0Sstevel@tonic-gate {
2501*0Sstevel@tonic-gate 	unsigned char tmp[16];
2502*0Sstevel@tonic-gate 	register unsigned char *cp;
2503*0Sstevel@tonic-gate 
2504*0Sstevel@tonic-gate 	if (my_want_state_is_dont(TELOPT_STATUS)) {
2505*0Sstevel@tonic-gate 		(void) printf("Remote side does not support STATUS option\n");
2506*0Sstevel@tonic-gate 		return (0);
2507*0Sstevel@tonic-gate 	}
2508*0Sstevel@tonic-gate 	cp = tmp;
2509*0Sstevel@tonic-gate 
2510*0Sstevel@tonic-gate 	*cp++ = IAC;
2511*0Sstevel@tonic-gate 	*cp++ = SB;
2512*0Sstevel@tonic-gate 	*cp++ = TELOPT_STATUS;
2513*0Sstevel@tonic-gate 	*cp++ = TELQUAL_SEND;
2514*0Sstevel@tonic-gate 	*cp++ = IAC;
2515*0Sstevel@tonic-gate 	*cp++ = SE;
2516*0Sstevel@tonic-gate 	if (NETROOM() >= cp - tmp) {
2517*0Sstevel@tonic-gate 		ring_supply_data(&netoring, tmp, cp-tmp);
2518*0Sstevel@tonic-gate 		printsub('>', tmp+2, cp - tmp - 2);
2519*0Sstevel@tonic-gate 	}
2520*0Sstevel@tonic-gate 	++want_status_response;
2521*0Sstevel@tonic-gate 	return (1);
2522*0Sstevel@tonic-gate }
2523*0Sstevel@tonic-gate 
2524*0Sstevel@tonic-gate void
intp()2525*0Sstevel@tonic-gate intp()
2526*0Sstevel@tonic-gate {
2527*0Sstevel@tonic-gate 	NET2ADD(IAC, IP);
2528*0Sstevel@tonic-gate 	printoption("SENT", IAC, IP);
2529*0Sstevel@tonic-gate 	flushline = 1;
2530*0Sstevel@tonic-gate 	if (autoflush) {
2531*0Sstevel@tonic-gate 		/* Ignore return as we're ending off anyway. */
2532*0Sstevel@tonic-gate 		(void) doflush();
2533*0Sstevel@tonic-gate 	}
2534*0Sstevel@tonic-gate 	if (autosynch) {
2535*0Sstevel@tonic-gate 		(void) dosynch();
2536*0Sstevel@tonic-gate 	}
2537*0Sstevel@tonic-gate }
2538*0Sstevel@tonic-gate 
2539*0Sstevel@tonic-gate int
sendbrk()2540*0Sstevel@tonic-gate sendbrk()
2541*0Sstevel@tonic-gate {
2542*0Sstevel@tonic-gate 	NET2ADD(IAC, BREAK);
2543*0Sstevel@tonic-gate 	printoption("SENT", IAC, BREAK);
2544*0Sstevel@tonic-gate 	flushline = 1;
2545*0Sstevel@tonic-gate 	if (autoflush) {
2546*0Sstevel@tonic-gate 		if (doflush() == -1)
2547*0Sstevel@tonic-gate 			return (-1);
2548*0Sstevel@tonic-gate 	}
2549*0Sstevel@tonic-gate 	if (autosynch) {
2550*0Sstevel@tonic-gate 		(void) dosynch();
2551*0Sstevel@tonic-gate 	}
2552*0Sstevel@tonic-gate 	return (0);
2553*0Sstevel@tonic-gate }
2554*0Sstevel@tonic-gate 
2555*0Sstevel@tonic-gate void
sendabort()2556*0Sstevel@tonic-gate sendabort()
2557*0Sstevel@tonic-gate {
2558*0Sstevel@tonic-gate 	NET2ADD(IAC, ABORT);
2559*0Sstevel@tonic-gate 	printoption("SENT", IAC, ABORT);
2560*0Sstevel@tonic-gate 	flushline = 1;
2561*0Sstevel@tonic-gate 	if (autoflush) {
2562*0Sstevel@tonic-gate 		/*
2563*0Sstevel@tonic-gate 		 * Since sendabort() gets called while aborting,
2564*0Sstevel@tonic-gate 		 * ignore the doflush() return
2565*0Sstevel@tonic-gate 		 */
2566*0Sstevel@tonic-gate 		(void) doflush();
2567*0Sstevel@tonic-gate 	}
2568*0Sstevel@tonic-gate 	if (autosynch) {
2569*0Sstevel@tonic-gate 		(void) dosynch();
2570*0Sstevel@tonic-gate 	}
2571*0Sstevel@tonic-gate }
2572*0Sstevel@tonic-gate 
2573*0Sstevel@tonic-gate void
sendsusp()2574*0Sstevel@tonic-gate sendsusp()
2575*0Sstevel@tonic-gate {
2576*0Sstevel@tonic-gate 	NET2ADD(IAC, SUSP);
2577*0Sstevel@tonic-gate 	printoption("SENT", IAC, SUSP);
2578*0Sstevel@tonic-gate 	flushline = 1;
2579*0Sstevel@tonic-gate 	if (autoflush) {
2580*0Sstevel@tonic-gate 		if (doflush() == -1) {
2581*0Sstevel@tonic-gate 			/* The following will not return. */
2582*0Sstevel@tonic-gate 			fatal_tty_error("write");
2583*0Sstevel@tonic-gate 		}
2584*0Sstevel@tonic-gate 	}
2585*0Sstevel@tonic-gate 	if (autosynch) {
2586*0Sstevel@tonic-gate 		(void) dosynch();
2587*0Sstevel@tonic-gate 	}
2588*0Sstevel@tonic-gate }
2589*0Sstevel@tonic-gate 
2590*0Sstevel@tonic-gate static void
sendeof()2591*0Sstevel@tonic-gate sendeof()
2592*0Sstevel@tonic-gate {
2593*0Sstevel@tonic-gate 	NET2ADD(IAC, xEOF);
2594*0Sstevel@tonic-gate 	printoption("SENT", IAC, xEOF);
2595*0Sstevel@tonic-gate }
2596*0Sstevel@tonic-gate 
2597*0Sstevel@tonic-gate /*
2598*0Sstevel@tonic-gate  * Send a window size update to the remote system.
2599*0Sstevel@tonic-gate  */
2600*0Sstevel@tonic-gate 
2601*0Sstevel@tonic-gate void
sendnaws()2602*0Sstevel@tonic-gate sendnaws()
2603*0Sstevel@tonic-gate {
2604*0Sstevel@tonic-gate 	unsigned short rows, cols;
2605*0Sstevel@tonic-gate 	unsigned char tmp[16];
2606*0Sstevel@tonic-gate 	register unsigned char *cp;
2607*0Sstevel@tonic-gate 
2608*0Sstevel@tonic-gate 	if (my_state_is_wont(TELOPT_NAWS))
2609*0Sstevel@tonic-gate 		return;
2610*0Sstevel@tonic-gate 
2611*0Sstevel@tonic-gate #define	PUTSHORT(cp, x) { if ((*cp++ = ((x)>>8)&0xff) == IAC) *cp++ = IAC; \
2612*0Sstevel@tonic-gate 			    if ((*cp++ = ((x))&0xff) == IAC) *cp++ = IAC; }
2613*0Sstevel@tonic-gate 
2614*0Sstevel@tonic-gate 	if (TerminalWindowSize(&rows, &cols) == 0) {	/* Failed */
2615*0Sstevel@tonic-gate 		return;
2616*0Sstevel@tonic-gate 	}
2617*0Sstevel@tonic-gate 
2618*0Sstevel@tonic-gate 	cp = tmp;
2619*0Sstevel@tonic-gate 
2620*0Sstevel@tonic-gate 	*cp++ = IAC;
2621*0Sstevel@tonic-gate 	*cp++ = SB;
2622*0Sstevel@tonic-gate 	*cp++ = TELOPT_NAWS;
2623*0Sstevel@tonic-gate 	PUTSHORT(cp, cols);
2624*0Sstevel@tonic-gate 	PUTSHORT(cp, rows);
2625*0Sstevel@tonic-gate 	*cp++ = IAC;
2626*0Sstevel@tonic-gate 	*cp++ = SE;
2627*0Sstevel@tonic-gate 	if (NETROOM() >= cp - tmp) {
2628*0Sstevel@tonic-gate 		ring_supply_data(&netoring, tmp, cp-tmp);
2629*0Sstevel@tonic-gate 		printsub('>', tmp+2, cp - tmp - 2);
2630*0Sstevel@tonic-gate 	}
2631*0Sstevel@tonic-gate }
2632*0Sstevel@tonic-gate 
2633*0Sstevel@tonic-gate void
tel_enter_binary(rw)2634*0Sstevel@tonic-gate tel_enter_binary(rw)
2635*0Sstevel@tonic-gate 	int rw;
2636*0Sstevel@tonic-gate {
2637*0Sstevel@tonic-gate 	if (rw&1)
2638*0Sstevel@tonic-gate 		send_do(TELOPT_BINARY, 1);
2639*0Sstevel@tonic-gate 	if (rw&2)
2640*0Sstevel@tonic-gate 		send_will(TELOPT_BINARY, 1);
2641*0Sstevel@tonic-gate }
2642*0Sstevel@tonic-gate 
2643*0Sstevel@tonic-gate void
tel_leave_binary(rw)2644*0Sstevel@tonic-gate tel_leave_binary(rw)
2645*0Sstevel@tonic-gate 	int rw;
2646*0Sstevel@tonic-gate {
2647*0Sstevel@tonic-gate 	if (rw&1)
2648*0Sstevel@tonic-gate 		send_dont(TELOPT_BINARY, 1);
2649*0Sstevel@tonic-gate 	if (rw&2)
2650*0Sstevel@tonic-gate 		send_wont(TELOPT_BINARY, 1);
2651*0Sstevel@tonic-gate }
2652