* Copyright (c) 1989 Regents of the University of California.
* %sccs.include.redist.c%
static char sccsid
[] = "@(#)termstat.c 5.10 (Berkeley) %G%";
int def_tspeed
= -1, def_rspeed
= -1;
int def_row
= 0, def_col
= 0;
static int _terminit
= 0;
#if defined(CRAY2) && defined(UNICOS5)
int newmap
= 1; /* nonzero if \n maps to ^M^J */
* This function handles all management of linemode.
* Linemode allows the client to do the local editing of data
* and send only complete lines to the server. Linemode state is
* based on the state of the pty driver. If the pty is set for
* external processing, then we can use linemode. Further, if we
* can use real linemode, then we can look at the edit control bits
* in the pty to determine what editing the client should do.
* Linemode support uses the following state flags to keep track of
* current and desired linemode state.
* alwayslinemode : true if -l was specified on the telnetd
* command line. It means to have linemode on as much as
* lmodetype: signifies whether the client can
* handle real linemode, or if use of kludgeomatic linemode
* is preferred. It will be set to one of the following:
* REAL_LINEMODE : use linemode option
* KLUDGE_LINEMODE : use kludge linemode
* NO_LINEMODE : client is ignorant of linemode
* linemode, uselinemode : linemode is true if linemode
* is currently on, uselinemode is the state that we wish
* to be in. If another function wishes to turn linemode
* on or off, it sets or clears uselinemode.
* editmode, useeditmode : like linemode/uselinemode, but
* these contain the edit mode states (edit and trapsig).
* The state variables correspond to some of the state information
* In real linemode, this corresponds to whether the pty
* expects external processing of incoming data.
* In kludge linemode, this more closely corresponds to the
* whether normal processing is on or not. (ICANON in
* system V, or COOKED mode in BSD.)
* If the -l option was specified (alwayslinemode), then
* an attempt is made to force external processing on at
* The following heuristics are applied to determine linemode
* handling within the server.
* 1) Early on in starting up the server, an attempt is made
* to negotiate the linemode option. If this succeeds
* then lmodetype is set to REAL_LINEMODE and all linemode
* processing occurs in the context of the linemode option.
* 2) If the attempt to negotiate the linemode option failed,
* then we try to use kludge linemode. We test for this
* capability by sending "do Timing Mark". If a positive
* response comes back, then we assume that the client
* understands kludge linemode (ech!) and the
* lmodetype flag is set to KLUDGE_LINEMODE.
* 3) Otherwise, linemode is not supported at all and
* lmodetype remains set to NO_LINEMODE (which happens
* to be 0 for convenience).
* 4) At any time a command arrives that implies a higher
* state of linemode support in the client, we move to that
* A short explanation of kludge linemode is in order here.
* 1) The heuristic to determine support for kludge linemode
* is to send a do timing mark. We assume that a client
* that supports timing marks also supports kludge linemode.
* A risky proposition at best.
* 2) Further negotiation of linemode is done by changing the
* the server's state regarding SGA. If server will SGA,
* then linemode is off, if server won't SGA, then linemode
#if defined(CRAY2) && defined(UNICOS5)
* Keep track of that ol' CR/NL mapping while we're in the
#endif /* defined(CRAY2) && defined(UNICOS5) */
* Check for state of BINARY options.
if (his_want_state_is_wont(TELOPT_BINARY
))
send_do(TELOPT_BINARY
, 1);
if (his_want_state_is_will(TELOPT_BINARY
))
send_dont(TELOPT_BINARY
, 1);
if (my_want_state_is_wont(TELOPT_BINARY
))
send_will(TELOPT_BINARY
, 1);
if (my_want_state_is_will(TELOPT_BINARY
))
send_wont(TELOPT_BINARY
, 1);
* Check for changes to flow control if client supports it.
if (his_state_is_will(TELOPT_LFLOW
)) {
if (tty_flowmode() != flowmode
) {
flowmode
= tty_flowmode();
(void) sprintf(nfrontp
, "%c%c%c%c%c%c", IAC
, SB
,
TELOPT_LFLOW
, flowmode
, IAC
, SE
);
* Check linemode on/off state
uselinemode
= tty_linemode();
* If alwayslinemode is on, and pty is changing to turn it off, then
* force linemode back on.
if (alwayslinemode
&& linemode
&& !uselinemode
) {
tty_setlinemode(uselinemode
);
* If the terminal is not echoing, but editing is enabled,
* something like password input is going to happen, so
* if we the other side is not currently sending encrypted
* data, ask the other side to start encrypting.
if (his_state_is_will(TELOPT_ENCRYPT
)) {
static int enc_passwd
= 0;
if (uselinemode
&& !tty_isecho() && tty_isediting()
&& (enc_passwd
== 0) && !decrypt_input
) {
encrypt_send_request_start();
encrypt_send_request_end();
* Do echo mode handling as soon as we know what the
* linemode is going to be.
* If the pty has echo turned off, then tell the client that
* the server will echo. If echo is on, then the server
* will echo if in character mode, but in linemode the
* client should do local echoing. The state machine will
* not send anything if it is unnecessary, so don't worry
* If we need to send the WILL ECHO (because echo is off),
* then delay that until after we have changed the MODE.
* This way, when the user is turning off both editing
* and echo, the client will get editing turned off first.
* This keeps the client from going into encryption mode
* and then right back out if it is doing auto-encryption
* when passwords are being typed.
send_wont(TELOPT_ECHO
, 1);
* If linemode is being turned off, send appropriate
* command and then we're all done.
if (!uselinemode
&& linemode
) {
if (lmodetype
== REAL_LINEMODE
) {
# endif /* KLUDGELINEMODE */
send_dont(TELOPT_LINEMODE
, 1);
} else if (lmodetype
== KLUDGE_LINEMODE
)
send_will(TELOPT_SGA
, 1);
# endif /* KLUDGELINEMODE */
send_will(TELOPT_ECHO
, 1);
* If using real linemode check edit modes for possible later use.
* If we are in kludge linemode, do the SGA negotiation.
if (lmodetype
== REAL_LINEMODE
) {
# endif /* KLUDGELINEMODE */
useeditmode
|= MODE_EDIT
;
useeditmode
|= MODE_TRAPSIG
;
useeditmode
|= MODE_SOFT_TAB
;
useeditmode
|= MODE_LIT_ECHO
;
} else if (lmodetype
== KLUDGE_LINEMODE
) {
if (tty_isediting() && uselinemode
)
send_wont(TELOPT_SGA
, 1);
send_will(TELOPT_SGA
, 1);
# endif /* KLUDGELINEMODE */
* Negotiate linemode on if pty state has changed to turn it on.
* Send appropriate command and send along edit mode, then all done.
if (uselinemode
&& !linemode
) {
if (lmodetype
== KLUDGE_LINEMODE
) {
send_wont(TELOPT_SGA
, 1);
} else if (lmodetype
== REAL_LINEMODE
) {
# endif /* KLUDGELINEMODE */
send_do(TELOPT_LINEMODE
, 1);
/* send along edit modes */
(void) sprintf(nfrontp
, "%c%c%c%c%c%c%c", IAC
, SB
,
TELOPT_LINEMODE
, LM_MODE
, useeditmode
,
# endif /* KLUDGELINEMODE */
* None of what follows is of any value if not using
if (lmodetype
< REAL_LINEMODE
)
# endif /* KLUDGELINEMODE */
if (linemode
&& his_state_is_will(TELOPT_LINEMODE
)) {
* If edit mode changed, send edit mode.
if (useeditmode
!= editmode
) {
* Send along appropriate edit mode mask.
(void) sprintf(nfrontp
, "%c%c%c%c%c%c%c", IAC
, SB
,
TELOPT_LINEMODE
, LM_MODE
, useeditmode
,
* Check for changes to special characters in use.
send_will(TELOPT_ECHO
, 1);
* Some things should be deferred until after the pty state has
* been set by the local process. Do those things that have been
* deferred now. This only happens once.
* Process linemode related requests from the client.
* Client can request a change to only one of linemode, editmode or slc's
* at a time, and if using kludge linemode, then only linemode may be
clientstat(code
, parm1
, parm2
)
register int code
, parm1
, parm2
;
* Get a copy of terminal characteristics.
* Process request from client. code tells what it is.
* Don't do anything unless client is asking us to change
uselinemode
= (parm1
== WILL
);
if (uselinemode
!= linemode
) {
* If using kludge linemode, make sure that
* we can do what the client asks.
* We can not turn off linemode if alwayslinemode
* and the ICANON bit is set.
if (lmodetype
== KLUDGE_LINEMODE
) {
if (alwayslinemode
&& tty_isediting()) {
* Quit now if we can't do it.
if (uselinemode
== linemode
)
* If using real linemode and linemode is being
* turned on, send along the edit mode mask.
if (lmodetype
== REAL_LINEMODE
&& uselinemode
)
# else /* KLUDGELINEMODE */
# endif /* KLUDGELINEMODE */
useeditmode
|= MODE_EDIT
;
useeditmode
|= MODE_TRAPSIG
;
useeditmode
|= MODE_SOFT_TAB
;
useeditmode
|= MODE_LIT_ECHO
;
(void) sprintf(nfrontp
, "%c%c%c%c%c%c%c", IAC
,
SB
, TELOPT_LINEMODE
, LM_MODE
,
tty_setlinemode(uselinemode
);
register int ack
, changed
;
* Client has sent along a mode mask. If it agrees with
* what we are currently doing, ignore it; if not, it could
* be viewed as a request to change. Note that the server
* will change to the modes in an ack if it is different from
* what we currently have, but we will not ack the ack.
useeditmode
&= MODE_MASK
;
ack
= (useeditmode
& MODE_ACK
);
useeditmode
&= ~MODE_ACK
;
if (changed
= (useeditmode
^ editmode
)) {
* This check is for a timing problem. If the
* state of the tty has changed (due to the user
* application) we need to process that info
* before we write in the state contained in the
* ack!!! This gets out the new MODE request,
* and when the ack to that command comes back
* we'll set it and be in the right mode.
tty_setedit(useeditmode
& MODE_EDIT
);
if (changed
& MODE_TRAPSIG
)
tty_setsig(useeditmode
& MODE_TRAPSIG
);
if (changed
& MODE_SOFT_TAB
)
tty_setsofttab(useeditmode
& MODE_SOFT_TAB
);
if (changed
& MODE_LIT_ECHO
)
tty_setlitecho(useeditmode
& MODE_LIT_ECHO
);
(void) sprintf(nfrontp
, "%c%c%c%c%c%c%c", IAC
,
SB
, TELOPT_LINEMODE
, LM_MODE
,
} /* end of case LM_MODE */
* Defer changing window size until after terminal is
* Change window size as requested by client.
(void) ioctl(pty
, TIOCSWINSZ
, (char *)&ws
);
* Defer changing the terminal speed.
* Change terminal speed as requested by client.
* We set the receive speed first, so that if we can't
* store seperate receive and transmit speeds, the transmit
* speed will take precedence.
} /* end of case TELOPT_TSPEED */
#if defined(CRAY2) && defined(UNICOS5)
* Just in case of the likely event that we changed the pty state.
#endif /* defined(CRAY2) && defined(UNICOS5) */
} /* end of clientstat */
#if defined(CRAY2) && defined(UNICOS5)
#endif /* defined(CRAY2) && defined(UNICOS5) */
* Some things should not be done until after the login process has started
* and all the pty modes are set to what they are supposed to be. This
* function is called when the pty state has been processed for the first time.
* It calls other functions that do things that were deferred in each module.
* local stuff that got deferred.
clientstat(TELOPT_TSPEED
, def_tspeed
, def_rspeed
);
def_tspeed
= def_rspeed
= 0;
if (def_col
|| def_row
) {
bzero((char *)&ws
, sizeof(ws
));
(void) ioctl(pty
, TIOCSWINSZ
, (char *)&ws
);
* The only other module that currently defers anything.
} /* end of defer_terminit */
* Returns true if the pty state has been processed yet.