|
|
1.1 ! root 1: /* ! 2: * Copyright (c) 1983 Regents of the University of California. ! 3: * All rights reserved. The Berkeley software License Agreement ! 4: * specifies the terms and conditions for redistribution. ! 5: */ ! 6: ! 7: #ifndef lint ! 8: char copyright[] = ! 9: "@(#) Copyright (c) 1983 Regents of the University of California.\n\ ! 10: All rights reserved.\n"; ! 11: #endif not lint ! 12: ! 13: #ifndef lint ! 14: static char sccsid[] = "@(#)telnet.c 5.16 (Berkeley) 5/27/86"; ! 15: #endif not lint ! 16: ! 17: /* ! 18: * User telnet program. ! 19: * ! 20: * Many of the FUNCTIONAL changes in this newest version of telnet ! 21: * were suggested by Dave Borman of Cray Research, Inc. ! 22: */ ! 23: ! 24: #include <sys/types.h> ! 25: #include <sys/socket.h> ! 26: #include <sys/ioctl.h> ! 27: #include <sys/time.h> ! 28: ! 29: #include <netinet/in.h> ! 30: ! 31: #define TELOPTS ! 32: #include <arpa/telnet.h> ! 33: #include <arpa/inet.h> ! 34: ! 35: #include <stdio.h> ! 36: #include <ctype.h> ! 37: #include <errno.h> ! 38: #include <signal.h> ! 39: #include <setjmp.h> ! 40: #include <netdb.h> ! 41: #include <strings.h> ! 42: ! 43: ! 44: ! 45: #ifndef FD_SETSIZE ! 46: /* ! 47: * The following is defined just in case someone should want to run ! 48: * this telnet on a 4.2 system. ! 49: * ! 50: */ ! 51: ! 52: #define FD_SET(n, p) ((p)->fds_bits[0] |= (1<<(n))) ! 53: #define FD_CLR(n, p) ((p)->fds_bits[0] &= ~(1<<(n))) ! 54: #define FD_ISSET(n, p) ((p)->fds_bits[0] & (1<<(n))) ! 55: #define FD_ZERO(p) ((p)->fds_bits[0] = 0) ! 56: ! 57: #endif ! 58: ! 59: #define strip(x) ((x)&0x7f) ! 60: ! 61: char ttyobuf[2*BUFSIZ], *tfrontp = ttyobuf, *tbackp = ttyobuf; ! 62: #define TTYADD(c) { if (!(SYNCHing||flushout)) { *tfrontp++ = c; } } ! 63: #define TTYLOC() (tfrontp) ! 64: #define TTYMAX() (ttyobuf+sizeof ttyobuf-1) ! 65: #define TTYMIN() (netobuf) ! 66: #define TTYBYTES() (tfrontp-tbackp) ! 67: #define TTYROOM() (TTYMAX()-TTYLOC()+1) ! 68: ! 69: char netobuf[2*BUFSIZ], *nfrontp = netobuf, *nbackp = netobuf; ! 70: #define NETADD(c) { *nfrontp++ = c; } ! 71: #define NET2ADD(c1,c2) { NETADD(c1); NETADD(c2); } ! 72: #define NETLOC() (nfrontp) ! 73: #define NETMAX() (netobuf+sizeof netobuf-1) ! 74: #define NETBYTES() (nfrontp-nbackp) ! 75: #define NETROOM() (NETMAX()-NETLOC()+1) ! 76: char *neturg = 0; /* one past last byte of urgent data */ ! 77: ! 78: char subbuffer[100], *subpointer, *subend; /* buffer for sub-options */ ! 79: #define SB_CLEAR() subpointer = subbuffer; ! 80: #define SB_TERM() subend = subpointer; ! 81: #define SB_ACCUM(c) if (subpointer < (subbuffer+sizeof subbuffer)) { \ ! 82: *subpointer++ = (c); \ ! 83: } ! 84: ! 85: char hisopts[256]; ! 86: char myopts[256]; ! 87: ! 88: char doopt[] = { IAC, DO, '%', 'c', 0 }; ! 89: char dont[] = { IAC, DONT, '%', 'c', 0 }; ! 90: char will[] = { IAC, WILL, '%', 'c', 0 }; ! 91: char wont[] = { IAC, WONT, '%', 'c', 0 }; ! 92: ! 93: struct cmd { ! 94: char *name; /* command name */ ! 95: char *help; /* help string */ ! 96: int (*handler)(); /* routine which executes command */ ! 97: int dohelp; /* Should we give general help information? */ ! 98: int needconnect; /* Do we need to be connected to execute? */ ! 99: }; ! 100: ! 101: int connected; ! 102: int net; ! 103: int tout; ! 104: int showoptions = 0; ! 105: int debug = 0; ! 106: int crmod = 0; ! 107: int netdata = 0; ! 108: static FILE *NetTrace; ! 109: int telnetport = 1; ! 110: ! 111: ! 112: char *prompt; ! 113: char escape = CTRL(]); ! 114: char echoc = CTRL(E); ! 115: ! 116: int SYNCHing = 0; /* we are in TELNET SYNCH mode */ ! 117: int flushout = 0; /* flush output */ ! 118: int autoflush = 0; /* flush output when interrupting? */ ! 119: int autosynch = 0; /* send interrupt characters with SYNCH? */ ! 120: int localchars = 0; /* we recognize interrupt/quit */ ! 121: int donelclchars = 0; /* the user has set "localchars" */ ! 122: int dontlecho = 0; /* do we suppress local echoing right now? */ ! 123: ! 124: char line[200]; ! 125: int margc; ! 126: char *margv[20]; ! 127: ! 128: jmp_buf toplevel; ! 129: jmp_buf peerdied; ! 130: ! 131: extern int errno; ! 132: ! 133: ! 134: struct sockaddr_in sin; ! 135: ! 136: struct cmd *getcmd(); ! 137: struct servent *sp; ! 138: ! 139: struct tchars otc, ntc; ! 140: struct ltchars oltc, nltc; ! 141: struct sgttyb ottyb, nttyb; ! 142: int globalmode = 0; ! 143: int flushline = 1; ! 144: ! 145: char *hostname; ! 146: char hnamebuf[32]; ! 147: ! 148: /* ! 149: * The following are some clocks used to decide how to interpret ! 150: * the relationship between various variables. ! 151: */ ! 152: ! 153: struct { ! 154: int ! 155: system, /* what the current time is */ ! 156: echotoggle, /* last time user entered echo character */ ! 157: modenegotiated, /* last time operating mode negotiated */ ! 158: didnetreceive, /* last time we read data from network */ ! 159: gotDM; /* when did we last see a data mark */ ! 160: } clocks; ! 161: ! 162: #define settimer(x) clocks.x = clocks.system++ ! 163: ! 164: /* ! 165: * Various utility routines. ! 166: */ ! 167: ! 168: char *ambiguous; /* special return value */ ! 169: #define Ambiguous(t) ((t)&ambiguous) ! 170: ! 171: ! 172: char ** ! 173: genget(name, table, next) ! 174: char *name; /* name to match */ ! 175: char **table; /* name entry in table */ ! 176: char **(*next)(); /* routine to return next entry in table */ ! 177: { ! 178: register char *p, *q; ! 179: register char **c, **found; ! 180: register int nmatches, longest; ! 181: ! 182: longest = 0; ! 183: nmatches = 0; ! 184: found = 0; ! 185: for (c = table; p = *c; c = (*next)(c)) { ! 186: for (q = name; *q == *p++; q++) ! 187: if (*q == 0) /* exact match? */ ! 188: return (c); ! 189: if (!*q) { /* the name was a prefix */ ! 190: if (q - name > longest) { ! 191: longest = q - name; ! 192: nmatches = 1; ! 193: found = c; ! 194: } else if (q - name == longest) ! 195: nmatches++; ! 196: } ! 197: } ! 198: if (nmatches > 1) ! 199: return Ambiguous(char **); ! 200: return (found); ! 201: } ! 202: ! 203: /* ! 204: * Make a character string into a number. ! 205: * ! 206: * Todo: 1. Could take random integers (12, 0x12, 012, 0b1). ! 207: */ ! 208: ! 209: special(s) ! 210: register char *s; ! 211: { ! 212: register char c; ! 213: char b; ! 214: ! 215: switch (*s) { ! 216: case '^': ! 217: b = *++s; ! 218: if (b == '?') { ! 219: c = b | 0x40; /* DEL */ ! 220: } else { ! 221: c = b & 0x1f; ! 222: } ! 223: break; ! 224: default: ! 225: c = *s; ! 226: break; ! 227: } ! 228: return c; ! 229: } ! 230: ! 231: /* ! 232: * Construct a control character sequence ! 233: * for a special character. ! 234: */ ! 235: char * ! 236: control(c) ! 237: register int c; ! 238: { ! 239: static char buf[3]; ! 240: ! 241: if (c == 0x7f) ! 242: return ("^?"); ! 243: if (c == '\377') { ! 244: return "off"; ! 245: } ! 246: if (c >= 0x20) { ! 247: buf[0] = c; ! 248: buf[1] = 0; ! 249: } else { ! 250: buf[0] = '^'; ! 251: buf[1] = '@'+c; ! 252: buf[2] = 0; ! 253: } ! 254: return (buf); ! 255: } ! 256: ! 257: ! 258: /* ! 259: * upcase() ! 260: * ! 261: * Upcase (in place) the argument. ! 262: */ ! 263: ! 264: void ! 265: upcase(argument) ! 266: register char *argument; ! 267: { ! 268: register int c; ! 269: ! 270: while (c = *argument) { ! 271: if (islower(c)) { ! 272: *argument = toupper(c); ! 273: } ! 274: argument++; ! 275: } ! 276: } ! 277: ! 278: /* ! 279: * Check to see if any out-of-band data exists on a socket (for ! 280: * Telnet "synch" processing). ! 281: */ ! 282: ! 283: int ! 284: stilloob(s) ! 285: int s; /* socket number */ ! 286: { ! 287: static struct timeval timeout = { 0 }; ! 288: fd_set excepts; ! 289: int value; ! 290: ! 291: do { ! 292: FD_ZERO(&excepts); ! 293: FD_SET(s, &excepts); ! 294: value = select(s+1, (fd_set *)0, (fd_set *)0, &excepts, &timeout); ! 295: } while ((value == -1) && (errno = EINTR)); ! 296: ! 297: if (value < 0) { ! 298: perror("select"); ! 299: quit(); ! 300: } ! 301: if (FD_ISSET(s, &excepts)) { ! 302: return 1; ! 303: } else { ! 304: return 0; ! 305: } ! 306: } ! 307: ! 308: ! 309: /* ! 310: * netflush ! 311: * Send as much data as possible to the network, ! 312: * handling requests for urgent data. ! 313: */ ! 314: ! 315: ! 316: netflush(fd) ! 317: { ! 318: int n; ! 319: ! 320: if ((n = nfrontp - nbackp) > 0) { ! 321: if (!neturg) { ! 322: n = write(fd, nbackp, n); /* normal write */ ! 323: } else { ! 324: n = neturg - nbackp; ! 325: /* ! 326: * In 4.2 (and 4.3) systems, there is some question about ! 327: * what byte in a sendOOB operation is the "OOB" data. ! 328: * To make ourselves compatible, we only send ONE byte ! 329: * out of band, the one WE THINK should be OOB (though ! 330: * we really have more the TCP philosophy of urgent data ! 331: * rather than the Unix philosophy of OOB data). ! 332: */ ! 333: if (n > 1) { ! 334: n = send(fd, nbackp, n-1, 0); /* send URGENT all by itself */ ! 335: } else { ! 336: n = send(fd, nbackp, n, MSG_OOB); /* URGENT data */ ! 337: } ! 338: } ! 339: } ! 340: if (n < 0) { ! 341: if (errno != ENOBUFS && errno != EWOULDBLOCK) { ! 342: setcommandmode(); ! 343: perror(hostname); ! 344: close(fd); ! 345: neturg = 0; ! 346: longjmp(peerdied, -1); ! 347: /*NOTREACHED*/ ! 348: } ! 349: n = 0; ! 350: } ! 351: if (netdata && n) { ! 352: Dump('>', nbackp, n); ! 353: } ! 354: nbackp += n; ! 355: if (nbackp >= neturg) { ! 356: neturg = 0; ! 357: } ! 358: if (nbackp == nfrontp) { ! 359: nbackp = nfrontp = netobuf; ! 360: } ! 361: } ! 362: ! 363: /* ! 364: * nextitem() ! 365: * ! 366: * Return the address of the next "item" in the TELNET data ! 367: * stream. This will be the address of the next character if ! 368: * the current address is a user data character, or it will ! 369: * be the address of the character following the TELNET command ! 370: * if the current address is a TELNET IAC ("I Am a Command") ! 371: * character. ! 372: */ ! 373: ! 374: char * ! 375: nextitem(current) ! 376: char *current; ! 377: { ! 378: if ((*current&0xff) != IAC) { ! 379: return current+1; ! 380: } ! 381: switch (*(current+1)&0xff) { ! 382: case DO: ! 383: case DONT: ! 384: case WILL: ! 385: case WONT: ! 386: return current+3; ! 387: case SB: /* loop forever looking for the SE */ ! 388: { ! 389: register char *look = current+2; ! 390: ! 391: for (;;) { ! 392: if ((*look++&0xff) == IAC) { ! 393: if ((*look++&0xff) == SE) { ! 394: return look; ! 395: } ! 396: } ! 397: } ! 398: } ! 399: default: ! 400: return current+2; ! 401: } ! 402: } ! 403: /* ! 404: * netclear() ! 405: * ! 406: * We are about to do a TELNET SYNCH operation. Clear ! 407: * the path to the network. ! 408: * ! 409: * Things are a bit tricky since we may have sent the first ! 410: * byte or so of a previous TELNET command into the network. ! 411: * So, we have to scan the network buffer from the beginning ! 412: * until we are up to where we want to be. ! 413: * ! 414: * A side effect of what we do, just to keep things ! 415: * simple, is to clear the urgent data pointer. The principal ! 416: * caller should be setting the urgent data pointer AFTER calling ! 417: * us in any case. ! 418: */ ! 419: ! 420: netclear() ! 421: { ! 422: register char *thisitem, *next; ! 423: char *good; ! 424: #define wewant(p) ((nfrontp > p) && ((*p&0xff) == IAC) && \ ! 425: ((*(p+1)&0xff) != EC) && ((*(p+1)&0xff) != EL)) ! 426: ! 427: thisitem = netobuf; ! 428: ! 429: while ((next = nextitem(thisitem)) <= nbackp) { ! 430: thisitem = next; ! 431: } ! 432: ! 433: /* Now, thisitem is first before/at boundary. */ ! 434: ! 435: good = netobuf; /* where the good bytes go */ ! 436: ! 437: while (nfrontp > thisitem) { ! 438: if (wewant(thisitem)) { ! 439: int length; ! 440: ! 441: next = thisitem; ! 442: do { ! 443: next = nextitem(next); ! 444: } while (wewant(next) && (nfrontp > next)); ! 445: length = next-thisitem; ! 446: bcopy(thisitem, good, length); ! 447: good += length; ! 448: thisitem = next; ! 449: } else { ! 450: thisitem = nextitem(thisitem); ! 451: } ! 452: } ! 453: ! 454: nbackp = netobuf; ! 455: nfrontp = good; /* next byte to be sent */ ! 456: neturg = 0; ! 457: } ! 458: ! 459: /* ! 460: * Send as much data as possible to the terminal. ! 461: */ ! 462: ! 463: ! 464: ttyflush() ! 465: { ! 466: int n; ! 467: ! 468: if ((n = tfrontp - tbackp) > 0) { ! 469: if (!(SYNCHing||flushout)) { ! 470: n = write(tout, tbackp, n); ! 471: } else { ! 472: ioctl(fileno(stdout), TIOCFLUSH, (char *) 0); ! 473: /* we leave 'n' alone! */ ! 474: } ! 475: } ! 476: if (n < 0) { ! 477: return; ! 478: } ! 479: tbackp += n; ! 480: if (tbackp == tfrontp) { ! 481: tbackp = tfrontp = ttyobuf; ! 482: } ! 483: } ! 484: ! 485: /* ! 486: * Various signal handling routines. ! 487: */ ! 488: ! 489: deadpeer() ! 490: { ! 491: setcommandmode(); ! 492: longjmp(peerdied, -1); ! 493: } ! 494: ! 495: intr() ! 496: { ! 497: if (localchars) { ! 498: intp(); ! 499: return; ! 500: } ! 501: setcommandmode(); ! 502: longjmp(toplevel, -1); ! 503: } ! 504: ! 505: intr2() ! 506: { ! 507: if (localchars) { ! 508: sendbrk(); ! 509: return; ! 510: } ! 511: } ! 512: ! 513: doescape() ! 514: { ! 515: command(0); ! 516: } ! 517: ! 518: /* ! 519: * The following are routines used to print out debugging information. ! 520: */ ! 521: ! 522: ! 523: static ! 524: Dump(direction, buffer, length) ! 525: char direction; ! 526: char *buffer; ! 527: int length; ! 528: { ! 529: # define BYTES_PER_LINE 32 ! 530: # define min(x,y) ((x<y)? x:y) ! 531: char *pThis; ! 532: int offset; ! 533: ! 534: offset = 0; ! 535: ! 536: while (length) { ! 537: /* print one line */ ! 538: fprintf(NetTrace, "%c 0x%x\t", direction, offset); ! 539: pThis = buffer; ! 540: buffer = buffer+min(length, BYTES_PER_LINE); ! 541: while (pThis < buffer) { ! 542: fprintf(NetTrace, "%.2x", (*pThis)&0xff); ! 543: pThis++; ! 544: } ! 545: fprintf(NetTrace, "\n"); ! 546: length -= BYTES_PER_LINE; ! 547: offset += BYTES_PER_LINE; ! 548: if (length < 0) { ! 549: return; ! 550: } ! 551: /* find next unique line */ ! 552: } ! 553: } ! 554: ! 555: ! 556: /*VARARGS*/ ! 557: printoption(direction, fmt, option, what) ! 558: char *direction, *fmt; ! 559: int option, what; ! 560: { ! 561: if (!showoptions) ! 562: return; ! 563: printf("%s ", direction+1); ! 564: if (fmt == doopt) ! 565: fmt = "do"; ! 566: else if (fmt == dont) ! 567: fmt = "dont"; ! 568: else if (fmt == will) ! 569: fmt = "will"; ! 570: else if (fmt == wont) ! 571: fmt = "wont"; ! 572: else ! 573: fmt = "???"; ! 574: if (option < (sizeof telopts/sizeof telopts[0])) ! 575: printf("%s %s", fmt, telopts[option]); ! 576: else ! 577: printf("%s %d", fmt, option); ! 578: if (*direction == '<') { ! 579: printf("\r\n"); ! 580: return; ! 581: } ! 582: printf(" (%s)\r\n", what ? "reply" : "don't reply"); ! 583: } ! 584: ! 585: /* ! 586: * Mode - set up terminal to a specific mode. ! 587: */ ! 588: ! 589: ! 590: mode(f) ! 591: register int f; ! 592: { ! 593: static int prevmode = 0; ! 594: struct tchars *tc; ! 595: struct ltchars *ltc; ! 596: struct sgttyb sb; ! 597: int onoff, old; ! 598: struct tchars notc2; ! 599: struct ltchars noltc2; ! 600: static struct tchars notc = { -1, -1, -1, -1, -1, -1 }; ! 601: static struct ltchars noltc = { -1, -1, -1, -1, -1, -1 }; ! 602: ! 603: globalmode = f; ! 604: if (prevmode == f) ! 605: return; ! 606: old = prevmode; ! 607: prevmode = f; ! 608: sb = nttyb; ! 609: switch (f) { ! 610: ! 611: case 0: ! 612: onoff = 0; ! 613: tc = &otc; ! 614: ltc = &oltc; ! 615: break; ! 616: ! 617: case 1: /* remote character processing, remote echo */ ! 618: case 2: /* remote character processing, local echo */ ! 619: sb.sg_flags |= CBREAK; ! 620: if (f == 1) ! 621: sb.sg_flags &= ~(ECHO|CRMOD); ! 622: else ! 623: sb.sg_flags |= ECHO|CRMOD; ! 624: sb.sg_erase = sb.sg_kill = -1; ! 625: tc = ¬c; ! 626: /* ! 627: * If user hasn't specified one way or the other, ! 628: * then default to not trapping signals. ! 629: */ ! 630: if (!donelclchars) { ! 631: localchars = 0; ! 632: } ! 633: if (localchars) { ! 634: notc2 = notc; ! 635: notc2.t_intrc = ntc.t_intrc; ! 636: notc2.t_quitc = ntc.t_quitc; ! 637: tc = ¬c2; ! 638: } else ! 639: tc = ¬c; ! 640: ltc = &noltc; ! 641: onoff = 1; ! 642: break; ! 643: case 3: /* local character processing, remote echo */ ! 644: case 4: /* local character processing, local echo */ ! 645: case 5: /* local character processing, no echo */ ! 646: sb.sg_flags &= ~CBREAK; ! 647: sb.sg_flags |= CRMOD; ! 648: if (f == 4) ! 649: sb.sg_flags |= ECHO; ! 650: else ! 651: sb.sg_flags &= ~ECHO; ! 652: notc2 = ntc; ! 653: tc = ¬c2; ! 654: noltc2 = oltc; ! 655: ltc = &noltc2; ! 656: /* ! 657: * If user hasn't specified one way or the other, ! 658: * then default to trapping signals. ! 659: */ ! 660: if (!donelclchars) { ! 661: localchars = 1; ! 662: } ! 663: if (localchars) { ! 664: notc2.t_brkc = nltc.t_flushc; ! 665: noltc2.t_flushc = -1; ! 666: } else { ! 667: notc2.t_intrc = notc2.t_quitc = -1; ! 668: } ! 669: noltc2.t_suspc = escape; ! 670: noltc2.t_dsuspc = -1; ! 671: onoff = 1; ! 672: break; ! 673: ! 674: default: ! 675: return; ! 676: } ! 677: ioctl(fileno(stdin), TIOCSLTC, (char *)ltc); ! 678: ioctl(fileno(stdin), TIOCSETC, (char *)tc); ! 679: ioctl(fileno(stdin), TIOCSETP, (char *)&sb); ! 680: ioctl(fileno(stdin), FIONBIO, (char *)&onoff); ! 681: ioctl(fileno(stdout), FIONBIO, (char *)&onoff); ! 682: if (f >= 3) ! 683: signal(SIGTSTP, doescape); ! 684: else if (old >= 3) { ! 685: signal(SIGTSTP, SIG_DFL); ! 686: sigsetmask(sigblock(0) & ~(1<<(SIGTSTP-1))); ! 687: } ! 688: } ! 689: ! 690: /* ! 691: * These routines decides on what the mode should be (based on the values ! 692: * of various global variables). ! 693: */ ! 694: ! 695: char *modedescriptions[] = { ! 696: "telnet command mode", /* 0 */ ! 697: "character-at-a-time mode", /* 1 */ ! 698: "character-at-a-time mode (local echo)", /* 2 */ ! 699: "line-by-line mode (remote echo)", /* 3 */ ! 700: "line-by-line mode", /* 4 */ ! 701: "line-by-line mode (local echoing suppressed)", /* 5 */ ! 702: }; ! 703: ! 704: getconnmode() ! 705: { ! 706: static char newmode[8] = { 4, 5, 3, 3, 2, 2, 1, 1 }; ! 707: int modeindex = 0; ! 708: ! 709: if (hisopts[TELOPT_ECHO]) { ! 710: modeindex += 2; ! 711: } ! 712: if (hisopts[TELOPT_SGA]) { ! 713: modeindex += 4; ! 714: } ! 715: if (dontlecho && (clocks.echotoggle > clocks.modenegotiated)) { ! 716: modeindex += 1; ! 717: } ! 718: return newmode[modeindex]; ! 719: } ! 720: ! 721: setconnmode() ! 722: { ! 723: mode(getconnmode()); ! 724: } ! 725: ! 726: ! 727: setcommandmode() ! 728: { ! 729: mode(0); ! 730: } ! 731: ! 732: char sibuf[BUFSIZ], *sbp; ! 733: char tibuf[BUFSIZ], *tbp; ! 734: int scc, tcc; ! 735: ! 736: ! 737: /* ! 738: * Select from tty and network... ! 739: */ ! 740: telnet() ! 741: { ! 742: register int c; ! 743: int tin = fileno(stdin); ! 744: int on = 1; ! 745: fd_set ibits, obits, xbits; ! 746: ! 747: tout = fileno(stdout); ! 748: setconnmode(); ! 749: scc = 0; ! 750: tcc = 0; ! 751: FD_ZERO(&ibits); ! 752: FD_ZERO(&obits); ! 753: FD_ZERO(&xbits); ! 754: ! 755: ioctl(net, FIONBIO, (char *)&on); ! 756: #if defined(SO_OOBINLINE) ! 757: setsockopt(net, SOL_SOCKET, SO_OOBINLINE, &on, sizeof on); ! 758: #endif /* defined(SO_OOBINLINE) */ ! 759: if (telnetport) { ! 760: if (!hisopts[TELOPT_SGA]) { ! 761: willoption(TELOPT_SGA, 0); ! 762: } ! 763: if (!myopts[TELOPT_TTYPE]) { ! 764: dooption(TELOPT_TTYPE, 0); ! 765: } ! 766: } ! 767: for (;;) { ! 768: if (scc < 0 && tcc < 0) { ! 769: break; ! 770: } ! 771: ! 772: if (((globalmode < 4) || flushline) && NETBYTES()) { ! 773: FD_SET(net, &obits); ! 774: } else { ! 775: FD_SET(tin, &ibits); ! 776: } ! 777: if (TTYBYTES()) { ! 778: FD_SET(tout, &obits); ! 779: } else { ! 780: FD_SET(net, &ibits); ! 781: } ! 782: if (!SYNCHing) { ! 783: FD_SET(net, &xbits); ! 784: } ! 785: if ((c = select(16, &ibits, &obits, &xbits, ! 786: (struct timeval *)0)) < 1) { ! 787: if (c == -1) { ! 788: /* ! 789: * we can get EINTR if we are in line mode, ! 790: * and the user does an escape (TSTP), or ! 791: * some other signal generator. ! 792: */ ! 793: if (errno == EINTR) { ! 794: continue; ! 795: } ! 796: } ! 797: sleep(5); ! 798: continue; ! 799: } ! 800: ! 801: /* ! 802: * Any urgent data? ! 803: */ ! 804: if (FD_ISSET(net, &xbits)) { ! 805: FD_CLR(net, &xbits); ! 806: SYNCHing = 1; ! 807: ttyflush(); /* flush already enqueued data */ ! 808: } ! 809: ! 810: /* ! 811: * Something to read from the network... ! 812: */ ! 813: if (FD_ISSET(net, &ibits)) { ! 814: int canread; ! 815: ! 816: FD_CLR(net, &ibits); ! 817: if (scc == 0) { ! 818: sbp = sibuf; ! 819: } ! 820: canread = sibuf + sizeof sibuf - sbp; ! 821: #if !defined(SO_OOBINLINE) ! 822: /* ! 823: * In 4.2 (and some early 4.3) systems, the ! 824: * OOB indication and data handling in the kernel ! 825: * is such that if two separate TCP Urgent requests ! 826: * come in, one byte of TCP data will be overlaid. ! 827: * This is fatal for Telnet, but we try to live ! 828: * with it. ! 829: * ! 830: * In addition, in 4.2 (and...), a special protocol ! 831: * is needed to pick up the TCP Urgent data in ! 832: * the correct sequence. ! 833: * ! 834: * What we do is: if we think we are in urgent ! 835: * mode, we look to see if we are "at the mark". ! 836: * If we are, we do an OOB receive. If we run ! 837: * this twice, we will do the OOB receive twice, ! 838: * but the second will fail, since the second ! 839: * time we were "at the mark", but there wasn't ! 840: * any data there (the kernel doesn't reset ! 841: * "at the mark" until we do a normal read). ! 842: * Once we've read the OOB data, we go ahead ! 843: * and do normal reads. ! 844: * ! 845: * There is also another problem, which is that ! 846: * since the OOB byte we read doesn't put us ! 847: * out of OOB state, and since that byte is most ! 848: * likely the TELNET DM (data mark), we would ! 849: * stay in the TELNET SYNCH (SYNCHing) state. ! 850: * So, clocks to the rescue. If we've "just" ! 851: * received a DM, then we test for the ! 852: * presence of OOB data when the receive OOB ! 853: * fails (and AFTER we did the normal mode read ! 854: * to clear "at the mark"). ! 855: */ ! 856: if (SYNCHing) { ! 857: int atmark; ! 858: ! 859: ioctl(net, SIOCATMARK, (char *)&atmark); ! 860: if (atmark) { ! 861: c = recv(net, sibuf, canread, MSG_OOB); ! 862: if ((c == -1) && (errno == EINVAL)) { ! 863: c = read(net, sibuf, canread); ! 864: if (clocks.didnetreceive < clocks.gotDM) { ! 865: SYNCHing = stilloob(net); ! 866: } ! 867: } ! 868: } else { ! 869: c = read(net, sibuf, canread); ! 870: } ! 871: } else { ! 872: c = read(net, sibuf, canread); ! 873: } ! 874: settimer(didnetreceive); ! 875: #else /* !defined(SO_OOBINLINE) */ ! 876: c = read(net, sbp, canread); ! 877: #endif /* !defined(SO_OOBINLINE) */ ! 878: if (c < 0 && errno == EWOULDBLOCK) { ! 879: c = 0; ! 880: } else if (c <= 0) { ! 881: break; ! 882: } ! 883: if (netdata) { ! 884: Dump('<', sbp, c); ! 885: } ! 886: scc += c; ! 887: } ! 888: ! 889: /* ! 890: * Something to read from the tty... ! 891: */ ! 892: if (FD_ISSET(tin, &ibits)) { ! 893: FD_CLR(tin, &ibits); ! 894: if (tcc == 0) { ! 895: tbp = tibuf; /* nothing left, reset */ ! 896: } ! 897: c = read(tin, tbp, tibuf+sizeof tibuf - tbp); ! 898: if (c < 0 && errno == EWOULDBLOCK) { ! 899: c = 0; ! 900: } else { ! 901: /* EOF detection for line mode!!!! */ ! 902: if (c == 0 && globalmode >= 3) { ! 903: /* must be an EOF... */ ! 904: *tbp = ntc.t_eofc; ! 905: c = 1; ! 906: } ! 907: if (c <= 0) { ! 908: tcc = c; ! 909: break; ! 910: } ! 911: } ! 912: tcc += c; ! 913: } ! 914: ! 915: while (tcc > 0) { ! 916: register int sc; ! 917: ! 918: if (NETROOM() < 2) { ! 919: flushline = 1; ! 920: break; ! 921: } ! 922: c = *tbp++ & 0xff, sc = strip(c), tcc--; ! 923: if (sc == escape) { ! 924: command(0); ! 925: tcc = 0; ! 926: flushline = 1; ! 927: break; ! 928: } else if ((globalmode >= 4) && (sc == echoc)) { ! 929: if (tcc > 0 && strip(*tbp) == echoc) { ! 930: tbp++; ! 931: tcc--; ! 932: } else { ! 933: dontlecho = !dontlecho; ! 934: settimer(echotoggle); ! 935: setconnmode(); ! 936: tcc = 0; ! 937: flushline = 1; ! 938: break; ! 939: } ! 940: } ! 941: if (localchars) { ! 942: if (sc == ntc.t_intrc) { ! 943: intp(); ! 944: break; ! 945: } else if (sc == ntc.t_quitc) { ! 946: sendbrk(); ! 947: break; ! 948: } else if (sc == nltc.t_flushc) { ! 949: NET2ADD(IAC, AO); ! 950: if (autoflush) { ! 951: doflush(); ! 952: } ! 953: break; ! 954: } else if (globalmode > 2) { ! 955: ; ! 956: } else if (sc == nttyb.sg_kill) { ! 957: NET2ADD(IAC, EL); ! 958: break; ! 959: } else if (sc == nttyb.sg_erase) { ! 960: NET2ADD(IAC, EC); ! 961: break; ! 962: } ! 963: } ! 964: switch (c) { ! 965: case '\n': ! 966: /* ! 967: * If we are in CRMOD mode (\r ==> \n) ! 968: * on our local machine, then probably ! 969: * a newline (unix) is CRLF (TELNET). ! 970: */ ! 971: if (globalmode >= 3) { ! 972: NETADD('\r'); ! 973: } ! 974: NETADD('\n'); ! 975: flushline = 1; ! 976: break; ! 977: case '\r': ! 978: NET2ADD('\r', '\0'); ! 979: flushline = 1; ! 980: break; ! 981: case IAC: ! 982: NET2ADD(IAC, IAC); ! 983: break; ! 984: default: ! 985: NETADD(c); ! 986: break; ! 987: } ! 988: } ! 989: if (((globalmode < 4) || flushline) && ! 990: FD_ISSET(net, &obits) && (NETBYTES() > 0)) { ! 991: FD_CLR(net, &obits); ! 992: netflush(net); ! 993: } ! 994: if (scc > 0) ! 995: telrcv(); ! 996: if (FD_ISSET(tout, &obits) && (TTYBYTES() > 0)) { ! 997: FD_CLR(tout, &obits); ! 998: ttyflush(); ! 999: } ! 1000: } ! 1001: setcommandmode(); ! 1002: } ! 1003: ! 1004: /* ! 1005: * Telnet receiver states for fsm ! 1006: */ ! 1007: #define TS_DATA 0 ! 1008: #define TS_IAC 1 ! 1009: #define TS_WILL 2 ! 1010: #define TS_WONT 3 ! 1011: #define TS_DO 4 ! 1012: #define TS_DONT 5 ! 1013: #define TS_CR 6 ! 1014: #define TS_SB 7 /* sub-option collection */ ! 1015: #define TS_SE 8 /* looking for sub-option end */ ! 1016: ! 1017: telrcv() ! 1018: { ! 1019: register int c; ! 1020: static int state = TS_DATA; ! 1021: ! 1022: while ((scc > 0) && (TTYROOM() > 2)) { ! 1023: c = *sbp++ & 0xff, scc--; ! 1024: switch (state) { ! 1025: ! 1026: case TS_CR: ! 1027: state = TS_DATA; ! 1028: if (c == '\0') { ! 1029: break; /* Ignore \0 after CR */ ! 1030: } else if (c == '\n') { ! 1031: if (hisopts[TELOPT_ECHO] && !crmod) { ! 1032: TTYADD(c); ! 1033: } ! 1034: break; ! 1035: } ! 1036: /* Else, fall through */ ! 1037: ! 1038: case TS_DATA: ! 1039: if (c == IAC) { ! 1040: state = TS_IAC; ! 1041: continue; ! 1042: } ! 1043: /* ! 1044: * The 'crmod' hack (see following) is needed ! 1045: * since we can't * set CRMOD on output only. ! 1046: * Machines like MULTICS like to send \r without ! 1047: * \n; since we must turn off CRMOD to get proper ! 1048: * input, the mapping is done here (sigh). ! 1049: */ ! 1050: if (c == '\r') { ! 1051: if (scc > 0) { ! 1052: c = *sbp&0xff; ! 1053: if (c == 0) { ! 1054: sbp++, scc--; ! 1055: /* a "true" CR */ ! 1056: TTYADD('\r'); ! 1057: } else if (!hisopts[TELOPT_ECHO] && ! 1058: (c == '\n')) { ! 1059: sbp++, scc--; ! 1060: TTYADD('\n'); ! 1061: } else { ! 1062: TTYADD('\r'); ! 1063: if (crmod) { ! 1064: TTYADD('\n'); ! 1065: } ! 1066: } ! 1067: } else { ! 1068: state = TS_CR; ! 1069: TTYADD('\r'); ! 1070: if (crmod) { ! 1071: TTYADD('\n'); ! 1072: } ! 1073: } ! 1074: } else { ! 1075: TTYADD(c); ! 1076: } ! 1077: continue; ! 1078: ! 1079: case TS_IAC: ! 1080: switch (c) { ! 1081: ! 1082: case WILL: ! 1083: state = TS_WILL; ! 1084: continue; ! 1085: ! 1086: case WONT: ! 1087: state = TS_WONT; ! 1088: continue; ! 1089: ! 1090: case DO: ! 1091: state = TS_DO; ! 1092: continue; ! 1093: ! 1094: case DONT: ! 1095: state = TS_DONT; ! 1096: continue; ! 1097: ! 1098: case DM: ! 1099: /* ! 1100: * We may have missed an urgent notification, ! 1101: * so make sure we flush whatever is in the ! 1102: * buffer currently. ! 1103: */ ! 1104: SYNCHing = 1; ! 1105: ttyflush(); ! 1106: SYNCHing = stilloob(net); ! 1107: settimer(gotDM); ! 1108: break; ! 1109: ! 1110: case NOP: ! 1111: case GA: ! 1112: break; ! 1113: ! 1114: case SB: ! 1115: SB_CLEAR(); ! 1116: state = TS_SB; ! 1117: continue; ! 1118: ! 1119: default: ! 1120: break; ! 1121: } ! 1122: state = TS_DATA; ! 1123: continue; ! 1124: ! 1125: case TS_WILL: ! 1126: printoption(">RCVD", will, c, !hisopts[c]); ! 1127: if (c == TELOPT_TM) { ! 1128: if (flushout) { ! 1129: flushout = 0; ! 1130: } ! 1131: } else if (!hisopts[c]) { ! 1132: willoption(c, 1); ! 1133: } ! 1134: state = TS_DATA; ! 1135: continue; ! 1136: ! 1137: case TS_WONT: ! 1138: printoption(">RCVD", wont, c, hisopts[c]); ! 1139: if (c == TELOPT_TM) { ! 1140: if (flushout) { ! 1141: flushout = 0; ! 1142: } ! 1143: } else if (hisopts[c]) { ! 1144: wontoption(c, 1); ! 1145: } ! 1146: state = TS_DATA; ! 1147: continue; ! 1148: ! 1149: case TS_DO: ! 1150: printoption(">RCVD", doopt, c, !myopts[c]); ! 1151: if (!myopts[c]) ! 1152: dooption(c); ! 1153: state = TS_DATA; ! 1154: continue; ! 1155: ! 1156: case TS_DONT: ! 1157: printoption(">RCVD", dont, c, myopts[c]); ! 1158: if (myopts[c]) { ! 1159: myopts[c] = 0; ! 1160: sprintf(nfrontp, wont, c); ! 1161: nfrontp += sizeof (wont) - 2; ! 1162: flushline = 1; ! 1163: setconnmode(); /* set new tty mode (maybe) */ ! 1164: printoption(">SENT", wont, c); ! 1165: } ! 1166: state = TS_DATA; ! 1167: continue; ! 1168: case TS_SB: ! 1169: if (c == IAC) { ! 1170: state = TS_SE; ! 1171: } else { ! 1172: SB_ACCUM(c); ! 1173: } ! 1174: continue; ! 1175: ! 1176: case TS_SE: ! 1177: if (c != SE) { ! 1178: if (c != IAC) { ! 1179: SB_ACCUM(IAC); ! 1180: } ! 1181: SB_ACCUM(c); ! 1182: state = TS_SB; ! 1183: } else { ! 1184: SB_TERM(); ! 1185: suboption(); /* handle sub-option */ ! 1186: state = TS_DATA; ! 1187: } ! 1188: } ! 1189: } ! 1190: } ! 1191: ! 1192: willoption(option, reply) ! 1193: int option, reply; ! 1194: { ! 1195: char *fmt; ! 1196: ! 1197: switch (option) { ! 1198: ! 1199: case TELOPT_ECHO: ! 1200: case TELOPT_SGA: ! 1201: settimer(modenegotiated); ! 1202: hisopts[option] = 1; ! 1203: fmt = doopt; ! 1204: setconnmode(); /* possibly set new tty mode */ ! 1205: break; ! 1206: ! 1207: case TELOPT_TM: ! 1208: return; /* Never reply to TM will's/wont's */ ! 1209: ! 1210: default: ! 1211: fmt = dont; ! 1212: break; ! 1213: } ! 1214: sprintf(nfrontp, fmt, option); ! 1215: nfrontp += sizeof (dont) - 2; ! 1216: if (reply) ! 1217: printoption(">SENT", fmt, option); ! 1218: else ! 1219: printoption("<SENT", fmt, option); ! 1220: } ! 1221: ! 1222: wontoption(option, reply) ! 1223: int option, reply; ! 1224: { ! 1225: char *fmt; ! 1226: ! 1227: switch (option) { ! 1228: ! 1229: case TELOPT_ECHO: ! 1230: case TELOPT_SGA: ! 1231: settimer(modenegotiated); ! 1232: hisopts[option] = 0; ! 1233: fmt = dont; ! 1234: setconnmode(); /* Set new tty mode */ ! 1235: break; ! 1236: ! 1237: case TELOPT_TM: ! 1238: return; /* Never reply to TM will's/wont's */ ! 1239: ! 1240: default: ! 1241: fmt = dont; ! 1242: } ! 1243: sprintf(nfrontp, fmt, option); ! 1244: nfrontp += sizeof (doopt) - 2; ! 1245: if (reply) ! 1246: printoption(">SENT", fmt, option); ! 1247: else ! 1248: printoption("<SENT", fmt, option); ! 1249: } ! 1250: ! 1251: dooption(option) ! 1252: int option; ! 1253: { ! 1254: char *fmt; ! 1255: ! 1256: switch (option) { ! 1257: ! 1258: case TELOPT_TM: ! 1259: fmt = will; ! 1260: break; ! 1261: ! 1262: case TELOPT_TTYPE: /* terminal type option */ ! 1263: case TELOPT_SGA: /* no big deal */ ! 1264: fmt = will; ! 1265: myopts[option] = 1; ! 1266: break; ! 1267: ! 1268: case TELOPT_ECHO: /* We're never going to echo... */ ! 1269: default: ! 1270: fmt = wont; ! 1271: break; ! 1272: } ! 1273: sprintf(nfrontp, fmt, option); ! 1274: nfrontp += sizeof (doopt) - 2; ! 1275: printoption(">SENT", fmt, option); ! 1276: } ! 1277: ! 1278: /* ! 1279: * suboption() ! 1280: * ! 1281: * Look at the sub-option buffer, and try to be helpful to the other ! 1282: * side. ! 1283: * ! 1284: * Currently we recognize: ! 1285: * ! 1286: * Terminal type, send request. ! 1287: */ ! 1288: ! 1289: suboption() ! 1290: { ! 1291: switch (subbuffer[0]&0xff) { ! 1292: case TELOPT_TTYPE: ! 1293: if ((subbuffer[1]&0xff) != TELQUAL_SEND) { ! 1294: ; ! 1295: } else { ! 1296: char *name; ! 1297: char namebuf[41]; ! 1298: char *getenv(); ! 1299: int len; ! 1300: ! 1301: name = getenv("TERM"); ! 1302: if ((name == 0) || ((len = strlen(name)) > 40)) { ! 1303: name = "UNKNOWN"; ! 1304: } ! 1305: if ((len + 4+2) < NETROOM()) { ! 1306: strcpy(namebuf, name); ! 1307: upcase(namebuf); ! 1308: sprintf(nfrontp, "%c%c%c%c%s%c%c", IAC, SB, TELOPT_TTYPE, ! 1309: TELQUAL_IS, namebuf, IAC, SE); ! 1310: nfrontp += 4+strlen(namebuf)+2; ! 1311: } ! 1312: } ! 1313: ! 1314: default: ! 1315: break; ! 1316: } ! 1317: } ! 1318: ! 1319: /* ! 1320: * The following are data structures and routines for ! 1321: * the "send" command. ! 1322: * ! 1323: */ ! 1324: ! 1325: struct sendlist { ! 1326: char *name; /* How user refers to it (case independent) */ ! 1327: int what; /* Character to be sent (<0 ==> special) */ ! 1328: char *help; /* Help information (0 ==> no help) */ ! 1329: int (*routine)(); /* Routine to perform (for special ops) */ ! 1330: }; ! 1331: ! 1332: /*ARGSUSED*/ ! 1333: dosynch(s) ! 1334: struct sendlist *s; ! 1335: { ! 1336: netclear(); /* clear the path to the network */ ! 1337: NET2ADD(IAC, DM); ! 1338: neturg = NETLOC()-1; /* Some systems are off by one XXX */ ! 1339: } ! 1340: ! 1341: doflush() ! 1342: { ! 1343: NET2ADD(IAC, DO); ! 1344: NETADD(TELOPT_TM); ! 1345: flushline = 1; ! 1346: flushout = 1; ! 1347: ttyflush(); ! 1348: /* do printoption AFTER flush, otherwise the output gets tossed... */ ! 1349: printoption("<SENT", doopt, TELOPT_TM); ! 1350: } ! 1351: ! 1352: intp() ! 1353: { ! 1354: NET2ADD(IAC, IP); ! 1355: if (autoflush) { ! 1356: doflush(); ! 1357: } ! 1358: if (autosynch) { ! 1359: dosynch(); ! 1360: } ! 1361: } ! 1362: ! 1363: sendbrk() ! 1364: { ! 1365: NET2ADD(IAC, BREAK); ! 1366: if (autoflush) { ! 1367: doflush(); ! 1368: } ! 1369: if (autosynch) { ! 1370: dosynch(); ! 1371: } ! 1372: } ! 1373: ! 1374: ! 1375: #define SENDQUESTION -1 ! 1376: #define SENDESCAPE -3 ! 1377: ! 1378: struct sendlist Sendlist[] = { ! 1379: { "ao", AO, "Send Telnet Abort output" }, ! 1380: { "ayt", AYT, "Send Telnet 'Are You There'" }, ! 1381: { "brk", BREAK, "Send Telnet Break" }, ! 1382: { "ec", EC, "Send Telnet Erase Character" }, ! 1383: { "el", EL, "Send Telnet Erase Line" }, ! 1384: { "escape", SENDESCAPE, "Send current escape character" }, ! 1385: { "ga", GA, "Send Telnet 'Go Ahead' sequence" }, ! 1386: { "ip", IP, "Send Telnet Interrupt Process" }, ! 1387: { "nop", NOP, "Send Telnet 'No operation'" }, ! 1388: { "synch", SYNCH, "Perform Telnet 'Synch operation'", dosynch }, ! 1389: { "?", SENDQUESTION, "Display send options" }, ! 1390: { 0 } ! 1391: }; ! 1392: ! 1393: struct sendlist Sendlist2[] = { /* some synonyms */ ! 1394: { "break", BREAK, 0 }, ! 1395: ! 1396: { "intp", IP, 0 }, ! 1397: { "interrupt", IP, 0 }, ! 1398: { "intr", IP, 0 }, ! 1399: ! 1400: { "help", SENDQUESTION, 0 }, ! 1401: ! 1402: { 0 } ! 1403: }; ! 1404: ! 1405: char ** ! 1406: getnextsend(name) ! 1407: char *name; ! 1408: { ! 1409: struct sendlist *c = (struct sendlist *) name; ! 1410: ! 1411: return (char **) (c+1); ! 1412: } ! 1413: ! 1414: struct sendlist * ! 1415: getsend(name) ! 1416: char *name; ! 1417: { ! 1418: struct sendlist *sl; ! 1419: ! 1420: if (sl = (struct sendlist *) ! 1421: genget(name, (char **) Sendlist, getnextsend)) { ! 1422: return sl; ! 1423: } else { ! 1424: return (struct sendlist *) ! 1425: genget(name, (char **) Sendlist2, getnextsend); ! 1426: } ! 1427: } ! 1428: ! 1429: sendcmd(argc, argv) ! 1430: int argc; ! 1431: char **argv; ! 1432: { ! 1433: int what; /* what we are sending this time */ ! 1434: int count; /* how many bytes we are going to need to send */ ! 1435: int hadsynch; /* are we going to process a "synch"? */ ! 1436: int i; ! 1437: int question = 0; /* was at least one argument a question */ ! 1438: struct sendlist *s; /* pointer to current command */ ! 1439: ! 1440: if (argc < 2) { ! 1441: printf("need at least one argument for 'send' command\n"); ! 1442: printf("'send ?' for help\n"); ! 1443: return 0; ! 1444: } ! 1445: /* ! 1446: * First, validate all the send arguments. ! 1447: * In addition, we see how much space we are going to need, and ! 1448: * whether or not we will be doing a "SYNCH" operation (which ! 1449: * flushes the network queue). ! 1450: */ ! 1451: count = 0; ! 1452: hadsynch = 0; ! 1453: for (i = 1; i < argc; i++) { ! 1454: s = getsend(argv[i]); ! 1455: if (s == 0) { ! 1456: printf("Unknown send argument '%s'\n'send ?' for help.\n", ! 1457: argv[i]); ! 1458: return 0; ! 1459: } else if (s == Ambiguous(struct sendlist *)) { ! 1460: printf("Ambiguous send argument '%s'\n'send ?' for help.\n", ! 1461: argv[i]); ! 1462: return 0; ! 1463: } ! 1464: switch (s->what) { ! 1465: case SENDQUESTION: ! 1466: break; ! 1467: case SENDESCAPE: ! 1468: count += 1; ! 1469: break; ! 1470: case SYNCH: ! 1471: hadsynch = 1; ! 1472: count += 2; ! 1473: break; ! 1474: default: ! 1475: count += 2; ! 1476: break; ! 1477: } ! 1478: } ! 1479: /* Now, do we have enough room? */ ! 1480: if (NETROOM() < count) { ! 1481: printf("There is not enough room in the buffer TO the network\n"); ! 1482: printf("to process your request. Nothing will be done.\n"); ! 1483: printf("('send synch' will throw away most data in the network\n"); ! 1484: printf("buffer, if this might help.)\n"); ! 1485: return 0; ! 1486: } ! 1487: /* OK, they are all OK, now go through again and actually send */ ! 1488: for (i = 1; i < argc; i++) { ! 1489: if (!(s = getsend(argv[i]))) { ! 1490: fprintf(stderr, "Telnet 'send' error - argument disappeared!\n"); ! 1491: quit(); ! 1492: /*NOTREACHED*/ ! 1493: } ! 1494: if (s->routine) { ! 1495: (*s->routine)(s); ! 1496: } else { ! 1497: switch (what = s->what) { ! 1498: case SYNCH: ! 1499: dosynch(); ! 1500: break; ! 1501: case SENDQUESTION: ! 1502: for (s = Sendlist; s->name; s++) { ! 1503: if (s->help) { ! 1504: printf(s->name); ! 1505: if (s->help) { ! 1506: printf("\t%s", s->help); ! 1507: } ! 1508: printf("\n"); ! 1509: } ! 1510: } ! 1511: question = 1; ! 1512: break; ! 1513: case SENDESCAPE: ! 1514: NETADD(escape); ! 1515: break; ! 1516: default: ! 1517: NET2ADD(IAC, what); ! 1518: break; ! 1519: } ! 1520: } ! 1521: } ! 1522: return !question; ! 1523: } ! 1524: ! 1525: /* ! 1526: * The following are the routines and data structures referred ! 1527: * to by the arguments to the "toggle" command. ! 1528: */ ! 1529: ! 1530: lclchars() ! 1531: { ! 1532: donelclchars = 1; ! 1533: return 1; ! 1534: } ! 1535: ! 1536: togdebug() ! 1537: { ! 1538: #ifndef NOT43 ! 1539: if (net > 0 && ! 1540: setsockopt(net, SOL_SOCKET, SO_DEBUG, (char *)&debug, sizeof(debug)) ! 1541: < 0) { ! 1542: perror("setsockopt (SO_DEBUG)"); ! 1543: } ! 1544: #else NOT43 ! 1545: if (debug) { ! 1546: if (net > 0 && setsockopt(net, SOL_SOCKET, SO_DEBUG, 0, 0) < 0) ! 1547: perror("setsockopt (SO_DEBUG)"); ! 1548: } else ! 1549: printf("Cannot turn off socket debugging\n"); ! 1550: #endif NOT43 ! 1551: return 1; ! 1552: } ! 1553: ! 1554: ! 1555: ! 1556: int togglehelp(); ! 1557: ! 1558: struct togglelist { ! 1559: char *name; /* name of toggle */ ! 1560: char *help; /* help message */ ! 1561: int (*handler)(); /* routine to do actual setting */ ! 1562: int dohelp; /* should we display help information */ ! 1563: int *variable; ! 1564: char *actionexplanation; ! 1565: }; ! 1566: ! 1567: struct togglelist Togglelist[] = { ! 1568: { "autoflush", ! 1569: "toggle flushing of output when sending interrupt characters", ! 1570: 0, ! 1571: 1, ! 1572: &autoflush, ! 1573: "flush output when sending interrupt characters" }, ! 1574: { "autosynch", ! 1575: "toggle automatic sending of interrupt characters in urgent mode", ! 1576: 0, ! 1577: 1, ! 1578: &autosynch, ! 1579: "send interrupt characters in urgent mode" }, ! 1580: { "crmod", ! 1581: "toggle mapping of received carriage returns", ! 1582: 0, ! 1583: 1, ! 1584: &crmod, ! 1585: "map carriage return on output" }, ! 1586: { "localchars", ! 1587: "toggle local recognition of certain control characters", ! 1588: lclchars, ! 1589: 1, ! 1590: &localchars, ! 1591: "recognize certain control characters" }, ! 1592: { " ", "", 0, 1 }, /* empty line */ ! 1593: { "debug", ! 1594: "(debugging) toggle debugging", ! 1595: togdebug, ! 1596: 1, ! 1597: &debug, ! 1598: "turn on socket level debugging" }, ! 1599: { "netdata", ! 1600: "(debugging) toggle printing of hexadecimal network data", ! 1601: 0, ! 1602: 1, ! 1603: &netdata, ! 1604: "print hexadecimal representation of network traffic" }, ! 1605: { "options", ! 1606: "(debugging) toggle viewing of options processing", ! 1607: 0, ! 1608: 1, ! 1609: &showoptions, ! 1610: "show option processing" }, ! 1611: { " ", "", 0, 1 }, /* empty line */ ! 1612: { "?", ! 1613: "display help information", ! 1614: togglehelp, ! 1615: 1 }, ! 1616: { "help", ! 1617: "display help information", ! 1618: togglehelp, ! 1619: 0 }, ! 1620: { 0 } ! 1621: }; ! 1622: ! 1623: togglehelp() ! 1624: { ! 1625: struct togglelist *c; ! 1626: ! 1627: for (c = Togglelist; c->name; c++) { ! 1628: if (c->dohelp) { ! 1629: printf("%s\t%s\n", c->name, c->help); ! 1630: } ! 1631: } ! 1632: return 0; ! 1633: } ! 1634: ! 1635: char ** ! 1636: getnexttoggle(name) ! 1637: char *name; ! 1638: { ! 1639: struct togglelist *c = (struct togglelist *) name; ! 1640: ! 1641: return (char **) (c+1); ! 1642: } ! 1643: ! 1644: struct togglelist * ! 1645: gettoggle(name) ! 1646: char *name; ! 1647: { ! 1648: return (struct togglelist *) ! 1649: genget(name, (char **) Togglelist, getnexttoggle); ! 1650: } ! 1651: ! 1652: toggle(argc, argv) ! 1653: int argc; ! 1654: char *argv[]; ! 1655: { ! 1656: int retval = 1; ! 1657: char *name; ! 1658: struct togglelist *c; ! 1659: ! 1660: if (argc < 2) { ! 1661: fprintf(stderr, ! 1662: "Need an argument to 'toggle' command. 'toggle ?' for help.\n"); ! 1663: return 0; ! 1664: } ! 1665: argc--; ! 1666: argv++; ! 1667: while (argc--) { ! 1668: name = *argv++; ! 1669: c = gettoggle(name); ! 1670: if (c == Ambiguous(struct togglelist *)) { ! 1671: fprintf(stderr, "'%s': ambiguous argument ('toggle ?' for help).\n", ! 1672: name); ! 1673: return 0; ! 1674: } else if (c == 0) { ! 1675: fprintf(stderr, "'%s': unknown argument ('toggle ?' for help).\n", ! 1676: name); ! 1677: return 0; ! 1678: } else { ! 1679: if (c->variable) { ! 1680: *c->variable = !*c->variable; /* invert it */ ! 1681: printf("%s %s.\n", *c->variable? "Will" : "Won't", ! 1682: c->actionexplanation); ! 1683: } ! 1684: if (c->handler) { ! 1685: retval &= (*c->handler)(c); ! 1686: } ! 1687: } ! 1688: } ! 1689: return retval; ! 1690: } ! 1691: ! 1692: /* ! 1693: * The following perform the "set" command. ! 1694: */ ! 1695: ! 1696: struct setlist { ! 1697: char *name; /* name */ ! 1698: char *help; /* help information */ ! 1699: char *charp; /* where it is located at */ ! 1700: }; ! 1701: ! 1702: struct setlist Setlist[] = { ! 1703: { "echo", "character to toggle local echoing on/off", &echoc }, ! 1704: { "escape", "character to escape back to telnet command mode", &escape }, ! 1705: { " ", "" }, ! 1706: { " ", "The following need 'localchars' to be toggled true", 0 }, ! 1707: { "erase", "character to cause an Erase Character", &nttyb.sg_erase }, ! 1708: { "flushoutput", "character to cause an Abort Oubput", &nltc.t_flushc }, ! 1709: { "interrupt", "character to cause an Interrupt Process", &ntc.t_intrc }, ! 1710: { "kill", "character to cause an Erase Line", &nttyb.sg_kill }, ! 1711: { "quit", "character to cause a Break", &ntc.t_quitc }, ! 1712: { "eof", "character to cause an EOF ", &ntc.t_eofc }, ! 1713: { 0 } ! 1714: }; ! 1715: ! 1716: char ** ! 1717: getnextset(name) ! 1718: char *name; ! 1719: { ! 1720: struct setlist *c = (struct setlist *)name; ! 1721: ! 1722: return (char **) (c+1); ! 1723: } ! 1724: ! 1725: struct setlist * ! 1726: getset(name) ! 1727: char *name; ! 1728: { ! 1729: return (struct setlist *) genget(name, (char **) Setlist, getnextset); ! 1730: } ! 1731: ! 1732: setcmd(argc, argv) ! 1733: int argc; ! 1734: char *argv[]; ! 1735: { ! 1736: int value; ! 1737: struct setlist *ct; ! 1738: ! 1739: /* XXX back we go... sigh */ ! 1740: if (argc != 3) { ! 1741: if ((argc == 2) && ! 1742: ((!strcmp(argv[1], "?")) || (!strcmp(argv[1], "help")))) { ! 1743: for (ct = Setlist; ct->name; ct++) { ! 1744: printf("%s\t%s\n", ct->name, ct->help); ! 1745: } ! 1746: printf("?\tdisplay help information\n"); ! 1747: } else { ! 1748: printf("Format is 'set Name Value'\n'set ?' for help.\n"); ! 1749: } ! 1750: return 0; ! 1751: } ! 1752: ! 1753: ct = getset(argv[1]); ! 1754: if (ct == 0) { ! 1755: fprintf(stderr, "'%s': unknown argument ('set ?' for help).\n", ! 1756: argv[1]); ! 1757: return 0; ! 1758: } else if (ct == Ambiguous(struct setlist *)) { ! 1759: fprintf(stderr, "'%s': ambiguous argument ('set ?' for help).\n", ! 1760: argv[1]); ! 1761: return 0; ! 1762: } else { ! 1763: if (strcmp("off", argv[2])) { ! 1764: value = special(argv[2]); ! 1765: } else { ! 1766: value = -1; ! 1767: } ! 1768: *(ct->charp) = value; ! 1769: printf("%s character is '%s'.\n", ct->name, control(*(ct->charp))); ! 1770: } ! 1771: return 1; ! 1772: } ! 1773: ! 1774: /* ! 1775: * The following are the data structures and routines for the ! 1776: * 'mode' command. ! 1777: */ ! 1778: ! 1779: dolinemode() ! 1780: { ! 1781: if (hisopts[TELOPT_SGA]) { ! 1782: wontoption(TELOPT_SGA, 0); ! 1783: } ! 1784: if (hisopts[TELOPT_ECHO]) { ! 1785: wontoption(TELOPT_ECHO, 0); ! 1786: } ! 1787: } ! 1788: ! 1789: docharmode() ! 1790: { ! 1791: if (!hisopts[TELOPT_SGA]) { ! 1792: willoption(TELOPT_SGA, 0); ! 1793: } ! 1794: if (!hisopts[TELOPT_ECHO]) { ! 1795: willoption(TELOPT_ECHO, 0); ! 1796: } ! 1797: } ! 1798: ! 1799: struct cmd Modelist[] = { ! 1800: { "character", "character-at-a-time mode", docharmode, 1, 1 }, ! 1801: { "line", "line-by-line mode", dolinemode, 1, 1 }, ! 1802: { 0 }, ! 1803: }; ! 1804: ! 1805: char ** ! 1806: getnextmode(name) ! 1807: char *name; ! 1808: { ! 1809: struct cmd *c = (struct cmd *) name; ! 1810: ! 1811: return (char **) (c+1); ! 1812: } ! 1813: ! 1814: struct cmd * ! 1815: getmodecmd(name) ! 1816: char *name; ! 1817: { ! 1818: return (struct cmd *) genget(name, (char **) Modelist, getnextmode); ! 1819: } ! 1820: ! 1821: modecmd(argc, argv) ! 1822: int argc; ! 1823: char *argv[]; ! 1824: { ! 1825: struct cmd *mt; ! 1826: ! 1827: if ((argc != 2) || !strcmp(argv[1], "?") || !strcmp(argv[1], "help")) { ! 1828: printf("format is: 'mode Mode', where 'Mode' is one of:\n\n"); ! 1829: for (mt = Modelist; mt->name; mt++) { ! 1830: printf("%s\t%s\n", mt->name, mt->help); ! 1831: } ! 1832: return 0; ! 1833: } ! 1834: mt = getmodecmd(argv[1]); ! 1835: if (mt == 0) { ! 1836: fprintf(stderr, "Unknown mode '%s' ('mode ?' for help).\n", argv[1]); ! 1837: return 0; ! 1838: } else if (mt == Ambiguous(struct cmd *)) { ! 1839: fprintf(stderr, "Ambiguous mode '%s' ('mode ?' for help).\n", argv[1]); ! 1840: return 0; ! 1841: } else { ! 1842: (*mt->handler)(); ! 1843: } ! 1844: return 1; ! 1845: } ! 1846: ! 1847: /* ! 1848: * The following data structures and routines implement the ! 1849: * "display" command. ! 1850: */ ! 1851: ! 1852: display(argc, argv) ! 1853: int argc; ! 1854: char *argv[]; ! 1855: { ! 1856: #define dotog(tl) if (tl->variable && tl->actionexplanation) { \ ! 1857: if (*tl->variable) { \ ! 1858: printf("will"); \ ! 1859: } else { \ ! 1860: printf("won't"); \ ! 1861: } \ ! 1862: printf(" %s.\n", tl->actionexplanation); \ ! 1863: } ! 1864: ! 1865: #define doset(sl) if (sl->name && *sl->name != ' ') { \ ! 1866: printf("[%s]\t%s.\n", control(*sl->charp), sl->name); \ ! 1867: } ! 1868: ! 1869: struct togglelist *tl; ! 1870: struct setlist *sl; ! 1871: ! 1872: if (argc == 1) { ! 1873: for (tl = Togglelist; tl->name; tl++) { ! 1874: dotog(tl); ! 1875: } ! 1876: printf("\n"); ! 1877: for (sl = Setlist; sl->name; sl++) { ! 1878: doset(sl); ! 1879: } ! 1880: } else { ! 1881: int i; ! 1882: ! 1883: for (i = 1; i < argc; i++) { ! 1884: sl = getset(argv[i]); ! 1885: tl = gettoggle(argv[i]); ! 1886: if ((sl == Ambiguous(struct setlist *)) || ! 1887: (tl == Ambiguous(struct togglelist *))) { ! 1888: printf("?Ambiguous argument '%s'.\n", argv[i]); ! 1889: return 0; ! 1890: } else if (!sl && !tl) { ! 1891: printf("?Unknown argument '%s'.\n", argv[i]); ! 1892: return 0; ! 1893: } else { ! 1894: if (tl) { ! 1895: dotog(tl); ! 1896: } ! 1897: if (sl) { ! 1898: doset(sl); ! 1899: } ! 1900: } ! 1901: } ! 1902: } ! 1903: return 1; ! 1904: #undef doset(sl) ! 1905: #undef dotog(tl) ! 1906: } ! 1907: ! 1908: /* ! 1909: * The following are the data structures, and many of the routines, ! 1910: * relating to command processing. ! 1911: */ ! 1912: ! 1913: /* ! 1914: * Set the escape character. ! 1915: */ ! 1916: setescape(argc, argv) ! 1917: int argc; ! 1918: char *argv[]; ! 1919: { ! 1920: register char *arg; ! 1921: char buf[50]; ! 1922: ! 1923: printf( ! 1924: "Deprecated usage - please use 'set escape%s%s' in the future.\n", ! 1925: (argc > 2)? " ":"", (argc > 2)? argv[1]: ""); ! 1926: if (argc > 2) ! 1927: arg = argv[1]; ! 1928: else { ! 1929: printf("new escape character: "); ! 1930: gets(buf); ! 1931: arg = buf; ! 1932: } ! 1933: if (arg[0] != '\0') ! 1934: escape = arg[0]; ! 1935: printf("Escape character is '%s'.\n", control(escape)); ! 1936: fflush(stdout); ! 1937: return 1; ! 1938: } ! 1939: ! 1940: /*VARARGS*/ ! 1941: togcrmod() ! 1942: { ! 1943: crmod = !crmod; ! 1944: printf("Deprecated usage - please use 'toggle crmod' in the future.\n"); ! 1945: printf("%s map carriage return on output.\n", crmod ? "Will" : "Won't"); ! 1946: fflush(stdout); ! 1947: return 1; ! 1948: } ! 1949: ! 1950: /*VARARGS*/ ! 1951: suspend() ! 1952: { ! 1953: setcommandmode(); ! 1954: kill(0, SIGTSTP); ! 1955: /* reget parameters in case they were changed */ ! 1956: ioctl(0, TIOCGETP, (char *)&ottyb); ! 1957: ioctl(0, TIOCGETC, (char *)&otc); ! 1958: ioctl(0, TIOCGLTC, (char *)&oltc); ! 1959: return 1; ! 1960: } ! 1961: ! 1962: /*VARARGS*/ ! 1963: bye() ! 1964: { ! 1965: register char *op; ! 1966: ! 1967: if (connected) { ! 1968: shutdown(net, 2); ! 1969: printf("Connection closed.\n"); ! 1970: close(net); ! 1971: connected = 0; ! 1972: /* reset his options */ ! 1973: for (op = hisopts; op < &hisopts[256]; op++) ! 1974: *op = 0; ! 1975: } ! 1976: return 1; ! 1977: } ! 1978: ! 1979: /*VARARGS*/ ! 1980: quit() ! 1981: { ! 1982: (void) call(bye, "bye", 0); ! 1983: exit(0); ! 1984: /*NOTREACHED*/ ! 1985: } ! 1986: ! 1987: /* ! 1988: * Print status about the connection. ! 1989: */ ! 1990: /*ARGSUSED*/ ! 1991: status(argc, argv) ! 1992: int argc; ! 1993: char *argv[]; ! 1994: { ! 1995: if (connected) { ! 1996: printf("Connected to %s.\n", hostname); ! 1997: if (argc < 2) { ! 1998: printf("Operating in %s.\n", modedescriptions[getconnmode()]); ! 1999: if (localchars) { ! 2000: printf("Catching signals locally.\n"); ! 2001: } ! 2002: } ! 2003: } else { ! 2004: printf("No connection.\n"); ! 2005: } ! 2006: printf("Escape character is '%s'.\n", control(escape)); ! 2007: fflush(stdout); ! 2008: return 1; ! 2009: } ! 2010: ! 2011: tn(argc, argv) ! 2012: int argc; ! 2013: char *argv[]; ! 2014: { ! 2015: register struct hostent *host = 0; ! 2016: ! 2017: if (connected) { ! 2018: printf("?Already connected to %s\n", hostname); ! 2019: return 0; ! 2020: } ! 2021: if (argc < 2) { ! 2022: (void) strcpy(line, "Connect "); ! 2023: printf("(to) "); ! 2024: gets(&line[strlen(line)]); ! 2025: makeargv(); ! 2026: argc = margc; ! 2027: argv = margv; ! 2028: } ! 2029: if (argc > 3) { ! 2030: printf("usage: %s host-name [port]\n", argv[0]); ! 2031: return 0; ! 2032: } ! 2033: sin.sin_addr.s_addr = inet_addr(argv[1]); ! 2034: if (sin.sin_addr.s_addr != -1) { ! 2035: sin.sin_family = AF_INET; ! 2036: (void) strcpy(hnamebuf, argv[1]); ! 2037: hostname = hnamebuf; ! 2038: } else { ! 2039: host = gethostbyname(argv[1]); ! 2040: if (host) { ! 2041: sin.sin_family = host->h_addrtype; ! 2042: #ifndef NOT43 ! 2043: bcopy(host->h_addr_list[0], (caddr_t)&sin.sin_addr, ! 2044: host->h_length); ! 2045: #else NOT43 ! 2046: bcopy(host->h_addr, (caddr_t)&sin.sin_addr, ! 2047: host->h_length); ! 2048: #endif NOT43 ! 2049: hostname = host->h_name; ! 2050: } else { ! 2051: printf("%s: unknown host\n", argv[1]); ! 2052: return 0; ! 2053: } ! 2054: } ! 2055: sin.sin_port = sp->s_port; ! 2056: if (argc == 3) { ! 2057: sin.sin_port = atoi(argv[2]); ! 2058: if (sin.sin_port == 0) { ! 2059: sp = getservbyname(argv[2], "tcp"); ! 2060: if (sp) ! 2061: sin.sin_port = sp->s_port; ! 2062: else { ! 2063: printf("%s: bad port number\n", argv[2]); ! 2064: return 0; ! 2065: } ! 2066: } else { ! 2067: sin.sin_port = atoi(argv[2]); ! 2068: sin.sin_port = htons(sin.sin_port); ! 2069: } ! 2070: telnetport = 0; ! 2071: } else { ! 2072: telnetport = 1; ! 2073: } ! 2074: signal(SIGINT, intr); ! 2075: signal(SIGQUIT, intr2); ! 2076: signal(SIGPIPE, deadpeer); ! 2077: printf("Trying...\n"); ! 2078: do { ! 2079: net = socket(AF_INET, SOCK_STREAM, 0); ! 2080: if (net < 0) { ! 2081: perror("telnet: socket"); ! 2082: return 0; ! 2083: } ! 2084: #ifndef NOT43 ! 2085: if (debug && ! 2086: setsockopt(net, SOL_SOCKET, SO_DEBUG, ! 2087: (char *)&debug, sizeof(debug)) < 0) ! 2088: #else NOT43 ! 2089: if (debug && setsockopt(net, SOL_SOCKET, SO_DEBUG, 0, 0) < 0) ! 2090: #endif NOT43 ! 2091: perror("setsockopt (SO_DEBUG)"); ! 2092: ! 2093: if (connect(net, (struct sockaddr *)&sin, sizeof (sin)) < 0) { ! 2094: #ifndef NOT43 ! 2095: if (host && host->h_addr_list[1]) { ! 2096: int oerrno = errno; ! 2097: ! 2098: fprintf(stderr, ! 2099: "telnet: connect to address %s: ", ! 2100: inet_ntoa(sin.sin_addr)); ! 2101: errno = oerrno; ! 2102: perror((char *)0); ! 2103: host->h_addr_list++; ! 2104: bcopy(host->h_addr_list[0], ! 2105: (caddr_t)&sin.sin_addr, host->h_length); ! 2106: fprintf(stderr, "Trying %s...\n", ! 2107: inet_ntoa(sin.sin_addr)); ! 2108: (void) close(net); ! 2109: continue; ! 2110: } ! 2111: #endif NOT43 ! 2112: perror("telnet: connect"); ! 2113: signal(SIGINT, SIG_DFL); ! 2114: signal(SIGQUIT, SIG_DFL); ! 2115: return 0; ! 2116: } ! 2117: connected++; ! 2118: } while (connected == 0); ! 2119: call(status, "status", "notmuch", 0); ! 2120: if (setjmp(peerdied) == 0) ! 2121: telnet(); ! 2122: fprintf(stderr, "Connection closed by foreign host.\n"); ! 2123: exit(1); ! 2124: /*NOTREACHED*/ ! 2125: } ! 2126: ! 2127: ! 2128: #define HELPINDENT (sizeof ("connect")) ! 2129: ! 2130: char openhelp[] = "connect to a site"; ! 2131: char closehelp[] = "close current connection"; ! 2132: char quithelp[] = "exit telnet"; ! 2133: char zhelp[] = "suspend telnet"; ! 2134: char statushelp[] = "print status information"; ! 2135: char helphelp[] = "print help information"; ! 2136: char sendhelp[] = "transmit special characters ('send ?' for more)"; ! 2137: char sethelp[] = "set operating parameters ('set ?' for more)"; ! 2138: char togglestring[] ="toggle operating parameters ('toggle ?' for more)"; ! 2139: char displayhelp[] = "display operating parameters"; ! 2140: char modehelp[] = ! 2141: "try to enter line-by-line or character-at-a-time mode"; ! 2142: ! 2143: int help(); ! 2144: ! 2145: struct cmd cmdtab[] = { ! 2146: { "close", closehelp, bye, 1, 1 }, ! 2147: { "display", displayhelp, display, 1, 0 }, ! 2148: { "mode", modehelp, modecmd, 1, 1 }, ! 2149: { "open", openhelp, tn, 1, 0 }, ! 2150: { "quit", quithelp, quit, 1, 0 }, ! 2151: { "send", sendhelp, sendcmd, 1, 1 }, ! 2152: { "set", sethelp, setcmd, 1, 0 }, ! 2153: { "status", statushelp, status, 1, 0 }, ! 2154: { "toggle", togglestring, toggle, 1, 0 }, ! 2155: { "z", zhelp, suspend, 1, 0 }, ! 2156: { "?", helphelp, help, 1, 0 }, ! 2157: 0 ! 2158: }; ! 2159: ! 2160: char crmodhelp[] = "deprecated command -- use 'toggle crmod' instead"; ! 2161: char escapehelp[] = "deprecated command -- use 'set escape' instead"; ! 2162: ! 2163: struct cmd cmdtab2[] = { ! 2164: { "help", helphelp, help, 0, 0 }, ! 2165: { "escape", escapehelp, setescape, 1, 0 }, ! 2166: { "crmod", crmodhelp, togcrmod, 1, 0 }, ! 2167: 0 ! 2168: }; ! 2169: ! 2170: /* ! 2171: * Help command. ! 2172: */ ! 2173: help(argc, argv) ! 2174: int argc; ! 2175: char *argv[]; ! 2176: { ! 2177: register struct cmd *c; ! 2178: ! 2179: if (argc == 1) { ! 2180: printf("Commands may be abbreviated. Commands are:\n\n"); ! 2181: for (c = cmdtab; c->name; c++) ! 2182: if (c->dohelp) { ! 2183: printf("%-*s\t%s\n", HELPINDENT, c->name, ! 2184: c->help); ! 2185: } ! 2186: return 0; ! 2187: } ! 2188: while (--argc > 0) { ! 2189: register char *arg; ! 2190: arg = *++argv; ! 2191: c = getcmd(arg); ! 2192: if (c == Ambiguous(struct cmd *)) ! 2193: printf("?Ambiguous help command %s\n", arg); ! 2194: else if (c == (struct cmd *)0) ! 2195: printf("?Invalid help command %s\n", arg); ! 2196: else ! 2197: printf("%s\n", c->help); ! 2198: } ! 2199: return 0; ! 2200: } ! 2201: /* ! 2202: * Call routine with argc, argv set from args (terminated by 0). ! 2203: * VARARGS2 ! 2204: */ ! 2205: call(routine, args) ! 2206: int (*routine)(); ! 2207: char *args; ! 2208: { ! 2209: register char **argp; ! 2210: register int argc; ! 2211: ! 2212: for (argc = 0, argp = &args; *argp++ != 0; argc++) ! 2213: ; ! 2214: return (*routine)(argc, &args); ! 2215: } ! 2216: ! 2217: makeargv() ! 2218: { ! 2219: register char *cp; ! 2220: register char **argp = margv; ! 2221: ! 2222: margc = 0; ! 2223: for (cp = line; *cp;) { ! 2224: while (isspace(*cp)) ! 2225: cp++; ! 2226: if (*cp == '\0') ! 2227: break; ! 2228: *argp++ = cp; ! 2229: margc += 1; ! 2230: while (*cp != '\0' && !isspace(*cp)) ! 2231: cp++; ! 2232: if (*cp == '\0') ! 2233: break; ! 2234: *cp++ = '\0'; ! 2235: } ! 2236: *argp++ = 0; ! 2237: } ! 2238: ! 2239: char ** ! 2240: getnextcmd(name) ! 2241: char *name; ! 2242: { ! 2243: struct cmd *c = (struct cmd *) name; ! 2244: ! 2245: return (char **) (c+1); ! 2246: } ! 2247: ! 2248: struct cmd * ! 2249: getcmd(name) ! 2250: char *name; ! 2251: { ! 2252: struct cmd *cm; ! 2253: ! 2254: if (cm = (struct cmd *) genget(name, (char **) cmdtab, getnextcmd)) { ! 2255: return cm; ! 2256: } else { ! 2257: return (struct cmd *) genget(name, (char **) cmdtab2, getnextcmd); ! 2258: } ! 2259: } ! 2260: ! 2261: command(top) ! 2262: int top; ! 2263: { ! 2264: register struct cmd *c; ! 2265: ! 2266: setcommandmode(); ! 2267: if (!top) { ! 2268: putchar('\n'); ! 2269: } else { ! 2270: signal(SIGINT, SIG_DFL); ! 2271: signal(SIGQUIT, SIG_DFL); ! 2272: } ! 2273: for (;;) { ! 2274: printf("%s> ", prompt); ! 2275: if (gets(line) == 0) { ! 2276: if (feof(stdin)) ! 2277: quit(); ! 2278: break; ! 2279: } ! 2280: if (line[0] == 0) ! 2281: break; ! 2282: makeargv(); ! 2283: c = getcmd(margv[0]); ! 2284: if (c == Ambiguous(struct cmd *)) { ! 2285: printf("?Ambiguous command\n"); ! 2286: continue; ! 2287: } ! 2288: if (c == 0) { ! 2289: printf("?Invalid command\n"); ! 2290: continue; ! 2291: } ! 2292: if (c->needconnect && !connected) { ! 2293: printf("?Need to be connected first.\n"); ! 2294: continue; ! 2295: } ! 2296: if ((*c->handler)(margc, margv)) { ! 2297: break; ! 2298: } ! 2299: } ! 2300: if (!top) { ! 2301: if (!connected) { ! 2302: longjmp(toplevel, 1); ! 2303: /*NOTREACHED*/ ! 2304: } ! 2305: setconnmode(); ! 2306: } ! 2307: } ! 2308: ! 2309: /* ! 2310: * main. Parse arguments, invoke the protocol or command parser. ! 2311: */ ! 2312: ! 2313: ! 2314: main(argc, argv) ! 2315: int argc; ! 2316: char *argv[]; ! 2317: { ! 2318: sp = getservbyname("telnet", "tcp"); ! 2319: if (sp == 0) { ! 2320: fprintf(stderr, "telnet: tcp/telnet: unknown service\n"); ! 2321: exit(1); ! 2322: } ! 2323: NetTrace = stdout; ! 2324: ioctl(0, TIOCGETP, (char *)&ottyb); ! 2325: ioctl(0, TIOCGETC, (char *)&otc); ! 2326: ioctl(0, TIOCGLTC, (char *)&oltc); ! 2327: #if defined(LNOFLSH) ! 2328: ioctl(0, TIOCLGET, (char *)&autoflush); ! 2329: autoflush = !(autoflush&LNOFLSH); /* if LNOFLSH, no autoflush */ ! 2330: #else /* LNOFLSH */ ! 2331: autoflush = 1; ! 2332: #endif /* LNOFLSH */ ! 2333: ntc = otc; ! 2334: nltc = oltc; ! 2335: nttyb = ottyb; ! 2336: setbuf(stdin, (char *)0); ! 2337: setbuf(stdout, (char *)0); ! 2338: prompt = argv[0]; ! 2339: if (argc > 1 && !strcmp(argv[1], "-d")) { ! 2340: debug = 1; ! 2341: argv++; ! 2342: argc--; ! 2343: } ! 2344: if (argc > 1 && !strcmp(argv[1], "-n")) { ! 2345: argv++; ! 2346: argc--; ! 2347: if (argc > 1) { /* get file name */ ! 2348: NetTrace = fopen(argv[1], "w"); ! 2349: argv++; ! 2350: argc--; ! 2351: if (NetTrace == NULL) { ! 2352: NetTrace = stdout; ! 2353: } ! 2354: } ! 2355: } ! 2356: if (argc != 1) { ! 2357: if (setjmp(toplevel) != 0) ! 2358: exit(0); ! 2359: tn(argc, argv); ! 2360: } ! 2361: setjmp(toplevel); ! 2362: for (;;) ! 2363: command(1); ! 2364: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.