Annotation of 40BSD/cmd/ucbmail/optim.c, revision 1.1.1.1

1.1       root        1: #
                      2: 
                      3: /*
                      4:  * Mail -- a program for sending and receiving mail.
                      5:  *
                      6:  * Network name modification routines.
                      7:  */
                      8: 
                      9: #include "rcv.h"
                     10: #include <ctype.h>
                     11: 
                     12: /*
                     13:  * Map a name into the correct network "view" of the
                     14:  * name.  This is done by prepending the name with the
                     15:  * network address of the sender, then optimizing away
                     16:  * nonsense.
                     17:  */
                     18: 
                     19: char   *metanet = "!^:%@.";
                     20: 
                     21: char *
                     22: netmap(name, from)
                     23:        char name[], from[];
                     24: {
                     25:        char nbuf[BUFSIZ], ret[BUFSIZ];
                     26:        register char *cp;
                     27: 
                     28:        if (strlen(from) == 0)
                     29:                return(name);
                     30:        if (any('@', name) || any('%', name))
                     31:                return(arpafix(name, from));
                     32:        cp = revarpa(from);
                     33:        if (cp == NOSTR)
                     34:                return(name);
                     35:        strcpy(nbuf, cp);
                     36:        cp = &nbuf[strlen(nbuf) - 1];
                     37:        while (!any(*cp, metanet) && cp > nbuf)
                     38:                cp--;
                     39:        if (cp == nbuf)
                     40:                return(name);
                     41:        *++cp = 0;
                     42:        strcat(nbuf, revarpa(name));
                     43:        optim(nbuf, ret);
                     44:        cp = revarpa(ret);
                     45:        if (!icequal(name, cp))
                     46:                return((char *) savestr(cp));
                     47:        return(name);
                     48: }
                     49: 
                     50: /*
                     51:  * Rename the given network path to use
                     52:  * the kinds of names that we would right here.
                     53:  */
                     54: 
                     55: char *
                     56: rename(str)
                     57:        char str[];
                     58: {
                     59:        register char *cp, *cp2;
                     60:        char buf[BUFSIZ], path[BUFSIZ];
                     61:        register int c, host;
                     62: 
                     63:        strcpy(path, "");
                     64:        for (;;) {
                     65:                if ((c = *cp++) == 0)
                     66:                        break;
                     67:                cp2 = buf;
                     68:                while (!any(c, metanet) && c != 0) {
                     69:                        *cp2++ = c;
                     70:                        c = *cp++;
                     71:                }
                     72:                *cp2 = 0;
                     73:                if (c == 0) {
                     74:                        strcat(path, buf);
                     75:                        break;
                     76:                }
                     77:                host = netlook(buf, ntype(c));
                     78:                strcat(path, netname(host));
                     79:                stradd(path, c);
                     80:        }
                     81:        if (strcmp(str, path) != 0)
                     82:                return(savestr(path));
                     83:        return(str);
                     84: }
                     85: /*
                     86:  * Turn a network machine name into a unique character
                     87:  * + give connection-to status.  BN -- connected to Bell Net.
                     88:  * AN -- connected to ARPA net, SN -- connected to Schmidt net.
                     89:  * CN -- connected to COCANET.
                     90:  */
                     91: 
                     92: #define        AN      1                       /* Connected to ARPA net */
                     93: #define        BN      2                       /* Connected to BTL net */
                     94: #define        CN      4                       /* Connected to COCANET */
                     95: #define        SN      8                       /* Connected to Schmidt net */
                     96: 
                     97: struct netmach {
                     98:        char    *nt_machine;
                     99:        char    nt_mid;
                    100:        short   nt_type;
                    101: } netmach[] = {
                    102:        "a",            'a',            SN,
                    103:        "b",            'b',            SN,
                    104:        "c",            'c',            SN,
                    105:        "d",            'd',            SN,
                    106:        "e",            'e',            SN,
                    107:        "f",            'f',            SN,
                    108:        "g",            'g',            SN,
                    109:        "ingres",       'i',            AN|SN,
                    110:        "ing70",        'i',            AN|SN,
                    111:        "berkeley",     'i',            AN|SN,
                    112:        "ingvax",       'j',            SN,
                    113:        "virus",        'k',            SN,
                    114:        "vlsi",         'l',            SN,
                    115:        "image",        'm',            SN,
                    116:        "esvax",        'o',            SN,
                    117:        "sesm",         'o',            SN,
                    118:        "q",            'q',            SN,
                    119:        "research",     'R',            BN,
                    120:        "arpavax",      'r',            SN,
                    121:        "src",          's',            SN,
                    122:        "mathstat",     't',            SN,
                    123:        "csvax",        'v',            BN|SN,
                    124:        "vax",          'v',            BN|SN,
                    125:        "ucb",          'v',            BN|SN,
                    126:        "ucbvax",       'v',            BN|SN,
                    127:        "vax135",       'x',            BN,
                    128:        "cory",         'y',            SN,
                    129:        "eecs40",       'z',            SN,
                    130:        0,              0,              0
                    131: };
                    132: 
                    133: netlook(machine, attnet)
                    134:        char machine[];
                    135: {
                    136:        register struct netmach *np;
                    137:        register char *cp, *cp2;
                    138:        char nbuf[20];
                    139: 
                    140:        /*
                    141:         * Make into lower case.
                    142:         */
                    143: 
                    144:        for (cp = machine, cp2 = nbuf; *cp; *cp2++ = little(*cp++))
                    145:                ;
                    146:        *cp2 = 0;
                    147: 
                    148:        /*
                    149:         * If a single letter machine, look through those first.
                    150:         */
                    151: 
                    152:        if (strlen(nbuf) == 1)
                    153:                for (np = netmach; np->nt_mid != 0; np++)
                    154:                        if (np->nt_mid == nbuf[0])
                    155:                                return(nbuf[0]);
                    156: 
                    157:        /*
                    158:         * Look for usual name
                    159:         */
                    160: 
                    161:        for (np = netmach; np->nt_mid != 0; np++)
                    162:                if (strcmp(np->nt_machine, nbuf) == 0)
                    163:                        return(np->nt_mid);
                    164: 
                    165:        /*
                    166:         * Look in side hash table.
                    167:         */
                    168: 
                    169:        return(mstash(nbuf, attnet));
                    170: }
                    171: 
                    172: /*
                    173:  * Make a little character.
                    174:  */
                    175: 
                    176: little(c)
                    177:        register int c;
                    178: {
                    179: 
                    180:        if (c >= 'A' && c <= 'Z')
                    181:                c += 'a' - 'A';
                    182:        return(c);
                    183: }
                    184: 
                    185: /*
                    186:  * Turn a network unique character identifier into a network name.
                    187:  */
                    188: 
                    189: char *
                    190: netname(mid)
                    191: {
                    192:        register struct netmach *np;
                    193:        char *mlook();
                    194: 
                    195:        if (mid & 0200)
                    196:                return(mlook(mid));
                    197:        for (np = netmach; np->nt_mid != 0; np++)
                    198:                if (np->nt_mid == mid)
                    199:                        return(np->nt_machine);
                    200:        return(NOSTR);
                    201: }
                    202: 
                    203: /*
                    204:  * Deal with arpa net addresses.  The way this is done is strange.
                    205:  * In particular, if the destination arpa net host is not Berkeley,
                    206:  * then the address is correct as stands.  Otherwise, we strip off
                    207:  * the trailing @Berkeley, then cook up a phony person for it to
                    208:  * be from and optimize the result.
                    209:  */
                    210: char *
                    211: arpafix(name, from)
                    212:        char name[];
                    213:        char from[];
                    214: {
                    215:        register char *cp;
                    216:        register int arpamach;
                    217:        char newname[BUFSIZ];
                    218:        char fake[5];
                    219:        char fakepath[20];
                    220: 
                    221:        if (debug) {
                    222:                fprintf(stderr, "arpafix(%s, %s)\n", name, from);
                    223:        }
                    224:        cp = rindex(name, '@');
                    225:        if (cp == NOSTR)
                    226:                cp = rindex(name, '%');
                    227:        if (cp == NOSTR) {
                    228:                fprintf(stderr, "Somethings amiss -- no @ or % in arpafix\n");
                    229:                return(name);
                    230:        }
                    231:        cp++;
                    232:        arpamach = netlook(cp, '@');
                    233:        if (arpamach == 0) {
                    234:                if (debug)
                    235:                        fprintf(stderr, "machine %s unknown, uses: %s\n", cp, name);
                    236:                return(name);
                    237:        }
                    238:        if (((nettype(arpamach) & nettype(LOCAL)) & ~AN) == 0) {
                    239:                if (debug)
                    240:                        fprintf(stderr, "machine %s known but remote, uses: %s\n",
                    241:                            cp, name);
                    242:                return(name);
                    243:        }
                    244:        strcpy(newname, name);
                    245:        cp = rindex(newname, '@');
                    246:        if (cp == NOSTR)
                    247:                cp = rindex(newname, '%');
                    248:        *cp = 0;
                    249:        fake[0] = arpamach;
                    250:        fake[1] = ':';
                    251:        fake[2] = LOCAL;
                    252:        fake[3] = ':';
                    253:        fake[4] = 0;
                    254:        prefer(fake);
                    255:        strcpy(fakepath, netname(fake[0]));
                    256:        stradd(fakepath, fake[1]);
                    257:        strcat(fakepath, "daemon");
                    258:        if (debug)
                    259:                fprintf(stderr, "machine local, call netmap(%s, %s)\n",
                    260:                    newname, fakepath);
                    261:        return(netmap(newname, fakepath));
                    262: }
                    263: 
                    264: /*
                    265:  * Take a network machine descriptor and find the types of connected
                    266:  * nets and return it.
                    267:  */
                    268: 
                    269: nettype(mid)
                    270: {
                    271:        register struct netmach *np;
                    272: 
                    273:        if (mid & 0200)
                    274:                return(mtype(mid));
                    275:        for (np = netmach; np->nt_mid != 0; np++)
                    276:                if (np->nt_mid == mid)
                    277:                        return(np->nt_type);
                    278:        return(0);
                    279: }
                    280: 
                    281: /*
                    282:  * Hashing routines to salt away machines seen scanning
                    283:  * networks paths that we don't know about.
                    284:  */
                    285: 
                    286: #define        XHSIZE          19              /* Size of extra hash table */
                    287: #define        NXMID           (XHSIZE*3/4)    /* Max extra machines */
                    288: 
                    289: struct xtrahash {
                    290:        char    *xh_name;               /* Name of machine */
                    291:        short   xh_mid;                 /* Machine ID */
                    292:        short   xh_attnet;              /* Attached networks */
                    293: } xtrahash[XHSIZE];
                    294: 
                    295: struct xtrahash        *xtab[XHSIZE];          /* F: mid-->machine name */
                    296: 
                    297: short  midfree;                        /* Next free machine id */
                    298: 
                    299: /*
                    300:  * Initialize the extra host hash table.
                    301:  * Called by sreset.
                    302:  */
                    303: 
                    304: minit()
                    305: {
                    306:        register struct xtrahash *xp, **tp;
                    307:        register int i;
                    308: 
                    309:        midfree = 0;
                    310:        tp = &xtab[0];
                    311:        for (xp = &xtrahash[0]; xp < &xtrahash[XHSIZE]; xp++) {
                    312:                xp->xh_name = NOSTR;
                    313:                xp->xh_mid = 0;
                    314:                xp->xh_attnet = 0;
                    315:                *tp++ = (struct xtrahash *) 0;
                    316:        }
                    317: }
                    318: 
                    319: /*
                    320:  * Stash a net name in the extra host hash table.
                    321:  * If a new entry is put in the hash table, deduce what
                    322:  * net the machine is attached to from the net character.
                    323:  *
                    324:  * If the machine is already known, add the given attached
                    325:  * net to those already known.
                    326:  */
                    327: 
                    328: mstash(name, attnet)
                    329:        char name[];
                    330: {
                    331:        register struct xtrahash *xp;
                    332:        struct xtrahash *xlocate();
                    333: 
                    334:        xp = xlocate(name);
                    335:        if (xp == (struct xtrahash *) 0) {
                    336:                printf("Ran out of machine id spots\n");
                    337:                return(0);
                    338:        }
                    339:        if (xp->xh_name == NOSTR) {
                    340:                if (midfree >= XHSIZE) {
                    341:                        printf("Out of machine ids\n");
                    342:                        return(0);
                    343:                }
                    344:                xtab[midfree] = xp;
                    345:                xp->xh_name = savestr(name);
                    346:                xp->xh_mid = 0200 + midfree++;
                    347:        }
                    348:        switch (attnet) {
                    349:        case '!':
                    350:        case '^':
                    351:                xp->xh_attnet |= BN;
                    352:                break;
                    353: 
                    354:        default:
                    355:        case ':':
                    356:                xp->xh_attnet |= SN;
                    357:                break;
                    358: 
                    359:        case '@':
                    360:        case '%':
                    361:                xp->xh_attnet |= AN;
                    362:                break;
                    363:        }
                    364:        return(xp->xh_mid);
                    365: }
                    366: 
                    367: /*
                    368:  * Search for the given name in the hash table
                    369:  * and return the pointer to it if found, or to the first
                    370:  * empty slot if not found.
                    371:  *
                    372:  * If no free slots can be found, return 0.
                    373:  */
                    374: 
                    375: struct xtrahash *
                    376: xlocate(name)
                    377:        char name[];
                    378: {
                    379:        register int h, q, i;
                    380:        register char *cp;
                    381:        register struct xtrahash *xp;
                    382: 
                    383:        for (h = 0, cp = name; *cp; h = (h << 2) + *cp++)
                    384:                ;
                    385:        if (h < 0 && (h = -h) < 0)
                    386:                h = 0;
                    387:        h = h % XHSIZE;
                    388:        cp = name;
                    389:        for (i = 0, q = 0; q < XHSIZE; i++, q = i * i) {
                    390:                xp = &xtrahash[(h + q) % XHSIZE];
                    391:                if (xp->xh_name == NOSTR)
                    392:                        return(xp);
                    393:                if (strcmp(cp, xp->xh_name) == 0)
                    394:                        return(xp);
                    395:                if (h - q < 0)
                    396:                        q += XHSIZE;
                    397:                xp = &xtrahash[(h - q) % XHSIZE];
                    398:                if (xp->xh_name == NOSTR)
                    399:                        return(xp);
                    400:                if (strcmp(cp, xp->xh_name) == 0)
                    401:                        return(xp);
                    402:        }
                    403:        return((struct xtrahash *) 0);
                    404: }
                    405: 
                    406: /*
                    407:  * Return the name from the extra host hash table corresponding
                    408:  * to the passed machine id.
                    409:  */
                    410: 
                    411: char *
                    412: mlook(mid)
                    413: {
                    414:        register int m;
                    415: 
                    416:        if ((mid & 0200) == 0)
                    417:                return(NOSTR);
                    418:        m = mid & 0177;
                    419:        if (m >= midfree) {
                    420:                printf("Use made of undefined machine id\n");
                    421:                return(NOSTR);
                    422:        }
                    423:        return(xtab[m]->xh_name);
                    424: }
                    425: 
                    426: /*
                    427:  * Return the bit mask of net's that the given extra host machine
                    428:  * id has so far.
                    429:  */
                    430: 
                    431: mtype(mid)
                    432: {
                    433:        register int m;
                    434: 
                    435:        if ((mid & 0200) == 0)
                    436:                return(0);
                    437:        m = mid & 0177;
                    438:        if (m >= midfree) {
                    439:                printf("Use made of undefined machine id\n");
                    440:                return(0);
                    441:        }
                    442:        return(xtab[m]->xh_attnet);
                    443: }
                    444: 
                    445: /*
                    446:  * Take a network name and optimize it.  This gloriously messy
                    447:  * opertions takes place as follows:  the name with machine names
                    448:  * in it is tokenized by mapping each machine name into a single
                    449:  * character machine id (netlook).  The separator characters (network
                    450:  * metacharacters) are left intact.  The last component of the network
                    451:  * name is stripped off and assumed to be the destination user name --
                    452:  * it does not participate in the optimization.  As an example, the
                    453:  * name "research!vax135!research!ucbvax!bill" becomes, tokenized,
                    454:  * "r!x!r!v!" and "bill"  A low level routine, optim1, fixes up the
                    455:  * network part (eg, "r!x!r!v!"), then we convert back to network
                    456:  * machine names and tack the user name on the end.
                    457:  *
                    458:  * The result of this is copied into the parameter "name"
                    459:  */
                    460: 
                    461: optim(net, name)
                    462:        char net[], name[];
                    463: {
                    464:        char netcomp[BUFSIZ], netstr[40], xfstr[40];
                    465:        register char *cp, *cp2;
                    466:        register int c;
                    467: 
                    468:        strcpy(netstr, "");
                    469:        cp = net;
                    470:        for (;;) {
                    471:                /*
                    472:                 * Rip off next path component into netcomp
                    473:                 */
                    474:                cp2 = netcomp;
                    475:                while (*cp && !any(*cp, metanet))
                    476:                        *cp2++ = *cp++;
                    477:                *cp2 = 0;
                    478:                /*
                    479:                 * If we hit null byte, then we just scanned
                    480:                 * the destination user name.  Go off and optimize
                    481:                 * if its so.
                    482:                 */
                    483:                if (*cp == 0)
                    484:                        break;
                    485:                if ((c = netlook(netcomp, *cp)) == 0) {
                    486:                        printf("No host named \"%s\"\n", netcomp);
                    487: err:
                    488:                        strcpy(name, net);
                    489:                        return;
                    490:                }
                    491:                stradd(netstr, c);
                    492:                stradd(netstr, *cp++);
                    493:                /*
                    494:                 * If multiple network separators given,
                    495:                 * throw away the extras.
                    496:                 */
                    497:                while (any(*cp, metanet))
                    498:                        cp++;
                    499:        }
                    500:        if (strlen(netcomp) == 0) {
                    501:                printf("net name syntax\n");
                    502:                goto err;
                    503:        }
                    504:        optim1(netstr, xfstr);
                    505: 
                    506:        /*
                    507:         * Convert back to machine names.
                    508:         */
                    509: 
                    510:        cp = xfstr;
                    511:        strcpy(name, "");
                    512:        while (*cp) {
                    513:                if ((cp2 = netname(*cp++)) == NOSTR) {
                    514:                        printf("Made up bad net name\n");
                    515:                        goto err;
                    516:                }
                    517:                strcat(name, cp2);
                    518:                stradd(name, *cp++);
                    519:        }
                    520:        strcat(name, netcomp);
                    521: }
                    522: 
                    523: /*
                    524:  * Take a string of network machine id's and separators and
                    525:  * optimize them.  We process these by pulling off maximal
                    526:  * leading strings of the same type, passing these to the appropriate
                    527:  * optimizer and concatenating the results.
                    528:  */
                    529: 
                    530: #define        IMPLICIT        1
                    531: #define        EXPLICIT        2
                    532: 
                    533: optim1(netstr, name)
                    534:        char netstr[], name[];
                    535: {
                    536:        char path[40], rpath[40];
                    537:        register char *cp, *cp2;
                    538:        register int tp, nc;
                    539: 
                    540:        cp = netstr;
                    541:        prefer(cp);
                    542:        strcpy(name, "");
                    543:        while (*cp != 0) {
                    544:                strcpy(path, "");
                    545:                tp = ntype(cp[1]);
                    546:                nc = cp[1];
                    547:                while (*cp && tp == ntype(cp[1])) {
                    548:                        stradd(path, *cp++);
                    549:                        cp++;
                    550:                }
                    551:                switch (netkind(tp)) {
                    552:                default:
                    553:                        strcpy(rpath, path);
                    554:                        break;
                    555: 
                    556:                case IMPLICIT:
                    557:                        optimimp(path, rpath);
                    558:                        break;
                    559: 
                    560:                case EXPLICIT:
                    561:                        optimex(path, rpath);
                    562:                        break;
                    563:                }
                    564:                for (cp2 = rpath; *cp2 != 0; cp2++) {
                    565:                        stradd(name, *cp2);
                    566:                        stradd(name, nc);
                    567:                }
                    568:        }
                    569:        optiboth(name);
                    570:        prefer(name);
                    571: }
                    572: 
                    573: /*
                    574:  * Return the network of the separator --
                    575:  *     AN for arpa net
                    576:  *     BN for Bell labs net
                    577:  *     SN for Schmidt (berkeley net)
                    578:  *     0 if we don't know.
                    579:  */
                    580: 
                    581: ntype(nc)
                    582:        register int nc;
                    583: {
                    584: 
                    585:        switch (nc) {
                    586:        case '^':
                    587:        case '!':
                    588:                return(BN);
                    589: 
                    590:        case ':':
                    591:        case '.':
                    592:                return(SN);
                    593: 
                    594:        case '@':
                    595:        case '%':
                    596:                return(AN);
                    597: 
                    598:        default:
                    599:                return(0);
                    600:        }
                    601:        /* NOTREACHED */
                    602: }
                    603: 
                    604: /*
                    605:  * Return the kind of routing used for the particular net
                    606:  * EXPLICIT means explicitly routed
                    607:  * IMPLICIT means implicitly routed
                    608:  * 0 means don't know
                    609:  */
                    610: 
                    611: netkind(nt)
                    612:        register int nt;
                    613: {
                    614: 
                    615:        switch (nt) {
                    616:        case BN:
                    617:                return(EXPLICIT);
                    618: 
                    619:        case AN:
                    620:        case SN:
                    621:                return(IMPLICIT);
                    622: 
                    623:        default:
                    624:                return(0);
                    625:        }
                    626:        /* NOTREACHED */
                    627: }
                    628: 
                    629: /*
                    630:  * Do name optimization for an explicitly routed network (eg BTL network).
                    631:  */
                    632: 
                    633: optimex(net, name)
                    634:        char net[], name[];
                    635: {
                    636:        register char *cp, *rp;
                    637:        register int m;
                    638:        char *rindex();
                    639: 
                    640:        strcpy(name, net);
                    641:        cp = name;
                    642:        if (strlen(cp) == 0)
                    643:                return(-1);
                    644:        if (cp[strlen(cp)-1] == LOCAL) {
                    645:                name[0] = 0;
                    646:                return(0);
                    647:        }
                    648:        for (cp = name; *cp; cp++) {
                    649:                m = *cp;
                    650:                rp = rindex(cp+1, m);
                    651:                if (rp != NOSTR)
                    652:                        strcpy(cp, rp);
                    653:        }
                    654:        return(0);
                    655: }
                    656: 
                    657: /*
                    658:  * Do name optimization for implicitly routed network (eg, arpanet,
                    659:  * Berkeley network)
                    660:  */
                    661: 
                    662: optimimp(net, name)
                    663:        char net[], name[];
                    664: {
                    665:        register char *cp;
                    666:        register int m;
                    667: 
                    668:        cp = net;
                    669:        if (strlen(cp) == 0)
                    670:                return(-1);
                    671:        m = cp[strlen(cp) - 1];
                    672:        if (m == LOCAL) {
                    673:                strcpy(name, "");
                    674:                return(0);
                    675:        }
                    676:        name[0] = m;
                    677:        name[1] = 0;
                    678:        return(0);
                    679: }
                    680: 
                    681: /*
                    682: 
                    683:  * Perform global optimization on the given network path.
                    684:  * The trick here is to look ahead to see if there are any loops
                    685:  * in the path and remove them.  The interpretation of loops is
                    686:  * more strict here than in optimex since both the machine and net
                    687:  * type must match.
                    688:  */
                    689: 
                    690: optiboth(net)
                    691:        char net[];
                    692: {
                    693:        register char *cp, *cp2;
                    694:        char *rpair();
                    695: 
                    696:        cp = net;
                    697:        if (strlen(cp) == 0)
                    698:                return;
                    699:        if ((strlen(cp) % 2) != 0) {
                    700:                printf("Strange arg to optiboth\n");
                    701:                return;
                    702:        }
                    703:        while (*cp) {
                    704:                cp2 = rpair(cp+2, *cp);
                    705:                if (cp2 != NOSTR)
                    706:                        strcpy(cp, cp2);
                    707:                cp += 2;
                    708:        }
                    709: }
                    710: 
                    711: /*
                    712:  * Find the rightmost instance of the given (machine, type) pair.
                    713:  */
                    714: 
                    715: char *
                    716: rpair(str, mach)
                    717:        char str[];
                    718: {
                    719:        register char *cp, *last;
                    720: 
                    721:        last = NOSTR;
                    722:        while (*cp) {
                    723:                if (*cp == mach)
                    724:                        last = cp;
                    725:                cp += 2;
                    726:        }
                    727:        return(last);
                    728: }
                    729: 
                    730: /*
                    731:  * Change the network separators in the given network path
                    732:  * to the preferred network transmission means.
                    733:  */
                    734: 
                    735: prefer(name)
                    736:        char name[];
                    737: {
                    738:        register char *cp;
                    739:        register int state, n;
                    740: 
                    741:        state = LOCAL;
                    742:        for (cp = name; *cp; cp += 2) {
                    743:                n = best(state, *cp);
                    744:                if (n)
                    745:                        cp[1] = n;
                    746:                state = *cp;
                    747:        }
                    748: }
                    749: 
                    750: /*
                    751:  * Return the best network separator for the given machine pair.
                    752:  */
                    753: 
                    754: struct netorder {
                    755:        short   no_stat;
                    756:        char    no_char;
                    757: } netorder[] = {
                    758:        CN,     ':',
                    759:        AN,     '@',
                    760:        AN,     '%',
                    761:        SN,     ':',
                    762:        BN,     '!',
                    763:        -1,     0
                    764: };
                    765: 
                    766: best(src, dest)
                    767: {
                    768:        register int dtype, stype;
                    769:        register struct netorder *np;
                    770: 
                    771:        stype = nettype(src);
                    772:        dtype = nettype(dest);
                    773:        if (stype == 0 || dtype == 0) {
                    774:                printf("ERROR:  unknown internal machine id\n");
                    775:                return(0);
                    776:        }
                    777:        if ((stype & dtype) == 0) {
                    778: #ifdef DELIVERMAIL
                    779:                if (src != LOCAL)
                    780: #endif
                    781:                        printf("No way to get from \"%s\" to \"%s\"\n", 
                    782:                            netname(src), netname(dest));
                    783:                return(0);
                    784:        }
                    785:        np = &netorder[0];
                    786:        while ((np->no_stat & stype & dtype) == 0)
                    787:                np++;
                    788:        return(np->no_char);
                    789: }
                    790: 
                    791: /*
                    792:  * Code to twist around arpa net names.
                    793:  */
                    794: 
                    795: #define WORD 257                       /* Token for a string */
                    796: 
                    797: static char netbuf[256];
                    798: static char *yylval;
                    799: 
                    800: /*
                    801:  * Reverse all of the arpa net addresses in the given name to
                    802:  * be of the form "host @ user" instead of "user @ host"
                    803:  * This function is its own inverse.
                    804:  */
                    805: 
                    806: char *
                    807: revarpa(str)
                    808:        char str[];
                    809: {
                    810: 
                    811:        if (yyinit(str) < 0)
                    812:                return(NOSTR);
                    813:        if (name())
                    814:                return(NOSTR);
                    815:        if (strcmp(str, netbuf) == 0)
                    816:                return(str);
                    817:        return(savestr(netbuf));
                    818: }
                    819: 
                    820: /*
                    821:  * Parse (by recursive descent) network names, using the following grammar:
                    822:  *     name:
                    823:  *             term {':' term}
                    824:  *             term {'^' term}
                    825:  *             term {'!' term}
                    826:  *             term '@' name
                    827:  *             term '%' name
                    828:  *
                    829:  *     term:
                    830:  *             string of characters.
                    831:  */
                    832: 
                    833: name()
                    834: {
                    835:        register int t;
                    836:        register char *cp;
                    837: 
                    838:        for (;;) {
                    839:                t = yylex();
                    840:                if (t != WORD)
                    841:                        return(-1);
                    842:                cp = yylval;
                    843:                t = yylex();
                    844:                switch (t) {
                    845:                case 0:
                    846:                        strcat(netbuf, cp);
                    847:                        return(0);
                    848: 
                    849:                case '@':
                    850:                case '%':
                    851:                        if (name())
                    852:                                return(-1);
                    853:                        stradd(netbuf, '@');
                    854:                        strcat(netbuf, cp);
                    855:                        return(0);
                    856: 
                    857:                case WORD:
                    858:                        return(-1);
                    859: 
                    860:                default:
                    861:                        strcat(netbuf, cp);
                    862:                        stradd(netbuf, t);
                    863:                }
                    864:        }
                    865: }
                    866: 
                    867: /*
                    868:  * Scanner for network names.
                    869:  */
                    870: 
                    871: static char *charp;                    /* Current input pointer */
                    872: static int nexttok;                    /* Salted away next token */
                    873: 
                    874: /*
                    875:  * Initialize the network name scanner.
                    876:  */
                    877: 
                    878: yyinit(str)
                    879:        char str[];
                    880: {
                    881:        static char lexbuf[BUFSIZ];
                    882: 
                    883:        netbuf[0] = 0;
                    884:        if (strlen(str) >= sizeof lexbuf - 1)
                    885:                return(-1);
                    886:        nexttok = 0;
                    887:        strcpy(lexbuf, str);
                    888:        charp = lexbuf;
                    889:        return(0);
                    890: }
                    891: 
                    892: /*
                    893:  * Scan and return a single token.
                    894:  * yylval is set to point to a scanned string.
                    895:  */
                    896: 
                    897: yylex()
                    898: {
                    899:        register char *cp, *dot;
                    900:        register int s;
                    901: 
                    902:        if (nexttok) {
                    903:                s = nexttok;
                    904:                nexttok = 0;
                    905:                return(s);
                    906:        }
                    907:        cp = charp;
                    908:        while (*cp && isspace(*cp))
                    909:                cp++;
                    910:        if (*cp == 0)
                    911:                return(0);
                    912:        if (any(*cp, "!^@:%")) {
                    913:                charp = cp+1;
                    914:                return(*cp);
                    915:        }
                    916:        dot = cp;
                    917:        while (*cp && !any(*cp, " \t!^@:%"))
                    918:                cp++;
                    919:        if (any(*cp, "!^@:%"))
                    920:                nexttok = *cp;
                    921:        if (*cp == 0)
                    922:                charp = cp;
                    923:        else
                    924:                charp = cp+1;
                    925:        *cp = 0;
                    926:        yylval = dot;
                    927:        return(WORD);
                    928: }
                    929: 
                    930: /*
                    931:  * Add a single character onto a string.
                    932:  */
                    933: 
                    934: stradd(str, c)
                    935:        register char *str;
                    936:        register int c;
                    937: {
                    938: 
                    939:        str += strlen(str);
                    940:        *str++ = c;
                    941:        *str = 0;
                    942: }

unix.superglobalmegacorp.com

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