Annotation of 43BSD/ucb/telnet.c, revision 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.