Home | History | Annotate | Line # | Download | only in telnetd
state.c revision 1.5.4.1
      1      1.1      cgd /*
      2      1.5      cgd  * Copyright (c) 1989, 1993
      3      1.5      cgd  *	The Regents of the University of California.  All rights reserved.
      4      1.1      cgd  *
      5      1.1      cgd  * Redistribution and use in source and binary forms, with or without
      6      1.1      cgd  * modification, are permitted provided that the following conditions
      7      1.1      cgd  * are met:
      8      1.1      cgd  * 1. Redistributions of source code must retain the above copyright
      9      1.1      cgd  *    notice, this list of conditions and the following disclaimer.
     10      1.1      cgd  * 2. Redistributions in binary form must reproduce the above copyright
     11      1.1      cgd  *    notice, this list of conditions and the following disclaimer in the
     12      1.1      cgd  *    documentation and/or other materials provided with the distribution.
     13      1.1      cgd  * 3. All advertising materials mentioning features or use of this software
     14      1.1      cgd  *    must display the following acknowledgement:
     15      1.1      cgd  *	This product includes software developed by the University of
     16      1.1      cgd  *	California, Berkeley and its contributors.
     17      1.1      cgd  * 4. Neither the name of the University nor the names of its contributors
     18      1.1      cgd  *    may be used to endorse or promote products derived from this software
     19      1.1      cgd  *    without specific prior written permission.
     20      1.1      cgd  *
     21      1.1      cgd  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
     22      1.1      cgd  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
     23      1.1      cgd  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
     24      1.1      cgd  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
     25      1.1      cgd  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
     26      1.1      cgd  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
     27      1.1      cgd  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
     28      1.1      cgd  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
     29      1.1      cgd  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
     30      1.1      cgd  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
     31      1.1      cgd  * SUCH DAMAGE.
     32      1.1      cgd  */
     33      1.1      cgd 
     34      1.1      cgd #ifndef lint
     35      1.5      cgd /* from: static char sccsid[] = "@(#)state.c	8.1 (Berkeley) 6/4/93"; */
     36  1.5.4.1  ghudson static char *rcsid = "$Id: state.c,v 1.5.4.1 1995/10/18 05:46:26 ghudson Exp $";
     37      1.1      cgd #endif /* not lint */
     38      1.1      cgd 
     39      1.1      cgd #include "telnetd.h"
     40      1.5      cgd #if	defined(AUTHENTICATION)
     41      1.1      cgd #include <libtelnet/auth.h>
     42      1.1      cgd #endif
     43      1.1      cgd 
     44      1.5      cgd unsigned char	doopt[] = { IAC, DO, '%', 'c', 0 };
     45      1.5      cgd unsigned char	dont[] = { IAC, DONT, '%', 'c', 0 };
     46      1.5      cgd unsigned char	will[] = { IAC, WILL, '%', 'c', 0 };
     47      1.5      cgd unsigned char	wont[] = { IAC, WONT, '%', 'c', 0 };
     48      1.1      cgd int	not42 = 1;
     49      1.1      cgd 
     50      1.1      cgd /*
     51      1.1      cgd  * Buffer for sub-options, and macros
     52      1.1      cgd  * for suboptions buffer manipulations
     53      1.1      cgd  */
     54      1.1      cgd unsigned char subbuffer[512], *subpointer= subbuffer, *subend= subbuffer;
     55      1.1      cgd 
     56      1.5      cgd #define	SB_CLEAR()	subpointer = subbuffer
     57      1.1      cgd #define	SB_TERM()	{ subend = subpointer; SB_CLEAR(); }
     58      1.1      cgd #define	SB_ACCUM(c)	if (subpointer < (subbuffer+sizeof subbuffer)) { \
     59      1.1      cgd 				*subpointer++ = (c); \
     60      1.1      cgd 			}
     61      1.1      cgd #define	SB_GET()	((*subpointer++)&0xff)
     62      1.1      cgd #define	SB_EOF()	(subpointer >= subend)
     63      1.1      cgd #define	SB_LEN()	(subend - subpointer)
     64      1.1      cgd 
     65      1.5      cgd #ifdef	ENV_HACK
     66      1.5      cgd unsigned char *subsave;
     67      1.5      cgd #define SB_SAVE()	subsave = subpointer;
     68      1.5      cgd #define	SB_RESTORE()	subpointer = subsave;
     69      1.5      cgd #endif
     70      1.1      cgd 
     71      1.1      cgd 
     72      1.1      cgd /*
     73      1.1      cgd  * State for recv fsm
     74      1.1      cgd  */
     75      1.1      cgd #define	TS_DATA		0	/* base state */
     76      1.1      cgd #define	TS_IAC		1	/* look for double IAC's */
     77      1.1      cgd #define	TS_CR		2	/* CR-LF ->'s CR */
     78      1.1      cgd #define	TS_SB		3	/* throw away begin's... */
     79      1.1      cgd #define	TS_SE		4	/* ...end's (suboption negotiation) */
     80      1.1      cgd #define	TS_WILL		5	/* will option negotiation */
     81      1.1      cgd #define	TS_WONT		6	/* wont " */
     82      1.1      cgd #define	TS_DO		7	/* do " */
     83      1.1      cgd #define	TS_DONT		8	/* dont " */
     84      1.1      cgd 
     85      1.1      cgd 	void
     86      1.1      cgd telrcv()
     87      1.1      cgd {
     88      1.1      cgd 	register int c;
     89      1.1      cgd 	static int state = TS_DATA;
     90      1.1      cgd #if	defined(CRAY2) && defined(UNICOS5)
     91      1.1      cgd 	char *opfrontp = pfrontp;
     92      1.1      cgd #endif
     93      1.1      cgd 
     94      1.1      cgd 	while (ncc > 0) {
     95      1.1      cgd 		if ((&ptyobuf[BUFSIZ] - pfrontp) < 2)
     96      1.1      cgd 			break;
     97      1.1      cgd 		c = *netip++ & 0377, ncc--;
     98      1.1      cgd 		switch (state) {
     99      1.1      cgd 
    100      1.1      cgd 		case TS_CR:
    101      1.1      cgd 			state = TS_DATA;
    102      1.1      cgd 			/* Strip off \n or \0 after a \r */
    103      1.1      cgd 			if ((c == 0) || (c == '\n')) {
    104      1.1      cgd 				break;
    105      1.1      cgd 			}
    106      1.1      cgd 			/* FALL THROUGH */
    107      1.1      cgd 
    108      1.1      cgd 		case TS_DATA:
    109      1.1      cgd 			if (c == IAC) {
    110      1.1      cgd 				state = TS_IAC;
    111      1.1      cgd 				break;
    112      1.1      cgd 			}
    113      1.1      cgd 			/*
    114      1.1      cgd 			 * We now map \r\n ==> \r for pragmatic reasons.
    115      1.1      cgd 			 * Many client implementations send \r\n when
    116      1.1      cgd 			 * the user hits the CarriageReturn key.
    117      1.1      cgd 			 *
    118      1.1      cgd 			 * We USED to map \r\n ==> \n, since \r\n says
    119      1.1      cgd 			 * that we want to be in column 1 of the next
    120      1.1      cgd 			 * printable line, and \n is the standard
    121      1.1      cgd 			 * unix way of saying that (\r is only good
    122      1.1      cgd 			 * if CRMOD is set, which it normally is).
    123      1.1      cgd 			 */
    124      1.1      cgd 			if ((c == '\r') && his_state_is_wont(TELOPT_BINARY)) {
    125      1.1      cgd 				int nc = *netip;
    126      1.1      cgd #ifdef	LINEMODE
    127      1.1      cgd 				/*
    128      1.1      cgd 				 * If we are operating in linemode,
    129      1.1      cgd 				 * convert to local end-of-line.
    130      1.1      cgd 				 */
    131      1.1      cgd 				if (linemode && (ncc > 0) && (('\n' == nc) ||
    132      1.1      cgd 					 ((0 == nc) && tty_iscrnl())) ) {
    133      1.1      cgd 					netip++; ncc--;
    134      1.1      cgd 					c = '\n';
    135      1.1      cgd 				} else
    136      1.1      cgd #endif
    137      1.1      cgd 				{
    138      1.1      cgd 					state = TS_CR;
    139      1.1      cgd 				}
    140      1.1      cgd 			}
    141      1.1      cgd 			*pfrontp++ = c;
    142      1.1      cgd 			break;
    143      1.1      cgd 
    144      1.1      cgd 		case TS_IAC:
    145      1.1      cgd gotiac:			switch (c) {
    146      1.1      cgd 
    147      1.1      cgd 			/*
    148      1.1      cgd 			 * Send the process on the pty side an
    149      1.1      cgd 			 * interrupt.  Do this with a NULL or
    150      1.1      cgd 			 * interrupt char; depending on the tty mode.
    151      1.1      cgd 			 */
    152      1.1      cgd 			case IP:
    153      1.1      cgd 				DIAG(TD_OPTIONS,
    154      1.1      cgd 					printoption("td: recv IAC", c));
    155      1.1      cgd 				interrupt();
    156      1.1      cgd 				break;
    157      1.1      cgd 
    158      1.1      cgd 			case BREAK:
    159      1.1      cgd 				DIAG(TD_OPTIONS,
    160      1.1      cgd 					printoption("td: recv IAC", c));
    161      1.1      cgd 				sendbrk();
    162      1.1      cgd 				break;
    163      1.1      cgd 
    164      1.1      cgd 			/*
    165      1.1      cgd 			 * Are You There?
    166      1.1      cgd 			 */
    167      1.1      cgd 			case AYT:
    168      1.1      cgd 				DIAG(TD_OPTIONS,
    169      1.1      cgd 					printoption("td: recv IAC", c));
    170      1.1      cgd 				recv_ayt();
    171      1.1      cgd 				break;
    172      1.1      cgd 
    173      1.1      cgd 			/*
    174      1.1      cgd 			 * Abort Output
    175      1.1      cgd 			 */
    176      1.1      cgd 			case AO:
    177      1.1      cgd 			    {
    178      1.1      cgd 				DIAG(TD_OPTIONS,
    179      1.1      cgd 					printoption("td: recv IAC", c));
    180      1.1      cgd 				ptyflush();	/* half-hearted */
    181      1.1      cgd 				init_termbuf();
    182      1.1      cgd 
    183      1.1      cgd 				if (slctab[SLC_AO].sptr &&
    184      1.1      cgd 				    *slctab[SLC_AO].sptr != (cc_t)(_POSIX_VDISABLE)) {
    185      1.1      cgd 				    *pfrontp++ =
    186      1.1      cgd 					(unsigned char)*slctab[SLC_AO].sptr;
    187      1.1      cgd 				}
    188      1.1      cgd 
    189      1.1      cgd 				netclear();	/* clear buffer back */
    190      1.1      cgd 				*nfrontp++ = IAC;
    191      1.1      cgd 				*nfrontp++ = DM;
    192      1.1      cgd 				neturg = nfrontp-1; /* off by one XXX */
    193      1.1      cgd 				DIAG(TD_OPTIONS,
    194      1.1      cgd 					printoption("td: send IAC", DM));
    195      1.1      cgd 				break;
    196      1.1      cgd 			    }
    197      1.1      cgd 
    198      1.1      cgd 			/*
    199      1.1      cgd 			 * Erase Character and
    200      1.1      cgd 			 * Erase Line
    201      1.1      cgd 			 */
    202      1.1      cgd 			case EC:
    203      1.1      cgd 			case EL:
    204      1.1      cgd 			    {
    205      1.1      cgd 				cc_t ch;
    206      1.1      cgd 
    207      1.1      cgd 				DIAG(TD_OPTIONS,
    208      1.1      cgd 					printoption("td: recv IAC", c));
    209      1.1      cgd 				ptyflush();	/* half-hearted */
    210      1.1      cgd 				init_termbuf();
    211      1.1      cgd 				if (c == EC)
    212      1.1      cgd 					ch = *slctab[SLC_EC].sptr;
    213      1.1      cgd 				else
    214      1.1      cgd 					ch = *slctab[SLC_EL].sptr;
    215      1.1      cgd 				if (ch != (cc_t)(_POSIX_VDISABLE))
    216      1.1      cgd 					*pfrontp++ = (unsigned char)ch;
    217      1.1      cgd 				break;
    218      1.1      cgd 			    }
    219      1.1      cgd 
    220      1.1      cgd 			/*
    221      1.1      cgd 			 * Check for urgent data...
    222      1.1      cgd 			 */
    223      1.1      cgd 			case DM:
    224      1.1      cgd 				DIAG(TD_OPTIONS,
    225      1.1      cgd 					printoption("td: recv IAC", c));
    226      1.1      cgd 				SYNCHing = stilloob(net);
    227      1.1      cgd 				settimer(gotDM);
    228      1.1      cgd 				break;
    229      1.1      cgd 
    230      1.1      cgd 
    231      1.1      cgd 			/*
    232      1.1      cgd 			 * Begin option subnegotiation...
    233      1.1      cgd 			 */
    234      1.1      cgd 			case SB:
    235      1.1      cgd 				state = TS_SB;
    236      1.1      cgd 				SB_CLEAR();
    237      1.1      cgd 				continue;
    238      1.1      cgd 
    239      1.1      cgd 			case WILL:
    240      1.1      cgd 				state = TS_WILL;
    241      1.1      cgd 				continue;
    242      1.1      cgd 
    243      1.1      cgd 			case WONT:
    244      1.1      cgd 				state = TS_WONT;
    245      1.1      cgd 				continue;
    246      1.1      cgd 
    247      1.1      cgd 			case DO:
    248      1.1      cgd 				state = TS_DO;
    249      1.1      cgd 				continue;
    250      1.1      cgd 
    251      1.1      cgd 			case DONT:
    252      1.1      cgd 				state = TS_DONT;
    253      1.1      cgd 				continue;
    254      1.1      cgd 			case EOR:
    255      1.1      cgd 				if (his_state_is_will(TELOPT_EOR))
    256      1.1      cgd 					doeof();
    257      1.1      cgd 				break;
    258      1.1      cgd 
    259      1.1      cgd 			/*
    260      1.1      cgd 			 * Handle RFC 10xx Telnet linemode option additions
    261      1.1      cgd 			 * to command stream (EOF, SUSP, ABORT).
    262      1.1      cgd 			 */
    263      1.1      cgd 			case xEOF:
    264      1.1      cgd 				doeof();
    265      1.1      cgd 				break;
    266      1.1      cgd 
    267      1.1      cgd 			case SUSP:
    268      1.1      cgd 				sendsusp();
    269      1.1      cgd 				break;
    270      1.1      cgd 
    271      1.1      cgd 			case ABORT:
    272      1.1      cgd 				sendbrk();
    273      1.1      cgd 				break;
    274      1.1      cgd 
    275      1.1      cgd 			case IAC:
    276      1.1      cgd 				*pfrontp++ = c;
    277      1.1      cgd 				break;
    278      1.1      cgd 			}
    279      1.1      cgd 			state = TS_DATA;
    280      1.1      cgd 			break;
    281      1.1      cgd 
    282      1.1      cgd 		case TS_SB:
    283      1.1      cgd 			if (c == IAC) {
    284      1.1      cgd 				state = TS_SE;
    285      1.1      cgd 			} else {
    286      1.1      cgd 				SB_ACCUM(c);
    287      1.1      cgd 			}
    288      1.1      cgd 			break;
    289      1.1      cgd 
    290      1.1      cgd 		case TS_SE:
    291      1.1      cgd 			if (c != SE) {
    292      1.1      cgd 				if (c != IAC) {
    293      1.1      cgd 					/*
    294      1.1      cgd 					 * bad form of suboption negotiation.
    295      1.1      cgd 					 * handle it in such a way as to avoid
    296      1.1      cgd 					 * damage to local state.  Parse
    297      1.1      cgd 					 * suboption buffer found so far,
    298      1.1      cgd 					 * then treat remaining stream as
    299      1.1      cgd 					 * another command sequence.
    300      1.1      cgd 					 */
    301      1.1      cgd 
    302      1.1      cgd 					/* for DIAGNOSTICS */
    303      1.1      cgd 					SB_ACCUM(IAC);
    304      1.1      cgd 					SB_ACCUM(c);
    305      1.1      cgd 					subpointer -= 2;
    306      1.1      cgd 
    307      1.1      cgd 					SB_TERM();
    308      1.1      cgd 					suboption();
    309      1.1      cgd 					state = TS_IAC;
    310      1.1      cgd 					goto gotiac;
    311      1.1      cgd 				}
    312      1.1      cgd 				SB_ACCUM(c);
    313      1.1      cgd 				state = TS_SB;
    314      1.1      cgd 			} else {
    315      1.1      cgd 				/* for DIAGNOSTICS */
    316      1.1      cgd 				SB_ACCUM(IAC);
    317      1.1      cgd 				SB_ACCUM(SE);
    318      1.1      cgd 				subpointer -= 2;
    319      1.1      cgd 
    320      1.1      cgd 				SB_TERM();
    321      1.1      cgd 				suboption();	/* handle sub-option */
    322      1.1      cgd 				state = TS_DATA;
    323      1.1      cgd 			}
    324      1.1      cgd 			break;
    325      1.1      cgd 
    326      1.1      cgd 		case TS_WILL:
    327      1.1      cgd 			willoption(c);
    328      1.1      cgd 			state = TS_DATA;
    329      1.1      cgd 			continue;
    330      1.1      cgd 
    331      1.1      cgd 		case TS_WONT:
    332      1.1      cgd 			wontoption(c);
    333      1.1      cgd 			state = TS_DATA;
    334      1.1      cgd 			continue;
    335      1.1      cgd 
    336      1.1      cgd 		case TS_DO:
    337      1.1      cgd 			dooption(c);
    338      1.1      cgd 			state = TS_DATA;
    339      1.1      cgd 			continue;
    340      1.1      cgd 
    341      1.1      cgd 		case TS_DONT:
    342      1.1      cgd 			dontoption(c);
    343      1.1      cgd 			state = TS_DATA;
    344      1.1      cgd 			continue;
    345      1.1      cgd 
    346      1.1      cgd 		default:
    347      1.1      cgd 			syslog(LOG_ERR, "telnetd: panic state=%d\n", state);
    348      1.1      cgd 			printf("telnetd: panic state=%d\n", state);
    349      1.1      cgd 			exit(1);
    350      1.1      cgd 		}
    351      1.1      cgd 	}
    352      1.1      cgd #if	defined(CRAY2) && defined(UNICOS5)
    353      1.1      cgd 	if (!linemode) {
    354      1.1      cgd 		char	xptyobuf[BUFSIZ+NETSLOP];
    355      1.1      cgd 		char	xbuf2[BUFSIZ];
    356      1.1      cgd 		register char *cp;
    357      1.1      cgd 		int n = pfrontp - opfrontp, oc;
    358      1.1      cgd 		bcopy(opfrontp, xptyobuf, n);
    359      1.1      cgd 		pfrontp = opfrontp;
    360      1.1      cgd 		pfrontp += term_input(xptyobuf, pfrontp, n, BUFSIZ+NETSLOP,
    361      1.1      cgd 					xbuf2, &oc, BUFSIZ);
    362      1.1      cgd 		for (cp = xbuf2; oc > 0; --oc)
    363      1.1      cgd 			if ((*nfrontp++ = *cp++) == IAC)
    364      1.1      cgd 				*nfrontp++ = IAC;
    365      1.1      cgd 	}
    366      1.1      cgd #endif	/* defined(CRAY2) && defined(UNICOS5) */
    367      1.1      cgd }  /* end of telrcv */
    368      1.1      cgd 
    369      1.1      cgd /*
    370      1.1      cgd  * The will/wont/do/dont state machines are based on Dave Borman's
    371      1.1      cgd  * Telnet option processing state machine.
    372      1.1      cgd  *
    373      1.1      cgd  * These correspond to the following states:
    374      1.1      cgd  *	my_state = the last negotiated state
    375      1.1      cgd  *	want_state = what I want the state to go to
    376      1.1      cgd  *	want_resp = how many requests I have sent
    377      1.1      cgd  * All state defaults are negative, and resp defaults to 0.
    378      1.1      cgd  *
    379      1.1      cgd  * When initiating a request to change state to new_state:
    380      1.1      cgd  *
    381      1.1      cgd  * if ((want_resp == 0 && new_state == my_state) || want_state == new_state) {
    382      1.1      cgd  *	do nothing;
    383      1.1      cgd  * } else {
    384      1.1      cgd  *	want_state = new_state;
    385      1.1      cgd  *	send new_state;
    386      1.1      cgd  *	want_resp++;
    387      1.1      cgd  * }
    388      1.1      cgd  *
    389      1.1      cgd  * When receiving new_state:
    390      1.1      cgd  *
    391      1.1      cgd  * if (want_resp) {
    392      1.1      cgd  *	want_resp--;
    393      1.1      cgd  *	if (want_resp && (new_state == my_state))
    394      1.1      cgd  *		want_resp--;
    395      1.1      cgd  * }
    396      1.1      cgd  * if ((want_resp == 0) && (new_state != want_state)) {
    397      1.1      cgd  *	if (ok_to_switch_to new_state)
    398      1.1      cgd  *		want_state = new_state;
    399      1.1      cgd  *	else
    400      1.1      cgd  *		want_resp++;
    401      1.1      cgd  *	send want_state;
    402      1.1      cgd  * }
    403      1.1      cgd  * my_state = new_state;
    404      1.1      cgd  *
    405      1.1      cgd  * Note that new_state is implied in these functions by the function itself.
    406      1.1      cgd  * will and do imply positive new_state, wont and dont imply negative.
    407      1.1      cgd  *
    408      1.1      cgd  * Finally, there is one catch.  If we send a negative response to a
    409      1.1      cgd  * positive request, my_state will be the positive while want_state will
    410      1.1      cgd  * remain negative.  my_state will revert to negative when the negative
    411      1.1      cgd  * acknowlegment arrives from the peer.  Thus, my_state generally tells
    412      1.1      cgd  * us not only the last negotiated state, but also tells us what the peer
    413      1.1      cgd  * wants to be doing as well.  It is important to understand this difference
    414      1.1      cgd  * as we may wish to be processing data streams based on our desired state
    415      1.1      cgd  * (want_state) or based on what the peer thinks the state is (my_state).
    416      1.1      cgd  *
    417      1.1      cgd  * This all works fine because if the peer sends a positive request, the data
    418      1.1      cgd  * that we receive prior to negative acknowlegment will probably be affected
    419      1.1      cgd  * by the positive state, and we can process it as such (if we can; if we
    420      1.1      cgd  * can't then it really doesn't matter).  If it is that important, then the
    421      1.1      cgd  * peer probably should be buffering until this option state negotiation
    422      1.1      cgd  * is complete.
    423      1.1      cgd  *
    424      1.1      cgd  */
    425      1.1      cgd 	void
    426      1.1      cgd send_do(option, init)
    427      1.1      cgd 	int option, init;
    428      1.1      cgd {
    429      1.1      cgd 	if (init) {
    430      1.1      cgd 		if ((do_dont_resp[option] == 0 && his_state_is_will(option)) ||
    431      1.1      cgd 		    his_want_state_is_will(option))
    432      1.1      cgd 			return;
    433      1.1      cgd 		/*
    434      1.1      cgd 		 * Special case for TELOPT_TM:  We send a DO, but pretend
    435      1.1      cgd 		 * that we sent a DONT, so that we can send more DOs if
    436      1.1      cgd 		 * we want to.
    437      1.1      cgd 		 */
    438      1.1      cgd 		if (option == TELOPT_TM)
    439      1.1      cgd 			set_his_want_state_wont(option);
    440      1.1      cgd 		else
    441      1.1      cgd 			set_his_want_state_will(option);
    442      1.1      cgd 		do_dont_resp[option]++;
    443      1.1      cgd 	}
    444      1.5      cgd 	(void) sprintf(nfrontp, (char *)doopt, option);
    445      1.1      cgd 	nfrontp += sizeof (dont) - 2;
    446      1.1      cgd 
    447      1.1      cgd 	DIAG(TD_OPTIONS, printoption("td: send do", option));
    448      1.1      cgd }
    449      1.1      cgd 
    450      1.5      cgd #ifdef	AUTHENTICATION
    451      1.1      cgd extern void auth_request();
    452      1.1      cgd #endif
    453      1.1      cgd #ifdef	LINEMODE
    454      1.1      cgd extern void doclientstat();
    455      1.1      cgd #endif
    456      1.1      cgd 
    457      1.1      cgd 	void
    458      1.1      cgd willoption(option)
    459      1.1      cgd 	int option;
    460      1.1      cgd {
    461      1.1      cgd 	int changeok = 0;
    462      1.1      cgd 	void (*func)() = 0;
    463      1.1      cgd 
    464      1.1      cgd 	/*
    465      1.1      cgd 	 * process input from peer.
    466      1.1      cgd 	 */
    467      1.1      cgd 
    468      1.1      cgd 	DIAG(TD_OPTIONS, printoption("td: recv will", option));
    469      1.1      cgd 
    470      1.1      cgd 	if (do_dont_resp[option]) {
    471      1.1      cgd 		do_dont_resp[option]--;
    472      1.1      cgd 		if (do_dont_resp[option] && his_state_is_will(option))
    473      1.1      cgd 			do_dont_resp[option]--;
    474      1.1      cgd 	}
    475      1.1      cgd 	if (do_dont_resp[option] == 0) {
    476      1.1      cgd 	    if (his_want_state_is_wont(option)) {
    477      1.1      cgd 		switch (option) {
    478      1.1      cgd 
    479      1.1      cgd 		case TELOPT_BINARY:
    480      1.1      cgd 			init_termbuf();
    481      1.1      cgd 			tty_binaryin(1);
    482      1.1      cgd 			set_termbuf();
    483      1.1      cgd 			changeok++;
    484      1.1      cgd 			break;
    485      1.1      cgd 
    486      1.1      cgd 		case TELOPT_ECHO:
    487      1.1      cgd 			/*
    488      1.1      cgd 			 * See comments below for more info.
    489      1.1      cgd 			 */
    490      1.1      cgd 			not42 = 0;	/* looks like a 4.2 system */
    491      1.1      cgd 			break;
    492      1.1      cgd 
    493      1.1      cgd 		case TELOPT_TM:
    494      1.1      cgd #if	defined(LINEMODE) && defined(KLUDGELINEMODE)
    495      1.1      cgd 			/*
    496      1.1      cgd 			 * This telnetd implementation does not really
    497      1.1      cgd 			 * support timing marks, it just uses them to
    498      1.1      cgd 			 * support the kludge linemode stuff.  If we
    499      1.1      cgd 			 * receive a will or wont TM in response to our
    500      1.1      cgd 			 * do TM request that may have been sent to
    501      1.1      cgd 			 * determine kludge linemode support, process
    502      1.1      cgd 			 * it, otherwise TM should get a negative
    503      1.1      cgd 			 * response back.
    504      1.1      cgd 			 */
    505      1.1      cgd 			/*
    506      1.1      cgd 			 * Handle the linemode kludge stuff.
    507      1.1      cgd 			 * If we are not currently supporting any
    508      1.1      cgd 			 * linemode at all, then we assume that this
    509      1.1      cgd 			 * is the client telling us to use kludge
    510      1.1      cgd 			 * linemode in response to our query.  Set the
    511      1.1      cgd 			 * linemode type that is to be supported, note
    512      1.1      cgd 			 * that the client wishes to use linemode, and
    513      1.1      cgd 			 * eat the will TM as though it never arrived.
    514      1.1      cgd 			 */
    515      1.1      cgd 			if (lmodetype < KLUDGE_LINEMODE) {
    516      1.1      cgd 				lmodetype = KLUDGE_LINEMODE;
    517      1.1      cgd 				clientstat(TELOPT_LINEMODE, WILL, 0);
    518      1.1      cgd 				send_wont(TELOPT_SGA, 1);
    519      1.5      cgd 			} else if (lmodetype == NO_AUTOKLUDGE) {
    520      1.5      cgd 				lmodetype = KLUDGE_OK;
    521      1.1      cgd 			}
    522      1.1      cgd #endif	/* defined(LINEMODE) && defined(KLUDGELINEMODE) */
    523      1.1      cgd 			/*
    524      1.1      cgd 			 * We never respond to a WILL TM, and
    525      1.1      cgd 			 * we leave the state WONT.
    526      1.1      cgd 			 */
    527      1.1      cgd 			return;
    528      1.1      cgd 
    529      1.1      cgd 		case TELOPT_LFLOW:
    530      1.1      cgd 			/*
    531      1.1      cgd 			 * If we are going to support flow control
    532      1.1      cgd 			 * option, then don't worry peer that we can't
    533      1.1      cgd 			 * change the flow control characters.
    534      1.1      cgd 			 */
    535      1.1      cgd 			slctab[SLC_XON].defset.flag &= ~SLC_LEVELBITS;
    536      1.1      cgd 			slctab[SLC_XON].defset.flag |= SLC_DEFAULT;
    537      1.1      cgd 			slctab[SLC_XOFF].defset.flag &= ~SLC_LEVELBITS;
    538      1.1      cgd 			slctab[SLC_XOFF].defset.flag |= SLC_DEFAULT;
    539      1.1      cgd 		case TELOPT_TTYPE:
    540      1.1      cgd 		case TELOPT_SGA:
    541      1.1      cgd 		case TELOPT_NAWS:
    542      1.1      cgd 		case TELOPT_TSPEED:
    543      1.1      cgd 		case TELOPT_XDISPLOC:
    544      1.5      cgd 		case TELOPT_NEW_ENVIRON:
    545      1.5      cgd 		case TELOPT_OLD_ENVIRON:
    546      1.1      cgd 			changeok++;
    547      1.1      cgd 			break;
    548      1.1      cgd 
    549      1.1      cgd #ifdef	LINEMODE
    550      1.1      cgd 		case TELOPT_LINEMODE:
    551      1.1      cgd # ifdef	KLUDGELINEMODE
    552      1.1      cgd 			/*
    553      1.1      cgd 			 * Note client's desire to use linemode.
    554      1.1      cgd 			 */
    555      1.1      cgd 			lmodetype = REAL_LINEMODE;
    556      1.1      cgd # endif	/* KLUDGELINEMODE */
    557      1.1      cgd 			func = doclientstat;
    558      1.1      cgd 			changeok++;
    559      1.1      cgd 			break;
    560      1.1      cgd #endif	/* LINEMODE */
    561      1.1      cgd 
    562      1.5      cgd #ifdef	AUTHENTICATION
    563      1.1      cgd 		case TELOPT_AUTHENTICATION:
    564      1.1      cgd 			func = auth_request;
    565      1.1      cgd 			changeok++;
    566      1.1      cgd 			break;
    567      1.1      cgd #endif
    568      1.1      cgd 
    569      1.1      cgd 
    570      1.1      cgd 		default:
    571      1.1      cgd 			break;
    572      1.1      cgd 		}
    573      1.1      cgd 		if (changeok) {
    574      1.1      cgd 			set_his_want_state_will(option);
    575      1.1      cgd 			send_do(option, 0);
    576      1.1      cgd 		} else {
    577      1.1      cgd 			do_dont_resp[option]++;
    578      1.1      cgd 			send_dont(option, 0);
    579      1.1      cgd 		}
    580      1.1      cgd 	    } else {
    581      1.1      cgd 		/*
    582      1.1      cgd 		 * Option processing that should happen when
    583      1.1      cgd 		 * we receive conformation of a change in
    584      1.1      cgd 		 * state that we had requested.
    585      1.1      cgd 		 */
    586      1.1      cgd 		switch (option) {
    587      1.1      cgd 		case TELOPT_ECHO:
    588      1.1      cgd 			not42 = 0;	/* looks like a 4.2 system */
    589      1.1      cgd 			/*
    590      1.1      cgd 			 * Egads, he responded "WILL ECHO".  Turn
    591      1.1      cgd 			 * it off right now!
    592      1.1      cgd 			 */
    593      1.1      cgd 			send_dont(option, 1);
    594      1.1      cgd 			/*
    595      1.1      cgd 			 * "WILL ECHO".  Kludge upon kludge!
    596      1.1      cgd 			 * A 4.2 client is now echoing user input at
    597      1.1      cgd 			 * the tty.  This is probably undesireable and
    598      1.1      cgd 			 * it should be stopped.  The client will
    599      1.1      cgd 			 * respond WONT TM to the DO TM that we send to
    600      1.1      cgd 			 * check for kludge linemode.  When the WONT TM
    601      1.1      cgd 			 * arrives, linemode will be turned off and a
    602      1.1      cgd 			 * change propogated to the pty.  This change
    603      1.1      cgd 			 * will cause us to process the new pty state
    604      1.1      cgd 			 * in localstat(), which will notice that
    605      1.1      cgd 			 * linemode is off and send a WILL ECHO
    606      1.1      cgd 			 * so that we are properly in character mode and
    607      1.1      cgd 			 * all is well.
    608      1.1      cgd 			 */
    609      1.1      cgd 			break;
    610      1.1      cgd #ifdef	LINEMODE
    611      1.1      cgd 		case TELOPT_LINEMODE:
    612      1.1      cgd # ifdef	KLUDGELINEMODE
    613      1.1      cgd 			/*
    614      1.1      cgd 			 * Note client's desire to use linemode.
    615      1.1      cgd 			 */
    616      1.1      cgd 			lmodetype = REAL_LINEMODE;
    617      1.1      cgd # endif	/* KLUDGELINEMODE */
    618      1.1      cgd 			func = doclientstat;
    619      1.1      cgd 			break;
    620      1.1      cgd #endif	/* LINEMODE */
    621      1.1      cgd 
    622      1.5      cgd #ifdef	AUTHENTICATION
    623      1.1      cgd 		case TELOPT_AUTHENTICATION:
    624      1.1      cgd 			func = auth_request;
    625      1.1      cgd 			break;
    626      1.1      cgd #endif
    627      1.1      cgd 
    628      1.5      cgd 		case TELOPT_LFLOW:
    629      1.5      cgd 			func = flowstat;
    630      1.1      cgd 			break;
    631      1.1      cgd 		}
    632      1.1      cgd 	    }
    633      1.1      cgd 	}
    634      1.1      cgd 	set_his_state_will(option);
    635      1.1      cgd 	if (func)
    636      1.1      cgd 		(*func)();
    637      1.1      cgd }  /* end of willoption */
    638      1.1      cgd 
    639      1.1      cgd 	void
    640      1.1      cgd send_dont(option, init)
    641      1.1      cgd 	int option, init;
    642      1.1      cgd {
    643      1.1      cgd 	if (init) {
    644      1.1      cgd 		if ((do_dont_resp[option] == 0 && his_state_is_wont(option)) ||
    645      1.1      cgd 		    his_want_state_is_wont(option))
    646      1.1      cgd 			return;
    647      1.1      cgd 		set_his_want_state_wont(option);
    648      1.1      cgd 		do_dont_resp[option]++;
    649      1.1      cgd 	}
    650      1.5      cgd 	(void) sprintf(nfrontp, (char *)dont, option);
    651      1.1      cgd 	nfrontp += sizeof (doopt) - 2;
    652      1.1      cgd 
    653      1.1      cgd 	DIAG(TD_OPTIONS, printoption("td: send dont", option));
    654      1.1      cgd }
    655      1.1      cgd 
    656      1.1      cgd 	void
    657      1.1      cgd wontoption(option)
    658      1.1      cgd 	int option;
    659      1.1      cgd {
    660      1.1      cgd 	/*
    661      1.1      cgd 	 * Process client input.
    662      1.1      cgd 	 */
    663      1.1      cgd 
    664      1.1      cgd 	DIAG(TD_OPTIONS, printoption("td: recv wont", option));
    665      1.1      cgd 
    666      1.1      cgd 	if (do_dont_resp[option]) {
    667      1.1      cgd 		do_dont_resp[option]--;
    668      1.1      cgd 		if (do_dont_resp[option] && his_state_is_wont(option))
    669      1.1      cgd 			do_dont_resp[option]--;
    670      1.1      cgd 	}
    671      1.1      cgd 	if (do_dont_resp[option] == 0) {
    672      1.1      cgd 	    if (his_want_state_is_will(option)) {
    673      1.1      cgd 		/* it is always ok to change to negative state */
    674      1.1      cgd 		switch (option) {
    675      1.1      cgd 		case TELOPT_ECHO:
    676      1.1      cgd 			not42 = 1; /* doesn't seem to be a 4.2 system */
    677      1.1      cgd 			break;
    678      1.1      cgd 
    679      1.1      cgd 		case TELOPT_BINARY:
    680      1.1      cgd 			init_termbuf();
    681      1.1      cgd 			tty_binaryin(0);
    682      1.1      cgd 			set_termbuf();
    683      1.1      cgd 			break;
    684      1.1      cgd 
    685      1.1      cgd #ifdef	LINEMODE
    686      1.1      cgd 		case TELOPT_LINEMODE:
    687      1.1      cgd # ifdef	KLUDGELINEMODE
    688      1.1      cgd 			/*
    689      1.1      cgd 			 * If real linemode is supported, then client is
    690      1.1      cgd 			 * asking to turn linemode off.
    691      1.1      cgd 			 */
    692      1.1      cgd 			if (lmodetype != REAL_LINEMODE)
    693      1.1      cgd 				break;
    694      1.1      cgd 			lmodetype = KLUDGE_LINEMODE;
    695      1.1      cgd # endif	/* KLUDGELINEMODE */
    696      1.1      cgd 			clientstat(TELOPT_LINEMODE, WONT, 0);
    697      1.1      cgd 			break;
    698      1.1      cgd #endif	/* LINEMODE */
    699      1.1      cgd 
    700      1.1      cgd 		case TELOPT_TM:
    701      1.1      cgd 			/*
    702      1.1      cgd 			 * If we get a WONT TM, and had sent a DO TM,
    703      1.1      cgd 			 * don't respond with a DONT TM, just leave it
    704      1.1      cgd 			 * as is.  Short circut the state machine to
    705      1.1      cgd 			 * achive this.
    706      1.1      cgd 			 */
    707      1.1      cgd 			set_his_want_state_wont(TELOPT_TM);
    708      1.1      cgd 			return;
    709      1.1      cgd 
    710      1.1      cgd 		case TELOPT_LFLOW:
    711      1.1      cgd 			/*
    712      1.1      cgd 			 * If we are not going to support flow control
    713      1.1      cgd 			 * option, then let peer know that we can't
    714      1.1      cgd 			 * change the flow control characters.
    715      1.1      cgd 			 */
    716      1.1      cgd 			slctab[SLC_XON].defset.flag &= ~SLC_LEVELBITS;
    717      1.1      cgd 			slctab[SLC_XON].defset.flag |= SLC_CANTCHANGE;
    718      1.1      cgd 			slctab[SLC_XOFF].defset.flag &= ~SLC_LEVELBITS;
    719      1.1      cgd 			slctab[SLC_XOFF].defset.flag |= SLC_CANTCHANGE;
    720      1.1      cgd 			break;
    721      1.1      cgd 
    722      1.5      cgd #if	defined(AUTHENTICATION)
    723      1.1      cgd 		case TELOPT_AUTHENTICATION:
    724      1.1      cgd 			auth_finished(0, AUTH_REJECT);
    725      1.1      cgd 			break;
    726      1.1      cgd #endif
    727      1.1      cgd 
    728      1.1      cgd 		/*
    729      1.1      cgd 		 * For options that we might spin waiting for
    730      1.1      cgd 		 * sub-negotiation, if the client turns off the
    731      1.1      cgd 		 * option rather than responding to the request,
    732      1.1      cgd 		 * we have to treat it here as if we got a response
    733      1.1      cgd 		 * to the sub-negotiation, (by updating the timers)
    734      1.1      cgd 		 * so that we'll break out of the loop.
    735      1.1      cgd 		 */
    736      1.1      cgd 		case TELOPT_TTYPE:
    737      1.1      cgd 			settimer(ttypesubopt);
    738      1.1      cgd 			break;
    739      1.1      cgd 
    740      1.1      cgd 		case TELOPT_TSPEED:
    741      1.1      cgd 			settimer(tspeedsubopt);
    742      1.1      cgd 			break;
    743      1.1      cgd 
    744      1.1      cgd 		case TELOPT_XDISPLOC:
    745      1.1      cgd 			settimer(xdisplocsubopt);
    746      1.1      cgd 			break;
    747      1.1      cgd 
    748      1.5      cgd 		case TELOPT_OLD_ENVIRON:
    749      1.5      cgd 			settimer(oenvironsubopt);
    750      1.5      cgd 			break;
    751      1.5      cgd 
    752      1.5      cgd 		case TELOPT_NEW_ENVIRON:
    753      1.1      cgd 			settimer(environsubopt);
    754      1.1      cgd 			break;
    755      1.1      cgd 
    756      1.1      cgd 		default:
    757      1.1      cgd 			break;
    758      1.1      cgd 		}
    759      1.1      cgd 		set_his_want_state_wont(option);
    760      1.1      cgd 		if (his_state_is_will(option))
    761      1.1      cgd 			send_dont(option, 0);
    762      1.1      cgd 	    } else {
    763      1.1      cgd 		switch (option) {
    764      1.1      cgd 		case TELOPT_TM:
    765      1.1      cgd #if	defined(LINEMODE) && defined(KLUDGELINEMODE)
    766      1.5      cgd 			if (lmodetype < NO_AUTOKLUDGE) {
    767      1.1      cgd 				lmodetype = NO_LINEMODE;
    768      1.1      cgd 				clientstat(TELOPT_LINEMODE, WONT, 0);
    769      1.1      cgd 				send_will(TELOPT_SGA, 1);
    770      1.1      cgd 				send_will(TELOPT_ECHO, 1);
    771      1.1      cgd 			}
    772      1.1      cgd #endif	/* defined(LINEMODE) && defined(KLUDGELINEMODE) */
    773      1.1      cgd 			break;
    774      1.1      cgd 
    775      1.5      cgd #if	defined(AUTHENTICATION)
    776      1.1      cgd 		case TELOPT_AUTHENTICATION:
    777      1.1      cgd 			auth_finished(0, AUTH_REJECT);
    778      1.1      cgd 			break;
    779      1.1      cgd #endif
    780      1.1      cgd 		default:
    781      1.1      cgd 			break;
    782      1.1      cgd 		}
    783      1.1      cgd 	    }
    784      1.1      cgd 	}
    785      1.1      cgd 	set_his_state_wont(option);
    786      1.1      cgd 
    787      1.1      cgd }  /* end of wontoption */
    788      1.1      cgd 
    789      1.1      cgd 	void
    790      1.1      cgd send_will(option, init)
    791      1.1      cgd 	int option, init;
    792      1.1      cgd {
    793      1.1      cgd 	if (init) {
    794      1.1      cgd 		if ((will_wont_resp[option] == 0 && my_state_is_will(option))||
    795      1.1      cgd 		    my_want_state_is_will(option))
    796      1.1      cgd 			return;
    797      1.1      cgd 		set_my_want_state_will(option);
    798      1.1      cgd 		will_wont_resp[option]++;
    799      1.1      cgd 	}
    800      1.5      cgd 	(void) sprintf(nfrontp, (char *)will, option);
    801      1.1      cgd 	nfrontp += sizeof (doopt) - 2;
    802      1.1      cgd 
    803      1.1      cgd 	DIAG(TD_OPTIONS, printoption("td: send will", option));
    804      1.1      cgd }
    805      1.1      cgd 
    806      1.1      cgd #if	!defined(LINEMODE) || !defined(KLUDGELINEMODE)
    807      1.1      cgd /*
    808      1.1      cgd  * When we get a DONT SGA, we will try once to turn it
    809      1.1      cgd  * back on.  If the other side responds DONT SGA, we
    810      1.1      cgd  * leave it at that.  This is so that when we talk to
    811      1.1      cgd  * clients that understand KLUDGELINEMODE but not LINEMODE,
    812      1.1      cgd  * we'll keep them in char-at-a-time mode.
    813      1.1      cgd  */
    814      1.1      cgd int turn_on_sga = 0;
    815      1.1      cgd #endif
    816      1.1      cgd 
    817      1.1      cgd 	void
    818      1.1      cgd dooption(option)
    819      1.1      cgd 	int option;
    820      1.1      cgd {
    821      1.1      cgd 	int changeok = 0;
    822      1.1      cgd 
    823      1.1      cgd 	/*
    824      1.1      cgd 	 * Process client input.
    825      1.1      cgd 	 */
    826      1.1      cgd 
    827      1.1      cgd 	DIAG(TD_OPTIONS, printoption("td: recv do", option));
    828      1.1      cgd 
    829      1.1      cgd 	if (will_wont_resp[option]) {
    830      1.1      cgd 		will_wont_resp[option]--;
    831      1.1      cgd 		if (will_wont_resp[option] && my_state_is_will(option))
    832      1.1      cgd 			will_wont_resp[option]--;
    833      1.1      cgd 	}
    834      1.1      cgd 	if ((will_wont_resp[option] == 0) && (my_want_state_is_wont(option))) {
    835      1.1      cgd 		switch (option) {
    836      1.1      cgd 		case TELOPT_ECHO:
    837      1.1      cgd #ifdef	LINEMODE
    838      1.1      cgd # ifdef	KLUDGELINEMODE
    839      1.1      cgd 			if (lmodetype == NO_LINEMODE)
    840      1.1      cgd # else
    841      1.1      cgd 			if (his_state_is_wont(TELOPT_LINEMODE))
    842      1.1      cgd # endif
    843      1.1      cgd #endif
    844      1.1      cgd 			{
    845      1.1      cgd 				init_termbuf();
    846      1.1      cgd 				tty_setecho(1);
    847      1.1      cgd 				set_termbuf();
    848      1.1      cgd 			}
    849      1.1      cgd 			changeok++;
    850      1.1      cgd 			break;
    851      1.1      cgd 
    852      1.1      cgd 		case TELOPT_BINARY:
    853      1.1      cgd 			init_termbuf();
    854      1.1      cgd 			tty_binaryout(1);
    855      1.1      cgd 			set_termbuf();
    856      1.1      cgd 			changeok++;
    857      1.1      cgd 			break;
    858      1.1      cgd 
    859      1.1      cgd 		case TELOPT_SGA:
    860      1.1      cgd #if	defined(LINEMODE) && defined(KLUDGELINEMODE)
    861      1.1      cgd 			/*
    862      1.1      cgd 			 * If kludge linemode is in use, then we must
    863      1.1      cgd 			 * process an incoming do SGA for linemode
    864      1.1      cgd 			 * purposes.
    865      1.1      cgd 			 */
    866      1.1      cgd 			if (lmodetype == KLUDGE_LINEMODE) {
    867      1.1      cgd 				/*
    868      1.1      cgd 				 * Receipt of "do SGA" in kludge
    869      1.1      cgd 				 * linemode is the peer asking us to
    870      1.1      cgd 				 * turn off linemode.  Make note of
    871      1.1      cgd 				 * the request.
    872      1.1      cgd 				 */
    873      1.1      cgd 				clientstat(TELOPT_LINEMODE, WONT, 0);
    874      1.1      cgd 				/*
    875      1.1      cgd 				 * If linemode did not get turned off
    876      1.1      cgd 				 * then don't tell peer that we did.
    877      1.1      cgd 				 * Breaking here forces a wont SGA to
    878      1.1      cgd 				 * be returned.
    879      1.1      cgd 				 */
    880      1.1      cgd 				if (linemode)
    881      1.1      cgd 					break;
    882      1.1      cgd 			}
    883      1.1      cgd #else
    884      1.1      cgd 			turn_on_sga = 0;
    885      1.1      cgd #endif	/* defined(LINEMODE) && defined(KLUDGELINEMODE) */
    886      1.1      cgd 			changeok++;
    887      1.1      cgd 			break;
    888      1.1      cgd 
    889      1.1      cgd 		case TELOPT_STATUS:
    890      1.1      cgd 			changeok++;
    891      1.1      cgd 			break;
    892      1.1      cgd 
    893      1.1      cgd 		case TELOPT_TM:
    894      1.1      cgd 			/*
    895      1.1      cgd 			 * Special case for TM.  We send a WILL, but
    896      1.1      cgd 			 * pretend we sent a WONT.
    897      1.1      cgd 			 */
    898      1.1      cgd 			send_will(option, 0);
    899      1.1      cgd 			set_my_want_state_wont(option);
    900      1.1      cgd 			set_my_state_wont(option);
    901      1.1      cgd 			return;
    902      1.1      cgd 
    903      1.1      cgd 		case TELOPT_LOGOUT:
    904      1.1      cgd 			/*
    905      1.1      cgd 			 * When we get a LOGOUT option, respond
    906      1.1      cgd 			 * with a WILL LOGOUT, make sure that
    907      1.1      cgd 			 * it gets written out to the network,
    908      1.1      cgd 			 * and then just go away...
    909      1.1      cgd 			 */
    910      1.1      cgd 			set_my_want_state_will(TELOPT_LOGOUT);
    911      1.1      cgd 			send_will(TELOPT_LOGOUT, 0);
    912      1.1      cgd 			set_my_state_will(TELOPT_LOGOUT);
    913      1.1      cgd 			(void)netflush();
    914      1.1      cgd 			cleanup(0);
    915      1.1      cgd 			/* NOT REACHED */
    916      1.1      cgd 			break;
    917      1.1      cgd 
    918      1.1      cgd 		case TELOPT_LINEMODE:
    919      1.1      cgd 		case TELOPT_TTYPE:
    920      1.1      cgd 		case TELOPT_NAWS:
    921      1.1      cgd 		case TELOPT_TSPEED:
    922      1.1      cgd 		case TELOPT_LFLOW:
    923      1.1      cgd 		case TELOPT_XDISPLOC:
    924      1.5      cgd #ifdef	TELOPT_ENVIRON
    925      1.5      cgd 		case TELOPT_NEW_ENVIRON:
    926      1.5      cgd #endif
    927      1.5      cgd 		case TELOPT_OLD_ENVIRON:
    928      1.1      cgd 		default:
    929      1.1      cgd 			break;
    930      1.1      cgd 		}
    931      1.1      cgd 		if (changeok) {
    932      1.1      cgd 			set_my_want_state_will(option);
    933      1.1      cgd 			send_will(option, 0);
    934      1.1      cgd 		} else {
    935      1.1      cgd 			will_wont_resp[option]++;
    936      1.1      cgd 			send_wont(option, 0);
    937      1.1      cgd 		}
    938      1.1      cgd 	}
    939      1.1      cgd 	set_my_state_will(option);
    940      1.1      cgd 
    941      1.1      cgd }  /* end of dooption */
    942      1.1      cgd 
    943      1.1      cgd 	void
    944      1.1      cgd send_wont(option, init)
    945      1.1      cgd 	int option, init;
    946      1.1      cgd {
    947      1.1      cgd 	if (init) {
    948      1.1      cgd 		if ((will_wont_resp[option] == 0 && my_state_is_wont(option)) ||
    949      1.1      cgd 		    my_want_state_is_wont(option))
    950      1.1      cgd 			return;
    951      1.1      cgd 		set_my_want_state_wont(option);
    952      1.1      cgd 		will_wont_resp[option]++;
    953      1.1      cgd 	}
    954      1.5      cgd 	(void) sprintf(nfrontp, (char *)wont, option);
    955      1.1      cgd 	nfrontp += sizeof (wont) - 2;
    956      1.1      cgd 
    957      1.1      cgd 	DIAG(TD_OPTIONS, printoption("td: send wont", option));
    958      1.1      cgd }
    959      1.1      cgd 
    960      1.1      cgd 	void
    961      1.1      cgd dontoption(option)
    962      1.1      cgd 	int option;
    963      1.1      cgd {
    964      1.1      cgd 	/*
    965      1.1      cgd 	 * Process client input.
    966      1.1      cgd 	 */
    967      1.1      cgd 
    968      1.1      cgd 
    969      1.1      cgd 	DIAG(TD_OPTIONS, printoption("td: recv dont", option));
    970      1.1      cgd 
    971      1.1      cgd 	if (will_wont_resp[option]) {
    972      1.1      cgd 		will_wont_resp[option]--;
    973      1.1      cgd 		if (will_wont_resp[option] && my_state_is_wont(option))
    974      1.1      cgd 			will_wont_resp[option]--;
    975      1.1      cgd 	}
    976      1.1      cgd 	if ((will_wont_resp[option] == 0) && (my_want_state_is_will(option))) {
    977      1.1      cgd 		switch (option) {
    978      1.1      cgd 		case TELOPT_BINARY:
    979      1.1      cgd 			init_termbuf();
    980      1.1      cgd 			tty_binaryout(0);
    981      1.1      cgd 			set_termbuf();
    982      1.1      cgd 			break;
    983      1.1      cgd 
    984      1.1      cgd 		case TELOPT_ECHO:	/* we should stop echoing */
    985      1.1      cgd #ifdef	LINEMODE
    986      1.1      cgd # ifdef	KLUDGELINEMODE
    987      1.5      cgd 			if ((lmodetype != REAL_LINEMODE) &&
    988      1.5      cgd 			    (lmodetype != KLUDGE_LINEMODE))
    989      1.1      cgd # else
    990      1.1      cgd 			if (his_state_is_wont(TELOPT_LINEMODE))
    991      1.1      cgd # endif
    992      1.1      cgd #endif
    993      1.1      cgd 			{
    994      1.1      cgd 				init_termbuf();
    995      1.1      cgd 				tty_setecho(0);
    996      1.1      cgd 				set_termbuf();
    997      1.1      cgd 			}
    998      1.1      cgd 			break;
    999      1.1      cgd 
   1000      1.1      cgd 		case TELOPT_SGA:
   1001      1.1      cgd #if	defined(LINEMODE) && defined(KLUDGELINEMODE)
   1002      1.1      cgd 			/*
   1003      1.1      cgd 			 * If kludge linemode is in use, then we
   1004      1.1      cgd 			 * must process an incoming do SGA for
   1005      1.1      cgd 			 * linemode purposes.
   1006      1.1      cgd 			 */
   1007      1.5      cgd 			if ((lmodetype == KLUDGE_LINEMODE) ||
   1008      1.5      cgd 			    (lmodetype == KLUDGE_OK)) {
   1009      1.1      cgd 				/*
   1010      1.1      cgd 				 * The client is asking us to turn
   1011      1.1      cgd 				 * linemode on.
   1012      1.1      cgd 				 */
   1013      1.5      cgd 				lmodetype = KLUDGE_LINEMODE;
   1014      1.1      cgd 				clientstat(TELOPT_LINEMODE, WILL, 0);
   1015      1.1      cgd 				/*
   1016      1.1      cgd 				 * If we did not turn line mode on,
   1017      1.1      cgd 				 * then what do we say?  Will SGA?
   1018      1.1      cgd 				 * This violates design of telnet.
   1019      1.1      cgd 				 * Gross.  Very Gross.
   1020      1.1      cgd 				 */
   1021      1.1      cgd 			}
   1022      1.1      cgd 			break;
   1023      1.1      cgd #else
   1024      1.1      cgd 			set_my_want_state_wont(option);
   1025      1.1      cgd 			if (my_state_is_will(option))
   1026      1.1      cgd 				send_wont(option, 0);
   1027      1.1      cgd 			set_my_state_wont(option);
   1028      1.1      cgd 			if (turn_on_sga ^= 1)
   1029      1.5      cgd 				send_will(option, 1);
   1030      1.1      cgd 			return;
   1031      1.1      cgd #endif	/* defined(LINEMODE) && defined(KLUDGELINEMODE) */
   1032      1.1      cgd 
   1033      1.1      cgd 		default:
   1034      1.1      cgd 			break;
   1035      1.1      cgd 		}
   1036      1.1      cgd 
   1037      1.1      cgd 		set_my_want_state_wont(option);
   1038      1.1      cgd 		if (my_state_is_will(option))
   1039      1.1      cgd 			send_wont(option, 0);
   1040      1.1      cgd 	}
   1041      1.1      cgd 	set_my_state_wont(option);
   1042      1.1      cgd 
   1043      1.1      cgd }  /* end of dontoption */
   1044      1.1      cgd 
   1045      1.5      cgd #ifdef	ENV_HACK
   1046      1.5      cgd int env_ovar = -1;
   1047      1.5      cgd int env_ovalue = -1;
   1048      1.5      cgd #else	/* ENV_HACK */
   1049      1.5      cgd # define env_ovar OLD_ENV_VAR
   1050      1.5      cgd # define env_ovalue OLD_ENV_VALUE
   1051      1.5      cgd #endif	/* ENV_HACK */
   1052      1.5      cgd 
   1053      1.1      cgd /*
   1054      1.1      cgd  * suboption()
   1055      1.1      cgd  *
   1056      1.1      cgd  *	Look at the sub-option buffer, and try to be helpful to the other
   1057      1.1      cgd  * side.
   1058      1.1      cgd  *
   1059      1.1      cgd  *	Currently we recognize:
   1060      1.1      cgd  *
   1061      1.1      cgd  *	Terminal type is
   1062      1.1      cgd  *	Linemode
   1063      1.1      cgd  *	Window size
   1064      1.1      cgd  *	Terminal speed
   1065      1.1      cgd  */
   1066      1.1      cgd 	void
   1067      1.1      cgd suboption()
   1068      1.1      cgd {
   1069      1.1      cgd     register int subchar;
   1070      1.1      cgd 
   1071      1.1      cgd     DIAG(TD_OPTIONS, {netflush(); printsub('<', subpointer, SB_LEN()+2);});
   1072      1.1      cgd 
   1073      1.1      cgd     subchar = SB_GET();
   1074      1.1      cgd     switch (subchar) {
   1075      1.1      cgd     case TELOPT_TSPEED: {
   1076      1.1      cgd 	register int xspeed, rspeed;
   1077      1.1      cgd 
   1078      1.1      cgd 	if (his_state_is_wont(TELOPT_TSPEED))	/* Ignore if option disabled */
   1079      1.1      cgd 		break;
   1080      1.1      cgd 
   1081      1.1      cgd 	settimer(tspeedsubopt);
   1082      1.1      cgd 
   1083      1.1      cgd 	if (SB_EOF() || SB_GET() != TELQUAL_IS)
   1084      1.1      cgd 		return;
   1085      1.1      cgd 
   1086      1.1      cgd 	xspeed = atoi((char *)subpointer);
   1087      1.1      cgd 
   1088      1.1      cgd 	while (SB_GET() != ',' && !SB_EOF());
   1089      1.1      cgd 	if (SB_EOF())
   1090      1.1      cgd 		return;
   1091      1.1      cgd 
   1092      1.1      cgd 	rspeed = atoi((char *)subpointer);
   1093      1.1      cgd 	clientstat(TELOPT_TSPEED, xspeed, rspeed);
   1094      1.1      cgd 
   1095      1.1      cgd 	break;
   1096      1.1      cgd 
   1097      1.1      cgd     }  /* end of case TELOPT_TSPEED */
   1098      1.1      cgd 
   1099      1.1      cgd     case TELOPT_TTYPE: {		/* Yaaaay! */
   1100      1.1      cgd 	static char terminalname[41];
   1101      1.1      cgd 
   1102      1.1      cgd 	if (his_state_is_wont(TELOPT_TTYPE))	/* Ignore if option disabled */
   1103      1.1      cgd 		break;
   1104      1.1      cgd 	settimer(ttypesubopt);
   1105      1.1      cgd 
   1106      1.1      cgd 	if (SB_EOF() || SB_GET() != TELQUAL_IS) {
   1107      1.1      cgd 	    return;		/* ??? XXX but, this is the most robust */
   1108      1.1      cgd 	}
   1109      1.1      cgd 
   1110      1.1      cgd 	terminaltype = terminalname;
   1111      1.1      cgd 
   1112      1.1      cgd 	while ((terminaltype < (terminalname + sizeof terminalname-1)) &&
   1113      1.1      cgd 								    !SB_EOF()) {
   1114      1.1      cgd 	    register int c;
   1115      1.1      cgd 
   1116      1.1      cgd 	    c = SB_GET();
   1117      1.1      cgd 	    if (isupper(c)) {
   1118      1.1      cgd 		c = tolower(c);
   1119      1.1      cgd 	    }
   1120      1.1      cgd 	    *terminaltype++ = c;    /* accumulate name */
   1121      1.1      cgd 	}
   1122      1.1      cgd 	*terminaltype = 0;
   1123      1.1      cgd 	terminaltype = terminalname;
   1124      1.1      cgd 	break;
   1125      1.1      cgd     }  /* end of case TELOPT_TTYPE */
   1126      1.1      cgd 
   1127      1.1      cgd     case TELOPT_NAWS: {
   1128      1.1      cgd 	register int xwinsize, ywinsize;
   1129      1.1      cgd 
   1130      1.1      cgd 	if (his_state_is_wont(TELOPT_NAWS))	/* Ignore if option disabled */
   1131      1.1      cgd 		break;
   1132      1.1      cgd 
   1133      1.1      cgd 	if (SB_EOF())
   1134      1.1      cgd 		return;
   1135      1.1      cgd 	xwinsize = SB_GET() << 8;
   1136      1.1      cgd 	if (SB_EOF())
   1137      1.1      cgd 		return;
   1138      1.1      cgd 	xwinsize |= SB_GET();
   1139      1.1      cgd 	if (SB_EOF())
   1140      1.1      cgd 		return;
   1141      1.1      cgd 	ywinsize = SB_GET() << 8;
   1142      1.1      cgd 	if (SB_EOF())
   1143      1.1      cgd 		return;
   1144      1.1      cgd 	ywinsize |= SB_GET();
   1145      1.1      cgd 	clientstat(TELOPT_NAWS, xwinsize, ywinsize);
   1146      1.1      cgd 
   1147      1.1      cgd 	break;
   1148      1.1      cgd 
   1149      1.1      cgd     }  /* end of case TELOPT_NAWS */
   1150      1.1      cgd 
   1151      1.1      cgd #ifdef	LINEMODE
   1152      1.1      cgd     case TELOPT_LINEMODE: {
   1153      1.1      cgd 	register int request;
   1154      1.1      cgd 
   1155      1.1      cgd 	if (his_state_is_wont(TELOPT_LINEMODE))	/* Ignore if option disabled */
   1156      1.1      cgd 		break;
   1157      1.1      cgd 	/*
   1158      1.1      cgd 	 * Process linemode suboptions.
   1159      1.1      cgd 	 */
   1160      1.1      cgd 	if (SB_EOF())
   1161      1.1      cgd 	    break;		/* garbage was sent */
   1162      1.1      cgd 	request = SB_GET();	/* get will/wont */
   1163      1.1      cgd 
   1164      1.1      cgd 	if (SB_EOF())
   1165      1.1      cgd 	    break;		/* another garbage check */
   1166      1.1      cgd 
   1167      1.1      cgd 	if (request == LM_SLC) {  /* SLC is not preceeded by WILL or WONT */
   1168      1.1      cgd 		/*
   1169      1.1      cgd 		 * Process suboption buffer of slc's
   1170      1.1      cgd 		 */
   1171      1.1      cgd 		start_slc(1);
   1172      1.1      cgd 		do_opt_slc(subpointer, subend - subpointer);
   1173      1.1      cgd 		(void) end_slc(0);
   1174      1.1      cgd 		break;
   1175      1.1      cgd 	} else if (request == LM_MODE) {
   1176      1.1      cgd 		if (SB_EOF())
   1177      1.1      cgd 		    return;
   1178      1.1      cgd 		useeditmode = SB_GET();  /* get mode flag */
   1179      1.1      cgd 		clientstat(LM_MODE, 0, 0);
   1180      1.1      cgd 		break;
   1181      1.1      cgd 	}
   1182      1.1      cgd 
   1183      1.1      cgd 	if (SB_EOF())
   1184      1.1      cgd 	    break;
   1185      1.1      cgd 	switch (SB_GET()) {  /* what suboption? */
   1186      1.1      cgd 	case LM_FORWARDMASK:
   1187      1.1      cgd 		/*
   1188      1.1      cgd 		 * According to spec, only server can send request for
   1189      1.1      cgd 		 * forwardmask, and client can only return a positive response.
   1190      1.1      cgd 		 * So don't worry about it.
   1191      1.1      cgd 		 */
   1192      1.1      cgd 
   1193      1.1      cgd 	default:
   1194      1.1      cgd 		break;
   1195      1.1      cgd 	}
   1196      1.1      cgd 	break;
   1197      1.1      cgd     }  /* end of case TELOPT_LINEMODE */
   1198      1.1      cgd #endif
   1199      1.1      cgd     case TELOPT_STATUS: {
   1200      1.1      cgd 	int mode;
   1201      1.1      cgd 
   1202      1.1      cgd 	if (SB_EOF())
   1203      1.1      cgd 	    break;
   1204      1.1      cgd 	mode = SB_GET();
   1205      1.1      cgd 	switch (mode) {
   1206      1.1      cgd 	case TELQUAL_SEND:
   1207      1.1      cgd 	    if (my_state_is_will(TELOPT_STATUS))
   1208      1.1      cgd 		send_status();
   1209      1.1      cgd 	    break;
   1210      1.1      cgd 
   1211      1.1      cgd 	case TELQUAL_IS:
   1212      1.1      cgd 	    break;
   1213      1.1      cgd 
   1214      1.1      cgd 	default:
   1215      1.1      cgd 	    break;
   1216      1.1      cgd 	}
   1217      1.1      cgd 	break;
   1218      1.1      cgd     }  /* end of case TELOPT_STATUS */
   1219      1.1      cgd 
   1220      1.1      cgd     case TELOPT_XDISPLOC: {
   1221      1.1      cgd 	if (SB_EOF() || SB_GET() != TELQUAL_IS)
   1222      1.1      cgd 		return;
   1223      1.1      cgd 	settimer(xdisplocsubopt);
   1224      1.1      cgd 	subpointer[SB_LEN()] = '\0';
   1225      1.1      cgd 	(void)setenv("DISPLAY", (char *)subpointer, 1);
   1226      1.1      cgd 	break;
   1227      1.1      cgd     }  /* end of case TELOPT_XDISPLOC */
   1228      1.1      cgd 
   1229      1.5      cgd #ifdef	TELOPT_NEW_ENVIRON
   1230      1.5      cgd     case TELOPT_NEW_ENVIRON:
   1231      1.5      cgd #endif
   1232      1.5      cgd     case TELOPT_OLD_ENVIRON: {
   1233      1.1      cgd 	register int c;
   1234      1.1      cgd 	register char *cp, *varp, *valp;
   1235      1.1      cgd 
   1236      1.1      cgd 	if (SB_EOF())
   1237      1.1      cgd 		return;
   1238      1.1      cgd 	c = SB_GET();
   1239      1.5      cgd 	if (c == TELQUAL_IS) {
   1240      1.5      cgd 		if (subchar == TELOPT_OLD_ENVIRON)
   1241      1.5      cgd 			settimer(oenvironsubopt);
   1242      1.5      cgd 		else
   1243      1.5      cgd 			settimer(environsubopt);
   1244      1.5      cgd 	} else if (c != TELQUAL_INFO) {
   1245      1.1      cgd 		return;
   1246      1.5      cgd 	}
   1247      1.5      cgd 
   1248      1.5      cgd #ifdef	TELOPT_NEW_ENVIRON
   1249      1.5      cgd 	if (subchar == TELOPT_NEW_ENVIRON) {
   1250      1.5      cgd 	    while (!SB_EOF()) {
   1251      1.5      cgd 		c = SB_GET();
   1252      1.5      cgd 		if ((c == NEW_ENV_VAR) || (c == ENV_USERVAR))
   1253      1.5      cgd 			break;
   1254      1.5      cgd 	    }
   1255      1.5      cgd 	} else
   1256      1.5      cgd #endif
   1257      1.5      cgd 	{
   1258      1.5      cgd #ifdef	ENV_HACK
   1259      1.5      cgd 	    /*
   1260      1.5      cgd 	     * We only want to do this if we haven't already decided
   1261      1.5      cgd 	     * whether or not the other side has its VALUE and VAR
   1262      1.5      cgd 	     * reversed.
   1263      1.5      cgd 	     */
   1264      1.5      cgd 	    if (env_ovar < 0) {
   1265      1.5      cgd 		register int last = -1;		/* invalid value */
   1266      1.5      cgd 		int empty = 0;
   1267      1.5      cgd 		int got_var = 0, got_value = 0, got_uservar = 0;
   1268      1.5      cgd 
   1269      1.5      cgd 		/*
   1270      1.5      cgd 		 * The other side might have its VALUE and VAR values
   1271      1.5      cgd 		 * reversed.  To be interoperable, we need to determine
   1272      1.5      cgd 		 * which way it is.  If the first recognized character
   1273      1.5      cgd 		 * is a VAR or VALUE, then that will tell us what
   1274      1.5      cgd 		 * type of client it is.  If the fist recognized
   1275      1.5      cgd 		 * character is a USERVAR, then we continue scanning
   1276      1.5      cgd 		 * the suboption looking for two consecutive
   1277      1.5      cgd 		 * VAR or VALUE fields.  We should not get two
   1278      1.5      cgd 		 * consecutive VALUE fields, so finding two
   1279      1.5      cgd 		 * consecutive VALUE or VAR fields will tell us
   1280      1.5      cgd 		 * what the client is.
   1281      1.5      cgd 		 */
   1282      1.5      cgd 		SB_SAVE();
   1283      1.5      cgd 		while (!SB_EOF()) {
   1284      1.5      cgd 			c = SB_GET();
   1285      1.5      cgd 			switch(c) {
   1286      1.5      cgd 			case OLD_ENV_VAR:
   1287      1.5      cgd 				if (last < 0 || last == OLD_ENV_VAR
   1288      1.5      cgd 				    || (empty && (last == OLD_ENV_VALUE)))
   1289      1.5      cgd 					goto env_ovar_ok;
   1290      1.5      cgd 				got_var++;
   1291      1.5      cgd 				last = OLD_ENV_VAR;
   1292      1.5      cgd 				break;
   1293      1.5      cgd 			case OLD_ENV_VALUE:
   1294      1.5      cgd 				if (last < 0 || last == OLD_ENV_VALUE
   1295      1.5      cgd 				    || (empty && (last == OLD_ENV_VAR)))
   1296      1.5      cgd 					goto env_ovar_wrong;
   1297      1.5      cgd 				got_value++;
   1298      1.5      cgd 				last = OLD_ENV_VALUE;
   1299      1.5      cgd 				break;
   1300      1.5      cgd 			case ENV_USERVAR:
   1301      1.5      cgd 				/* count strings of USERVAR as one */
   1302      1.5      cgd 				if (last != ENV_USERVAR)
   1303      1.5      cgd 					got_uservar++;
   1304      1.5      cgd 				if (empty) {
   1305      1.5      cgd 					if (last == OLD_ENV_VALUE)
   1306      1.5      cgd 						goto env_ovar_ok;
   1307      1.5      cgd 					if (last == OLD_ENV_VAR)
   1308      1.5      cgd 						goto env_ovar_wrong;
   1309      1.5      cgd 				}
   1310      1.5      cgd 				last = ENV_USERVAR;
   1311      1.5      cgd 				break;
   1312      1.5      cgd 			case ENV_ESC:
   1313      1.5      cgd 				if (!SB_EOF())
   1314      1.5      cgd 					c = SB_GET();
   1315      1.5      cgd 				/* FALL THROUGH */
   1316      1.5      cgd 			default:
   1317      1.5      cgd 				empty = 0;
   1318      1.5      cgd 				continue;
   1319      1.5      cgd 			}
   1320      1.5      cgd 			empty = 1;
   1321      1.5      cgd 		}
   1322      1.5      cgd 		if (empty) {
   1323      1.5      cgd 			if (last == OLD_ENV_VALUE)
   1324      1.5      cgd 				goto env_ovar_ok;
   1325      1.5      cgd 			if (last == OLD_ENV_VAR)
   1326      1.5      cgd 				goto env_ovar_wrong;
   1327      1.5      cgd 		}
   1328      1.5      cgd 		/*
   1329      1.5      cgd 		 * Ok, the first thing was a USERVAR, and there
   1330      1.5      cgd 		 * are not two consecutive VAR or VALUE commands,
   1331      1.5      cgd 		 * and none of the VAR or VALUE commands are empty.
   1332      1.5      cgd 		 * If the client has sent us a well-formed option,
   1333      1.5      cgd 		 * then the number of VALUEs received should always
   1334      1.5      cgd 		 * be less than or equal to the number of VARs and
   1335      1.5      cgd 		 * USERVARs received.
   1336      1.5      cgd 		 *
   1337      1.5      cgd 		 * If we got exactly as many VALUEs as VARs and
   1338      1.5      cgd 		 * USERVARs, the client has the same definitions.
   1339      1.5      cgd 		 *
   1340      1.5      cgd 		 * If we got exactly as many VARs as VALUEs and
   1341      1.5      cgd 		 * USERVARS, the client has reversed definitions.
   1342      1.5      cgd 		 */
   1343      1.5      cgd 		if (got_uservar + got_var == got_value) {
   1344      1.5      cgd 	    env_ovar_ok:
   1345      1.5      cgd 			env_ovar = OLD_ENV_VAR;
   1346      1.5      cgd 			env_ovalue = OLD_ENV_VALUE;
   1347      1.5      cgd 		} else if (got_uservar + got_value == got_var) {
   1348      1.5      cgd 	    env_ovar_wrong:
   1349      1.5      cgd 			env_ovar = OLD_ENV_VALUE;
   1350      1.5      cgd 			env_ovalue = OLD_ENV_VAR;
   1351      1.5      cgd 			DIAG(TD_OPTIONS, {sprintf(nfrontp,
   1352      1.5      cgd 				"ENVIRON VALUE and VAR are reversed!\r\n");
   1353      1.5      cgd 				nfrontp += strlen(nfrontp);});
   1354      1.1      cgd 
   1355      1.5      cgd 		}
   1356      1.5      cgd 	    }
   1357      1.5      cgd 	    SB_RESTORE();
   1358      1.5      cgd #endif
   1359      1.5      cgd 
   1360      1.5      cgd 	    while (!SB_EOF()) {
   1361      1.5      cgd 		c = SB_GET();
   1362      1.5      cgd 		if ((c == env_ovar) || (c == ENV_USERVAR))
   1363      1.5      cgd 			break;
   1364      1.5      cgd 	    }
   1365      1.5      cgd 	}
   1366      1.1      cgd 
   1367      1.1      cgd 	if (SB_EOF())
   1368      1.1      cgd 		return;
   1369      1.1      cgd 
   1370      1.1      cgd 	cp = varp = (char *)subpointer;
   1371      1.1      cgd 	valp = 0;
   1372      1.1      cgd 
   1373      1.1      cgd 	while (!SB_EOF()) {
   1374      1.5      cgd 		c = SB_GET();
   1375      1.5      cgd 		if (subchar == TELOPT_OLD_ENVIRON) {
   1376      1.5      cgd 			if (c == env_ovar)
   1377      1.5      cgd 				c = NEW_ENV_VAR;
   1378      1.5      cgd 			else if (c == env_ovalue)
   1379      1.5      cgd 				c = NEW_ENV_VALUE;
   1380      1.5      cgd 		}
   1381      1.5      cgd 		switch (c) {
   1382      1.5      cgd 
   1383      1.5      cgd 		case NEW_ENV_VALUE:
   1384      1.1      cgd 			*cp = '\0';
   1385      1.1      cgd 			cp = valp = (char *)subpointer;
   1386      1.1      cgd 			break;
   1387      1.1      cgd 
   1388      1.5      cgd 		case NEW_ENV_VAR:
   1389      1.5      cgd 		case ENV_USERVAR:
   1390      1.1      cgd 			*cp = '\0';
   1391  1.5.4.1  ghudson 			if (strcmp(varp, "LD_LIBRARY_PATH") != 0 &&
   1392  1.5.4.1  ghudson 			    strcmp(varp, "LD_PRELOAD") != 0 &&
   1393  1.5.4.1  ghudson 			    strcmp(varp, "IFS") != 0) {
   1394  1.5.4.1  ghudson 				if (valp)
   1395  1.5.4.1  ghudson 					(void)setenv(varp, valp, 1);
   1396  1.5.4.1  ghudson 				else
   1397  1.5.4.1  ghudson 					unsetenv(varp);
   1398  1.5.4.1  ghudson 			}
   1399      1.1      cgd 			cp = varp = (char *)subpointer;
   1400      1.1      cgd 			valp = 0;
   1401      1.1      cgd 			break;
   1402      1.1      cgd 
   1403      1.1      cgd 		case ENV_ESC:
   1404      1.1      cgd 			if (SB_EOF())
   1405      1.1      cgd 				break;
   1406      1.1      cgd 			c = SB_GET();
   1407      1.1      cgd 			/* FALL THROUGH */
   1408      1.1      cgd 		default:
   1409      1.1      cgd 			*cp++ = c;
   1410      1.1      cgd 			break;
   1411      1.1      cgd 		}
   1412      1.1      cgd 	}
   1413      1.1      cgd 	*cp = '\0';
   1414      1.1      cgd 	if (valp)
   1415      1.1      cgd 		(void)setenv(varp, valp, 1);
   1416      1.1      cgd 	else
   1417      1.1      cgd 		unsetenv(varp);
   1418      1.1      cgd 	break;
   1419      1.5      cgd     }  /* end of case TELOPT_NEW_ENVIRON */
   1420      1.5      cgd #if	defined(AUTHENTICATION)
   1421      1.1      cgd     case TELOPT_AUTHENTICATION:
   1422      1.1      cgd 	if (SB_EOF())
   1423      1.1      cgd 		break;
   1424      1.1      cgd 	switch(SB_GET()) {
   1425      1.1      cgd 	case TELQUAL_SEND:
   1426      1.1      cgd 	case TELQUAL_REPLY:
   1427      1.1      cgd 		/*
   1428      1.1      cgd 		 * These are sent by us and cannot be sent by
   1429      1.1      cgd 		 * the client.
   1430      1.1      cgd 		 */
   1431      1.1      cgd 		break;
   1432      1.1      cgd 	case TELQUAL_IS:
   1433      1.1      cgd 		auth_is(subpointer, SB_LEN());
   1434      1.1      cgd 		break;
   1435      1.1      cgd 	case TELQUAL_NAME:
   1436      1.1      cgd 		auth_name(subpointer, SB_LEN());
   1437      1.1      cgd 		break;
   1438      1.1      cgd 	}
   1439      1.1      cgd 	break;
   1440      1.1      cgd #endif
   1441      1.1      cgd 
   1442      1.1      cgd     default:
   1443      1.1      cgd 	break;
   1444      1.1      cgd     }  /* end of switch */
   1445      1.1      cgd 
   1446      1.1      cgd }  /* end of suboption */
   1447      1.1      cgd 
   1448      1.1      cgd 	void
   1449      1.1      cgd doclientstat()
   1450      1.1      cgd {
   1451      1.1      cgd 	clientstat(TELOPT_LINEMODE, WILL, 0);
   1452      1.1      cgd }
   1453      1.1      cgd 
   1454      1.1      cgd #define	ADD(c)	 *ncp++ = c;
   1455      1.1      cgd #define	ADD_DATA(c) { *ncp++ = c; if (c == SE) *ncp++ = c; }
   1456      1.1      cgd 	void
   1457      1.1      cgd send_status()
   1458      1.1      cgd {
   1459      1.1      cgd 	unsigned char statusbuf[256];
   1460      1.1      cgd 	register unsigned char *ncp;
   1461      1.1      cgd 	register unsigned char i;
   1462      1.1      cgd 
   1463      1.1      cgd 	ncp = statusbuf;
   1464      1.1      cgd 
   1465      1.1      cgd 	netflush();	/* get rid of anything waiting to go out */
   1466      1.1      cgd 
   1467      1.1      cgd 	ADD(IAC);
   1468      1.1      cgd 	ADD(SB);
   1469      1.1      cgd 	ADD(TELOPT_STATUS);
   1470      1.1      cgd 	ADD(TELQUAL_IS);
   1471      1.1      cgd 
   1472      1.1      cgd 	/*
   1473      1.1      cgd 	 * We check the want_state rather than the current state,
   1474      1.1      cgd 	 * because if we received a DO/WILL for an option that we
   1475      1.1      cgd 	 * don't support, and the other side didn't send a DONT/WONT
   1476      1.1      cgd 	 * in response to our WONT/DONT, then the "state" will be
   1477      1.1      cgd 	 * WILL/DO, and the "want_state" will be WONT/DONT.  We
   1478      1.1      cgd 	 * need to go by the latter.
   1479      1.1      cgd 	 */
   1480      1.5      cgd 	for (i = 0; i < (unsigned char)NTELOPTS; i++) {
   1481      1.1      cgd 		if (my_want_state_is_will(i)) {
   1482      1.1      cgd 			ADD(WILL);
   1483      1.1      cgd 			ADD_DATA(i);
   1484      1.1      cgd 			if (i == IAC)
   1485      1.1      cgd 				ADD(IAC);
   1486      1.1      cgd 		}
   1487      1.1      cgd 		if (his_want_state_is_will(i)) {
   1488      1.1      cgd 			ADD(DO);
   1489      1.1      cgd 			ADD_DATA(i);
   1490      1.1      cgd 			if (i == IAC)
   1491      1.1      cgd 				ADD(IAC);
   1492      1.1      cgd 		}
   1493      1.1      cgd 	}
   1494      1.1      cgd 
   1495      1.1      cgd 	if (his_want_state_is_will(TELOPT_LFLOW)) {
   1496      1.1      cgd 		ADD(SB);
   1497      1.1      cgd 		ADD(TELOPT_LFLOW);
   1498      1.5      cgd 		if (flowmode) {
   1499      1.5      cgd 			ADD(LFLOW_ON);
   1500      1.5      cgd 		} else {
   1501      1.5      cgd 			ADD(LFLOW_OFF);
   1502      1.5      cgd 		}
   1503      1.1      cgd 		ADD(SE);
   1504      1.5      cgd 
   1505      1.5      cgd 		if (restartany >= 0) {
   1506      1.5      cgd 			ADD(SB)
   1507      1.5      cgd 			ADD(TELOPT_LFLOW);
   1508      1.5      cgd 			if (restartany) {
   1509      1.5      cgd 				ADD(LFLOW_RESTART_ANY);
   1510      1.5      cgd 			} else {
   1511      1.5      cgd 				ADD(LFLOW_RESTART_XON);
   1512      1.5      cgd 			}
   1513      1.5      cgd 			ADD(SE)
   1514      1.5      cgd 			ADD(SB);
   1515      1.5      cgd 		}
   1516      1.1      cgd 	}
   1517      1.1      cgd 
   1518      1.1      cgd #ifdef	LINEMODE
   1519      1.1      cgd 	if (his_want_state_is_will(TELOPT_LINEMODE)) {
   1520      1.1      cgd 		unsigned char *cp, *cpe;
   1521      1.1      cgd 		int len;
   1522      1.1      cgd 
   1523      1.1      cgd 		ADD(SB);
   1524      1.1      cgd 		ADD(TELOPT_LINEMODE);
   1525      1.1      cgd 		ADD(LM_MODE);
   1526      1.1      cgd 		ADD_DATA(editmode);
   1527      1.1      cgd 		if (editmode == IAC)
   1528      1.1      cgd 			ADD(IAC);
   1529      1.1      cgd 		ADD(SE);
   1530      1.1      cgd 
   1531      1.1      cgd 		ADD(SB);
   1532      1.1      cgd 		ADD(TELOPT_LINEMODE);
   1533      1.1      cgd 		ADD(LM_SLC);
   1534      1.1      cgd 		start_slc(0);
   1535      1.1      cgd 		send_slc();
   1536      1.1      cgd 		len = end_slc(&cp);
   1537      1.1      cgd 		for (cpe = cp + len; cp < cpe; cp++)
   1538      1.1      cgd 			ADD_DATA(*cp);
   1539      1.1      cgd 		ADD(SE);
   1540      1.1      cgd 	}
   1541      1.1      cgd #endif	/* LINEMODE */
   1542      1.1      cgd 
   1543      1.1      cgd 	ADD(IAC);
   1544      1.1      cgd 	ADD(SE);
   1545      1.1      cgd 
   1546      1.1      cgd 	writenet(statusbuf, ncp - statusbuf);
   1547      1.1      cgd 	netflush();	/* Send it on its way */
   1548      1.1      cgd 
   1549      1.1      cgd 	DIAG(TD_OPTIONS,
   1550      1.1      cgd 		{printsub('>', statusbuf, ncp - statusbuf); netflush();});
   1551      1.1      cgd }
   1552