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) 6/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 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 fmt = dont; 288 } 289 printring(&netoring, fmt, option); 290 if (reply) 291 printoption(">SENT", fmt, option, reply); 292 else 293 printoption("<SENT", fmt, option, reply); 294 } 295 296 static void 297 dooption(option) 298 int option; 299 { 300 char *fmt; 301 302 switch (option) { 303 304 case TELOPT_TM: 305 fmt = will; 306 break; 307 308 # if defined(TN3270) 309 case TELOPT_EOR: 310 case TELOPT_BINARY: 311 # endif /* defined(TN3270) */ 312 case TELOPT_TTYPE: /* terminal type option */ 313 case TELOPT_SGA: /* no big deal */ 314 fmt = will; 315 myopts[option] = 1; 316 break; 317 318 case TELOPT_ECHO: /* We're never going to echo... */ 319 default: 320 fmt = wont; 321 break; 322 } 323 printring(&netoring, fmt, option); 324 printoption(">SENT", fmt, option, 0); 325 } 326 327 /* 328 * suboption() 329 * 330 * Look at the sub-option buffer, and try to be helpful to the other 331 * side. 332 * 333 * Currently we recognize: 334 * 335 * Terminal type, send request. 336 */ 337 338 static void 339 suboption() 340 { 341 printsub("<", subbuffer, subend-subbuffer+1); 342 switch (subbuffer[0]&0xff) { 343 case TELOPT_TTYPE: 344 if ((subbuffer[1]&0xff) != TELQUAL_SEND) { 345 ; 346 } else { 347 char *name; 348 char namebuf[41]; 349 extern char *getenv(); 350 int len; 351 352 #if defined(TN3270) 353 if (tn3270_ttype()) { 354 return; 355 } 356 #endif /* defined(TN3270) */ 357 name = getenv("TERM"); 358 if ((name == 0) || ((len = strlen(name)) > 40)) { 359 name = "UNKNOWN"; 360 len = strlen(name); 361 } 362 if ((len + 4+2) < NETROOM()) { 363 strcpy(namebuf, name); 364 upcase(namebuf); 365 printring(&netoring, "%c%c%c%c%s%c%c", IAC, SB, TELOPT_TTYPE, 366 TELQUAL_IS, namebuf, IAC, SE); 367 /* XXX */ 368 /* printsub(">", nfrontp+2, 4+strlen(namebuf)+2-2-2); */ 369 } else { 370 ExitString("No room in buffer for terminal type.\n", 371 1); 372 /*NOTREACHED*/ 373 } 374 } 375 376 default: 377 break; 378 } 379 } 380 381 382 int 383 telrcv() 384 { 385 register int c; 386 register int scc; 387 register char *sbp; 388 int count; 389 int returnValue = 0; 390 391 scc = 0; 392 count = 0; 393 while (TTYROOM() > 2) { 394 if (scc == 0) { 395 if (count) { 396 ring_consumed(&netiring, count); 397 returnValue = 1; 398 count = 0; 399 } 400 sbp = netiring.consume; 401 scc = ring_full_consecutive(&netiring); 402 if (scc == 0) { 403 /* No more data coming in */ 404 break; 405 } 406 } 407 408 c = *sbp++ & 0xff, scc--; count++; 409 410 switch (telrcv_state) { 411 412 case TS_CR: 413 telrcv_state = TS_DATA; 414 if (c == '\0') { 415 break; /* Ignore \0 after CR */ 416 } else if ((c == '\n') && (!hisopts[TELOPT_ECHO]) && !crmod) { 417 TTYADD(c); 418 break; 419 } 420 /* Else, fall through */ 421 422 case TS_DATA: 423 if (c == IAC) { 424 telrcv_state = TS_IAC; 425 break; 426 } 427 # if defined(TN3270) 428 if (In3270) { 429 *Ifrontp++ = c; 430 while (scc > 0) { 431 c = *sbp++ & 0377, scc--; count++; 432 if (c == IAC) { 433 telrcv_state = TS_IAC; 434 break; 435 } 436 *Ifrontp++ = c; 437 } 438 } else 439 # endif /* defined(TN3270) */ 440 /* 441 * The 'crmod' hack (see following) is needed 442 * since we can't * set CRMOD on output only. 443 * Machines like MULTICS like to send \r without 444 * \n; since we must turn off CRMOD to get proper 445 * input, the mapping is done here (sigh). 446 */ 447 if ((c == '\r') && !hisopts[TELOPT_BINARY]) { 448 if (scc > 0) { 449 c = *sbp&0xff; 450 if (c == 0) { 451 sbp++, scc--; count++; 452 /* a "true" CR */ 453 TTYADD('\r'); 454 } else if (!hisopts[TELOPT_ECHO] && 455 (c == '\n')) { 456 sbp++, scc--; count++; 457 TTYADD('\n'); 458 } else { 459 TTYADD('\r'); 460 if (crmod) { 461 TTYADD('\n'); 462 } 463 } 464 } else { 465 telrcv_state = TS_CR; 466 TTYADD('\r'); 467 if (crmod) { 468 TTYADD('\n'); 469 } 470 } 471 } else { 472 TTYADD(c); 473 } 474 continue; 475 476 case TS_IAC: 477 switch (c) { 478 479 case WILL: 480 telrcv_state = TS_WILL; 481 continue; 482 483 case WONT: 484 telrcv_state = TS_WONT; 485 continue; 486 487 case DO: 488 telrcv_state = TS_DO; 489 continue; 490 491 case DONT: 492 telrcv_state = TS_DONT; 493 continue; 494 495 case DM: 496 /* 497 * We may have missed an urgent notification, 498 * so make sure we flush whatever is in the 499 * buffer currently. 500 */ 501 SYNCHing = 1; 502 ttyflush(1); 503 SYNCHing = stilloob(); 504 settimer(gotDM); 505 break; 506 507 case NOP: 508 case GA: 509 break; 510 511 case SB: 512 SB_CLEAR(); 513 telrcv_state = TS_SB; 514 continue; 515 516 # if defined(TN3270) 517 case EOR: 518 if (In3270) { 519 Ibackp += DataFromNetwork(Ibackp, Ifrontp-Ibackp, 1); 520 if (Ibackp == Ifrontp) { 521 Ibackp = Ifrontp = Ibuf; 522 ISend = 0; /* should have been! */ 523 } else { 524 ISend = 1; 525 } 526 } 527 break; 528 # endif /* defined(TN3270) */ 529 530 case IAC: 531 # if !defined(TN3270) 532 TTYADD(IAC); 533 # else /* !defined(TN3270) */ 534 if (In3270) { 535 *Ifrontp++ = IAC; 536 } else { 537 TTYADD(IAC); 538 } 539 # endif /* !defined(TN3270) */ 540 break; 541 542 default: 543 break; 544 } 545 telrcv_state = TS_DATA; 546 continue; 547 548 case TS_WILL: 549 printoption(">RCVD", will, c, !hisopts[c]); 550 if (c == TELOPT_TM) { 551 if (flushout) { 552 flushout = 0; 553 } 554 } else if (!hisopts[c]) { 555 willoption(c, 1); 556 } 557 SetIn3270(); 558 telrcv_state = TS_DATA; 559 continue; 560 561 case TS_WONT: 562 printoption(">RCVD", wont, c, hisopts[c]); 563 if (c == TELOPT_TM) { 564 if (flushout) { 565 flushout = 0; 566 } 567 } else if (hisopts[c]) { 568 wontoption(c, 1); 569 } 570 SetIn3270(); 571 telrcv_state = TS_DATA; 572 continue; 573 574 case TS_DO: 575 printoption(">RCVD", doopt, c, !myopts[c]); 576 if (!myopts[c]) 577 dooption(c); 578 SetIn3270(); 579 telrcv_state = TS_DATA; 580 continue; 581 582 case TS_DONT: 583 printoption(">RCVD", dont, c, myopts[c]); 584 if (myopts[c]) { 585 myopts[c] = 0; 586 printring(&netoring, wont, c); 587 flushline = 1; 588 setconnmode(); /* set new tty mode (maybe) */ 589 printoption(">SENT", wont, c, 0); 590 } 591 SetIn3270(); 592 telrcv_state = TS_DATA; 593 continue; 594 595 case TS_SB: 596 if (c == IAC) { 597 telrcv_state = TS_SE; 598 } else { 599 SB_ACCUM(c); 600 } 601 continue; 602 603 case TS_SE: 604 if (c != SE) { 605 if (c != IAC) { 606 SB_ACCUM(IAC); 607 } 608 SB_ACCUM(c); 609 telrcv_state = TS_SB; 610 } else { 611 SB_TERM(); 612 suboption(); /* handle sub-option */ 613 SetIn3270(); 614 telrcv_state = TS_DATA; 615 } 616 } 617 } 618 if (count) 619 ring_consumed(&netiring, count); 620 return returnValue||count; 621 } 622 623 static int 624 telsnd() 625 { 626 int tcc; 627 int count; 628 int returnValue = 0; 629 char *tbp; 630 631 tcc = 0; 632 count = 0; 633 while (NETROOM() > 2) { 634 register int sc; 635 register int c; 636 637 if (tcc == 0) { 638 if (count) { 639 ring_consumed(&ttyiring, count); 640 returnValue = 1; 641 count = 0; 642 } 643 tbp = ttyiring.consume; 644 tcc = ring_full_consecutive(&ttyiring); 645 if (tcc == 0) { 646 break; 647 } 648 } 649 c = *tbp++ & 0xff, sc = strip(c), tcc--; count++; 650 if (sc == escape) { 651 command(0); 652 tcc = 0; 653 flushline = 1; 654 break; 655 } else if (MODE_LINE(globalmode) && (sc == echoc)) { 656 if (tcc > 0 && strip(*tbp) == echoc) { 657 tcc--; tbp++; count++; 658 } else { 659 dontlecho = !dontlecho; 660 settimer(echotoggle); 661 setconnmode(); 662 flushline = 1; 663 break; 664 } 665 } 666 if (localchars) { 667 if (TerminalSpecialChars(sc) == 0) { 668 break; 669 } 670 } 671 if (!myopts[TELOPT_BINARY]) { 672 switch (c) { 673 case '\n': 674 /* 675 * If we are in CRMOD mode (\r ==> \n) 676 * on our local machine, then probably 677 * a newline (unix) is CRLF (TELNET). 678 */ 679 if (MODE_LOCAL_CHARS(globalmode)) { 680 NETADD('\r'); 681 } 682 NETADD('\n'); 683 flushline = 1; 684 break; 685 case '\r': 686 if (!crlf) { 687 NET2ADD('\r', '\0'); 688 } else { 689 NET2ADD('\r', '\n'); 690 } 691 flushline = 1; 692 break; 693 case IAC: 694 NET2ADD(IAC, IAC); 695 break; 696 default: 697 NETADD(c); 698 break; 699 } 700 } else if (c == IAC) { 701 NET2ADD(IAC, IAC); 702 } else { 703 NETADD(c); 704 } 705 } 706 if (count) 707 ring_consumed(&ttyiring, count); 708 return returnValue||count; /* Non-zero if we did anything */ 709 } 710 711 /* 712 * Scheduler() 713 * 714 * Try to do something. 715 * 716 * If we do something useful, return 1; else return 0. 717 * 718 */ 719 720 721 int 722 Scheduler(block) 723 int block; /* should we block in the select ? */ 724 { 725 /* One wants to be a bit careful about setting returnValue 726 * to one, since a one implies we did some useful work, 727 * and therefore probably won't be called to block next 728 * time (TN3270 mode only). 729 */ 730 int returnValue; 731 int netin, netout, netex, ttyin, ttyout; 732 733 /* Decide which rings should be processed */ 734 735 netout = ring_full_count(&netoring) && 736 (!MODE_LINE(globalmode) || flushline || myopts[TELOPT_BINARY]); 737 ttyout = ring_full_count(&ttyoring); 738 739 #if defined(TN3270) 740 ttyin = ring_empty_count(&ttyiring) && (shell_active == 0); 741 #else /* defined(TN3270) */ 742 ttyin = ring_empty_count(&ttyiring); 743 #endif /* defined(TN3270) */ 744 745 #if defined(TN3270) 746 netin = ring_empty_count(&netiring); 747 # else /* !defined(TN3270) */ 748 netin = !ISend && ring_empty_count(&netiring); 749 # endif /* !defined(TN3270) */ 750 751 netex = !SYNCHing; 752 753 /* If we have seen a signal recently, reset things */ 754 # if defined(TN3270) && defined(unix) 755 if (HaveInput) { 756 HaveInput = 0; 757 signal(SIGIO, inputAvailable); 758 } 759 #endif /* defined(TN3270) && defined(unix) */ 760 761 /* Call to system code to process rings */ 762 763 returnValue = process_rings(netin, netout, netex, ttyin, ttyout, !block); 764 765 /* Now, look at the input rings, looking for work to do. */ 766 767 if (ring_full_count(&ttyiring)) { 768 # if defined(TN3270) 769 if (In3270) { 770 int c; 771 772 c = DataFromTerminal(ttyiring.consume, 773 ring_full_consecutive(&ttyiring)); 774 if (c) { 775 returnValue = 1; 776 ring_consumed(&ttyiring, c); 777 } 778 } else { 779 # endif /* defined(TN3270) */ 780 returnValue |= telsnd(); 781 # if defined(TN3270) 782 } 783 # endif /* defined(TN3270) */ 784 } 785 786 if (ring_full_count(&netiring)) { 787 # if !defined(TN3270) 788 returnValue |= telrcv(); 789 # else /* !defined(TN3270) */ 790 returnValue = Push3270(); 791 # endif /* !defined(TN3270) */ 792 } 793 return returnValue; 794 } 795 796 /* 797 * Select from tty and network... 798 */ 799 void 800 telnet() 801 { 802 sys_telnet_init(); 803 804 # if !defined(TN3270) 805 if (telnetport) { 806 if (!hisopts[TELOPT_SGA]) { 807 willoption(TELOPT_SGA, 0); 808 } 809 if (!myopts[TELOPT_TTYPE]) { 810 dooption(TELOPT_TTYPE); 811 } 812 } 813 # endif /* !defined(TN3270) */ 814 815 # if !defined(TN3270) 816 for (;;) { 817 int schedValue; 818 819 while ((schedValue = Scheduler(0)) != 0) { 820 if (schedValue == -1) { 821 setcommandmode(); 822 return; 823 } 824 } 825 826 if (Scheduler(1) == -1) { 827 setcommandmode(); 828 return; 829 } 830 } 831 # else /* !defined(TN3270) */ 832 for (;;) { 833 int schedValue; 834 835 while (!In3270 && !shell_active) { 836 if (Scheduler(1) == -1) { 837 setcommandmode(); 838 return; 839 } 840 } 841 842 while ((schedValue = Scheduler(0)) != 0) { 843 if (schedValue == -1) { 844 setcommandmode(); 845 return; 846 } 847 } 848 /* If there is data waiting to go out to terminal, don't 849 * schedule any more data for the terminal. 850 */ 851 if (ring_full_count(&ttyoring)) { 852 schedValue = 1; 853 } else { 854 if (shell_active) { 855 if (shell_continue() == 0) { 856 ConnectScreen(); 857 } 858 } else if (In3270) { 859 schedValue = DoTerminalOutput(); 860 } 861 } 862 if (schedValue && (shell_active == 0)) { 863 if (Scheduler(1) == -1) { 864 setcommandmode(); 865 return; 866 } 867 } 868 } 869 # endif /* !defined(TN3270) */ 870 } 871 872 #if 0 /* XXX - this not being in is a bug */ 873 /* 874 * nextitem() 875 * 876 * Return the address of the next "item" in the TELNET data 877 * stream. This will be the address of the next character if 878 * the current address is a user data character, or it will 879 * be the address of the character following the TELNET command 880 * if the current address is a TELNET IAC ("I Am a Command") 881 * character. 882 */ 883 884 static char * 885 nextitem(current) 886 char *current; 887 { 888 if ((*current&0xff) != IAC) { 889 return current+1; 890 } 891 switch (*(current+1)&0xff) { 892 case DO: 893 case DONT: 894 case WILL: 895 case WONT: 896 return current+3; 897 case SB: /* loop forever looking for the SE */ 898 { 899 register char *look = current+2; 900 901 for (;;) { 902 if ((*look++&0xff) == IAC) { 903 if ((*look++&0xff) == SE) { 904 return look; 905 } 906 } 907 } 908 } 909 default: 910 return current+2; 911 } 912 } 913 #endif /* 0 */ 914 915 /* 916 * netclear() 917 * 918 * We are about to do a TELNET SYNCH operation. Clear 919 * the path to the network. 920 * 921 * Things are a bit tricky since we may have sent the first 922 * byte or so of a previous TELNET command into the network. 923 * So, we have to scan the network buffer from the beginning 924 * until we are up to where we want to be. 925 * 926 * A side effect of what we do, just to keep things 927 * simple, is to clear the urgent data pointer. The principal 928 * caller should be setting the urgent data pointer AFTER calling 929 * us in any case. 930 */ 931 932 static void 933 netclear() 934 { 935 #if 0 /* XXX */ 936 register char *thisitem, *next; 937 char *good; 938 #define wewant(p) ((nfrontp > p) && ((*p&0xff) == IAC) && \ 939 ((*(p+1)&0xff) != EC) && ((*(p+1)&0xff) != EL)) 940 941 thisitem = netobuf; 942 943 while ((next = nextitem(thisitem)) <= netobuf.send) { 944 thisitem = next; 945 } 946 947 /* Now, thisitem is first before/at boundary. */ 948 949 good = netobuf; /* where the good bytes go */ 950 951 while (netoring.add > thisitem) { 952 if (wewant(thisitem)) { 953 int length; 954 955 next = thisitem; 956 do { 957 next = nextitem(next); 958 } while (wewant(next) && (nfrontp > next)); 959 length = next-thisitem; 960 memcpy(good, thisitem, length); 961 good += length; 962 thisitem = next; 963 } else { 964 thisitem = nextitem(thisitem); 965 } 966 } 967 968 #endif /* 0 */ 969 } 970 971 /* 972 * These routines add various telnet commands to the data stream. 973 */ 974 975 static void 976 doflush() 977 { 978 NET2ADD(IAC, DO); 979 NETADD(TELOPT_TM); 980 flushline = 1; 981 flushout = 1; 982 ttyflush(1); /* Flush/drop output */ 983 /* do printoption AFTER flush, otherwise the output gets tossed... */ 984 printoption("<SENT", doopt, TELOPT_TM, 0); 985 } 986 987 void 988 xmitAO() 989 { 990 NET2ADD(IAC, AO); 991 if (autoflush) { 992 doflush(); 993 } 994 } 995 996 997 void 998 xmitEL() 999 { 1000 NET2ADD(IAC, EL); 1001 } 1002 1003 void 1004 xmitEC() 1005 { 1006 NET2ADD(IAC, EC); 1007 } 1008 1009 1010 #if defined(NOT43) 1011 int 1012 #else /* defined(NOT43) */ 1013 void 1014 #endif /* defined(NOT43) */ 1015 dosynch() 1016 { 1017 netclear(); /* clear the path to the network */ 1018 NETADD(IAC); 1019 setneturg(); 1020 NETADD(DM); 1021 1022 #if defined(NOT43) 1023 return 0; 1024 #endif /* defined(NOT43) */ 1025 } 1026 1027 void 1028 intp() 1029 { 1030 NET2ADD(IAC, IP); 1031 flushline = 1; 1032 if (autoflush) { 1033 doflush(); 1034 } 1035 if (autosynch) { 1036 dosynch(); 1037 } 1038 } 1039 1040 void 1041 sendbrk() 1042 { 1043 NET2ADD(IAC, BREAK); 1044 flushline = 1; 1045 if (autoflush) { 1046 doflush(); 1047 } 1048 if (autosynch) { 1049 dosynch(); 1050 } 1051 } 1052