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
34114630Sobrien#if 0
3529088Smarkm#ifndef lint
3629181Smarkmstatic const char sccsid[] = "@(#)termstat.c	8.2 (Berkeley) 5/30/95";
3731622Scharnier#endif
38114630Sobrien#endif
39114630Sobrien#include <sys/cdefs.h>
40114630Sobrien__FBSDID("$FreeBSD$");
4129088Smarkm
4229088Smarkm#include "telnetd.h"
4329088Smarkm
4487139Smarkm#ifdef	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#ifdef	LINEMODE
6029088Smarkm/*
6129088Smarkm * localstat
6229088Smarkm *
6329088Smarkm * This function handles all management of linemode.
6429088Smarkm *
6529088Smarkm * Linemode allows the client to do the local editing of data
6629088Smarkm * and send only complete lines to the server.  Linemode state is
6729088Smarkm * based on the state of the pty driver.  If the pty is set for
6829088Smarkm * external processing, then we can use linemode.  Further, if we
6929088Smarkm * can use real linemode, then we can look at the edit control bits
7029088Smarkm * in the pty to determine what editing the client should do.
7129088Smarkm *
7229088Smarkm * Linemode support uses the following state flags to keep track of
7329088Smarkm * current and desired linemode state.
7429088Smarkm *	alwayslinemode : true if -l was specified on the telnetd
7529088Smarkm * 	command line.  It means to have linemode on as much as
7629088Smarkm *	possible.
7729088Smarkm *
7829088Smarkm * 	lmodetype: signifies whether the client can
7929088Smarkm *	handle real linemode, or if use of kludgeomatic linemode
8029088Smarkm *	is preferred.  It will be set to one of the following:
8129088Smarkm *		REAL_LINEMODE : use linemode option
8229088Smarkm *		NO_KLUDGE : don't initiate kludge linemode.
8329088Smarkm *		KLUDGE_LINEMODE : use kludge linemode
8429088Smarkm *		NO_LINEMODE : client is ignorant of linemode
8529088Smarkm *
8629088Smarkm *	linemode, uselinemode : linemode is true if linemode
8729088Smarkm *	is currently on, uselinemode is the state that we wish
8829088Smarkm *	to be in.  If another function wishes to turn linemode
8929088Smarkm *	on or off, it sets or clears uselinemode.
9029088Smarkm *
9129088Smarkm *	editmode, useeditmode : like linemode/uselinemode, but
9229088Smarkm *	these contain the edit mode states (edit and trapsig).
9329088Smarkm *
9429088Smarkm * The state variables correspond to some of the state information
9529088Smarkm * in the pty.
9629088Smarkm *	linemode:
9729088Smarkm *		In real linemode, this corresponds to whether the pty
9829088Smarkm *		expects external processing of incoming data.
9929088Smarkm *		In kludge linemode, this more closely corresponds to the
10029088Smarkm *		whether normal processing is on or not.  (ICANON in
10129088Smarkm *		system V, or COOKED mode in BSD.)
10229088Smarkm *		If the -l option was specified (alwayslinemode), then
10329088Smarkm *		an attempt is made to force external processing on at
10429088Smarkm *		all times.
10529088Smarkm *
10629088Smarkm * The following heuristics are applied to determine linemode
10729088Smarkm * handling within the server.
10829088Smarkm *	1) Early on in starting up the server, an attempt is made
10929088Smarkm *	   to negotiate the linemode option.  If this succeeds
11029088Smarkm *	   then lmodetype is set to REAL_LINEMODE and all linemode
11129088Smarkm *	   processing occurs in the context of the linemode option.
11229088Smarkm *	2) If the attempt to negotiate the linemode option failed,
11329088Smarkm *	   and the "-k" (don't initiate kludge linemode) isn't set,
11429088Smarkm *	   then we try to use kludge linemode.  We test for this
11529088Smarkm *	   capability by sending "do Timing Mark".  If a positive
11629088Smarkm *	   response comes back, then we assume that the client
11729088Smarkm *	   understands kludge linemode (ech!) and the
11829088Smarkm *	   lmodetype flag is set to KLUDGE_LINEMODE.
11929088Smarkm *	3) Otherwise, linemode is not supported at all and
12029088Smarkm *	   lmodetype remains set to NO_LINEMODE (which happens
12129088Smarkm *	   to be 0 for convenience).
12229088Smarkm *	4) At any time a command arrives that implies a higher
12329088Smarkm *	   state of linemode support in the client, we move to that
12429088Smarkm *	   linemode support.
12529088Smarkm *
12629088Smarkm * A short explanation of kludge linemode is in order here.
12729088Smarkm *	1) The heuristic to determine support for kludge linemode
12829088Smarkm *	   is to send a do timing mark.  We assume that a client
12929088Smarkm *	   that supports timing marks also supports kludge linemode.
13029088Smarkm *	   A risky proposition at best.
13129088Smarkm *	2) Further negotiation of linemode is done by changing the
13229088Smarkm *	   the server's state regarding SGA.  If server will SGA,
13329088Smarkm *	   then linemode is off, if server won't SGA, then linemode
13429088Smarkm *	   is on.
13529088Smarkm */
13687139Smarkmvoid
13787139Smarkmlocalstat(void)
13829088Smarkm{
13929088Smarkm	int need_will_echo = 0;
14029088Smarkm
14129088Smarkm	/*
14229181Smarkm	 * Check for changes to flow control if client supports it.
14329181Smarkm	 */
14429181Smarkm	flowstat();
14529181Smarkm
14629181Smarkm	/*
14729181Smarkm	 * Check linemode on/off state
14829181Smarkm	 */
14929181Smarkm	uselinemode = tty_linemode();
15029181Smarkm
15129181Smarkm	/*
15229181Smarkm	 * If alwayslinemode is on, and pty is changing to turn it off, then
15329181Smarkm	 * force linemode back on.
15429181Smarkm	 */
15529181Smarkm	if (alwayslinemode && linemode && !uselinemode) {
15629181Smarkm		uselinemode = 1;
15729181Smarkm		tty_setlinemode(uselinemode);
15829181Smarkm	}
15929181Smarkm
16029181Smarkm	if (uselinemode) {
16129181Smarkm		/*
16281965Smarkm		 * Check for state of BINARY options.
16329181Smarkm		 *
16429181Smarkm		 * We only need to do the binary dance if we are actually going
16529181Smarkm		 * to use linemode.  As this confuses some telnet clients
16629181Smarkm		 * that don't support linemode, and doesn't gain us
16729181Smarkm		 * anything, we don't do it unless we're doing linemode.
16829181Smarkm		 * -Crh (henrich@msu.edu)
16981965Smarkm		 */
17029181Smarkm
17181965Smarkm		if (tty_isbinaryin()) {
17281965Smarkm			if (his_want_state_is_wont(TELOPT_BINARY))
17381965Smarkm				send_do(TELOPT_BINARY, 1);
17481965Smarkm		} else {
17581965Smarkm			if (his_want_state_is_will(TELOPT_BINARY))
17681965Smarkm				send_dont(TELOPT_BINARY, 1);
17781965Smarkm		}
17829088Smarkm
17981965Smarkm		if (tty_isbinaryout()) {
18081965Smarkm			if (my_want_state_is_wont(TELOPT_BINARY))
18181965Smarkm				send_will(TELOPT_BINARY, 1);
18281965Smarkm		} else {
18381965Smarkm			if (my_want_state_is_will(TELOPT_BINARY))
18481965Smarkm				send_wont(TELOPT_BINARY, 1);
18581965Smarkm		}
18629088Smarkm	}
18729088Smarkm
18829088Smarkm#ifdef	ENCRYPTION
18929088Smarkm	/*
19029088Smarkm	 * If the terminal is not echoing, but editing is enabled,
19129088Smarkm	 * something like password input is going to happen, so
19229088Smarkm	 * if we the other side is not currently sending encrypted
19329088Smarkm	 * data, ask the other side to start encrypting.
19429088Smarkm	 */
19529088Smarkm	if (his_state_is_will(TELOPT_ENCRYPT)) {
19629088Smarkm		static int enc_passwd = 0;
19729088Smarkm		if (uselinemode && !tty_isecho() && tty_isediting()
19829088Smarkm		    && (enc_passwd == 0) && !decrypt_input) {
19929088Smarkm			encrypt_send_request_start();
20029088Smarkm			enc_passwd = 1;
20129088Smarkm		} else if (enc_passwd) {
20229088Smarkm			encrypt_send_request_end();
20329088Smarkm			enc_passwd = 0;
20429088Smarkm		}
20529088Smarkm	}
20629088Smarkm#endif	/* ENCRYPTION */
20729088Smarkm
20829088Smarkm	/*
20929088Smarkm	 * Do echo mode handling as soon as we know what the
21029088Smarkm	 * linemode is going to be.
21129088Smarkm	 * If the pty has echo turned off, then tell the client that
21229088Smarkm	 * the server will echo.  If echo is on, then the server
21329088Smarkm	 * will echo if in character mode, but in linemode the
21429088Smarkm	 * client should do local echoing.  The state machine will
21529088Smarkm	 * not send anything if it is unnecessary, so don't worry
21629088Smarkm	 * about that here.
21729088Smarkm	 *
21829088Smarkm	 * If we need to send the WILL ECHO (because echo is off),
21929088Smarkm	 * then delay that until after we have changed the MODE.
22029088Smarkm	 * This way, when the user is turning off both editing
22129088Smarkm	 * and echo, the client will get editing turned off first.
22229088Smarkm	 * This keeps the client from going into encryption mode
22329088Smarkm	 * and then right back out if it is doing auto-encryption
22429088Smarkm	 * when passwords are being typed.
22529088Smarkm	 */
22629088Smarkm	if (uselinemode) {
22729088Smarkm		if (tty_isecho())
22829088Smarkm			send_wont(TELOPT_ECHO, 1);
22929088Smarkm		else
23029088Smarkm			need_will_echo = 1;
23129088Smarkm#ifdef	KLUDGELINEMODE
23229088Smarkm		if (lmodetype == KLUDGE_OK)
23329088Smarkm			lmodetype = KLUDGE_LINEMODE;
23429088Smarkm#endif
23529088Smarkm	}
23629088Smarkm
23729088Smarkm	/*
23829088Smarkm	 * If linemode is being turned off, send appropriate
23929088Smarkm	 * command and then we're all done.
24029088Smarkm	 */
24129088Smarkm	 if (!uselinemode && linemode) {
24229088Smarkm# ifdef	KLUDGELINEMODE
24329088Smarkm		if (lmodetype == REAL_LINEMODE) {
24429088Smarkm# endif	/* KLUDGELINEMODE */
24529088Smarkm			send_dont(TELOPT_LINEMODE, 1);
24629088Smarkm# ifdef	KLUDGELINEMODE
24729088Smarkm		} else if (lmodetype == KLUDGE_LINEMODE)
24829088Smarkm			send_will(TELOPT_SGA, 1);
24929088Smarkm# endif	/* KLUDGELINEMODE */
25029088Smarkm		send_will(TELOPT_ECHO, 1);
25129088Smarkm		linemode = uselinemode;
25229088Smarkm		goto done;
25329088Smarkm	}
25429088Smarkm
25529088Smarkm# ifdef	KLUDGELINEMODE
25629088Smarkm	/*
25729088Smarkm	 * If using real linemode check edit modes for possible later use.
25829088Smarkm	 * If we are in kludge linemode, do the SGA negotiation.
25929088Smarkm	 */
26029088Smarkm	if (lmodetype == REAL_LINEMODE) {
26129088Smarkm# endif	/* KLUDGELINEMODE */
26229088Smarkm		useeditmode = 0;
26329088Smarkm		if (tty_isediting())
26429088Smarkm			useeditmode |= MODE_EDIT;
26529088Smarkm		if (tty_istrapsig())
26629088Smarkm			useeditmode |= MODE_TRAPSIG;
26729088Smarkm		if (tty_issofttab())
26829088Smarkm			useeditmode |= MODE_SOFT_TAB;
26929088Smarkm		if (tty_islitecho())
27029088Smarkm			useeditmode |= MODE_LIT_ECHO;
27129088Smarkm# ifdef	KLUDGELINEMODE
27229088Smarkm	} else if (lmodetype == KLUDGE_LINEMODE) {
27329088Smarkm		if (tty_isediting() && uselinemode)
27429088Smarkm			send_wont(TELOPT_SGA, 1);
27529088Smarkm		else
27629088Smarkm			send_will(TELOPT_SGA, 1);
27729088Smarkm	}
27829088Smarkm# endif	/* KLUDGELINEMODE */
27929088Smarkm
28029088Smarkm	/*
28129088Smarkm	 * Negotiate linemode on if pty state has changed to turn it on.
28229088Smarkm	 * Send appropriate command and send along edit mode, then all done.
28329088Smarkm	 */
28429088Smarkm	if (uselinemode && !linemode) {
28529088Smarkm# ifdef	KLUDGELINEMODE
28629088Smarkm		if (lmodetype == KLUDGE_LINEMODE) {
28729088Smarkm			send_wont(TELOPT_SGA, 1);
28829088Smarkm		} else if (lmodetype == REAL_LINEMODE) {
28929088Smarkm# endif	/* KLUDGELINEMODE */
29029088Smarkm			send_do(TELOPT_LINEMODE, 1);
29129088Smarkm			/* send along edit modes */
29279981Sru			output_data("%c%c%c%c%c%c%c", IAC, SB,
29329088Smarkm				TELOPT_LINEMODE, LM_MODE, useeditmode,
29429088Smarkm				IAC, SE);
29529088Smarkm			editmode = useeditmode;
29629088Smarkm# ifdef	KLUDGELINEMODE
29729088Smarkm		}
29829088Smarkm# endif	/* KLUDGELINEMODE */
29929088Smarkm		linemode = uselinemode;
30029088Smarkm		goto done;
30129088Smarkm	}
30229088Smarkm
30329088Smarkm# ifdef	KLUDGELINEMODE
30429088Smarkm	/*
30529088Smarkm	 * None of what follows is of any value if not using
30629088Smarkm	 * real linemode.
30729088Smarkm	 */
30829088Smarkm	if (lmodetype < REAL_LINEMODE)
30929088Smarkm		goto done;
31029088Smarkm# endif	/* KLUDGELINEMODE */
31129088Smarkm
31229088Smarkm	if (linemode && his_state_is_will(TELOPT_LINEMODE)) {
31329088Smarkm		/*
31429088Smarkm		 * If edit mode changed, send edit mode.
31529088Smarkm		 */
31629088Smarkm		 if (useeditmode != editmode) {
31729088Smarkm			/*
31829088Smarkm			 * Send along appropriate edit mode mask.
31929088Smarkm			 */
32079981Sru			output_data("%c%c%c%c%c%c%c", IAC, SB,
32129088Smarkm				TELOPT_LINEMODE, LM_MODE, useeditmode,
32229088Smarkm				IAC, SE);
32329088Smarkm			editmode = useeditmode;
32429088Smarkm		}
32529088Smarkm
32629088Smarkm
32729088Smarkm		/*
32829088Smarkm		 * Check for changes to special characters in use.
32929088Smarkm		 */
33029088Smarkm		start_slc(0);
33129088Smarkm		check_slc();
33229088Smarkm		(void) end_slc(0);
33329088Smarkm	}
33429088Smarkm
33529088Smarkmdone:
33629088Smarkm	if (need_will_echo)
33729088Smarkm		send_will(TELOPT_ECHO, 1);
33829088Smarkm	/*
33929088Smarkm	 * Some things should be deferred until after the pty state has
34029088Smarkm	 * been set by the local process.  Do those things that have been
34129088Smarkm	 * deferred now.  This only happens once.
34229088Smarkm	 */
34329088Smarkm	if (_terminit == 0) {
34429088Smarkm		_terminit = 1;
34529088Smarkm		defer_terminit();
34629088Smarkm	}
34729088Smarkm
34829088Smarkm	netflush();
34929088Smarkm	set_termbuf();
35029088Smarkm	return;
35129088Smarkm
35229088Smarkm}  /* end of localstat */
35329088Smarkm#endif	/* LINEMODE */
35429088Smarkm
35529088Smarkm/*
35629088Smarkm * flowstat
35729088Smarkm *
35829088Smarkm * Check for changes to flow control
35929088Smarkm */
36087139Smarkmvoid
36187139Smarkmflowstat(void)
36229088Smarkm{
36329088Smarkm	if (his_state_is_will(TELOPT_LFLOW)) {
36429088Smarkm		if (tty_flowmode() != flowmode) {
36529088Smarkm			flowmode = tty_flowmode();
36679981Sru			output_data("%c%c%c%c%c%c",
36729088Smarkm					IAC, SB, TELOPT_LFLOW,
36829088Smarkm					flowmode ? LFLOW_ON : LFLOW_OFF,
36929088Smarkm					IAC, SE);
37029088Smarkm		}
37129088Smarkm		if (tty_restartany() != restartany) {
37229088Smarkm			restartany = tty_restartany();
37379981Sru			output_data("%c%c%c%c%c%c",
37429088Smarkm					IAC, SB, TELOPT_LFLOW,
37529088Smarkm					restartany ? LFLOW_RESTART_ANY
37629088Smarkm						   : LFLOW_RESTART_XON,
37729088Smarkm					IAC, SE);
37829088Smarkm		}
37929088Smarkm	}
38029088Smarkm}
38129088Smarkm
38229088Smarkm/*
38329088Smarkm * clientstat
38429088Smarkm *
38529088Smarkm * Process linemode related requests from the client.
38629088Smarkm * Client can request a change to only one of linemode, editmode or slc's
38729088Smarkm * at a time, and if using kludge linemode, then only linemode may be
38829088Smarkm * affected.
38929088Smarkm */
39087139Smarkmvoid
39187139Smarkmclientstat(int code, int parm1, int parm2)
39229088Smarkm{
39329088Smarkm
39429088Smarkm	/*
39529088Smarkm	 * Get a copy of terminal characteristics.
39629088Smarkm	 */
39729088Smarkm	init_termbuf();
39829088Smarkm
39929088Smarkm	/*
40029088Smarkm	 * Process request from client. code tells what it is.
40129088Smarkm	 */
40229088Smarkm	switch (code) {
40329088Smarkm#ifdef	LINEMODE
40429088Smarkm	case TELOPT_LINEMODE:
40529088Smarkm		/*
40629088Smarkm		 * Don't do anything unless client is asking us to change
40729088Smarkm		 * modes.
40829088Smarkm		 */
40929088Smarkm		uselinemode = (parm1 == WILL);
41029088Smarkm		if (uselinemode != linemode) {
41129088Smarkm# ifdef	KLUDGELINEMODE
41229088Smarkm			/*
41329088Smarkm			 * If using kludge linemode, make sure that
41429088Smarkm			 * we can do what the client asks.
41529088Smarkm			 * We can not turn off linemode if alwayslinemode
41629088Smarkm			 * and the ICANON bit is set.
41729088Smarkm			 */
41829088Smarkm			if (lmodetype == KLUDGE_LINEMODE) {
41929088Smarkm				if (alwayslinemode && tty_isediting()) {
42029088Smarkm					uselinemode = 1;
42129088Smarkm				}
42229088Smarkm			}
42329088Smarkm
42429088Smarkm			/*
42529088Smarkm			 * Quit now if we can't do it.
42629088Smarkm			 */
42729088Smarkm			if (uselinemode == linemode)
42829088Smarkm				return;
42929088Smarkm
43029088Smarkm			/*
43129088Smarkm			 * If using real linemode and linemode is being
43229088Smarkm			 * turned on, send along the edit mode mask.
43329088Smarkm			 */
43429088Smarkm			if (lmodetype == REAL_LINEMODE && uselinemode)
43529088Smarkm# else	/* KLUDGELINEMODE */
43629088Smarkm			if (uselinemode)
43729088Smarkm# endif	/* KLUDGELINEMODE */
43829088Smarkm			{
43929088Smarkm				useeditmode = 0;
44029088Smarkm				if (tty_isediting())
44129088Smarkm					useeditmode |= MODE_EDIT;
442132753Skan				if (tty_istrapsig())
44329088Smarkm					useeditmode |= MODE_TRAPSIG;
44429088Smarkm				if (tty_issofttab())
44529088Smarkm					useeditmode |= MODE_SOFT_TAB;
44629088Smarkm				if (tty_islitecho())
44729088Smarkm					useeditmode |= MODE_LIT_ECHO;
44879981Sru				output_data("%c%c%c%c%c%c%c", IAC,
44929088Smarkm					SB, TELOPT_LINEMODE, LM_MODE,
45029088Smarkm							useeditmode, IAC, SE);
45129088Smarkm				editmode = useeditmode;
45229088Smarkm			}
45329088Smarkm
45429088Smarkm
45529088Smarkm			tty_setlinemode(uselinemode);
45629088Smarkm
45729088Smarkm			linemode = uselinemode;
45829088Smarkm
45929088Smarkm			if (!linemode)
46029088Smarkm				send_will(TELOPT_ECHO, 1);
46129088Smarkm		}
46229088Smarkm		break;
46329088Smarkm
46429088Smarkm	case LM_MODE:
46529088Smarkm	    {
46687139Smarkm		int ack, changed;
46729088Smarkm
46829088Smarkm		/*
46929088Smarkm		 * Client has sent along a mode mask.  If it agrees with
47029088Smarkm		 * what we are currently doing, ignore it; if not, it could
47129088Smarkm		 * be viewed as a request to change.  Note that the server
47229088Smarkm		 * will change to the modes in an ack if it is different from
47329088Smarkm		 * what we currently have, but we will not ack the ack.
47429088Smarkm		 */
47529088Smarkm		 useeditmode &= MODE_MASK;
47629088Smarkm		 ack = (useeditmode & MODE_ACK);
47729088Smarkm		 useeditmode &= ~MODE_ACK;
47829088Smarkm
47929181Smarkm		 if ((changed = (useeditmode ^ editmode))) {
48029088Smarkm			/*
48129088Smarkm			 * This check is for a timing problem.  If the
48229088Smarkm			 * state of the tty has changed (due to the user
48329088Smarkm			 * application) we need to process that info
48429088Smarkm			 * before we write in the state contained in the
48529088Smarkm			 * ack!!!  This gets out the new MODE request,
48629088Smarkm			 * and when the ack to that command comes back
48729088Smarkm			 * we'll set it and be in the right mode.
48829088Smarkm			 */
48929088Smarkm			if (ack)
49029088Smarkm				localstat();
49129088Smarkm			if (changed & MODE_EDIT)
49229088Smarkm				tty_setedit(useeditmode & MODE_EDIT);
49329088Smarkm
49429088Smarkm			if (changed & MODE_TRAPSIG)
49529088Smarkm				tty_setsig(useeditmode & MODE_TRAPSIG);
49629088Smarkm
49729088Smarkm			if (changed & MODE_SOFT_TAB)
49829088Smarkm				tty_setsofttab(useeditmode & MODE_SOFT_TAB);
49929088Smarkm
50029088Smarkm			if (changed & MODE_LIT_ECHO)
50129088Smarkm				tty_setlitecho(useeditmode & MODE_LIT_ECHO);
50229088Smarkm
50329088Smarkm			set_termbuf();
50429088Smarkm
50529088Smarkm 			if (!ack) {
50679981Sru				output_data("%c%c%c%c%c%c%c", IAC,
50729088Smarkm					SB, TELOPT_LINEMODE, LM_MODE,
50829088Smarkm 					useeditmode|MODE_ACK,
50929088Smarkm 					IAC, SE);
51029088Smarkm 			}
51129088Smarkm
51229088Smarkm			editmode = useeditmode;
51329088Smarkm		}
51429088Smarkm
51529088Smarkm		break;
51629088Smarkm
51729088Smarkm	    }  /* end of case LM_MODE */
51829088Smarkm#endif	/* LINEMODE */
51929088Smarkm
52029088Smarkm	case TELOPT_NAWS:
52129088Smarkm#ifdef	TIOCSWINSZ
52229088Smarkm	    {
52329088Smarkm		struct winsize ws;
52429088Smarkm
52529088Smarkm		def_col = parm1;
52629088Smarkm		def_row = parm2;
52729088Smarkm#ifdef	LINEMODE
52829088Smarkm		/*
52929088Smarkm		 * Defer changing window size until after terminal is
53029088Smarkm		 * initialized.
53129088Smarkm		 */
53229088Smarkm		if (terminit() == 0)
53329088Smarkm			return;
53429088Smarkm#endif	/* LINEMODE */
53529088Smarkm
53629088Smarkm		/*
53729088Smarkm		 * Change window size as requested by client.
53829088Smarkm		 */
53929088Smarkm
54029088Smarkm		ws.ws_col = parm1;
54129088Smarkm		ws.ws_row = parm2;
54229088Smarkm		(void) ioctl(pty, TIOCSWINSZ, (char *)&ws);
54329088Smarkm	    }
54429088Smarkm#endif	/* TIOCSWINSZ */
54529088Smarkm
54629088Smarkm		break;
54729088Smarkm
54829088Smarkm	case TELOPT_TSPEED:
54929088Smarkm	    {
55029088Smarkm		def_tspeed = parm1;
55129088Smarkm		def_rspeed = parm2;
55229088Smarkm#ifdef	LINEMODE
55329088Smarkm		/*
55429088Smarkm		 * Defer changing the terminal speed.
55529088Smarkm		 */
55629088Smarkm		if (terminit() == 0)
55729088Smarkm			return;
55829088Smarkm#endif	/* LINEMODE */
55929088Smarkm		/*
56029088Smarkm		 * Change terminal speed as requested by client.
56129088Smarkm		 * We set the receive speed first, so that if we can't
56272089Sasmodai		 * store separate receive and transmit speeds, the transmit
56329088Smarkm		 * speed will take precedence.
56429088Smarkm		 */
56529088Smarkm		tty_rspeed(parm2);
56629088Smarkm		tty_tspeed(parm1);
56729088Smarkm		set_termbuf();
56829088Smarkm
56929088Smarkm		break;
57029088Smarkm
57129088Smarkm	    }  /* end of case TELOPT_TSPEED */
57229088Smarkm
57329088Smarkm	default:
57429088Smarkm		/* What? */
57529088Smarkm		break;
57629088Smarkm	}  /* end of switch */
57729088Smarkm
57829088Smarkm	netflush();
57929088Smarkm
58029088Smarkm}  /* end of clientstat */
58129088Smarkm
58229088Smarkm#ifdef	LINEMODE
58329088Smarkm/*
58429088Smarkm * defer_terminit
58529088Smarkm *
58629088Smarkm * Some things should not be done until after the login process has started
58729088Smarkm * and all the pty modes are set to what they are supposed to be.  This
58829088Smarkm * function is called when the pty state has been processed for the first time.
58929088Smarkm * It calls other functions that do things that were deferred in each module.
59029088Smarkm */
59187139Smarkmvoid
59287139Smarkmdefer_terminit(void)
59329088Smarkm{
59429088Smarkm
59529088Smarkm	/*
59629088Smarkm	 * local stuff that got deferred.
59729088Smarkm	 */
59829088Smarkm	if (def_tspeed != -1) {
59929088Smarkm		clientstat(TELOPT_TSPEED, def_tspeed, def_rspeed);
60029088Smarkm		def_tspeed = def_rspeed = 0;
60129088Smarkm	}
60229088Smarkm
60329088Smarkm#ifdef	TIOCSWINSZ
60429088Smarkm	if (def_col || def_row) {
60529088Smarkm		struct winsize ws;
60629088Smarkm
60729088Smarkm		memset((char *)&ws, 0, sizeof(ws));
60829088Smarkm		ws.ws_col = def_col;
60929088Smarkm		ws.ws_row = def_row;
61029088Smarkm		(void) ioctl(pty, TIOCSWINSZ, (char *)&ws);
61129088Smarkm	}
61229088Smarkm#endif
61329088Smarkm
61429088Smarkm	/*
61529088Smarkm	 * The only other module that currently defers anything.
61629088Smarkm	 */
61729088Smarkm	deferslc();
61829088Smarkm
61929088Smarkm}  /* end of defer_terminit */
62029088Smarkm
62129088Smarkm/*
62229088Smarkm * terminit
62329088Smarkm *
62429088Smarkm * Returns true if the pty state has been processed yet.
62529088Smarkm */
62687139Smarkmint
62787139Smarkmterminit(void)
62829088Smarkm{
62929088Smarkm	return(_terminit);
63029088Smarkm
63129088Smarkm}  /* end of terminit */
63229088Smarkm#endif	/* LINEMODE */
633