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