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