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