Latest batch of changes. See the README file
[unix-history] / usr / src / libexec / telnetd / termstat.c
CommitLineData
ea139302
PB
1/*
2 * Copyright (c) 1989 Regents of the University of California.
3 * All rights reserved.
4 *
836fe169 5 * %sccs.include.redist.c%
ea139302
PB
6 */
7
8#ifndef lint
4a8a7128 9static char sccsid[] = "@(#)termstat.c 5.6 (Berkeley) %G%";
ea139302
PB
10#endif /* not lint */
11
12#include "telnetd.h"
13
14/*
15 * local variables
16 */
17#ifdef LINEMODE
18static int _terminit = 0;
19static int def_tspeed = -1, def_rspeed = -1;
20#ifdef TIOCSWINSZ
21static int def_row = 0, def_col = 0;
22#endif
23#endif LINEMODE
24
ed8f31c1 25#if defined(CRAY2) && defined(UNICOS5)
ea139302
PB
26int newmap = 1; /* nonzero if \n maps to ^M^J */
27#endif
28
29#ifdef LINEMODE
30/*
31 * localstat
32 *
33 * This function handles all management of linemode.
34 *
35 * Linemode allows the client to do the local editing of data
36 * and send only complete lines to the server. Linemode state is
37 * based on the state of the pty driver. If the pty is set for
38 * external processing, then we can use linemode. Further, if we
39 * can use real linemode, then we can look at the edit control bits
40 * in the pty to determine what editing the client should do.
41 *
42 * Linemode support uses the following state flags to keep track of
43 * current and desired linemode state.
44 * alwayslinemode : true if -l was specified on the telnetd
45 * command line. It means to have linemode on as much as
46 * possible.
47 *
48 * lmodetype: signifies whether the client can
49 * handle real linemode, or if use of kludgeomatic linemode
50 * is preferred. It will be set to one of the following:
51 * REAL_LINEMODE : use linemode option
52 * KLUDGE_LINEMODE : use kludge linemode
53 * NO_LINEMODE : client is ignorant of linemode
54 *
55 * linemode, uselinemode : linemode is true if linemode
56 * is currently on, uselinemode is the state that we wish
57 * to be in. If another function wishes to turn linemode
58 * on or off, it sets or clears uselinemode.
59 *
60 * editmode, useeditmode : like linemode/uselinemode, but
61 * these contain the edit mode states (edit and trapsig).
62 *
63 * The state variables correspond to some of the state information
64 * in the pty.
65 * linemode:
66 * In real linemode, this corresponds to whether the pty
67 * expects external processing of incoming data.
68 * In kludge linemode, this more closely corresponds to the
69 * whether normal processing is on or not. (ICANON in
70 * system V, or COOKED mode in BSD.)
71 * If the -l option was specified (alwayslinemode), then
72 * an attempt is made to force external processing on at
73 * all times.
74 *
75 * The following heuristics are applied to determine linemode
76 * handling within the server.
77 * 1) Early on in starting up the server, an attempt is made
78 * to negotiate the linemode option. If this succeeds
79 * then lmodetype is set to REAL_LINEMODE and all linemode
80 * processing occurs in the context of the linemode option.
81 * 2) If the attempt to negotiate the linemode option failed,
82 * then we try to use kludge linemode. We test for this
83 * capability by sending "do Timing Mark". If a positive
84 * response comes back, then we assume that the client
85 * understands kludge linemode (ech!) and the
86 * lmodetype flag is set to KLUDGE_LINEMODE.
87 * 3) Otherwise, linemode is not supported at all and
88 * lmodetype remains set to NO_LINEMODE (which happens
89 * to be 0 for convenience).
90 * 4) At any time a command arrives that implies a higher
91 * state of linemode support in the client, we move to that
92 * linemode support.
93 *
94 * A short explanation of kludge linemode is in order here.
95 * 1) The heuristic to determine support for kludge linemode
96 * is to send a do timing mark. We assume that a client
97 * that supports timing marks also supports kludge linemode.
98 * A risky proposition at best.
99 * 2) Further negotiation of linemode is done by changing the
100 * the server's state regarding SGA. If server will SGA,
101 * then linemode is off, if server won't SGA, then linemode
102 * is on.
103 */
104localstat()
105{
106 void netflush();
107
4a8a7128 108#if defined(CRAY2) && defined(UNICOS5)
ea139302
PB
109 /*
110 * Keep track of that ol' CR/NL mapping while we're in the
111 * neighborhood.
112 */
113 newmap = tty_isnewmap();
ed8f31c1 114#endif defined(CRAY2) && defined(UNICOS5)
ea139302
PB
115
116 /*
117 * Check for state of BINARY options.
118 */
119 if (tty_isbinaryin()) {
4a8a7128 120 if (his_want_state_is_wont(TELOPT_BINARY))
053fd49d 121 send_do(TELOPT_BINARY, 1);
ea139302 122 } else {
4a8a7128 123 if (his_want_state_is_will(TELOPT_BINARY))
053fd49d 124 send_dont(TELOPT_BINARY, 1);
ea139302
PB
125 }
126
127 if (tty_isbinaryout()) {
4a8a7128 128 if (my_want_state_is_wont(TELOPT_BINARY))
053fd49d 129 send_will(TELOPT_BINARY, 1);
ea139302 130 } else {
4a8a7128 131 if (my_want_state_is_will(TELOPT_BINARY))
053fd49d 132 send_wont(TELOPT_BINARY, 1);
ea139302
PB
133 }
134
135 /*
136 * Check for changes to flow control if client supports it.
137 */
4a8a7128 138 if (his_state_is_will(TELOPT_LFLOW)) {
ea139302
PB
139 if (tty_flowmode() != flowmode) {
140 flowmode = tty_flowmode();
141 (void) sprintf(nfrontp, "%c%c%c%c%c%c", IAC, SB,
142 TELOPT_LFLOW, flowmode, IAC, SE);
143 nfrontp += 6;
144 }
145 }
146
147 /*
148 * Check linemode on/off state
149 */
150 uselinemode = tty_linemode();
151
152 /*
153 * If alwayslinemode is on, and pty is changing to turn it off, then
154 * force linemode back on.
155 */
156 if (alwayslinemode && linemode && !uselinemode) {
157 uselinemode = 1;
158 tty_setlinemode(uselinemode);
159 }
160
ea139302
PB
161 /*
162 * Do echo mode handling as soon as we know what the
163 * linemode is going to be.
164 * If the pty has echo turned off, then tell the client that
165 * the server will echo. If echo is on, then the server
166 * will echo if in character mode, but in linemode the
167 * client should do local echoing. The state machine will
168 * not send anything if it is unnecessary, so don't worry
169 * about that here.
170 */
171 if (tty_isecho() && uselinemode)
053fd49d 172 send_wont(TELOPT_ECHO, 1);
ea139302 173 else
053fd49d 174 send_will(TELOPT_ECHO, 1);
ea139302
PB
175
176 /*
177 * If linemode is being turned off, send appropriate
178 * command and then we're all done.
179 */
180 if (!uselinemode && linemode) {
181# ifdef KLUDGELINEMODE
182 if (lmodetype == REAL_LINEMODE)
183# endif /* KLUDGELINEMODE */
053fd49d 184 send_dont(TELOPT_LINEMODE, 1);
ea139302
PB
185# ifdef KLUDGELINEMODE
186 else if (lmodetype == KLUDGE_LINEMODE)
cb781470 187 send_will(TELOPT_SGA, 1);
ea139302
PB
188# endif /* KLUDGELINEMODE */
189 linemode = uselinemode;
190 goto done;
191 }
192
193# ifdef KLUDGELINEMODE
194 /*
195 * If using real linemode check edit modes for possible later use.
4a8a7128 196 * If we are in kludge linemode, do the SGA negotiation.
ea139302
PB
197 */
198 if (lmodetype == REAL_LINEMODE) {
199# endif /* KLUDGELINEMODE */
200 useeditmode = 0;
201 if (tty_isediting())
202 useeditmode |= MODE_EDIT;
203 if (tty_istrapsig())
204 useeditmode |= MODE_TRAPSIG;
4a8a7128
PB
205 if (tty_issofttab())
206 useeditmode |= MODE_SOFT_TAB;
207 if (tty_islitecho())
208 useeditmode |= MODE_LIT_ECHO;
ea139302 209# ifdef KLUDGELINEMODE
4a8a7128
PB
210 } else if (lmodetype == KLUDGE_LINEMODE) {
211 if (tty_isediting() && uselinemode)
212 send_wont(TELOPT_SGA, 1);
213 else
214 send_will(TELOPT_SGA, 1);
ea139302
PB
215 }
216# endif /* KLUDGELINEMODE */
217
218 /*
219 * Negotiate linemode on if pty state has changed to turn it on.
220 * Send appropriate command and send along edit mode, then all done.
221 */
222 if (uselinemode && !linemode) {
223# ifdef KLUDGELINEMODE
224 if (lmodetype == KLUDGE_LINEMODE) {
053fd49d 225 send_wont(TELOPT_SGA, 1);
ea139302
PB
226 } else if (lmodetype == REAL_LINEMODE) {
227# endif /* KLUDGELINEMODE */
053fd49d 228 send_do(TELOPT_LINEMODE, 1);
ea139302
PB
229 /* send along edit modes */
230 (void) sprintf(nfrontp, "%c%c%c%c%c%c%c", IAC, SB,
231 TELOPT_LINEMODE, LM_MODE, useeditmode,
232 IAC, SE);
233 nfrontp += 7;
234 editmode = useeditmode;
235# ifdef KLUDGELINEMODE
236 }
237# endif /* KLUDGELINEMODE */
238 linemode = uselinemode;
239 goto done;
240 }
241
242# ifdef KLUDGELINEMODE
243 /*
244 * None of what follows is of any value if not using
245 * real linemode.
246 */
247 if (lmodetype < REAL_LINEMODE)
248 goto done;
249# endif /* KLUDGELINEMODE */
250
251 if (linemode) {
252 /*
253 * If edit mode changed, send edit mode.
254 */
255 if (useeditmode != editmode) {
256 /*
257 * Send along appropriate edit mode mask.
258 */
259 (void) sprintf(nfrontp, "%c%c%c%c%c%c%c", IAC, SB,
260 TELOPT_LINEMODE, LM_MODE, useeditmode,
261 IAC, SE);
262 nfrontp += 7;
263 editmode = useeditmode;
264 }
265
266
267 /*
268 * Check for changes to special characters in use.
269 */
270 start_slc(0);
271 check_slc();
272 end_slc(0);
273 }
274
275done:
276 /*
277 * Some things should be deferred until after the pty state has
278 * been set by the local process. Do those things that have been
279 * deferred now. This only happens once.
280 */
281 if (_terminit == 0) {
282 _terminit = 1;
283 defer_terminit();
284 }
285
286 netflush();
287 set_termbuf();
288 return;
289
290} /* end of localstat */
291#endif /* LINEMODE */
292
293
294/*
295 * clientstat
296 *
297 * Process linemode related requests from the client.
298 * Client can request a change to only one of linemode, editmode or slc's
299 * at a time, and if using kludge linemode, then only linemode may be
300 * affected.
301 */
302clientstat(code, parm1, parm2)
303register int code, parm1, parm2;
304{
305 void netflush();
306
307 /*
308 * Get a copy of terminal characteristics.
309 */
310 init_termbuf();
311
312 /*
313 * Process request from client. code tells what it is.
314 */
315 switch (code) {
316#ifdef LINEMODE
317 case TELOPT_LINEMODE:
318 /*
319 * Don't do anything unless client is asking us to change
320 * modes.
321 */
322 uselinemode = (parm1 == WILL);
323 if (uselinemode != linemode) {
324# ifdef KLUDGELINEMODE
325 /*
326 * If using kludge linemode, make sure that
327 * we can do what the client asks.
328 * We can not turn off linemode if alwayslinemode
053fd49d 329 * and the ICANON bit is set.
ea139302
PB
330 */
331 if (lmodetype == KLUDGE_LINEMODE) {
053fd49d 332 if (alwayslinemode && tty_isediting()) {
ea139302
PB
333 uselinemode = 1;
334 }
335 }
336
337 /*
338 * Quit now if we can't do it.
339 */
340 if (uselinemode == linemode)
341 return;
342
343 /*
344 * If using real linemode and linemode is being
345 * turned on, send along the edit mode mask.
346 */
347 if (lmodetype == REAL_LINEMODE && uselinemode)
348# else /* KLUDGELINEMODE */
349 if (uselinemode)
350# endif /* KLUDGELINEMODE */
351 {
352 useeditmode = 0;
353 if (tty_isediting())
354 useeditmode |= MODE_EDIT;
355 if (tty_istrapsig)
356 useeditmode |= MODE_TRAPSIG;
4a8a7128
PB
357 if (tty_issofttab())
358 useeditmode |= MODE_SOFT_TAB;
359 if (tty_islitecho())
360 useeditmode |= MODE_LIT_ECHO;
ea139302
PB
361 (void) sprintf(nfrontp, "%c%c%c%c%c%c%c", IAC,
362 SB, TELOPT_LINEMODE, LM_MODE,
363 useeditmode, IAC, SE);
364 nfrontp += 7;
365 editmode = useeditmode;
366 }
367
368
369 tty_setlinemode(uselinemode);
370
371 linemode = uselinemode;
372
373 }
374 break;
375
376 case LM_MODE:
377 {
4a8a7128 378 register int ack, changed;
ea139302
PB
379
380 /*
381 * Client has sent along a mode mask. If it agrees with
382 * what we are currently doing, ignore it; if not, it could
383 * be viewed as a request to change. Note that the server
384 * will change to the modes in an ack if it is different from
385 * what we currently have, but we will not ack the ack.
386 */
387 useeditmode &= MODE_MASK;
388 ack = (useeditmode & MODE_ACK);
389 useeditmode &= ~MODE_ACK;
390
4a8a7128
PB
391 if (changed = (useeditmode ^ editmode)) {
392 if (changed & MODE_EDIT)
393 tty_setedit(useeditmode & MODE_EDIT);
ea139302 394
4a8a7128
PB
395 if (changed & MODE_TRAPSIG)
396 tty_setsig(useeditmode & MODE_TRAPSIG);
397
398 if (changed & MODE_SOFT_TAB)
399 tty_setsofttab(useeditmode & MODE_SOFT_TAB);
400
401 if (changed & MODE_LIT_ECHO)
402 tty_setlitecho(useeditmode & MODE_LIT_ECHO);
ea139302
PB
403
404 set_termbuf();
405
406 if (!ack) {
407 (void) sprintf(nfrontp, "%c%c%c%c%c%c%c", IAC,
408 SB, TELOPT_LINEMODE, LM_MODE,
409 useeditmode|MODE_ACK,
410 IAC, SE);
411 nfrontp += 7;
412 }
413
414 editmode = useeditmode;
415 }
416
417 break;
418
419 } /* end of case LM_MODE */
420#endif /* LINEMODE */
421
422 case TELOPT_NAWS:
423#ifdef TIOCSWINSZ
424 {
425 struct winsize ws;
426
427#ifdef LINEMODE
428 /*
429 * Defer changing window size until after terminal is
430 * initialized.
431 */
432 if (terminit() == 0) {
433 def_col = parm1;
ed8f31c1 434 def_row = parm2;
ea139302
PB
435 return;
436 }
437#endif /* LINEMODE */
438
439 /*
440 * Change window size as requested by client.
441 */
442
443 ws.ws_col = parm1;
444 ws.ws_row = parm2;
445 (void) ioctl(pty, TIOCSWINSZ, (char *)&ws);
446 }
447#endif /* TIOCSWINSZ */
448
449 break;
450
451 case TELOPT_TSPEED:
452 {
453#ifdef LINEMODE
454 /*
455 * Defer changing the terminal speed.
456 */
457 if (terminit() == 0) {
458 def_tspeed = parm1;
459 def_rspeed = parm2;
460 return;
461 }
462#endif /* LINEMODE */
463 /*
464 * Change terminal speed as requested by client.
465 */
466 tty_tspeed(parm1);
467 tty_rspeed(parm2);
468 set_termbuf();
469
470 break;
471
472 } /* end of case TELOPT_TSPEED */
473
474 default:
475 /* What? */
476 break;
477 } /* end of switch */
478
ed8f31c1 479#if defined(CRAY2) && defined(UNICOS5)
ea139302
PB
480 /*
481 * Just in case of the likely event that we changed the pty state.
482 */
483 rcv_ioctl();
ed8f31c1 484#endif /* defined(CRAY2) && defined(UNICOS5) */
ea139302
PB
485
486 netflush();
487
488} /* end of clientstat */
489
ed8f31c1 490#if defined(CRAY2) && defined(UNICOS5)
ea139302
PB
491termstat()
492{
493 needtermstat = 1;
494}
495
496_termstat()
497{
498 needtermstat = 0;
499 init_termbuf();
500 localstat();
501 rcv_ioctl();
502}
ed8f31c1 503#endif /* defined(CRAY2) && defined(UNICOS5) */
ea139302
PB
504
505#ifdef LINEMODE
506/*
507 * defer_terminit
508 *
509 * Some things should not be done until after the login process has started
510 * and all the pty modes are set to what they are supposed to be. This
511 * function is called when the pty state has been processed for the first time.
512 * It calls other functions that do things that were deferred in each module.
513 */
514defer_terminit()
515{
516
517 /*
518 * local stuff that got deferred.
519 */
520 if (def_tspeed != -1) {
521 clientstat(TELOPT_TSPEED, def_tspeed, def_rspeed);
522 def_tspeed = def_rspeed = 0;
523 }
524
525#ifdef TIOCSWINSZ
526 if (def_col || def_row) {
527 struct winsize ws;
528
529 ws.ws_col = def_col;
530 ws.ws_row = def_row;
531 (void) ioctl(pty, TIOCSWINSZ, (char *)&ws);
532 }
533#endif
534
535 /*
536 * The only other module that currently defers anything.
537 */
538 deferslc();
539
540} /* end of defer_terminit */
541
542/*
543 * terminit
544 *
545 * Returns true if the pty state has been processed yet.
546 */
547int terminit()
548{
549 return _terminit;
550
551} /* end of terminit */
552#endif /* LINEMODE */