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

Defined variables

Modelist defined in line 1797; used 2 times
SYNCHing defined in line 114; used 8 times
Sendlist defined in line 1376; used 2 times
Sendlist2 defined in line 1391; used 1 times
Setlist defined in line 1700; used 3 times
Togglelist defined in line 1565; used 3 times
ambiguous defined in line 166; used 1 times
autoflush defined in line 116; used 8 times
autosynch defined in line 117; 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 99; used 8 times
copyright defined in line 8; never used
crmod defined in line 104; used 7 times
crmodhelp defined in line 2160; used 1 times
debug defined in line 103; used 9 times
displayhelp defined in line 2139; used 1 times
donelclchars defined in line 119; used 3 times
dont defined in line 87; used 6 times
dontlecho defined in line 120; used 3 times
doopt defined in line 86; used 6 times
echoc defined in line 112; used 3 times
escape defined in line 111; used 7 times
escapehelp defined in line 2161; used 1 times
flushline defined in line 141; used 9 times
flushout defined in line 115; used 7 times
globalmode defined in line 140; used 7 times
helphelp defined in line 2135; used 2 times
hisopts defined in line 83; used 17 times
hnamebuf defined in line 144; used 2 times
hostname defined in line 143; used 5 times
line defined in line 122; used 6 times
localchars defined in line 118; used 9 times
margc defined in line 123; used 4 times
margv defined in line 124; used 4 times
modedescriptions defined in line 693; used 1 times
modehelp defined in line 2140; used 1 times
myopts defined in line 84; used 8 times
net defined in line 100; used 32 times
netdata defined in line 105; used 3 times
netobuf defined in line 67; used 9 times
neturg defined in line 74; used 7 times
nfrontp defined in line 67; used 20 times
nltc defined in line 138; used 4 times
ntc defined in line 137; used 10 times
nttyb defined in line 139; used 6 times
oltc defined in line 138; used 5 times
openhelp defined in line 2130; used 1 times
otc defined in line 137; used 4 times
ottyb defined in line 139; used 3 times
peerdied defined in line 127; used 3 times
prompt defined in line 110; used 2 times
quithelp defined in line 2132; used 1 times
sbp defined in line 730; used 8 times
scc defined in line 732; used 10 times
sccsid defined in line 12; never used
sendhelp defined in line 2136; used 1 times
sethelp defined in line 2137; used 1 times
showoptions defined in line 102; used 2 times
sibuf defined in line 730; used 7 times
sin defined in line 132; used 18 times
sp defined in line 135; used 6 times
statushelp defined in line 2134; used 1 times
subbuffer defined in line 76; used 5 times
subend defined in line 76; used 1 times
  • in line 78
subpointer defined in line 76; used 4 times
tbp defined in line 731; used 7 times
tcc defined in line 732; used 11 times
telnetport defined in line 107; used 3 times
tfrontp defined in line 59; used 6 times
tibuf defined in line 731; used 3 times
togglestring defined in line 2138; used 1 times
toplevel defined in line 126; used 4 times
tout defined in line 101; used 5 times
ttyobuf defined in line 59; used 5 times
will defined in line 88; used 4 times
wont defined in line 89; used 6 times
zhelp defined in line 2133; used 1 times

Defined struct's

cmd defined in line 91; used 42 times
sendlist defined in line 1323; used 22 times
setlist defined in line 1694; used 18 times
togglelist defined in line 1556; used 20 times

Defined macros

Ambiguous defined in line 167; used 9 times
BYTES_PER_LINE defined in line 527; used 3 times
FD_CLR defined in line 51; used 5 times
FD_ISSET defined in line 52; used 6 times
FD_SET defined in line 50; used 6 times
FD_ZERO defined in line 53; used 4 times
HELPINDENT defined in line 2128; used 1 times
NET2ADD defined in line 69; used 10 times
NETADD defined in line 68; used 7 times
NETBYTES defined in line 72; used 2 times
NETLOC defined in line 70; used 2 times
NETMAX defined in line 71; used 1 times
  • in line 73
NETROOM defined in line 73; used 3 times
SB_ACCUM defined in line 79; used 3 times
SB_CLEAR defined in line 77; used 1 times
SB_TERM defined in line 78; used 1 times
SENDESCAPE defined in line 1374; used 1 times
SENDQUESTION defined in line 1373; used 2 times
TELOPTS defined in line 29; never used
TS_CR defined in line 1011; used 1 times
TS_DATA defined in line 1005; used 8 times
TS_DO defined in line 1009; used 1 times
TS_DONT defined in line 1010; used 1 times
TS_IAC defined in line 1006; used 1 times
TS_SB defined in line 1012; used 2 times
TS_SE defined in line 1013; used 1 times
TS_WILL defined in line 1007; used 1 times
TS_WONT defined in line 1008; used 1 times
TTYADD defined in line 60; used 8 times
TTYBYTES defined in line 64; used 2 times
TTYLOC defined in line 61; used 1 times
  • in line 65
TTYMAX defined in line 62; used 1 times
  • in line 65
TTYMIN defined in line 63; never used
TTYROOM defined in line 65; used 1 times
doset defined in line 1863; used 3 times
dotog defined in line 1854; used 3 times
min defined in line 528; used 1 times
settimer defined in line 160; used 5 times
strip defined in line 57; used 2 times
wewant defined in line 422; used 2 times
Last modified: 1994-01-11
Generated: 2016-12-26
Generated by src2html V0.67
page hit count: 14984
Valid CSS Valid XHTML 1.0 Strict