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

Defined functions

DataToNetwork defined in line 1234; used 3 times
DataToTerminal defined in line 1271; used 3 times
Dump defined in line 1396; used 2 times
EmptyTerminal defined in line 1303; used 5 times
Exit defined in line 1368; used 2 times
ExitPerror defined in line 1386; never used
ExitString defined in line 1376; used 3 times
Scheduler defined in line 520; used 2 times
SetForExit defined in line 1354; used 3 times
SetIn3270 defined in line 1020; used 5 times
SetPrintNet defined in line 1098; used 2 times
StringToTerminal defined in line 1327; used 6 times
TtyChars defined in line 1200; never used
_putchar defined in line 1344; never used
bye defined in line 334; used 3 times
call defined in line 393; used 2 times
command defined in line 676; used 4 times
control defined in line 1111; used 2 times
deadpeer defined in line 1159; used 2 times
dooption defined in line 981; used 1 times
getcmd defined in line 1130; used 3 times
help defined in line 361; used 7 times
inputAvailable defined in line 1173; used 2 times
intr defined in line 1166; used 2 times
main defined in line 165; never used
makeargv defined in line 296; used 2 times
mode defined in line 409; used 24 times
netflush defined in line 1205; used 4 times
outputPurge defined in line 1180; used 2 times
printoption defined in line 1430; used 9 times
quit defined in line 352; used 3 times
setcrmod defined in line 1075; used 2 times
setdebug defined in line 1085; used 2 times
setescape defined in line 1043; used 2 times
setoptions defined in line 1065; used 2 times
status defined in line 285; used 3 times
suspend defined in line 320; used 4 times
telnet defined in line 479; used 1 times
telrcv defined in line 738; used 1 times
tn defined in line 212; used 3 times
ttyflush defined in line 1186; used 4 times
willoption defined in line 915; used 1 times
wontoption defined in line 951; used 1 times

Defined variables

ForceMode defined in line 92; used 3 times
HaveInput defined in line 85; used 3 times
ISend defined in line 91; used 6 times
Ibackp defined in line 57; used 19 times
Ibuf defined in line 57; used 11 times
Ifrontp defined in line 57; used 16 times
In3270 defined in line 90; used 14 times
SbBuffer defined in line 62; used 7 times
SentTerminalType defined in line 89; used 2 times
closehelp defined in line 126; used 1 times
cmdtab defined in line 137; used 2 times
connected defined in line 88; used 6 times
crmod defined in line 96; used 4 times
crmodhelp defined in line 134; used 1 times
debug defined in line 95; used 6 times
debughelp defined in line 129; used 1 times
dont defined in line 71; used 8 times
doopt defined in line 70; used 6 times
escape defined in line 100; used 3 times
escapehelp defined in line 130; used 1 times
helphelp defined in line 132; used 2 times
hisopts defined in line 67; used 12 times
hnamebuf defined in line 210; used 2 times
hostname defined in line 209; used 5 times
line defined in line 102; used 6 times
margc defined in line 103; used 4 times
margv defined in line 104; used 4 times
myopts defined in line 68; used 7 times
net defined in line 93; used 20 times
netobuf defined in line 60; used 8 times
nfrontp defined in line 60; used 27 times
noltc defined in line 407; used 1 times
notc defined in line 406; used 2 times
oltc defined in line 162; used 3 times
openhelp defined in line 125; used 1 times
optionshelp defined in line 133; used 1 times
otc defined in line 161; used 5 times
ottyb defined in line 163; used 3 times
pSb defined in line 62; used 5 times
peerdied defined in line 107; used 3 times
printnet defined in line 97; used 5 times
printnethelp defined in line 135; used 1 times
prompt defined in line 99; used 2 times
quithelp defined in line 127; used 1 times
sb_terminal defined in line 74; used 5 times
sbp defined in line 471; used 5 times
scc defined in line 473; used 13 times
sccsid defined in line 24; never used
showoptions defined in line 94; used 4 times
sibuf defined in line 471; used 3 times
sin defined in line 154; used 11 times
sp defined in line 159; used 3 times
statushelp defined in line 131; used 1 times
tbp defined in line 472; used 4 times
tcc defined in line 473; used 13 times
tfrontp defined in line 59; used 20 times
tibuf defined in line 472; used 3 times
tin defined in line 474; used 5 times
toplevel defined in line 106; used 4 times
tout defined in line 474; used 10 times
ttyobuf defined in line 59; used 11 times
will defined in line 72; used 5 times
wont defined in line 73; used 7 times
zhelp defined in line 128; used 2 times

Defined struct's

cmd defined in line 118; used 20 times

Defined macros

BYTES_PER_LINE defined in line 1402; used 3 times
FD_NEXT defined in line 571; used 2 times
  • in line 573(2)
HELPINDENT defined in line 116; used 1 times
IBUFSIZ defined in line 56; used 4 times
SB_ACCUM defined in line 731; used 3 times
Sb_Command defined in line 64; used 1 times
Sb_Option defined in line 63; used 1 times
TELOPTS defined in line 38; never used
TS_DATA defined in line 722; used 7 times
TS_DO defined in line 726; used 1 times
TS_DONT defined in line 727; used 1 times
TS_IAC defined in line 723; used 2 times
TS_SB defined in line 728; used 2 times
TS_SE defined in line 729; used 1 times
TS_WILL defined in line 724; used 1 times
TS_WONT defined in line 725; used 1 times
min defined in line 49; used 1 times
strip defined in line 48; used 1 times
Last modified: 1994-01-01
Generated: 2016-12-26
Generated by src2html V0.67
page hit count: 10254
Valid CSS Valid XHTML 1.0 Strict