Annotation of 3BSD/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: 
                     11: /*
                     12:  * Map a name into the correct network "view" of the
                     13:  * name.  This is done by prepending the name with the
                     14:  * network address of the sender, then optimizing away
                     15:  * nonsense.
                     16:  */
                     17: 
                     18: char   *metanet = "!^:@";
                     19: 
                     20: char *
                     21: netmap(name, from)
                     22:        char name[], from[];
                     23: {
                     24:        char nbuf[BUFSIZ], ret[BUFSIZ];
                     25:        register char *cp;
                     26: 
                     27:        strcpy(nbuf, from);
                     28:        if (strlen(nbuf) == 0)
                     29:                return(name);
                     30:        cp = &nbuf[strlen(nbuf) - 1];
                     31:        while (!any(*cp, metanet) && cp > nbuf)
                     32:                cp--;
                     33:        if (cp == nbuf)
                     34:                return(name);
                     35:        *++cp = 0;
                     36:        strcat(nbuf, name);
                     37:        optim(nbuf, ret);
                     38:        if (!equal(name, ret))
                     39:                return((char *) savestr(ret));
                     40:        return(name);
                     41: }
                     42: 
                     43: /*
                     44:  * Turn a network machine name into a unique character
                     45:  * + give connection-to status.  BN -- connected to Bell Net.
                     46:  * AN -- connected to ARPA net, SN -- connected to Schmidt net.
                     47:  * CN -- connected to COCANET.
                     48:  */
                     49: 
                     50: #define        AN      1                       /* Connected to ARPA net */
                     51: #define        BN      2                       /* Connected to BTL net */
                     52: #define        CN      4                       /* Connected to COCANET */
                     53: #define        SN      8                       /* Connected to Schmidt net */
                     54: 
                     55: struct netmach {
                     56:        char    *nt_machine;
                     57:        char    nt_mid;
                     58:        short   nt_type;
                     59: } netmach[] = {
                     60:        "a",            'a',            SN,
                     61:        "b",            'b',            SN,
                     62:        "c",            'c',            SN,
                     63:        "d",            'd',            SN,
                     64:        "e",            'e',            SN,
                     65:        "f",            'f',            SN,
                     66:        "ccvax",        'f',            SN,
                     67:        "ingres",       'i',            AN|SN,
                     68:        "ing70",        'i',            AN|SN,
                     69:        "ingvax",       'j',            SN,
                     70:        "image",        'm',            SN,
                     71:        "optvax",       'o',            SN,
                     72:        "sesm",         'o',            SN,
                     73:        "q",            'q',            SN,
                     74:        "research",     'r',            BN,
                     75:        "src",          's',            SN,
                     76:        "vax",          'v',            BN|SN,
                     77:        "csvax",        'v',            BN|SN,
                     78:        "ucbvax",       'v',            BN|SN,
                     79:        "vax135",       'x',            BN,
                     80:        "cory",         'y',            SN,
                     81:        "eecs40",       'z',            SN,
                     82:        0,              0,              0
                     83: };
                     84: 
                     85: netlook(machine, attnet)
                     86:        char machine[];
                     87: {
                     88:        register struct netmach *np;
                     89:        register char *cp, *cp2;
                     90:        char nbuf[20];
                     91: 
                     92:        /*
                     93:         * Make into lower case.
                     94:         */
                     95: 
                     96:        for (cp = machine, cp2 = nbuf; *cp; *cp2++ = little(*cp++))
                     97:                ;
                     98:        *cp2 = 0;
                     99: 
                    100:        /*
                    101:         * If a single letter machine, look through those first.
                    102:         */
                    103: 
                    104:        if (strlen(nbuf) == 1)
                    105:                for (np = netmach; np->nt_mid != 0; np++)
                    106:                        if (np->nt_mid == nbuf[0])
                    107:                                return(nbuf[0]);
                    108: 
                    109:        /*
                    110:         * Look for usual name
                    111:         */
                    112: 
                    113:        for (np = netmach; np->nt_mid != 0; np++)
                    114:                if (strcmp(np->nt_machine, nbuf) == 0)
                    115:                        return(np->nt_mid);
                    116: 
                    117:        /*
                    118:         * Look in side hash table.
                    119:         */
                    120: 
                    121:        return(mstash(nbuf, attnet));
                    122: }
                    123: 
                    124: /*
                    125:  * Make a little character.
                    126:  */
                    127: 
                    128: little(c)
                    129:        register int c;
                    130: {
                    131: 
                    132:        if (c >= 'A' && c <= 'Z')
                    133:                c += 'a' - 'A';
                    134:        return(c);
                    135: }
                    136: 
                    137: /*
                    138:  * Turn a network unique character identifier into a network name.
                    139:  */
                    140: 
                    141: char *
                    142: netname(mid)
                    143: {
                    144:        register struct netmach *np;
                    145:        char *mlook();
                    146: 
                    147:        if (mid & 0200)
                    148:                return(mlook(mid));
                    149:        for (np = netmach; np->nt_mid != 0; np++)
                    150:                if (np->nt_mid == mid)
                    151:                        return(np->nt_machine);
                    152:        return(NOSTR);
                    153: }
                    154: 
                    155: /*
                    156:  * Take a network machine descriptor and find the types of connected
                    157:  * nets and return it.
                    158:  */
                    159: 
                    160: nettype(mid)
                    161: {
                    162:        register struct netmach *np;
                    163: 
                    164:        if (mid & 0200)
                    165:                return(mtype(mid));
                    166:        for (np = netmach; np->nt_mid != 0; np++)
                    167:                if (np->nt_mid == mid)
                    168:                        return(np->nt_type);
                    169:        return(0);
                    170: }
                    171: 
                    172: /*
                    173:  * Hashing routines to salt away machines seen scanning
                    174:  * networks paths that we don't know about.
                    175:  */
                    176: 
                    177: #define        XHSIZE          19              /* Size of extra hash table */
                    178: #define        NXMID           (XHSIZE*3/4)    /* Max extra machines */
                    179: 
                    180: struct xtrahash {
                    181:        char    *xh_name;               /* Name of machine */
                    182:        short   xh_mid;                 /* Machine ID */
                    183:        short   xh_attnet;              /* Attached networks */
                    184: } xtrahash[XHSIZE];
                    185: 
                    186: struct xtrahash        *xtab[XHSIZE];          /* F: mid-->machine name */
                    187: 
                    188: short  midfree;                        /* Next free machine id */
                    189: 
                    190: /*
                    191:  * Initialize the extra host hash table.
                    192:  * Called by sreset.
                    193:  */
                    194: 
                    195: minit()
                    196: {
                    197:        register struct xtrahash *xp, **tp;
                    198:        register int i;
                    199: 
                    200:        midfree = 0;
                    201:        tp = &xtab[0];
                    202:        for (xp = &xtrahash[0]; xp < &xtrahash[XHSIZE]; xp++) {
                    203:                xp->xh_name = NOSTR;
                    204:                xp->xh_mid = 0;
                    205:                xp->xh_attnet = 0;
                    206:                *tp++ = (struct xtrahash *) 0;
                    207:        }
                    208: }
                    209: 
                    210: /*
                    211:  * Stash a net name in the extra host hash table.
                    212:  * If a new entry is put in the hash table, deduce what
                    213:  * net the machine is attached to from the net character.
                    214:  *
                    215:  * If the machine is already known, add the given attached
                    216:  * net to those already known.
                    217:  */
                    218: 
                    219: mstash(name, attnet)
                    220:        char name[];
                    221: {
                    222:        register struct xtrahash *xp;
                    223:        struct xtrahash *xlocate();
                    224: 
                    225:        xp = xlocate(name);
                    226:        if (xp == (struct xtrahash *) 0) {
                    227:                printf("Ran out of machine id spots\n");
                    228:                return(0);
                    229:        }
                    230:        if (xp->xh_name == NOSTR) {
                    231:                if (midfree >= XHSIZE) {
                    232:                        printf("Out of machine ids\n");
                    233:                        return(0);
                    234:                }
                    235:                xtab[midfree] = xp;
                    236:                xp->xh_name = savestr(name);
                    237:                xp->xh_mid = 0200 + midfree++;
                    238:        }
                    239:        switch (attnet) {
                    240:        case '!':
                    241:        case '^':
                    242:                xp->xh_attnet |= BN;
                    243:                break;
                    244: 
                    245:        default:
                    246:        case ':':
                    247:                xp->xh_attnet |= SN;
                    248:                break;
                    249: 
                    250:        case '@':
                    251:                xp->xh_attnet |= AN;
                    252:                break;
                    253:        }
                    254:        return(xp->xh_mid);
                    255: }
                    256: 
                    257: /*
                    258:  * Search for the given name in the hash table
                    259:  * and return the pointer to it if found, or to the first
                    260:  * empty slot if not found.
                    261:  *
                    262:  * If no free slots can be found, return 0.
                    263:  */
                    264: 
                    265: struct xtrahash *
                    266: xlocate(name)
                    267:        char name[];
                    268: {
                    269:        register int h, q, i;
                    270:        register char *cp;
                    271:        register struct xtrahash *xp;
                    272: 
                    273:        for (h = 0, cp = name; *cp; h = (h << 2) + *cp++)
                    274:                ;
                    275:        if (h < 0 && (h = -h) < 0)
                    276:                h = 0;
                    277:        h = h % XHSIZE;
                    278:        cp = name;
                    279:        for (i = 0, q = 0; q < XHSIZE; i++, q = i * i) {
                    280:                xp = &xtrahash[(h + q) % XHSIZE];
                    281:                if (xp->xh_name == NOSTR)
                    282:                        return(xp);
                    283:                if (strcmp(cp, xp->xh_name) == 0)
                    284:                        return(xp);
                    285:                if (h - q < 0)
                    286:                        q += XHSIZE;
                    287:                xp = &xtrahash[(h - q) % XHSIZE];
                    288:                if (xp->xh_name == NOSTR)
                    289:                        return(xp);
                    290:                if (strcmp(cp, xp->xh_name) == 0)
                    291:                        return(xp);
                    292:        }
                    293:        return((struct xtrahash *) 0);
                    294: }
                    295: 
                    296: /*
                    297:  * Return the name from the extra host hash table corresponding
                    298:  * to the passed machine id.
                    299:  */
                    300: 
                    301: char *
                    302: mlook(mid)
                    303: {
                    304:        register int m;
                    305: 
                    306:        if ((mid & 0200) == 0)
                    307:                return(NOSTR);
                    308:        m = mid & 0177;
                    309:        if (m >= midfree) {
                    310:                printf("Use made of undefined machine id\n");
                    311:                return(NOSTR);
                    312:        }
                    313:        return(xtab[m]->xh_name);
                    314: }
                    315: 
                    316: /*
                    317:  * Return the bit mask of net's that the given extra host machine
                    318:  * id has so far.
                    319:  */
                    320: 
                    321: mtype(mid)
                    322: {
                    323:        register int m;
                    324: 
                    325:        if ((mid & 0200) == 0)
                    326:                return(0);
                    327:        m = mid & 0177;
                    328:        if (m >= midfree) {
                    329:                printf("Use made of undefined machine id\n");
                    330:                return(0);
                    331:        }
                    332:        return(xtab[m]->xh_attnet);
                    333: }
                    334: 
                    335: /*
                    336:  * Take a network name and optimize it.  This gloriously messy
                    337:  * opertions takes place as follows:  the name with machine names
                    338:  * in it is tokenized by mapping each machine name into a single
                    339:  * character machine id (netlook).  The separator characters (network
                    340:  * metacharacters) are left intact.  The last component of the network
                    341:  * name is stripped off and assumed to be the destination user name --
                    342:  * it does not participate in the optimization.  As an example, the
                    343:  * name "research!vax135!research!ucbvax!bill" becomes, tokenized,
                    344:  * "r!x!r!v!" and "bill"  A low level routine, optim1, fixes up the
                    345:  * network part (eg, "r!x!r!v!"), then we convert back to network
                    346:  * machine names and tack the user name on the end.
                    347:  *
                    348:  * The result of this is copied into the parameter "name"
                    349:  */
                    350: 
                    351: optim(net, name)
                    352:        char net[], name[];
                    353: {
                    354:        char netcomp[BUFSIZ], netstr[40], xfstr[40];
                    355:        register char *cp, *cp2;
                    356:        register int c;
                    357: 
                    358:        strcpy(netstr, "");
                    359:        cp = net;
                    360:        for (;;) {
                    361:                /*
                    362:                 * Rip off next path component into netcomp
                    363:                 */
                    364:                cp2 = netcomp;
                    365:                while (*cp && !any(*cp, metanet))
                    366:                        *cp2++ = *cp++;
                    367:                *cp2 = 0;
                    368:                /*
                    369:                 * If we hit null byte, then we just scanned
                    370:                 * the destination user name.  Go off and optimize
                    371:                 * if its so.
                    372:                 */
                    373:                if (*cp == 0)
                    374:                        break;
                    375:                if ((c = netlook(netcomp, *cp)) == 0) {
                    376:                        printf("No host named \"%s\"\n", netcomp);
                    377: err:
                    378:                        strcpy(name, net);
                    379:                        return;
                    380:                }
                    381:                stradd(netstr, c);
                    382:                stradd(netstr, *cp++);
                    383:                /*
                    384:                 * If multiple network separators given,
                    385:                 * throw away the extras.
                    386:                 */
                    387:                while (any(*cp, metanet))
                    388:                        cp++;
                    389:        }
                    390:        if (strlen(netcomp) == 0) {
                    391:                printf("net name syntax\n");
                    392:                goto err;
                    393:        }
                    394:        optim1(netstr, xfstr);
                    395: 
                    396:        /*
                    397:         * Convert back to machine names.
                    398:         */
                    399: 
                    400:        cp = xfstr;
                    401:        strcpy(name, "");
                    402:        while (*cp) {
                    403:                if ((cp2 = netname(*cp++)) == NOSTR) {
                    404:                        printf("Made up bad net name\n");
                    405:                        goto err;
                    406:                }
                    407:                strcat(name, cp2);
                    408:                stradd(name, *cp++);
                    409:        }
                    410:        strcat(name, netcomp);
                    411: }
                    412: 
                    413: /*
                    414:  * Take a string of network machine id's and separators and
                    415:  * optimize them.  We process these by pulling off maximal
                    416:  * leading strings of the same type, ppassing these to the appropriate
                    417:  * optimizer and concatenating the results.
                    418:  */
                    419: 
                    420: #define        IMPLICIT        1
                    421: #define        EXPLICIT        2
                    422: 
                    423: optim1(netstr, name)
                    424:        char netstr[], name[];
                    425: {
                    426:        char path[40], rpath[40];
                    427:        register char *cp, *cp2;
                    428:        register int tp, nc;
                    429: 
                    430:        cp = netstr;
                    431:        prefer(cp);
                    432:        strcpy(name, "");
                    433:        while (*cp != 0) {
                    434:                strcpy(path, "");
                    435:                tp = ntype(cp[1]);
                    436:                nc = cp[1];
                    437:                while (*cp && tp == ntype(cp[1])) {
                    438:                        stradd(path, *cp++);
                    439:                        cp++;
                    440:                }
                    441:                switch (tp) {
                    442:                default:
                    443:                        strcpy(rpath, path);
                    444:                        break;
                    445: 
                    446:                case IMPLICIT:
                    447:                        optimimp(path, rpath);
                    448:                        break;
                    449: 
                    450:                case EXPLICIT:
                    451:                        optimex(path, rpath);
                    452:                        break;
                    453:                }
                    454:                for (cp2 = rpath; *cp2 != 0; cp2++) {
                    455:                        stradd(name, *cp2);
                    456:                        stradd(name, nc);
                    457:                }
                    458:        }
                    459:        optiboth(name);
                    460:        prefer(name);
                    461: }
                    462: 
                    463: /*
                    464:  * Return the type of the separator --
                    465:  *     IMPLICIT -- if for a smart, implicitly routed network
                    466:  *     EXPLICIT -- if for a dumb, explicitly routed neetwork.
                    467:  *     0 if we don't know.
                    468:  */
                    469: 
                    470: ntype(nc)
                    471:        register int nc;
                    472: {
                    473: 
                    474:        switch (nc) {
                    475:        case '^':
                    476:        case '!':
                    477:                return(EXPLICIT);
                    478: 
                    479:        case ':':
                    480:                return(IMPLICIT);
                    481: 
                    482:        default:
                    483:                return(0);
                    484:        }
                    485:        /* NOTREACHED */
                    486: }
                    487:                
                    488: /*
                    489:  * Do name optimization for an explicitly routed network (eg BTL network).
                    490:  */
                    491: 
                    492: optimex(net, name)
                    493:        char net[], name[];
                    494: {
                    495:        register char *cp, *rp;
                    496:        register int m;
                    497:        char *rindex();
                    498: 
                    499:        strcpy(name, net);
                    500:        cp = name;
                    501:        if (strlen(cp) == 0)
                    502:                return(-1);
                    503:        if (cp[strlen(cp)-1] == LOCAL) {
                    504:                name[0] = 0;
                    505:                return(0);
                    506:        }
                    507:        for (cp = name; *cp; cp++) {
                    508:                m = *cp;
                    509:                rp = rindex(cp+1, m);
                    510:                if (rp != NOSTR)
                    511:                        strcpy(cp, rp);
                    512:        }
                    513:        return(0);
                    514: }
                    515: 
                    516: /*
                    517:  * Do name optimization for implicitly routed network (eg, arpanet,
                    518:  * Berkeley network)
                    519:  */
                    520: 
                    521: optimimp(net, name)
                    522:        char net[], name[];
                    523: {
                    524:        register char *cp;
                    525:        register int m;
                    526: 
                    527:        cp = net;
                    528:        if (strlen(cp) == 0)
                    529:                return(-1);
                    530:        m = cp[strlen(cp) - 1];
                    531:        if (m == LOCAL) {
                    532:                strcpy(name, "");
                    533:                return(0);
                    534:        }
                    535:        name[0] = m;
                    536:        name[1] = 0;
                    537:        return(0);
                    538: }
                    539: 
                    540: /*
                    541: 
                    542:  * Perform global optimization on the given network path.
                    543:  * The trick here is to look ahead to see if there are any loops
                    544:  * in the path and remove them.  The interpretation of loops is
                    545:  * more strict here than in optimex since both the machine and net
                    546:  * type must match.
                    547:  */
                    548: 
                    549: optiboth(net)
                    550:        char net[];
                    551: {
                    552:        register char *cp, *cp2;
                    553:        char *rpair();
                    554: 
                    555:        cp = net;
                    556:        if (strlen(cp) == 0)
                    557:                return;
                    558:        if ((strlen(cp) % 2) != 0) {
                    559:                printf("Strange arg to optiboth\n");
                    560:                return;
                    561:        }
                    562:        while (*cp) {
                    563:                cp2 = rpair(cp+2, *cp, ntype(cp[1]));
                    564:                if (cp2 != NOSTR)
                    565:                        strcpy(cp, cp2);
                    566:                cp += 2;
                    567:        }
                    568: }
                    569: 
                    570: /*
                    571:  * Find the rightmost instance of the given (machine, type) pair.
                    572:  */
                    573: 
                    574: char *
                    575: rpair(str, mach, t)
                    576:        char str[];
                    577: {
                    578:        register char *cp, *last;
                    579: 
                    580:        last = NOSTR;
                    581:        while (*cp) {
                    582:                if (*cp == mach /* && ntype(cp[1]) == t */ )
                    583:                        last = cp;
                    584:                cp += 2;
                    585:        }
                    586:        return(last);
                    587: }
                    588: 
                    589: /*
                    590:  * Change the network separators in the given network path
                    591:  * to the preferred network transmission means.
                    592:  */
                    593: 
                    594: prefer(name)
                    595:        char name[];
                    596: {
                    597:        register char *cp;
                    598:        register int state, n;
                    599: 
                    600:        state = LOCAL;
                    601:        for (cp = name; *cp; cp += 2) {
                    602:                n = best(state, *cp);
                    603:                if (n)
                    604:                        cp[1] = n;
                    605:                state = *cp;
                    606:        }
                    607: }
                    608: 
                    609: /*
                    610:  * Return the best network separator for the given machine pair.
                    611:  */
                    612: 
                    613: struct netorder {
                    614:        short   no_stat;
                    615:        char    no_char;
                    616: } netorder[] = {
                    617:        CN,     ':',
                    618:        AN,     '@',
                    619:        SN,     ':',
                    620:        BN,     '!',
                    621:        -1,     0
                    622: };
                    623: 
                    624: best(src, dest)
                    625: {
                    626:        register int dtype, stype;
                    627:        register struct netorder *np;
                    628: 
                    629:        stype = nettype(src);
                    630:        dtype = nettype(dest);
                    631:        if (stype == 0 || dtype == 0) {
                    632:                printf("ERROR:  unknown internal machine id\n");
                    633:                return(0);
                    634:        }
                    635:        if ((stype & dtype) == 0) {
                    636:                printf("No way to get from \"%s\" to \"%s\"\n", 
                    637:                    netname(src), netname(dest));
                    638:                return(0);
                    639:        }
                    640:        np = &netorder[0];
                    641:        while ((np->no_stat & stype & dtype) == 0)
                    642:                np++;
                    643:        return(np->no_char);
                    644: }
                    645: 
                    646: /*
                    647:  * Add a single character onto a string.
                    648:  */
                    649: 
                    650: stradd(str, c)
                    651:        register char *str;
                    652:        register int c;
                    653: {
                    654: 
                    655:        str += strlen(str);
                    656:        *str++ = c;
                    657:        *str = 0;
                    658: }

unix.superglobalmegacorp.com

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