xref: /freebsd/contrib/telnet/telnet/telnet.c (revision 3157ba21)
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
36 static 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 
74 static 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 
87 char	options[256];		/* The combined options */
88 char	do_dont_resp[256];
89 char	will_wont_resp[256];
90 
91 int
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 
117 char *prompt = 0;
118 #ifdef ENCRYPTION
119 char *line;		/* hack around breakage in sra.c :-( !! */
120 #endif
121 
122 cc_t escape;
123 cc_t rlogin;
124 #ifdef	KLUDGELINEMODE
125 cc_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 
141 static int	telrcv_state;
142 #ifdef	OLD_ENVIRON
143 unsigned char telopt_environ = TELOPT_NEW_ENVIRON;
144 #else
145 # define telopt_environ TELOPT_NEW_ENVIRON
146 #endif
147 
148 jmp_buf	toplevel;
149 
150 int	flushline;
151 int	linemode;
152 
153 #ifdef	KLUDGELINEMODE
154 int	kludgelinemode = 1;
155 #endif
156 
157 static 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 
164 Clocks clocks;
165 
166 /*
167  * Initialize telnet environment.
168  */
169 
170 void
171 init_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 
209 void
210 send_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 
226 void
227 send_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 
243 void
244 send_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 
260 void
261 send_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 
277 void
278 willoption(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 
339 void
340 wontoption(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 
387 static void
388 dooption(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 
496 static void
497 dontoption(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 
538 static const char *name_unknown = "UNKNOWN";
539 static const char *unknown[] = { NULL, NULL };
540 
541 static const char **
542 mklist(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 
651 static int
652 is_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
665 char termbuf[1024];
666 
667 /*ARGSUSED*/
668 static int
669 setupterm(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
683 extern char ttytype[];
684 #endif
685 
686 int resettermname = 1;
687 
688 static const char *
689 gettermname(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 
731 static void
732 suboption(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 
988 static unsigned char str_lm[] = { IAC, SB, TELOPT_LINEMODE, 0, 0, IAC, SE };
989 
990 void
991 lm_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 
1011 void
1012 lm_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 
1026 void
1027 lm_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 
1047 void
1048 lm_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 
1062 static unsigned char str_lm_mode[] = {
1063 	IAC, SB, TELOPT_LINEMODE, LM_MODE, 0, IAC, SE
1064 };
1065 
1066 void
1067 lm_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 
1094 struct 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
1104 static int slc_mode = SLC_EXPORT;
1105 
1106 void
1107 slc_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 
1168 void
1169 slcstate(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 
1177 void
1178 slc_mode_export(void)
1179 {
1180     slc_mode = SLC_EXPORT;
1181     if (my_state_is_will(TELOPT_LINEMODE))
1182 	slc_export();
1183 }
1184 
1185 void
1186 slc_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 
1193 unsigned char slc_import_val[] = {
1194 	IAC, SB, TELOPT_LINEMODE, LM_SLC, 0, SLC_VARIABLE, 0, IAC, SE
1195 };
1196 unsigned char slc_import_def[] = {
1197 	IAC, SB, TELOPT_LINEMODE, LM_SLC, 0, SLC_DEFAULT, 0, IAC, SE
1198 };
1199 
1200 void
1201 slc_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 
1215 void
1216 slc_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 
1239 void
1240 slc(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 
1307 void
1308 slc_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 
1327 unsigned char slc_reply[128];
1328 unsigned char const * const slc_reply_eom = &slc_reply[sizeof(slc_reply)];
1329 unsigned char *slc_replyp;
1330 
1331 void
1332 slc_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 
1341 void
1342 slc_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 
1360 void
1361 slc_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 
1380 int
1381 slc_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  */
1409 int env_auto = 1;
1410 int old_env_var = OLD_ENV_VAR;
1411 int 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 
1418 void
1419 env_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)
1486 unsigned char *opt_reply = NULL;
1487 unsigned char *opt_replyp;
1488 unsigned char *opt_replyend;
1489 
1490 void
1491 env_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 
1510 void
1511 env_opt_start_info(void)
1512 {
1513 	env_opt_start();
1514 	if (opt_replyp)
1515 	    opt_replyp[-1] = TELQUAL_INFO;
1516 }
1517 
1518 void
1519 env_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 
1595 int
1596 opt_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 
1608 void
1609 env_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 
1633 int
1634 telrcv(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:
1729 process_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 
1862 static int bol = 1, local = 0;
1863 
1864 int
1865 rlogin_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 
1876 static int
1877 telsnd(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 
2026 static int
2027 Scheduler(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  */
2078 void
2079 telnet(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 
2149 static char *
2150 nextitem(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 
2196 static void
2197 netclear(void)
2198 {
2199 	/* Deleted */
2200 }
2201 
2202 /*
2203  * These routines add various telnet commands to the data stream.
2204  */
2205 
2206 static void
2207 doflush(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 
2218 void
2219 xmitAO(void)
2220 {
2221     NET2ADD(IAC, AO);
2222     printoption("SENT", IAC, AO);
2223     if (autoflush) {
2224 	doflush();
2225     }
2226 }
2227 
2228 void
2229 xmitEL(void)
2230 {
2231     NET2ADD(IAC, EL);
2232     printoption("SENT", IAC, EL);
2233 }
2234 
2235 void
2236 xmitEC(void)
2237 {
2238     NET2ADD(IAC, EC);
2239     printoption("SENT", IAC, EC);
2240 }
2241 
2242 int
2243 dosynch(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 
2253 int want_status_response = 0;
2254 
2255 int
2256 get_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 
2281 void
2282 intp(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 
2295 void
2296 sendbrk(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 
2309 void
2310 sendabort(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 
2323 void
2324 sendsusp(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 
2337 void
2338 sendeof(void)
2339 {
2340     NET2ADD(IAC, xEOF);
2341     printoption("SENT", IAC, xEOF);
2342 }
2343 
2344 void
2345 sendayt(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 
2355 void
2356 sendnaws(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 
2387 void
2388 tel_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 
2396 void
2397 tel_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