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 = &notc;
 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 = &notc2;
 638:         } else
 639:             tc = &notc;
 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 = &notc2;
 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: }

Defined functions

Dump defined in line 523; used 2 times
bye defined in line 1963; used 2 times
call defined in line 2205; used 2 times
command defined in line 2261; used 3 times
control defined in line 235; used 4 times
deadpeer defined in line 489; used 1 times
display defined in line 1852; used 1 times
docharmode defined in line 1789; used 1 times
doescape defined in line 513; used 1 times
doflush defined in line 1341; used 3 times
dolinemode defined in line 1779; used 1 times
dooption defined in line 1251; used 2 times
dosynch defined in line 1333; used 4 times
genget defined in line 172; used 7 times
getcmd defined in line 2248; used 3 times
getconnmode defined in line 704; used 2 times
getmodecmd defined in line 1814; used 1 times
getnextcmd defined in line 2239; used 2 times
getnextmode defined in line 1805; used 1 times
getnextsend defined in line 1405; used 2 times
getnextset defined in line 1716; used 1 times
getnexttoggle defined in line 1635; used 1 times
getsend defined in line 1414; used 2 times
getset defined in line 1725; used 2 times
gettoggle defined in line 1644; used 2 times
help defined in line 2173; used 15 times
intp defined in line 1352; used 2 times
intr defined in line 495; used 1 times
intr2 defined in line 505; used 1 times
lclchars defined in line 1530; used 1 times
main defined in line 2314; never used
makeargv defined in line 2217; used 2 times
mode defined in line 590; used 2 times
modecmd defined in line 1821; used 1 times
netclear defined in line 420; used 1 times
netflush defined in line 316; used 1 times
nextitem defined in line 374; used 3 times
printoption defined in line 557; used 11 times
quit defined in line 1980; used 4 times
sendbrk defined in line 1363; used 2 times
sendcmd defined in line 1429; used 1 times
setcmd defined in line 1732; used 1 times
setcommandmode defined in line 727; used 6 times
setconnmode defined in line 721; used 6 times
setescape defined in line 1916; used 1 times
special defined in line 209; used 1 times
status defined in line 1991; used 2 times
stilloob defined in line 283; used 2 times
suboption defined in line 1289; used 1 times
suspend defined in line 1951; used 1 times
telnet defined in line 740; used 1 times
telrcv defined in line 1017; used 1 times
tn defined in line 2011; used 2 times
togcrmod defined in line 1941; used 1 times
togdebug defined in line 1536; used 1 times
toggle defined in line 1652; used 1 times
togglehelp defined in line 1623; used 3 times
ttyflush defined in line 464; used 4 times
upcase defined in line 264; used 1 times
willoption defined in line 1192; used 4 times
wontoption defined in line 1222; used 3 times

Defined variables

Modelist defined in line 1799; used 2 times
SYNCHing defined in line 116; used 8 times
Sendlist defined in line 1378; used 2 times
Sendlist2 defined in line 1393; used 1 times
Setlist defined in line 1702; used 3 times
Togglelist defined in line 1567; used 3 times
ambiguous defined in line 168; used 1 times
autoflush defined in line 118; used 8 times
autosynch defined in line 119; used 3 times
closehelp defined in line 2131; used 1 times
cmdtab defined in line 2145; used 2 times
cmdtab2 defined in line 2163; used 1 times
connected defined in line 101; used 8 times
copyright defined in line 8; never used
crmod defined in line 106; used 7 times
crmodhelp defined in line 2160; used 1 times
debug defined in line 105; used 9 times
displayhelp defined in line 2139; used 1 times
donelclchars defined in line 121; used 3 times
dont defined in line 89; used 6 times
dontlecho defined in line 122; used 3 times
doopt defined in line 88; used 6 times
echoc defined in line 114; used 3 times
escape defined in line 113; used 7 times
escapehelp defined in line 2161; used 1 times
flushline defined in line 143; used 9 times
flushout defined in line 117; used 7 times
globalmode defined in line 142; used 7 times
helphelp defined in line 2135; used 2 times
hisopts defined in line 85; used 17 times
hnamebuf defined in line 146; used 2 times
hostname defined in line 145; used 5 times
line defined in line 124; used 6 times
localchars defined in line 120; used 9 times
margc defined in line 125; used 4 times
margv defined in line 126; used 4 times
modedescriptions defined in line 695; used 1 times
modehelp defined in line 2140; used 1 times
myopts defined in line 86; used 7 times
net defined in line 102; used 32 times
netdata defined in line 107; used 3 times
netobuf defined in line 69; used 9 times
neturg defined in line 76; used 7 times
nfrontp defined in line 69; used 20 times
nltc defined in line 140; used 4 times
ntc defined in line 139; used 10 times
nttyb defined in line 141; used 6 times
oltc defined in line 140; used 5 times
openhelp defined in line 2130; used 1 times
otc defined in line 139; used 4 times
ottyb defined in line 141; used 3 times
peerdied defined in line 129; used 3 times
prompt defined in line 112; used 2 times
quithelp defined in line 2132; used 1 times
sbp defined in line 732; used 8 times
scc defined in line 734; used 10 times
sccsid defined in line 14; never used
sendhelp defined in line 2136; used 1 times
sethelp defined in line 2137; used 1 times
showoptions defined in line 104; used 2 times
sibuf defined in line 732; used 7 times
sin defined in line 134; used 18 times
sp defined in line 137; used 6 times
statushelp defined in line 2134; used 1 times
subbuffer defined in line 78; used 5 times
subend defined in line 78; used 1 times
  • in line 80
subpointer defined in line 78; used 4 times
tbp defined in line 733; used 7 times
tcc defined in line 734; used 11 times
telnetport defined in line 109; used 3 times
tfrontp defined in line 61; used 6 times
tibuf defined in line 733; used 3 times
togglestring defined in line 2138; used 1 times
toplevel defined in line 128; used 4 times
tout defined in line 103; used 5 times
ttyobuf defined in line 61; used 5 times
will defined in line 90; used 4 times
wont defined in line 91; used 6 times
zhelp defined in line 2133; used 1 times

Defined struct's

cmd defined in line 93; used 42 times
sendlist defined in line 1325; used 22 times
setlist defined in line 1696; used 18 times
togglelist defined in line 1558; used 20 times

Defined macros

Ambiguous defined in line 169; used 9 times
BYTES_PER_LINE defined in line 529; used 3 times
FD_CLR defined in line 53; used 5 times
FD_ISSET defined in line 54; used 6 times
FD_SET defined in line 52; used 6 times
FD_ZERO defined in line 55; used 4 times
HELPINDENT defined in line 2128; used 1 times
NET2ADD defined in line 71; used 10 times
NETADD defined in line 70; used 7 times
NETBYTES defined in line 74; used 2 times
NETLOC defined in line 72; used 2 times
NETMAX defined in line 73; used 1 times
  • in line 75
NETROOM defined in line 75; used 3 times
SB_ACCUM defined in line 81; used 3 times
SB_CLEAR defined in line 79; used 1 times
SB_TERM defined in line 80; used 1 times
SENDESCAPE defined in line 1376; used 1 times
SENDQUESTION defined in line 1375; used 2 times
TELOPTS defined in line 31; never used
TS_CR defined in line 1013; used 1 times
TS_DATA defined in line 1007; used 8 times
TS_DO defined in line 1011; used 1 times
TS_DONT defined in line 1012; used 1 times
TS_IAC defined in line 1008; used 1 times
TS_SB defined in line 1014; used 2 times
TS_SE defined in line 1015; used 1 times
TS_WILL defined in line 1009; used 1 times
TS_WONT defined in line 1010; used 1 times
TTYADD defined in line 62; used 8 times
TTYBYTES defined in line 66; used 2 times
TTYLOC defined in line 63; used 1 times
  • in line 67
TTYMAX defined in line 64; used 1 times
  • in line 67
TTYMIN defined in line 65; never used
TTYROOM defined in line 67; used 1 times
doset defined in line 1865; used 3 times
dotog defined in line 1856; used 3 times
min defined in line 530; used 1 times
settimer defined in line 162; used 5 times
strip defined in line 59; used 2 times
wewant defined in line 424; used 2 times
Last modified: 1986-05-27
Generated: 2016-12-26
Generated by src2html V0.67
page hit count: 8040
Valid CSS Valid XHTML 1.0 Strict