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