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