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