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