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