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