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