Annotation of 43BSD/ucb/telnet.c, revision 1.1.1.1

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

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.