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