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