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