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