1 /* 2 * Copyright (c) 1988 Regents of the University of California. 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms are permitted 6 * provided that the above copyright notice and this paragraph are 7 * duplicated in all such forms and that any documentation, 8 * advertising materials, and other materials related to such 9 * distribution and use acknowledge that the software was developed 10 * by the University of California, Berkeley. The name of the 11 * University may not be used to endorse or promote products derived 12 * from this software without specific prior written permission. 13 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR 14 * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED 15 * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. 16 */ 17 18 #ifndef lint 19 static char sccsid[] = "@(#)telnet.c 5.38 (Berkeley) 02/06/89"; 20 #endif /* not lint */ 21 22 #include <sys/types.h> 23 24 #if defined(unix) 25 #include <signal.h> 26 /* By the way, we need to include curses.h before telnet.h since, 27 * among other things, telnet.h #defines 'DO', which is a variable 28 * declared in curses.h. 29 */ 30 #include <curses.h> 31 #endif /* defined(unix) */ 32 33 #include <arpa/telnet.h> 34 35 #if defined(unix) 36 #include <strings.h> 37 #else /* defined(unix) */ 38 #include <string.h> 39 #endif /* defined(unix) */ 40 41 #include "ring.h" 42 43 #include "defines.h" 44 #include "externs.h" 45 #include "types.h" 46 #include "general.h" 47 48 49 #define strip(x) ((x)&0x7f) 50 51 52 static char subbuffer[SUBBUFSIZE], 53 *subpointer, *subend; /* buffer for sub-options */ 54 #define SB_CLEAR() subpointer = subbuffer; 55 #define SB_TERM() subend = subpointer; 56 #define SB_ACCUM(c) if (subpointer < (subbuffer+sizeof subbuffer)) { \ 57 *subpointer++ = (c); \ 58 } 59 60 char hisopts[256]; 61 char myopts[256]; 62 63 char doopt[] = { IAC, DO, '%', 'c', 0 }; 64 char dont[] = { IAC, DONT, '%', 'c', 0 }; 65 char will[] = { IAC, WILL, '%', 'c', 0 }; 66 char wont[] = { IAC, WONT, '%', 'c', 0 }; 67 68 int 69 connected, 70 showoptions, 71 In3270, /* Are we in 3270 mode? */ 72 ISend, /* trying to send network data in */ 73 debug = 0, 74 crmod, 75 netdata, /* Print out network data flow */ 76 crlf, /* Should '\r' be mapped to <CR><LF> (or <CR><NUL>)? */ 77 #if defined(TN3270) 78 noasynchtty = 0,/* User specified "-noasynch" on command line */ 79 noasynchnet = 0,/* User specified "-noasynch" on command line */ 80 askedSGA = 0, /* We have talked about suppress go ahead */ 81 #endif /* defined(TN3270) */ 82 telnetport, 83 SYNCHing, /* we are in TELNET SYNCH mode */ 84 flushout, /* flush output */ 85 autoflush = 0, /* flush output when interrupting? */ 86 autosynch, /* send interrupt characters with SYNCH? */ 87 localchars, /* we recognize interrupt/quit */ 88 donelclchars, /* the user has set "localchars" */ 89 donebinarytoggle, /* the user has put us in binary */ 90 dontlecho, /* do we suppress local echoing right now? */ 91 globalmode; 92 93 #define CONTROL(x) ((x)&0x1f) /* CTRL(x) is not portable */ 94 95 char 96 *prompt = 0, 97 escape, 98 echoc; 99 100 /* 101 * Telnet receiver states for fsm 102 */ 103 #define TS_DATA 0 104 #define TS_IAC 1 105 #define TS_WILL 2 106 #define TS_WONT 3 107 #define TS_DO 4 108 #define TS_DONT 5 109 #define TS_CR 6 110 #define TS_SB 7 /* sub-option collection */ 111 #define TS_SE 8 /* looking for sub-option end */ 112 113 static int telrcv_state; 114 115 jmp_buf toplevel = { 0 }; 116 jmp_buf peerdied; 117 118 int flushline; 119 120 /* 121 * The following are some clocks used to decide how to interpret 122 * the relationship between various variables. 123 */ 124 125 Clocks clocks; 126 127 Modelist modelist[] = { 128 { "telnet command mode", COMMAND_LINE }, 129 { "character-at-a-time mode", 0 }, 130 { "character-at-a-time mode (local echo)", LOCAL_ECHO|LOCAL_CHARS }, 131 { "line-by-line mode (remote echo)", LINE | LOCAL_CHARS }, 132 { "line-by-line mode", LINE | LOCAL_ECHO | LOCAL_CHARS }, 133 { "line-by-line mode (local echoing suppressed)", LINE | LOCAL_CHARS }, 134 { "3270 mode", 0 }, 135 }; 136 137 138 /* 139 * Initialize telnet environment. 140 */ 141 142 init_telnet() 143 { 144 SB_CLEAR(); 145 ClearArray(hisopts); 146 ClearArray(myopts); 147 148 connected = In3270 = ISend = donebinarytoggle = 0; 149 150 SYNCHing = 0; 151 152 /* Don't change NetTrace */ 153 154 escape = CONTROL(']'); 155 echoc = CONTROL('E'); 156 157 flushline = 1; 158 telrcv_state = TS_DATA; 159 } 160 161 162 #include <varargs.h> 163 164 /*VARARGS*/ 165 static void 166 printring(va_alist) 167 va_dcl 168 { 169 va_list ap; 170 char buffer[100]; /* where things go */ 171 char *ptr; 172 char *format; 173 char *string; 174 Ring *ring; 175 int i; 176 177 va_start(ap); 178 179 ring = va_arg(ap, Ring *); 180 format = va_arg(ap, char *); 181 ptr = buffer; 182 183 while ((i = *format++) != 0) { 184 if (i == '%') { 185 i = *format++; 186 switch (i) { 187 case 'c': 188 *ptr++ = va_arg(ap, int); 189 break; 190 case 's': 191 string = va_arg(ap, char *); 192 ring_supply_data(ring, buffer, ptr-buffer); 193 ring_supply_data(ring, string, strlen(string)); 194 ptr = buffer; 195 break; 196 case 0: 197 ExitString("printring: trailing %%.\n", 1); 198 /*NOTREACHED*/ 199 default: 200 ExitString("printring: unknown format character.\n", 1); 201 /*NOTREACHED*/ 202 } 203 } else { 204 *ptr++ = i; 205 } 206 } 207 ring_supply_data(ring, buffer, ptr-buffer); 208 } 209 210 211 void 212 willoption(option, reply) 213 int option, reply; 214 { 215 char *fmt; 216 217 switch (option) { 218 219 case TELOPT_ECHO: 220 # if defined(TN3270) 221 /* 222 * The following is a pain in the rear-end. 223 * Various IBM servers (some versions of Wiscnet, 224 * possibly Fibronics/Spartacus, and who knows who 225 * else) will NOT allow us to send "DO SGA" too early 226 * in the setup proceedings. On the other hand, 227 * 4.2 servers (telnetd) won't set SGA correctly. 228 * So, we are stuck. Empirically (but, based on 229 * a VERY small sample), the IBM servers don't send 230 * out anything about ECHO, so we postpone our sending 231 * "DO SGA" until we see "WILL ECHO" (which 4.2 servers 232 * DO send). 233 */ 234 { 235 if (askedSGA == 0) { 236 askedSGA = 1; 237 if (!hisopts[TELOPT_SGA]) { 238 willoption(TELOPT_SGA, 0); 239 } 240 } 241 } 242 /* Fall through */ 243 case TELOPT_EOR: 244 case TELOPT_BINARY: 245 #endif /* defined(TN3270) */ 246 case TELOPT_SGA: 247 settimer(modenegotiated); 248 hisopts[option] = 1; 249 fmt = doopt; 250 setconnmode(); /* possibly set new tty mode */ 251 break; 252 253 case TELOPT_TM: 254 return; /* Never reply to TM will's/wont's */ 255 256 default: 257 fmt = dont; 258 break; 259 } 260 printring(&netoring, fmt, option); 261 if (reply) 262 printoption(">SENT", fmt, option, reply); 263 else 264 printoption("<SENT", fmt, option, reply); 265 } 266 267 void 268 wontoption(option, reply) 269 int option, reply; 270 { 271 char *fmt; 272 273 switch (option) { 274 275 case TELOPT_ECHO: 276 case TELOPT_SGA: 277 settimer(modenegotiated); 278 hisopts[option] = 0; 279 fmt = dont; 280 setconnmode(); /* Set new tty mode */ 281 break; 282 283 case TELOPT_TM: 284 return; /* Never reply to TM will's/wont's */ 285 286 default: 287 hisopts[option] = 0; 288 fmt = dont; 289 } 290 printring(&netoring, fmt, option); 291 if (reply) 292 printoption(">SENT", fmt, option, reply); 293 else 294 printoption("<SENT", fmt, option, reply); 295 } 296 297 static void 298 dooption(option) 299 int option; 300 { 301 char *fmt; 302 303 switch (option) { 304 305 case TELOPT_TM: 306 fmt = will; 307 break; 308 309 # if defined(TN3270) 310 case TELOPT_EOR: 311 case TELOPT_BINARY: 312 # endif /* defined(TN3270) */ 313 case TELOPT_TTYPE: /* terminal type option */ 314 case TELOPT_SGA: /* no big deal */ 315 fmt = will; 316 myopts[option] = 1; 317 break; 318 319 case TELOPT_ECHO: /* We're never going to echo... */ 320 default: 321 fmt = wont; 322 break; 323 } 324 printring(&netoring, fmt, option); 325 printoption(">SENT", fmt, option, 0); 326 } 327 328 /* 329 * suboption() 330 * 331 * Look at the sub-option buffer, and try to be helpful to the other 332 * side. 333 * 334 * Currently we recognize: 335 * 336 * Terminal type, send request. 337 */ 338 339 static void 340 suboption() 341 { 342 printsub("<", subbuffer, subend-subbuffer+1); 343 switch (subbuffer[0]&0xff) { 344 case TELOPT_TTYPE: 345 if ((subbuffer[1]&0xff) != TELQUAL_SEND) { 346 ; 347 } else { 348 char *name; 349 char namebuf[41]; 350 extern char *getenv(); 351 int len; 352 353 #if defined(TN3270) 354 if (tn3270_ttype()) { 355 return; 356 } 357 #endif /* defined(TN3270) */ 358 name = getenv("TERM"); 359 if ((name == 0) || ((len = strlen(name)) > 40)) { 360 name = "UNKNOWN"; 361 len = strlen(name); 362 } 363 if ((len + 4+2) < NETROOM()) { 364 strcpy(namebuf, name); 365 upcase(namebuf); 366 printring(&netoring, "%c%c%c%c%s%c%c", IAC, SB, TELOPT_TTYPE, 367 TELQUAL_IS, namebuf, IAC, SE); 368 /* XXX */ 369 /* printsub(">", nfrontp+2, 4+strlen(namebuf)+2-2-2); */ 370 } else { 371 ExitString("No room in buffer for terminal type.\n", 372 1); 373 /*NOTREACHED*/ 374 } 375 } 376 377 default: 378 break; 379 } 380 } 381 382 383 int 384 telrcv() 385 { 386 register int c; 387 register int scc; 388 register char *sbp; 389 int count; 390 int returnValue = 0; 391 392 scc = 0; 393 count = 0; 394 while (TTYROOM() > 2) { 395 if (scc == 0) { 396 if (count) { 397 ring_consumed(&netiring, count); 398 returnValue = 1; 399 count = 0; 400 } 401 sbp = netiring.consume; 402 scc = ring_full_consecutive(&netiring); 403 if (scc == 0) { 404 /* No more data coming in */ 405 break; 406 } 407 } 408 409 c = *sbp++ & 0xff, scc--; count++; 410 411 switch (telrcv_state) { 412 413 case TS_CR: 414 telrcv_state = TS_DATA; 415 if (c == '\0') { 416 break; /* Ignore \0 after CR */ 417 } else if ((c == '\n') && (!hisopts[TELOPT_ECHO]) && !crmod) { 418 TTYADD(c); 419 break; 420 } 421 /* Else, fall through */ 422 423 case TS_DATA: 424 if (c == IAC) { 425 telrcv_state = TS_IAC; 426 break; 427 } 428 # if defined(TN3270) 429 if (In3270) { 430 *Ifrontp++ = c; 431 while (scc > 0) { 432 c = *sbp++ & 0377, scc--; count++; 433 if (c == IAC) { 434 telrcv_state = TS_IAC; 435 break; 436 } 437 *Ifrontp++ = c; 438 } 439 } else 440 # endif /* defined(TN3270) */ 441 /* 442 * The 'crmod' hack (see following) is needed 443 * since we can't * set CRMOD on output only. 444 * Machines like MULTICS like to send \r without 445 * \n; since we must turn off CRMOD to get proper 446 * input, the mapping is done here (sigh). 447 */ 448 if ((c == '\r') && !hisopts[TELOPT_BINARY]) { 449 if (scc > 0) { 450 c = *sbp&0xff; 451 if (c == 0) { 452 sbp++, scc--; count++; 453 /* a "true" CR */ 454 TTYADD('\r'); 455 } else if (!hisopts[TELOPT_ECHO] && 456 (c == '\n')) { 457 sbp++, scc--; count++; 458 TTYADD('\n'); 459 } else { 460 TTYADD('\r'); 461 if (crmod) { 462 TTYADD('\n'); 463 } 464 } 465 } else { 466 telrcv_state = TS_CR; 467 TTYADD('\r'); 468 if (crmod) { 469 TTYADD('\n'); 470 } 471 } 472 } else { 473 TTYADD(c); 474 } 475 continue; 476 477 case TS_IAC: 478 switch (c) { 479 480 case WILL: 481 telrcv_state = TS_WILL; 482 continue; 483 484 case WONT: 485 telrcv_state = TS_WONT; 486 continue; 487 488 case DO: 489 telrcv_state = TS_DO; 490 continue; 491 492 case DONT: 493 telrcv_state = TS_DONT; 494 continue; 495 496 case DM: 497 /* 498 * We may have missed an urgent notification, 499 * so make sure we flush whatever is in the 500 * buffer currently. 501 */ 502 SYNCHing = 1; 503 ttyflush(1); 504 SYNCHing = stilloob(); 505 settimer(gotDM); 506 break; 507 508 case NOP: 509 case GA: 510 break; 511 512 case SB: 513 SB_CLEAR(); 514 telrcv_state = TS_SB; 515 continue; 516 517 # if defined(TN3270) 518 case EOR: 519 if (In3270) { 520 Ibackp += DataFromNetwork(Ibackp, Ifrontp-Ibackp, 1); 521 if (Ibackp == Ifrontp) { 522 Ibackp = Ifrontp = Ibuf; 523 ISend = 0; /* should have been! */ 524 } else { 525 ISend = 1; 526 } 527 } 528 break; 529 # endif /* defined(TN3270) */ 530 531 case IAC: 532 # if !defined(TN3270) 533 TTYADD(IAC); 534 # else /* !defined(TN3270) */ 535 if (In3270) { 536 *Ifrontp++ = IAC; 537 } else { 538 TTYADD(IAC); 539 } 540 # endif /* !defined(TN3270) */ 541 break; 542 543 default: 544 break; 545 } 546 telrcv_state = TS_DATA; 547 continue; 548 549 case TS_WILL: 550 printoption(">RCVD", will, c, !hisopts[c]); 551 if (c == TELOPT_TM) { 552 if (flushout) { 553 flushout = 0; 554 } 555 } else if (!hisopts[c]) { 556 willoption(c, 1); 557 } 558 SetIn3270(); 559 telrcv_state = TS_DATA; 560 continue; 561 562 case TS_WONT: 563 printoption(">RCVD", wont, c, hisopts[c]); 564 if (c == TELOPT_TM) { 565 if (flushout) { 566 flushout = 0; 567 } 568 } else if (hisopts[c]) { 569 wontoption(c, 1); 570 } 571 SetIn3270(); 572 telrcv_state = TS_DATA; 573 continue; 574 575 case TS_DO: 576 printoption(">RCVD", doopt, c, !myopts[c]); 577 if (!myopts[c]) 578 dooption(c); 579 SetIn3270(); 580 telrcv_state = TS_DATA; 581 continue; 582 583 case TS_DONT: 584 printoption(">RCVD", dont, c, myopts[c]); 585 if (myopts[c]) { 586 myopts[c] = 0; 587 printring(&netoring, wont, c); 588 flushline = 1; 589 setconnmode(); /* set new tty mode (maybe) */ 590 printoption(">SENT", wont, c, 0); 591 } 592 SetIn3270(); 593 telrcv_state = TS_DATA; 594 continue; 595 596 case TS_SB: 597 if (c == IAC) { 598 telrcv_state = TS_SE; 599 } else { 600 SB_ACCUM(c); 601 } 602 continue; 603 604 case TS_SE: 605 if (c != SE) { 606 if (c != IAC) { 607 SB_ACCUM(IAC); 608 } 609 SB_ACCUM(c); 610 telrcv_state = TS_SB; 611 } else { 612 SB_TERM(); 613 suboption(); /* handle sub-option */ 614 SetIn3270(); 615 telrcv_state = TS_DATA; 616 } 617 } 618 } 619 if (count) 620 ring_consumed(&netiring, count); 621 return returnValue||count; 622 } 623 624 static int 625 telsnd() 626 { 627 int tcc; 628 int count; 629 int returnValue = 0; 630 char *tbp; 631 632 tcc = 0; 633 count = 0; 634 while (NETROOM() > 2) { 635 register int sc; 636 register int c; 637 638 if (tcc == 0) { 639 if (count) { 640 ring_consumed(&ttyiring, count); 641 returnValue = 1; 642 count = 0; 643 } 644 tbp = ttyiring.consume; 645 tcc = ring_full_consecutive(&ttyiring); 646 if (tcc == 0) { 647 break; 648 } 649 } 650 c = *tbp++ & 0xff, sc = strip(c), tcc--; count++; 651 if (sc == escape) { 652 command(0); 653 tcc = 0; 654 flushline = 1; 655 break; 656 } else if (MODE_LINE(globalmode) && (sc == echoc)) { 657 if (tcc > 0 && strip(*tbp) == echoc) { 658 tcc--; tbp++; count++; 659 } else { 660 dontlecho = !dontlecho; 661 settimer(echotoggle); 662 setconnmode(); 663 flushline = 1; 664 break; 665 } 666 } 667 if (localchars) { 668 if (TerminalSpecialChars(sc) == 0) { 669 break; 670 } 671 } 672 if (!myopts[TELOPT_BINARY]) { 673 switch (c) { 674 case '\n': 675 /* 676 * If we are in CRMOD mode (\r ==> \n) 677 * on our local machine, then probably 678 * a newline (unix) is CRLF (TELNET). 679 */ 680 if (MODE_LOCAL_CHARS(globalmode)) { 681 NETADD('\r'); 682 } 683 NETADD('\n'); 684 flushline = 1; 685 break; 686 case '\r': 687 if (!crlf) { 688 NET2ADD('\r', '\0'); 689 } else { 690 NET2ADD('\r', '\n'); 691 } 692 flushline = 1; 693 break; 694 case IAC: 695 NET2ADD(IAC, IAC); 696 break; 697 default: 698 NETADD(c); 699 break; 700 } 701 } else if (c == IAC) { 702 NET2ADD(IAC, IAC); 703 } else { 704 NETADD(c); 705 } 706 } 707 if (count) 708 ring_consumed(&ttyiring, count); 709 return returnValue||count; /* Non-zero if we did anything */ 710 } 711 712 /* 713 * Scheduler() 714 * 715 * Try to do something. 716 * 717 * If we do something useful, return 1; else return 0. 718 * 719 */ 720 721 722 int 723 Scheduler(block) 724 int block; /* should we block in the select ? */ 725 { 726 /* One wants to be a bit careful about setting returnValue 727 * to one, since a one implies we did some useful work, 728 * and therefore probably won't be called to block next 729 * time (TN3270 mode only). 730 */ 731 int returnValue; 732 int netin, netout, netex, ttyin, ttyout; 733 734 /* Decide which rings should be processed */ 735 736 netout = ring_full_count(&netoring) && 737 (!MODE_LINE(globalmode) || flushline || myopts[TELOPT_BINARY]); 738 ttyout = ring_full_count(&ttyoring); 739 740 #if defined(TN3270) 741 ttyin = ring_empty_count(&ttyiring) && (shell_active == 0); 742 #else /* defined(TN3270) */ 743 ttyin = ring_empty_count(&ttyiring); 744 #endif /* defined(TN3270) */ 745 746 #if defined(TN3270) 747 netin = ring_empty_count(&netiring); 748 # else /* !defined(TN3270) */ 749 netin = !ISend && ring_empty_count(&netiring); 750 # endif /* !defined(TN3270) */ 751 752 netex = !SYNCHing; 753 754 /* If we have seen a signal recently, reset things */ 755 # if defined(TN3270) && defined(unix) 756 if (HaveInput) { 757 HaveInput = 0; 758 signal(SIGIO, inputAvailable); 759 } 760 #endif /* defined(TN3270) && defined(unix) */ 761 762 /* Call to system code to process rings */ 763 764 returnValue = process_rings(netin, netout, netex, ttyin, ttyout, !block); 765 766 /* Now, look at the input rings, looking for work to do. */ 767 768 if (ring_full_count(&ttyiring)) { 769 # if defined(TN3270) 770 if (In3270) { 771 int c; 772 773 c = DataFromTerminal(ttyiring.consume, 774 ring_full_consecutive(&ttyiring)); 775 if (c) { 776 returnValue = 1; 777 ring_consumed(&ttyiring, c); 778 } 779 } else { 780 # endif /* defined(TN3270) */ 781 returnValue |= telsnd(); 782 # if defined(TN3270) 783 } 784 # endif /* defined(TN3270) */ 785 } 786 787 if (ring_full_count(&netiring)) { 788 # if !defined(TN3270) 789 returnValue |= telrcv(); 790 # else /* !defined(TN3270) */ 791 returnValue = Push3270(); 792 # endif /* !defined(TN3270) */ 793 } 794 return returnValue; 795 } 796 797 /* 798 * Select from tty and network... 799 */ 800 void 801 telnet() 802 { 803 sys_telnet_init(); 804 805 # if !defined(TN3270) 806 if (telnetport) { 807 if (!hisopts[TELOPT_SGA]) { 808 willoption(TELOPT_SGA, 0); 809 } 810 if (!myopts[TELOPT_TTYPE]) { 811 dooption(TELOPT_TTYPE); 812 } 813 } 814 # endif /* !defined(TN3270) */ 815 816 # if !defined(TN3270) 817 for (;;) { 818 int schedValue; 819 820 while ((schedValue = Scheduler(0)) != 0) { 821 if (schedValue == -1) { 822 setcommandmode(); 823 return; 824 } 825 } 826 827 if (Scheduler(1) == -1) { 828 setcommandmode(); 829 return; 830 } 831 } 832 # else /* !defined(TN3270) */ 833 for (;;) { 834 int schedValue; 835 836 while (!In3270 && !shell_active) { 837 if (Scheduler(1) == -1) { 838 setcommandmode(); 839 return; 840 } 841 } 842 843 while ((schedValue = Scheduler(0)) != 0) { 844 if (schedValue == -1) { 845 setcommandmode(); 846 return; 847 } 848 } 849 /* If there is data waiting to go out to terminal, don't 850 * schedule any more data for the terminal. 851 */ 852 if (ring_full_count(&ttyoring)) { 853 schedValue = 1; 854 } else { 855 if (shell_active) { 856 if (shell_continue() == 0) { 857 ConnectScreen(); 858 } 859 } else if (In3270) { 860 schedValue = DoTerminalOutput(); 861 } 862 } 863 if (schedValue && (shell_active == 0)) { 864 if (Scheduler(1) == -1) { 865 setcommandmode(); 866 return; 867 } 868 } 869 } 870 # endif /* !defined(TN3270) */ 871 } 872 873 #if 0 /* XXX - this not being in is a bug */ 874 /* 875 * nextitem() 876 * 877 * Return the address of the next "item" in the TELNET data 878 * stream. This will be the address of the next character if 879 * the current address is a user data character, or it will 880 * be the address of the character following the TELNET command 881 * if the current address is a TELNET IAC ("I Am a Command") 882 * character. 883 */ 884 885 static char * 886 nextitem(current) 887 char *current; 888 { 889 if ((*current&0xff) != IAC) { 890 return current+1; 891 } 892 switch (*(current+1)&0xff) { 893 case DO: 894 case DONT: 895 case WILL: 896 case WONT: 897 return current+3; 898 case SB: /* loop forever looking for the SE */ 899 { 900 register char *look = current+2; 901 902 for (;;) { 903 if ((*look++&0xff) == IAC) { 904 if ((*look++&0xff) == SE) { 905 return look; 906 } 907 } 908 } 909 } 910 default: 911 return current+2; 912 } 913 } 914 #endif /* 0 */ 915 916 /* 917 * netclear() 918 * 919 * We are about to do a TELNET SYNCH operation. Clear 920 * the path to the network. 921 * 922 * Things are a bit tricky since we may have sent the first 923 * byte or so of a previous TELNET command into the network. 924 * So, we have to scan the network buffer from the beginning 925 * until we are up to where we want to be. 926 * 927 * A side effect of what we do, just to keep things 928 * simple, is to clear the urgent data pointer. The principal 929 * caller should be setting the urgent data pointer AFTER calling 930 * us in any case. 931 */ 932 933 static void 934 netclear() 935 { 936 #if 0 /* XXX */ 937 register char *thisitem, *next; 938 char *good; 939 #define wewant(p) ((nfrontp > p) && ((*p&0xff) == IAC) && \ 940 ((*(p+1)&0xff) != EC) && ((*(p+1)&0xff) != EL)) 941 942 thisitem = netobuf; 943 944 while ((next = nextitem(thisitem)) <= netobuf.send) { 945 thisitem = next; 946 } 947 948 /* Now, thisitem is first before/at boundary. */ 949 950 good = netobuf; /* where the good bytes go */ 951 952 while (netoring.add > thisitem) { 953 if (wewant(thisitem)) { 954 int length; 955 956 next = thisitem; 957 do { 958 next = nextitem(next); 959 } while (wewant(next) && (nfrontp > next)); 960 length = next-thisitem; 961 memcpy(good, thisitem, length); 962 good += length; 963 thisitem = next; 964 } else { 965 thisitem = nextitem(thisitem); 966 } 967 } 968 969 #endif /* 0 */ 970 } 971 972 /* 973 * These routines add various telnet commands to the data stream. 974 */ 975 976 static void 977 doflush() 978 { 979 NET2ADD(IAC, DO); 980 NETADD(TELOPT_TM); 981 flushline = 1; 982 flushout = 1; 983 ttyflush(1); /* Flush/drop output */ 984 /* do printoption AFTER flush, otherwise the output gets tossed... */ 985 printoption("<SENT", doopt, TELOPT_TM, 0); 986 } 987 988 void 989 xmitAO() 990 { 991 NET2ADD(IAC, AO); 992 if (autoflush) { 993 doflush(); 994 } 995 } 996 997 998 void 999 xmitEL() 1000 { 1001 NET2ADD(IAC, EL); 1002 } 1003 1004 void 1005 xmitEC() 1006 { 1007 NET2ADD(IAC, EC); 1008 } 1009 1010 1011 #if defined(NOT43) 1012 int 1013 #else /* defined(NOT43) */ 1014 void 1015 #endif /* defined(NOT43) */ 1016 dosynch() 1017 { 1018 netclear(); /* clear the path to the network */ 1019 NETADD(IAC); 1020 setneturg(); 1021 NETADD(DM); 1022 1023 #if defined(NOT43) 1024 return 0; 1025 #endif /* defined(NOT43) */ 1026 } 1027 1028 void 1029 intp() 1030 { 1031 NET2ADD(IAC, IP); 1032 flushline = 1; 1033 if (autoflush) { 1034 doflush(); 1035 } 1036 if (autosynch) { 1037 dosynch(); 1038 } 1039 } 1040 1041 void 1042 sendbrk() 1043 { 1044 NET2ADD(IAC, BREAK); 1045 flushline = 1; 1046 if (autoflush) { 1047 doflush(); 1048 } 1049 if (autosynch) { 1050 dosynch(); 1051 } 1052 } 1053