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