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