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