1 /*
2 * Copyright (c) 1988, 1990, 1993
3 * The Regents of the University of California. All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 * 3. All advertising materials mentioning features or use of this software
14 * must display the following acknowledgement:
15 * This product includes software developed by the University of
16 * California, Berkeley and its contributors.
17 * 4. Neither the name of the University nor the names of its contributors
18 * may be used to endorse or promote products derived from this software
19 * without specific prior written permission.
20 *
21 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
25 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31 * SUCH DAMAGE.
32 */
33
34 #include "telnet_locl.h"
35
36 RCSID("$Id$");
37
38 #define strip(x) (eight ? (x) : ((x) & 0x7f))
39
40 static unsigned char subbuffer[SUBBUFSIZE],
41 *subpointer, *subend; /* buffer for sub-options */
42 #define SB_CLEAR() subpointer = subbuffer;
43 #define SB_TERM() { subend = subpointer; SB_CLEAR(); }
44 #define SB_ACCUM(c) if (subpointer < (subbuffer+sizeof subbuffer)) { \
45 *subpointer++ = (c); \
46 }
47
48 #define SB_GET() ((*subpointer++)&0xff)
49 #define SB_PEEK() ((*subpointer)&0xff)
50 #define SB_EOF() (subpointer >= subend)
51 #define SB_LEN() (subend - subpointer)
52
53 char options[256]; /* The combined options */
54 char do_dont_resp[256];
55 char will_wont_resp[256];
56
57 int
58 eight = 3,
59 binary = 0,
60 autologin = 0, /* Autologin anyone? */
61 skiprc = 0,
62 connected,
63 showoptions,
64 ISend, /* trying to send network data in */
65 debug = 0,
66 crmod,
67 netdata, /* Print out network data flow */
68 crlf, /* Should '\r' be mapped to <CR><LF> (or <CR><NUL>)? */
69 telnetport,
70 wantencryption = 0,
71 SYNCHing, /* we are in TELNET SYNCH mode */
72 flushout, /* flush output */
73 autoflush = 0, /* flush output when interrupting? */
74 autosynch, /* send interrupt characters with SYNCH? */
75 localflow, /* we handle flow control locally */
76 restartany, /* if flow control enabled, restart on any character */
77 localchars, /* we recognize interrupt/quit */
78 donelclchars, /* the user has set "localchars" */
79 donebinarytoggle, /* the user has put us in binary */
80 dontlecho, /* do we suppress local echoing right now? */
81 globalmode;
82
83 char *prompt = 0;
84
85 int scheduler_lockout_tty = 0;
86
87 cc_t escape;
88 cc_t rlogin;
89 #ifdef KLUDGELINEMODE
90 cc_t echoc;
91 #endif
92
93 /*
94 * Telnet receiver states for fsm
95 */
96 #define TS_DATA 0
97 #define TS_IAC 1
98 #define TS_WILL 2
99 #define TS_WONT 3
100 #define TS_DO 4
101 #define TS_DONT 5
102 #define TS_CR 6
103 #define TS_SB 7 /* sub-option collection */
104 #define TS_SE 8 /* looking for sub-option end */
105
106 static int telrcv_state;
107 #ifdef OLD_ENVIRON
108 unsigned char telopt_environ = TELOPT_NEW_ENVIRON;
109 #else
110 # define telopt_environ TELOPT_NEW_ENVIRON
111 #endif
112
113 jmp_buf toplevel;
114 jmp_buf peerdied;
115
116 int flushline;
117 int linemode;
118
119 #ifdef KLUDGELINEMODE
120 int kludgelinemode = 1;
121 #endif
122
123 /*
124 * The following are some clocks used to decide how to interpret
125 * the relationship between various variables.
126 */
127
128 Clocks clocks;
129
130 static int is_unique(char *name, char **as, char **ae);
131
132
133 /*
134 * Initialize telnet environment.
135 */
136
137 void
init_telnet(void)138 init_telnet(void)
139 {
140 env_init();
141
142 SB_CLEAR();
143 memset(options, 0, sizeof options);
144
145 connected = ISend = localflow = donebinarytoggle = 0;
146 #if defined(AUTHENTICATION) || defined(ENCRYPTION)
147 auth_encrypt_connect(connected);
148 #endif /* defined(AUTHENTICATION) || defined(ENCRYPTION) */
149 restartany = -1;
150
151 SYNCHing = 0;
152
153 /* Don't change NetTrace */
154
155 escape = CONTROL(']');
156 rlogin = _POSIX_VDISABLE;
157 #ifdef KLUDGELINEMODE
158 echoc = CONTROL('E');
159 #endif
160
161 flushline = 1;
162 telrcv_state = TS_DATA;
163 }
164
165
166 /*
167 * These routines are in charge of sending option negotiations
168 * to the other side.
169 *
170 * The basic idea is that we send the negotiation if either side
171 * is in disagreement as to what the current state should be.
172 */
173
174 void
send_do(int c,int init)175 send_do(int c, int init)
176 {
177 if (init) {
178 if (((do_dont_resp[c] == 0) && my_state_is_do(c)) ||
179 my_want_state_is_do(c))
180 return;
181 set_my_want_state_do(c);
182 do_dont_resp[c]++;
183 }
184 NET2ADD(IAC, DO);
185 NETADD(c);
186 printoption("SENT", DO, c);
187 }
188
189 void
send_dont(int c,int init)190 send_dont(int c, int init)
191 {
192 if (init) {
193 if (((do_dont_resp[c] == 0) && my_state_is_dont(c)) ||
194 my_want_state_is_dont(c))
195 return;
196 set_my_want_state_dont(c);
197 do_dont_resp[c]++;
198 }
199 NET2ADD(IAC, DONT);
200 NETADD(c);
201 printoption("SENT", DONT, c);
202 }
203
204 void
send_will(int c,int init)205 send_will(int c, int init)
206 {
207 if (init) {
208 if (((will_wont_resp[c] == 0) && my_state_is_will(c)) ||
209 my_want_state_is_will(c))
210 return;
211 set_my_want_state_will(c);
212 will_wont_resp[c]++;
213 }
214 NET2ADD(IAC, WILL);
215 NETADD(c);
216 printoption("SENT", WILL, c);
217 }
218
219 void
send_wont(int c,int init)220 send_wont(int c, int init)
221 {
222 if (init) {
223 if (((will_wont_resp[c] == 0) && my_state_is_wont(c)) ||
224 my_want_state_is_wont(c))
225 return;
226 set_my_want_state_wont(c);
227 will_wont_resp[c]++;
228 }
229 NET2ADD(IAC, WONT);
230 NETADD(c);
231 printoption("SENT", WONT, c);
232 }
233
234
235 void
willoption(int option)236 willoption(int option)
237 {
238 int new_state_ok = 0;
239
240 if (do_dont_resp[option]) {
241 --do_dont_resp[option];
242 if (do_dont_resp[option] && my_state_is_do(option))
243 --do_dont_resp[option];
244 }
245
246 if ((do_dont_resp[option] == 0) && my_want_state_is_dont(option)) {
247
248 switch (option) {
249
250 case TELOPT_ECHO:
251 case TELOPT_BINARY:
252 case TELOPT_SGA:
253 settimer(modenegotiated);
254 /* FALL THROUGH */
255 case TELOPT_STATUS:
256 #if defined(AUTHENTICATION)
257 case TELOPT_AUTHENTICATION:
258 #endif
259 #if defined(ENCRYPTION)
260 case TELOPT_ENCRYPT:
261 #endif
262 new_state_ok = 1;
263 break;
264
265 case TELOPT_TM:
266 if (flushout)
267 flushout = 0;
268 /*
269 * Special case for TM. If we get back a WILL,
270 * pretend we got back a WONT.
271 */
272 set_my_want_state_dont(option);
273 set_my_state_dont(option);
274 return; /* Never reply to TM will's/wont's */
275
276 case TELOPT_LINEMODE:
277 default:
278 break;
279 }
280
281 if (new_state_ok) {
282 set_my_want_state_do(option);
283 send_do(option, 0);
284 setconnmode(0); /* possibly set new tty mode */
285 } else {
286 do_dont_resp[option]++;
287 send_dont(option, 0);
288 }
289 }
290 set_my_state_do(option);
291 #if defined(ENCRYPTION)
292 if (option == TELOPT_ENCRYPT)
293 encrypt_send_support();
294 #endif
295 }
296
297 void
wontoption(int option)298 wontoption(int option)
299 {
300 if (do_dont_resp[option]) {
301 --do_dont_resp[option];
302 if (do_dont_resp[option] && my_state_is_dont(option))
303 --do_dont_resp[option];
304 }
305
306 if ((do_dont_resp[option] == 0) && my_want_state_is_do(option)) {
307
308 switch (option) {
309
310 #ifdef KLUDGELINEMODE
311 case TELOPT_SGA:
312 if (!kludgelinemode)
313 break;
314 /* FALL THROUGH */
315 #endif
316 case TELOPT_ECHO:
317 settimer(modenegotiated);
318 break;
319
320 case TELOPT_TM:
321 if (flushout)
322 flushout = 0;
323 set_my_want_state_dont(option);
324 set_my_state_dont(option);
325 return; /* Never reply to TM will's/wont's */
326
327 #ifdef ENCRYPTION
328 case TELOPT_ENCRYPT:
329 encrypt_not();
330 break;
331 #endif
332 default:
333 break;
334 }
335 set_my_want_state_dont(option);
336 if (my_state_is_do(option))
337 send_dont(option, 0);
338 setconnmode(0); /* Set new tty mode */
339 } else if (option == TELOPT_TM) {
340 /*
341 * Special case for TM.
342 */
343 if (flushout)
344 flushout = 0;
345 set_my_want_state_dont(option);
346 }
347 set_my_state_dont(option);
348 }
349
350 static void
dooption(int option)351 dooption(int option)
352 {
353 int new_state_ok = 0;
354
355 if (will_wont_resp[option]) {
356 --will_wont_resp[option];
357 if (will_wont_resp[option] && my_state_is_will(option))
358 --will_wont_resp[option];
359 }
360
361 if (will_wont_resp[option] == 0) {
362 if (my_want_state_is_wont(option)) {
363
364 switch (option) {
365
366 case TELOPT_TM:
367 /*
368 * Special case for TM. We send a WILL, but pretend
369 * we sent WONT.
370 */
371 send_will(option, 0);
372 set_my_want_state_wont(TELOPT_TM);
373 set_my_state_wont(TELOPT_TM);
374 return;
375
376 case TELOPT_BINARY: /* binary mode */
377 case TELOPT_NAWS: /* window size */
378 case TELOPT_TSPEED: /* terminal speed */
379 case TELOPT_LFLOW: /* local flow control */
380 case TELOPT_TTYPE: /* terminal type option */
381 case TELOPT_SGA: /* no big deal */
382 #if defined(ENCRYPTION)
383 case TELOPT_ENCRYPT: /* encryption variable option */
384 #endif
385 new_state_ok = 1;
386 break;
387
388 case TELOPT_NEW_ENVIRON: /* New environment variable option */
389 #ifdef OLD_ENVIRON
390 if (my_state_is_will(TELOPT_OLD_ENVIRON))
391 send_wont(TELOPT_OLD_ENVIRON, 1); /* turn off the old */
392 goto env_common;
393 case TELOPT_OLD_ENVIRON: /* Old environment variable option */
394 if (my_state_is_will(TELOPT_NEW_ENVIRON))
395 break; /* Don't enable if new one is in use! */
396 env_common:
397 telopt_environ = option;
398 #endif
399 new_state_ok = 1;
400 break;
401
402 #if defined(AUTHENTICATION)
403 case TELOPT_AUTHENTICATION:
404 if (autologin)
405 new_state_ok = 1;
406 break;
407 #endif
408
409 case TELOPT_XDISPLOC: /* X Display location */
410 if (env_getvalue((unsigned char *)"DISPLAY"))
411 new_state_ok = 1;
412 break;
413
414 case TELOPT_LINEMODE:
415 #ifdef KLUDGELINEMODE
416 kludgelinemode = 0;
417 send_do(TELOPT_SGA, 1);
418 #endif
419 set_my_want_state_will(TELOPT_LINEMODE);
420 send_will(option, 0);
421 set_my_state_will(TELOPT_LINEMODE);
422 slc_init();
423 return;
424
425 case TELOPT_ECHO: /* We're never going to echo... */
426 default:
427 break;
428 }
429
430 if (new_state_ok) {
431 set_my_want_state_will(option);
432 send_will(option, 0);
433 setconnmode(0); /* Set new tty mode */
434 } else {
435 will_wont_resp[option]++;
436 send_wont(option, 0);
437 }
438 } else {
439 /*
440 * Handle options that need more things done after the
441 * other side has acknowledged the option.
442 */
443 switch (option) {
444 case TELOPT_LINEMODE:
445 #ifdef KLUDGELINEMODE
446 kludgelinemode = 0;
447 send_do(TELOPT_SGA, 1);
448 #endif
449 set_my_state_will(option);
450 slc_init();
451 send_do(TELOPT_SGA, 0);
452 return;
453 }
454 }
455 }
456 set_my_state_will(option);
457 }
458
459 static void
dontoption(int option)460 dontoption(int option)
461 {
462
463 if (will_wont_resp[option]) {
464 --will_wont_resp[option];
465 if (will_wont_resp[option] && my_state_is_wont(option))
466 --will_wont_resp[option];
467 }
468
469 if ((will_wont_resp[option] == 0) && my_want_state_is_will(option)) {
470 switch (option) {
471 case TELOPT_LINEMODE:
472 linemode = 0; /* put us back to the default state */
473 break;
474 #ifdef OLD_ENVIRON
475 case TELOPT_NEW_ENVIRON:
476 /*
477 * The new environ option wasn't recognized, try
478 * the old one.
479 */
480 send_will(TELOPT_OLD_ENVIRON, 1);
481 telopt_environ = TELOPT_OLD_ENVIRON;
482 break;
483 #endif
484 #if 0
485 #ifdef ENCRYPTION
486 case TELOPT_ENCRYPT:
487 encrypt_not();
488 break;
489 #endif
490 #endif
491 }
492 /* we always accept a DONT */
493 set_my_want_state_wont(option);
494 if (my_state_is_will(option))
495 send_wont(option, 0);
496 setconnmode(0); /* Set new tty mode */
497 }
498 set_my_state_wont(option);
499 }
500
501 /*
502 * Given a buffer returned by tgetent(), this routine will turn
503 * the pipe separated list of names in the buffer into an array
504 * of pointers to null terminated names. We toss out any bad,
505 * duplicate, or verbose names (names with spaces).
506 */
507
508 static char *name_unknown = "UNKNOWN";
509 static char *unknown[] = { 0, 0 };
510
511 static char **
mklist(char * buf,char * name)512 mklist(char *buf, char *name)
513 {
514 int n;
515 char c, *cp, **argvp, *cp2, **argv, **avt;
516
517 if (name) {
518 if ((int)strlen(name) > 40) {
519 name = 0;
520 unknown[0] = name_unknown;
521 } else {
522 unknown[0] = name;
523 strupr(name);
524 }
525 } else
526 unknown[0] = name_unknown;
527 /*
528 * Count up the number of names.
529 */
530 for (n = 1, cp = buf; *cp && *cp != ':'; cp++) {
531 if (*cp == '|')
532 n++;
533 }
534 /*
535 * Allocate an array to put the name pointers into
536 */
537 argv = (char **)malloc((n+3)*sizeof(char *));
538 if (argv == 0)
539 return(unknown);
540
541 /*
542 * Fill up the array of pointers to names.
543 */
544 *argv = 0;
545 argvp = argv+1;
546 n = 0;
547 for (cp = cp2 = buf; (c = *cp); cp++) {
548 if (c == '|' || c == ':') {
549 *cp++ = '\0';
550 /*
551 * Skip entries that have spaces or are over 40
552 * characters long. If this is our environment
553 * name, then put it up front. Otherwise, as
554 * long as this is not a duplicate name (case
555 * insensitive) add it to the list.
556 */
557 if (n || (cp - cp2 > 41))
558 ;
559 else if (name && (strncasecmp(name, cp2, cp-cp2) == 0))
560 *argv = cp2;
561 else if (is_unique(cp2, argv+1, argvp))
562 *argvp++ = cp2;
563 if (c == ':')
564 break;
565 /*
566 * Skip multiple delimiters. Reset cp2 to
567 * the beginning of the next name. Reset n,
568 * the flag for names with spaces.
569 */
570 while ((c = *cp) == '|')
571 cp++;
572 cp2 = cp;
573 n = 0;
574 }
575 /*
576 * Skip entries with spaces or non-ascii values.
577 * Convert lower case letters to upper case.
578 */
579 #undef ISASCII
580 #define ISASCII(c) (!((c)&0x80))
581 if ((c == ' ') || !ISASCII(c))
582 n = 1;
583 else if (islower((unsigned char)c))
584 *cp = toupper((unsigned char)c);
585 }
586
587 /*
588 * Check for an old V6 2 character name. If the second
589 * name points to the beginning of the buffer, and is
590 * only 2 characters long, move it to the end of the array.
591 */
592 if ((argv[1] == buf) && (strlen(argv[1]) == 2)) {
593 --argvp;
594 for (avt = &argv[1]; avt < argvp; avt++)
595 *avt = *(avt+1);
596 *argvp++ = buf;
597 }
598
599 /*
600 * Duplicate last name, for TTYPE option, and null
601 * terminate the array. If we didn't find a match on
602 * our terminal name, put that name at the beginning.
603 */
604 cp = *(argvp-1);
605 *argvp++ = cp;
606 *argvp = 0;
607
608 if (*argv == 0) {
609 if (name)
610 *argv = name;
611 else {
612 --argvp;
613 for (avt = argv; avt < argvp; avt++)
614 *avt = *(avt+1);
615 }
616 }
617 if (*argv)
618 return(argv);
619 else
620 return(unknown);
621 }
622
623 static int
is_unique(char * name,char ** as,char ** ae)624 is_unique(char *name, char **as, char **ae)
625 {
626 char **ap;
627 int n;
628
629 n = strlen(name) + 1;
630 for (ap = as; ap < ae; ap++)
631 if (strncasecmp(*ap, name, n) == 0)
632 return(0);
633 return (1);
634 }
635
636 static char termbuf[1024];
637
638 static int
telnet_setupterm(const char * tname,int fd,int * errp)639 telnet_setupterm(const char *tname, int fd, int *errp)
640 {
641 #ifdef HAVE_TGETENT
642 if (tgetent(termbuf, tname) == 1) {
643 termbuf[1023] = '\0';
644 if (errp)
645 *errp = 1;
646 return(0);
647 }
648 if (errp)
649 *errp = 0;
650 return(-1);
651 #else
652 strlcpy(termbuf, tname, sizeof(termbuf));
653 if(errp) *errp = 1;
654 return 0;
655 #endif
656 }
657
658 int resettermname = 1;
659
660 static char *
gettermname()661 gettermname()
662 {
663 char *tname;
664 static char **tnamep = 0;
665 static char **next;
666 int err;
667
668 if (resettermname) {
669 resettermname = 0;
670 if (tnamep && tnamep != unknown)
671 free(tnamep);
672 if ((tname = (char *)env_getvalue((unsigned char *)"TERM")) &&
673 telnet_setupterm(tname, 1, &err) == 0) {
674 tnamep = mklist(termbuf, tname);
675 } else {
676 if (tname && ((int)strlen(tname) <= 40)) {
677 unknown[0] = tname;
678 strupr(tname);
679 } else
680 unknown[0] = name_unknown;
681 tnamep = unknown;
682 }
683 next = tnamep;
684 }
685 if (*next == 0)
686 next = tnamep;
687 return(*next++);
688 }
689 /*
690 * suboption()
691 *
692 * Look at the sub-option buffer, and try to be helpful to the other
693 * side.
694 *
695 * Currently we recognize:
696 *
697 * Terminal type, send request.
698 * Terminal speed (send request).
699 * Local flow control (is request).
700 * Linemode
701 */
702
703 static void
suboption()704 suboption()
705 {
706 unsigned char subchar;
707
708 printsub('<', subbuffer, SB_LEN()+2);
709 switch (subchar = SB_GET()) {
710 case TELOPT_TTYPE:
711 if (my_want_state_is_wont(TELOPT_TTYPE))
712 return;
713 if (SB_EOF() || SB_GET() != TELQUAL_SEND) {
714 return;
715 } else {
716 char *name;
717 unsigned char temp[50];
718 int len;
719
720 name = gettermname();
721 len = strlen(name) + 4 + 2;
722 if (len < NETROOM()) {
723 snprintf((char *)temp, sizeof(temp),
724 "%c%c%c%c%s%c%c", IAC, SB, TELOPT_TTYPE,
725 TELQUAL_IS, name, IAC, SE);
726 ring_supply_data(&netoring, temp, len);
727 printsub('>', &temp[2], len-2);
728 } else {
729 ExitString("No room in buffer for terminal type.\n", 1);
730 /*NOTREACHED*/
731 }
732 }
733 break;
734 case TELOPT_TSPEED:
735 if (my_want_state_is_wont(TELOPT_TSPEED))
736 return;
737 if (SB_EOF())
738 return;
739 if (SB_GET() == TELQUAL_SEND) {
740 long output_speed, input_speed;
741 unsigned char temp[50];
742 int len;
743
744 TerminalSpeeds(&input_speed, &output_speed);
745
746 snprintf((char *)temp, sizeof(temp),
747 "%c%c%c%c%u,%u%c%c", IAC, SB, TELOPT_TSPEED,
748 TELQUAL_IS,
749 (unsigned)output_speed,
750 (unsigned)input_speed, IAC, SE);
751 len = strlen((char *)temp+4) + 4; /* temp[3] is 0 ... */
752
753 if (len < NETROOM()) {
754 ring_supply_data(&netoring, temp, len);
755 printsub('>', temp+2, len - 2);
756 }
757 /*@*/ else printf("lm_will: not enough room in buffer\n");
758 }
759 break;
760 case TELOPT_LFLOW:
761 if (my_want_state_is_wont(TELOPT_LFLOW))
762 return;
763 if (SB_EOF())
764 return;
765 switch(SB_GET()) {
766 case LFLOW_RESTART_ANY:
767 restartany = 1;
768 break;
769 case LFLOW_RESTART_XON:
770 restartany = 0;
771 break;
772 case LFLOW_ON:
773 localflow = 1;
774 break;
775 case LFLOW_OFF:
776 localflow = 0;
777 break;
778 default:
779 return;
780 }
781 setcommandmode();
782 setconnmode(0);
783 break;
784
785 case TELOPT_LINEMODE:
786 if (my_want_state_is_wont(TELOPT_LINEMODE))
787 return;
788 if (SB_EOF())
789 return;
790 switch (SB_GET()) {
791 case WILL:
792 lm_will(subpointer, SB_LEN());
793 break;
794 case WONT:
795 lm_wont(subpointer, SB_LEN());
796 break;
797 case DO:
798 lm_do(subpointer, SB_LEN());
799 break;
800 case DONT:
801 lm_dont(subpointer, SB_LEN());
802 break;
803 case LM_SLC:
804 slc(subpointer, SB_LEN());
805 break;
806 case LM_MODE:
807 lm_mode(subpointer, SB_LEN(), 0);
808 break;
809 default:
810 break;
811 }
812 break;
813
814 #ifdef OLD_ENVIRON
815 case TELOPT_OLD_ENVIRON:
816 #endif
817 case TELOPT_NEW_ENVIRON:
818 if (SB_EOF())
819 return;
820 switch(SB_PEEK()) {
821 case TELQUAL_IS:
822 case TELQUAL_INFO:
823 if (my_want_state_is_dont(subchar))
824 return;
825 break;
826 case TELQUAL_SEND:
827 if (my_want_state_is_wont(subchar)) {
828 return;
829 }
830 break;
831 default:
832 return;
833 }
834 env_opt(subpointer, SB_LEN());
835 break;
836
837 case TELOPT_XDISPLOC:
838 if (my_want_state_is_wont(TELOPT_XDISPLOC))
839 return;
840 if (SB_EOF())
841 return;
842 if (SB_GET() == TELQUAL_SEND) {
843 unsigned char temp[50], *dp;
844 int len;
845
846 if ((dp = env_getvalue((unsigned char *)"DISPLAY")) == NULL) {
847 /*
848 * Something happened, we no longer have a DISPLAY
849 * variable. So, turn off the option.
850 */
851 send_wont(TELOPT_XDISPLOC, 1);
852 break;
853 }
854 snprintf((char *)temp, sizeof(temp),
855 "%c%c%c%c%s%c%c", IAC, SB, TELOPT_XDISPLOC,
856 TELQUAL_IS, dp, IAC, SE);
857 len = strlen((char *)temp+4) + 4; /* temp[3] is 0 ... */
858
859 if (len < NETROOM()) {
860 ring_supply_data(&netoring, temp, len);
861 printsub('>', temp+2, len - 2);
862 }
863 /*@*/ else printf("lm_will: not enough room in buffer\n");
864 }
865 break;
866
867 #if defined(AUTHENTICATION)
868 case TELOPT_AUTHENTICATION: {
869 if (!autologin)
870 break;
871 if (SB_EOF())
872 return;
873 switch(SB_GET()) {
874 case TELQUAL_IS:
875 if (my_want_state_is_dont(TELOPT_AUTHENTICATION))
876 return;
877 auth_is(subpointer, SB_LEN());
878 break;
879 case TELQUAL_SEND:
880 if (my_want_state_is_wont(TELOPT_AUTHENTICATION))
881 return;
882 auth_send(subpointer, SB_LEN());
883 break;
884 case TELQUAL_REPLY:
885 if (my_want_state_is_wont(TELOPT_AUTHENTICATION))
886 return;
887 auth_reply(subpointer, SB_LEN());
888 break;
889 case TELQUAL_NAME:
890 if (my_want_state_is_dont(TELOPT_AUTHENTICATION))
891 return;
892 auth_name(subpointer, SB_LEN());
893 break;
894 }
895 }
896 break;
897 #endif
898 #if defined(ENCRYPTION)
899 case TELOPT_ENCRYPT:
900 if (SB_EOF())
901 return;
902 switch(SB_GET()) {
903 case ENCRYPT_START:
904 if (my_want_state_is_dont(TELOPT_ENCRYPT))
905 return;
906 encrypt_start(subpointer, SB_LEN());
907 break;
908 case ENCRYPT_END:
909 if (my_want_state_is_dont(TELOPT_ENCRYPT))
910 return;
911 encrypt_end();
912 break;
913 case ENCRYPT_SUPPORT:
914 if (my_want_state_is_wont(TELOPT_ENCRYPT))
915 return;
916 encrypt_support(subpointer, SB_LEN());
917 break;
918 case ENCRYPT_REQSTART:
919 if (my_want_state_is_wont(TELOPT_ENCRYPT))
920 return;
921 encrypt_request_start(subpointer, SB_LEN());
922 break;
923 case ENCRYPT_REQEND:
924 if (my_want_state_is_wont(TELOPT_ENCRYPT))
925 return;
926 /*
927 * We can always send an REQEND so that we cannot
928 * get stuck encrypting. We should only get this
929 * if we have been able to get in the correct mode
930 * anyhow.
931 */
932 encrypt_request_end();
933 break;
934 case ENCRYPT_IS:
935 if (my_want_state_is_dont(TELOPT_ENCRYPT))
936 return;
937 encrypt_is(subpointer, SB_LEN());
938 break;
939 case ENCRYPT_REPLY:
940 if (my_want_state_is_wont(TELOPT_ENCRYPT))
941 return;
942 encrypt_reply(subpointer, SB_LEN());
943 break;
944 case ENCRYPT_ENC_KEYID:
945 if (my_want_state_is_dont(TELOPT_ENCRYPT))
946 return;
947 encrypt_enc_keyid(subpointer, SB_LEN());
948 break;
949 case ENCRYPT_DEC_KEYID:
950 if (my_want_state_is_wont(TELOPT_ENCRYPT))
951 return;
952 encrypt_dec_keyid(subpointer, SB_LEN());
953 break;
954 default:
955 break;
956 }
957 break;
958 #endif
959 default:
960 break;
961 }
962 }
963
964 static unsigned char str_lm[] = { IAC, SB, TELOPT_LINEMODE, 0, 0, IAC, SE };
965
966 void
lm_will(unsigned char * cmd,int len)967 lm_will(unsigned char *cmd, int len)
968 {
969 if (len < 1) {
970 /*@*/ printf("lm_will: no command!!!\n"); /* Should not happen... */
971 return;
972 }
973 switch(cmd[0]) {
974 case LM_FORWARDMASK: /* We shouldn't ever get this... */
975 default:
976 str_lm[3] = DONT;
977 str_lm[4] = cmd[0];
978 if (NETROOM() > sizeof(str_lm)) {
979 ring_supply_data(&netoring, str_lm, sizeof(str_lm));
980 printsub('>', &str_lm[2], sizeof(str_lm)-2);
981 }
982 /*@*/ else printf("lm_will: not enough room in buffer\n");
983 break;
984 }
985 }
986
987 void
lm_wont(unsigned char * cmd,int len)988 lm_wont(unsigned char *cmd, int len)
989 {
990 if (len < 1) {
991 /*@*/ printf("lm_wont: no command!!!\n"); /* Should not happen... */
992 return;
993 }
994 switch(cmd[0]) {
995 case LM_FORWARDMASK: /* We shouldn't ever get this... */
996 default:
997 /* We are always DONT, so don't respond */
998 return;
999 }
1000 }
1001
1002 void
lm_do(unsigned char * cmd,int len)1003 lm_do(unsigned char *cmd, int len)
1004 {
1005 if (len < 1) {
1006 /*@*/ printf("lm_do: no command!!!\n"); /* Should not happen... */
1007 return;
1008 }
1009 switch(cmd[0]) {
1010 case LM_FORWARDMASK:
1011 default:
1012 str_lm[3] = WONT;
1013 str_lm[4] = cmd[0];
1014 if (NETROOM() > sizeof(str_lm)) {
1015 ring_supply_data(&netoring, str_lm, sizeof(str_lm));
1016 printsub('>', &str_lm[2], sizeof(str_lm)-2);
1017 }
1018 /*@*/ else printf("lm_do: not enough room in buffer\n");
1019 break;
1020 }
1021 }
1022
1023 void
lm_dont(unsigned char * cmd,int len)1024 lm_dont(unsigned char *cmd, int len)
1025 {
1026 if (len < 1) {
1027 /*@*/ printf("lm_dont: no command!!!\n"); /* Should not happen... */
1028 return;
1029 }
1030 switch(cmd[0]) {
1031 case LM_FORWARDMASK:
1032 default:
1033 /* we are always WONT, so don't respond */
1034 break;
1035 }
1036 }
1037
1038 static unsigned char str_lm_mode[] = {
1039 IAC, SB, TELOPT_LINEMODE, LM_MODE, 0, IAC, SE
1040 };
1041
1042 void
lm_mode(unsigned char * cmd,int len,int init)1043 lm_mode(unsigned char *cmd, int len, int init)
1044 {
1045 if (len != 1)
1046 return;
1047 if ((linemode&MODE_MASK&~MODE_ACK) == *cmd)
1048 return;
1049 if (*cmd&MODE_ACK)
1050 return;
1051 linemode = *cmd&(MODE_MASK&~MODE_ACK);
1052 str_lm_mode[4] = linemode;
1053 if (!init)
1054 str_lm_mode[4] |= MODE_ACK;
1055 if (NETROOM() > sizeof(str_lm_mode)) {
1056 ring_supply_data(&netoring, str_lm_mode, sizeof(str_lm_mode));
1057 printsub('>', &str_lm_mode[2], sizeof(str_lm_mode)-2);
1058 }
1059 /*@*/ else printf("lm_mode: not enough room in buffer\n");
1060 setconnmode(0); /* set changed mode */
1061 }
1062
1063
1064
1065 /*
1066 * slc()
1067 * Handle special character suboption of LINEMODE.
1068 */
1069
1070 struct spc {
1071 cc_t val;
1072 cc_t *valp;
1073 char flags; /* Current flags & level */
1074 char mylevel; /* Maximum level & flags */
1075 } spc_data[NSLC+1];
1076
1077 #define SLC_IMPORT 0
1078 #define SLC_EXPORT 1
1079 #define SLC_RVALUE 2
1080 static int slc_mode = SLC_EXPORT;
1081
1082 void
slc_init()1083 slc_init()
1084 {
1085 struct spc *spcp;
1086
1087 localchars = 1;
1088 for (spcp = spc_data; spcp < &spc_data[NSLC+1]; spcp++) {
1089 spcp->val = 0;
1090 spcp->valp = 0;
1091 spcp->flags = spcp->mylevel = SLC_NOSUPPORT;
1092 }
1093
1094 #define initfunc(func, flags) { \
1095 spcp = &spc_data[func]; \
1096 if ((spcp->valp = tcval(func))) { \
1097 spcp->val = *spcp->valp; \
1098 spcp->mylevel = SLC_VARIABLE|flags; \
1099 } else { \
1100 spcp->val = 0; \
1101 spcp->mylevel = SLC_DEFAULT; \
1102 } \
1103 }
1104
1105 initfunc(SLC_SYNCH, 0);
1106 /* No BRK */
1107 initfunc(SLC_AO, 0);
1108 initfunc(SLC_AYT, 0);
1109 /* No EOR */
1110 initfunc(SLC_ABORT, SLC_FLUSHIN|SLC_FLUSHOUT);
1111 initfunc(SLC_EOF, 0);
1112 initfunc(SLC_SUSP, SLC_FLUSHIN);
1113 initfunc(SLC_EC, 0);
1114 initfunc(SLC_EL, 0);
1115 initfunc(SLC_EW, 0);
1116 initfunc(SLC_RP, 0);
1117 initfunc(SLC_LNEXT, 0);
1118 initfunc(SLC_XON, 0);
1119 initfunc(SLC_XOFF, 0);
1120 initfunc(SLC_FORW1, 0);
1121 initfunc(SLC_FORW2, 0);
1122 /* No FORW2 */
1123
1124 initfunc(SLC_IP, SLC_FLUSHIN|SLC_FLUSHOUT);
1125 #undef initfunc
1126
1127 if (slc_mode == SLC_EXPORT)
1128 slc_export();
1129 else
1130 slc_import(1);
1131
1132 }
1133
1134 void
slcstate()1135 slcstate()
1136 {
1137 printf("Special characters are %s values\n",
1138 slc_mode == SLC_IMPORT ? "remote default" :
1139 slc_mode == SLC_EXPORT ? "local" :
1140 "remote");
1141 }
1142
1143 void
slc_mode_export()1144 slc_mode_export()
1145 {
1146 slc_mode = SLC_EXPORT;
1147 if (my_state_is_will(TELOPT_LINEMODE))
1148 slc_export();
1149 }
1150
1151 void
slc_mode_import(int def)1152 slc_mode_import(int def)
1153 {
1154 slc_mode = def ? SLC_IMPORT : SLC_RVALUE;
1155 if (my_state_is_will(TELOPT_LINEMODE))
1156 slc_import(def);
1157 }
1158
1159 unsigned char slc_import_val[] = {
1160 IAC, SB, TELOPT_LINEMODE, LM_SLC, 0, SLC_VARIABLE, 0, IAC, SE
1161 };
1162 unsigned char slc_import_def[] = {
1163 IAC, SB, TELOPT_LINEMODE, LM_SLC, 0, SLC_DEFAULT, 0, IAC, SE
1164 };
1165
1166 void
slc_import(int def)1167 slc_import(int def)
1168 {
1169 if (NETROOM() > sizeof(slc_import_val)) {
1170 if (def) {
1171 ring_supply_data(&netoring, slc_import_def, sizeof(slc_import_def));
1172 printsub('>', &slc_import_def[2], sizeof(slc_import_def)-2);
1173 } else {
1174 ring_supply_data(&netoring, slc_import_val, sizeof(slc_import_val));
1175 printsub('>', &slc_import_val[2], sizeof(slc_import_val)-2);
1176 }
1177 }
1178 /*@*/ else printf("slc_import: not enough room\n");
1179 }
1180
1181 void
slc_export()1182 slc_export()
1183 {
1184 struct spc *spcp;
1185
1186 TerminalDefaultChars();
1187
1188 slc_start_reply();
1189 for (spcp = &spc_data[1]; spcp < &spc_data[NSLC+1]; spcp++) {
1190 if (spcp->mylevel != SLC_NOSUPPORT) {
1191 if (spcp->val == (cc_t)(_POSIX_VDISABLE))
1192 spcp->flags = SLC_NOSUPPORT;
1193 else
1194 spcp->flags = spcp->mylevel;
1195 if (spcp->valp)
1196 spcp->val = *spcp->valp;
1197 slc_add_reply(spcp - spc_data, spcp->flags, spcp->val);
1198 }
1199 }
1200 slc_end_reply();
1201 slc_update();
1202 setconnmode(1); /* Make sure the character values are set */
1203 }
1204
1205 void
slc(unsigned char * cp,int len)1206 slc(unsigned char *cp, int len)
1207 {
1208 struct spc *spcp;
1209 int func,level;
1210
1211 slc_start_reply();
1212
1213 for (; len >= 3; len -=3, cp +=3) {
1214
1215 func = cp[SLC_FUNC];
1216
1217 if (func == 0) {
1218 /*
1219 * Client side: always ignore 0 function.
1220 */
1221 continue;
1222 }
1223 if (func > NSLC) {
1224 if ((cp[SLC_FLAGS] & SLC_LEVELBITS) != SLC_NOSUPPORT)
1225 slc_add_reply(func, SLC_NOSUPPORT, 0);
1226 continue;
1227 }
1228
1229 spcp = &spc_data[func];
1230
1231 level = cp[SLC_FLAGS]&(SLC_LEVELBITS|SLC_ACK);
1232
1233 if ((cp[SLC_VALUE] == (unsigned char)spcp->val) &&
1234 ((level&SLC_LEVELBITS) == (spcp->flags&SLC_LEVELBITS))) {
1235 continue;
1236 }
1237
1238 if (level == (SLC_DEFAULT|SLC_ACK)) {
1239 /*
1240 * This is an error condition, the SLC_ACK
1241 * bit should never be set for the SLC_DEFAULT
1242 * level. Our best guess to recover is to
1243 * ignore the SLC_ACK bit.
1244 */
1245 cp[SLC_FLAGS] &= ~SLC_ACK;
1246 }
1247
1248 if (level == ((spcp->flags&SLC_LEVELBITS)|SLC_ACK)) {
1249 spcp->val = (cc_t)cp[SLC_VALUE];
1250 spcp->flags = cp[SLC_FLAGS]; /* include SLC_ACK */
1251 continue;
1252 }
1253
1254 level &= ~SLC_ACK;
1255
1256 if (level <= (spcp->mylevel&SLC_LEVELBITS)) {
1257 spcp->flags = cp[SLC_FLAGS]|SLC_ACK;
1258 spcp->val = (cc_t)cp[SLC_VALUE];
1259 }
1260 if (level == SLC_DEFAULT) {
1261 if ((spcp->mylevel&SLC_LEVELBITS) != SLC_DEFAULT)
1262 spcp->flags = spcp->mylevel;
1263 else
1264 spcp->flags = SLC_NOSUPPORT;
1265 }
1266 slc_add_reply(func, spcp->flags, spcp->val);
1267 }
1268 slc_end_reply();
1269 if (slc_update())
1270 setconnmode(1); /* set the new character values */
1271 }
1272
1273 void
slc_check()1274 slc_check()
1275 {
1276 struct spc *spcp;
1277
1278 slc_start_reply();
1279 for (spcp = &spc_data[1]; spcp < &spc_data[NSLC+1]; spcp++) {
1280 if (spcp->valp && spcp->val != *spcp->valp) {
1281 spcp->val = *spcp->valp;
1282 if (spcp->val == (cc_t)(_POSIX_VDISABLE))
1283 spcp->flags = SLC_NOSUPPORT;
1284 else
1285 spcp->flags = spcp->mylevel;
1286 slc_add_reply(spcp - spc_data, spcp->flags, spcp->val);
1287 }
1288 }
1289 slc_end_reply();
1290 setconnmode(1);
1291 }
1292
1293
1294 unsigned char slc_reply[128];
1295 unsigned char const * const slc_reply_eom = &slc_reply[sizeof(slc_reply)];
1296 unsigned char *slc_replyp;
1297
1298 void
slc_start_reply()1299 slc_start_reply()
1300 {
1301 slc_replyp = slc_reply;
1302 *slc_replyp++ = IAC;
1303 *slc_replyp++ = SB;
1304 *slc_replyp++ = TELOPT_LINEMODE;
1305 *slc_replyp++ = LM_SLC;
1306 }
1307
1308 void
slc_add_reply(unsigned char func,unsigned char flags,cc_t value)1309 slc_add_reply(unsigned char func, unsigned char flags, cc_t value)
1310 {
1311 /* A sequence of up to 6 bytes my be written for this member of the SLC
1312 * suboption list by this function. The end of negotiation command,
1313 * which is written by slc_end_reply(), will require 2 additional
1314 * bytes. Do not proceed unless there is sufficient space for these
1315 * items.
1316 */
1317 if (&slc_replyp[6+2] > slc_reply_eom)
1318 return;
1319 if ((*slc_replyp++ = func) == IAC)
1320 *slc_replyp++ = IAC;
1321 if ((*slc_replyp++ = flags) == IAC)
1322 *slc_replyp++ = IAC;
1323 if ((*slc_replyp++ = (unsigned char)value) == IAC)
1324 *slc_replyp++ = IAC;
1325 }
1326
1327 void
slc_end_reply()1328 slc_end_reply()
1329 {
1330 int len;
1331
1332 /* The end of negotiation command requires 2 bytes. */
1333 if (&slc_replyp[2] > slc_reply_eom)
1334 return;
1335 *slc_replyp++ = IAC;
1336 *slc_replyp++ = SE;
1337 len = slc_replyp - slc_reply;
1338 if (len <= 6)
1339 return;
1340 if (NETROOM() > len) {
1341 ring_supply_data(&netoring, slc_reply, slc_replyp - slc_reply);
1342 printsub('>', &slc_reply[2], slc_replyp - slc_reply - 2);
1343 }
1344 /*@*/else printf("slc_end_reply: not enough room\n");
1345 }
1346
1347 int
slc_update()1348 slc_update()
1349 {
1350 struct spc *spcp;
1351 int need_update = 0;
1352
1353 for (spcp = &spc_data[1]; spcp < &spc_data[NSLC+1]; spcp++) {
1354 if (!(spcp->flags&SLC_ACK))
1355 continue;
1356 spcp->flags &= ~SLC_ACK;
1357 if (spcp->valp && (*spcp->valp != spcp->val)) {
1358 *spcp->valp = spcp->val;
1359 need_update = 1;
1360 }
1361 }
1362 return(need_update);
1363 }
1364
1365 #ifdef OLD_ENVIRON
1366 # define old_env_var OLD_ENV_VAR
1367 # define old_env_value OLD_ENV_VALUE
1368 #endif
1369
1370 void
env_opt(unsigned char * buf,int len)1371 env_opt(unsigned char *buf, int len)
1372 {
1373 unsigned char *ep = 0, *epc = 0;
1374 int i;
1375
1376 switch(buf[0]&0xff) {
1377 case TELQUAL_SEND:
1378 env_opt_start();
1379 if (len == 1) {
1380 env_opt_add(NULL);
1381 } else for (i = 1; i < len; i++) {
1382 switch (buf[i]&0xff) {
1383 #ifdef OLD_ENVIRON
1384 case OLD_ENV_VAR:
1385 case OLD_ENV_VALUE:
1386 /*
1387 * Although OLD_ENV_VALUE is not legal, we will
1388 * still recognize it, just in case it is an
1389 * old server that has VAR & VALUE mixed up...
1390 */
1391 /* FALL THROUGH */
1392 #else
1393 case NEW_ENV_VAR:
1394 #endif
1395 case ENV_USERVAR:
1396 if (ep) {
1397 *epc = 0;
1398 env_opt_add(ep);
1399 }
1400 ep = epc = &buf[i+1];
1401 break;
1402 case ENV_ESC:
1403 i++;
1404 /*FALL THROUGH*/
1405 default:
1406 if (epc)
1407 *epc++ = buf[i];
1408 break;
1409 }
1410 }
1411 if (ep) {
1412 *epc = 0;
1413 env_opt_add(ep);
1414 }
1415 env_opt_end(1);
1416 break;
1417
1418 case TELQUAL_IS:
1419 case TELQUAL_INFO:
1420 /* Ignore for now. We shouldn't get it anyway. */
1421 break;
1422
1423 default:
1424 break;
1425 }
1426 }
1427
1428 #define OPT_REPLY_SIZE (2 * SUBBUFSIZE)
1429 unsigned char *opt_reply;
1430 unsigned char *opt_replyp;
1431 unsigned char *opt_replyend;
1432
1433 void
env_opt_start()1434 env_opt_start()
1435 {
1436 if (opt_reply) {
1437 void *tmp = realloc (opt_reply, OPT_REPLY_SIZE);
1438 if (tmp != NULL) {
1439 opt_reply = tmp;
1440 } else {
1441 free (opt_reply);
1442 opt_reply = NULL;
1443 }
1444 } else
1445 opt_reply = (unsigned char *)malloc(OPT_REPLY_SIZE);
1446 if (opt_reply == NULL) {
1447 /*@*/ printf("env_opt_start: malloc()/realloc() failed!!!\n");
1448 opt_reply = opt_replyp = opt_replyend = NULL;
1449 return;
1450 }
1451 opt_replyp = opt_reply;
1452 opt_replyend = opt_reply + OPT_REPLY_SIZE;
1453 *opt_replyp++ = IAC;
1454 *opt_replyp++ = SB;
1455 *opt_replyp++ = telopt_environ;
1456 *opt_replyp++ = TELQUAL_IS;
1457 }
1458
1459 void
env_opt_start_info()1460 env_opt_start_info()
1461 {
1462 env_opt_start();
1463 if (opt_replyp)
1464 opt_replyp[-1] = TELQUAL_INFO;
1465 }
1466
1467 void
env_opt_add(unsigned char * ep)1468 env_opt_add(unsigned char *ep)
1469 {
1470 unsigned char *vp, c;
1471
1472 if (opt_reply == NULL) /*XXX*/
1473 return; /*XXX*/
1474
1475 if (ep == NULL || *ep == '\0') {
1476 /* Send user defined variables first. */
1477 env_default(1, 0);
1478 while ((ep = env_default(0, 0)))
1479 env_opt_add(ep);
1480
1481 /* Now add the list of well know variables. */
1482 env_default(1, 1);
1483 while ((ep = env_default(0, 1)))
1484 env_opt_add(ep);
1485 return;
1486 }
1487 vp = env_getvalue(ep);
1488 if (opt_replyp + (vp ? 2 * strlen((char *)vp) : 0) +
1489 2 * strlen((char *)ep) + 6 > opt_replyend)
1490 {
1491 int len;
1492 void *tmp;
1493 opt_replyend += OPT_REPLY_SIZE;
1494 len = opt_replyend - opt_reply;
1495 tmp = realloc(opt_reply, len);
1496 if (tmp == NULL) {
1497 /*@*/ printf("env_opt_add: realloc() failed!!!\n");
1498 opt_reply = opt_replyp = opt_replyend = NULL;
1499 return;
1500 }
1501 opt_reply = tmp;
1502 opt_replyp = opt_reply + len - (opt_replyend - opt_replyp);
1503 opt_replyend = opt_reply + len;
1504 }
1505 if (opt_welldefined((char *)ep)) {
1506 #ifdef OLD_ENVIRON
1507 if (telopt_environ == TELOPT_OLD_ENVIRON)
1508 *opt_replyp++ = old_env_var;
1509 else
1510 #endif
1511 *opt_replyp++ = NEW_ENV_VAR;
1512 } else
1513 *opt_replyp++ = ENV_USERVAR;
1514 for (;;) {
1515 while ((c = *ep++)) {
1516 if (opt_replyp + (2 + 2) > opt_replyend)
1517 return;
1518 switch(c&0xff) {
1519 case IAC:
1520 *opt_replyp++ = IAC;
1521 break;
1522 case NEW_ENV_VAR:
1523 case NEW_ENV_VALUE:
1524 case ENV_ESC:
1525 case ENV_USERVAR:
1526 *opt_replyp++ = ENV_ESC;
1527 break;
1528 }
1529 *opt_replyp++ = c;
1530 }
1531 if ((ep = vp)) {
1532 if (opt_replyp + (1 + 2 + 2) > opt_replyend)
1533 return;
1534 #ifdef OLD_ENVIRON
1535 if (telopt_environ == TELOPT_OLD_ENVIRON)
1536 *opt_replyp++ = old_env_value;
1537 else
1538 #endif
1539 *opt_replyp++ = NEW_ENV_VALUE;
1540 vp = NULL;
1541 } else
1542 break;
1543 }
1544 }
1545
1546 int
opt_welldefined(char * ep)1547 opt_welldefined(char *ep)
1548 {
1549 if ((strcmp(ep, "USER") == 0) ||
1550 (strcmp(ep, "DISPLAY") == 0) ||
1551 (strcmp(ep, "PRINTER") == 0) ||
1552 (strcmp(ep, "SYSTEMTYPE") == 0) ||
1553 (strcmp(ep, "JOB") == 0) ||
1554 (strcmp(ep, "ACCT") == 0))
1555 return(1);
1556 return(0);
1557 }
1558
1559 void
env_opt_end(int emptyok)1560 env_opt_end(int emptyok)
1561 {
1562 int len;
1563
1564 if (opt_replyp + 2 > opt_replyend)
1565 return;
1566 len = opt_replyp + 2 - opt_reply;
1567 if (emptyok || len > 6) {
1568 *opt_replyp++ = IAC;
1569 *opt_replyp++ = SE;
1570 if (NETROOM() > len) {
1571 ring_supply_data(&netoring, opt_reply, len);
1572 printsub('>', &opt_reply[2], len - 2);
1573 }
1574 /*@*/ else printf("slc_end_reply: not enough room\n");
1575 }
1576 if (opt_reply) {
1577 free(opt_reply);
1578 opt_reply = opt_replyp = opt_replyend = NULL;
1579 }
1580 }
1581
1582
1583
1584 int
telrcv(void)1585 telrcv(void)
1586 {
1587 int c;
1588 int scc;
1589 unsigned char *sbp = NULL;
1590 int count;
1591 int returnValue = 0;
1592
1593 scc = 0;
1594 count = 0;
1595 while (TTYROOM() > 2) {
1596 if (scc == 0) {
1597 if (count) {
1598 ring_consumed(&netiring, count);
1599 returnValue = 1;
1600 count = 0;
1601 }
1602 sbp = netiring.consume;
1603 scc = ring_full_consecutive(&netiring);
1604 if (scc == 0) {
1605 /* No more data coming in */
1606 break;
1607 }
1608 }
1609
1610 c = *sbp++ & 0xff, scc--; count++;
1611 #if defined(ENCRYPTION)
1612 if (decrypt_input)
1613 c = (*decrypt_input)(c);
1614 #endif
1615
1616 switch (telrcv_state) {
1617
1618 case TS_CR:
1619 telrcv_state = TS_DATA;
1620 if (c == '\0') {
1621 break; /* Ignore \0 after CR */
1622 }
1623 else if ((c == '\n') && my_want_state_is_dont(TELOPT_ECHO) && !crmod) {
1624 TTYADD(c);
1625 break;
1626 }
1627 /* Else, fall through */
1628
1629 case TS_DATA:
1630 if (c == IAC) {
1631 telrcv_state = TS_IAC;
1632 break;
1633 }
1634 /*
1635 * The 'crmod' hack (see following) is needed
1636 * since we can't set CRMOD on output only.
1637 * Machines like MULTICS like to send \r without
1638 * \n; since we must turn off CRMOD to get proper
1639 * input, the mapping is done here (sigh).
1640 */
1641 if ((c == '\r') && my_want_state_is_dont(TELOPT_BINARY)) {
1642 if (scc > 0) {
1643 c = *sbp&0xff;
1644 #if defined(ENCRYPTION)
1645 if (decrypt_input)
1646 c = (*decrypt_input)(c);
1647 #endif
1648 if (c == 0) {
1649 sbp++, scc--; count++;
1650 /* a "true" CR */
1651 TTYADD('\r');
1652 } else if (my_want_state_is_dont(TELOPT_ECHO) &&
1653 (c == '\n')) {
1654 sbp++, scc--; count++;
1655 TTYADD('\n');
1656 } else {
1657 #if defined(ENCRYPTION)
1658 if (decrypt_input)
1659 (*decrypt_input)(-1);
1660 #endif
1661
1662 TTYADD('\r');
1663 if (crmod) {
1664 TTYADD('\n');
1665 }
1666 }
1667 } else {
1668 telrcv_state = TS_CR;
1669 TTYADD('\r');
1670 if (crmod) {
1671 TTYADD('\n');
1672 }
1673 }
1674 } else {
1675 TTYADD(c);
1676 }
1677 continue;
1678
1679 case TS_IAC:
1680 process_iac:
1681 switch (c) {
1682
1683 case WILL:
1684 telrcv_state = TS_WILL;
1685 continue;
1686
1687 case WONT:
1688 telrcv_state = TS_WONT;
1689 continue;
1690
1691 case DO:
1692 telrcv_state = TS_DO;
1693 continue;
1694
1695 case DONT:
1696 telrcv_state = TS_DONT;
1697 continue;
1698
1699 case DM:
1700 /*
1701 * We may have missed an urgent notification,
1702 * so make sure we flush whatever is in the
1703 * buffer currently.
1704 */
1705 printoption("RCVD", IAC, DM);
1706 SYNCHing = 1;
1707 ttyflush(1);
1708 SYNCHing = stilloob();
1709 settimer(gotDM);
1710 break;
1711
1712 case SB:
1713 SB_CLEAR();
1714 telrcv_state = TS_SB;
1715 continue;
1716
1717
1718 case IAC:
1719 TTYADD(IAC);
1720 break;
1721
1722 case NOP:
1723 case GA:
1724 default:
1725 printoption("RCVD", IAC, c);
1726 break;
1727 }
1728 telrcv_state = TS_DATA;
1729 continue;
1730
1731 case TS_WILL:
1732 printoption("RCVD", WILL, c);
1733 willoption(c);
1734 telrcv_state = TS_DATA;
1735 continue;
1736
1737 case TS_WONT:
1738 printoption("RCVD", WONT, c);
1739 wontoption(c);
1740 telrcv_state = TS_DATA;
1741 continue;
1742
1743 case TS_DO:
1744 printoption("RCVD", DO, c);
1745 dooption(c);
1746 if (c == TELOPT_NAWS) {
1747 sendnaws();
1748 } else if (c == TELOPT_LFLOW) {
1749 localflow = 1;
1750 setcommandmode();
1751 setconnmode(0);
1752 }
1753 telrcv_state = TS_DATA;
1754 continue;
1755
1756 case TS_DONT:
1757 printoption("RCVD", DONT, c);
1758 dontoption(c);
1759 flushline = 1;
1760 setconnmode(0); /* set new tty mode (maybe) */
1761 telrcv_state = TS_DATA;
1762 continue;
1763
1764 case TS_SB:
1765 if (c == IAC) {
1766 telrcv_state = TS_SE;
1767 } else {
1768 SB_ACCUM(c);
1769 }
1770 continue;
1771
1772 case TS_SE:
1773 if (c != SE) {
1774 if (c != IAC) {
1775 /*
1776 * This is an error. We only expect to get
1777 * "IAC IAC" or "IAC SE". Several things may
1778 * have happened. An IAC was not doubled, the
1779 * IAC SE was left off, or another option got
1780 * inserted into the suboption are all possibilities.
1781 * If we assume that the IAC was not doubled,
1782 * and really the IAC SE was left off, we could
1783 * get into an infinite loop here. So, instead,
1784 * we terminate the suboption, and process the
1785 * partial suboption if we can.
1786 */
1787 SB_ACCUM(IAC);
1788 SB_ACCUM(c);
1789 subpointer -= 2;
1790 SB_TERM();
1791
1792 printoption("In SUBOPTION processing, RCVD", IAC, c);
1793 suboption(); /* handle sub-option */
1794 telrcv_state = TS_IAC;
1795 goto process_iac;
1796 }
1797 SB_ACCUM(c);
1798 telrcv_state = TS_SB;
1799 } else {
1800 SB_ACCUM(IAC);
1801 SB_ACCUM(SE);
1802 subpointer -= 2;
1803 SB_TERM();
1804 suboption(); /* handle sub-option */
1805 telrcv_state = TS_DATA;
1806 }
1807 }
1808 }
1809 if (count)
1810 ring_consumed(&netiring, count);
1811 return returnValue||count;
1812 }
1813
1814 static int bol = 1, local = 0;
1815
1816 int
rlogin_susp(void)1817 rlogin_susp(void)
1818 {
1819 if (local) {
1820 local = 0;
1821 bol = 1;
1822 command(0, "z\n", 2);
1823 return(1);
1824 }
1825 return(0);
1826 }
1827
1828 static int
telsnd()1829 telsnd()
1830 {
1831 int tcc;
1832 int count;
1833 int returnValue = 0;
1834 unsigned char *tbp = NULL;
1835
1836 tcc = 0;
1837 count = 0;
1838 while (NETROOM() > 2) {
1839 int sc;
1840 int c;
1841
1842 if (tcc == 0) {
1843 if (count) {
1844 ring_consumed(&ttyiring, count);
1845 returnValue = 1;
1846 count = 0;
1847 }
1848 tbp = ttyiring.consume;
1849 tcc = ring_full_consecutive(&ttyiring);
1850 if (tcc == 0) {
1851 break;
1852 }
1853 }
1854 c = *tbp++ & 0xff, sc = strip(c), tcc--; count++;
1855 if (rlogin != _POSIX_VDISABLE) {
1856 if (bol) {
1857 bol = 0;
1858 if (sc == rlogin) {
1859 local = 1;
1860 continue;
1861 }
1862 } else if (local) {
1863 local = 0;
1864 if (sc == '.' || c == termEofChar) {
1865 bol = 1;
1866 command(0, "close\n", 6);
1867 continue;
1868 }
1869 if (sc == termSuspChar) {
1870 bol = 1;
1871 command(0, "z\n", 2);
1872 continue;
1873 }
1874 if (sc == escape) {
1875 command(0, (char *)tbp, tcc);
1876 bol = 1;
1877 count += tcc;
1878 tcc = 0;
1879 flushline = 1;
1880 break;
1881 }
1882 if (sc != rlogin) {
1883 ++tcc;
1884 --tbp;
1885 --count;
1886 c = sc = rlogin;
1887 }
1888 }
1889 if ((sc == '\n') || (sc == '\r'))
1890 bol = 1;
1891 } else if (sc == escape) {
1892 /*
1893 * Double escape is a pass through of a single escape character.
1894 */
1895 if (tcc && strip(*tbp) == escape) {
1896 tbp++;
1897 tcc--;
1898 count++;
1899 bol = 0;
1900 } else {
1901 command(0, (char *)tbp, tcc);
1902 bol = 1;
1903 count += tcc;
1904 tcc = 0;
1905 flushline = 1;
1906 break;
1907 }
1908 } else
1909 bol = 0;
1910 #ifdef KLUDGELINEMODE
1911 if (kludgelinemode && (globalmode&MODE_EDIT) && (sc == echoc)) {
1912 if (tcc > 0 && strip(*tbp) == echoc) {
1913 tcc--; tbp++; count++;
1914 } else {
1915 dontlecho = !dontlecho;
1916 settimer(echotoggle);
1917 setconnmode(0);
1918 flushline = 1;
1919 break;
1920 }
1921 }
1922 #endif
1923 if (MODE_LOCAL_CHARS(globalmode)) {
1924 if (TerminalSpecialChars(sc) == 0) {
1925 bol = 1;
1926 break;
1927 }
1928 }
1929 if (my_want_state_is_wont(TELOPT_BINARY)) {
1930 switch (c) {
1931 case '\n':
1932 /*
1933 * If we are in CRMOD mode (\r ==> \n)
1934 * on our local machine, then probably
1935 * a newline (unix) is CRLF (TELNET).
1936 */
1937 if (MODE_LOCAL_CHARS(globalmode)) {
1938 NETADD('\r');
1939 }
1940 NETADD('\n');
1941 bol = flushline = 1;
1942 break;
1943 case '\r':
1944 if (!crlf) {
1945 NET2ADD('\r', '\0');
1946 } else {
1947 NET2ADD('\r', '\n');
1948 }
1949 bol = flushline = 1;
1950 break;
1951 case IAC:
1952 NET2ADD(IAC, IAC);
1953 break;
1954 default:
1955 NETADD(c);
1956 break;
1957 }
1958 } else if (c == IAC) {
1959 NET2ADD(IAC, IAC);
1960 } else {
1961 NETADD(c);
1962 }
1963 }
1964 if (count)
1965 ring_consumed(&ttyiring, count);
1966 return returnValue||count; /* Non-zero if we did anything */
1967 }
1968
1969 /*
1970 * Scheduler()
1971 *
1972 * Try to do something.
1973 *
1974 * If we do something useful, return 1; else return 0.
1975 *
1976 */
1977
1978
1979 int
Scheduler(int block)1980 Scheduler(int block) /* should we block in the select ? */
1981 {
1982 /* One wants to be a bit careful about setting returnValue
1983 * to one, since a one implies we did some useful work,
1984 * and therefore probably won't be called to block next
1985 * time (TN3270 mode only).
1986 */
1987 int returnValue;
1988 int netin, netout, netex, ttyin, ttyout;
1989
1990 /* Decide which rings should be processed */
1991
1992 netout = ring_full_count(&netoring) &&
1993 (flushline ||
1994 (my_want_state_is_wont(TELOPT_LINEMODE)
1995 #ifdef KLUDGELINEMODE
1996 && (!kludgelinemode || my_want_state_is_do(TELOPT_SGA))
1997 #endif
1998 ) ||
1999 my_want_state_is_will(TELOPT_BINARY));
2000 ttyout = ring_full_count(&ttyoring);
2001
2002 ttyin = ring_empty_count(&ttyiring);
2003
2004 netin = !ISend && ring_empty_count(&netiring);
2005
2006 netex = !SYNCHing;
2007
2008 /* If we have seen a signal recently, reset things */
2009
2010 if (scheduler_lockout_tty) {
2011 ttyin = ttyout = 0;
2012 }
2013
2014 /* Call to system code to process rings */
2015
2016 returnValue = process_rings(netin, netout, netex, ttyin, ttyout, !block);
2017
2018 /* Now, look at the input rings, looking for work to do. */
2019
2020 if (ring_full_count(&ttyiring)) {
2021 returnValue |= telsnd();
2022 }
2023
2024 if (ring_full_count(&netiring)) {
2025 returnValue |= telrcv();
2026 }
2027 return returnValue;
2028 }
2029
2030 extern int auth_has_failed; /* XXX should be somewhere else */
2031
2032 /*
2033 * Select from tty and network...
2034 */
2035 void
my_telnet(char * user)2036 my_telnet(char *user)
2037 {
2038 int printed_encrypt = 0;
2039
2040 sys_telnet_init();
2041
2042 #if defined(AUTHENTICATION) || defined(ENCRYPTION)
2043 {
2044 static char local_host[256] = { 0 };
2045
2046 if (!local_host[0]) {
2047 /* XXX - should be k_gethostname? */
2048 gethostname(local_host, sizeof(local_host));
2049 local_host[sizeof(local_host)-1] = 0;
2050 }
2051 auth_encrypt_init(local_host, hostname, "TELNET", 0);
2052 auth_encrypt_user(user);
2053 }
2054 #endif
2055 if (telnetport) {
2056 #if defined(AUTHENTICATION)
2057 if (autologin)
2058 send_will(TELOPT_AUTHENTICATION, 1);
2059 #endif
2060 #if defined(ENCRYPTION)
2061 send_do(TELOPT_ENCRYPT, 1);
2062 send_will(TELOPT_ENCRYPT, 1);
2063 #endif
2064 send_do(TELOPT_SGA, 1);
2065 send_will(TELOPT_TTYPE, 1);
2066 send_will(TELOPT_NAWS, 1);
2067 send_will(TELOPT_TSPEED, 1);
2068 send_will(TELOPT_LFLOW, 1);
2069 send_will(TELOPT_LINEMODE, 1);
2070 send_will(TELOPT_NEW_ENVIRON, 1);
2071 send_do(TELOPT_STATUS, 1);
2072 if (env_getvalue((unsigned char *)"DISPLAY"))
2073 send_will(TELOPT_XDISPLOC, 1);
2074 if (binary)
2075 tel_enter_binary(binary);
2076 }
2077
2078 #ifdef ENCRYPTION
2079 /*
2080 * Note: we assume a tie to the authentication option here. This
2081 * is necessary so that authentication fails, we don't spin
2082 * forever.
2083 */
2084 if (telnetport && wantencryption) {
2085 time_t timeout = time(0) + 60;
2086
2087 send_do(TELOPT_ENCRYPT, 1);
2088 send_will(TELOPT_ENCRYPT, 1);
2089 while (1) {
2090 if (my_want_state_is_wont(TELOPT_AUTHENTICATION)) {
2091 if (wantencryption == -1) {
2092 break;
2093 } else {
2094 printf("\nServer refused to negotiate authentication,\n");
2095 printf("which is required for encryption.\n");
2096 Exit(1);
2097 }
2098 }
2099 if (auth_has_failed) {
2100 printf("\nAuthentication negotiation has failed,\n");
2101 printf("which is required for encryption.\n");
2102 Exit(1);
2103 }
2104 if (my_want_state_is_dont(TELOPT_ENCRYPT) ||
2105 my_want_state_is_wont(TELOPT_ENCRYPT)) {
2106 printf("\nServer refused to negotiate encryption.\n");
2107 Exit(1);
2108 }
2109 if (encrypt_is_encrypting())
2110 break;
2111 if (time(0) > timeout) {
2112 printf("\nEncryption could not be enabled.\n");
2113 Exit(1);
2114 }
2115 if (printed_encrypt == 0) {
2116 printed_encrypt = 1;
2117 printf("Waiting for encryption to be negotiated...\n");
2118 /*
2119 * Turn on MODE_TRAPSIG and then turn off localchars
2120 * so that ^C will cause telnet to exit.
2121 */
2122 TerminalNewMode(getconnmode()|MODE_TRAPSIG);
2123 intr_waiting = 1;
2124 }
2125 if (intr_happened) {
2126 printf("\nUser interrupt.\n");
2127 Exit(1);
2128 }
2129 if (telnet_spin()) {
2130 printf("\nServer disconnected.\n");
2131 Exit(1);
2132 }
2133
2134 }
2135 if (printed_encrypt) {
2136 printf("Encryption negotiated.\n");
2137 intr_waiting = 0;
2138 setconnmode(0);
2139 }
2140 }
2141 #endif
2142
2143 for (;;) {
2144 int schedValue;
2145
2146 while ((schedValue = Scheduler(0)) != 0) {
2147 if (schedValue == -1) {
2148 setcommandmode();
2149 return;
2150 }
2151 }
2152
2153 if (Scheduler(1) == -1) {
2154 setcommandmode();
2155 return;
2156 }
2157 }
2158 }
2159
2160 /*
2161 * netclear()
2162 *
2163 * We are about to do a TELNET SYNCH operation. Clear
2164 * the path to the network.
2165 *
2166 * Things are a bit tricky since we may have sent the first
2167 * byte or so of a previous TELNET command into the network.
2168 * So, we have to scan the network buffer from the beginning
2169 * until we are up to where we want to be.
2170 *
2171 * A side effect of what we do, just to keep things
2172 * simple, is to clear the urgent data pointer. The principal
2173 * caller should be setting the urgent data pointer AFTER calling
2174 * us in any case.
2175 */
2176
2177 static void
netclear()2178 netclear()
2179 {
2180 #if 0 /* XXX */
2181 char *thisitem, *next;
2182 char *good;
2183 #define wewant(p) ((nfrontp > p) && ((*p&0xff) == IAC) && \
2184 ((*(p+1)&0xff) != EC) && ((*(p+1)&0xff) != EL))
2185
2186 thisitem = netobuf;
2187
2188 while ((next = nextitem(thisitem)) <= netobuf.send) {
2189 thisitem = next;
2190 }
2191
2192 /* Now, thisitem is first before/at boundary. */
2193
2194 good = netobuf; /* where the good bytes go */
2195
2196 while (netoring.add > thisitem) {
2197 if (wewant(thisitem)) {
2198 int length;
2199
2200 next = thisitem;
2201 do {
2202 next = nextitem(next);
2203 } while (wewant(next) && (nfrontp > next));
2204 length = next-thisitem;
2205 memmove(good, thisitem, length);
2206 good += length;
2207 thisitem = next;
2208 } else {
2209 thisitem = nextitem(thisitem);
2210 }
2211 }
2212
2213 #endif /* 0 */
2214 }
2215
2216 /*
2217 * These routines add various telnet commands to the data stream.
2218 */
2219
2220 static void
doflush()2221 doflush()
2222 {
2223 NET2ADD(IAC, DO);
2224 NETADD(TELOPT_TM);
2225 flushline = 1;
2226 flushout = 1;
2227 ttyflush(1); /* Flush/drop output */
2228 /* do printoption AFTER flush, otherwise the output gets tossed... */
2229 printoption("SENT", DO, TELOPT_TM);
2230 }
2231
2232 void
xmitAO(void)2233 xmitAO(void)
2234 {
2235 NET2ADD(IAC, AO);
2236 printoption("SENT", IAC, AO);
2237 if (autoflush) {
2238 doflush();
2239 }
2240 }
2241
2242
2243 void
xmitEL(void)2244 xmitEL(void)
2245 {
2246 NET2ADD(IAC, EL);
2247 printoption("SENT", IAC, EL);
2248 }
2249
2250 void
xmitEC(void)2251 xmitEC(void)
2252 {
2253 NET2ADD(IAC, EC);
2254 printoption("SENT", IAC, EC);
2255 }
2256
2257
2258 int
dosynch()2259 dosynch()
2260 {
2261 netclear(); /* clear the path to the network */
2262 NETADD(IAC);
2263 setneturg();
2264 NETADD(DM);
2265 printoption("SENT", IAC, DM);
2266 return 1;
2267 }
2268
2269 int want_status_response = 0;
2270
2271 int
get_status()2272 get_status()
2273 {
2274 unsigned char tmp[16];
2275 unsigned char *cp;
2276
2277 if (my_want_state_is_dont(TELOPT_STATUS)) {
2278 printf("Remote side does not support STATUS option\n");
2279 return 0;
2280 }
2281 cp = tmp;
2282
2283 *cp++ = IAC;
2284 *cp++ = SB;
2285 *cp++ = TELOPT_STATUS;
2286 *cp++ = TELQUAL_SEND;
2287 *cp++ = IAC;
2288 *cp++ = SE;
2289 if (NETROOM() >= cp - tmp) {
2290 ring_supply_data(&netoring, tmp, cp-tmp);
2291 printsub('>', tmp+2, cp - tmp - 2);
2292 }
2293 ++want_status_response;
2294 return 1;
2295 }
2296
2297 void
intp(void)2298 intp(void)
2299 {
2300 NET2ADD(IAC, IP);
2301 printoption("SENT", IAC, IP);
2302 flushline = 1;
2303 if (autoflush) {
2304 doflush();
2305 }
2306 if (autosynch) {
2307 dosynch();
2308 }
2309 }
2310
2311 void
sendbrk(void)2312 sendbrk(void)
2313 {
2314 NET2ADD(IAC, BREAK);
2315 printoption("SENT", IAC, BREAK);
2316 flushline = 1;
2317 if (autoflush) {
2318 doflush();
2319 }
2320 if (autosynch) {
2321 dosynch();
2322 }
2323 }
2324
2325 void
sendabort(void)2326 sendabort(void)
2327 {
2328 NET2ADD(IAC, ABORT);
2329 printoption("SENT", IAC, ABORT);
2330 flushline = 1;
2331 if (autoflush) {
2332 doflush();
2333 }
2334 if (autosynch) {
2335 dosynch();
2336 }
2337 }
2338
2339 void
sendsusp(void)2340 sendsusp(void)
2341 {
2342 NET2ADD(IAC, SUSP);
2343 printoption("SENT", IAC, SUSP);
2344 flushline = 1;
2345 if (autoflush) {
2346 doflush();
2347 }
2348 if (autosynch) {
2349 dosynch();
2350 }
2351 }
2352
2353 void
sendeof(void)2354 sendeof(void)
2355 {
2356 NET2ADD(IAC, xEOF);
2357 printoption("SENT", IAC, xEOF);
2358 }
2359
2360 void
sendayt(void)2361 sendayt(void)
2362 {
2363 NET2ADD(IAC, AYT);
2364 printoption("SENT", IAC, AYT);
2365 }
2366
2367 /*
2368 * Send a window size update to the remote system.
2369 */
2370
2371 void
sendnaws()2372 sendnaws()
2373 {
2374 long rows, cols;
2375 unsigned char tmp[16];
2376 unsigned char *cp;
2377
2378 if (my_state_is_wont(TELOPT_NAWS))
2379 return;
2380
2381 #undef PUTSHORT
2382 #define PUTSHORT(cp, x) { if ((*cp++ = ((x)>>8)&0xff) == IAC) *cp++ = IAC; \
2383 if ((*cp++ = ((x))&0xff) == IAC) *cp++ = IAC; }
2384
2385 if (TerminalWindowSize(&rows, &cols) == 0) { /* Failed */
2386 return;
2387 }
2388
2389 cp = tmp;
2390
2391 *cp++ = IAC;
2392 *cp++ = SB;
2393 *cp++ = TELOPT_NAWS;
2394 PUTSHORT(cp, cols);
2395 PUTSHORT(cp, rows);
2396 *cp++ = IAC;
2397 *cp++ = SE;
2398 if (NETROOM() >= cp - tmp) {
2399 ring_supply_data(&netoring, tmp, cp-tmp);
2400 printsub('>', tmp+2, cp - tmp - 2);
2401 }
2402 }
2403
2404 void
tel_enter_binary(int rw)2405 tel_enter_binary(int rw)
2406 {
2407 if (rw&1)
2408 send_do(TELOPT_BINARY, 1);
2409 if (rw&2)
2410 send_will(TELOPT_BINARY, 1);
2411 }
2412
2413 void
tel_leave_binary(int rw)2414 tel_leave_binary(int rw)
2415 {
2416 if (rw&1)
2417 send_dont(TELOPT_BINARY, 1);
2418 if (rw&2)
2419 send_wont(TELOPT_BINARY, 1);
2420 }
2421