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