c181962a6386eb2b98fadcdb0bddc6a2714fb896
* Copyright (c) 1989 Regents of the University of California.
* %sccs.include.redist.c%
static char sccsid
[] = "@(#)termstat.c 5.5 (Berkeley) %G%";
static int _terminit
= 0;
static int def_tspeed
= -1, def_rspeed
= -1;
static int def_row
= 0, def_col
= 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
#ifdef 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 (hiswants
[TELOPT_BINARY
] == OPT_NO
)
send_do(TELOPT_BINARY
, 1);
if (hiswants
[TELOPT_BINARY
] == OPT_YES
)
send_dont(TELOPT_BINARY
, 1);
if (mywants
[TELOPT_BINARY
] == OPT_NO
)
send_will(TELOPT_BINARY
, 1);
if (mywants
[TELOPT_BINARY
] == OPT_YES
)
send_wont(TELOPT_BINARY
, 1);
* Check for changes to flow control if client supports it.
if (hisopts
[TELOPT_LFLOW
] == OPT_YES
) {
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 using kludge linemode and linemode is desired, it can't
* be done if normal line editing is not available on the
* pty. This becomes the test for linemode on/off when
if (lmodetype
== KLUDGE_LINEMODE
&& uselinemode
&& tty_israw()) {
tty_setlinemode(uselinemode
);
# endif /* KLUDGELINEMODE */
* 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 (tty_isecho() && uselinemode
)
send_wont(TELOPT_ECHO
, 1);
send_will(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 */
* If using real linemode check edit modes for possible later use.
if (lmodetype
== REAL_LINEMODE
) {
# endif /* KLUDGELINEMODE */
useeditmode
|= MODE_EDIT
;
useeditmode
|= MODE_TRAPSIG
;
# 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 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.
* 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
;
(void) sprintf(nfrontp
, "%c%c%c%c%c%c%c", IAC
,
SB
, TELOPT_LINEMODE
, LM_MODE
,
tty_setlinemode(uselinemode
);
register int mode
, sig
, ack
;
* 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 (useeditmode
!= editmode
) {
mode
= (useeditmode
& MODE_EDIT
);
sig
= (useeditmode
& MODE_TRAPSIG
);
if (mode
!= (editmode
& LM_MODE
)) {
if (sig
!= (editmode
& MODE_TRAPSIG
)) {
(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.
} /* 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
) {
(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.