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