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