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