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