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