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