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