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