Home | History | Annotate | Line # | Download | only in telnetd
termstat.c revision 1.10
      1  1.10      wiz /*	$NetBSD: termstat.c,v 1.10 2001/08/01 16:41:14 wiz Exp $	*/
      2   1.5  thorpej 
      3   1.1      cgd /*
      4   1.3      cgd  * Copyright (c) 1989, 1993
      5   1.3      cgd  *	The Regents of the University of California.  All rights reserved.
      6   1.1      cgd  *
      7   1.1      cgd  * Redistribution and use in source and binary forms, with or without
      8   1.1      cgd  * modification, are permitted provided that the following conditions
      9   1.1      cgd  * are met:
     10   1.1      cgd  * 1. Redistributions of source code must retain the above copyright
     11   1.1      cgd  *    notice, this list of conditions and the following disclaimer.
     12   1.1      cgd  * 2. Redistributions in binary form must reproduce the above copyright
     13   1.1      cgd  *    notice, this list of conditions and the following disclaimer in the
     14   1.1      cgd  *    documentation and/or other materials provided with the distribution.
     15   1.1      cgd  * 3. All advertising materials mentioning features or use of this software
     16   1.1      cgd  *    must display the following acknowledgement:
     17   1.1      cgd  *	This product includes software developed by the University of
     18   1.1      cgd  *	California, Berkeley and its contributors.
     19   1.1      cgd  * 4. Neither the name of the University nor the names of its contributors
     20   1.1      cgd  *    may be used to endorse or promote products derived from this software
     21   1.1      cgd  *    without specific prior written permission.
     22   1.1      cgd  *
     23   1.1      cgd  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
     24   1.1      cgd  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
     25   1.1      cgd  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
     26   1.1      cgd  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
     27   1.1      cgd  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
     28   1.1      cgd  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
     29   1.1      cgd  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
     30   1.1      cgd  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
     31   1.1      cgd  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
     32   1.1      cgd  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
     33   1.1      cgd  * SUCH DAMAGE.
     34   1.1      cgd  */
     35   1.1      cgd 
     36   1.6      mrg #include <sys/cdefs.h>
     37   1.1      cgd #ifndef lint
     38   1.5  thorpej #if 0
     39   1.5  thorpej static char sccsid[] = "@(#)termstat.c	8.2 (Berkeley) 5/30/95";
     40   1.5  thorpej #else
     41  1.10      wiz __RCSID("$NetBSD: termstat.c,v 1.10 2001/08/01 16:41:14 wiz Exp $");
     42   1.5  thorpej #endif
     43   1.1      cgd #endif /* not lint */
     44   1.1      cgd 
     45   1.1      cgd #include "telnetd.h"
     46   1.1      cgd 
     47   1.7  thorpej #if defined(ENCRYPTION)
     48   1.7  thorpej #include <libtelnet/encrypt.h>
     49   1.7  thorpej #endif
     50   1.7  thorpej 
     51   1.1      cgd /*
     52   1.1      cgd  * local variables
     53   1.1      cgd  */
     54   1.1      cgd int def_tspeed = -1, def_rspeed = -1;
     55   1.1      cgd #ifdef	TIOCSWINSZ
     56   1.1      cgd int def_row = 0, def_col = 0;
     57   1.1      cgd #endif
     58   1.1      cgd #ifdef	LINEMODE
     59   1.1      cgd static int _terminit = 0;
     60   1.1      cgd #endif	/* LINEMODE */
     61   1.1      cgd 
     62   1.1      cgd #if	defined(CRAY2) && defined(UNICOS5)
     63   1.1      cgd int	newmap = 1;	/* nonzero if \n maps to ^M^J */
     64   1.1      cgd #endif
     65   1.1      cgd 
     66   1.1      cgd #ifdef	LINEMODE
     67   1.1      cgd /*
     68   1.1      cgd  * localstat
     69   1.1      cgd  *
     70   1.1      cgd  * This function handles all management of linemode.
     71   1.1      cgd  *
     72   1.1      cgd  * Linemode allows the client to do the local editing of data
     73   1.1      cgd  * and send only complete lines to the server.  Linemode state is
     74   1.1      cgd  * based on the state of the pty driver.  If the pty is set for
     75   1.1      cgd  * external processing, then we can use linemode.  Further, if we
     76   1.1      cgd  * can use real linemode, then we can look at the edit control bits
     77   1.1      cgd  * in the pty to determine what editing the client should do.
     78   1.1      cgd  *
     79   1.1      cgd  * Linemode support uses the following state flags to keep track of
     80   1.1      cgd  * current and desired linemode state.
     81   1.1      cgd  *	alwayslinemode : true if -l was specified on the telnetd
     82   1.1      cgd  * 	command line.  It means to have linemode on as much as
     83   1.1      cgd  *	possible.
     84   1.1      cgd  *
     85   1.1      cgd  * 	lmodetype: signifies whether the client can
     86   1.1      cgd  *	handle real linemode, or if use of kludgeomatic linemode
     87   1.1      cgd  *	is preferred.  It will be set to one of the following:
     88   1.1      cgd  *		REAL_LINEMODE : use linemode option
     89   1.3      cgd  *		NO_KLUDGE : don't initiate kludge linemode.
     90   1.1      cgd  *		KLUDGE_LINEMODE : use kludge linemode
     91   1.1      cgd  *		NO_LINEMODE : client is ignorant of linemode
     92   1.1      cgd  *
     93   1.1      cgd  *	linemode, uselinemode : linemode is true if linemode
     94   1.1      cgd  *	is currently on, uselinemode is the state that we wish
     95   1.1      cgd  *	to be in.  If another function wishes to turn linemode
     96   1.1      cgd  *	on or off, it sets or clears uselinemode.
     97   1.1      cgd  *
     98   1.1      cgd  *	editmode, useeditmode : like linemode/uselinemode, but
     99   1.1      cgd  *	these contain the edit mode states (edit and trapsig).
    100   1.1      cgd  *
    101   1.1      cgd  * The state variables correspond to some of the state information
    102   1.1      cgd  * in the pty.
    103   1.1      cgd  *	linemode:
    104   1.1      cgd  *		In real linemode, this corresponds to whether the pty
    105   1.1      cgd  *		expects external processing of incoming data.
    106   1.1      cgd  *		In kludge linemode, this more closely corresponds to the
    107   1.1      cgd  *		whether normal processing is on or not.  (ICANON in
    108   1.1      cgd  *		system V, or COOKED mode in BSD.)
    109   1.1      cgd  *		If the -l option was specified (alwayslinemode), then
    110   1.1      cgd  *		an attempt is made to force external processing on at
    111   1.1      cgd  *		all times.
    112   1.1      cgd  *
    113   1.1      cgd  * The following heuristics are applied to determine linemode
    114   1.1      cgd  * handling within the server.
    115   1.1      cgd  *	1) Early on in starting up the server, an attempt is made
    116   1.1      cgd  *	   to negotiate the linemode option.  If this succeeds
    117   1.1      cgd  *	   then lmodetype is set to REAL_LINEMODE and all linemode
    118   1.1      cgd  *	   processing occurs in the context of the linemode option.
    119   1.1      cgd  *	2) If the attempt to negotiate the linemode option failed,
    120   1.3      cgd  *	   and the "-k" (don't initiate kludge linemode) isn't set,
    121   1.1      cgd  *	   then we try to use kludge linemode.  We test for this
    122   1.1      cgd  *	   capability by sending "do Timing Mark".  If a positive
    123   1.1      cgd  *	   response comes back, then we assume that the client
    124   1.1      cgd  *	   understands kludge linemode (ech!) and the
    125   1.1      cgd  *	   lmodetype flag is set to KLUDGE_LINEMODE.
    126   1.1      cgd  *	3) Otherwise, linemode is not supported at all and
    127   1.1      cgd  *	   lmodetype remains set to NO_LINEMODE (which happens
    128   1.1      cgd  *	   to be 0 for convenience).
    129   1.1      cgd  *	4) At any time a command arrives that implies a higher
    130   1.1      cgd  *	   state of linemode support in the client, we move to that
    131   1.1      cgd  *	   linemode support.
    132   1.1      cgd  *
    133   1.1      cgd  * A short explanation of kludge linemode is in order here.
    134   1.1      cgd  *	1) The heuristic to determine support for kludge linemode
    135   1.1      cgd  *	   is to send a do timing mark.  We assume that a client
    136   1.1      cgd  *	   that supports timing marks also supports kludge linemode.
    137   1.1      cgd  *	   A risky proposition at best.
    138   1.1      cgd  *	2) Further negotiation of linemode is done by changing the
    139   1.1      cgd  *	   the server's state regarding SGA.  If server will SGA,
    140   1.1      cgd  *	   then linemode is off, if server won't SGA, then linemode
    141   1.1      cgd  *	   is on.
    142   1.1      cgd  */
    143   1.1      cgd 	void
    144   1.1      cgd localstat()
    145   1.1      cgd {
    146   1.1      cgd 	int need_will_echo = 0;
    147   1.1      cgd 
    148   1.1      cgd #if	defined(CRAY2) && defined(UNICOS5)
    149   1.1      cgd 	/*
    150   1.1      cgd 	 * Keep track of that ol' CR/NL mapping while we're in the
    151   1.1      cgd 	 * neighborhood.
    152   1.1      cgd 	 */
    153   1.1      cgd 	newmap = tty_isnewmap();
    154   1.1      cgd #endif	/* defined(CRAY2) && defined(UNICOS5) */
    155   1.1      cgd 
    156   1.1      cgd 	/*
    157   1.1      cgd 	 * Check for state of BINARY options.
    158   1.1      cgd 	 */
    159   1.1      cgd 	if (tty_isbinaryin()) {
    160   1.1      cgd 		if (his_want_state_is_wont(TELOPT_BINARY))
    161   1.1      cgd 			send_do(TELOPT_BINARY, 1);
    162   1.1      cgd 	} else {
    163   1.1      cgd 		if (his_want_state_is_will(TELOPT_BINARY))
    164   1.1      cgd 			send_dont(TELOPT_BINARY, 1);
    165   1.1      cgd 	}
    166   1.1      cgd 
    167   1.1      cgd 	if (tty_isbinaryout()) {
    168   1.1      cgd 		if (my_want_state_is_wont(TELOPT_BINARY))
    169   1.1      cgd 			send_will(TELOPT_BINARY, 1);
    170   1.1      cgd 	} else {
    171   1.1      cgd 		if (my_want_state_is_will(TELOPT_BINARY))
    172   1.1      cgd 			send_wont(TELOPT_BINARY, 1);
    173   1.1      cgd 	}
    174   1.1      cgd 
    175   1.1      cgd 	/*
    176   1.1      cgd 	 * Check for changes to flow control if client supports it.
    177   1.1      cgd 	 */
    178   1.3      cgd 	flowstat();
    179   1.1      cgd 
    180   1.1      cgd 	/*
    181   1.1      cgd 	 * Check linemode on/off state
    182   1.1      cgd 	 */
    183   1.1      cgd 	uselinemode = tty_linemode();
    184   1.1      cgd 
    185   1.1      cgd 	/*
    186   1.1      cgd 	 * If alwayslinemode is on, and pty is changing to turn it off, then
    187   1.1      cgd 	 * force linemode back on.
    188   1.1      cgd 	 */
    189   1.1      cgd 	if (alwayslinemode && linemode && !uselinemode) {
    190   1.1      cgd 		uselinemode = 1;
    191   1.1      cgd 		tty_setlinemode(uselinemode);
    192   1.1      cgd 	}
    193   1.1      cgd 
    194   1.7  thorpej #ifdef	ENCRYPTION
    195   1.7  thorpej 	/*
    196   1.7  thorpej 	 * If the terminal is not echoing, but editing is enabled,
    197   1.7  thorpej 	 * something like password input is going to happen, so
    198   1.7  thorpej 	 * if we the other side is not currently sending encrypted
    199   1.7  thorpej 	 * data, ask the other side to start encrypting.
    200   1.7  thorpej 	 */
    201   1.7  thorpej 	if (his_state_is_will(TELOPT_ENCRYPT)) {
    202   1.7  thorpej 		static int enc_passwd = 0;
    203   1.7  thorpej 		if (uselinemode && !tty_isecho() && tty_isediting()
    204   1.7  thorpej 		    && (enc_passwd == 0) && !decrypt_input) {
    205   1.7  thorpej 			encrypt_send_request_start();
    206   1.7  thorpej 			enc_passwd = 1;
    207   1.7  thorpej 		} else if (enc_passwd) {
    208   1.7  thorpej 			encrypt_send_request_end();
    209   1.7  thorpej 			enc_passwd = 0;
    210   1.7  thorpej 		}
    211   1.7  thorpej 	}
    212   1.7  thorpej #endif	/* ENCRYPTION */
    213   1.1      cgd 
    214   1.1      cgd 	/*
    215   1.1      cgd 	 * Do echo mode handling as soon as we know what the
    216   1.1      cgd 	 * linemode is going to be.
    217   1.1      cgd 	 * If the pty has echo turned off, then tell the client that
    218   1.1      cgd 	 * the server will echo.  If echo is on, then the server
    219   1.1      cgd 	 * will echo if in character mode, but in linemode the
    220   1.1      cgd 	 * client should do local echoing.  The state machine will
    221   1.1      cgd 	 * not send anything if it is unnecessary, so don't worry
    222   1.1      cgd 	 * about that here.
    223   1.1      cgd 	 *
    224   1.1      cgd 	 * If we need to send the WILL ECHO (because echo is off),
    225   1.1      cgd 	 * then delay that until after we have changed the MODE.
    226   1.1      cgd 	 * This way, when the user is turning off both editing
    227   1.1      cgd 	 * and echo, the client will get editing turned off first.
    228   1.1      cgd 	 * This keeps the client from going into encryption mode
    229   1.1      cgd 	 * and then right back out if it is doing auto-encryption
    230   1.1      cgd 	 * when passwords are being typed.
    231   1.1      cgd 	 */
    232   1.1      cgd 	if (uselinemode) {
    233   1.1      cgd 		if (tty_isecho())
    234   1.1      cgd 			send_wont(TELOPT_ECHO, 1);
    235   1.1      cgd 		else
    236   1.1      cgd 			need_will_echo = 1;
    237   1.3      cgd #ifdef	KLUDGELINEMODE
    238   1.3      cgd 		if (lmodetype == KLUDGE_OK)
    239   1.3      cgd 			lmodetype = KLUDGE_LINEMODE;
    240   1.3      cgd #endif
    241   1.1      cgd 	}
    242   1.1      cgd 
    243   1.1      cgd 	/*
    244   1.1      cgd 	 * If linemode is being turned off, send appropriate
    245   1.1      cgd 	 * command and then we're all done.
    246   1.1      cgd 	 */
    247   1.1      cgd 	 if (!uselinemode && linemode) {
    248   1.1      cgd # ifdef	KLUDGELINEMODE
    249   1.1      cgd 		if (lmodetype == REAL_LINEMODE) {
    250   1.1      cgd # endif	/* KLUDGELINEMODE */
    251   1.1      cgd 			send_dont(TELOPT_LINEMODE, 1);
    252   1.1      cgd # ifdef	KLUDGELINEMODE
    253   1.1      cgd 		} else if (lmodetype == KLUDGE_LINEMODE)
    254   1.1      cgd 			send_will(TELOPT_SGA, 1);
    255   1.1      cgd # endif	/* KLUDGELINEMODE */
    256   1.1      cgd 		send_will(TELOPT_ECHO, 1);
    257   1.1      cgd 		linemode = uselinemode;
    258   1.1      cgd 		goto done;
    259   1.1      cgd 	}
    260   1.1      cgd 
    261   1.1      cgd # ifdef	KLUDGELINEMODE
    262   1.1      cgd 	/*
    263   1.1      cgd 	 * If using real linemode check edit modes for possible later use.
    264   1.1      cgd 	 * If we are in kludge linemode, do the SGA negotiation.
    265   1.1      cgd 	 */
    266   1.1      cgd 	if (lmodetype == REAL_LINEMODE) {
    267   1.1      cgd # endif	/* KLUDGELINEMODE */
    268   1.1      cgd 		useeditmode = 0;
    269   1.1      cgd 		if (tty_isediting())
    270   1.1      cgd 			useeditmode |= MODE_EDIT;
    271   1.1      cgd 		if (tty_istrapsig())
    272   1.1      cgd 			useeditmode |= MODE_TRAPSIG;
    273   1.1      cgd 		if (tty_issofttab())
    274   1.1      cgd 			useeditmode |= MODE_SOFT_TAB;
    275   1.1      cgd 		if (tty_islitecho())
    276   1.1      cgd 			useeditmode |= MODE_LIT_ECHO;
    277   1.1      cgd # ifdef	KLUDGELINEMODE
    278   1.1      cgd 	} else if (lmodetype == KLUDGE_LINEMODE) {
    279   1.1      cgd 		if (tty_isediting() && uselinemode)
    280   1.1      cgd 			send_wont(TELOPT_SGA, 1);
    281   1.1      cgd 		else
    282   1.1      cgd 			send_will(TELOPT_SGA, 1);
    283   1.1      cgd 	}
    284   1.1      cgd # endif	/* KLUDGELINEMODE */
    285   1.1      cgd 
    286   1.1      cgd 	/*
    287   1.1      cgd 	 * Negotiate linemode on if pty state has changed to turn it on.
    288   1.1      cgd 	 * Send appropriate command and send along edit mode, then all done.
    289   1.1      cgd 	 */
    290   1.1      cgd 	if (uselinemode && !linemode) {
    291   1.1      cgd # ifdef	KLUDGELINEMODE
    292   1.1      cgd 		if (lmodetype == KLUDGE_LINEMODE) {
    293   1.1      cgd 			send_wont(TELOPT_SGA, 1);
    294   1.1      cgd 		} else if (lmodetype == REAL_LINEMODE) {
    295   1.1      cgd # endif	/* KLUDGELINEMODE */
    296   1.1      cgd 			send_do(TELOPT_LINEMODE, 1);
    297   1.1      cgd 			/* send along edit modes */
    298   1.8   itojun 			(void) output_data("%c%c%c%c%c%c%c", IAC, SB,
    299   1.1      cgd 				TELOPT_LINEMODE, LM_MODE, useeditmode,
    300   1.1      cgd 				IAC, SE);
    301   1.1      cgd 			editmode = useeditmode;
    302   1.1      cgd # ifdef	KLUDGELINEMODE
    303   1.1      cgd 		}
    304   1.1      cgd # endif	/* KLUDGELINEMODE */
    305   1.1      cgd 		linemode = uselinemode;
    306   1.1      cgd 		goto done;
    307   1.1      cgd 	}
    308   1.1      cgd 
    309   1.1      cgd # ifdef	KLUDGELINEMODE
    310   1.1      cgd 	/*
    311   1.1      cgd 	 * None of what follows is of any value if not using
    312   1.1      cgd 	 * real linemode.
    313   1.1      cgd 	 */
    314   1.1      cgd 	if (lmodetype < REAL_LINEMODE)
    315   1.1      cgd 		goto done;
    316   1.1      cgd # endif	/* KLUDGELINEMODE */
    317   1.1      cgd 
    318   1.1      cgd 	if (linemode && his_state_is_will(TELOPT_LINEMODE)) {
    319   1.1      cgd 		/*
    320   1.1      cgd 		 * If edit mode changed, send edit mode.
    321   1.1      cgd 		 */
    322   1.1      cgd 		 if (useeditmode != editmode) {
    323   1.1      cgd 			/*
    324   1.1      cgd 			 * Send along appropriate edit mode mask.
    325   1.1      cgd 			 */
    326   1.8   itojun 			(void) output_data("%c%c%c%c%c%c%c", IAC, SB,
    327   1.1      cgd 				TELOPT_LINEMODE, LM_MODE, useeditmode,
    328   1.1      cgd 				IAC, SE);
    329   1.1      cgd 			editmode = useeditmode;
    330   1.1      cgd 		}
    331   1.4      jtk 
    332   1.1      cgd 
    333   1.1      cgd 		/*
    334   1.1      cgd 		 * Check for changes to special characters in use.
    335   1.1      cgd 		 */
    336   1.1      cgd 		start_slc(0);
    337   1.1      cgd 		check_slc();
    338   1.1      cgd 		(void) end_slc(0);
    339   1.1      cgd 	}
    340   1.1      cgd 
    341   1.1      cgd done:
    342   1.1      cgd 	if (need_will_echo)
    343   1.1      cgd 		send_will(TELOPT_ECHO, 1);
    344   1.1      cgd 	/*
    345   1.1      cgd 	 * Some things should be deferred until after the pty state has
    346   1.1      cgd 	 * been set by the local process.  Do those things that have been
    347   1.1      cgd 	 * deferred now.  This only happens once.
    348   1.1      cgd 	 */
    349   1.1      cgd 	if (_terminit == 0) {
    350   1.1      cgd 		_terminit = 1;
    351   1.1      cgd 		defer_terminit();
    352   1.1      cgd 	}
    353   1.1      cgd 
    354   1.1      cgd 	netflush();
    355   1.1      cgd 	set_termbuf();
    356   1.1      cgd 	return;
    357   1.1      cgd 
    358   1.1      cgd }  /* end of localstat */
    359   1.1      cgd #endif	/* LINEMODE */
    360   1.1      cgd 
    361   1.3      cgd /*
    362   1.3      cgd  * flowstat
    363   1.3      cgd  *
    364   1.3      cgd  * Check for changes to flow control
    365   1.3      cgd  */
    366   1.3      cgd 	void
    367   1.3      cgd flowstat()
    368   1.3      cgd {
    369   1.3      cgd 	if (his_state_is_will(TELOPT_LFLOW)) {
    370   1.3      cgd 		if (tty_flowmode() != flowmode) {
    371   1.3      cgd 			flowmode = tty_flowmode();
    372   1.8   itojun 			(void) output_data("%c%c%c%c%c%c",
    373   1.3      cgd 					IAC, SB, TELOPT_LFLOW,
    374   1.3      cgd 					flowmode ? LFLOW_ON : LFLOW_OFF,
    375   1.3      cgd 					IAC, SE);
    376   1.3      cgd 		}
    377   1.3      cgd 		if (tty_restartany() != restartany) {
    378   1.3      cgd 			restartany = tty_restartany();
    379   1.8   itojun 			(void) output_data("%c%c%c%c%c%c",
    380   1.3      cgd 					IAC, SB, TELOPT_LFLOW,
    381   1.3      cgd 					restartany ? LFLOW_RESTART_ANY
    382   1.3      cgd 						   : LFLOW_RESTART_XON,
    383   1.3      cgd 					IAC, SE);
    384   1.3      cgd 		}
    385   1.3      cgd 	}
    386   1.3      cgd }
    387   1.1      cgd 
    388   1.1      cgd /*
    389   1.1      cgd  * clientstat
    390   1.1      cgd  *
    391   1.1      cgd  * Process linemode related requests from the client.
    392   1.1      cgd  * Client can request a change to only one of linemode, editmode or slc's
    393   1.1      cgd  * at a time, and if using kludge linemode, then only linemode may be
    394   1.1      cgd  * affected.
    395   1.1      cgd  */
    396   1.1      cgd 	void
    397   1.1      cgd clientstat(code, parm1, parm2)
    398   1.1      cgd 	register int code, parm1, parm2;
    399   1.1      cgd {
    400   1.1      cgd 
    401   1.1      cgd 	/*
    402   1.1      cgd 	 * Get a copy of terminal characteristics.
    403   1.1      cgd 	 */
    404   1.1      cgd 	init_termbuf();
    405   1.1      cgd 
    406   1.1      cgd 	/*
    407   1.1      cgd 	 * Process request from client. code tells what it is.
    408   1.1      cgd 	 */
    409   1.1      cgd 	switch (code) {
    410   1.1      cgd #ifdef	LINEMODE
    411   1.1      cgd 	case TELOPT_LINEMODE:
    412   1.1      cgd 		/*
    413   1.1      cgd 		 * Don't do anything unless client is asking us to change
    414   1.1      cgd 		 * modes.
    415   1.1      cgd 		 */
    416   1.1      cgd 		uselinemode = (parm1 == WILL);
    417   1.1      cgd 		if (uselinemode != linemode) {
    418   1.1      cgd # ifdef	KLUDGELINEMODE
    419   1.1      cgd 			/*
    420   1.1      cgd 			 * If using kludge linemode, make sure that
    421   1.1      cgd 			 * we can do what the client asks.
    422   1.1      cgd 			 * We can not turn off linemode if alwayslinemode
    423   1.1      cgd 			 * and the ICANON bit is set.
    424   1.1      cgd 			 */
    425   1.1      cgd 			if (lmodetype == KLUDGE_LINEMODE) {
    426   1.1      cgd 				if (alwayslinemode && tty_isediting()) {
    427   1.1      cgd 					uselinemode = 1;
    428   1.1      cgd 				}
    429   1.1      cgd 			}
    430   1.4      jtk 
    431   1.1      cgd 			/*
    432   1.1      cgd 			 * Quit now if we can't do it.
    433   1.1      cgd 			 */
    434   1.1      cgd 			if (uselinemode == linemode)
    435   1.1      cgd 				return;
    436   1.1      cgd 
    437   1.1      cgd 			/*
    438   1.1      cgd 			 * If using real linemode and linemode is being
    439   1.1      cgd 			 * turned on, send along the edit mode mask.
    440   1.1      cgd 			 */
    441   1.1      cgd 			if (lmodetype == REAL_LINEMODE && uselinemode)
    442   1.1      cgd # else	/* KLUDGELINEMODE */
    443   1.1      cgd 			if (uselinemode)
    444   1.1      cgd # endif	/* KLUDGELINEMODE */
    445   1.1      cgd 			{
    446   1.1      cgd 				useeditmode = 0;
    447   1.1      cgd 				if (tty_isediting())
    448   1.1      cgd 					useeditmode |= MODE_EDIT;
    449  1.10      wiz 				if (tty_istrapsig())
    450   1.1      cgd 					useeditmode |= MODE_TRAPSIG;
    451   1.1      cgd 				if (tty_issofttab())
    452   1.1      cgd 					useeditmode |= MODE_SOFT_TAB;
    453   1.1      cgd 				if (tty_islitecho())
    454   1.1      cgd 					useeditmode |= MODE_LIT_ECHO;
    455   1.8   itojun 				(void) output_data("%c%c%c%c%c%c%c", IAC,
    456   1.1      cgd 					SB, TELOPT_LINEMODE, LM_MODE,
    457   1.1      cgd 							useeditmode, IAC, SE);
    458   1.1      cgd 				editmode = useeditmode;
    459   1.1      cgd 			}
    460   1.1      cgd 
    461   1.1      cgd 
    462   1.1      cgd 			tty_setlinemode(uselinemode);
    463   1.1      cgd 
    464   1.1      cgd 			linemode = uselinemode;
    465   1.1      cgd 
    466   1.3      cgd 			if (!linemode)
    467   1.3      cgd 				send_will(TELOPT_ECHO, 1);
    468   1.1      cgd 		}
    469   1.1      cgd 		break;
    470   1.4      jtk 
    471   1.1      cgd 	case LM_MODE:
    472   1.1      cgd 	    {
    473   1.1      cgd 		register int ack, changed;
    474   1.1      cgd 
    475   1.1      cgd 		/*
    476   1.1      cgd 		 * Client has sent along a mode mask.  If it agrees with
    477   1.1      cgd 		 * what we are currently doing, ignore it; if not, it could
    478   1.1      cgd 		 * be viewed as a request to change.  Note that the server
    479   1.1      cgd 		 * will change to the modes in an ack if it is different from
    480   1.1      cgd 		 * what we currently have, but we will not ack the ack.
    481   1.1      cgd 		 */
    482   1.1      cgd 		 useeditmode &= MODE_MASK;
    483   1.1      cgd 		 ack = (useeditmode & MODE_ACK);
    484   1.1      cgd 		 useeditmode &= ~MODE_ACK;
    485   1.1      cgd 
    486   1.6      mrg 		 if ((changed = (useeditmode ^ editmode))) {
    487   1.1      cgd 			/*
    488   1.1      cgd 			 * This check is for a timing problem.  If the
    489   1.1      cgd 			 * state of the tty has changed (due to the user
    490   1.1      cgd 			 * application) we need to process that info
    491   1.1      cgd 			 * before we write in the state contained in the
    492   1.1      cgd 			 * ack!!!  This gets out the new MODE request,
    493   1.1      cgd 			 * and when the ack to that command comes back
    494   1.1      cgd 			 * we'll set it and be in the right mode.
    495   1.1      cgd 			 */
    496   1.1      cgd 			if (ack)
    497   1.1      cgd 				localstat();
    498   1.1      cgd 			if (changed & MODE_EDIT)
    499   1.1      cgd 				tty_setedit(useeditmode & MODE_EDIT);
    500   1.1      cgd 
    501   1.1      cgd 			if (changed & MODE_TRAPSIG)
    502   1.1      cgd 				tty_setsig(useeditmode & MODE_TRAPSIG);
    503   1.1      cgd 
    504   1.1      cgd 			if (changed & MODE_SOFT_TAB)
    505   1.1      cgd 				tty_setsofttab(useeditmode & MODE_SOFT_TAB);
    506   1.1      cgd 
    507   1.1      cgd 			if (changed & MODE_LIT_ECHO)
    508   1.1      cgd 				tty_setlitecho(useeditmode & MODE_LIT_ECHO);
    509   1.1      cgd 
    510   1.1      cgd 			set_termbuf();
    511   1.1      cgd 
    512   1.1      cgd  			if (!ack) {
    513   1.8   itojun  				(void) output_data("%c%c%c%c%c%c%c", IAC,
    514   1.1      cgd 					SB, TELOPT_LINEMODE, LM_MODE,
    515   1.1      cgd  					useeditmode|MODE_ACK,
    516   1.1      cgd  					IAC, SE);
    517   1.1      cgd  			}
    518   1.4      jtk 
    519   1.1      cgd 			editmode = useeditmode;
    520   1.1      cgd 		}
    521   1.1      cgd 
    522   1.1      cgd 		break;
    523   1.1      cgd 
    524   1.1      cgd 	    }  /* end of case LM_MODE */
    525   1.1      cgd #endif	/* LINEMODE */
    526   1.1      cgd 
    527   1.1      cgd 	case TELOPT_NAWS:
    528   1.1      cgd #ifdef	TIOCSWINSZ
    529   1.1      cgd 	    {
    530   1.1      cgd 		struct winsize ws;
    531   1.1      cgd 
    532   1.1      cgd 		def_col = parm1;
    533   1.1      cgd 		def_row = parm2;
    534   1.1      cgd #ifdef	LINEMODE
    535   1.1      cgd 		/*
    536   1.1      cgd 		 * Defer changing window size until after terminal is
    537   1.1      cgd 		 * initialized.
    538   1.1      cgd 		 */
    539   1.1      cgd 		if (terminit() == 0)
    540   1.1      cgd 			return;
    541   1.1      cgd #endif	/* LINEMODE */
    542   1.1      cgd 
    543   1.1      cgd 		/*
    544   1.1      cgd 		 * Change window size as requested by client.
    545   1.1      cgd 		 */
    546   1.1      cgd 
    547   1.1      cgd 		ws.ws_col = parm1;
    548   1.1      cgd 		ws.ws_row = parm2;
    549   1.1      cgd 		(void) ioctl(pty, TIOCSWINSZ, (char *)&ws);
    550   1.1      cgd 	    }
    551   1.1      cgd #endif	/* TIOCSWINSZ */
    552   1.4      jtk 
    553   1.1      cgd 		break;
    554   1.4      jtk 
    555   1.1      cgd 	case TELOPT_TSPEED:
    556   1.1      cgd 	    {
    557   1.1      cgd 		def_tspeed = parm1;
    558   1.1      cgd 		def_rspeed = parm2;
    559   1.1      cgd #ifdef	LINEMODE
    560   1.1      cgd 		/*
    561   1.1      cgd 		 * Defer changing the terminal speed.
    562   1.1      cgd 		 */
    563   1.1      cgd 		if (terminit() == 0)
    564   1.1      cgd 			return;
    565   1.1      cgd #endif	/* LINEMODE */
    566   1.1      cgd 		/*
    567   1.1      cgd 		 * Change terminal speed as requested by client.
    568   1.1      cgd 		 * We set the receive speed first, so that if we can't
    569   1.9      wiz 		 * store separate receive and transmit speeds, the transmit
    570   1.1      cgd 		 * speed will take precedence.
    571   1.1      cgd 		 */
    572   1.1      cgd 		tty_rspeed(parm2);
    573   1.1      cgd 		tty_tspeed(parm1);
    574   1.1      cgd 		set_termbuf();
    575   1.1      cgd 
    576   1.1      cgd 		break;
    577   1.1      cgd 
    578   1.1      cgd 	    }  /* end of case TELOPT_TSPEED */
    579   1.1      cgd 
    580   1.1      cgd 	default:
    581   1.1      cgd 		/* What? */
    582   1.1      cgd 		break;
    583   1.1      cgd 	}  /* end of switch */
    584   1.1      cgd 
    585   1.1      cgd #if	defined(CRAY2) && defined(UNICOS5)
    586   1.1      cgd 	/*
    587   1.1      cgd 	 * Just in case of the likely event that we changed the pty state.
    588   1.1      cgd 	 */
    589   1.1      cgd 	rcv_ioctl();
    590   1.1      cgd #endif	/* defined(CRAY2) && defined(UNICOS5) */
    591   1.1      cgd 
    592   1.1      cgd 	netflush();
    593   1.1      cgd 
    594   1.1      cgd }  /* end of clientstat */
    595   1.1      cgd 
    596   1.1      cgd #if	defined(CRAY2) && defined(UNICOS5)
    597   1.1      cgd 	void
    598   1.1      cgd termstat()
    599   1.1      cgd {
    600   1.1      cgd 	needtermstat = 1;
    601   1.1      cgd }
    602   1.1      cgd 
    603   1.1      cgd 	void
    604   1.1      cgd _termstat()
    605   1.1      cgd {
    606   1.1      cgd 	needtermstat = 0;
    607   1.1      cgd 	init_termbuf();
    608   1.1      cgd 	localstat();
    609   1.1      cgd 	rcv_ioctl();
    610   1.1      cgd }
    611   1.1      cgd #endif	/* defined(CRAY2) && defined(UNICOS5) */
    612   1.1      cgd 
    613   1.1      cgd #ifdef	LINEMODE
    614   1.1      cgd /*
    615   1.1      cgd  * defer_terminit
    616   1.1      cgd  *
    617   1.1      cgd  * Some things should not be done until after the login process has started
    618   1.1      cgd  * and all the pty modes are set to what they are supposed to be.  This
    619   1.4      jtk  * function is called when the pty state has been processed for the first time.
    620   1.1      cgd  * It calls other functions that do things that were deferred in each module.
    621   1.1      cgd  */
    622   1.1      cgd 	void
    623   1.1      cgd defer_terminit()
    624   1.1      cgd {
    625   1.1      cgd 
    626   1.1      cgd 	/*
    627   1.1      cgd 	 * local stuff that got deferred.
    628   1.1      cgd 	 */
    629   1.1      cgd 	if (def_tspeed != -1) {
    630   1.1      cgd 		clientstat(TELOPT_TSPEED, def_tspeed, def_rspeed);
    631   1.1      cgd 		def_tspeed = def_rspeed = 0;
    632   1.1      cgd 	}
    633   1.1      cgd 
    634   1.1      cgd #ifdef	TIOCSWINSZ
    635   1.1      cgd 	if (def_col || def_row) {
    636   1.1      cgd 		struct winsize ws;
    637   1.1      cgd 
    638   1.4      jtk 		memset((char *)&ws, 0, sizeof(ws));
    639   1.1      cgd 		ws.ws_col = def_col;
    640   1.1      cgd 		ws.ws_row = def_row;
    641   1.1      cgd 		(void) ioctl(pty, TIOCSWINSZ, (char *)&ws);
    642   1.1      cgd 	}
    643   1.1      cgd #endif
    644   1.1      cgd 
    645   1.1      cgd 	/*
    646   1.1      cgd 	 * The only other module that currently defers anything.
    647   1.1      cgd 	 */
    648   1.1      cgd 	deferslc();
    649   1.1      cgd 
    650   1.1      cgd }  /* end of defer_terminit */
    651   1.1      cgd 
    652   1.1      cgd /*
    653   1.1      cgd  * terminit
    654   1.1      cgd  *
    655   1.1      cgd  * Returns true if the pty state has been processed yet.
    656   1.1      cgd  */
    657   1.1      cgd 	int
    658   1.1      cgd terminit()
    659   1.1      cgd {
    660   1.3      cgd 	return(_terminit);
    661   1.1      cgd 
    662   1.1      cgd }  /* end of terminit */
    663   1.1      cgd #endif	/* LINEMODE */
    664