Fix for Cray UNICOS sessions
[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
b7c8f459 9static char sccsid[] = "@(#)termstat.c 5.10 (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
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 */
1af3d848 104 void
ea139302
PB
105localstat()
106{
107 void netflush();
1af3d848 108 int need_will_echo = 0;
ea139302 109
4a8a7128 110#if defined(CRAY2) && defined(UNICOS5)
ea139302
PB
111 /*
112 * Keep track of that ol' CR/NL mapping while we're in the
113 * neighborhood.
114 */
115 newmap = tty_isnewmap();
1af3d848 116#endif /* defined(CRAY2) && defined(UNICOS5) */
ea139302
PB
117
118 /*
119 * Check for state of BINARY options.
120 */
121 if (tty_isbinaryin()) {
4a8a7128 122 if (his_want_state_is_wont(TELOPT_BINARY))
053fd49d 123 send_do(TELOPT_BINARY, 1);
ea139302 124 } else {
4a8a7128 125 if (his_want_state_is_will(TELOPT_BINARY))
053fd49d 126 send_dont(TELOPT_BINARY, 1);
ea139302
PB
127 }
128
129 if (tty_isbinaryout()) {
4a8a7128 130 if (my_want_state_is_wont(TELOPT_BINARY))
053fd49d 131 send_will(TELOPT_BINARY, 1);
ea139302 132 } else {
4a8a7128 133 if (my_want_state_is_will(TELOPT_BINARY))
053fd49d 134 send_wont(TELOPT_BINARY, 1);
ea139302
PB
135 }
136
137 /*
138 * Check for changes to flow control if client supports it.
139 */
4a8a7128 140 if (his_state_is_will(TELOPT_LFLOW)) {
ea139302
PB
141 if (tty_flowmode() != flowmode) {
142 flowmode = tty_flowmode();
143 (void) sprintf(nfrontp, "%c%c%c%c%c%c", IAC, SB,
144 TELOPT_LFLOW, flowmode, IAC, SE);
145 nfrontp += 6;
146 }
147 }
148
149 /*
150 * Check linemode on/off state
151 */
152 uselinemode = tty_linemode();
153
154 /*
155 * If alwayslinemode is on, and pty is changing to turn it off, then
156 * force linemode back on.
157 */
158 if (alwayslinemode && linemode && !uselinemode) {
159 uselinemode = 1;
160 tty_setlinemode(uselinemode);
161 }
162
b7c8f459
DB
163#if defined(ENCRYPT)
164 /*
165 * If the terminal is not echoing, but editing is enabled,
166 * something like password input is going to happen, so
167 * if we the other side is not currently sending encrypted
168 * data, ask the other side to start encrypting.
169 */
170 if (his_state_is_will(TELOPT_ENCRYPT)) {
171 static int enc_passwd = 0;
172 if (uselinemode && !tty_isecho() && tty_isediting()
173 && (enc_passwd == 0) && !decrypt_input) {
174 encrypt_send_request_start();
175 enc_passwd = 1;
176 } else if (enc_passwd) {
177 encrypt_send_request_end();
178 enc_passwd = 0;
179 }
180 }
181#endif
182
ea139302
PB
183 /*
184 * Do echo mode handling as soon as we know what the
185 * linemode is going to be.
186 * If the pty has echo turned off, then tell the client that
187 * the server will echo. If echo is on, then the server
188 * will echo if in character mode, but in linemode the
189 * client should do local echoing. The state machine will
190 * not send anything if it is unnecessary, so don't worry
191 * about that here.
1af3d848
DB
192 *
193 * If we need to send the WILL ECHO (because echo is off),
194 * then delay that until after we have changed the MODE.
195 * This way, when the user is turning off both editing
196 * and echo, the client will get editing turned off first.
197 * This keeps the client from going into encryption mode
198 * and then right back out if it is doing auto-encryption
199 * when passwords are being typed.
ea139302 200 */
2c9c7136
PB
201 if (uselinemode) {
202 if (tty_isecho())
203 send_wont(TELOPT_ECHO, 1);
204 else
1af3d848 205 need_will_echo = 1;
2c9c7136 206 }
ea139302
PB
207
208 /*
209 * If linemode is being turned off, send appropriate
210 * command and then we're all done.
211 */
212 if (!uselinemode && linemode) {
213# ifdef KLUDGELINEMODE
1af3d848 214 if (lmodetype == REAL_LINEMODE) {
ea139302 215# endif /* KLUDGELINEMODE */
053fd49d 216 send_dont(TELOPT_LINEMODE, 1);
ea139302 217# ifdef KLUDGELINEMODE
1af3d848 218 } else if (lmodetype == KLUDGE_LINEMODE)
cb781470 219 send_will(TELOPT_SGA, 1);
ea139302 220# endif /* KLUDGELINEMODE */
1af3d848 221 send_will(TELOPT_ECHO, 1);
ea139302
PB
222 linemode = uselinemode;
223 goto done;
224 }
225
226# ifdef KLUDGELINEMODE
227 /*
228 * If using real linemode check edit modes for possible later use.
4a8a7128 229 * If we are in kludge linemode, do the SGA negotiation.
ea139302
PB
230 */
231 if (lmodetype == REAL_LINEMODE) {
232# endif /* KLUDGELINEMODE */
233 useeditmode = 0;
234 if (tty_isediting())
235 useeditmode |= MODE_EDIT;
236 if (tty_istrapsig())
237 useeditmode |= MODE_TRAPSIG;
4a8a7128
PB
238 if (tty_issofttab())
239 useeditmode |= MODE_SOFT_TAB;
240 if (tty_islitecho())
241 useeditmode |= MODE_LIT_ECHO;
ea139302 242# ifdef KLUDGELINEMODE
4a8a7128
PB
243 } else if (lmodetype == KLUDGE_LINEMODE) {
244 if (tty_isediting() && uselinemode)
245 send_wont(TELOPT_SGA, 1);
246 else
247 send_will(TELOPT_SGA, 1);
ea139302
PB
248 }
249# endif /* KLUDGELINEMODE */
250
251 /*
252 * Negotiate linemode on if pty state has changed to turn it on.
253 * Send appropriate command and send along edit mode, then all done.
254 */
255 if (uselinemode && !linemode) {
256# ifdef KLUDGELINEMODE
257 if (lmodetype == KLUDGE_LINEMODE) {
053fd49d 258 send_wont(TELOPT_SGA, 1);
ea139302
PB
259 } else if (lmodetype == REAL_LINEMODE) {
260# endif /* KLUDGELINEMODE */
053fd49d 261 send_do(TELOPT_LINEMODE, 1);
ea139302
PB
262 /* send along edit modes */
263 (void) sprintf(nfrontp, "%c%c%c%c%c%c%c", IAC, SB,
264 TELOPT_LINEMODE, LM_MODE, useeditmode,
265 IAC, SE);
266 nfrontp += 7;
267 editmode = useeditmode;
268# ifdef KLUDGELINEMODE
269 }
270# endif /* KLUDGELINEMODE */
271 linemode = uselinemode;
272 goto done;
273 }
274
275# ifdef KLUDGELINEMODE
276 /*
277 * None of what follows is of any value if not using
278 * real linemode.
279 */
280 if (lmodetype < REAL_LINEMODE)
281 goto done;
282# endif /* KLUDGELINEMODE */
283
2c9c7136 284 if (linemode && his_state_is_will(TELOPT_LINEMODE)) {
ea139302
PB
285 /*
286 * If edit mode changed, send edit mode.
287 */
288 if (useeditmode != editmode) {
289 /*
290 * Send along appropriate edit mode mask.
291 */
292 (void) sprintf(nfrontp, "%c%c%c%c%c%c%c", IAC, SB,
293 TELOPT_LINEMODE, LM_MODE, useeditmode,
294 IAC, SE);
295 nfrontp += 7;
296 editmode = useeditmode;
297 }
298
299
300 /*
301 * Check for changes to special characters in use.
302 */
303 start_slc(0);
304 check_slc();
1af3d848 305 (void) end_slc(0);
ea139302
PB
306 }
307
308done:
1af3d848
DB
309 if (need_will_echo)
310 send_will(TELOPT_ECHO, 1);
ea139302
PB
311 /*
312 * Some things should be deferred until after the pty state has
313 * been set by the local process. Do those things that have been
314 * deferred now. This only happens once.
315 */
316 if (_terminit == 0) {
317 _terminit = 1;
318 defer_terminit();
319 }
320
321 netflush();
322 set_termbuf();
323 return;
324
325} /* end of localstat */
326#endif /* LINEMODE */
327
328
329/*
330 * clientstat
331 *
332 * Process linemode related requests from the client.
333 * Client can request a change to only one of linemode, editmode or slc's
334 * at a time, and if using kludge linemode, then only linemode may be
335 * affected.
336 */
1af3d848 337 void
ea139302 338clientstat(code, parm1, parm2)
1af3d848 339 register int code, parm1, parm2;
ea139302
PB
340{
341 void netflush();
342
343 /*
344 * Get a copy of terminal characteristics.
345 */
346 init_termbuf();
347
348 /*
349 * Process request from client. code tells what it is.
350 */
351 switch (code) {
352#ifdef LINEMODE
353 case TELOPT_LINEMODE:
354 /*
355 * Don't do anything unless client is asking us to change
356 * modes.
357 */
358 uselinemode = (parm1 == WILL);
359 if (uselinemode != linemode) {
360# ifdef KLUDGELINEMODE
361 /*
362 * If using kludge linemode, make sure that
363 * we can do what the client asks.
364 * We can not turn off linemode if alwayslinemode
053fd49d 365 * and the ICANON bit is set.
ea139302
PB
366 */
367 if (lmodetype == KLUDGE_LINEMODE) {
053fd49d 368 if (alwayslinemode && tty_isediting()) {
ea139302
PB
369 uselinemode = 1;
370 }
371 }
372
373 /*
374 * Quit now if we can't do it.
375 */
376 if (uselinemode == linemode)
377 return;
378
379 /*
380 * If using real linemode and linemode is being
381 * turned on, send along the edit mode mask.
382 */
383 if (lmodetype == REAL_LINEMODE && uselinemode)
384# else /* KLUDGELINEMODE */
385 if (uselinemode)
386# endif /* KLUDGELINEMODE */
387 {
388 useeditmode = 0;
389 if (tty_isediting())
390 useeditmode |= MODE_EDIT;
1af3d848 391 if (tty_istrapsig)
ea139302 392 useeditmode |= MODE_TRAPSIG;
4a8a7128
PB
393 if (tty_issofttab())
394 useeditmode |= MODE_SOFT_TAB;
395 if (tty_islitecho())
396 useeditmode |= MODE_LIT_ECHO;
ea139302
PB
397 (void) sprintf(nfrontp, "%c%c%c%c%c%c%c", IAC,
398 SB, TELOPT_LINEMODE, LM_MODE,
399 useeditmode, IAC, SE);
400 nfrontp += 7;
401 editmode = useeditmode;
402 }
403
404
405 tty_setlinemode(uselinemode);
406
407 linemode = uselinemode;
408
409 }
410 break;
411
412 case LM_MODE:
413 {
4a8a7128 414 register int ack, changed;
ea139302
PB
415
416 /*
417 * Client has sent along a mode mask. If it agrees with
418 * what we are currently doing, ignore it; if not, it could
419 * be viewed as a request to change. Note that the server
420 * will change to the modes in an ack if it is different from
421 * what we currently have, but we will not ack the ack.
422 */
423 useeditmode &= MODE_MASK;
424 ack = (useeditmode & MODE_ACK);
425 useeditmode &= ~MODE_ACK;
426
4a8a7128 427 if (changed = (useeditmode ^ editmode)) {
1af3d848
DB
428 /*
429 * This check is for a timing problem. If the
430 * state of the tty has changed (due to the user
431 * application) we need to process that info
432 * before we write in the state contained in the
433 * ack!!! This gets out the new MODE request,
434 * and when the ack to that command comes back
435 * we'll set it and be in the right mode.
436 */
437 if (ack)
438 localstat();
4a8a7128
PB
439 if (changed & MODE_EDIT)
440 tty_setedit(useeditmode & MODE_EDIT);
ea139302 441
4a8a7128
PB
442 if (changed & MODE_TRAPSIG)
443 tty_setsig(useeditmode & MODE_TRAPSIG);
444
445 if (changed & MODE_SOFT_TAB)
446 tty_setsofttab(useeditmode & MODE_SOFT_TAB);
447
448 if (changed & MODE_LIT_ECHO)
449 tty_setlitecho(useeditmode & MODE_LIT_ECHO);
ea139302
PB
450
451 set_termbuf();
452
453 if (!ack) {
454 (void) sprintf(nfrontp, "%c%c%c%c%c%c%c", IAC,
455 SB, TELOPT_LINEMODE, LM_MODE,
456 useeditmode|MODE_ACK,
457 IAC, SE);
458 nfrontp += 7;
459 }
460
461 editmode = useeditmode;
462 }
463
464 break;
465
466 } /* end of case LM_MODE */
467#endif /* LINEMODE */
468
469 case TELOPT_NAWS:
470#ifdef TIOCSWINSZ
471 {
472 struct winsize ws;
473
1af3d848
DB
474 def_col = parm1;
475 def_row = parm2;
ea139302
PB
476#ifdef LINEMODE
477 /*
478 * Defer changing window size until after terminal is
479 * initialized.
480 */
1af3d848 481 if (terminit() == 0)
ea139302 482 return;
ea139302
PB
483#endif /* LINEMODE */
484
485 /*
486 * Change window size as requested by client.
487 */
488
489 ws.ws_col = parm1;
490 ws.ws_row = parm2;
491 (void) ioctl(pty, TIOCSWINSZ, (char *)&ws);
492 }
493#endif /* TIOCSWINSZ */
494
495 break;
496
497 case TELOPT_TSPEED:
498 {
1af3d848
DB
499 def_tspeed = parm1;
500 def_rspeed = parm2;
ea139302
PB
501#ifdef LINEMODE
502 /*
503 * Defer changing the terminal speed.
504 */
1af3d848 505 if (terminit() == 0)
ea139302 506 return;
ea139302
PB
507#endif /* LINEMODE */
508 /*
509 * Change terminal speed as requested by client.
1af3d848
DB
510 * We set the receive speed first, so that if we can't
511 * store seperate receive and transmit speeds, the transmit
512 * speed will take precedence.
ea139302 513 */
ea139302 514 tty_rspeed(parm2);
1af3d848 515 tty_tspeed(parm1);
ea139302
PB
516 set_termbuf();
517
518 break;
519
520 } /* end of case TELOPT_TSPEED */
521
522 default:
523 /* What? */
524 break;
525 } /* end of switch */
526
ed8f31c1 527#if defined(CRAY2) && defined(UNICOS5)
ea139302
PB
528 /*
529 * Just in case of the likely event that we changed the pty state.
530 */
531 rcv_ioctl();
ed8f31c1 532#endif /* defined(CRAY2) && defined(UNICOS5) */
ea139302
PB
533
534 netflush();
535
536} /* end of clientstat */
537
ed8f31c1 538#if defined(CRAY2) && defined(UNICOS5)
1af3d848 539 void
ea139302
PB
540termstat()
541{
542 needtermstat = 1;
543}
544
1af3d848 545 void
ea139302
PB
546_termstat()
547{
548 needtermstat = 0;
549 init_termbuf();
550 localstat();
551 rcv_ioctl();
552}
ed8f31c1 553#endif /* defined(CRAY2) && defined(UNICOS5) */
ea139302
PB
554
555#ifdef LINEMODE
556/*
557 * defer_terminit
558 *
559 * Some things should not be done until after the login process has started
560 * and all the pty modes are set to what they are supposed to be. This
561 * function is called when the pty state has been processed for the first time.
562 * It calls other functions that do things that were deferred in each module.
563 */
1af3d848 564 void
ea139302
PB
565defer_terminit()
566{
567
568 /*
569 * local stuff that got deferred.
570 */
571 if (def_tspeed != -1) {
572 clientstat(TELOPT_TSPEED, def_tspeed, def_rspeed);
573 def_tspeed = def_rspeed = 0;
574 }
575
576#ifdef TIOCSWINSZ
577 if (def_col || def_row) {
578 struct winsize ws;
579
1af3d848 580 bzero((char *)&ws, sizeof(ws));
ea139302
PB
581 ws.ws_col = def_col;
582 ws.ws_row = def_row;
583 (void) ioctl(pty, TIOCSWINSZ, (char *)&ws);
584 }
585#endif
586
587 /*
588 * The only other module that currently defers anything.
589 */
590 deferslc();
591
592} /* end of defer_terminit */
593
594/*
595 * terminit
596 *
597 * Returns true if the pty state has been processed yet.
598 */
1af3d848
DB
599 int
600terminit()
ea139302
PB
601{
602 return _terminit;
603
604} /* end of terminit */
605#endif /* LINEMODE */