termstat.c revision 72089
129088Smarkm/*
229088Smarkm * Copyright (c) 1989, 1993
329088Smarkm *	The Regents of the University of California.  All rights reserved.
429088Smarkm *
529088Smarkm * Redistribution and use in source and binary forms, with or without
629088Smarkm * modification, are permitted provided that the following conditions
729088Smarkm * are met:
829088Smarkm * 1. Redistributions of source code must retain the above copyright
929088Smarkm *    notice, this list of conditions and the following disclaimer.
1029088Smarkm * 2. Redistributions in binary form must reproduce the above copyright
1129088Smarkm *    notice, this list of conditions and the following disclaimer in the
1229088Smarkm *    documentation and/or other materials provided with the distribution.
1329088Smarkm * 3. All advertising materials mentioning features or use of this software
1429088Smarkm *    must display the following acknowledgement:
1529088Smarkm *	This product includes software developed by the University of
1629088Smarkm *	California, Berkeley and its contributors.
1729088Smarkm * 4. Neither the name of the University nor the names of its contributors
1829088Smarkm *    may be used to endorse or promote products derived from this software
1929088Smarkm *    without specific prior written permission.
2029088Smarkm *
2129088Smarkm * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
2229088Smarkm * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
2329088Smarkm * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
2429088Smarkm * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
2529088Smarkm * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2629088Smarkm * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2729088Smarkm * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2829088Smarkm * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2929088Smarkm * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
3029088Smarkm * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
3129088Smarkm * SUCH DAMAGE.
3229088Smarkm */
3329088Smarkm
3429088Smarkm#ifndef lint
3531622Scharnier#if 0
3629181Smarkmstatic const char sccsid[] = "@(#)termstat.c	8.2 (Berkeley) 5/30/95";
3731622Scharnier#endif
3831622Scharnierstatic const char rcsid[] =
3950479Speter  "$FreeBSD: head/contrib/telnet/telnetd/termstat.c 72089 2001-02-06 10:39:38Z asmodai $";
4029088Smarkm#endif /* not lint */
4129088Smarkm
4229088Smarkm#include "telnetd.h"
4329088Smarkm
4429181Smarkm#if	defined(ENCRYPTION)
4529181Smarkm#include <libtelnet/encrypt.h>
4629181Smarkm#endif
4729181Smarkm
4829088Smarkm/*
4929088Smarkm * local variables
5029088Smarkm */
5129088Smarkmint def_tspeed = -1, def_rspeed = -1;
5229088Smarkm#ifdef	TIOCSWINSZ
5329088Smarkmint def_row = 0, def_col = 0;
5429088Smarkm#endif
5529088Smarkm#ifdef	LINEMODE
5629088Smarkmstatic int _terminit = 0;
5729088Smarkm#endif	/* LINEMODE */
5829088Smarkm
5929088Smarkm#if	defined(CRAY2) && defined(UNICOS5)
6029088Smarkmint	newmap = 1;	/* nonzero if \n maps to ^M^J */
6129088Smarkm#endif
6229088Smarkm
6329088Smarkm#ifdef	LINEMODE
6429088Smarkm/*
6529088Smarkm * localstat
6629088Smarkm *
6729088Smarkm * This function handles all management of linemode.
6829088Smarkm *
6929088Smarkm * Linemode allows the client to do the local editing of data
7029088Smarkm * and send only complete lines to the server.  Linemode state is
7129088Smarkm * based on the state of the pty driver.  If the pty is set for
7229088Smarkm * external processing, then we can use linemode.  Further, if we
7329088Smarkm * can use real linemode, then we can look at the edit control bits
7429088Smarkm * in the pty to determine what editing the client should do.
7529088Smarkm *
7629088Smarkm * Linemode support uses the following state flags to keep track of
7729088Smarkm * current and desired linemode state.
7829088Smarkm *	alwayslinemode : true if -l was specified on the telnetd
7929088Smarkm * 	command line.  It means to have linemode on as much as
8029088Smarkm *	possible.
8129088Smarkm *
8229088Smarkm * 	lmodetype: signifies whether the client can
8329088Smarkm *	handle real linemode, or if use of kludgeomatic linemode
8429088Smarkm *	is preferred.  It will be set to one of the following:
8529088Smarkm *		REAL_LINEMODE : use linemode option
8629088Smarkm *		NO_KLUDGE : don't initiate kludge linemode.
8729088Smarkm *		KLUDGE_LINEMODE : use kludge linemode
8829088Smarkm *		NO_LINEMODE : client is ignorant of linemode
8929088Smarkm *
9029088Smarkm *	linemode, uselinemode : linemode is true if linemode
9129088Smarkm *	is currently on, uselinemode is the state that we wish
9229088Smarkm *	to be in.  If another function wishes to turn linemode
9329088Smarkm *	on or off, it sets or clears uselinemode.
9429088Smarkm *
9529088Smarkm *	editmode, useeditmode : like linemode/uselinemode, but
9629088Smarkm *	these contain the edit mode states (edit and trapsig).
9729088Smarkm *
9829088Smarkm * The state variables correspond to some of the state information
9929088Smarkm * in the pty.
10029088Smarkm *	linemode:
10129088Smarkm *		In real linemode, this corresponds to whether the pty
10229088Smarkm *		expects external processing of incoming data.
10329088Smarkm *		In kludge linemode, this more closely corresponds to the
10429088Smarkm *		whether normal processing is on or not.  (ICANON in
10529088Smarkm *		system V, or COOKED mode in BSD.)
10629088Smarkm *		If the -l option was specified (alwayslinemode), then
10729088Smarkm *		an attempt is made to force external processing on at
10829088Smarkm *		all times.
10929088Smarkm *
11029088Smarkm * The following heuristics are applied to determine linemode
11129088Smarkm * handling within the server.
11229088Smarkm *	1) Early on in starting up the server, an attempt is made
11329088Smarkm *	   to negotiate the linemode option.  If this succeeds
11429088Smarkm *	   then lmodetype is set to REAL_LINEMODE and all linemode
11529088Smarkm *	   processing occurs in the context of the linemode option.
11629088Smarkm *	2) If the attempt to negotiate the linemode option failed,
11729088Smarkm *	   and the "-k" (don't initiate kludge linemode) isn't set,
11829088Smarkm *	   then we try to use kludge linemode.  We test for this
11929088Smarkm *	   capability by sending "do Timing Mark".  If a positive
12029088Smarkm *	   response comes back, then we assume that the client
12129088Smarkm *	   understands kludge linemode (ech!) and the
12229088Smarkm *	   lmodetype flag is set to KLUDGE_LINEMODE.
12329088Smarkm *	3) Otherwise, linemode is not supported at all and
12429088Smarkm *	   lmodetype remains set to NO_LINEMODE (which happens
12529088Smarkm *	   to be 0 for convenience).
12629088Smarkm *	4) At any time a command arrives that implies a higher
12729088Smarkm *	   state of linemode support in the client, we move to that
12829088Smarkm *	   linemode support.
12929088Smarkm *
13029088Smarkm * A short explanation of kludge linemode is in order here.
13129088Smarkm *	1) The heuristic to determine support for kludge linemode
13229088Smarkm *	   is to send a do timing mark.  We assume that a client
13329088Smarkm *	   that supports timing marks also supports kludge linemode.
13429088Smarkm *	   A risky proposition at best.
13529088Smarkm *	2) Further negotiation of linemode is done by changing the
13629088Smarkm *	   the server's state regarding SGA.  If server will SGA,
13729088Smarkm *	   then linemode is off, if server won't SGA, then linemode
13829088Smarkm *	   is on.
13929088Smarkm */
14029088Smarkm	void
14129088Smarkmlocalstat()
14229088Smarkm{
14329088Smarkm	void netflush();
14429088Smarkm	int need_will_echo = 0;
14529088Smarkm
14629088Smarkm#if	defined(CRAY2) && defined(UNICOS5)
14729088Smarkm	/*
14829088Smarkm	 * Keep track of that ol' CR/NL mapping while we're in the
14929088Smarkm	 * neighborhood.
15029088Smarkm	 */
15129088Smarkm	newmap = tty_isnewmap();
15229088Smarkm#endif	/* defined(CRAY2) && defined(UNICOS5) */
15329088Smarkm
15429088Smarkm	/*
15529181Smarkm	 * Check for changes to flow control if client supports it.
15629181Smarkm	 */
15729181Smarkm	flowstat();
15829181Smarkm
15929181Smarkm	/*
16029181Smarkm	 * Check linemode on/off state
16129181Smarkm	 */
16229181Smarkm	uselinemode = tty_linemode();
16329181Smarkm
16429181Smarkm	/*
16529181Smarkm	 * If alwayslinemode is on, and pty is changing to turn it off, then
16629181Smarkm	 * force linemode back on.
16729181Smarkm	 */
16829181Smarkm	if (alwayslinemode && linemode && !uselinemode) {
16929181Smarkm		uselinemode = 1;
17029181Smarkm		tty_setlinemode(uselinemode);
17129181Smarkm	}
17229181Smarkm
17329181Smarkm	if (uselinemode) {
17429181Smarkm		/*
17529088Smarkm	 * Check for state of BINARY options.
17629181Smarkm		 *
17729181Smarkm		 * We only need to do the binary dance if we are actually going
17829181Smarkm		 * to use linemode.  As this confuses some telnet clients
17929181Smarkm		 * that don't support linemode, and doesn't gain us
18029181Smarkm		 * anything, we don't do it unless we're doing linemode.
18129181Smarkm		 * -Crh (henrich@msu.edu)
18229088Smarkm	 */
18329181Smarkm
18429088Smarkm	if (tty_isbinaryin()) {
18529088Smarkm		if (his_want_state_is_wont(TELOPT_BINARY))
18629088Smarkm			send_do(TELOPT_BINARY, 1);
18729088Smarkm	} else {
18829088Smarkm		if (his_want_state_is_will(TELOPT_BINARY))
18929088Smarkm			send_dont(TELOPT_BINARY, 1);
19029088Smarkm	}
19129088Smarkm
19229088Smarkm	if (tty_isbinaryout()) {
19329088Smarkm		if (my_want_state_is_wont(TELOPT_BINARY))
19429088Smarkm			send_will(TELOPT_BINARY, 1);
19529088Smarkm	} else {
19629088Smarkm		if (my_want_state_is_will(TELOPT_BINARY))
19729088Smarkm			send_wont(TELOPT_BINARY, 1);
19829088Smarkm	}
19929088Smarkm	}
20029088Smarkm
20129088Smarkm#ifdef	ENCRYPTION
20229088Smarkm	/*
20329088Smarkm	 * If the terminal is not echoing, but editing is enabled,
20429088Smarkm	 * something like password input is going to happen, so
20529088Smarkm	 * if we the other side is not currently sending encrypted
20629088Smarkm	 * data, ask the other side to start encrypting.
20729088Smarkm	 */
20829088Smarkm	if (his_state_is_will(TELOPT_ENCRYPT)) {
20929088Smarkm		static int enc_passwd = 0;
21029088Smarkm		if (uselinemode && !tty_isecho() && tty_isediting()
21129088Smarkm		    && (enc_passwd == 0) && !decrypt_input) {
21229088Smarkm			encrypt_send_request_start();
21329088Smarkm			enc_passwd = 1;
21429088Smarkm		} else if (enc_passwd) {
21529088Smarkm			encrypt_send_request_end();
21629088Smarkm			enc_passwd = 0;
21729088Smarkm		}
21829088Smarkm	}
21929088Smarkm#endif	/* ENCRYPTION */
22029088Smarkm
22129088Smarkm	/*
22229088Smarkm	 * Do echo mode handling as soon as we know what the
22329088Smarkm	 * linemode is going to be.
22429088Smarkm	 * If the pty has echo turned off, then tell the client that
22529088Smarkm	 * the server will echo.  If echo is on, then the server
22629088Smarkm	 * will echo if in character mode, but in linemode the
22729088Smarkm	 * client should do local echoing.  The state machine will
22829088Smarkm	 * not send anything if it is unnecessary, so don't worry
22929088Smarkm	 * about that here.
23029088Smarkm	 *
23129088Smarkm	 * If we need to send the WILL ECHO (because echo is off),
23229088Smarkm	 * then delay that until after we have changed the MODE.
23329088Smarkm	 * This way, when the user is turning off both editing
23429088Smarkm	 * and echo, the client will get editing turned off first.
23529088Smarkm	 * This keeps the client from going into encryption mode
23629088Smarkm	 * and then right back out if it is doing auto-encryption
23729088Smarkm	 * when passwords are being typed.
23829088Smarkm	 */
23929088Smarkm	if (uselinemode) {
24029088Smarkm		if (tty_isecho())
24129088Smarkm			send_wont(TELOPT_ECHO, 1);
24229088Smarkm		else
24329088Smarkm			need_will_echo = 1;
24429088Smarkm#ifdef	KLUDGELINEMODE
24529088Smarkm		if (lmodetype == KLUDGE_OK)
24629088Smarkm			lmodetype = KLUDGE_LINEMODE;
24729088Smarkm#endif
24829088Smarkm	}
24929088Smarkm
25029088Smarkm	/*
25129088Smarkm	 * If linemode is being turned off, send appropriate
25229088Smarkm	 * command and then we're all done.
25329088Smarkm	 */
25429088Smarkm	 if (!uselinemode && linemode) {
25529088Smarkm# ifdef	KLUDGELINEMODE
25629088Smarkm		if (lmodetype == REAL_LINEMODE) {
25729088Smarkm# endif	/* KLUDGELINEMODE */
25829088Smarkm			send_dont(TELOPT_LINEMODE, 1);
25929088Smarkm# ifdef	KLUDGELINEMODE
26029088Smarkm		} else if (lmodetype == KLUDGE_LINEMODE)
26129088Smarkm			send_will(TELOPT_SGA, 1);
26229088Smarkm# endif	/* KLUDGELINEMODE */
26329088Smarkm		send_will(TELOPT_ECHO, 1);
26429088Smarkm		linemode = uselinemode;
26529088Smarkm		goto done;
26629088Smarkm	}
26729088Smarkm
26829088Smarkm# ifdef	KLUDGELINEMODE
26929088Smarkm	/*
27029088Smarkm	 * If using real linemode check edit modes for possible later use.
27129088Smarkm	 * If we are in kludge linemode, do the SGA negotiation.
27229088Smarkm	 */
27329088Smarkm	if (lmodetype == REAL_LINEMODE) {
27429088Smarkm# endif	/* KLUDGELINEMODE */
27529088Smarkm		useeditmode = 0;
27629088Smarkm		if (tty_isediting())
27729088Smarkm			useeditmode |= MODE_EDIT;
27829088Smarkm		if (tty_istrapsig())
27929088Smarkm			useeditmode |= MODE_TRAPSIG;
28029088Smarkm		if (tty_issofttab())
28129088Smarkm			useeditmode |= MODE_SOFT_TAB;
28229088Smarkm		if (tty_islitecho())
28329088Smarkm			useeditmode |= MODE_LIT_ECHO;
28429088Smarkm# ifdef	KLUDGELINEMODE
28529088Smarkm	} else if (lmodetype == KLUDGE_LINEMODE) {
28629088Smarkm		if (tty_isediting() && uselinemode)
28729088Smarkm			send_wont(TELOPT_SGA, 1);
28829088Smarkm		else
28929088Smarkm			send_will(TELOPT_SGA, 1);
29029088Smarkm	}
29129088Smarkm# endif	/* KLUDGELINEMODE */
29229088Smarkm
29329088Smarkm	/*
29429088Smarkm	 * Negotiate linemode on if pty state has changed to turn it on.
29529088Smarkm	 * Send appropriate command and send along edit mode, then all done.
29629088Smarkm	 */
29729088Smarkm	if (uselinemode && !linemode) {
29829088Smarkm# ifdef	KLUDGELINEMODE
29929088Smarkm		if (lmodetype == KLUDGE_LINEMODE) {
30029088Smarkm			send_wont(TELOPT_SGA, 1);
30129088Smarkm		} else if (lmodetype == REAL_LINEMODE) {
30229088Smarkm# endif	/* KLUDGELINEMODE */
30329088Smarkm			send_do(TELOPT_LINEMODE, 1);
30429088Smarkm			/* send along edit modes */
30529088Smarkm			(void) sprintf(nfrontp, "%c%c%c%c%c%c%c", IAC, SB,
30629088Smarkm				TELOPT_LINEMODE, LM_MODE, useeditmode,
30729088Smarkm				IAC, SE);
30829088Smarkm			nfrontp += 7;
30929088Smarkm			editmode = useeditmode;
31029088Smarkm# ifdef	KLUDGELINEMODE
31129088Smarkm		}
31229088Smarkm# endif	/* KLUDGELINEMODE */
31329088Smarkm		linemode = uselinemode;
31429088Smarkm		goto done;
31529088Smarkm	}
31629088Smarkm
31729088Smarkm# ifdef	KLUDGELINEMODE
31829088Smarkm	/*
31929088Smarkm	 * None of what follows is of any value if not using
32029088Smarkm	 * real linemode.
32129088Smarkm	 */
32229088Smarkm	if (lmodetype < REAL_LINEMODE)
32329088Smarkm		goto done;
32429088Smarkm# endif	/* KLUDGELINEMODE */
32529088Smarkm
32629088Smarkm	if (linemode && his_state_is_will(TELOPT_LINEMODE)) {
32729088Smarkm		/*
32829088Smarkm		 * If edit mode changed, send edit mode.
32929088Smarkm		 */
33029088Smarkm		 if (useeditmode != editmode) {
33129088Smarkm			/*
33229088Smarkm			 * Send along appropriate edit mode mask.
33329088Smarkm			 */
33429088Smarkm			(void) sprintf(nfrontp, "%c%c%c%c%c%c%c", IAC, SB,
33529088Smarkm				TELOPT_LINEMODE, LM_MODE, useeditmode,
33629088Smarkm				IAC, SE);
33729088Smarkm			nfrontp += 7;
33829088Smarkm			editmode = useeditmode;
33929088Smarkm		}
34029088Smarkm
34129088Smarkm
34229088Smarkm		/*
34329088Smarkm		 * Check for changes to special characters in use.
34429088Smarkm		 */
34529088Smarkm		start_slc(0);
34629088Smarkm		check_slc();
34729088Smarkm		(void) end_slc(0);
34829088Smarkm	}
34929088Smarkm
35029088Smarkmdone:
35129088Smarkm	if (need_will_echo)
35229088Smarkm		send_will(TELOPT_ECHO, 1);
35329088Smarkm	/*
35429088Smarkm	 * Some things should be deferred until after the pty state has
35529088Smarkm	 * been set by the local process.  Do those things that have been
35629088Smarkm	 * deferred now.  This only happens once.
35729088Smarkm	 */
35829088Smarkm	if (_terminit == 0) {
35929088Smarkm		_terminit = 1;
36029088Smarkm		defer_terminit();
36129088Smarkm	}
36229088Smarkm
36329088Smarkm	netflush();
36429088Smarkm	set_termbuf();
36529088Smarkm	return;
36629088Smarkm
36729088Smarkm}  /* end of localstat */
36829088Smarkm#endif	/* LINEMODE */
36929088Smarkm
37029088Smarkm/*
37129088Smarkm * flowstat
37229088Smarkm *
37329088Smarkm * Check for changes to flow control
37429088Smarkm */
37529088Smarkm	void
37629088Smarkmflowstat()
37729088Smarkm{
37829088Smarkm	if (his_state_is_will(TELOPT_LFLOW)) {
37929088Smarkm		if (tty_flowmode() != flowmode) {
38029088Smarkm			flowmode = tty_flowmode();
38129088Smarkm			(void) sprintf(nfrontp, "%c%c%c%c%c%c",
38229088Smarkm					IAC, SB, TELOPT_LFLOW,
38329088Smarkm					flowmode ? LFLOW_ON : LFLOW_OFF,
38429088Smarkm					IAC, SE);
38529088Smarkm			nfrontp += 6;
38629088Smarkm		}
38729088Smarkm		if (tty_restartany() != restartany) {
38829088Smarkm			restartany = tty_restartany();
38929088Smarkm			(void) sprintf(nfrontp, "%c%c%c%c%c%c",
39029088Smarkm					IAC, SB, TELOPT_LFLOW,
39129088Smarkm					restartany ? LFLOW_RESTART_ANY
39229088Smarkm						   : LFLOW_RESTART_XON,
39329088Smarkm					IAC, SE);
39429088Smarkm			nfrontp += 6;
39529088Smarkm		}
39629088Smarkm	}
39729088Smarkm}
39829088Smarkm
39929088Smarkm/*
40029088Smarkm * clientstat
40129088Smarkm *
40229088Smarkm * Process linemode related requests from the client.
40329088Smarkm * Client can request a change to only one of linemode, editmode or slc's
40429088Smarkm * at a time, and if using kludge linemode, then only linemode may be
40529088Smarkm * affected.
40629088Smarkm */
40729088Smarkm	void
40829088Smarkmclientstat(code, parm1, parm2)
40929088Smarkm	register int code, parm1, parm2;
41029088Smarkm{
41129088Smarkm	void netflush();
41229088Smarkm
41329088Smarkm	/*
41429088Smarkm	 * Get a copy of terminal characteristics.
41529088Smarkm	 */
41629088Smarkm	init_termbuf();
41729088Smarkm
41829088Smarkm	/*
41929088Smarkm	 * Process request from client. code tells what it is.
42029088Smarkm	 */
42129088Smarkm	switch (code) {
42229088Smarkm#ifdef	LINEMODE
42329088Smarkm	case TELOPT_LINEMODE:
42429088Smarkm		/*
42529088Smarkm		 * Don't do anything unless client is asking us to change
42629088Smarkm		 * modes.
42729088Smarkm		 */
42829088Smarkm		uselinemode = (parm1 == WILL);
42929088Smarkm		if (uselinemode != linemode) {
43029088Smarkm# ifdef	KLUDGELINEMODE
43129088Smarkm			/*
43229088Smarkm			 * If using kludge linemode, make sure that
43329088Smarkm			 * we can do what the client asks.
43429088Smarkm			 * We can not turn off linemode if alwayslinemode
43529088Smarkm			 * and the ICANON bit is set.
43629088Smarkm			 */
43729088Smarkm			if (lmodetype == KLUDGE_LINEMODE) {
43829088Smarkm				if (alwayslinemode && tty_isediting()) {
43929088Smarkm					uselinemode = 1;
44029088Smarkm				}
44129088Smarkm			}
44229088Smarkm
44329088Smarkm			/*
44429088Smarkm			 * Quit now if we can't do it.
44529088Smarkm			 */
44629088Smarkm			if (uselinemode == linemode)
44729088Smarkm				return;
44829088Smarkm
44929088Smarkm			/*
45029088Smarkm			 * If using real linemode and linemode is being
45129088Smarkm			 * turned on, send along the edit mode mask.
45229088Smarkm			 */
45329088Smarkm			if (lmodetype == REAL_LINEMODE && uselinemode)
45429088Smarkm# else	/* KLUDGELINEMODE */
45529088Smarkm			if (uselinemode)
45629088Smarkm# endif	/* KLUDGELINEMODE */
45729088Smarkm			{
45829088Smarkm				useeditmode = 0;
45929088Smarkm				if (tty_isediting())
46029088Smarkm					useeditmode |= MODE_EDIT;
46129088Smarkm				if (tty_istrapsig)
46229088Smarkm					useeditmode |= MODE_TRAPSIG;
46329088Smarkm				if (tty_issofttab())
46429088Smarkm					useeditmode |= MODE_SOFT_TAB;
46529088Smarkm				if (tty_islitecho())
46629088Smarkm					useeditmode |= MODE_LIT_ECHO;
46729088Smarkm				(void) sprintf(nfrontp, "%c%c%c%c%c%c%c", IAC,
46829088Smarkm					SB, TELOPT_LINEMODE, LM_MODE,
46929088Smarkm							useeditmode, IAC, SE);
47029088Smarkm				nfrontp += 7;
47129088Smarkm				editmode = useeditmode;
47229088Smarkm			}
47329088Smarkm
47429088Smarkm
47529088Smarkm			tty_setlinemode(uselinemode);
47629088Smarkm
47729088Smarkm			linemode = uselinemode;
47829088Smarkm
47929088Smarkm			if (!linemode)
48029088Smarkm				send_will(TELOPT_ECHO, 1);
48129088Smarkm		}
48229088Smarkm		break;
48329088Smarkm
48429088Smarkm	case LM_MODE:
48529088Smarkm	    {
48629088Smarkm		register int ack, changed;
48729088Smarkm
48829088Smarkm		/*
48929088Smarkm		 * Client has sent along a mode mask.  If it agrees with
49029088Smarkm		 * what we are currently doing, ignore it; if not, it could
49129088Smarkm		 * be viewed as a request to change.  Note that the server
49229088Smarkm		 * will change to the modes in an ack if it is different from
49329088Smarkm		 * what we currently have, but we will not ack the ack.
49429088Smarkm		 */
49529088Smarkm		 useeditmode &= MODE_MASK;
49629088Smarkm		 ack = (useeditmode & MODE_ACK);
49729088Smarkm		 useeditmode &= ~MODE_ACK;
49829088Smarkm
49929181Smarkm		 if ((changed = (useeditmode ^ editmode))) {
50029088Smarkm			/*
50129088Smarkm			 * This check is for a timing problem.  If the
50229088Smarkm			 * state of the tty has changed (due to the user
50329088Smarkm			 * application) we need to process that info
50429088Smarkm			 * before we write in the state contained in the
50529088Smarkm			 * ack!!!  This gets out the new MODE request,
50629088Smarkm			 * and when the ack to that command comes back
50729088Smarkm			 * we'll set it and be in the right mode.
50829088Smarkm			 */
50929088Smarkm			if (ack)
51029088Smarkm				localstat();
51129088Smarkm			if (changed & MODE_EDIT)
51229088Smarkm				tty_setedit(useeditmode & MODE_EDIT);
51329088Smarkm
51429088Smarkm			if (changed & MODE_TRAPSIG)
51529088Smarkm				tty_setsig(useeditmode & MODE_TRAPSIG);
51629088Smarkm
51729088Smarkm			if (changed & MODE_SOFT_TAB)
51829088Smarkm				tty_setsofttab(useeditmode & MODE_SOFT_TAB);
51929088Smarkm
52029088Smarkm			if (changed & MODE_LIT_ECHO)
52129088Smarkm				tty_setlitecho(useeditmode & MODE_LIT_ECHO);
52229088Smarkm
52329088Smarkm			set_termbuf();
52429088Smarkm
52529088Smarkm 			if (!ack) {
52629088Smarkm 				(void) sprintf(nfrontp, "%c%c%c%c%c%c%c", IAC,
52729088Smarkm					SB, TELOPT_LINEMODE, LM_MODE,
52829088Smarkm 					useeditmode|MODE_ACK,
52929088Smarkm 					IAC, SE);
53029088Smarkm 				nfrontp += 7;
53129088Smarkm 			}
53229088Smarkm
53329088Smarkm			editmode = useeditmode;
53429088Smarkm		}
53529088Smarkm
53629088Smarkm		break;
53729088Smarkm
53829088Smarkm	    }  /* end of case LM_MODE */
53929088Smarkm#endif	/* LINEMODE */
54029088Smarkm
54129088Smarkm	case TELOPT_NAWS:
54229088Smarkm#ifdef	TIOCSWINSZ
54329088Smarkm	    {
54429088Smarkm		struct winsize ws;
54529088Smarkm
54629088Smarkm		def_col = parm1;
54729088Smarkm		def_row = parm2;
54829088Smarkm#ifdef	LINEMODE
54929088Smarkm		/*
55029088Smarkm		 * Defer changing window size until after terminal is
55129088Smarkm		 * initialized.
55229088Smarkm		 */
55329088Smarkm		if (terminit() == 0)
55429088Smarkm			return;
55529088Smarkm#endif	/* LINEMODE */
55629088Smarkm
55729088Smarkm		/*
55829088Smarkm		 * Change window size as requested by client.
55929088Smarkm		 */
56029088Smarkm
56129088Smarkm		ws.ws_col = parm1;
56229088Smarkm		ws.ws_row = parm2;
56329088Smarkm		(void) ioctl(pty, TIOCSWINSZ, (char *)&ws);
56429088Smarkm	    }
56529088Smarkm#endif	/* TIOCSWINSZ */
56629088Smarkm
56729088Smarkm		break;
56829088Smarkm
56929088Smarkm	case TELOPT_TSPEED:
57029088Smarkm	    {
57129088Smarkm		def_tspeed = parm1;
57229088Smarkm		def_rspeed = parm2;
57329088Smarkm#ifdef	LINEMODE
57429088Smarkm		/*
57529088Smarkm		 * Defer changing the terminal speed.
57629088Smarkm		 */
57729088Smarkm		if (terminit() == 0)
57829088Smarkm			return;
57929088Smarkm#endif	/* LINEMODE */
58029088Smarkm		/*
58129088Smarkm		 * Change terminal speed as requested by client.
58229088Smarkm		 * We set the receive speed first, so that if we can't
58372089Sasmodai		 * store separate receive and transmit speeds, the transmit
58429088Smarkm		 * speed will take precedence.
58529088Smarkm		 */
58629088Smarkm		tty_rspeed(parm2);
58729088Smarkm		tty_tspeed(parm1);
58829088Smarkm		set_termbuf();
58929088Smarkm
59029088Smarkm		break;
59129088Smarkm
59229088Smarkm	    }  /* end of case TELOPT_TSPEED */
59329088Smarkm
59429088Smarkm	default:
59529088Smarkm		/* What? */
59629088Smarkm		break;
59729088Smarkm	}  /* end of switch */
59829088Smarkm
59929088Smarkm#if	defined(CRAY2) && defined(UNICOS5)
60029088Smarkm	/*
60129088Smarkm	 * Just in case of the likely event that we changed the pty state.
60229088Smarkm	 */
60329088Smarkm	rcv_ioctl();
60429088Smarkm#endif	/* defined(CRAY2) && defined(UNICOS5) */
60529088Smarkm
60629088Smarkm	netflush();
60729088Smarkm
60829088Smarkm}  /* end of clientstat */
60929088Smarkm
61029088Smarkm#if	defined(CRAY2) && defined(UNICOS5)
61129088Smarkm	void
61229088Smarkmtermstat()
61329088Smarkm{
61429088Smarkm	needtermstat = 1;
61529088Smarkm}
61629088Smarkm
61729088Smarkm	void
61829088Smarkm_termstat()
61929088Smarkm{
62029088Smarkm	needtermstat = 0;
62129088Smarkm	init_termbuf();
62229088Smarkm	localstat();
62329088Smarkm	rcv_ioctl();
62429088Smarkm}
62529088Smarkm#endif	/* defined(CRAY2) && defined(UNICOS5) */
62629088Smarkm
62729088Smarkm#ifdef	LINEMODE
62829088Smarkm/*
62929088Smarkm * defer_terminit
63029088Smarkm *
63129088Smarkm * Some things should not be done until after the login process has started
63229088Smarkm * and all the pty modes are set to what they are supposed to be.  This
63329088Smarkm * function is called when the pty state has been processed for the first time.
63429088Smarkm * It calls other functions that do things that were deferred in each module.
63529088Smarkm */
63629088Smarkm	void
63729088Smarkmdefer_terminit()
63829088Smarkm{
63929088Smarkm
64029088Smarkm	/*
64129088Smarkm	 * local stuff that got deferred.
64229088Smarkm	 */
64329088Smarkm	if (def_tspeed != -1) {
64429088Smarkm		clientstat(TELOPT_TSPEED, def_tspeed, def_rspeed);
64529088Smarkm		def_tspeed = def_rspeed = 0;
64629088Smarkm	}
64729088Smarkm
64829088Smarkm#ifdef	TIOCSWINSZ
64929088Smarkm	if (def_col || def_row) {
65029088Smarkm		struct winsize ws;
65129088Smarkm
65229088Smarkm		memset((char *)&ws, 0, sizeof(ws));
65329088Smarkm		ws.ws_col = def_col;
65429088Smarkm		ws.ws_row = def_row;
65529088Smarkm		(void) ioctl(pty, TIOCSWINSZ, (char *)&ws);
65629088Smarkm	}
65729088Smarkm#endif
65829088Smarkm
65929088Smarkm	/*
66029088Smarkm	 * The only other module that currently defers anything.
66129088Smarkm	 */
66229088Smarkm	deferslc();
66329088Smarkm
66429088Smarkm}  /* end of defer_terminit */
66529088Smarkm
66629088Smarkm/*
66729088Smarkm * terminit
66829088Smarkm *
66929088Smarkm * Returns true if the pty state has been processed yet.
67029088Smarkm */
67129088Smarkm	int
67229088Smarkmterminit()
67329088Smarkm{
67429088Smarkm	return(_terminit);
67529088Smarkm
67629088Smarkm}  /* end of terminit */
67729088Smarkm#endif	/* LINEMODE */
678