|
|
1.1 ! root 1: /* ! 2: * Copyright 1984, 1985 by the Regents of the University of ! 3: * California and by Gregory Glenn Minshall. ! 4: * ! 5: * Permission to use, copy, modify, and distribute these ! 6: * programs and their documentation for any purpose and ! 7: * without fee is hereby granted, provided that this ! 8: * copyright and permission appear on all copies and ! 9: * supporting documentation, the name of the Regents of ! 10: * the University of California not be used in advertising ! 11: * or publicity pertaining to distribution of the programs ! 12: * without specific prior permission, and notice be given in ! 13: * supporting documentation that copying and distribution is ! 14: * by permission of the Regents of the University of California ! 15: * and by Gregory Glenn Minshall. Neither the Regents of the ! 16: * University of California nor Gregory Glenn Minshall make ! 17: * representations about the suitability of this software ! 18: * for any purpose. It is provided "as is" without ! 19: * express or implied warranty. ! 20: */ ! 21: ! 22: ! 23: #ifndef lint ! 24: static char sccsid[] = "@(#)tn3270.c 2.7\t5/13/86"; ! 25: #endif ! 26: ! 27: /* ! 28: * User telnet program, specially modified for tn3270. ! 29: */ ! 30: #include <sys/types.h> ! 31: #include <sys/socket.h> ! 32: #include <sys/ioctl.h> ! 33: #include <sys/time.h> ! 34: ! 35: #include <netinet/in.h> ! 36: ! 37: #define TELOPTS ! 38: #include <arpa/telnet.h> ! 39: ! 40: #include <stdio.h> ! 41: #include <ctype.h> ! 42: #include <errno.h> ! 43: #include <signal.h> ! 44: #include <setjmp.h> ! 45: #include <netdb.h> ! 46: ! 47: #define strip(x) ((x)&0177) ! 48: #define min(x,y) ((x<y)? x:y) ! 49: ! 50: static char Ibuf[8*BUFSIZ], *Ifrontp = Ibuf, *Ibackp = Ibuf; ! 51: static char ttyobuf[BUFSIZ], *tfrontp = ttyobuf, *tbackp = ttyobuf; ! 52: static char netobuf[BUFSIZ], *nfrontp = netobuf, *nbackp = netobuf; ! 53: ! 54: static char SbBuffer[100], *pSb = SbBuffer; ! 55: #define Sb_Option SbBuffer[0] ! 56: #define Sb_Command SbBuffer[1] ! 57: ! 58: ! 59: static char hisopts[256]; ! 60: static char myopts[256]; ! 61: ! 62: static char doopt[] = { IAC, DO, '%', 'c', 0 }; ! 63: static char dont[] = { IAC, DONT, '%', 'c', 0 }; ! 64: static char will[] = { IAC, WILL, '%', 'c', 0 }; ! 65: static char wont[] = { IAC, WONT, '%', 'c', 0 }; ! 66: static char sb_terminal[] = { IAC, SB, ! 67: TELOPT_TTYPE, TELQUAL_IS, ! 68: 'I', 'B', 'M', '-', '3', '2', '7', '7', '-', '2', ! 69: IAC, SE }; ! 70: ! 71: /* The following is a real, live, global. */ ! 72: ! 73: /* The point of HaveInput is to give a hint to the terminal output processor ! 74: * that some input from some source (network or terminal) has come in. ! 75: */ ! 76: ! 77: int HaveInput = 1; /* we have received input in the not too distant past */ ! 78: ! 79: ! 80: static int connected; ! 81: static int SentTerminalType = 0; /* returned sb_terminal to other? */ ! 82: static int In3270 = 0; /* we are in 3270 binary mode */ ! 83: static int ISend = 0; /* trying to send network data in */ ! 84: static int ForceMode = -1; /* for debugging */ ! 85: static int net; ! 86: static int showoptions = 0; ! 87: static int debug = 0; ! 88: static int crmod = 0; ! 89: static int printnet = 0; ! 90: static FILE *NetTrace; ! 91: static char *prompt; ! 92: static char escape = CTRL(]); ! 93: ! 94: static char line[200]; ! 95: static int margc; ! 96: static char *margv[20]; ! 97: ! 98: static jmp_buf toplevel; ! 99: static jmp_buf peerdied; ! 100: ! 101: extern int errno; ! 102: ! 103: int quit(), suspend(); ! 104: static int tn(), bye(), help(); ! 105: static int setescape(), status(), toggle(), setoptions(); ! 106: static int setcrmod(), setdebug(), SetPrintNet(); ! 107: ! 108: #define HELPINDENT (sizeof ("connect")) ! 109: ! 110: struct cmd { ! 111: char *name; /* command name */ ! 112: char *help; /* help string */ ! 113: int (*handler)(); /* routine which executes command */ ! 114: int dohelp; /* Should we give general help information? */ ! 115: }; ! 116: ! 117: static char openhelp[] = "connect to a site"; ! 118: static char closehelp[] = "close current connection"; ! 119: static char quithelp[] = "exit telnet"; ! 120: static char zhelp[] = "suspend telnet"; ! 121: static char debughelp[] = "toggle debugging"; ! 122: static char escapehelp[] = "set escape character"; ! 123: static char statushelp[] = "print status information"; ! 124: static char helphelp[] = "print help information"; ! 125: static char optionshelp[] = "toggle viewing of options processing"; ! 126: static char crmodhelp[] = "toggle mapping of received carriage returns"; ! 127: static char printnethelp[] = "print out raw data to/from net"; ! 128: ! 129: static struct cmd cmdtab[] = { ! 130: { "open", openhelp, tn, 1 }, ! 131: { "close", closehelp, bye, 1 }, ! 132: { "quit", quithelp, quit, 1 }, ! 133: { "z", zhelp, suspend, 1 }, ! 134: { "suspend", zhelp, suspend, 0 }, ! 135: { "escape", escapehelp, setescape, 0 }, ! 136: { "status", statushelp, status, 1 }, ! 137: { "options", optionshelp, setoptions, 0 }, ! 138: { "crmod", crmodhelp, setcrmod, 0 }, ! 139: { "debug", debughelp, setdebug, 0 }, ! 140: { "printnet", printnethelp, SetPrintNet, 0 }, ! 141: { "?", helphelp, help, 1 }, ! 142: { "help", helphelp, help, 0 }, ! 143: 0 ! 144: }; ! 145: ! 146: static struct sockaddr_in sin; ! 147: ! 148: static int intr(), deadpeer(), inputAvailable(); ! 149: static char *control(); ! 150: static struct cmd *getcmd(); ! 151: static struct servent *sp; ! 152: ! 153: static struct tchars otc; ! 154: static struct ltchars oltc; ! 155: static struct sgttyb ottyb; ! 156: ! 157: main(argc, argv) ! 158: int argc; ! 159: char *argv[]; ! 160: { ! 161: ioctl(0, TIOCGETP, (char *)&ottyb); ! 162: ioctl(0, TIOCGETC, (char *)&otc); ! 163: ioctl(0, TIOCGLTC, (char *)&oltc); ! 164: sp = getservbyname("telnet", "tcp"); ! 165: if (sp == 0) { ! 166: ExitString(stderr, "telnet: tcp/telnet: unknown service\n", 1); ! 167: } ! 168: NetTrace = stdout; ! 169: prompt = argv[0]; ! 170: if (argc > 1 && !strcmp(argv[1], "-d")) { ! 171: debug = SO_DEBUG, argv++, argc--; ! 172: } ! 173: if (argc > 1 && !strcmp(argv[1], "-n")) { ! 174: argv++; ! 175: argc--; ! 176: if (argc > 1) { /* get file name */ ! 177: NetTrace = fopen(argv[1], "w"); ! 178: argv++; ! 179: argc--; ! 180: if (NetTrace == NULL) { ! 181: NetTrace = stdout; ! 182: } ! 183: } ! 184: } ! 185: if (argc != 1) { ! 186: if (setjmp(toplevel) != 0) ! 187: Exit(0); ! 188: tn(argc, argv); ! 189: } ! 190: setjmp(toplevel); ! 191: for (;;) ! 192: command(1); ! 193: } ! 194: ! 195: static char *hostname; ! 196: static char hnamebuf[32]; ! 197: ! 198: static ! 199: tn(argc, argv) ! 200: int argc; ! 201: char *argv[]; ! 202: { ! 203: register struct hostent *host; ! 204: char *strcpy(); ! 205: ! 206: if (connected) { ! 207: printf("?Already connected to %s\n", hostname); ! 208: return; ! 209: } ! 210: if (argc < 2) { ! 211: (void) strcpy(line, "Connect "); ! 212: printf("(to) "); ! 213: gets(&line[strlen(line)]); ! 214: makeargv(); ! 215: argc = margc; ! 216: argv = margv; ! 217: } ! 218: if (argc > 3) { ! 219: printf("usage: %s host-name [port]\n", argv[0]); ! 220: return; ! 221: } ! 222: host = gethostbyname(argv[1]); ! 223: if (host) { ! 224: sin.sin_family = host->h_addrtype; ! 225: bcopy(host->h_addr, (caddr_t)&sin.sin_addr, host->h_length); ! 226: hostname = host->h_name; ! 227: } else { ! 228: sin.sin_family = AF_INET; ! 229: sin.sin_addr.s_addr = inet_addr(argv[1]); ! 230: if (sin.sin_addr.s_addr == -1) { ! 231: printf("%s: unknown host\n", argv[1]); ! 232: return; ! 233: } ! 234: (void) strcpy(hnamebuf, argv[1]); ! 235: hostname = hnamebuf; ! 236: } ! 237: sin.sin_port = sp->s_port; ! 238: if (argc == 3) { ! 239: sin.sin_port = atoi(argv[2]); ! 240: sin.sin_port = htons(sin.sin_port); ! 241: } ! 242: net = socket(AF_INET, SOCK_STREAM, 0); ! 243: if (net < 0) { ! 244: perror("telnet: socket"); ! 245: return; ! 246: } ! 247: if (debug && setsockopt(net, SOL_SOCKET, SO_DEBUG, 0, 0) < 0) ! 248: perror("setsockopt (SO_DEBUG)"); ! 249: signal(SIGINT, intr); ! 250: signal(SIGPIPE, deadpeer); ! 251: printf("Trying...\n"); ! 252: if (connect(net, (struct sockaddr *)&sin, sizeof (sin)) < 0) { ! 253: perror("telnet: connect"); ! 254: signal(SIGINT, SIG_DFL); ! 255: return; ! 256: } ! 257: connected++; ! 258: call(status, "status", 0); ! 259: if (setjmp(peerdied) == 0) ! 260: telnet(); ! 261: if (In3270) { ! 262: Stop3270(1); ! 263: } ! 264: ExitString(stderr, "Connection closed by foreign host.\n", 1); ! 265: } ! 266: ! 267: /* ! 268: * Print status about the connection. ! 269: */ ! 270: /*VARARGS*/ ! 271: static ! 272: status() ! 273: { ! 274: if (connected) ! 275: printf("Connected to %s.\n", hostname); ! 276: else ! 277: printf("No connection.\n"); ! 278: /*printf("Escape character is '%s'.\n", control(escape));*/ ! 279: fflush(stdout); ! 280: } ! 281: ! 282: static ! 283: makeargv() ! 284: { ! 285: register char *cp; ! 286: register char **argp = margv; ! 287: ! 288: margc = 0; ! 289: for (cp = line; *cp;) { ! 290: while (isspace(*cp)) ! 291: cp++; ! 292: if (*cp == '\0') ! 293: break; ! 294: *argp++ = cp; ! 295: margc += 1; ! 296: while (*cp != '\0' && !isspace(*cp)) ! 297: cp++; ! 298: if (*cp == '\0') ! 299: break; ! 300: *cp++ = '\0'; ! 301: } ! 302: *argp++ = 0; ! 303: } ! 304: ! 305: /*VARARGS*/ ! 306: suspend() ! 307: { ! 308: register int save; ! 309: ! 310: save = mode(0); ! 311: kill(0, SIGTSTP); ! 312: /* reget parameters in case they were changed */ ! 313: ioctl(0, TIOCGETP, (char *)&ottyb); ! 314: ioctl(0, TIOCGETC, (char *)&otc); ! 315: ioctl(0, TIOCGLTC, (char *)&oltc); ! 316: (void) mode(save); ! 317: } ! 318: ! 319: /*VARARGS*/ ! 320: static ! 321: bye() ! 322: { ! 323: register char *op; ! 324: ! 325: (void) mode(0); ! 326: if (connected) { ! 327: shutdown(net, 2); ! 328: printf("Connection closed.\n"); ! 329: close(net); ! 330: connected = 0; ! 331: /* reset his options */ ! 332: for (op = hisopts; op < &hisopts[256]; op++) ! 333: *op = 0; ! 334: } ! 335: } ! 336: ! 337: /*VARARGS*/ ! 338: quit() ! 339: { ! 340: call(bye, "bye", 0); ! 341: Exit(0); ! 342: } ! 343: ! 344: /* ! 345: * Help command. ! 346: */ ! 347: static ! 348: help(argc, argv) ! 349: int argc; ! 350: char *argv[]; ! 351: { ! 352: register struct cmd *c; ! 353: ! 354: if (argc == 1) { ! 355: printf("Commands may be abbreviated. Commands are:\n\n"); ! 356: for (c = cmdtab; c->name; c++) ! 357: if (c->dohelp) { ! 358: printf("%-*s\t%s\n", HELPINDENT, c->name, c->help); ! 359: } ! 360: return; ! 361: } ! 362: while (--argc > 0) { ! 363: register char *arg; ! 364: arg = *++argv; ! 365: c = getcmd(arg); ! 366: if (c == (struct cmd *)-1) ! 367: printf("?Ambiguous help command %s\n", arg); ! 368: else if (c == (struct cmd *)0) ! 369: printf("?Invalid help command %s\n", arg); ! 370: else ! 371: printf("%s\n", c->help); ! 372: } ! 373: } ! 374: ! 375: /* ! 376: * Call routine with argc, argv set from args (terminated by 0). ! 377: * VARARGS2 ! 378: */ ! 379: static ! 380: call(routine, args) ! 381: int (*routine)(); ! 382: int args; ! 383: { ! 384: register int *argp; ! 385: register int argc; ! 386: ! 387: for (argc = 0, argp = &args; *argp++ != 0; argc++) ! 388: ; ! 389: (*routine)(argc, &args); ! 390: } ! 391: ! 392: static struct tchars notc = { -1, -1, -1, -1, -1, -1 }; ! 393: static struct ltchars noltc = { -1, -1, -1, -1, -1, -1 }; ! 394: ! 395: mode(f) ! 396: register int f; ! 397: { ! 398: static int prevmode = 0; ! 399: struct tchars *tc, tc3; ! 400: struct ltchars *ltc; ! 401: struct sgttyb sb; ! 402: int onoff, old; ! 403: ! 404: if (prevmode == f) ! 405: return (f); ! 406: old = prevmode; ! 407: prevmode = f; ! 408: sb = ottyb; ! 409: if (ForceMode != -1) { ! 410: f = ForceMode; ! 411: ForceMode = -1; ! 412: } ! 413: switch (f) { ! 414: ! 415: case 0: ! 416: onoff = 0; ! 417: tc = &otc; ! 418: ltc = &oltc; ! 419: break; ! 420: ! 421: case 1: /* the rawest */ ! 422: case 2: /* allows for local echoing, newline mapping */ ! 423: case 3: /* like 1, but with XON/XOFF */ ! 424: ! 425: sb.sg_flags |= CBREAK; ! 426: if ((f == 1) || (f == 3)) { ! 427: sb.sg_flags &= ~(ECHO|CRMOD); ! 428: } else { ! 429: sb.sg_flags |= ECHO|CRMOD; ! 430: } ! 431: sb.sg_erase = sb.sg_kill = -1; ! 432: if (f == 3) { ! 433: tc = &tc3; ! 434: tc3 = notc; ! 435: /* get XON, XOFF characters */ ! 436: tc3.t_startc = otc.t_startc; ! 437: tc3.t_stopc = otc.t_stopc; ! 438: } else { ! 439: tc = ¬c; ! 440: } ! 441: ltc = &noltc; ! 442: onoff = 1; ! 443: break; ! 444: ! 445: default: ! 446: return(old); ! 447: } ! 448: ioctl(fileno(stdin), TIOCSLTC, (char *)ltc); ! 449: ioctl(fileno(stdin), TIOCSETC, (char *)tc); ! 450: ioctl(fileno(stdin), TIOCSETP, (char *)&sb); ! 451: ioctl(fileno(stdin), FIONBIO, (char *)&onoff); ! 452: ioctl(fileno(stdout), FIONBIO, (char *)&onoff); ! 453: ioctl(fileno(stdin), FIOASYNC, (char *)&onoff); ! 454: return (old); ! 455: } ! 456: ! 457: static char sibuf[BUFSIZ], *sbp; ! 458: static char tibuf[BUFSIZ], *tbp; ! 459: static int scc, tcc; ! 460: static int tin, tout; /* file descriptors */ ! 461: ! 462: /* ! 463: * Select from tty and network... ! 464: */ ! 465: static ! 466: telnet() ! 467: { ! 468: int on = 1; ! 469: int negativePid = -getpid(); ! 470: int schedValue; ! 471: ! 472: (void) mode(2); ! 473: ioctl(net, FIONBIO, (char *)&on); ! 474: ioctl(net, FIOASYNC, (char *)&on); /* hear about input */ ! 475: ioctl(net, SIOCSPGRP, (char *)&negativePid); /* set my pid */ ! 476: tin = fileno(stdin); ! 477: tout = fileno(stdout); ! 478: ! 479: for (;;) { ! 480: while (schedValue = Scheduler(0)) { ! 481: if (schedValue == -1) { ! 482: (void) mode(0); ! 483: return; ! 484: } ! 485: } ! 486: /* If there is data waiting to go out to terminal, don't ! 487: * schedule any more data for the terminal. ! 488: */ ! 489: if (tfrontp-tbackp) { ! 490: schedValue = 1; ! 491: } else { ! 492: schedValue = DoTerminalOutput(); ! 493: } ! 494: if (schedValue) { ! 495: if (Scheduler(1) == -1) { ! 496: (void) mode(0); ! 497: return; ! 498: } ! 499: } ! 500: } ! 501: } ! 502: ! 503: ! 504: /* Loop around once. */ ! 505: ! 506: static ! 507: Scheduler(block) ! 508: int block; /* should we block in the select? */ ! 509: { ! 510: register int c; ! 511: int ibits = 0, obits = 0; ! 512: /* One wants to be a bit careful about setting returnValue ! 513: * to one, since a one implies we did some useful work, ! 514: * and therefore probably won't be called to block next ! 515: * time. ! 516: */ ! 517: int returnValue = 0; ! 518: static struct timeval TimeValue = {0}; ! 519: ! 520: if (!In3270) { ! 521: if (nfrontp - nbackp) ! 522: obits |= (1 << net); ! 523: else if (tcc == 0) { ! 524: ibits |= (1 << tin); ! 525: } ! 526: if (tfrontp - tbackp) ! 527: obits |= (1 << tout); ! 528: else if (!ISend) ! 529: ibits |= (1 << net); ! 530: } else { ! 531: if (nfrontp - nbackp) { /* something for network? */ ! 532: obits |= 1<<net; /* yes - wait for space */ ! 533: } ! 534: if (tcc == 0) { /* any pending tty input? */ ! 535: ibits |= 1<<tin; /* no, look for new input */ ! 536: } ! 537: if (tfrontp-tbackp) { /* any pending tty output? */ ! 538: obits |= 1<<tout; /* yes - wait for space */ ! 539: } ! 540: if (!ISend) { /* any pending net input? */ ! 541: ibits |= 1<<net; /* no, look for new input */ ! 542: } ! 543: } ! 544: if (scc < 0 && tcc < 0) { ! 545: return(-1); ! 546: } ! 547: if (HaveInput) { /* Reprime SIGIO handler if appropriate */ ! 548: HaveInput = 0; ! 549: signal(SIGIO, inputAvailable); ! 550: } ! 551: select(16, &ibits, &obits, (int *) 0, ! 552: (block)? (struct timeval *)0:&TimeValue); ! 553: if (ibits == 0 && obits == 0 && block) { ! 554: /* I don't like this, does it ever happen? */ ! 555: printf("sleep(5) from tn3270, after select\n"); ! 556: sleep(5); ! 557: return(0); ! 558: } ! 559: ! 560: /* ! 561: * Something to read from the network... ! 562: */ ! 563: if (ibits & (1 << net)) { ! 564: scc = read(net, sibuf, sizeof (sibuf)); ! 565: if (scc < 0 && errno == EWOULDBLOCK) ! 566: scc = 0; ! 567: else { ! 568: if (scc <= 0) ! 569: return(-1); ! 570: sbp = sibuf; ! 571: if (printnet) { ! 572: Dump('<', sbp, scc); ! 573: } ! 574: returnValue = 1; /* did something usefull */ ! 575: } ! 576: } ! 577: ! 578: /* ! 579: * Something to read from the tty... ! 580: */ ! 581: if (ibits & (1 << tin)) { ! 582: tcc = read(tin, tibuf, sizeof tibuf); ! 583: if (tcc < 0 && errno == EWOULDBLOCK) ! 584: tcc = 0; ! 585: else { ! 586: if (tcc <= 0) ! 587: return(-1); ! 588: tbp = tibuf; ! 589: returnValue = 1; /* did something usefull */ ! 590: } ! 591: } ! 592: ! 593: if (tcc > 0) { ! 594: if (In3270) { ! 595: c = DataFromTerminal(tbp, tcc); ! 596: if (c) { ! 597: returnValue = 1; /* did something usefull */ ! 598: } ! 599: tcc -= c; ! 600: tbp += c; ! 601: } else { ! 602: returnValue = 1; /* did something usefull */ ! 603: while (tcc > 0) { ! 604: if ((&netobuf[BUFSIZ] - nfrontp) < 2) ! 605: break; ! 606: c = *tbp++ & 0377, tcc--; ! 607: if (strip(c) == escape) { ! 608: command(0); ! 609: tcc = 0; ! 610: break; ! 611: } ! 612: if (c == IAC) ! 613: *nfrontp++ = c; ! 614: *nfrontp++ = c; ! 615: } ! 616: } ! 617: } ! 618: if ((obits & (1 << net)) && (c = (int) (nfrontp - nbackp)) > 0) { ! 619: netflush(); ! 620: if (c != (int) (nfrontp-nbackp)) { ! 621: returnValue = 1; ! 622: } ! 623: } ! 624: if (scc > 0) { ! 625: if (Ifrontp+scc >= Ibuf+sizeof Ibuf) { ! 626: if (Ibackp != Ibuf) { /* do some copying */ ! 627: bcopy(Ibackp, Ibuf, Ifrontp-Ibackp); ! 628: Ifrontp -= (Ibackp-Ibuf); ! 629: Ibackp = Ibuf; ! 630: } ! 631: } ! 632: if (Ifrontp+scc < Ibuf+sizeof Ibuf) { ! 633: returnValue = 1; /* doing something useful */ ! 634: telrcv(); ! 635: } /* Else - we may never recover */ ! 636: } ! 637: if ((obits & (1 << tout)) && (c = (int) (tfrontp - tbackp)) > 0) { ! 638: ttyflush(); ! 639: if (c != (int) (tfrontp-tbackp)) { ! 640: returnValue = 1; ! 641: } ! 642: } ! 643: if (In3270 && (c = (int) (Ifrontp-Ibackp))) { ! 644: Ibackp += DataFromNetwork(Ibackp, Ifrontp-Ibackp, ISend); ! 645: if (c != (int) (Ifrontp-Ibackp)) { ! 646: returnValue = 1; ! 647: } ! 648: if (Ibackp == Ifrontp) { ! 649: Ibackp = Ifrontp = Ibuf; ! 650: ISend = 0; /* take data from network */ ! 651: } ! 652: } ! 653: return(returnValue); /* good return */ ! 654: } ! 655: ! 656: command(top) ! 657: int top; ! 658: { ! 659: register struct cmd *c; ! 660: int oldmode; ! 661: ! 662: oldmode = mode(0); ! 663: if (!top) ! 664: putchar('\n'); ! 665: else ! 666: signal(SIGINT, SIG_DFL); ! 667: for (;;) { ! 668: printf("%s> ", prompt); ! 669: if (gets(line) == 0) { ! 670: if (feof(stdin)) { ! 671: clearerr(stdin); ! 672: putchar('\n'); ! 673: } ! 674: break; ! 675: } ! 676: if (line[0] == 0) ! 677: break; ! 678: makeargv(); ! 679: c = getcmd(margv[0]); ! 680: if (c == (struct cmd *)-1) { ! 681: printf("?Ambiguous command\n"); ! 682: continue; ! 683: } ! 684: if (c == 0) { ! 685: printf("?Invalid command\n"); ! 686: continue; ! 687: } ! 688: (*c->handler)(margc, margv); ! 689: if (c->handler != help) ! 690: break; ! 691: } ! 692: if (!top) { ! 693: if (!connected) ! 694: longjmp(toplevel, 1); ! 695: (void) mode(oldmode); ! 696: } ! 697: } ! 698: ! 699: /* ! 700: * Telnet receiver states for fsm ! 701: */ ! 702: #define TS_DATA 0 ! 703: #define TS_IAC 1 ! 704: #define TS_WILL 2 ! 705: #define TS_WONT 3 ! 706: #define TS_DO 4 ! 707: #define TS_DONT 5 ! 708: #define TS_SB 6 /* in sub-negotiation */ ! 709: #define TS_SE 7 /* coming out of sub-negotiation */ ! 710: ! 711: #define SB_ACCUM(c) {*pSb = c; /* accumulate character */ \ ! 712: if (pSb >= SbBuffer+sizeof (SbBuffer)) { \ ! 713: /* can't accept any more */ \ ! 714: pSb = SbBuffer; \ ! 715: } \ ! 716: pSb++;} ! 717: ! 718: static ! 719: telrcv() ! 720: { ! 721: register int c; ! 722: register char *Sbp; ! 723: register int Scc; ! 724: static int state = TS_DATA; ! 725: ! 726: while (scc > 0) { ! 727: c = *sbp++ & 0377, scc--; ! 728: switch (state) { ! 729: ! 730: case TS_DATA: ! 731: if (c == IAC) { ! 732: state = TS_IAC; ! 733: continue; ! 734: } ! 735: /* We optimize this loop, since it is ! 736: * where we spend 99% of this routine. ! 737: */ ! 738: if (In3270) { ! 739: *Ifrontp++ = c; ! 740: Sbp = sbp; ! 741: Scc = scc; ! 742: while (Scc > 0) { ! 743: c = *Sbp++ & 0377, Scc--; ! 744: if (c == IAC) { ! 745: state = TS_IAC; ! 746: break; ! 747: } ! 748: *Ifrontp++ = c; ! 749: } ! 750: sbp = Sbp; ! 751: scc = Scc; ! 752: } else { ! 753: *tfrontp++ = c; ! 754: /* ! 755: * This hack is needed since we can't set ! 756: * CRMOD on output only. Machines like MULTICS ! 757: * like to send \r without \n; since we must ! 758: * turn off CRMOD to get proper input, the mapping ! 759: * is done here (sigh). ! 760: */ ! 761: if (c == '\r' && crmod && !In3270) ! 762: *tfrontp++ = '\n'; ! 763: } ! 764: continue; ! 765: ! 766: ! 767: case TS_IAC: ! 768: switch (c) { ! 769: ! 770: case WILL: ! 771: state = TS_WILL; ! 772: continue; ! 773: ! 774: case WONT: ! 775: state = TS_WONT; ! 776: continue; ! 777: ! 778: case DO: ! 779: state = TS_DO; ! 780: continue; ! 781: ! 782: case DONT: ! 783: state = TS_DONT; ! 784: continue; ! 785: ! 786: case DM: ! 787: outputPurge(); ! 788: break; ! 789: ! 790: case NOP: ! 791: case GA: ! 792: break; ! 793: ! 794: case SB: ! 795: state = TS_SB; ! 796: pSb = SbBuffer; /* where to collect */ ! 797: continue; ! 798: ! 799: case EOR: ! 800: if (In3270) { ! 801: Ibackp += DataFromNetwork(Ibackp, ! 802: Ifrontp-Ibackp, 1); ! 803: if (Ibackp == Ifrontp) { ! 804: Ibackp = Ifrontp = Ibuf; ! 805: ISend = 0; /* should have been! */ ! 806: } else { ! 807: ISend = 1; ! 808: } ! 809: } ! 810: break; ! 811: ! 812: case IAC: ! 813: if (In3270) { ! 814: *Ifrontp++ = IAC; ! 815: } else { ! 816: *tfrontp++ = IAC; ! 817: } ! 818: break; ! 819: ! 820: default: ! 821: break; ! 822: } ! 823: state = TS_DATA; ! 824: continue; ! 825: ! 826: case TS_WILL: ! 827: printoption("RCVD", will, c, !hisopts[c]); ! 828: if (!hisopts[c]) ! 829: willoption(c); ! 830: state = TS_DATA; ! 831: continue; ! 832: ! 833: case TS_WONT: ! 834: printoption("RCVD", wont, c, hisopts[c]); ! 835: if (hisopts[c]) ! 836: wontoption(c); ! 837: state = TS_DATA; ! 838: continue; ! 839: ! 840: case TS_DO: ! 841: printoption("RCVD", doopt, c, !myopts[c]); ! 842: if (!myopts[c]) ! 843: dooption(c); ! 844: state = TS_DATA; ! 845: continue; ! 846: ! 847: case TS_DONT: ! 848: printoption("RCVD", dont, c, myopts[c]); ! 849: if (myopts[c]) { ! 850: myopts[c] = 0; ! 851: if (c == TELOPT_BINARY) { ! 852: SetIn3270(); ! 853: } ! 854: sprintf(nfrontp, wont, c); ! 855: nfrontp += sizeof (wont) - 2; ! 856: printoption("SENT", wont, c); ! 857: } ! 858: state = TS_DATA; ! 859: continue; ! 860: case TS_SB: ! 861: if (c == IAC) { ! 862: state = TS_SE; ! 863: continue; ! 864: } ! 865: SB_ACCUM(c); ! 866: continue; ! 867: case TS_SE: ! 868: if (c != SE) { ! 869: if (c != IAC) { ! 870: SB_ACCUM(IAC); ! 871: } ! 872: SB_ACCUM(c); ! 873: state = TS_SB; ! 874: } else { ! 875: /* this is the end of the sub negotiation */ ! 876: /* we only allow a termtype, send, sub */ ! 877: if ((Sb_Option != TELOPT_TTYPE) || ! 878: (Sb_Command != TELQUAL_SEND)) { ! 879: /* what to do? XXX */ ! 880: } else { ! 881: /* send our type */ ! 882: SentTerminalType = 1; ! 883: SetIn3270(); ! 884: bcopy(sb_terminal, nfrontp, sizeof sb_terminal); ! 885: nfrontp += sizeof sb_terminal; ! 886: printoption("SENT", sb_terminal, ! 887: TELOPT_TTYPE); ! 888: } ! 889: state = TS_DATA; ! 890: } ! 891: } ! 892: } ! 893: } ! 894: ! 895: static ! 896: willoption(option) ! 897: int option; ! 898: { ! 899: char *fmt; ! 900: ! 901: switch (option) { ! 902: ! 903: case TELOPT_ECHO: ! 904: (void) mode(1); ! 905: ! 906: case TELOPT_BINARY: ! 907: hisopts[option] = 1; ! 908: SetIn3270(); ! 909: fmt = doopt; ! 910: break; ! 911: ! 912: case TELOPT_EOR: ! 913: case TELOPT_SGA: ! 914: hisopts[option] = 1; ! 915: fmt = doopt; ! 916: break; ! 917: ! 918: case TELOPT_TM: ! 919: fmt = dont; ! 920: break; ! 921: ! 922: default: ! 923: fmt = dont; ! 924: break; ! 925: } ! 926: sprintf(nfrontp, fmt, option); ! 927: nfrontp += sizeof (dont) - 2; ! 928: printoption("SENT", fmt, option); ! 929: } ! 930: ! 931: static ! 932: wontoption(option) ! 933: int option; ! 934: { ! 935: char *fmt; ! 936: ! 937: switch (option) { ! 938: ! 939: case TELOPT_BINARY: ! 940: hisopts[option] = 0; ! 941: SetIn3270(); ! 942: fmt = doopt; ! 943: break; ! 944: ! 945: case TELOPT_ECHO: ! 946: (void) mode(2); ! 947: ! 948: case TELOPT_SGA: ! 949: hisopts[option] = 0; ! 950: fmt = dont; ! 951: break; ! 952: ! 953: default: ! 954: fmt = dont; ! 955: } ! 956: sprintf(nfrontp, fmt, option); ! 957: nfrontp += sizeof (doopt) - 2; ! 958: printoption("SENT", fmt, option); ! 959: } ! 960: ! 961: static ! 962: dooption(option) ! 963: int option; ! 964: { ! 965: char *fmt; ! 966: ! 967: switch (option) { ! 968: ! 969: case TELOPT_TTYPE: ! 970: case TELOPT_BINARY: ! 971: myopts[option] = 1; ! 972: SetIn3270(); ! 973: fmt = will; ! 974: break; ! 975: ! 976: case TELOPT_TM: ! 977: fmt = wont; ! 978: break; ! 979: ! 980: case TELOPT_ECHO: ! 981: (void) mode(2); ! 982: fmt = will; ! 983: hisopts[option] = 0; ! 984: break; ! 985: ! 986: case TELOPT_EOR: ! 987: case TELOPT_SGA: ! 988: fmt = will; ! 989: break; ! 990: ! 991: default: ! 992: fmt = wont; ! 993: break; ! 994: } ! 995: sprintf(nfrontp, fmt, option); ! 996: nfrontp += (sizeof dont)-2; ! 997: printoption("SENT", fmt, option); ! 998: } ! 999: ! 1000: static ! 1001: SetIn3270() ! 1002: { ! 1003: if (SentTerminalType && myopts[TELOPT_BINARY] && hisopts[TELOPT_BINARY]) { ! 1004: if (!In3270) { ! 1005: In3270 = 1; ! 1006: OptInit(); /* initialize mappings */ ! 1007: /* initialize terminal key mapping */ ! 1008: (void) DataFromTerminal(ttyobuf, 0); ! 1009: (void) mode(3); ! 1010: } ! 1011: } else { ! 1012: if (In3270) { ! 1013: Stop3270(1); ! 1014: In3270 = 0; ! 1015: (void) mode(2); ! 1016: } ! 1017: } ! 1018: } ! 1019: ! 1020: /* ! 1021: * Set the escape character. ! 1022: */ ! 1023: static ! 1024: setescape(argc, argv) ! 1025: int argc; ! 1026: char *argv[]; ! 1027: { ! 1028: register char *arg; ! 1029: char buf[50]; ! 1030: ! 1031: if (argc > 2) ! 1032: arg = argv[1]; ! 1033: else { ! 1034: printf("new escape character: "); ! 1035: gets(buf); ! 1036: arg = buf; ! 1037: } ! 1038: if (arg[0] != '\0') ! 1039: escape = arg[0]; ! 1040: printf("Escape character is '%s'.\n", control(escape)); ! 1041: fflush(stdout); ! 1042: } ! 1043: ! 1044: /*VARARGS*/ ! 1045: static ! 1046: setoptions() ! 1047: { ! 1048: ! 1049: showoptions = !showoptions; ! 1050: printf("%s show option processing.\n", showoptions ? "Will" : "Wont"); ! 1051: fflush(stdout); ! 1052: } ! 1053: ! 1054: /*VARARGS*/ ! 1055: static ! 1056: setcrmod() ! 1057: { ! 1058: ! 1059: crmod = !crmod; ! 1060: printf("%s map carriage return on output.\n", crmod ? "Will" : "Wont"); ! 1061: fflush(stdout); ! 1062: } ! 1063: ! 1064: /*VARARGS*/ ! 1065: static ! 1066: setdebug() ! 1067: { ! 1068: ! 1069: debug = !debug; ! 1070: printf("%s turn on socket level debugging.\n", ! 1071: debug ? "Will" : "Wont"); ! 1072: fflush(stdout); ! 1073: if (debug && net > 0 && setsockopt(net, SOL_SOCKET, SO_DEBUG, 0, 0) < 0) ! 1074: perror("setsockopt (SO_DEBUG)"); ! 1075: } ! 1076: ! 1077: /*VARARGS*/ ! 1078: static ! 1079: SetPrintNet() ! 1080: { ! 1081: ! 1082: printnet = !printnet; ! 1083: printf("%s turn on printing of raw network traffic.\n", ! 1084: printnet ? "Will" : "Wont"); ! 1085: } ! 1086: ! 1087: /* ! 1088: * Construct a control character sequence ! 1089: * for a special character. ! 1090: */ ! 1091: static char * ! 1092: control(c) ! 1093: register int c; ! 1094: { ! 1095: static char buf[3]; ! 1096: ! 1097: if (c == 0177) ! 1098: return ("^?"); ! 1099: if (c >= 040) { ! 1100: buf[0] = c; ! 1101: buf[1] = 0; ! 1102: } else { ! 1103: buf[0] = '^'; ! 1104: buf[1] = '@'+c; ! 1105: buf[2] = 0; ! 1106: } ! 1107: return (buf); ! 1108: } ! 1109: ! 1110: static struct cmd * ! 1111: getcmd(name) ! 1112: register char *name; ! 1113: { ! 1114: register char *p, *q; ! 1115: register struct cmd *c, *found; ! 1116: register int nmatches, longest; ! 1117: ! 1118: longest = 0; ! 1119: nmatches = 0; ! 1120: found = 0; ! 1121: for (c = cmdtab; p = c->name; c++) { ! 1122: for (q = name; *q == *p++; q++) ! 1123: if (*q == 0) /* exact match? */ ! 1124: return (c); ! 1125: if (!*q) { /* the name was a prefix */ ! 1126: if (q - name > longest) { ! 1127: longest = q - name; ! 1128: nmatches = 1; ! 1129: found = c; ! 1130: } else if (q - name == longest) ! 1131: nmatches++; ! 1132: } ! 1133: } ! 1134: if (nmatches > 1) ! 1135: return ((struct cmd *)-1); ! 1136: return (found); ! 1137: } ! 1138: ! 1139: static ! 1140: deadpeer() ! 1141: { ! 1142: (void) mode(0); ! 1143: longjmp(peerdied, -1); ! 1144: } ! 1145: ! 1146: static ! 1147: intr() ! 1148: { ! 1149: (void) mode(0); ! 1150: longjmp(toplevel, -1); ! 1151: } ! 1152: ! 1153: static ! 1154: inputAvailable() ! 1155: { ! 1156: HaveInput = 1; ! 1157: } ! 1158: ! 1159: /* outputPurge() - get rid of all output destined for terminal. */ ! 1160: outputPurge() ! 1161: { ! 1162: ioctl(fileno(stdout), TIOCFLUSH, (char *)0); ! 1163: tbackp = tfrontp = ttyobuf; ! 1164: } ! 1165: ! 1166: ttyflush() ! 1167: { ! 1168: int n; ! 1169: ! 1170: if ((n = tfrontp - tbackp) > 0) ! 1171: n = write(tout, tbackp, n); ! 1172: if (n < 0) ! 1173: return; ! 1174: tbackp += n; ! 1175: if (tbackp == tfrontp) ! 1176: tbackp = tfrontp = ttyobuf; ! 1177: } ! 1178: ! 1179: /* TtyChars() - returns the number of characters in the TTY buffer */ ! 1180: TtyChars() ! 1181: { ! 1182: return(tfrontp-tbackp); ! 1183: } ! 1184: ! 1185: netflush() ! 1186: { ! 1187: int n; ! 1188: ! 1189: if ((n = nfrontp - nbackp) > 0) ! 1190: n = write(net, nbackp, n); ! 1191: if (n < 0) { ! 1192: if (errno != ENOBUFS && errno != EWOULDBLOCK) { ! 1193: (void) mode(0); ! 1194: perror(hostname); ! 1195: close(net); ! 1196: longjmp(peerdied, -1); ! 1197: /*NOTREACHED*/ ! 1198: } ! 1199: n = 0; ! 1200: } ! 1201: if (printnet) { ! 1202: Dump('>', nbackp, n); ! 1203: } ! 1204: nbackp += n; ! 1205: if (nbackp == nfrontp) ! 1206: nbackp = nfrontp = netobuf; ! 1207: } ! 1208: ! 1209: /* DataToNetwork - queue up some data to go to network. When last byte is ! 1210: queued, we add on an IAC EOR sequence (so, don't call us until you ! 1211: want that done...) ! 1212: */ ! 1213: ! 1214: int ! 1215: DataToNetwork(buffer, count) ! 1216: register char *buffer; /* where the data is */ ! 1217: register int count; /* how much to send */ ! 1218: { ! 1219: register int c; ! 1220: int origCount; ! 1221: ! 1222: origCount = count; ! 1223: ! 1224: while (count) { ! 1225: if ((&netobuf[sizeof netobuf] - nfrontp) < 6) { ! 1226: netflush(); ! 1227: if ((&netobuf[sizeof netobuf] - nfrontp) < 6) { ! 1228: break; ! 1229: } ! 1230: } ! 1231: c = *buffer++; ! 1232: count--; ! 1233: if (c == IAC) { ! 1234: *nfrontp++ = IAC; ! 1235: *nfrontp++ = IAC; ! 1236: } else { ! 1237: *nfrontp++ = c; ! 1238: } ! 1239: } ! 1240: ! 1241: if (!count) { ! 1242: *nfrontp++ = IAC; ! 1243: *nfrontp++ = EOR; ! 1244: netflush(); /* try to move along as quickly as ... */ ! 1245: } ! 1246: return(origCount - count); ! 1247: } ! 1248: ! 1249: /* DataToTerminal - queue up some data to go to terminal. */ ! 1250: ! 1251: int ! 1252: DataToTerminal(buffer, count) ! 1253: register char *buffer; /* where the data is */ ! 1254: register int count; /* how much to send */ ! 1255: { ! 1256: int origCount; ! 1257: int o; ! 1258: ! 1259: origCount = count; ! 1260: ! 1261: while (count) { ! 1262: if (tfrontp >= &ttyobuf[sizeof ttyobuf]) { ! 1263: ttyflush(); ! 1264: while (tfrontp >= &ttyobuf[sizeof ttyobuf]) { ! 1265: o = 1<<tout; ! 1266: (void) select(tout+1, (int *) 0, &o, (int *) 0, ! 1267: (struct timeval *) 0); ! 1268: ttyflush(); ! 1269: } ! 1270: } ! 1271: *tfrontp++ = *buffer++; ! 1272: count--; ! 1273: } ! 1274: return(origCount - count); ! 1275: } ! 1276: ! 1277: /* EmptyTerminal - called to make sure that the terminal buffer is empty. ! 1278: * Note that we consider the buffer to run all the ! 1279: * way to the kernel (thus the select). ! 1280: */ ! 1281: ! 1282: void ! 1283: EmptyTerminal() ! 1284: { ! 1285: int o; ! 1286: ! 1287: o = 1<<tout; ! 1288: ! 1289: if (tfrontp == tbackp) { ! 1290: (void) select(tout+1, (int *) 0, &o, (int *) 0, ! 1291: (struct timeval *) 0); /* wait for TTLOWAT */ ! 1292: } else { ! 1293: while (tfrontp != tbackp) { ! 1294: ttyflush(); ! 1295: (void) select(tout+1, (int *) 0, &o, (int *) 0, ! 1296: (struct timeval *) 0); /* wait for TTLOWAT */ ! 1297: } ! 1298: } ! 1299: } ! 1300: ! 1301: ! 1302: ! 1303: /* StringToTerminal - output a null terminated string to the terminal */ ! 1304: ! 1305: int ! 1306: StringToTerminal(s) ! 1307: char *s; ! 1308: { ! 1309: int count; ! 1310: ! 1311: count = strlen(s); ! 1312: if (count) { ! 1313: (void) DataToTerminal(s, count); /* we know it always goes... */ ! 1314: } ! 1315: } ! 1316: ! 1317: ! 1318: /* _putchar - output a single character to the terminal. This name is so that ! 1319: * curses(3x) can call us to send out data. ! 1320: */ ! 1321: ! 1322: _putchar(c) ! 1323: char c; ! 1324: { ! 1325: if (tfrontp >= &ttyobuf[sizeof ttyobuf]) { ! 1326: (void) DataToTerminal(&c, 1); ! 1327: } else { ! 1328: *tfrontp++ = c; /* optimize if possible. */ ! 1329: } ! 1330: } ! 1331: ! 1332: static ! 1333: SetForExit() ! 1334: { ! 1335: (void) mode(2); /* switch modes to flush output */ ! 1336: (void) mode(0); ! 1337: fflush(stdout); ! 1338: fflush(stderr); ! 1339: if (In3270) { ! 1340: Stop3270(0); ! 1341: } ! 1342: (void) mode(2); /* make sure we go back to mode 0 */ ! 1343: (void) mode(0); ! 1344: } ! 1345: ! 1346: static ! 1347: Exit(returnCode) ! 1348: int returnCode; ! 1349: { ! 1350: SetForExit(); ! 1351: exit(returnCode); ! 1352: } ! 1353: ! 1354: ExitString(file, string, returnCode) ! 1355: FILE *file; ! 1356: char *string; ! 1357: int returnCode; ! 1358: { ! 1359: SetForExit(); ! 1360: fwrite(string, 1, strlen(string), file); ! 1361: exit(returnCode); ! 1362: } ! 1363: ! 1364: ExitPerror(string, returnCode) ! 1365: char *string; ! 1366: int returnCode; ! 1367: { ! 1368: SetForExit(); ! 1369: perror(string); ! 1370: exit(returnCode); ! 1371: } ! 1372: ! 1373: ! 1374: static ! 1375: Dump(direction, buffer, length) ! 1376: char direction; ! 1377: char *buffer; ! 1378: int length; ! 1379: { ! 1380: # define BYTES_PER_LINE 32 ! 1381: char *pThis; ! 1382: int offset; ! 1383: ! 1384: offset = 0; ! 1385: ! 1386: while (length) { ! 1387: /* print one line */ ! 1388: fprintf(NetTrace, "%c 0x%x\t", direction, offset); ! 1389: pThis = buffer; ! 1390: buffer = buffer+min(length, BYTES_PER_LINE); ! 1391: while (pThis < buffer) { ! 1392: fprintf(NetTrace, "%.2x", (*pThis)&0xff); ! 1393: pThis++; ! 1394: } ! 1395: fprintf(NetTrace, "\n"); ! 1396: length -= BYTES_PER_LINE; ! 1397: offset += BYTES_PER_LINE; ! 1398: if (length < 0) { ! 1399: return; ! 1400: } ! 1401: /* find next unique line */ ! 1402: } ! 1403: } ! 1404: ! 1405: ! 1406: ! 1407: /*VARARGS*/ ! 1408: static ! 1409: printoption(direction, fmt, option, what) ! 1410: char *direction, *fmt; ! 1411: int option, what; ! 1412: { ! 1413: if (!showoptions) ! 1414: return; ! 1415: printf("%s ", direction); ! 1416: if (fmt == doopt) ! 1417: fmt = "do"; ! 1418: else if (fmt == dont) ! 1419: fmt = "dont"; ! 1420: else if (fmt == will) ! 1421: fmt = "will"; ! 1422: else if (fmt == wont) ! 1423: fmt = "wont"; ! 1424: else if (fmt == sb_terminal) ! 1425: fmt = "will (terminal)"; ! 1426: else ! 1427: fmt = "???"; ! 1428: if (option < TELOPT_SUPDUP) ! 1429: printf("%s %s", fmt, telopts[option]); ! 1430: else ! 1431: printf("%s %d", fmt, option); ! 1432: if (*direction == '<') { ! 1433: printf("\r\n"); ! 1434: return; ! 1435: } ! 1436: printf(" (%s)\r\n", what ? "reply" : "don't reply"); ! 1437: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.