11242Skas # 21242Skas 31242Skas /* 41242Skas * Mail -- a program for sending and receiving mail. 51242Skas * 61242Skas * Network name modification routines. 71242Skas */ 81242Skas 91242Skas #include "rcv.h" 104337Skurt #include "configdefs.h" 111242Skas #include <ctype.h> 121242Skas 13*4342Skurt static char *SccsId = "@(#)optim.c 2.4 09/09/81"; 141242Skas 151242Skas /* 161242Skas * Map a name into the correct network "view" of the 171242Skas * name. This is done by prepending the name with the 181242Skas * network address of the sender, then optimizing away 191242Skas * nonsense. 201242Skas */ 211242Skas 221242Skas char * 231242Skas netmap(name, from) 241242Skas char name[], from[]; 251242Skas { 261242Skas char nbuf[BUFSIZ], ret[BUFSIZ]; 271242Skas register char *cp; 281242Skas 291242Skas if (strlen(from) == 0) 301242Skas return(name); 311242Skas if (any('@', name) || any('%', name)) 321242Skas return(arpafix(name, from)); 331242Skas cp = revarpa(from); 341242Skas if (cp == NOSTR) 351242Skas return(name); 361242Skas strcpy(nbuf, cp); 371242Skas cp = &nbuf[strlen(nbuf) - 1]; 381242Skas while (!any(*cp, metanet) && cp > nbuf) 391242Skas cp--; 401242Skas if (cp == nbuf) 411242Skas return(name); 421242Skas *++cp = 0; 431242Skas strcat(nbuf, revarpa(name)); 441242Skas optim(nbuf, ret); 451242Skas cp = revarpa(ret); 461242Skas if (!icequal(name, cp)) 471242Skas return((char *) savestr(cp)); 481242Skas return(name); 491242Skas } 501242Skas 511242Skas /* 521242Skas * Rename the given network path to use 531242Skas * the kinds of names that we would right here. 541242Skas */ 551242Skas 561242Skas char * 571242Skas rename(str) 581242Skas char str[]; 591242Skas { 601242Skas register char *cp, *cp2; 611242Skas char buf[BUFSIZ], path[BUFSIZ]; 621242Skas register int c, host; 631242Skas 641242Skas strcpy(path, ""); 651242Skas for (;;) { 661242Skas if ((c = *cp++) == 0) 671242Skas break; 681242Skas cp2 = buf; 691242Skas while (!any(c, metanet) && c != 0) { 701242Skas *cp2++ = c; 711242Skas c = *cp++; 721242Skas } 731242Skas *cp2 = 0; 741242Skas if (c == 0) { 751242Skas strcat(path, buf); 761242Skas break; 771242Skas } 781242Skas host = netlook(buf, ntype(c)); 791242Skas strcat(path, netname(host)); 801242Skas stradd(path, c); 811242Skas } 821242Skas if (strcmp(str, path) != 0) 831242Skas return(savestr(path)); 841242Skas return(str); 851242Skas } 864337Skurt 871242Skas /* 881242Skas * Turn a network machine name into a unique character 891242Skas */ 901242Skas netlook(machine, attnet) 911242Skas char machine[]; 921242Skas { 931242Skas register struct netmach *np; 941242Skas register char *cp, *cp2; 951242Skas char nbuf[20]; 961242Skas 971242Skas /* 981242Skas * Make into lower case. 991242Skas */ 1001242Skas 1011242Skas for (cp = machine, cp2 = nbuf; *cp; *cp2++ = little(*cp++)) 1021242Skas ; 1031242Skas *cp2 = 0; 1041242Skas 1051242Skas /* 1061242Skas * If a single letter machine, look through those first. 1071242Skas */ 1081242Skas 1091242Skas if (strlen(nbuf) == 1) 1101242Skas for (np = netmach; np->nt_mid != 0; np++) 1111242Skas if (np->nt_mid == nbuf[0]) 1121242Skas return(nbuf[0]); 1131242Skas 1141242Skas /* 1151242Skas * Look for usual name 1161242Skas */ 1171242Skas 1181242Skas for (np = netmach; np->nt_mid != 0; np++) 1191242Skas if (strcmp(np->nt_machine, nbuf) == 0) 1201242Skas return(np->nt_mid); 1211242Skas 1221242Skas /* 1231242Skas * Look in side hash table. 1241242Skas */ 1251242Skas 1261242Skas return(mstash(nbuf, attnet)); 1271242Skas } 1281242Skas 1291242Skas /* 1301242Skas * Make a little character. 1311242Skas */ 1321242Skas 1331242Skas little(c) 1341242Skas register int c; 1351242Skas { 1361242Skas 1371242Skas if (c >= 'A' && c <= 'Z') 1381242Skas c += 'a' - 'A'; 1391242Skas return(c); 1401242Skas } 1411242Skas 1421242Skas /* 1431242Skas * Turn a network unique character identifier into a network name. 1441242Skas */ 1451242Skas 1461242Skas char * 1471242Skas netname(mid) 1481242Skas { 1491242Skas register struct netmach *np; 1501242Skas char *mlook(); 1511242Skas 1521242Skas if (mid & 0200) 1531242Skas return(mlook(mid)); 1541242Skas for (np = netmach; np->nt_mid != 0; np++) 1551242Skas if (np->nt_mid == mid) 1561242Skas return(np->nt_machine); 1571242Skas return(NOSTR); 1581242Skas } 1591242Skas 1601242Skas /* 1611242Skas * Deal with arpa net addresses. The way this is done is strange. 1621242Skas * In particular, if the destination arpa net host is not Berkeley, 1631242Skas * then the address is correct as stands. Otherwise, we strip off 1641242Skas * the trailing @Berkeley, then cook up a phony person for it to 1651242Skas * be from and optimize the result. 1661242Skas */ 1671242Skas char * 1681242Skas arpafix(name, from) 1691242Skas char name[]; 1701242Skas char from[]; 1711242Skas { 1721242Skas register char *cp; 1731242Skas register int arpamach; 1741242Skas char newname[BUFSIZ]; 1751242Skas char fake[5]; 1761242Skas char fakepath[20]; 1771242Skas 1781242Skas if (debug) { 1791242Skas fprintf(stderr, "arpafix(%s, %s)\n", name, from); 1801242Skas } 1811242Skas cp = rindex(name, '@'); 1821242Skas if (cp == NOSTR) 1831242Skas cp = rindex(name, '%'); 1841242Skas if (cp == NOSTR) { 1851242Skas fprintf(stderr, "Somethings amiss -- no @ or % in arpafix\n"); 1861242Skas return(name); 1871242Skas } 1881242Skas cp++; 1891242Skas arpamach = netlook(cp, '@'); 1901242Skas if (arpamach == 0) { 1911242Skas if (debug) 1921242Skas fprintf(stderr, "machine %s unknown, uses: %s\n", cp, name); 1931242Skas return(name); 1941242Skas } 1951242Skas if (((nettype(arpamach) & nettype(LOCAL)) & ~AN) == 0) { 1961242Skas if (debug) 1971242Skas fprintf(stderr, "machine %s known but remote, uses: %s\n", 1981242Skas cp, name); 1991242Skas return(name); 2001242Skas } 2011242Skas strcpy(newname, name); 2021242Skas cp = rindex(newname, '@'); 2031242Skas if (cp == NOSTR) 2041242Skas cp = rindex(newname, '%'); 2051242Skas *cp = 0; 2061242Skas fake[0] = arpamach; 2071242Skas fake[1] = ':'; 2081242Skas fake[2] = LOCAL; 2091242Skas fake[3] = ':'; 2101242Skas fake[4] = 0; 2111242Skas prefer(fake); 2121242Skas strcpy(fakepath, netname(fake[0])); 2131242Skas stradd(fakepath, fake[1]); 2141242Skas strcat(fakepath, "daemon"); 2151242Skas if (debug) 2161242Skas fprintf(stderr, "machine local, call netmap(%s, %s)\n", 2171242Skas newname, fakepath); 2181242Skas return(netmap(newname, fakepath)); 2191242Skas } 2201242Skas 2211242Skas /* 2221242Skas * Take a network machine descriptor and find the types of connected 2231242Skas * nets and return it. 2241242Skas */ 2251242Skas 2261242Skas nettype(mid) 2271242Skas { 2281242Skas register struct netmach *np; 2291242Skas 2301242Skas if (mid & 0200) 2311242Skas return(mtype(mid)); 2321242Skas for (np = netmach; np->nt_mid != 0; np++) 2331242Skas if (np->nt_mid == mid) 2341242Skas return(np->nt_type); 2351242Skas return(0); 2361242Skas } 2371242Skas 2381242Skas /* 2391242Skas * Hashing routines to salt away machines seen scanning 2401242Skas * networks paths that we don't know about. 2411242Skas */ 2421242Skas 2431242Skas #define XHSIZE 19 /* Size of extra hash table */ 2441242Skas #define NXMID (XHSIZE*3/4) /* Max extra machines */ 2451242Skas 2461242Skas struct xtrahash { 2471242Skas char *xh_name; /* Name of machine */ 2481242Skas short xh_mid; /* Machine ID */ 2491242Skas short xh_attnet; /* Attached networks */ 2501242Skas } xtrahash[XHSIZE]; 2511242Skas 2521242Skas struct xtrahash *xtab[XHSIZE]; /* F: mid-->machine name */ 2531242Skas 2541242Skas short midfree; /* Next free machine id */ 2551242Skas 2561242Skas /* 2571242Skas * Initialize the extra host hash table. 2581242Skas * Called by sreset. 2591242Skas */ 2601242Skas 2611242Skas minit() 2621242Skas { 2631242Skas register struct xtrahash *xp, **tp; 2641242Skas register int i; 2651242Skas 2661242Skas midfree = 0; 2671242Skas tp = &xtab[0]; 2681242Skas for (xp = &xtrahash[0]; xp < &xtrahash[XHSIZE]; xp++) { 2691242Skas xp->xh_name = NOSTR; 2701242Skas xp->xh_mid = 0; 2711242Skas xp->xh_attnet = 0; 2721242Skas *tp++ = (struct xtrahash *) 0; 2731242Skas } 2741242Skas } 2751242Skas 2761242Skas /* 2771242Skas * Stash a net name in the extra host hash table. 2781242Skas * If a new entry is put in the hash table, deduce what 2791242Skas * net the machine is attached to from the net character. 2801242Skas * 2811242Skas * If the machine is already known, add the given attached 2821242Skas * net to those already known. 2831242Skas */ 2841242Skas 2851242Skas mstash(name, attnet) 2861242Skas char name[]; 2871242Skas { 2881242Skas register struct xtrahash *xp; 2891242Skas struct xtrahash *xlocate(); 2904337Skurt int x; 2911242Skas 2921242Skas xp = xlocate(name); 2931242Skas if (xp == (struct xtrahash *) 0) { 2941242Skas printf("Ran out of machine id spots\n"); 2951242Skas return(0); 2961242Skas } 2971242Skas if (xp->xh_name == NOSTR) { 2981242Skas if (midfree >= XHSIZE) { 2991242Skas printf("Out of machine ids\n"); 3001242Skas return(0); 3011242Skas } 3021242Skas xtab[midfree] = xp; 3031242Skas xp->xh_name = savestr(name); 3041242Skas xp->xh_mid = 0200 + midfree++; 3051242Skas } 3064337Skurt x = ntype(attnet); 3074337Skurt if (x == 0) 3081242Skas xp->xh_attnet |= SN; 3094337Skurt else 3104337Skurt xp->xh_attnet |= x; 3111242Skas return(xp->xh_mid); 3121242Skas } 3131242Skas 3141242Skas /* 3151242Skas * Search for the given name in the hash table 3161242Skas * and return the pointer to it if found, or to the first 3171242Skas * empty slot if not found. 3181242Skas * 3191242Skas * If no free slots can be found, return 0. 3201242Skas */ 3211242Skas 3221242Skas struct xtrahash * 3231242Skas xlocate(name) 3241242Skas char name[]; 3251242Skas { 3261242Skas register int h, q, i; 3271242Skas register char *cp; 3281242Skas register struct xtrahash *xp; 3291242Skas 3301242Skas for (h = 0, cp = name; *cp; h = (h << 2) + *cp++) 3311242Skas ; 3321242Skas if (h < 0 && (h = -h) < 0) 3331242Skas h = 0; 3341242Skas h = h % XHSIZE; 3351242Skas cp = name; 3361242Skas for (i = 0, q = 0; q < XHSIZE; i++, q = i * i) { 3371242Skas xp = &xtrahash[(h + q) % XHSIZE]; 3381242Skas if (xp->xh_name == NOSTR) 3391242Skas return(xp); 3401242Skas if (strcmp(cp, xp->xh_name) == 0) 3411242Skas return(xp); 3421242Skas if (h - q < 0) 3431242Skas q += XHSIZE; 3441242Skas xp = &xtrahash[(h - q) % XHSIZE]; 3451242Skas if (xp->xh_name == NOSTR) 3461242Skas return(xp); 3471242Skas if (strcmp(cp, xp->xh_name) == 0) 3481242Skas return(xp); 3491242Skas } 3501242Skas return((struct xtrahash *) 0); 3511242Skas } 3521242Skas 3531242Skas /* 3541242Skas * Return the name from the extra host hash table corresponding 3551242Skas * to the passed machine id. 3561242Skas */ 3571242Skas 3581242Skas char * 3591242Skas mlook(mid) 3601242Skas { 3611242Skas register int m; 3621242Skas 3631242Skas if ((mid & 0200) == 0) 3641242Skas return(NOSTR); 3651242Skas m = mid & 0177; 3661242Skas if (m >= midfree) { 3671242Skas printf("Use made of undefined machine id\n"); 3681242Skas return(NOSTR); 3691242Skas } 3701242Skas return(xtab[m]->xh_name); 3711242Skas } 3721242Skas 3731242Skas /* 3741242Skas * Return the bit mask of net's that the given extra host machine 3751242Skas * id has so far. 3761242Skas */ 3771242Skas 3781242Skas mtype(mid) 3791242Skas { 3801242Skas register int m; 3811242Skas 3821242Skas if ((mid & 0200) == 0) 3831242Skas return(0); 3841242Skas m = mid & 0177; 3851242Skas if (m >= midfree) { 3861242Skas printf("Use made of undefined machine id\n"); 3871242Skas return(0); 3881242Skas } 3891242Skas return(xtab[m]->xh_attnet); 3901242Skas } 3911242Skas 3921242Skas /* 3931242Skas * Take a network name and optimize it. This gloriously messy 3943915Skurt * operation takes place as follows: the name with machine names 3951242Skas * in it is tokenized by mapping each machine name into a single 3961242Skas * character machine id (netlook). The separator characters (network 3971242Skas * metacharacters) are left intact. The last component of the network 3981242Skas * name is stripped off and assumed to be the destination user name -- 3991242Skas * it does not participate in the optimization. As an example, the 4001242Skas * name "research!vax135!research!ucbvax!bill" becomes, tokenized, 4011242Skas * "r!x!r!v!" and "bill" A low level routine, optim1, fixes up the 4021242Skas * network part (eg, "r!x!r!v!"), then we convert back to network 4031242Skas * machine names and tack the user name on the end. 4041242Skas * 4051242Skas * The result of this is copied into the parameter "name" 4061242Skas */ 4071242Skas 4081242Skas optim(net, name) 4091242Skas char net[], name[]; 4101242Skas { 4111242Skas char netcomp[BUFSIZ], netstr[40], xfstr[40]; 4121242Skas register char *cp, *cp2; 4131242Skas register int c; 4141242Skas 4151242Skas strcpy(netstr, ""); 4161242Skas cp = net; 4171242Skas for (;;) { 4181242Skas /* 4191242Skas * Rip off next path component into netcomp 4201242Skas */ 4211242Skas cp2 = netcomp; 4221242Skas while (*cp && !any(*cp, metanet)) 4231242Skas *cp2++ = *cp++; 4241242Skas *cp2 = 0; 4251242Skas /* 4261242Skas * If we hit null byte, then we just scanned 4271242Skas * the destination user name. Go off and optimize 4281242Skas * if its so. 4291242Skas */ 4301242Skas if (*cp == 0) 4311242Skas break; 4321242Skas if ((c = netlook(netcomp, *cp)) == 0) { 4331242Skas printf("No host named \"%s\"\n", netcomp); 4341242Skas err: 4351242Skas strcpy(name, net); 4361242Skas return; 4371242Skas } 4381242Skas stradd(netstr, c); 4391242Skas stradd(netstr, *cp++); 4401242Skas /* 4411242Skas * If multiple network separators given, 4421242Skas * throw away the extras. 4431242Skas */ 4441242Skas while (any(*cp, metanet)) 4451242Skas cp++; 4461242Skas } 4471242Skas if (strlen(netcomp) == 0) { 4481242Skas printf("net name syntax\n"); 4491242Skas goto err; 4501242Skas } 4511242Skas optim1(netstr, xfstr); 4521242Skas 4531242Skas /* 4541242Skas * Convert back to machine names. 4551242Skas */ 4561242Skas 4571242Skas cp = xfstr; 4581242Skas strcpy(name, ""); 4591242Skas while (*cp) { 4601242Skas if ((cp2 = netname(*cp++)) == NOSTR) { 4611242Skas printf("Made up bad net name\n"); 4624333Skurt printf("Machine code %c (0%o)\n", cp[-1], cp[-1]); 4634333Skurt printf("Sorry -- dumping now. Alert K. Shoens\n"); 4644333Skurt core(0); 4651242Skas goto err; 4661242Skas } 4671242Skas strcat(name, cp2); 4681242Skas stradd(name, *cp++); 4691242Skas } 4701242Skas strcat(name, netcomp); 4711242Skas } 4721242Skas 4731242Skas /* 4741242Skas * Take a string of network machine id's and separators and 4751242Skas * optimize them. We process these by pulling off maximal 4761242Skas * leading strings of the same type, passing these to the appropriate 4771242Skas * optimizer and concatenating the results. 4781242Skas */ 4791242Skas 4801242Skas optim1(netstr, name) 4811242Skas char netstr[], name[]; 4821242Skas { 4831242Skas char path[40], rpath[40]; 4841242Skas register char *cp, *cp2; 4851242Skas register int tp, nc; 4861242Skas 4871242Skas cp = netstr; 4881242Skas prefer(cp); 489*4342Skurt strcpy(name, ""); 4903915Skurt /* 4913915Skurt * If the address ultimately points back to us, 4923915Skurt * just return a null network path. 4933915Skurt */ 4943915Skurt if (strlen(cp) > 1 && cp[strlen(cp) - 2] == LOCAL) 4953915Skurt return; 4961242Skas while (*cp != 0) { 4971242Skas strcpy(path, ""); 4981242Skas tp = ntype(cp[1]); 4991242Skas nc = cp[1]; 5001242Skas while (*cp && tp == ntype(cp[1])) { 5011242Skas stradd(path, *cp++); 5021242Skas cp++; 5031242Skas } 5041242Skas switch (netkind(tp)) { 5051242Skas default: 5061242Skas strcpy(rpath, path); 5071242Skas break; 5081242Skas 5091242Skas case IMPLICIT: 5101242Skas optimimp(path, rpath); 5111242Skas break; 5121242Skas 5131242Skas case EXPLICIT: 5141242Skas optimex(path, rpath); 5151242Skas break; 5161242Skas } 5171242Skas for (cp2 = rpath; *cp2 != 0; cp2++) { 5181242Skas stradd(name, *cp2); 5191242Skas stradd(name, nc); 5201242Skas } 5211242Skas } 5221242Skas optiboth(name); 5231242Skas prefer(name); 5241242Skas } 5251242Skas 5261242Skas /* 5271242Skas * Return the network of the separator -- 5281242Skas * AN for arpa net 5291242Skas * BN for Bell labs net 5301242Skas * SN for Schmidt (berkeley net) 5311242Skas * 0 if we don't know. 5321242Skas */ 5331242Skas 5341242Skas ntype(nc) 5351242Skas register int nc; 5361242Skas { 5374337Skurt register struct nettypetab *np; 5381242Skas 5394337Skurt for (np = nettypetab; np->nt_char != 0; np++) 5404337Skurt if (np->nt_char == nc) 5414337Skurt return(np->nt_type); 5424337Skurt return(0); 5431242Skas } 5441242Skas 5451242Skas /* 5461242Skas * Return the kind of routing used for the particular net 5471242Skas * EXPLICIT means explicitly routed 5481242Skas * IMPLICIT means implicitly routed 5491242Skas * 0 means don't know 5501242Skas */ 5511242Skas 5521242Skas netkind(nt) 5531242Skas register int nt; 5541242Skas { 5554337Skurt register struct netkindtab *np; 5561242Skas 5574337Skurt for (np = netkindtab; np->nk_type != 0; np++) 5584337Skurt if (np->nk_type == nt) 5594337Skurt return(np->nk_kind); 5604337Skurt return(0); 5611242Skas } 5621242Skas 5631242Skas /* 5641242Skas * Do name optimization for an explicitly routed network (eg BTL network). 5651242Skas */ 5661242Skas 5671242Skas optimex(net, name) 5681242Skas char net[], name[]; 5691242Skas { 5701242Skas register char *cp, *rp; 5711242Skas register int m; 5721242Skas char *rindex(); 5731242Skas 5741242Skas strcpy(name, net); 5751242Skas cp = name; 5761242Skas if (strlen(cp) == 0) 5771242Skas return(-1); 5781242Skas if (cp[strlen(cp)-1] == LOCAL) { 5791242Skas name[0] = 0; 5801242Skas return(0); 5811242Skas } 5821242Skas for (cp = name; *cp; cp++) { 5831242Skas m = *cp; 5841242Skas rp = rindex(cp+1, m); 5851242Skas if (rp != NOSTR) 5861242Skas strcpy(cp, rp); 5871242Skas } 5881242Skas return(0); 5891242Skas } 5901242Skas 5911242Skas /* 5921242Skas * Do name optimization for implicitly routed network (eg, arpanet, 5931242Skas * Berkeley network) 5941242Skas */ 5951242Skas 5961242Skas optimimp(net, name) 5971242Skas char net[], name[]; 5981242Skas { 5991242Skas register char *cp; 6001242Skas register int m; 6011242Skas 6021242Skas cp = net; 6031242Skas if (strlen(cp) == 0) 6041242Skas return(-1); 6051242Skas m = cp[strlen(cp) - 1]; 6061242Skas if (m == LOCAL) { 6071242Skas strcpy(name, ""); 6081242Skas return(0); 6091242Skas } 6101242Skas name[0] = m; 6111242Skas name[1] = 0; 6121242Skas return(0); 6131242Skas } 6141242Skas 6151242Skas /* 6161242Skas * Perform global optimization on the given network path. 6171242Skas * The trick here is to look ahead to see if there are any loops 6181242Skas * in the path and remove them. The interpretation of loops is 6191242Skas * more strict here than in optimex since both the machine and net 6201242Skas * type must match. 6211242Skas */ 6221242Skas 6231242Skas optiboth(net) 6241242Skas char net[]; 6251242Skas { 6261242Skas register char *cp, *cp2; 6271242Skas char *rpair(); 6281242Skas 6291242Skas cp = net; 6301242Skas if (strlen(cp) == 0) 6311242Skas return; 6321242Skas if ((strlen(cp) % 2) != 0) { 6331242Skas printf("Strange arg to optiboth\n"); 6341242Skas return; 6351242Skas } 6361242Skas while (*cp) { 6371242Skas cp2 = rpair(cp+2, *cp); 6381242Skas if (cp2 != NOSTR) 6391242Skas strcpy(cp, cp2); 6401242Skas cp += 2; 6411242Skas } 6421242Skas } 6431242Skas 6441242Skas /* 6451242Skas * Find the rightmost instance of the given (machine, type) pair. 6461242Skas */ 6471242Skas 6481242Skas char * 6491242Skas rpair(str, mach) 6501242Skas char str[]; 6511242Skas { 6521242Skas register char *cp, *last; 6531242Skas 6541242Skas last = NOSTR; 6551242Skas while (*cp) { 6561242Skas if (*cp == mach) 6571242Skas last = cp; 6581242Skas cp += 2; 6591242Skas } 6601242Skas return(last); 6611242Skas } 6621242Skas 6631242Skas /* 6641242Skas * Change the network separators in the given network path 6651242Skas * to the preferred network transmission means. 6661242Skas */ 6671242Skas 6681242Skas prefer(name) 6691242Skas char name[]; 6701242Skas { 6711242Skas register char *cp; 6721242Skas register int state, n; 6731242Skas 6741242Skas state = LOCAL; 6751242Skas for (cp = name; *cp; cp += 2) { 6761242Skas n = best(state, *cp); 6771242Skas if (n) 6781242Skas cp[1] = n; 6791242Skas state = *cp; 6801242Skas } 6811242Skas } 6821242Skas 6831242Skas /* 6841242Skas * Return the best network separator for the given machine pair. 6851242Skas */ 6861242Skas 6871242Skas best(src, dest) 6881242Skas { 6891242Skas register int dtype, stype; 6901242Skas register struct netorder *np; 6911242Skas 6921242Skas stype = nettype(src); 6931242Skas dtype = nettype(dest); 6943915Skurt fflush(stdout); 6951242Skas if (stype == 0 || dtype == 0) { 6961242Skas printf("ERROR: unknown internal machine id\n"); 6971242Skas return(0); 6981242Skas } 6993915Skurt if ((stype & dtype) == 0) 7001242Skas return(0); 7011242Skas np = &netorder[0]; 7021242Skas while ((np->no_stat & stype & dtype) == 0) 7031242Skas np++; 7041242Skas return(np->no_char); 7051242Skas } 7061242Skas 7071242Skas /* 7081242Skas * Code to twist around arpa net names. 7091242Skas */ 7101242Skas 7111242Skas #define WORD 257 /* Token for a string */ 7121242Skas 7131242Skas static char netbuf[256]; 7141242Skas static char *yylval; 7151242Skas 7161242Skas /* 7171242Skas * Reverse all of the arpa net addresses in the given name to 7181242Skas * be of the form "host @ user" instead of "user @ host" 7191242Skas * This function is its own inverse. 7201242Skas */ 7211242Skas 7221242Skas char * 7231242Skas revarpa(str) 7241242Skas char str[]; 7251242Skas { 7261242Skas 7271242Skas if (yyinit(str) < 0) 7281242Skas return(NOSTR); 7291242Skas if (name()) 7301242Skas return(NOSTR); 7311242Skas if (strcmp(str, netbuf) == 0) 7321242Skas return(str); 7331242Skas return(savestr(netbuf)); 7341242Skas } 7351242Skas 7361242Skas /* 7371242Skas * Parse (by recursive descent) network names, using the following grammar: 7381242Skas * name: 7391242Skas * term {':' term} 7401242Skas * term {'^' term} 7411242Skas * term {'!' term} 7421242Skas * term '@' name 7431242Skas * term '%' name 7441242Skas * 7451242Skas * term: 7461242Skas * string of characters. 7471242Skas */ 7481242Skas 7491242Skas name() 7501242Skas { 7511242Skas register int t; 7521242Skas register char *cp; 7531242Skas 7541242Skas for (;;) { 7551242Skas t = yylex(); 7561242Skas if (t != WORD) 7571242Skas return(-1); 7581242Skas cp = yylval; 7591242Skas t = yylex(); 7601242Skas switch (t) { 7611242Skas case 0: 7621242Skas strcat(netbuf, cp); 7631242Skas return(0); 7641242Skas 7651242Skas case '@': 7661242Skas case '%': 7671242Skas if (name()) 7681242Skas return(-1); 7691242Skas stradd(netbuf, '@'); 7701242Skas strcat(netbuf, cp); 7711242Skas return(0); 7721242Skas 7731242Skas case WORD: 7741242Skas return(-1); 7751242Skas 7761242Skas default: 7771242Skas strcat(netbuf, cp); 7781242Skas stradd(netbuf, t); 7791242Skas } 7801242Skas } 7811242Skas } 7821242Skas 7831242Skas /* 7841242Skas * Scanner for network names. 7851242Skas */ 7861242Skas 7871242Skas static char *charp; /* Current input pointer */ 7881242Skas static int nexttok; /* Salted away next token */ 7891242Skas 7901242Skas /* 7911242Skas * Initialize the network name scanner. 7921242Skas */ 7931242Skas 7941242Skas yyinit(str) 7951242Skas char str[]; 7961242Skas { 7971242Skas static char lexbuf[BUFSIZ]; 7981242Skas 7991242Skas netbuf[0] = 0; 8001242Skas if (strlen(str) >= sizeof lexbuf - 1) 8011242Skas return(-1); 8021242Skas nexttok = 0; 8031242Skas strcpy(lexbuf, str); 8041242Skas charp = lexbuf; 8051242Skas return(0); 8061242Skas } 8071242Skas 8081242Skas /* 8091242Skas * Scan and return a single token. 8101242Skas * yylval is set to point to a scanned string. 8111242Skas */ 8121242Skas 8131242Skas yylex() 8141242Skas { 8151242Skas register char *cp, *dot; 8161242Skas register int s; 8171242Skas 8181242Skas if (nexttok) { 8191242Skas s = nexttok; 8201242Skas nexttok = 0; 8211242Skas return(s); 8221242Skas } 8231242Skas cp = charp; 8241242Skas while (*cp && isspace(*cp)) 8251242Skas cp++; 8261242Skas if (*cp == 0) 8271242Skas return(0); 8284337Skurt if (any(*cp, metanet)) { 8291242Skas charp = cp+1; 8301242Skas return(*cp); 8311242Skas } 8321242Skas dot = cp; 8334337Skurt while (*cp && !any(*cp, metanet) && !any(*cp, " \t")) 8341242Skas cp++; 8354337Skurt if (any(*cp, metanet)) 8361242Skas nexttok = *cp; 8371242Skas if (*cp == 0) 8381242Skas charp = cp; 8391242Skas else 8401242Skas charp = cp+1; 8411242Skas *cp = 0; 8421242Skas yylval = dot; 8431242Skas return(WORD); 8441242Skas } 8451242Skas 8461242Skas /* 8471242Skas * Add a single character onto a string. 8481242Skas */ 8491242Skas 8501242Skas stradd(str, c) 8511242Skas register char *str; 8521242Skas register int c; 8531242Skas { 8541242Skas 8551242Skas str += strlen(str); 8561242Skas *str++ = c; 8571242Skas *str = 0; 8581242Skas } 859