122462Sdist /*
222462Sdist * Copyright (c) 1980 Regents of the University of California.
3*33499Sbostic * All rights reserved.
4*33499Sbostic *
5*33499Sbostic * Redistribution and use in source and binary forms are permitted
6*33499Sbostic * provided that this notice is preserved and that due credit is given
7*33499Sbostic * to the University of California at Berkeley. The name of the University
8*33499Sbostic * may not be used to endorse or promote products derived from this
9*33499Sbostic * software without specific prior written permission. This software
10*33499Sbostic * is provided ``as is'' without express or implied warranty.
1122462Sdist */
1222462Sdist
13*33499Sbostic #ifdef notdef
14*33499Sbostic static char sccsid[] = "@(#)optim.c 5.9 (Berkeley) 02/18/88";
15*33499Sbostic #endif /* notdef */
161242Skas
171242Skas /*
181242Skas * Mail -- a program for sending and receiving mail.
191242Skas *
201242Skas * Network name modification routines.
211242Skas */
221242Skas
231242Skas #include "rcv.h"
244337Skurt #include "configdefs.h"
251242Skas
261242Skas /*
271242Skas * Map a name into the correct network "view" of the
281242Skas * name. This is done by prepending the name with the
291242Skas * network address of the sender, then optimizing away
301242Skas * nonsense.
311242Skas */
321242Skas
331242Skas char *
netmap(name,from)341242Skas netmap(name, from)
351242Skas char name[], from[];
361242Skas {
371242Skas char nbuf[BUFSIZ], ret[BUFSIZ];
381242Skas register char *cp;
391242Skas
401242Skas if (strlen(from) == 0)
411242Skas return(name);
421242Skas if (any('@', name) || any('%', name))
4311387Sleres return(savestr(arpafix(name, from)));
441242Skas cp = revarpa(from);
451242Skas if (cp == NOSTR)
461242Skas return(name);
471242Skas strcpy(nbuf, cp);
481242Skas cp = &nbuf[strlen(nbuf) - 1];
491242Skas while (!any(*cp, metanet) && cp > nbuf)
501242Skas cp--;
511242Skas if (cp == nbuf)
521242Skas return(name);
531242Skas *++cp = 0;
5432272Sbostic if ((cp = revarpa(name)) != NOSTR)
5532272Sbostic strcat(nbuf, cp);
561242Skas optim(nbuf, ret);
571242Skas cp = revarpa(ret);
5832272Sbostic if (cp && !icequal(name, cp))
5911387Sleres return(savestr(cp));
601242Skas return(name);
611242Skas }
621242Skas
631242Skas /*
641242Skas * Turn a network machine name into a unique character
651242Skas */
netlook(machine,attnet)661242Skas netlook(machine, attnet)
671242Skas char machine[];
681242Skas {
691242Skas register struct netmach *np;
701242Skas register char *cp, *cp2;
7125374Sserge char nbuf[BUFSIZ];
721242Skas
731242Skas /*
741242Skas * Make into lower case.
751242Skas */
761242Skas
771242Skas for (cp = machine, cp2 = nbuf; *cp; *cp2++ = little(*cp++))
7816768Sralph if (cp2 >= &nbuf[sizeof(nbuf)-1])
7916768Sralph break;
801242Skas *cp2 = 0;
811242Skas
821242Skas /*
831242Skas * If a single letter machine, look through those first.
841242Skas */
851242Skas
861242Skas if (strlen(nbuf) == 1)
871242Skas for (np = netmach; np->nt_mid != 0; np++)
881242Skas if (np->nt_mid == nbuf[0])
891242Skas return(nbuf[0]);
901242Skas
911242Skas /*
921242Skas * Look for usual name
931242Skas */
941242Skas
951242Skas for (np = netmach; np->nt_mid != 0; np++)
961242Skas if (strcmp(np->nt_machine, nbuf) == 0)
971242Skas return(np->nt_mid);
981242Skas
991242Skas /*
1001242Skas * Look in side hash table.
1011242Skas */
1021242Skas
1031242Skas return(mstash(nbuf, attnet));
1041242Skas }
1051242Skas
1061242Skas /*
1071242Skas * Make a little character.
1081242Skas */
1091242Skas
little(c)1101242Skas little(c)
1111242Skas register int c;
1121242Skas {
1131242Skas
1141242Skas if (c >= 'A' && c <= 'Z')
1151242Skas c += 'a' - 'A';
1161242Skas return(c);
1171242Skas }
1181242Skas
1191242Skas /*
1201242Skas * Turn a network unique character identifier into a network name.
1211242Skas */
1221242Skas
1231242Skas char *
netname(mid)1241242Skas netname(mid)
1251242Skas {
1261242Skas register struct netmach *np;
1271242Skas char *mlook();
1281242Skas
1291242Skas if (mid & 0200)
1301242Skas return(mlook(mid));
1311242Skas for (np = netmach; np->nt_mid != 0; np++)
1321242Skas if (np->nt_mid == mid)
1331242Skas return(np->nt_machine);
1341242Skas return(NOSTR);
1351242Skas }
1361242Skas
1371242Skas /*
1381242Skas * Deal with arpa net addresses. The way this is done is strange.
1391242Skas * In particular, if the destination arpa net host is not Berkeley,
1401242Skas * then the address is correct as stands. Otherwise, we strip off
1411242Skas * the trailing @Berkeley, then cook up a phony person for it to
1421242Skas * be from and optimize the result.
1431242Skas */
1441242Skas char *
arpafix(name,from)1451242Skas arpafix(name, from)
1461242Skas char name[];
1471242Skas char from[];
1481242Skas {
1491242Skas register char *cp;
1501242Skas register int arpamach;
1511242Skas char newname[BUFSIZ];
1521242Skas char fake[5];
1531242Skas char fakepath[20];
1541242Skas
1551242Skas if (debug) {
1561242Skas fprintf(stderr, "arpafix(%s, %s)\n", name, from);
1571242Skas }
1581242Skas cp = rindex(name, '@');
1591242Skas if (cp == NOSTR)
1601242Skas cp = rindex(name, '%');
1611242Skas if (cp == NOSTR) {
16231142Sedward fprintf(stderr, "Somethings amiss -- no @ or %% in arpafix\n");
1631242Skas return(name);
1641242Skas }
1651242Skas cp++;
1661242Skas arpamach = netlook(cp, '@');
1671242Skas if (arpamach == 0) {
1681242Skas if (debug)
1691242Skas fprintf(stderr, "machine %s unknown, uses: %s\n", cp, name);
1701242Skas return(name);
1711242Skas }
1721242Skas if (((nettype(arpamach) & nettype(LOCAL)) & ~AN) == 0) {
1731242Skas if (debug)
1741242Skas fprintf(stderr, "machine %s known but remote, uses: %s\n",
1751242Skas cp, name);
1761242Skas return(name);
1771242Skas }
1781242Skas strcpy(newname, name);
1791242Skas cp = rindex(newname, '@');
1801242Skas if (cp == NOSTR)
1811242Skas cp = rindex(newname, '%');
1821242Skas *cp = 0;
1831242Skas fake[0] = arpamach;
1841242Skas fake[1] = ':';
1851242Skas fake[2] = LOCAL;
1861242Skas fake[3] = ':';
1871242Skas fake[4] = 0;
1881242Skas prefer(fake);
1891242Skas strcpy(fakepath, netname(fake[0]));
1901242Skas stradd(fakepath, fake[1]);
1911242Skas strcat(fakepath, "daemon");
1921242Skas if (debug)
1931242Skas fprintf(stderr, "machine local, call netmap(%s, %s)\n",
1941242Skas newname, fakepath);
1951242Skas return(netmap(newname, fakepath));
1961242Skas }
1971242Skas
1981242Skas /*
1991242Skas * Take a network machine descriptor and find the types of connected
2001242Skas * nets and return it.
2011242Skas */
2021242Skas
nettype(mid)2031242Skas nettype(mid)
2041242Skas {
2051242Skas register struct netmach *np;
2061242Skas
2071242Skas if (mid & 0200)
2081242Skas return(mtype(mid));
2091242Skas for (np = netmach; np->nt_mid != 0; np++)
2101242Skas if (np->nt_mid == mid)
2111242Skas return(np->nt_type);
2121242Skas return(0);
2131242Skas }
2141242Skas
2151242Skas /*
2161242Skas * Hashing routines to salt away machines seen scanning
2171242Skas * networks paths that we don't know about.
2181242Skas */
2191242Skas
2201242Skas #define XHSIZE 19 /* Size of extra hash table */
2211242Skas #define NXMID (XHSIZE*3/4) /* Max extra machines */
2221242Skas
2231242Skas struct xtrahash {
2241242Skas char *xh_name; /* Name of machine */
2251242Skas short xh_mid; /* Machine ID */
2261242Skas short xh_attnet; /* Attached networks */
2271242Skas } xtrahash[XHSIZE];
2281242Skas
2291242Skas struct xtrahash *xtab[XHSIZE]; /* F: mid-->machine name */
2301242Skas
2311242Skas short midfree; /* Next free machine id */
2321242Skas
2331242Skas /*
2341242Skas * Initialize the extra host hash table.
2351242Skas * Called by sreset.
2361242Skas */
2371242Skas
minit()2381242Skas minit()
2391242Skas {
2401242Skas register struct xtrahash *xp, **tp;
2411242Skas
2421242Skas midfree = 0;
2431242Skas tp = &xtab[0];
2441242Skas for (xp = &xtrahash[0]; xp < &xtrahash[XHSIZE]; xp++) {
2451242Skas xp->xh_name = NOSTR;
2461242Skas xp->xh_mid = 0;
2471242Skas xp->xh_attnet = 0;
2481242Skas *tp++ = (struct xtrahash *) 0;
2491242Skas }
2501242Skas }
2511242Skas
2521242Skas /*
2531242Skas * Stash a net name in the extra host hash table.
2541242Skas * If a new entry is put in the hash table, deduce what
2551242Skas * net the machine is attached to from the net character.
2561242Skas *
2571242Skas * If the machine is already known, add the given attached
2581242Skas * net to those already known.
2591242Skas */
2601242Skas
mstash(name,attnet)2611242Skas mstash(name, attnet)
2621242Skas char name[];
2631242Skas {
2641242Skas register struct xtrahash *xp;
2651242Skas struct xtrahash *xlocate();
2664337Skurt int x;
2671242Skas
2681242Skas xp = xlocate(name);
2691242Skas if (xp == (struct xtrahash *) 0) {
2701242Skas printf("Ran out of machine id spots\n");
2711242Skas return(0);
2721242Skas }
2731242Skas if (xp->xh_name == NOSTR) {
2741242Skas if (midfree >= XHSIZE) {
2751242Skas printf("Out of machine ids\n");
2761242Skas return(0);
2771242Skas }
2781242Skas xtab[midfree] = xp;
2791242Skas xp->xh_name = savestr(name);
2801242Skas xp->xh_mid = 0200 + midfree++;
2811242Skas }
2824337Skurt x = ntype(attnet);
2834337Skurt if (x == 0)
2841242Skas xp->xh_attnet |= SN;
2854337Skurt else
2864337Skurt xp->xh_attnet |= x;
2871242Skas return(xp->xh_mid);
2881242Skas }
2891242Skas
2901242Skas /*
2911242Skas * Search for the given name in the hash table
2921242Skas * and return the pointer to it if found, or to the first
2931242Skas * empty slot if not found.
2941242Skas *
2951242Skas * If no free slots can be found, return 0.
2961242Skas */
2971242Skas
2981242Skas struct xtrahash *
xlocate(name)2991242Skas xlocate(name)
3001242Skas char name[];
3011242Skas {
3021242Skas register int h, q, i;
3031242Skas register char *cp;
3041242Skas register struct xtrahash *xp;
3051242Skas
3061242Skas for (h = 0, cp = name; *cp; h = (h << 2) + *cp++)
3071242Skas ;
3081242Skas if (h < 0 && (h = -h) < 0)
3091242Skas h = 0;
3101242Skas h = h % XHSIZE;
3111242Skas cp = name;
3121242Skas for (i = 0, q = 0; q < XHSIZE; i++, q = i * i) {
3131242Skas xp = &xtrahash[(h + q) % XHSIZE];
3141242Skas if (xp->xh_name == NOSTR)
3151242Skas return(xp);
3161242Skas if (strcmp(cp, xp->xh_name) == 0)
3171242Skas return(xp);
3181242Skas if (h - q < 0)
31923466Slepreau h += XHSIZE;
3201242Skas xp = &xtrahash[(h - q) % XHSIZE];
3211242Skas if (xp->xh_name == NOSTR)
3221242Skas return(xp);
3231242Skas if (strcmp(cp, xp->xh_name) == 0)
3241242Skas return(xp);
3251242Skas }
3261242Skas return((struct xtrahash *) 0);
3271242Skas }
3281242Skas
3291242Skas /*
3301242Skas * Return the name from the extra host hash table corresponding
3311242Skas * to the passed machine id.
3321242Skas */
3331242Skas
3341242Skas char *
mlook(mid)3351242Skas mlook(mid)
3361242Skas {
3371242Skas register int m;
3381242Skas
3391242Skas if ((mid & 0200) == 0)
3401242Skas return(NOSTR);
3411242Skas m = mid & 0177;
3421242Skas if (m >= midfree) {
3431242Skas printf("Use made of undefined machine id\n");
3441242Skas return(NOSTR);
3451242Skas }
3461242Skas return(xtab[m]->xh_name);
3471242Skas }
3481242Skas
3491242Skas /*
3501242Skas * Return the bit mask of net's that the given extra host machine
3511242Skas * id has so far.
3521242Skas */
3531242Skas
mtype(mid)3541242Skas mtype(mid)
3551242Skas {
3561242Skas register int m;
3571242Skas
3581242Skas if ((mid & 0200) == 0)
3591242Skas return(0);
3601242Skas m = mid & 0177;
3611242Skas if (m >= midfree) {
3621242Skas printf("Use made of undefined machine id\n");
3631242Skas return(0);
3641242Skas }
3651242Skas return(xtab[m]->xh_attnet);
3661242Skas }
3671242Skas
3681242Skas /*
3691242Skas * Take a network name and optimize it. This gloriously messy
3703915Skurt * operation takes place as follows: the name with machine names
3711242Skas * in it is tokenized by mapping each machine name into a single
3721242Skas * character machine id (netlook). The separator characters (network
3731242Skas * metacharacters) are left intact. The last component of the network
3741242Skas * name is stripped off and assumed to be the destination user name --
3751242Skas * it does not participate in the optimization. As an example, the
3761242Skas * name "research!vax135!research!ucbvax!bill" becomes, tokenized,
3771242Skas * "r!x!r!v!" and "bill" A low level routine, optim1, fixes up the
3781242Skas * network part (eg, "r!x!r!v!"), then we convert back to network
3791242Skas * machine names and tack the user name on the end.
3801242Skas *
3811242Skas * The result of this is copied into the parameter "name"
3821242Skas */
3831242Skas
optim(net,name)3841242Skas optim(net, name)
3851242Skas char net[], name[];
3861242Skas {
3871242Skas char netcomp[BUFSIZ], netstr[40], xfstr[40];
3881242Skas register char *cp, *cp2;
3891242Skas register int c;
3901242Skas
3911242Skas strcpy(netstr, "");
3921242Skas cp = net;
3931242Skas for (;;) {
3941242Skas /*
3951242Skas * Rip off next path component into netcomp
3961242Skas */
3971242Skas cp2 = netcomp;
3981242Skas while (*cp && !any(*cp, metanet))
3991242Skas *cp2++ = *cp++;
4001242Skas *cp2 = 0;
4011242Skas /*
4021242Skas * If we hit null byte, then we just scanned
4031242Skas * the destination user name. Go off and optimize
4041242Skas * if its so.
4051242Skas */
4061242Skas if (*cp == 0)
4071242Skas break;
4081242Skas if ((c = netlook(netcomp, *cp)) == 0) {
4091242Skas printf("No host named \"%s\"\n", netcomp);
4101242Skas err:
4111242Skas strcpy(name, net);
4121242Skas return;
4131242Skas }
4141242Skas stradd(netstr, c);
4151242Skas stradd(netstr, *cp++);
4161242Skas /*
4171242Skas * If multiple network separators given,
4181242Skas * throw away the extras.
4191242Skas */
4201242Skas while (any(*cp, metanet))
4211242Skas cp++;
4221242Skas }
4231242Skas if (strlen(netcomp) == 0) {
4241242Skas printf("net name syntax\n");
4251242Skas goto err;
4261242Skas }
4271242Skas optim1(netstr, xfstr);
4281242Skas
4291242Skas /*
4301242Skas * Convert back to machine names.
4311242Skas */
4321242Skas
4331242Skas cp = xfstr;
4341242Skas strcpy(name, "");
4351242Skas while (*cp) {
4361242Skas if ((cp2 = netname(*cp++)) == NOSTR) {
4371242Skas printf("Made up bad net name\n");
4384333Skurt printf("Machine code %c (0%o)\n", cp[-1], cp[-1]);
4394333Skurt printf("Sorry -- dumping now. Alert K. Shoens\n");
44031142Sedward core();
4411242Skas goto err;
4421242Skas }
4431242Skas strcat(name, cp2);
4441242Skas stradd(name, *cp++);
4451242Skas }
4461242Skas strcat(name, netcomp);
4471242Skas }
4481242Skas
4491242Skas /*
4501242Skas * Take a string of network machine id's and separators and
4511242Skas * optimize them. We process these by pulling off maximal
4521242Skas * leading strings of the same type, passing these to the appropriate
4531242Skas * optimizer and concatenating the results.
4541242Skas */
4551242Skas
optim1(netstr,name)4561242Skas optim1(netstr, name)
4571242Skas char netstr[], name[];
4581242Skas {
4591242Skas char path[40], rpath[40];
4601242Skas register char *cp, *cp2;
4611242Skas register int tp, nc;
4621242Skas
4631242Skas cp = netstr;
4641242Skas prefer(cp);
4654342Skurt strcpy(name, "");
4663915Skurt /*
4673915Skurt * If the address ultimately points back to us,
4683915Skurt * just return a null network path.
4693915Skurt */
4703915Skurt if (strlen(cp) > 1 && cp[strlen(cp) - 2] == LOCAL)
4713915Skurt return;
4721242Skas while (*cp != 0) {
4731242Skas strcpy(path, "");
4741242Skas tp = ntype(cp[1]);
4751242Skas nc = cp[1];
4761242Skas while (*cp && tp == ntype(cp[1])) {
4771242Skas stradd(path, *cp++);
4781242Skas cp++;
4791242Skas }
4801242Skas switch (netkind(tp)) {
4811242Skas default:
4821242Skas strcpy(rpath, path);
4831242Skas break;
4841242Skas
4851242Skas case IMPLICIT:
4861242Skas optimimp(path, rpath);
4871242Skas break;
4881242Skas
4891242Skas case EXPLICIT:
4901242Skas optimex(path, rpath);
4911242Skas break;
4921242Skas }
4931242Skas for (cp2 = rpath; *cp2 != 0; cp2++) {
4941242Skas stradd(name, *cp2);
4951242Skas stradd(name, nc);
4961242Skas }
4971242Skas }
4981242Skas optiboth(name);
4991242Skas prefer(name);
5001242Skas }
5011242Skas
5021242Skas /*
5031242Skas * Return the network of the separator --
5041242Skas * AN for arpa net
5051242Skas * BN for Bell labs net
5061242Skas * SN for Schmidt (berkeley net)
5071242Skas * 0 if we don't know.
5081242Skas */
5091242Skas
ntype(nc)5101242Skas ntype(nc)
5111242Skas register int nc;
5121242Skas {
5137566Skurt register struct ntypetab *np;
5141242Skas
5157566Skurt for (np = ntypetab; np->nt_char != 0; np++)
5164337Skurt if (np->nt_char == nc)
5177566Skurt return(np->nt_bcode);
5184337Skurt return(0);
5191242Skas }
5201242Skas
5211242Skas /*
5221242Skas * Return the kind of routing used for the particular net
5231242Skas * EXPLICIT means explicitly routed
5241242Skas * IMPLICIT means implicitly routed
5251242Skas * 0 means don't know
5261242Skas */
5271242Skas
netkind(nt)5281242Skas netkind(nt)
5291242Skas register int nt;
5301242Skas {
5317566Skurt register struct nkindtab *np;
5321242Skas
5337566Skurt for (np = nkindtab; np->nk_type != 0; np++)
5344337Skurt if (np->nk_type == nt)
5354337Skurt return(np->nk_kind);
5364337Skurt return(0);
5371242Skas }
5381242Skas
5391242Skas /*
5401242Skas * Do name optimization for an explicitly routed network (eg BTL network).
5411242Skas */
5421242Skas
optimex(net,name)5431242Skas optimex(net, name)
5441242Skas char net[], name[];
5451242Skas {
5461242Skas register char *cp, *rp;
5471242Skas register int m;
5481242Skas
5491242Skas strcpy(name, net);
5501242Skas cp = name;
5511242Skas if (strlen(cp) == 0)
5521242Skas return(-1);
5531242Skas if (cp[strlen(cp)-1] == LOCAL) {
5541242Skas name[0] = 0;
5551242Skas return(0);
5561242Skas }
5571242Skas for (cp = name; *cp; cp++) {
5581242Skas m = *cp;
5591242Skas rp = rindex(cp+1, m);
5601242Skas if (rp != NOSTR)
5611242Skas strcpy(cp, rp);
5621242Skas }
5631242Skas return(0);
5641242Skas }
5651242Skas
5661242Skas /*
5671242Skas * Do name optimization for implicitly routed network (eg, arpanet,
5681242Skas * Berkeley network)
5691242Skas */
5701242Skas
optimimp(net,name)5711242Skas optimimp(net, name)
5721242Skas char net[], name[];
5731242Skas {
5741242Skas register char *cp;
5751242Skas register int m;
5761242Skas
5771242Skas cp = net;
5781242Skas if (strlen(cp) == 0)
5791242Skas return(-1);
5801242Skas m = cp[strlen(cp) - 1];
5811242Skas if (m == LOCAL) {
5821242Skas strcpy(name, "");
5831242Skas return(0);
5841242Skas }
5851242Skas name[0] = m;
5861242Skas name[1] = 0;
5871242Skas return(0);
5881242Skas }
5891242Skas
5901242Skas /*
5911242Skas * Perform global optimization on the given network path.
5921242Skas * The trick here is to look ahead to see if there are any loops
5931242Skas * in the path and remove them. The interpretation of loops is
5941242Skas * more strict here than in optimex since both the machine and net
5951242Skas * type must match.
5961242Skas */
5971242Skas
optiboth(net)5981242Skas optiboth(net)
5991242Skas char net[];
6001242Skas {
6011242Skas register char *cp, *cp2;
6021242Skas char *rpair();
6031242Skas
6041242Skas cp = net;
6051242Skas if (strlen(cp) == 0)
6061242Skas return;
6071242Skas if ((strlen(cp) % 2) != 0) {
6081242Skas printf("Strange arg to optiboth\n");
6091242Skas return;
6101242Skas }
6111242Skas while (*cp) {
6121242Skas cp2 = rpair(cp+2, *cp);
6131242Skas if (cp2 != NOSTR)
6141242Skas strcpy(cp, cp2);
6151242Skas cp += 2;
6161242Skas }
6171242Skas }
6181242Skas
6191242Skas /*
6201242Skas * Find the rightmost instance of the given (machine, type) pair.
6211242Skas */
6221242Skas
6231242Skas char *
rpair(str,mach)6241242Skas rpair(str, mach)
6251242Skas char str[];
6261242Skas {
6271242Skas register char *cp, *last;
6281242Skas
62924756Sserge cp = str;
6301242Skas last = NOSTR;
6311242Skas while (*cp) {
6321242Skas if (*cp == mach)
6331242Skas last = cp;
6341242Skas cp += 2;
6351242Skas }
6361242Skas return(last);
6371242Skas }
6381242Skas
6391242Skas /*
6401242Skas * Change the network separators in the given network path
6411242Skas * to the preferred network transmission means.
6421242Skas */
6431242Skas
prefer(name)6441242Skas prefer(name)
6451242Skas char name[];
6461242Skas {
6471242Skas register char *cp;
6481242Skas register int state, n;
6491242Skas
6501242Skas state = LOCAL;
6511242Skas for (cp = name; *cp; cp += 2) {
6521242Skas n = best(state, *cp);
6531242Skas if (n)
6541242Skas cp[1] = n;
6551242Skas state = *cp;
6561242Skas }
6571242Skas }
6581242Skas
6591242Skas /*
6601242Skas * Return the best network separator for the given machine pair.
6611242Skas */
6621242Skas
best(src,dest)6631242Skas best(src, dest)
6641242Skas {
6651242Skas register int dtype, stype;
6661242Skas register struct netorder *np;
6671242Skas
6681242Skas stype = nettype(src);
6691242Skas dtype = nettype(dest);
6703915Skurt fflush(stdout);
6711242Skas if (stype == 0 || dtype == 0) {
6721242Skas printf("ERROR: unknown internal machine id\n");
6731242Skas return(0);
6741242Skas }
6753915Skurt if ((stype & dtype) == 0)
6761242Skas return(0);
6771242Skas np = &netorder[0];
6781242Skas while ((np->no_stat & stype & dtype) == 0)
6791242Skas np++;
6801242Skas return(np->no_char);
6811242Skas }
6821242Skas
6839069Smckusick #ifdef GETHOST
6841242Skas /*
6858014Smckusick * Initialize the network name of the current host.
6868014Smckusick */
inithost()6878014Smckusick inithost()
6888014Smckusick {
6898014Smckusick register struct netmach *np;
6908014Smckusick static char host[64];
6918014Smckusick
6928014Smckusick gethostname(host, sizeof host);
6938014Smckusick for (np = netmach; np->nt_machine != 0; np++)
6948014Smckusick if (strcmp(np->nt_machine, EMPTY) == 0)
6958014Smckusick break;
6968014Smckusick if (np->nt_machine == 0) {
6978014Smckusick printf("Cannot find empty slot for dynamic host entry\n");
6988014Smckusick exit(1);
6998014Smckusick }
7008014Smckusick np->nt_machine = host;
7018014Smckusick }
7029069Smckusick #endif GETHOST
7038014Smckusick
7048014Smckusick /*
7051242Skas * Code to twist around arpa net names.
7061242Skas */
7071242Skas
7081242Skas #define WORD 257 /* Token for a string */
7091242Skas
7101242Skas static char netbuf[256];
7111242Skas static char *yylval;
7121242Skas
7131242Skas /*
7141242Skas * Reverse all of the arpa net addresses in the given name to
7151242Skas * be of the form "host @ user" instead of "user @ host"
7161242Skas * This function is its own inverse.
7171242Skas */
7181242Skas
7191242Skas char *
revarpa(str)7201242Skas revarpa(str)
7211242Skas char str[];
7221242Skas {
7231242Skas
7241242Skas if (yyinit(str) < 0)
7251242Skas return(NOSTR);
7261242Skas if (name())
7271242Skas return(NOSTR);
7281242Skas if (strcmp(str, netbuf) == 0)
7291242Skas return(str);
7301242Skas return(savestr(netbuf));
7311242Skas }
7321242Skas
7331242Skas /*
7341242Skas * Parse (by recursive descent) network names, using the following grammar:
7351242Skas * name:
7361242Skas * term {':' term}
7371242Skas * term {'^' term}
7381242Skas * term {'!' term}
7391242Skas * term '@' name
7401242Skas * term '%' name
7411242Skas *
7421242Skas * term:
7431242Skas * string of characters.
7441242Skas */
7451242Skas
name()7461242Skas name()
7471242Skas {
7481242Skas register int t;
7491242Skas register char *cp;
7501242Skas
7511242Skas for (;;) {
7521242Skas t = yylex();
7531242Skas if (t != WORD)
7541242Skas return(-1);
7551242Skas cp = yylval;
7561242Skas t = yylex();
7571242Skas switch (t) {
7581242Skas case 0:
7591242Skas strcat(netbuf, cp);
7601242Skas return(0);
7611242Skas
7621242Skas case '@':
7631242Skas case '%':
7641242Skas if (name())
7651242Skas return(-1);
7661242Skas stradd(netbuf, '@');
7671242Skas strcat(netbuf, cp);
7681242Skas return(0);
7691242Skas
7701242Skas case WORD:
7711242Skas return(-1);
7721242Skas
7731242Skas default:
7741242Skas strcat(netbuf, cp);
7751242Skas stradd(netbuf, t);
7761242Skas }
7771242Skas }
7781242Skas }
7791242Skas
7801242Skas /*
7811242Skas * Scanner for network names.
7821242Skas */
7831242Skas
7841242Skas static char *charp; /* Current input pointer */
7851242Skas static int nexttok; /* Salted away next token */
7861242Skas
7871242Skas /*
7881242Skas * Initialize the network name scanner.
7891242Skas */
7901242Skas
yyinit(str)7911242Skas yyinit(str)
7921242Skas char str[];
7931242Skas {
7941242Skas static char lexbuf[BUFSIZ];
7951242Skas
7961242Skas netbuf[0] = 0;
7971242Skas if (strlen(str) >= sizeof lexbuf - 1)
7981242Skas return(-1);
7991242Skas nexttok = 0;
8001242Skas strcpy(lexbuf, str);
8011242Skas charp = lexbuf;
8021242Skas return(0);
8031242Skas }
8041242Skas
8051242Skas /*
8061242Skas * Scan and return a single token.
8071242Skas * yylval is set to point to a scanned string.
8081242Skas */
8091242Skas
yylex()8101242Skas yylex()
8111242Skas {
8121242Skas register char *cp, *dot;
8131242Skas register int s;
8141242Skas
8151242Skas if (nexttok) {
8161242Skas s = nexttok;
8171242Skas nexttok = 0;
8181242Skas return(s);
8191242Skas }
8201242Skas cp = charp;
8211242Skas while (*cp && isspace(*cp))
8221242Skas cp++;
8231242Skas if (*cp == 0)
8241242Skas return(0);
8254337Skurt if (any(*cp, metanet)) {
8261242Skas charp = cp+1;
8271242Skas return(*cp);
8281242Skas }
8291242Skas dot = cp;
8304337Skurt while (*cp && !any(*cp, metanet) && !any(*cp, " \t"))
8311242Skas cp++;
8324337Skurt if (any(*cp, metanet))
8331242Skas nexttok = *cp;
8341242Skas if (*cp == 0)
8351242Skas charp = cp;
8361242Skas else
8371242Skas charp = cp+1;
8381242Skas *cp = 0;
8391242Skas yylval = dot;
8401242Skas return(WORD);
8411242Skas }
842