|
|
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 provided ! 6: * that: (1) source distributions retain this entire copyright notice and ! 7: * comment, and (2) distributions including binaries display the following ! 8: * acknowledgement: ``This product includes software developed by the ! 9: * University of California, Berkeley and its contributors'' in the ! 10: * documentation or other materials provided with the distribution and in ! 11: * all advertising materials mentioning features or use of this software. ! 12: * Neither the name of the University nor the names of its contributors may ! 13: * be used to endorse or promote products derived from this software without ! 14: * specific prior written permission. ! 15: * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED ! 16: * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF ! 17: * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. ! 18: */ ! 19: ! 20: #ifndef lint ! 21: static char sccsid[] = "@(#)telnet.c 5.50 (Berkeley) 6/28/90"; ! 22: #endif /* not lint */ ! 23: ! 24: #include <sys/types.h> ! 25: ! 26: #ifdef KERBEROS ! 27: #include <sys/socket.h> ! 28: #include <netinet/in.h> ! 29: #include <kerberosIV/des.h> ! 30: #include <kerberosIV/krb.h> ! 31: #include "krb4-proto.h" ! 32: #endif ! 33: ! 34: #if defined(unix) ! 35: #include <signal.h> ! 36: /* By the way, we need to include curses.h before telnet.h since, ! 37: * among other things, telnet.h #defines 'DO', which is a variable ! 38: * declared in curses.h. ! 39: */ ! 40: #endif /* defined(unix) */ ! 41: ! 42: #include <arpa/telnet.h> ! 43: ! 44: #if defined(unix) ! 45: #include <strings.h> ! 46: #else /* defined(unix) */ ! 47: #include <string.h> ! 48: #endif /* defined(unix) */ ! 49: ! 50: #include <ctype.h> ! 51: ! 52: #include "ring.h" ! 53: ! 54: #include "defines.h" ! 55: #include "externs.h" ! 56: #include "types.h" ! 57: #include "general.h" ! 58: ! 59: ! 60: #define strip(x) ((x)&0x7f) ! 61: ! 62: extern char *env_getvalue(); ! 63: ! 64: static char subbuffer[SUBBUFSIZE], ! 65: *subpointer, *subend; /* buffer for sub-options */ ! 66: #define SB_CLEAR() subpointer = subbuffer; ! 67: #define SB_TERM() subend = subpointer; ! 68: #define SB_ACCUM(c) if (subpointer < (subbuffer+sizeof subbuffer)) { \ ! 69: *subpointer++ = (c); \ ! 70: } ! 71: ! 72: char options[256]; /* The combined options */ ! 73: char do_dont_resp[256]; ! 74: char will_wont_resp[256]; ! 75: ! 76: int ! 77: connected, ! 78: showoptions, ! 79: In3270, /* Are we in 3270 mode? */ ! 80: ISend, /* trying to send network data in */ ! 81: #ifdef KERBEROS ! 82: kerberized = 0, /* Are we using Kerberos authentication ? */ ! 83: #endif ! 84: debug = 0, ! 85: crmod, ! 86: netdata, /* Print out network data flow */ ! 87: crlf, /* Should '\r' be mapped to <CR><LF> (or <CR><NUL>)? */ ! 88: #if defined(TN3270) ! 89: noasynchtty = 0,/* User specified "-noasynch" on command line */ ! 90: noasynchnet = 0,/* User specified "-noasynch" on command line */ ! 91: askedSGA = 0, /* We have talked about suppress go ahead */ ! 92: #endif /* defined(TN3270) */ ! 93: telnetport, ! 94: SYNCHing, /* we are in TELNET SYNCH mode */ ! 95: flushout, /* flush output */ ! 96: autoflush = 0, /* flush output when interrupting? */ ! 97: autosynch, /* send interrupt characters with SYNCH? */ ! 98: localflow, /* we handle flow control locally */ ! 99: localchars, /* we recognize interrupt/quit */ ! 100: donelclchars, /* the user has set "localchars" */ ! 101: donebinarytoggle, /* the user has put us in binary */ ! 102: dontlecho, /* do we suppress local echoing right now? */ ! 103: globalmode; ! 104: ! 105: char *prompt = 0; ! 106: ! 107: cc_t escape; ! 108: #ifdef KLUDGELINEMODE ! 109: cc_t echoc; ! 110: #endif ! 111: ! 112: /* ! 113: * Telnet receiver states for fsm ! 114: */ ! 115: #define TS_DATA 0 ! 116: #define TS_IAC 1 ! 117: #define TS_WILL 2 ! 118: #define TS_WONT 3 ! 119: #define TS_DO 4 ! 120: #define TS_DONT 5 ! 121: #define TS_CR 6 ! 122: #define TS_SB 7 /* sub-option collection */ ! 123: #define TS_SE 8 /* looking for sub-option end */ ! 124: ! 125: static int telrcv_state; ! 126: ! 127: jmp_buf toplevel = { 0 }; ! 128: jmp_buf peerdied; ! 129: ! 130: int flushline; ! 131: int linemode; ! 132: ! 133: #ifdef KLUDGELINEMODE ! 134: int kludgelinemode = 1; ! 135: #endif ! 136: ! 137: /* ! 138: * The following are some clocks used to decide how to interpret ! 139: * the relationship between various variables. ! 140: */ ! 141: ! 142: Clocks clocks; ! 143: ! 144: #ifdef notdef ! 145: Modelist modelist[] = { ! 146: { "telnet command mode", COMMAND_LINE }, ! 147: { "character-at-a-time mode", 0 }, ! 148: { "character-at-a-time mode (local echo)", LOCAL_ECHO|LOCAL_CHARS }, ! 149: { "line-by-line mode (remote echo)", LINE | LOCAL_CHARS }, ! 150: { "line-by-line mode", LINE | LOCAL_ECHO | LOCAL_CHARS }, ! 151: { "line-by-line mode (local echoing suppressed)", LINE | LOCAL_CHARS }, ! 152: { "3270 mode", 0 }, ! 153: }; ! 154: #endif ! 155: ! 156: ! 157: /* ! 158: * Initialize telnet environment. ! 159: */ ! 160: ! 161: init_telnet() ! 162: { ! 163: env_init(); ! 164: ! 165: SB_CLEAR(); ! 166: ClearArray(options); ! 167: ! 168: connected = In3270 = ISend = localflow = donebinarytoggle = 0; ! 169: ! 170: SYNCHing = 0; ! 171: ! 172: /* Don't change NetTrace */ ! 173: ! 174: escape = CONTROL(']'); ! 175: #ifdef KLUDGELINEMODE ! 176: echoc = CONTROL('E'); ! 177: #endif ! 178: ! 179: flushline = 1; ! 180: telrcv_state = TS_DATA; ! 181: } ! 182: ! 183: ! 184: #ifdef notdef ! 185: #include <varargs.h> ! 186: ! 187: /*VARARGS*/ ! 188: static void ! 189: printring(va_alist) ! 190: va_dcl ! 191: { ! 192: va_list ap; ! 193: char buffer[100]; /* where things go */ ! 194: char *ptr; ! 195: char *format; ! 196: char *string; ! 197: Ring *ring; ! 198: int i; ! 199: ! 200: va_start(ap); ! 201: ! 202: ring = va_arg(ap, Ring *); ! 203: format = va_arg(ap, char *); ! 204: ptr = buffer; ! 205: ! 206: while ((i = *format++) != 0) { ! 207: if (i == '%') { ! 208: i = *format++; ! 209: switch (i) { ! 210: case 'c': ! 211: *ptr++ = va_arg(ap, int); ! 212: break; ! 213: case 's': ! 214: string = va_arg(ap, char *); ! 215: ring_supply_data(ring, buffer, ptr-buffer); ! 216: ring_supply_data(ring, string, strlen(string)); ! 217: ptr = buffer; ! 218: break; ! 219: case 0: ! 220: ExitString("printring: trailing %%.\n", 1); ! 221: /*NOTREACHED*/ ! 222: default: ! 223: ExitString("printring: unknown format character.\n", 1); ! 224: /*NOTREACHED*/ ! 225: } ! 226: } else { ! 227: *ptr++ = i; ! 228: } ! 229: } ! 230: ring_supply_data(ring, buffer, ptr-buffer); ! 231: } ! 232: #endif ! 233: ! 234: /* ! 235: * These routines are in charge of sending option negotiations ! 236: * to the other side. ! 237: * ! 238: * The basic idea is that we send the negotiation if either side ! 239: * is in disagreement as to what the current state should be. ! 240: */ ! 241: ! 242: send_do(c, init) ! 243: register int c, init; ! 244: { ! 245: if (init) { ! 246: if (((do_dont_resp[c] == 0) && my_state_is_do(c)) || ! 247: my_want_state_is_do(c)) ! 248: return; ! 249: set_my_want_state_do(c); ! 250: do_dont_resp[c]++; ! 251: } ! 252: NET2ADD(IAC, DO); ! 253: NETADD(c); ! 254: printoption("SENT", "do", c); ! 255: } ! 256: ! 257: void ! 258: send_dont(c, init) ! 259: register int c, init; ! 260: { ! 261: if (init) { ! 262: if (((do_dont_resp[c] == 0) && my_state_is_dont(c)) || ! 263: my_want_state_is_dont(c)) ! 264: return; ! 265: set_my_want_state_dont(c); ! 266: do_dont_resp[c]++; ! 267: } ! 268: NET2ADD(IAC, DONT); ! 269: NETADD(c); ! 270: printoption("SENT", "dont", c); ! 271: } ! 272: ! 273: void ! 274: send_will(c, init) ! 275: register int c, init; ! 276: { ! 277: if (init) { ! 278: if (((will_wont_resp[c] == 0) && my_state_is_will(c)) || ! 279: my_want_state_is_will(c)) ! 280: return; ! 281: set_my_want_state_will(c); ! 282: will_wont_resp[c]++; ! 283: } ! 284: NET2ADD(IAC, WILL); ! 285: NETADD(c); ! 286: printoption("SENT", "will", c); ! 287: } ! 288: ! 289: void ! 290: send_wont(c, init) ! 291: register int c, init; ! 292: { ! 293: if (init) { ! 294: if (((will_wont_resp[c] == 0) && my_state_is_wont(c)) || ! 295: my_want_state_is_wont(c)) ! 296: return; ! 297: set_my_want_state_wont(c); ! 298: will_wont_resp[c]++; ! 299: } ! 300: NET2ADD(IAC, WONT); ! 301: NETADD(c); ! 302: printoption("SENT", "wont", c); ! 303: } ! 304: ! 305: ! 306: void ! 307: willoption(option) ! 308: int option; ! 309: { ! 310: int new_state_ok = 0; ! 311: ! 312: if (do_dont_resp[option]) { ! 313: --do_dont_resp[option]; ! 314: if (do_dont_resp[option] && my_state_is_do(option)) ! 315: --do_dont_resp[option]; ! 316: } ! 317: ! 318: if ((do_dont_resp[option] == 0) && my_want_state_is_dont(option)) { ! 319: ! 320: switch (option) { ! 321: ! 322: case TELOPT_ECHO: ! 323: # if defined(TN3270) ! 324: /* ! 325: * The following is a pain in the rear-end. ! 326: * Various IBM servers (some versions of Wiscnet, ! 327: * possibly Fibronics/Spartacus, and who knows who ! 328: * else) will NOT allow us to send "DO SGA" too early ! 329: * in the setup proceedings. On the other hand, ! 330: * 4.2 servers (telnetd) won't set SGA correctly. ! 331: * So, we are stuck. Empirically (but, based on ! 332: * a VERY small sample), the IBM servers don't send ! 333: * out anything about ECHO, so we postpone our sending ! 334: * "DO SGA" until we see "WILL ECHO" (which 4.2 servers ! 335: * DO send). ! 336: */ ! 337: { ! 338: if (askedSGA == 0) { ! 339: askedSGA = 1; ! 340: if (my_want_state_is_dont(TELOPT_SGA)) ! 341: send_do(TELOPT_SGA, 1); ! 342: } ! 343: } ! 344: /* Fall through */ ! 345: case TELOPT_EOR: ! 346: #endif /* defined(TN3270) */ ! 347: case TELOPT_BINARY: ! 348: case TELOPT_SGA: ! 349: settimer(modenegotiated); ! 350: /* FALL THROUGH */ ! 351: case TELOPT_STATUS: ! 352: new_state_ok = 1; ! 353: break; ! 354: ! 355: case TELOPT_TM: ! 356: if (flushout) ! 357: flushout = 0; ! 358: /* ! 359: * Special case for TM. If we get back a WILL, ! 360: * pretend we got back a WONT. ! 361: */ ! 362: set_my_want_state_dont(option); ! 363: set_my_state_dont(option); ! 364: return; /* Never reply to TM will's/wont's */ ! 365: ! 366: case TELOPT_LINEMODE: ! 367: default: ! 368: break; ! 369: } ! 370: ! 371: if (new_state_ok) { ! 372: set_my_want_state_do(option); ! 373: send_do(option, 0); ! 374: setconnmode(0); /* possibly set new tty mode */ ! 375: } else { ! 376: do_dont_resp[option]++; ! 377: send_dont(option, 0); ! 378: } ! 379: } ! 380: set_my_state_do(option); ! 381: } ! 382: ! 383: void ! 384: wontoption(option) ! 385: int option; ! 386: { ! 387: if (do_dont_resp[option]) { ! 388: --do_dont_resp[option]; ! 389: if (do_dont_resp[option] && my_state_is_dont(option)) ! 390: --do_dont_resp[option]; ! 391: } ! 392: ! 393: if ((do_dont_resp[option] == 0) && my_want_state_is_do(option)) { ! 394: ! 395: switch (option) { ! 396: ! 397: #ifdef KLUDGELINEMODE ! 398: case TELOPT_SGA: ! 399: if (!kludgelinemode) ! 400: break; ! 401: /* FALL THROUGH */ ! 402: #endif ! 403: case TELOPT_ECHO: ! 404: settimer(modenegotiated); ! 405: break; ! 406: ! 407: case TELOPT_TM: ! 408: if (flushout) ! 409: flushout = 0; ! 410: set_my_want_state_dont(option); ! 411: set_my_state_dont(option); ! 412: return; /* Never reply to TM will's/wont's */ ! 413: ! 414: default: ! 415: break; ! 416: } ! 417: set_my_want_state_dont(option); ! 418: if (my_state_is_do(option)) ! 419: send_dont(option, 0); ! 420: setconnmode(0); /* Set new tty mode */ ! 421: } else if (option == TELOPT_TM) { ! 422: /* ! 423: * Special case for TM. ! 424: */ ! 425: if (flushout) ! 426: flushout = 0; ! 427: set_my_want_state_dont(option); ! 428: } ! 429: set_my_state_dont(option); ! 430: } ! 431: ! 432: static void ! 433: dooption(option) ! 434: int option; ! 435: { ! 436: int new_state_ok = 0; ! 437: ! 438: if (will_wont_resp[option]) { ! 439: --will_wont_resp[option]; ! 440: if (will_wont_resp[option] && my_state_is_will(option)) ! 441: --will_wont_resp[option]; ! 442: } ! 443: ! 444: if (will_wont_resp[option] == 0) { ! 445: if (my_want_state_is_wont(option)) { ! 446: ! 447: switch (option) { ! 448: ! 449: case TELOPT_TM: ! 450: /* ! 451: * Special case for TM. We send a WILL, but pretend ! 452: * we sent WONT. ! 453: */ ! 454: send_will(option, 0); ! 455: set_my_want_state_wont(TELOPT_TM); ! 456: set_my_state_wont(TELOPT_TM); ! 457: return; ! 458: ! 459: #ifdef KERBEROS ! 460: case TELOPT_AUTHENTICATION: ! 461: if (kerberized) ! 462: new_state_ok = 1; ! 463: break; ! 464: #endif ! 465: # if defined(TN3270) ! 466: case TELOPT_EOR: /* end of record */ ! 467: # endif /* defined(TN3270) */ ! 468: case TELOPT_BINARY: /* binary mode */ ! 469: case TELOPT_NAWS: /* window size */ ! 470: case TELOPT_TSPEED: /* terminal speed */ ! 471: case TELOPT_LFLOW: /* local flow control */ ! 472: case TELOPT_TTYPE: /* terminal type option */ ! 473: case TELOPT_SGA: /* no big deal */ ! 474: case TELOPT_ENVIRON: /* environment variable option */ ! 475: new_state_ok = 1; ! 476: break; ! 477: ! 478: case TELOPT_XDISPLOC: /* X Display location */ ! 479: if (env_getvalue("DISPLAY")) ! 480: new_state_ok = 1; ! 481: break; ! 482: ! 483: case TELOPT_LINEMODE: ! 484: #ifdef KLUDGELINEMODE ! 485: kludgelinemode = 0; ! 486: send_do(TELOPT_SGA, 1); ! 487: #endif ! 488: set_my_want_state_will(TELOPT_LINEMODE); ! 489: send_will(option, 0); ! 490: set_my_state_will(TELOPT_LINEMODE); ! 491: slc_init(); ! 492: return; ! 493: ! 494: case TELOPT_ECHO: /* We're never going to echo... */ ! 495: default: ! 496: break; ! 497: } ! 498: ! 499: if (new_state_ok) { ! 500: set_my_want_state_will(option); ! 501: send_will(option, 0); ! 502: } else { ! 503: will_wont_resp[option]++; ! 504: send_wont(option, 0); ! 505: } ! 506: } else { ! 507: /* ! 508: * Handle options that need more things done after the ! 509: * other side has acknowledged the option. ! 510: */ ! 511: switch (option) { ! 512: case TELOPT_LINEMODE: ! 513: #ifdef KLUDGELINEMODE ! 514: kludgelinemode = 0; ! 515: send_do(TELOPT_SGA, 1); ! 516: #endif ! 517: set_my_state_will(option); ! 518: slc_init(); ! 519: send_do(TELOPT_SGA, 0); ! 520: return; ! 521: } ! 522: } ! 523: } ! 524: set_my_state_will(option); ! 525: } ! 526: ! 527: static void ! 528: dontoption(option) ! 529: int option; ! 530: { ! 531: ! 532: if (will_wont_resp[option]) { ! 533: --will_wont_resp[option]; ! 534: if (will_wont_resp[option] && my_state_is_wont(option)) ! 535: --will_wont_resp[option]; ! 536: } ! 537: ! 538: if ((will_wont_resp[option] == 0) && my_want_state_is_will(option)) { ! 539: switch (option) { ! 540: case TELOPT_LINEMODE: ! 541: linemode = 0; /* put us back to the default state */ ! 542: break; ! 543: } ! 544: /* we always accept a DONT */ ! 545: set_my_want_state_wont(option); ! 546: if (my_state_is_will(option)) ! 547: send_wont(option, 0); ! 548: setconnmode(0); /* Set new tty mode */ ! 549: } ! 550: set_my_state_wont(option); ! 551: } ! 552: ! 553: /* ! 554: * Given a buffer returned by tgetent(), this routine will turn ! 555: * the pipe seperated list of names in the buffer into an array ! 556: * of pointers to null terminated names. We toss out any bad, ! 557: * duplicate, or verbose names (names with spaces). ! 558: */ ! 559: ! 560: static char *unknown[] = { "UNKNOWN", 0 }; ! 561: ! 562: char ** ! 563: mklist(buf, name) ! 564: char *buf, *name; ! 565: { ! 566: register int n; ! 567: register char c, *cp, **argvp, *cp2, **argv; ! 568: char *malloc(); ! 569: ! 570: if (name) { ! 571: if (strlen(name) > 40) ! 572: name = 0; ! 573: else { ! 574: unknown[0] = name; ! 575: upcase(name); ! 576: } ! 577: } ! 578: /* ! 579: * Count up the number of names. ! 580: */ ! 581: for (n = 1, cp = buf; *cp && *cp != ':'; cp++) { ! 582: if (*cp == '|') ! 583: n++; ! 584: } ! 585: /* ! 586: * Allocate an array to put the name pointers into ! 587: */ ! 588: argv = (char **)malloc((n+3)*sizeof(char *)); ! 589: if (argv == 0) ! 590: return(unknown); ! 591: ! 592: /* ! 593: * Fill up the array of pointers to names. ! 594: */ ! 595: *argv = 0; ! 596: argvp = argv+1; ! 597: n = 0; ! 598: for (cp = cp2 = buf; (c = *cp); cp++) { ! 599: if (c == '|' || c == ':') { ! 600: *cp++ = '\0'; ! 601: /* ! 602: * Skip entries that have spaces or are over 40 ! 603: * characters long. If this is our environment ! 604: * name, then put it up front. Otherwise, as ! 605: * long as this is not a duplicate name (case ! 606: * insensitive) add it to the list. ! 607: */ ! 608: if (n || (cp - cp2 > 41)) ! 609: ; ! 610: else if (name && (strncasecmp(name, cp2, cp-cp2) == 0)) ! 611: *argv = cp2; ! 612: else if (is_unique(cp2, argv+1, argvp)) ! 613: *argvp++ = cp2; ! 614: if (c == ':') ! 615: break; ! 616: /* ! 617: * Skip multiple delimiters. Reset cp2 to ! 618: * the beginning of the next name. Reset n, ! 619: * the flag for names with spaces. ! 620: */ ! 621: while ((c = *cp) == '|') ! 622: cp++; ! 623: cp2 = cp; ! 624: n = 0; ! 625: } ! 626: /* ! 627: * Skip entries with spaces or non-ascii values. ! 628: * Convert lower case letters to upper case. ! 629: */ ! 630: if ((c == ' ') || !isascii(c)) ! 631: n = 1; ! 632: else if (islower(c)) ! 633: *cp = toupper(c); ! 634: } ! 635: ! 636: /* ! 637: * Check for an old V6 2 character name. If the second ! 638: * name points to the beginning of the buffer, and is ! 639: * only 2 characters long, move it to the end of the array. ! 640: */ ! 641: if ((argv[1] == buf) && (strlen(argv[1]) == 2)) { ! 642: *argvp++ = buf; ! 643: cp = *argv++; ! 644: *argv = cp; ! 645: } ! 646: ! 647: /* ! 648: * Duplicate last name, for TTYPE option, and null ! 649: * terminate the array. If we didn't find a match on ! 650: * our terminal name, put that name at the beginning. ! 651: */ ! 652: cp = *(argvp-1); ! 653: *argvp++ = cp; ! 654: *argvp = 0; ! 655: ! 656: if (*argv == 0) { ! 657: if (name) ! 658: *argv = name; ! 659: else ! 660: argv++; ! 661: } ! 662: if (*argv) ! 663: return(argv); ! 664: else ! 665: return(unknown); ! 666: } ! 667: ! 668: is_unique(name, as, ae) ! 669: register char *name, **as, **ae; ! 670: { ! 671: register char **ap; ! 672: register int n; ! 673: ! 674: n = strlen(name) + 1; ! 675: for (ap = as; ap < ae; ap++) ! 676: if (strncasecmp(*ap, name, n) == 0) ! 677: return(0); ! 678: return (1); ! 679: } ! 680: ! 681: #ifdef TERMCAP ! 682: char termbuf[1024]; ! 683: /*ARGSUSED*/ ! 684: setupterm(tname, fd, errp) ! 685: char *tname; ! 686: int fd, *errp; ! 687: { ! 688: if (tgetent(termbuf, tname) == 1) { ! 689: termbuf[1023] = '\0'; ! 690: if (errp) ! 691: *errp = 1; ! 692: return(0); ! 693: } ! 694: if (errp) ! 695: *errp = 0; ! 696: return(-1); ! 697: } ! 698: #else ! 699: #define termbuf ttytype ! 700: extern char ttytype[]; ! 701: #endif ! 702: ! 703: char * ! 704: gettermname() ! 705: { ! 706: char *tname; ! 707: static int first = 1; ! 708: static char **tnamep; ! 709: static char **next; ! 710: int err; ! 711: ! 712: if (first) { ! 713: first = 0; ! 714: if ((tname = env_getvalue("TERM")) && ! 715: (setupterm(tname, 1, &err) == 0)) { ! 716: tnamep = mklist(termbuf, tname); ! 717: } else { ! 718: if (tname && (strlen(tname) <= 40)) { ! 719: unknown[0] = tname; ! 720: upcase(tname); ! 721: } ! 722: tnamep = unknown; ! 723: } ! 724: next = tnamep; ! 725: } ! 726: if (*next == 0) ! 727: next = tnamep; ! 728: return(*next++); ! 729: } ! 730: /* ! 731: * suboption() ! 732: * ! 733: * Look at the sub-option buffer, and try to be helpful to the other ! 734: * side. ! 735: * ! 736: * Currently we recognize: ! 737: * ! 738: * Terminal type, send request. ! 739: * Terminal speed (send request). ! 740: * Local flow control (is request). ! 741: * Linemode ! 742: */ ! 743: ! 744: static void ! 745: suboption() ! 746: { ! 747: printsub('<', subbuffer, subend-subbuffer+2); ! 748: switch (subbuffer[0]&0xff) { ! 749: case TELOPT_TTYPE: ! 750: if (my_want_state_is_wont(TELOPT_TTYPE)) ! 751: return; ! 752: if ((subbuffer[1]&0xff) != TELQUAL_SEND) { ! 753: ; ! 754: } else { ! 755: char *name; ! 756: char temp[50]; ! 757: int len; ! 758: ! 759: #if defined(TN3270) ! 760: if (tn3270_ttype()) { ! 761: return; ! 762: } ! 763: #endif /* defined(TN3270) */ ! 764: name = gettermname(); ! 765: len = strlen(name) + 4 + 2; ! 766: if (len < NETROOM()) { ! 767: sprintf(temp, "%c%c%c%c%s%c%c", IAC, SB, TELOPT_TTYPE, ! 768: TELQUAL_IS, name, IAC, SE); ! 769: ring_supply_data(&netoring, temp, len); ! 770: printsub('>', &temp[2], len-2); ! 771: } else { ! 772: ExitString("No room in buffer for terminal type.\n", 1); ! 773: /*NOTREACHED*/ ! 774: } ! 775: } ! 776: break; ! 777: case TELOPT_TSPEED: ! 778: if (my_want_state_is_wont(TELOPT_TSPEED)) ! 779: return; ! 780: if ((subbuffer[1]&0xff) == TELQUAL_SEND) { ! 781: int ospeed, ispeed; ! 782: char temp[50]; ! 783: int len; ! 784: ! 785: TerminalSpeeds(&ispeed, &ospeed); ! 786: ! 787: sprintf(temp, "%c%c%c%c%d,%d%c%c", IAC, SB, TELOPT_TSPEED, ! 788: TELQUAL_IS, ospeed, ispeed, IAC, SE); ! 789: len = strlen(temp+4) + 4; /* temp[3] is 0 ... */ ! 790: ! 791: if (len < NETROOM()) { ! 792: ring_supply_data(&netoring, temp, len); ! 793: printsub('>', temp+2, len - 2); ! 794: } ! 795: /*@*/ else printf("lm_will: not enough room in buffer\n"); ! 796: } ! 797: break; ! 798: case TELOPT_LFLOW: ! 799: if (my_want_state_is_wont(TELOPT_LFLOW)) ! 800: return; ! 801: if ((subbuffer[1]&0xff) == 1) { ! 802: localflow = 1; ! 803: } else if ((subbuffer[1]&0xff) == 0) { ! 804: localflow = 0; ! 805: } ! 806: setcommandmode(); ! 807: setconnmode(0); ! 808: break; ! 809: ! 810: case TELOPT_LINEMODE: ! 811: if (my_want_state_is_wont(TELOPT_LINEMODE)) ! 812: return; ! 813: switch (subbuffer[1]&0xff) { ! 814: case WILL: ! 815: lm_will(&subbuffer[2], subend - &subbuffer[2]); ! 816: break; ! 817: case WONT: ! 818: lm_wont(&subbuffer[2], subend - &subbuffer[2]); ! 819: break; ! 820: case DO: ! 821: lm_do(&subbuffer[2], subend - &subbuffer[2]); ! 822: break; ! 823: case DONT: ! 824: lm_dont(&subbuffer[2], subend - &subbuffer[2]); ! 825: break; ! 826: case LM_SLC: ! 827: slc(&subbuffer[2], subend - &subbuffer[2]); ! 828: break; ! 829: case LM_MODE: ! 830: lm_mode(&subbuffer[2], subend - &subbuffer[2], 0); ! 831: break; ! 832: default: ! 833: break; ! 834: } ! 835: break; ! 836: ! 837: case TELOPT_ENVIRON: ! 838: switch(subbuffer[1]&0xff) { ! 839: case TELQUAL_IS: ! 840: case TELQUAL_INFO: ! 841: if (my_want_state_is_dont(TELOPT_ENVIRON)) ! 842: return; ! 843: break; ! 844: case TELQUAL_SEND: ! 845: if (my_want_state_is_wont(TELOPT_ENVIRON)) { ! 846: return; ! 847: } ! 848: break; ! 849: default: ! 850: return; ! 851: } ! 852: env_opt(&subbuffer[1], subend - &subbuffer[1]); ! 853: break; ! 854: ! 855: case TELOPT_XDISPLOC: ! 856: if (my_want_state_is_wont(TELOPT_XDISPLOC)) ! 857: return; ! 858: if ((subbuffer[1]&0xff) == TELQUAL_SEND) { ! 859: char temp[50], *dp; ! 860: int len; ! 861: ! 862: if ((dp = env_getvalue("DISPLAY")) == NULL) { ! 863: /* ! 864: * Something happened, we no longer have a DISPLAY ! 865: * variable. So, turn off the option. ! 866: */ ! 867: send_wont(TELOPT_XDISPLOC, 1); ! 868: break; ! 869: } ! 870: sprintf(temp, "%c%c%c%c%s%c%c", IAC, SB, TELOPT_XDISPLOC, ! 871: TELQUAL_IS, dp, IAC, SE); ! 872: len = strlen(temp+4) + 4; /* temp[3] is 0 ... */ ! 873: ! 874: if (len < NETROOM()) { ! 875: ring_supply_data(&netoring, temp, len); ! 876: printsub('>', temp+2, len - 2); ! 877: } ! 878: /*@*/ else printf("lm_will: not enough room in buffer\n"); ! 879: } ! 880: break; ! 881: ! 882: #ifdef KERBEROS ! 883: case TELOPT_AUTHENTICATION: ! 884: if ((subbuffer[1] & 0xff) == TELQUAL_SEND) { ! 885: register char *cp = &subbuffer[2]; ! 886: char tmp[256]; ! 887: int dokrb4 = 0, unknowntypes = 0, noresponse = 1; ! 888: ! 889: while (cp < subend) { ! 890: switch (*cp) { ! 891: case TELQUAL_AUTHTYPE_KERBEROS_V4: ! 892: dokrb4 = 1; ! 893: break; ! 894: default: ! 895: unknowntypes++; ! 896: } ! 897: cp++; ! 898: } ! 899: ! 900: if (noresponse && dokrb4) { ! 901: register unsigned char *ucp = (unsigned char *)cp; ! 902: char *krb_realm; ! 903: char hst_inst[INST_SZ]; ! 904: KTEXT_ST authent_st; ! 905: int space = 0; ! 906: int retval; ! 907: extern char *krb_realmofhost(), *krb_get_phost(); ! 908: ! 909: fprintf(stderr, ! 910: "[Trying Kerberos V4 authentication]\n"); ! 911: ! 912: krb_realm = krb_get_phost(hostname); ! 913: bzero(hst_inst, sizeof(hst_inst)); ! 914: if (krb_realm) ! 915: strncpy(hst_inst, krb_realm, sizeof(hst_inst)); ! 916: hst_inst[sizeof(hst_inst)-1] = '\0'; ! 917: if (!(krb_realm = krb_realmofhost(hst_inst))) { ! 918: fprintf(stderr, "no realm for %s\n", hostname); ! 919: goto cantsend4; ! 920: } ! 921: if (retval = krb_mk_req(&authent_st, "rcmd", hst_inst, ! 922: krb_realm, 0L)) { ! 923: fprintf(stderr, "mk_req failed: %s\n", ! 924: krb_err_txt[retval]); ! 925: goto cantsend4; ! 926: } ! 927: space = authent_st.length; ! 928: for (ucp = authent_st.dat; ucp < authent_st.dat + ! 929: authent_st.length; ucp++) { ! 930: if (*ucp == IAC) ! 931: space++; ! 932: } ! 933: if (NETROOM() < 6 + 1 + 2 + ! 934: space + 2) { ! 935: fprintf(stderr, ! 936: "no room to send V4 ticket/authenticator\n"); ! 937: cantsend4: ! 938: if (7 < NETROOM()) { ! 939: printring(&netoring, "%c%c%c%c%c%c%c", IAC, SB, ! 940: TELOPT_AUTHENTICATION, ! 941: TELQUAL_IS, TELQUAL_AUTHTYPE_NONE, IAC, SE); ! 942: sprintf(tmp, "%c%c%c%c%c", TELOPT_AUTHENTICATION, ! 943: TELQUAL_IS, TELQUAL_AUTHTYPE_NONE, IAC, SE); ! 944: printsub(">", tmp, 4+2-2-2); ! 945: } else ! 946: exit(1); ! 947: } else { ! 948: #ifdef notdef ! 949: printring(&netoring, "%c%c%c%c%c%c", IAC, SB, ! 950: TELOPT_AUTHENTICATION, ! 951: TELQUAL_IS, TELQUAL_AUTHTYPE_KERBEROS, ! 952: TELQUAL_AUTHTYPE_KERBEROS_V4); ! 953: sprintf(tmp, "%c%c%c%c%c%c", TELOPT_AUTHENTICATION, ! 954: TELQUAL_IS, TELQUAL_AUTHTYPE_KERBEROS, ! 955: TELQUAL_AUTHTYPE_KERBEROS_V4, IAC, SE); ! 956: #else ! 957: printring(&netoring, "%c%c%c%c%c", IAC, SB, ! 958: TELOPT_AUTHENTICATION, ! 959: TELQUAL_IS, ! 960: TELQUAL_AUTHTYPE_KERBEROS_V4); ! 961: sprintf(tmp, "%c%c%c%c%c", TELOPT_AUTHENTICATION, ! 962: TELQUAL_IS, ! 963: TELQUAL_AUTHTYPE_KERBEROS_V4, IAC, SE); ! 964: #endif ! 965: printsub(">", tmp, 4+2-2-2); ! 966: ring_supply_bindata(&netoring, ! 967: (char *)authent_st.dat, authent_st.length, IAC); ! 968: printring(&netoring, "%c%c", IAC, SE); ! 969: } ! 970: noresponse = 0; ! 971: } ! 972: if (noresponse) { ! 973: if (NETROOM() < 7) { ! 974: ExitString("not enough room to reject unhandled authtype\n", 1); ! 975: } else { ! 976: fprintf(stderr,"[Sending empty auth info in response to request for %d unknown type(s):\n\t", unknowntypes); ! 977: #ifdef notdef ! 978: cp = &subbuffer[3]; ! 979: #else ! 980: cp = &subbuffer[2]; ! 981: #endif ! 982: while (cp < subend) { ! 983: switch (*cp) { ! 984: case TELQUAL_AUTHTYPE_KERBEROS_V4: ! 985: break; ! 986: default: ! 987: fprintf(stderr, "%d,", *cp); ! 988: break; ! 989: } ! 990: cp++; ! 991: } ! 992: fputs("]\n", stderr); ! 993: printring(&netoring, "%c%c%c%c%c%c%c", IAC, SB, ! 994: TELOPT_AUTHENTICATION, ! 995: TELQUAL_IS, TELQUAL_AUTHTYPE_NONE, IAC, SE); ! 996: } ! 997: } ! 998: } ! 999: break; ! 1000: #endif /* KERBEROS */ ! 1001: ! 1002: default: ! 1003: break; ! 1004: } ! 1005: } ! 1006: ! 1007: static char str_lm[] = { IAC, SB, TELOPT_LINEMODE, 0, 0, IAC, SE }; ! 1008: ! 1009: lm_will(cmd, len) ! 1010: char *cmd; ! 1011: { ! 1012: if (len < 1) { ! 1013: /*@*/ printf("lm_will: no command!!!\n"); /* Should not happen... */ ! 1014: return; ! 1015: } ! 1016: switch(cmd[0]) { ! 1017: case LM_FORWARDMASK: /* We shouldn't ever get this... */ ! 1018: default: ! 1019: str_lm[3] = DONT; ! 1020: str_lm[4] = cmd[0]; ! 1021: if (NETROOM() > sizeof(str_lm)) { ! 1022: ring_supply_data(&netoring, str_lm, sizeof(str_lm)); ! 1023: printsub('>', &str_lm[2], sizeof(str_lm)-2); ! 1024: } ! 1025: /*@*/ else printf("lm_will: not enough room in buffer\n"); ! 1026: break; ! 1027: } ! 1028: } ! 1029: ! 1030: lm_wont(cmd, len) ! 1031: char *cmd; ! 1032: { ! 1033: if (len < 1) { ! 1034: /*@*/ printf("lm_wont: no command!!!\n"); /* Should not happen... */ ! 1035: return; ! 1036: } ! 1037: switch(cmd[0]) { ! 1038: case LM_FORWARDMASK: /* We shouldn't ever get this... */ ! 1039: default: ! 1040: /* We are always DONT, so don't respond */ ! 1041: return; ! 1042: } ! 1043: } ! 1044: ! 1045: lm_do(cmd, len) ! 1046: char *cmd; ! 1047: { ! 1048: if (len < 1) { ! 1049: /*@*/ printf("lm_do: no command!!!\n"); /* Should not happen... */ ! 1050: return; ! 1051: } ! 1052: switch(cmd[0]) { ! 1053: case LM_FORWARDMASK: ! 1054: default: ! 1055: str_lm[3] = WONT; ! 1056: str_lm[4] = cmd[0]; ! 1057: if (NETROOM() > sizeof(str_lm)) { ! 1058: ring_supply_data(&netoring, str_lm, sizeof(str_lm)); ! 1059: printsub('>', &str_lm[2], sizeof(str_lm)-2); ! 1060: } ! 1061: /*@*/ else printf("lm_do: not enough room in buffer\n"); ! 1062: break; ! 1063: } ! 1064: } ! 1065: ! 1066: lm_dont(cmd, len) ! 1067: char *cmd; ! 1068: { ! 1069: if (len < 1) { ! 1070: /*@*/ printf("lm_dont: no command!!!\n"); /* Should not happen... */ ! 1071: return; ! 1072: } ! 1073: switch(cmd[0]) { ! 1074: case LM_FORWARDMASK: ! 1075: default: ! 1076: /* we are always WONT, so don't respond */ ! 1077: break; ! 1078: } ! 1079: } ! 1080: ! 1081: static char str_lm_mode[] = { IAC, SB, TELOPT_LINEMODE, LM_MODE, 0, IAC, SE }; ! 1082: ! 1083: lm_mode(cmd, len, init) ! 1084: char *cmd; ! 1085: int len, init; ! 1086: { ! 1087: if (len != 1) ! 1088: return; ! 1089: if ((linemode&MODE_MASK&~MODE_ACK) == *cmd) ! 1090: return; ! 1091: if (*cmd&MODE_ACK) ! 1092: return; ! 1093: linemode = *cmd&(MODE_MASK&~MODE_ACK); ! 1094: str_lm_mode[4] = linemode; ! 1095: if (!init) ! 1096: str_lm_mode[4] |= MODE_ACK; ! 1097: if (NETROOM() > sizeof(str_lm_mode)) { ! 1098: ring_supply_data(&netoring, str_lm_mode, sizeof(str_lm_mode)); ! 1099: printsub('>', &str_lm_mode[2], sizeof(str_lm_mode)-2); ! 1100: } ! 1101: /*@*/ else printf("lm_mode: not enough room in buffer\n"); ! 1102: setconnmode(0); /* set changed mode */ ! 1103: } ! 1104: ! 1105: ! 1106: ! 1107: /* ! 1108: * slc() ! 1109: * Handle special character suboption of LINEMODE. ! 1110: */ ! 1111: ! 1112: struct spc { ! 1113: cc_t val; ! 1114: cc_t *valp; ! 1115: char flags; /* Current flags & level */ ! 1116: char mylevel; /* Maximum level & flags */ ! 1117: } spc_data[NSLC+1]; ! 1118: ! 1119: #define SLC_IMPORT 0 ! 1120: #define SLC_EXPORT 1 ! 1121: #define SLC_RVALUE 2 ! 1122: static int slc_mode = SLC_EXPORT; ! 1123: ! 1124: slc_init() ! 1125: { ! 1126: register struct spc *spcp; ! 1127: extern cc_t *tcval(); ! 1128: ! 1129: localchars = 1; ! 1130: for (spcp = spc_data; spcp < &spc_data[NSLC+1]; spcp++) { ! 1131: spcp->val = 0; ! 1132: spcp->valp = 0; ! 1133: spcp->flags = spcp->mylevel = SLC_NOSUPPORT; ! 1134: } ! 1135: ! 1136: #define initfunc(func, flags) { \ ! 1137: spcp = &spc_data[func]; \ ! 1138: if (spcp->valp = tcval(func)) { \ ! 1139: spcp->val = *spcp->valp; \ ! 1140: spcp->mylevel = SLC_VARIABLE|flags; \ ! 1141: } else { \ ! 1142: spcp->val = 0; \ ! 1143: spcp->mylevel = SLC_DEFAULT; \ ! 1144: } \ ! 1145: } ! 1146: ! 1147: initfunc(SLC_SYNCH, 0); ! 1148: /* No BRK */ ! 1149: initfunc(SLC_AO, 0); ! 1150: initfunc(SLC_AYT, 0); ! 1151: /* No EOR */ ! 1152: initfunc(SLC_ABORT, SLC_FLUSHIN|SLC_FLUSHOUT); ! 1153: initfunc(SLC_EOF, 0); ! 1154: #ifndef SYSV_TERMIO ! 1155: initfunc(SLC_SUSP, SLC_FLUSHIN); ! 1156: #endif ! 1157: initfunc(SLC_EC, 0); ! 1158: initfunc(SLC_EL, 0); ! 1159: #ifndef SYSV_TERMIO ! 1160: initfunc(SLC_EW, 0); ! 1161: initfunc(SLC_RP, 0); ! 1162: initfunc(SLC_LNEXT, 0); ! 1163: #endif ! 1164: initfunc(SLC_XON, 0); ! 1165: initfunc(SLC_XOFF, 0); ! 1166: #ifdef SYSV_TERMIO ! 1167: spc_data[SLC_XON].mylevel = SLC_CANTCHANGE; ! 1168: spc_data[SLC_XOFF].mylevel = SLC_CANTCHANGE; ! 1169: #endif ! 1170: initfunc(SLC_FORW1, 0); ! 1171: #ifdef USE_TERMIO ! 1172: initfunc(SLC_FORW2, 0); ! 1173: /* No FORW2 */ ! 1174: #endif ! 1175: ! 1176: initfunc(SLC_IP, SLC_FLUSHIN|SLC_FLUSHOUT); ! 1177: #undef initfunc ! 1178: ! 1179: if (slc_mode == SLC_EXPORT) ! 1180: slc_export(); ! 1181: else ! 1182: slc_import(1); ! 1183: ! 1184: } ! 1185: ! 1186: slcstate() ! 1187: { ! 1188: printf("Special characters are %s values\n", ! 1189: slc_mode == SLC_IMPORT ? "remote default" : ! 1190: slc_mode == SLC_EXPORT ? "local" : ! 1191: "remote"); ! 1192: } ! 1193: ! 1194: slc_mode_export() ! 1195: { ! 1196: slc_mode = SLC_EXPORT; ! 1197: if (my_state_is_will(TELOPT_LINEMODE)) ! 1198: slc_export(); ! 1199: } ! 1200: ! 1201: slc_mode_import(def) ! 1202: { ! 1203: slc_mode = def ? SLC_IMPORT : SLC_RVALUE; ! 1204: if (my_state_is_will(TELOPT_LINEMODE)) ! 1205: slc_import(def); ! 1206: } ! 1207: ! 1208: char slc_import_val[] = { ! 1209: IAC, SB, TELOPT_LINEMODE, LM_SLC, 0, SLC_VARIABLE, 0, IAC, SE ! 1210: }; ! 1211: char slc_import_def[] = { ! 1212: IAC, SB, TELOPT_LINEMODE, LM_SLC, 0, SLC_DEFAULT, 0, IAC, SE ! 1213: }; ! 1214: ! 1215: slc_import(def) ! 1216: int def; ! 1217: { ! 1218: if (NETROOM() > sizeof(slc_import_val)) { ! 1219: if (def) { ! 1220: ring_supply_data(&netoring, slc_import_def, sizeof(slc_import_def)); ! 1221: printsub('>', &slc_import_def[2], sizeof(slc_import_def)-2); ! 1222: } else { ! 1223: ring_supply_data(&netoring, slc_import_val, sizeof(slc_import_val)); ! 1224: printsub('>', &slc_import_val[2], sizeof(slc_import_val)-2); ! 1225: } ! 1226: } ! 1227: /*@*/ else printf("slc_import: not enough room\n"); ! 1228: } ! 1229: ! 1230: slc_export() ! 1231: { ! 1232: register struct spc *spcp; ! 1233: ! 1234: TerminalDefaultChars(); ! 1235: ! 1236: slc_start_reply(); ! 1237: for (spcp = &spc_data[1]; spcp < &spc_data[NSLC+1]; spcp++) { ! 1238: if (spcp->mylevel != SLC_NOSUPPORT) { ! 1239: spcp->flags = spcp->mylevel; ! 1240: if (spcp->valp) ! 1241: spcp->val = *spcp->valp; ! 1242: slc_add_reply(spcp - spc_data, spcp->mylevel, spcp->val); ! 1243: } ! 1244: } ! 1245: slc_end_reply(); ! 1246: if (slc_update()) ! 1247: setconnmode(1); /* set the new character values */ ! 1248: } ! 1249: ! 1250: slc(cp, len) ! 1251: register char *cp; ! 1252: int len; ! 1253: { ! 1254: register struct spc *spcp; ! 1255: register int func,level; ! 1256: ! 1257: slc_start_reply(); ! 1258: ! 1259: for (; len >= 3; len -=3, cp +=3) { ! 1260: ! 1261: func = cp[SLC_FUNC]; ! 1262: ! 1263: if (func == 0) { ! 1264: /* ! 1265: * Client side: always ignore 0 function. ! 1266: */ ! 1267: continue; ! 1268: } ! 1269: if (func > NSLC) { ! 1270: if (cp[SLC_FLAGS] & SLC_LEVELBITS != SLC_NOSUPPORT) ! 1271: slc_add_reply(func, SLC_NOSUPPORT, 0); ! 1272: continue; ! 1273: } ! 1274: ! 1275: spcp = &spc_data[func]; ! 1276: ! 1277: level = cp[SLC_FLAGS]&(SLC_LEVELBITS|SLC_ACK); ! 1278: ! 1279: if ((cp[SLC_VALUE] == (unsigned char)spcp->val) && ! 1280: ((level&SLC_LEVELBITS) == (spcp->flags&SLC_LEVELBITS))) { ! 1281: continue; ! 1282: } ! 1283: ! 1284: if (level == (SLC_DEFAULT|SLC_ACK)) { ! 1285: /* ! 1286: * This is an error condition, the SLC_ACK ! 1287: * bit should never be set for the SLC_DEFAULT ! 1288: * level. Our best guess to recover is to ! 1289: * ignore the SLC_ACK bit. ! 1290: */ ! 1291: cp[SLC_FLAGS] &= ~SLC_ACK; ! 1292: } ! 1293: ! 1294: if (level == ((spcp->flags&SLC_LEVELBITS)|SLC_ACK)) { ! 1295: spcp->val = (cc_t)cp[SLC_VALUE]; ! 1296: spcp->flags = cp[SLC_FLAGS]; /* include SLC_ACK */ ! 1297: continue; ! 1298: } ! 1299: ! 1300: level &= ~SLC_ACK; ! 1301: ! 1302: if (level <= (spcp->mylevel&SLC_LEVELBITS)) { ! 1303: spcp->flags = cp[SLC_FLAGS]|SLC_ACK; ! 1304: spcp->val = (cc_t)cp[SLC_VALUE]; ! 1305: } ! 1306: if (level == SLC_DEFAULT) { ! 1307: if ((spcp->mylevel&SLC_LEVELBITS) != SLC_DEFAULT) ! 1308: spcp->flags = spcp->mylevel; ! 1309: else ! 1310: spcp->flags = SLC_NOSUPPORT; ! 1311: } ! 1312: slc_add_reply(func, spcp->flags, spcp->val); ! 1313: } ! 1314: slc_end_reply(); ! 1315: if (slc_update()) ! 1316: setconnmode(1); /* set the new character values */ ! 1317: } ! 1318: ! 1319: slc_check() ! 1320: { ! 1321: register struct spc *spcp; ! 1322: ! 1323: slc_start_reply(); ! 1324: for (spcp = &spc_data[1]; spcp < &spc_data[NSLC+1]; spcp++) { ! 1325: if (spcp->valp && spcp->val != *spcp->valp) { ! 1326: spcp->val = *spcp->valp; ! 1327: slc_add_reply(spcp - spc_data, spcp->mylevel, spcp->val); ! 1328: } ! 1329: } ! 1330: slc_end_reply(); ! 1331: setconnmode(1); ! 1332: } ! 1333: ! 1334: ! 1335: unsigned char slc_reply[128]; ! 1336: unsigned char *slc_replyp; ! 1337: slc_start_reply() ! 1338: { ! 1339: slc_replyp = slc_reply; ! 1340: *slc_replyp++ = IAC; ! 1341: *slc_replyp++ = SB; ! 1342: *slc_replyp++ = TELOPT_LINEMODE; ! 1343: *slc_replyp++ = LM_SLC; ! 1344: } ! 1345: ! 1346: slc_add_reply(func, flags, value) ! 1347: char func; ! 1348: char flags; ! 1349: cc_t value; ! 1350: { ! 1351: if ((*slc_replyp++ = func) == IAC) ! 1352: *slc_replyp++ = IAC; ! 1353: if ((*slc_replyp++ = flags) == IAC) ! 1354: *slc_replyp++ = IAC; ! 1355: if ((*slc_replyp++ = (unsigned char)value) == IAC) ! 1356: *slc_replyp++ = IAC; ! 1357: } ! 1358: ! 1359: slc_end_reply() ! 1360: { ! 1361: register int len; ! 1362: ! 1363: *slc_replyp++ = IAC; ! 1364: *slc_replyp++ = SE; ! 1365: len = slc_replyp - slc_reply; ! 1366: if (len <= 6) ! 1367: return; ! 1368: if (NETROOM() > len) { ! 1369: ring_supply_data(&netoring, slc_reply, slc_replyp - slc_reply); ! 1370: printsub('>', &slc_reply[2], slc_replyp - slc_reply - 2); ! 1371: } ! 1372: /*@*/else printf("slc_end_reply: not enough room\n"); ! 1373: } ! 1374: ! 1375: slc_update() ! 1376: { ! 1377: register struct spc *spcp; ! 1378: int need_update = 0; ! 1379: ! 1380: for (spcp = &spc_data[1]; spcp < &spc_data[NSLC+1]; spcp++) { ! 1381: if (!(spcp->flags&SLC_ACK)) ! 1382: continue; ! 1383: spcp->flags &= ~SLC_ACK; ! 1384: if (spcp->valp && (*spcp->valp != spcp->val)) { ! 1385: *spcp->valp = spcp->val; ! 1386: need_update = 1; ! 1387: } ! 1388: } ! 1389: return(need_update); ! 1390: } ! 1391: ! 1392: env_opt(buf, len) ! 1393: register char *buf; ! 1394: register int len; ! 1395: { ! 1396: register char *ep = 0, *epc = 0; ! 1397: register int i; ! 1398: ! 1399: switch(buf[0]) { ! 1400: case TELQUAL_SEND: ! 1401: env_opt_start(); ! 1402: if (len == 1) { ! 1403: env_opt_add(NULL); ! 1404: } else for (i = 1; i < len; i++) { ! 1405: switch (buf[i]) { ! 1406: case ENV_VALUE: ! 1407: if (ep) { ! 1408: *epc = 0; ! 1409: env_opt_add(ep); ! 1410: } ! 1411: ep = epc = &buf[i+1]; ! 1412: break; ! 1413: case ENV_ESC: ! 1414: i++; ! 1415: /*FALL THROUGH*/ ! 1416: default: ! 1417: if (epc) ! 1418: *epc++ = buf[i]; ! 1419: break; ! 1420: } ! 1421: if (ep) { ! 1422: *epc = 0; ! 1423: env_opt_add(ep); ! 1424: } ! 1425: } ! 1426: env_opt_end(1); ! 1427: break; ! 1428: ! 1429: case TELQUAL_IS: ! 1430: case TELQUAL_INFO: ! 1431: /* Ignore for now. We shouldn't get it anyway. */ ! 1432: break; ! 1433: ! 1434: default: ! 1435: break; ! 1436: } ! 1437: } ! 1438: ! 1439: #define OPT_REPLY_SIZE 256 ! 1440: unsigned char *opt_reply; ! 1441: unsigned char *opt_replyp; ! 1442: unsigned char *opt_replyend; ! 1443: ! 1444: env_opt_start() ! 1445: { ! 1446: extern char *realloc(); ! 1447: extern char *malloc(); ! 1448: ! 1449: if (opt_reply) ! 1450: opt_reply = (unsigned char *)realloc(opt_reply, OPT_REPLY_SIZE); ! 1451: else ! 1452: opt_reply = (unsigned char *)malloc(OPT_REPLY_SIZE); ! 1453: if (opt_reply == NULL) { ! 1454: /*@*/ printf("env_opt_start: malloc()/realloc() failed!!!\n"); ! 1455: opt_reply = opt_replyp = opt_replyend = NULL; ! 1456: return; ! 1457: } ! 1458: opt_replyp = opt_reply; ! 1459: opt_replyend = opt_reply + OPT_REPLY_SIZE; ! 1460: *opt_replyp++ = IAC; ! 1461: *opt_replyp++ = SB; ! 1462: *opt_replyp++ = TELOPT_ENVIRON; ! 1463: *opt_replyp++ = TELQUAL_IS; ! 1464: } ! 1465: ! 1466: env_opt_start_info() ! 1467: { ! 1468: env_opt_start(); ! 1469: if (opt_replyp) ! 1470: opt_replyp[-1] = TELQUAL_INFO; ! 1471: } ! 1472: ! 1473: env_opt_add(ep) ! 1474: register char *ep; ! 1475: { ! 1476: register char *vp, c; ! 1477: extern char *realloc(); ! 1478: extern char *env_default(); ! 1479: ! 1480: if (opt_reply == NULL) /*XXX*/ ! 1481: return; /*XXX*/ ! 1482: ! 1483: if (ep == NULL || *ep == '\0') { ! 1484: env_default(1); ! 1485: while (ep = env_default(0)) ! 1486: env_opt_add(ep); ! 1487: return; ! 1488: } ! 1489: vp = env_getvalue(ep); ! 1490: if (opt_replyp + (vp?strlen(vp):0) + strlen(ep) + 6 > opt_replyend) { ! 1491: register int len; ! 1492: opt_replyend += OPT_REPLY_SIZE; ! 1493: len = opt_replyend - opt_reply; ! 1494: opt_reply = (unsigned char *)realloc(opt_reply, len); ! 1495: if (opt_reply == NULL) { ! 1496: /*@*/ printf("env_opt_add: realloc() failed!!!\n"); ! 1497: opt_reply = opt_replyp = opt_replyend = NULL; ! 1498: return; ! 1499: } ! 1500: opt_replyp = opt_reply + len - (opt_replyend - opt_replyp); ! 1501: opt_replyend = opt_reply + len; ! 1502: } ! 1503: *opt_replyp++ = ENV_VAR; ! 1504: for (;;) { ! 1505: while (c = *ep++) { ! 1506: switch(c) { ! 1507: case IAC: ! 1508: *opt_replyp++ = IAC; ! 1509: break; ! 1510: case ENV_VALUE: ! 1511: case ENV_VAR: ! 1512: case ENV_ESC: ! 1513: *opt_replyp++ = ENV_ESC; ! 1514: break; ! 1515: } ! 1516: *opt_replyp++ = c; ! 1517: } ! 1518: if (ep = vp) { ! 1519: *opt_replyp++ = ENV_VALUE; ! 1520: vp = NULL; ! 1521: } else ! 1522: break; ! 1523: } ! 1524: } ! 1525: ! 1526: env_opt_end(emptyok) ! 1527: register int emptyok; ! 1528: { ! 1529: register int len; ! 1530: ! 1531: len = opt_replyp - opt_reply + 2; ! 1532: if (emptyok || len > 6) { ! 1533: *opt_replyp++ = IAC; ! 1534: *opt_replyp++ = SE; ! 1535: if (NETROOM() > len) { ! 1536: ring_supply_data(&netoring, opt_reply, len); ! 1537: printsub('>', &opt_reply[2], len - 2); ! 1538: } ! 1539: /*@*/ else printf("slc_end_reply: not enough room\n"); ! 1540: } ! 1541: if (opt_reply) { ! 1542: free(opt_reply); ! 1543: opt_reply = opt_replyp = opt_replyend = NULL; ! 1544: } ! 1545: } ! 1546: ! 1547: ! 1548: ! 1549: int ! 1550: telrcv() ! 1551: { ! 1552: register int c; ! 1553: register int scc; ! 1554: register char *sbp; ! 1555: int count; ! 1556: int returnValue = 0; ! 1557: ! 1558: scc = 0; ! 1559: count = 0; ! 1560: while (TTYROOM() > 2) { ! 1561: if (scc == 0) { ! 1562: if (count) { ! 1563: ring_consumed(&netiring, count); ! 1564: returnValue = 1; ! 1565: count = 0; ! 1566: } ! 1567: sbp = netiring.consume; ! 1568: scc = ring_full_consecutive(&netiring); ! 1569: if (scc == 0) { ! 1570: /* No more data coming in */ ! 1571: break; ! 1572: } ! 1573: } ! 1574: ! 1575: c = *sbp++ & 0xff, scc--; count++; ! 1576: ! 1577: switch (telrcv_state) { ! 1578: ! 1579: case TS_CR: ! 1580: telrcv_state = TS_DATA; ! 1581: if (c == '\0') { ! 1582: break; /* Ignore \0 after CR */ ! 1583: } ! 1584: else if ((c == '\n') && my_want_state_is_dont(TELOPT_ECHO) && !crmod) { ! 1585: TTYADD(c); ! 1586: break; ! 1587: } ! 1588: /* Else, fall through */ ! 1589: ! 1590: case TS_DATA: ! 1591: if (c == IAC) { ! 1592: telrcv_state = TS_IAC; ! 1593: break; ! 1594: } ! 1595: # if defined(TN3270) ! 1596: if (In3270) { ! 1597: *Ifrontp++ = c; ! 1598: while (scc > 0) { ! 1599: c = *sbp++ & 0377, scc--; count++; ! 1600: if (c == IAC) { ! 1601: telrcv_state = TS_IAC; ! 1602: break; ! 1603: } ! 1604: *Ifrontp++ = c; ! 1605: } ! 1606: } else ! 1607: # endif /* defined(TN3270) */ ! 1608: /* ! 1609: * The 'crmod' hack (see following) is needed ! 1610: * since we can't * set CRMOD on output only. ! 1611: * Machines like MULTICS like to send \r without ! 1612: * \n; since we must turn off CRMOD to get proper ! 1613: * input, the mapping is done here (sigh). ! 1614: */ ! 1615: if ((c == '\r') && my_want_state_is_dont(TELOPT_BINARY)) { ! 1616: if (scc > 0) { ! 1617: c = *sbp&0xff; ! 1618: if (c == 0) { ! 1619: sbp++, scc--; count++; ! 1620: /* a "true" CR */ ! 1621: TTYADD('\r'); ! 1622: } else if (my_want_state_is_dont(TELOPT_ECHO) && ! 1623: (c == '\n')) { ! 1624: sbp++, scc--; count++; ! 1625: TTYADD('\n'); ! 1626: } else { ! 1627: TTYADD('\r'); ! 1628: if (crmod) { ! 1629: TTYADD('\n'); ! 1630: } ! 1631: } ! 1632: } else { ! 1633: telrcv_state = TS_CR; ! 1634: TTYADD('\r'); ! 1635: if (crmod) { ! 1636: TTYADD('\n'); ! 1637: } ! 1638: } ! 1639: } else { ! 1640: TTYADD(c); ! 1641: } ! 1642: continue; ! 1643: ! 1644: case TS_IAC: ! 1645: process_iac: ! 1646: switch (c) { ! 1647: ! 1648: case WILL: ! 1649: telrcv_state = TS_WILL; ! 1650: continue; ! 1651: ! 1652: case WONT: ! 1653: telrcv_state = TS_WONT; ! 1654: continue; ! 1655: ! 1656: case DO: ! 1657: telrcv_state = TS_DO; ! 1658: continue; ! 1659: ! 1660: case DONT: ! 1661: telrcv_state = TS_DONT; ! 1662: continue; ! 1663: ! 1664: case DM: ! 1665: /* ! 1666: * We may have missed an urgent notification, ! 1667: * so make sure we flush whatever is in the ! 1668: * buffer currently. ! 1669: */ ! 1670: SYNCHing = 1; ! 1671: (void) ttyflush(1); ! 1672: SYNCHing = stilloob(); ! 1673: settimer(gotDM); ! 1674: break; ! 1675: ! 1676: case SB: ! 1677: SB_CLEAR(); ! 1678: telrcv_state = TS_SB; ! 1679: printoption("RCVD", "IAC", SB); ! 1680: continue; ! 1681: ! 1682: # if defined(TN3270) ! 1683: case EOR: ! 1684: if (In3270) { ! 1685: if (Ibackp == Ifrontp) { ! 1686: Ibackp = Ifrontp = Ibuf; ! 1687: ISend = 0; /* should have been! */ ! 1688: } else { ! 1689: Ibackp += DataFromNetwork(Ibackp, Ifrontp-Ibackp, 1); ! 1690: ISend = 1; ! 1691: } ! 1692: } ! 1693: break; ! 1694: # endif /* defined(TN3270) */ ! 1695: ! 1696: case IAC: ! 1697: # if !defined(TN3270) ! 1698: TTYADD(IAC); ! 1699: # else /* !defined(TN3270) */ ! 1700: if (In3270) { ! 1701: *Ifrontp++ = IAC; ! 1702: } else { ! 1703: TTYADD(IAC); ! 1704: } ! 1705: # endif /* !defined(TN3270) */ ! 1706: break; ! 1707: ! 1708: case NOP: ! 1709: case GA: ! 1710: default: ! 1711: printoption("RCVD", "IAC", c); ! 1712: break; ! 1713: } ! 1714: telrcv_state = TS_DATA; ! 1715: continue; ! 1716: ! 1717: case TS_WILL: ! 1718: printoption("RCVD", "will", c); ! 1719: willoption(c); ! 1720: SetIn3270(); ! 1721: telrcv_state = TS_DATA; ! 1722: continue; ! 1723: ! 1724: case TS_WONT: ! 1725: printoption("RCVD", "wont", c); ! 1726: wontoption(c); ! 1727: SetIn3270(); ! 1728: telrcv_state = TS_DATA; ! 1729: continue; ! 1730: ! 1731: case TS_DO: ! 1732: printoption("RCVD", "do", c); ! 1733: dooption(c); ! 1734: SetIn3270(); ! 1735: if (c == TELOPT_NAWS) { ! 1736: sendnaws(); ! 1737: } else if (c == TELOPT_LFLOW) { ! 1738: localflow = 1; ! 1739: setcommandmode(); ! 1740: setconnmode(0); ! 1741: } ! 1742: telrcv_state = TS_DATA; ! 1743: continue; ! 1744: ! 1745: case TS_DONT: ! 1746: printoption("RCVD", "dont", c); ! 1747: dontoption(c); ! 1748: flushline = 1; ! 1749: setconnmode(0); /* set new tty mode (maybe) */ ! 1750: SetIn3270(); ! 1751: telrcv_state = TS_DATA; ! 1752: continue; ! 1753: ! 1754: case TS_SB: ! 1755: if (c == IAC) { ! 1756: telrcv_state = TS_SE; ! 1757: } else { ! 1758: SB_ACCUM(c); ! 1759: } ! 1760: continue; ! 1761: ! 1762: case TS_SE: ! 1763: if (c != SE) { ! 1764: if (c != IAC) { ! 1765: /* ! 1766: * This is an error. We only expect to get ! 1767: * "IAC IAC" or "IAC SE". Several things may ! 1768: * have happend. An IAC was not doubled, the ! 1769: * IAC SE was left off, or another option got ! 1770: * inserted into the suboption are all possibilities. ! 1771: * If we assume that the IAC was not doubled, ! 1772: * and really the IAC SE was left off, we could ! 1773: * get into an infinate loop here. So, instead, ! 1774: * we terminate the suboption, and process the ! 1775: * partial suboption if we can. ! 1776: */ ! 1777: SB_TERM(); ! 1778: SB_ACCUM(IAC); ! 1779: SB_ACCUM(c); ! 1780: printoption("In SUBOPTION processing, RCVD", "IAC", c); ! 1781: suboption(); /* handle sub-option */ ! 1782: SetIn3270(); ! 1783: telrcv_state = TS_IAC; ! 1784: goto process_iac; ! 1785: } ! 1786: SB_ACCUM(c); ! 1787: telrcv_state = TS_SB; ! 1788: } else { ! 1789: SB_TERM(); ! 1790: SB_ACCUM(IAC); ! 1791: SB_ACCUM(SE); ! 1792: suboption(); /* handle sub-option */ ! 1793: SetIn3270(); ! 1794: telrcv_state = TS_DATA; ! 1795: } ! 1796: } ! 1797: } ! 1798: if (count) ! 1799: ring_consumed(&netiring, count); ! 1800: return returnValue||count; ! 1801: } ! 1802: ! 1803: static int ! 1804: telsnd() ! 1805: { ! 1806: int tcc; ! 1807: int count; ! 1808: int returnValue = 0; ! 1809: char *tbp; ! 1810: ! 1811: tcc = 0; ! 1812: count = 0; ! 1813: while (NETROOM() > 2) { ! 1814: register int sc; ! 1815: register int c; ! 1816: ! 1817: if (tcc == 0) { ! 1818: if (count) { ! 1819: ring_consumed(&ttyiring, count); ! 1820: returnValue = 1; ! 1821: count = 0; ! 1822: } ! 1823: tbp = ttyiring.consume; ! 1824: tcc = ring_full_consecutive(&ttyiring); ! 1825: if (tcc == 0) { ! 1826: break; ! 1827: } ! 1828: } ! 1829: c = *tbp++ & 0xff, sc = strip(c), tcc--; count++; ! 1830: if (sc == escape) { ! 1831: /* ! 1832: * Double escape is a pass through of a single escape character. ! 1833: */ ! 1834: if (tcc && strip(*tbp) == escape) { ! 1835: tbp++; ! 1836: tcc--; ! 1837: count++; ! 1838: } else { ! 1839: command(0, tbp, tcc); ! 1840: count += tcc; ! 1841: tcc = 0; ! 1842: flushline = 1; ! 1843: break; ! 1844: } ! 1845: } ! 1846: #ifdef KLUDGELINEMODE ! 1847: if (kludgelinemode && (globalmode&MODE_EDIT) && (sc == echoc)) { ! 1848: if (tcc > 0 && strip(*tbp) == echoc) { ! 1849: tcc--; tbp++; count++; ! 1850: } else { ! 1851: dontlecho = !dontlecho; ! 1852: settimer(echotoggle); ! 1853: setconnmode(0); ! 1854: flushline = 1; ! 1855: break; ! 1856: } ! 1857: } ! 1858: #endif ! 1859: if (MODE_LOCAL_CHARS(globalmode)) { ! 1860: if (TerminalSpecialChars(sc) == 0) { ! 1861: break; ! 1862: } ! 1863: } ! 1864: if (my_want_state_is_wont(TELOPT_BINARY)) { ! 1865: switch (c) { ! 1866: case '\n': ! 1867: /* ! 1868: * If we are in CRMOD mode (\r ==> \n) ! 1869: * on our local machine, then probably ! 1870: * a newline (unix) is CRLF (TELNET). ! 1871: */ ! 1872: if (MODE_LOCAL_CHARS(globalmode)) { ! 1873: NETADD('\r'); ! 1874: } ! 1875: NETADD('\n'); ! 1876: flushline = 1; ! 1877: break; ! 1878: case '\r': ! 1879: if (!crlf) { ! 1880: NET2ADD('\r', '\0'); ! 1881: } else { ! 1882: NET2ADD('\r', '\n'); ! 1883: } ! 1884: flushline = 1; ! 1885: break; ! 1886: case IAC: ! 1887: NET2ADD(IAC, IAC); ! 1888: break; ! 1889: default: ! 1890: NETADD(c); ! 1891: break; ! 1892: } ! 1893: } else if (c == IAC) { ! 1894: NET2ADD(IAC, IAC); ! 1895: } else { ! 1896: NETADD(c); ! 1897: } ! 1898: } ! 1899: if (count) ! 1900: ring_consumed(&ttyiring, count); ! 1901: return returnValue||count; /* Non-zero if we did anything */ ! 1902: } ! 1903: ! 1904: /* ! 1905: * Scheduler() ! 1906: * ! 1907: * Try to do something. ! 1908: * ! 1909: * If we do something useful, return 1; else return 0. ! 1910: * ! 1911: */ ! 1912: ! 1913: ! 1914: int ! 1915: Scheduler(block) ! 1916: int block; /* should we block in the select ? */ ! 1917: { ! 1918: /* One wants to be a bit careful about setting returnValue ! 1919: * to one, since a one implies we did some useful work, ! 1920: * and therefore probably won't be called to block next ! 1921: * time (TN3270 mode only). ! 1922: */ ! 1923: int returnValue; ! 1924: int netin, netout, netex, ttyin, ttyout; ! 1925: ! 1926: /* Decide which rings should be processed */ ! 1927: ! 1928: netout = ring_full_count(&netoring) && ! 1929: (flushline || ! 1930: (my_want_state_is_wont(TELOPT_LINEMODE) ! 1931: #ifdef KLUDGELINEMODE ! 1932: && (!kludgelinemode || my_want_state_is_do(TELOPT_SGA)) ! 1933: #endif ! 1934: ) || ! 1935: my_want_state_is_will(TELOPT_BINARY)); ! 1936: ttyout = ring_full_count(&ttyoring); ! 1937: ! 1938: #if defined(TN3270) ! 1939: ttyin = ring_empty_count(&ttyiring) && (shell_active == 0); ! 1940: #else /* defined(TN3270) */ ! 1941: ttyin = ring_empty_count(&ttyiring); ! 1942: #endif /* defined(TN3270) */ ! 1943: ! 1944: #if defined(TN3270) ! 1945: netin = ring_empty_count(&netiring); ! 1946: # else /* !defined(TN3270) */ ! 1947: netin = !ISend && ring_empty_count(&netiring); ! 1948: # endif /* !defined(TN3270) */ ! 1949: ! 1950: netex = !SYNCHing; ! 1951: ! 1952: /* If we have seen a signal recently, reset things */ ! 1953: # if defined(TN3270) && defined(unix) ! 1954: if (HaveInput) { ! 1955: HaveInput = 0; ! 1956: (void) signal(SIGIO, inputAvailable); ! 1957: } ! 1958: #endif /* defined(TN3270) && defined(unix) */ ! 1959: ! 1960: /* Call to system code to process rings */ ! 1961: ! 1962: returnValue = process_rings(netin, netout, netex, ttyin, ttyout, !block); ! 1963: ! 1964: /* Now, look at the input rings, looking for work to do. */ ! 1965: ! 1966: if (ring_full_count(&ttyiring)) { ! 1967: # if defined(TN3270) ! 1968: if (In3270) { ! 1969: int c; ! 1970: ! 1971: c = DataFromTerminal(ttyiring.consume, ! 1972: ring_full_consecutive(&ttyiring)); ! 1973: if (c) { ! 1974: returnValue = 1; ! 1975: ring_consumed(&ttyiring, c); ! 1976: } ! 1977: } else { ! 1978: # endif /* defined(TN3270) */ ! 1979: returnValue |= telsnd(); ! 1980: # if defined(TN3270) ! 1981: } ! 1982: # endif /* defined(TN3270) */ ! 1983: } ! 1984: ! 1985: if (ring_full_count(&netiring)) { ! 1986: # if !defined(TN3270) ! 1987: returnValue |= telrcv(); ! 1988: # else /* !defined(TN3270) */ ! 1989: returnValue = Push3270(); ! 1990: # endif /* !defined(TN3270) */ ! 1991: } ! 1992: return returnValue; ! 1993: } ! 1994: ! 1995: /* ! 1996: * Select from tty and network... ! 1997: */ ! 1998: void ! 1999: telnet() ! 2000: { ! 2001: sys_telnet_init(); ! 2002: ! 2003: # if !defined(TN3270) ! 2004: if (telnetport) { ! 2005: send_do(TELOPT_SGA, 1); ! 2006: send_will(TELOPT_TTYPE, 1); ! 2007: send_will(TELOPT_NAWS, 1); ! 2008: send_will(TELOPT_TSPEED, 1); ! 2009: send_will(TELOPT_LFLOW, 1); ! 2010: send_will(TELOPT_LINEMODE, 1); ! 2011: #ifdef KERBEROS ! 2012: if (kerberized) ! 2013: send_will(TELOPT_AUTHENTICATION, 1); ! 2014: #endif ! 2015: send_do(TELOPT_STATUS, 1); ! 2016: if (env_getvalue("DISPLAY")) ! 2017: send_will(TELOPT_XDISPLOC, 1); ! 2018: send_will(TELOPT_ENVIRON, 1); ! 2019: } ! 2020: # endif /* !defined(TN3270) */ ! 2021: ! 2022: # if !defined(TN3270) ! 2023: for (;;) { ! 2024: int schedValue; ! 2025: ! 2026: while ((schedValue = Scheduler(0)) != 0) { ! 2027: if (schedValue == -1) { ! 2028: setcommandmode(); ! 2029: return; ! 2030: } ! 2031: } ! 2032: ! 2033: if (Scheduler(1) == -1) { ! 2034: setcommandmode(); ! 2035: return; ! 2036: } ! 2037: } ! 2038: # else /* !defined(TN3270) */ ! 2039: for (;;) { ! 2040: int schedValue; ! 2041: ! 2042: while (!In3270 && !shell_active) { ! 2043: if (Scheduler(1) == -1) { ! 2044: setcommandmode(); ! 2045: return; ! 2046: } ! 2047: } ! 2048: ! 2049: while ((schedValue = Scheduler(0)) != 0) { ! 2050: if (schedValue == -1) { ! 2051: setcommandmode(); ! 2052: return; ! 2053: } ! 2054: } ! 2055: /* If there is data waiting to go out to terminal, don't ! 2056: * schedule any more data for the terminal. ! 2057: */ ! 2058: if (ring_full_count(&ttyoring)) { ! 2059: schedValue = 1; ! 2060: } else { ! 2061: if (shell_active) { ! 2062: if (shell_continue() == 0) { ! 2063: ConnectScreen(); ! 2064: } ! 2065: } else if (In3270) { ! 2066: schedValue = DoTerminalOutput(); ! 2067: } ! 2068: } ! 2069: if (schedValue && (shell_active == 0)) { ! 2070: if (Scheduler(1) == -1) { ! 2071: setcommandmode(); ! 2072: return; ! 2073: } ! 2074: } ! 2075: } ! 2076: # endif /* !defined(TN3270) */ ! 2077: } ! 2078: ! 2079: #if 0 /* XXX - this not being in is a bug */ ! 2080: /* ! 2081: * nextitem() ! 2082: * ! 2083: * Return the address of the next "item" in the TELNET data ! 2084: * stream. This will be the address of the next character if ! 2085: * the current address is a user data character, or it will ! 2086: * be the address of the character following the TELNET command ! 2087: * if the current address is a TELNET IAC ("I Am a Command") ! 2088: * character. ! 2089: */ ! 2090: ! 2091: static char * ! 2092: nextitem(current) ! 2093: char *current; ! 2094: { ! 2095: if ((*current&0xff) != IAC) { ! 2096: return current+1; ! 2097: } ! 2098: switch (*(current+1)&0xff) { ! 2099: case DO: ! 2100: case DONT: ! 2101: case WILL: ! 2102: case WONT: ! 2103: return current+3; ! 2104: case SB: /* loop forever looking for the SE */ ! 2105: { ! 2106: register char *look = current+2; ! 2107: ! 2108: for (;;) { ! 2109: if ((*look++&0xff) == IAC) { ! 2110: if ((*look++&0xff) == SE) { ! 2111: return look; ! 2112: } ! 2113: } ! 2114: } ! 2115: } ! 2116: default: ! 2117: return current+2; ! 2118: } ! 2119: } ! 2120: #endif /* 0 */ ! 2121: ! 2122: /* ! 2123: * netclear() ! 2124: * ! 2125: * We are about to do a TELNET SYNCH operation. Clear ! 2126: * the path to the network. ! 2127: * ! 2128: * Things are a bit tricky since we may have sent the first ! 2129: * byte or so of a previous TELNET command into the network. ! 2130: * So, we have to scan the network buffer from the beginning ! 2131: * until we are up to where we want to be. ! 2132: * ! 2133: * A side effect of what we do, just to keep things ! 2134: * simple, is to clear the urgent data pointer. The principal ! 2135: * caller should be setting the urgent data pointer AFTER calling ! 2136: * us in any case. ! 2137: */ ! 2138: ! 2139: static void ! 2140: netclear() ! 2141: { ! 2142: #if 0 /* XXX */ ! 2143: register char *thisitem, *next; ! 2144: char *good; ! 2145: #define wewant(p) ((nfrontp > p) && ((*p&0xff) == IAC) && \ ! 2146: ((*(p+1)&0xff) != EC) && ((*(p+1)&0xff) != EL)) ! 2147: ! 2148: thisitem = netobuf; ! 2149: ! 2150: while ((next = nextitem(thisitem)) <= netobuf.send) { ! 2151: thisitem = next; ! 2152: } ! 2153: ! 2154: /* Now, thisitem is first before/at boundary. */ ! 2155: ! 2156: good = netobuf; /* where the good bytes go */ ! 2157: ! 2158: while (netoring.add > thisitem) { ! 2159: if (wewant(thisitem)) { ! 2160: int length; ! 2161: ! 2162: next = thisitem; ! 2163: do { ! 2164: next = nextitem(next); ! 2165: } while (wewant(next) && (nfrontp > next)); ! 2166: length = next-thisitem; ! 2167: memcpy(good, thisitem, length); ! 2168: good += length; ! 2169: thisitem = next; ! 2170: } else { ! 2171: thisitem = nextitem(thisitem); ! 2172: } ! 2173: } ! 2174: ! 2175: #endif /* 0 */ ! 2176: } ! 2177: ! 2178: /* ! 2179: * These routines add various telnet commands to the data stream. ! 2180: */ ! 2181: ! 2182: static void ! 2183: doflush() ! 2184: { ! 2185: NET2ADD(IAC, DO); ! 2186: NETADD(TELOPT_TM); ! 2187: flushline = 1; ! 2188: flushout = 1; ! 2189: (void) ttyflush(1); /* Flush/drop output */ ! 2190: /* do printoption AFTER flush, otherwise the output gets tossed... */ ! 2191: printoption("SENT", "do", TELOPT_TM); ! 2192: } ! 2193: ! 2194: void ! 2195: xmitAO() ! 2196: { ! 2197: NET2ADD(IAC, AO); ! 2198: printoption("SENT", "IAC", AO); ! 2199: if (autoflush) { ! 2200: doflush(); ! 2201: } ! 2202: } ! 2203: ! 2204: ! 2205: void ! 2206: xmitEL() ! 2207: { ! 2208: NET2ADD(IAC, EL); ! 2209: printoption("SENT", "IAC", EL); ! 2210: } ! 2211: ! 2212: void ! 2213: xmitEC() ! 2214: { ! 2215: NET2ADD(IAC, EC); ! 2216: printoption("SENT", "IAC", EC); ! 2217: } ! 2218: ! 2219: ! 2220: #if defined(NOT43) ! 2221: int ! 2222: #else /* defined(NOT43) */ ! 2223: void ! 2224: #endif /* defined(NOT43) */ ! 2225: dosynch() ! 2226: { ! 2227: netclear(); /* clear the path to the network */ ! 2228: NETADD(IAC); ! 2229: setneturg(); ! 2230: NETADD(DM); ! 2231: printoption("SENT", "IAC", DM); ! 2232: ! 2233: #if defined(NOT43) ! 2234: return 0; ! 2235: #endif /* defined(NOT43) */ ! 2236: } ! 2237: ! 2238: void ! 2239: get_status() ! 2240: { ! 2241: char tmp[16]; ! 2242: register char *cp; ! 2243: ! 2244: if (my_want_state_is_dont(TELOPT_STATUS)) { ! 2245: printf("Remote side does not support STATUS option\n"); ! 2246: return; ! 2247: } ! 2248: if (!showoptions) ! 2249: printf("You will not see the response unless you set \"options\"\n"); ! 2250: ! 2251: cp = tmp; ! 2252: ! 2253: *cp++ = IAC; ! 2254: *cp++ = SB; ! 2255: *cp++ = TELOPT_STATUS; ! 2256: *cp++ = TELQUAL_SEND; ! 2257: *cp++ = IAC; ! 2258: *cp++ = SE; ! 2259: if (NETROOM() >= cp - tmp) { ! 2260: ring_supply_data(&netoring, tmp, cp-tmp); ! 2261: printsub('>', tmp+2, cp - tmp - 2); ! 2262: } ! 2263: } ! 2264: ! 2265: void ! 2266: intp() ! 2267: { ! 2268: NET2ADD(IAC, IP); ! 2269: printoption("SENT", "IAC", IP); ! 2270: flushline = 1; ! 2271: if (autoflush) { ! 2272: doflush(); ! 2273: } ! 2274: if (autosynch) { ! 2275: dosynch(); ! 2276: } ! 2277: } ! 2278: ! 2279: void ! 2280: sendbrk() ! 2281: { ! 2282: NET2ADD(IAC, BREAK); ! 2283: printoption("SENT", "IAC", BREAK); ! 2284: flushline = 1; ! 2285: if (autoflush) { ! 2286: doflush(); ! 2287: } ! 2288: if (autosynch) { ! 2289: dosynch(); ! 2290: } ! 2291: } ! 2292: ! 2293: void ! 2294: sendabort() ! 2295: { ! 2296: NET2ADD(IAC, ABORT); ! 2297: printoption("SENT", "IAC", ABORT); ! 2298: flushline = 1; ! 2299: if (autoflush) { ! 2300: doflush(); ! 2301: } ! 2302: if (autosynch) { ! 2303: dosynch(); ! 2304: } ! 2305: } ! 2306: ! 2307: void ! 2308: sendsusp() ! 2309: { ! 2310: NET2ADD(IAC, SUSP); ! 2311: printoption("SENT", "IAC", SUSP); ! 2312: flushline = 1; ! 2313: if (autoflush) { ! 2314: doflush(); ! 2315: } ! 2316: if (autosynch) { ! 2317: dosynch(); ! 2318: } ! 2319: } ! 2320: ! 2321: void ! 2322: sendeof() ! 2323: { ! 2324: NET2ADD(IAC, xEOF); ! 2325: printoption("SENT", "IAC", xEOF); ! 2326: } ! 2327: ! 2328: /* ! 2329: * Send a window size update to the remote system. ! 2330: */ ! 2331: ! 2332: void ! 2333: sendnaws() ! 2334: { ! 2335: long rows, cols; ! 2336: unsigned char tmp[16]; ! 2337: register unsigned char *cp; ! 2338: ! 2339: if (my_state_is_wont(TELOPT_NAWS)) ! 2340: return; ! 2341: ! 2342: #define PUTSHORT(cp, x) { if ((*cp++ = ((x)>>8)&0xff) == IAC) *cp++ = IAC; \ ! 2343: if ((*cp++ = ((x))&0xff) == IAC) *cp++ = IAC; } ! 2344: ! 2345: if (TerminalWindowSize(&rows, &cols) == 0) { /* Failed */ ! 2346: return; ! 2347: } ! 2348: ! 2349: cp = tmp; ! 2350: ! 2351: *cp++ = IAC; ! 2352: *cp++ = SB; ! 2353: *cp++ = TELOPT_NAWS; ! 2354: PUTSHORT(cp, cols); ! 2355: PUTSHORT(cp, rows); ! 2356: *cp++ = IAC; ! 2357: *cp++ = SE; ! 2358: if (NETROOM() >= cp - tmp) { ! 2359: ring_supply_data(&netoring, tmp, cp-tmp); ! 2360: printsub('>', tmp+2, cp - tmp - 2); ! 2361: } ! 2362: } ! 2363: ! 2364: tel_enter_binary(rw) ! 2365: int rw; ! 2366: { ! 2367: if (rw&1) ! 2368: send_do(TELOPT_BINARY, 1); ! 2369: if (rw&2) ! 2370: send_will(TELOPT_BINARY, 1); ! 2371: } ! 2372: ! 2373: tel_leave_binary(rw) ! 2374: int rw; ! 2375: { ! 2376: if (rw&1) ! 2377: send_dont(TELOPT_BINARY, 1); ! 2378: if (rw&2) ! 2379: send_wont(TELOPT_BINARY, 1); ! 2380: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.