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