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