diff usr/src/cmd/mailx/optim.c @ 0:c9caec207d52 b86

Initial porting based on b86
author Koji Uno <koji.uno@sun.com>
date Tue, 02 Jun 2009 18:56:50 +0900
parents
children 1a15d5aaf794
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/cmd/mailx/optim.c	Tue Jun 02 18:56:50 2009 +0900
@@ -0,0 +1,1008 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License, Version 1.0 only
+ * (the "License").  You may not use this file except in compliance
+ * with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 1998 Sun Microsystems, Inc.  All rights reserved.
+ * Use is subject to license terms.
+ */
+
+/*	Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T	*/
+/*	  All Rights Reserved  	*/
+
+
+#pragma ident	"@(#)optim.c	1.26	05/06/13 SMI"
+
+/*
+ * mailx -- a modified version of a University of California at Berkeley
+ *	mail program
+ *
+ * Network name modification routines.
+ */
+
+#include "rcv.h"
+#include "configdefs.h"
+#include <locale.h>
+
+static char		*arpafix(char name[], char from[]);
+static char		*lasthost(char *addr);
+static char		*makeremote(char name[], char from[]);
+static int		mstash(char name[], int attnet);
+static int		mtype(int mid);
+static int		netlook(char machine[], int attnet);
+static int		nettype(int mid);
+static int		ntype(register int nc);
+static void		stradd(register char *str, int n, register int c);
+static char		*tackon(char *sys, char *rest);
+static struct xtrahash	*xlocate(char name[]);
+#ifdef OPTIM
+static char		best(int src, int dest);
+static char		*mlook(int mid);
+static int		netkind(register int nt);
+static void		optiboth(char net[]);
+static void		optim(char net[], char name[]);
+static void		optim1(char netstr[], char name[]);
+static int		optimex(char net[], char name[]);
+static int		optimimp(char net[], char name[]);
+static void		prefer(char name[]);
+static char		*rpair(char str[], int mach);
+#endif
+
+/*
+ * Map a name into the correct network "view" of the
+ * name.  This is done by prepending the name with the
+ * network address of the sender, then optimizing away
+ * nonsense.
+ */
+
+char *
+netmap(char name[], char from[])
+{
+	char nbuf[BUFSIZ], ret[BUFSIZ];
+	register char *cp, *oname;
+
+	if (debug) fprintf(stderr, "netmap(name '%s', from '%s')\n", name, from);
+	if (strlen(from) == 0)
+		return(name);	/* "from" is empty - can't do anything */
+
+	if (strcmp(from, name) == 0)
+		return(name);	/* "from" and "name" are the same, do nothing */
+
+	/*
+	 * If the name contains an "@" or a "%", remove it and the host
+	 * following it if that host is "known".
+	 */
+	if (any('@', name) || any('%', name))
+		return(arpafix(name, from));
+
+	/*
+	 * If the sender contains a "@" or a "%", make "name" into an
+	 * address on that host, on the presumption that it should
+	 * really have read "name@from" when we received the message
+	 * rather than just "name".
+	 */
+	if (any('@', from) || any('%', from))
+		return(unuucp(makeremote(name, from)));
+	if (value("onehop") && (cp = strchr(name, '!')) && cp > name) {
+		/*
+		 * "onehop" is set, meaning all machines are one UUCP
+		 * hop away (fat chance, in this day and age), and "name"
+		 * is a UUCP path rather than just a name.  Leave it alone.
+		 */
+		nstrcpy(nbuf, sizeof (nbuf), name);
+	} else {
+		from = tackon(host, from);
+		*strrchr(from, '!') = 0;
+		name = tackon(lasthost(from), name);
+		while (((cp = lasthost(from)) != 0) && ishost(cp, name)) {
+			oname = name;
+			name = strchr(name, '!') + 1;
+			if (cp == from) {
+				from[strlen(from)] = '!';
+				if (value("mustbang") && !strchr(name, '!'))
+					name = oname;
+				return(unuucp(name));
+			}
+			*--cp = 0;
+		}
+		from[strlen(from)] = '!';
+		from = strchr(from, '!') + 1;
+		snprintf(nbuf, sizeof (nbuf), "%s!%s", from, name);
+	}
+	if (debug) fprintf(stderr, "before optim, nbuf '%s'\n", name);
+#ifdef	OPTIM
+	if ((cp = value("conv"))==NOSTR || strcmp(cp, "optimize") != 0)
+		nstrcpy(ret, sizeof (ret), nbuf);
+	else
+		optim(nbuf, ret);
+#else
+	nstrcpy(ret, sizeof (ret), nbuf);
+#endif	/* OPTIM */
+	if (debug) fprintf(stderr, "after  optim, nbuf '%s', ret '%s'\n", nbuf, ret);
+	cp = ret;
+	if (debug) fprintf(stderr, "wind up with '%s'\n", name);
+	if (!icequal(name, cp))
+		return(unuucp((char *) savestr(cp)));
+	return(unuucp(name));
+}
+
+/*
+ * Stick a host on the beginning of a uucp
+ * address if it isn't there already.
+ */
+static char *
+tackon(char *sys, char *rest)
+{
+	while (*rest == '!')
+		rest++;
+	if (!ishost(sys, rest)) {
+		char *r = (char *)salloc(strlen(sys) + strlen(rest) + 2);
+		sprintf(r, "%s!%s", sys, rest);
+		rest = r;
+	}
+	return rest;
+}
+
+/*
+ * Check equality of the first host in a uucp address.
+ */
+int 
+ishost(char *sys, char *rest)
+{
+	while (*sys && *sys == *rest)
+		sys++, rest++;
+	return(*sys == 0 && *rest == '!');
+}
+
+/*
+ * Return last host in a uucp address.
+ */
+static char *
+lasthost(char *addr)
+{
+	char *r = strrchr(addr, '!');
+	return r ? ++r : addr;
+}
+
+/*
+ * Optionally translate an old format uucp name into a new one, e.g.
+ * "mach1!mach2!user" becomes "user@mach2.UUCP".  This optional because
+ * some information is necessarily lost (e.g. the route it got here
+ * via) and if we don't have the host in our routing tables, we lose.
+ * XXX THIS IS NO LONGER VALID WITH THE NEW UUCP PROJECT PLANS TO
+ * REGISTER UUCP HOSTS IN THE STANDARD INTERNET NAMESPACE, E.G.
+ * ihnp4 BECOMES "ihnp4.att.com".
+ */
+char *
+unuucp(char *name)
+{
+	register char *np, *hp, *cp;
+	char result[100];
+	char tname[300];
+
+	if (UnUUCP==0 &&
+	    ((cp = value("conv"))==NOSTR || strcmp(cp, "internet")))
+		return name;
+	if (debug) fprintf(stderr, "unuucp(%s)\n", name);
+	nstrcpy(tname, sizeof (tname), name);
+	np = strrchr(tname, '!');
+	if (np == NOSTR)
+		return name;
+	*np++ = 0;
+	hp = strrchr(tname, '!');
+	if (hp == NOSTR)
+		hp = tname;
+	else
+		*hp++ = 0;
+	cp = strchr(np, '@');
+	if (cp == NOSTR)
+		cp = strchr(np, '%');
+	if (cp)
+		*cp = 0;
+	if (debug) fprintf(stderr, "host %s, name %s\n", hp, np);
+	snprintf(result, sizeof (result), "%s@%s.UUCP", np, hp);
+	if (debug) fprintf(stderr, "unuucp returns %s\n", result);
+	return savestr(result);
+}
+
+/*
+ * Turn a network machine name into a unique character
+ */
+static int 
+netlook(char machine[], int attnet)
+{
+	register struct netmach *np;
+	register char *cp, *cp2;
+	char nbuf[BUFSIZ];
+
+	/*
+	 * Make into lower case.
+	 */
+	for (cp = machine, cp2 = nbuf;
+	     *cp && cp2 < &nbuf[BUFSIZ-1];
+	     *cp2++ = tolower(*cp++))
+		/*nothing*/;
+	*cp2 = 0;
+
+	/*
+	 * If a single letter machine, look through those first.
+	 */
+
+	if (strlen(nbuf) == 1)
+		for (np = netmach; np->nt_mid != 0; np++)
+			if (np->nt_mid == nbuf[0])
+				return(nbuf[0]);
+
+	/*
+	 * Look for usual name
+	 */
+
+	for (np = netmach; np->nt_mid != 0; np++)
+		if (strcmp(np->nt_machine, nbuf) == 0)
+			return(np->nt_mid);
+
+	/*
+	 * Look in side hash table.
+	 */
+
+	return(mstash(nbuf, attnet));
+}
+
+#ifdef OPTIM
+/*
+ * Turn a network unique character identifier into a network name.
+ */
+
+static char *
+netname(int mid)
+{
+	register struct netmach *np;
+
+	if (mid & 0200)
+		return(mlook(mid));
+	for (np = netmach; np->nt_mid != 0; np++)
+		if (np->nt_mid == mid)
+			return(np->nt_machine);
+	return(NOSTR);
+}
+#endif
+
+/*
+ * Deal with arpa net addresses.  The way this is done is strange.
+ * name contains an "@" or "%".  Look up the machine after it in
+ * the hash table.  If it isn't found, return name unmolested.
+ * If ???, return name unmolested.
+ * Otherwise, delete the "@" or "%" and the machine after it from
+ * name, and return the new string.
+ */
+static char *
+arpafix(char name[], char from[])
+{
+	register char *cp;
+	register int arpamach;
+	char newname[BUFSIZ];
+
+	if (debug) {
+		fprintf(stderr, "arpafix(%s, %s)\n", name, from);
+	}
+	cp = strrchr(name, '@');
+	if (cp == NOSTR)
+		cp = strrchr(name, '%');
+	if (cp == NOSTR) {
+		fprintf(stderr,
+		    gettext("Something's amiss -- no @ or %% in arpafix\n"));
+		return(name);
+	}
+	cp++;
+	arpamach = netlook(cp, '@');
+	if (debug)
+		fprintf(stderr,
+		    "cp '%s', arpamach %o, nettypes arpamach %o LOCAL %o\n",
+		    cp, arpamach, nettype(arpamach), nettype(LOCAL));
+	if (arpamach == 0) {
+		if (debug)
+			fprintf(stderr, "machine %s unknown, uses: %s\n",
+			    cp, name);
+		return(name);
+	}
+	if (((nettype(arpamach) & nettype(LOCAL)) & ~AN) == 0) {
+		if (debug)
+			fprintf(stderr, "machine %s known but remote, uses: %s\n",
+			    cp, name);
+		return(name);
+	}
+	nstrcpy(newname, sizeof (newname), name);
+	cp = strrchr(newname, '@');
+	if (cp == NOSTR)
+		cp = strrchr(newname, '%');
+	*cp = 0;
+	if (debug) fprintf(stderr, "local address, return '%s'\n", newname);
+	return(savestr(newname));
+}
+
+/*
+ * We have name with no @'s in it, and from with @'s.
+ * Assume that name is meaningful only on the site in from,
+ * and return "name@site_in_from".
+ */
+static char *
+makeremote(char name[], char from[])
+{
+	register char *cp;
+	char rbuf[BUFSIZ];
+
+	if (!value("makeremote"))
+		return(name);
+	if (debug) fprintf(stderr, "makeremote(%s, %s) returns ", name, from);
+	cp = strrchr(from, '@');
+	if (cp == NOSTR)
+		cp = strrchr(from, '%');
+	snprintf(rbuf, sizeof (rbuf), "%s%s", name, cp);
+	if (debug) fprintf(stderr, "%s\n", rbuf);
+	return(savestr(rbuf));
+}
+
+/*
+ * Take a network machine descriptor and find the types of connected
+ * nets and return it.
+ */
+static int 
+nettype(int mid)
+{
+	register struct netmach *np;
+
+	if (mid & 0200)
+		return(mtype(mid));
+	for (np = netmach; np->nt_mid != 0; np++)
+		if (np->nt_mid == mid)
+			return(np->nt_type);
+	return(0);
+}
+
+/*
+ * Hashing routines to salt away machines seen scanning
+ * networks paths that we don't know about.
+ */
+
+#define	XHSIZE		97		/* Size of extra hash table */
+#define	NXMID		(XHSIZE*3/4)	/* Max extra machines */
+
+struct xtrahash {
+	char	*xh_name;		/* Name of machine */
+	short	xh_mid;			/* Machine ID */
+	short	xh_attnet;		/* Attached networks */
+} xtrahash[XHSIZE];
+
+static struct xtrahash	*xtab[XHSIZE];		/* F: mid-->machine name */
+
+static short	midfree;			/* Next free machine id */
+
+/*
+ * Initialize the extra host hash table.
+ * Called by sreset.
+ */
+void 
+minit(void)
+{
+	register struct xtrahash *xp, **tp;
+
+	midfree = 0;
+	tp = &xtab[0];
+	for (xp = &xtrahash[0]; xp < &xtrahash[XHSIZE]; xp++) {
+		xp->xh_name = NOSTR;
+		xp->xh_mid = 0;
+		xp->xh_attnet = 0;
+		*tp++ = (struct xtrahash *) 0;
+	}
+}
+
+/*
+ * Stash a net name in the extra host hash table.
+ * If a new entry is put in the hash table, deduce what
+ * net the machine is attached to from the net character.
+ *
+ * If the machine is already known, add the given attached
+ * net to those already known.
+ */
+static int 
+mstash(char name[], int attnet)
+{
+	register struct xtrahash *xp;
+	int x;
+
+	xp = xlocate(name);
+	if (xp == (struct xtrahash *) 0) {
+		printf(gettext("Ran out of machine id spots\n"));
+		return(0);
+	}
+	if (xp->xh_name == NOSTR) {
+		if (midfree >= XHSIZE) {
+			printf(gettext("Out of machine ids\n"));
+			return(0);
+		}
+		xtab[midfree] = xp;
+		xp->xh_name = savestr(name);
+		xp->xh_mid = 0200 + midfree++;
+	}
+	x = ntype(attnet);
+	if (x == 0)
+		xp->xh_attnet |= AN;
+	else
+		xp->xh_attnet |= x;
+	return(xp->xh_mid);
+}
+
+/*
+ * Search for the given name in the hash table
+ * and return the pointer to it if found, or to the first
+ * empty slot if not found.
+ *
+ * If no free slots can be found, return 0.
+ */
+
+static struct xtrahash *
+xlocate(char name[])
+{
+	register int h, q, i;
+	register char *cp;
+	register struct xtrahash *xp;
+
+	for (h = 0, cp = name; *cp; h = (h << 2) + *cp++)
+		;
+	if (h < 0 && (h = -h) < 0)
+		h = 0;
+	h = h % XHSIZE;
+	cp = name;
+	for (i = 0, q = 0; q < XHSIZE; i++, q = i * i) {
+		xp = &xtrahash[(h + q) % XHSIZE];
+		if (xp->xh_name == NOSTR)
+			return(xp);
+		if (strcmp(cp, xp->xh_name) == 0)
+			return(xp);
+		if (h - q < 0)
+			h += XHSIZE;
+		xp = &xtrahash[(h - q) % XHSIZE];
+		if (xp->xh_name == NOSTR)
+			return(xp);
+		if (strcmp(cp, xp->xh_name) == 0)
+			return(xp);
+	}
+	return((struct xtrahash *) 0);
+}
+
+#ifdef OPTIM
+/*
+ * Return the name from the extra host hash table corresponding
+ * to the passed machine id.
+ */
+
+static char *
+mlook(int mid)
+{
+	register int m;
+
+	if ((mid & 0200) == 0)
+		return(NOSTR);
+	m = mid & 0177;
+	if (m >= midfree) {
+		printf(gettext("Use made of undefined machine id\n"));
+		return(NOSTR);
+	}
+	return(xtab[m]->xh_name);
+}
+#endif
+
+/*
+ * Return the bit mask of net's that the given extra host machine
+ * id has so far.
+ */
+static int 
+mtype(int mid)
+{
+	register int m;
+
+	if ((mid & 0200) == 0)
+		return(0);
+	m = mid & 0177;
+	if (m >= midfree) {
+		printf(gettext("Use made of undefined machine id\n"));
+		return(0);
+	}
+	return(xtab[m]->xh_attnet);
+}
+
+#ifdef	OPTIM
+/*
+ * Take a network name and optimize it.  This gloriously messy
+ * operation takes place as follows:  the name with machine names
+ * in it is tokenized by mapping each machine name into a single
+ * character machine id (netlook).  The separator characters (network
+ * metacharacters) are left intact.  The last component of the network
+ * name is stripped off and assumed to be the destination user name --
+ * it does not participate in the optimization.  As an example, the
+ * name "res!vax!res!uvax!bill" becomes, tokenized,
+ * "r!x!r!v!" and "bill"  A low level routine, optim1, fixes up the
+ * network part (eg, "r!x!r!v!"), then we convert back to network
+ * machine names and tack the user name on the end.
+ *
+ * The result of this is copied into the parameter "name"
+ */
+
+static void
+optim(char net[], char name[])
+{
+	char netcomp[BUFSIZ], netstr[STSIZ], xfstr[STSIZ];
+	register char *cp, *cp2;
+	register int c;
+
+	if (debug) fprintf(stderr, "optim(%s, %s) called\n", net, name);
+	*netstr = '\0';
+	cp = net;
+	for (;;) {
+		/*
+		 * Rip off next path component into netcomp
+		 */
+		cp2 = netcomp;
+		while (*cp && !any(*cp, metanet))
+			*cp2++ = *cp++;
+		*cp2 = 0;
+		/*
+		 * If we hit null byte, then we just scanned
+		 * the destination user name.  Go off and optimize
+		 * if its so.
+		 */
+		if (*cp == 0)
+			break;
+		if ((c = netlook(netcomp, *cp)) == 0) {
+			printf(gettext("No host named \"%s\"\n"), netcomp);
+err:
+			nstrcpy(name, BUFSIZ, net);
+			return;
+		}
+		stradd(name, BUFSIZ, c);
+		stradd(name, BUFSIZ, *cp++);
+		/*
+		 * If multiple network separators given,
+		 * throw away the extras.
+		 */
+		while (any(*cp, metanet))
+			cp++;
+	}
+	if (strlen(netcomp) == 0) {
+		printf(gettext("net name syntax\n"));
+		goto err;
+	}
+	if (debug) fprintf(stderr, "optim1(%s,%s) called\n", netstr, xfstr);
+	optim1(netstr, xfstr);
+	if (debug) fprintf(stderr, "optim1(%s,%s) returns\n", netstr, xfstr);
+
+	/*
+	 * Convert back to machine names.
+	 */
+
+	cp = xfstr;
+	*name = '\0';
+	while (*cp) {
+		if ((cp2 = netname(*cp++)) == NOSTR) {
+			printf(gettext("Made up bad net name\n"));
+			printf(gettext("Machine code %c (0%o)\n"), cp[-1],
+cp[-1]);
+			printf(gettext("Sorry.\n"));
+			goto err;
+		}
+		nstrcat(name, BUFSIZ, cp2);
+		stradd(name, BUFSIZ, *cp++);
+	}
+	nstrcat(name, BUFSIZ, netcomp);
+	if (debug) fprintf(stderr, "optim returns %s in name\n", name);
+}
+
+/*
+ * Take a string of network machine id's and separators and
+ * optimize them.  We process these by pulling off maximal
+ * leading strings of the same type, passing these to the appropriate
+ * optimizer and concatenating the results.
+ */
+
+static void 
+optim1(char netstr[], char name[])
+{
+	char path[STSIZ], rpath[STSIZ];
+	register char *cp, *cp2;
+	register int tp, nc;
+	
+	cp = netstr;
+	prefer(cp);
+	*name  = '\0';
+	/*
+	 * If the address ultimately points back to us,
+	 * just return a null network path.
+	 */
+	if ((int)strlen(cp) > 1 && cp[strlen(cp) - 2] == LOCAL)
+		return;
+	while (*cp != 0) {
+		*path = '\0';
+
+		tp = ntype(cp[1]);
+		nc = cp[1];
+		while (*cp && tp == ntype(cp[1])) {
+			stradd(path, sizeof (path), *cp++);
+			cp++;
+		}
+		switch (netkind(tp)) {
+		default:
+			nstrcpy(rpath, sizeof (rpath), path);
+			break;
+
+		case IMPLICIT:
+			optimimp(path, rpath);
+			break;
+
+		case EXPLICIT:
+			optimex(path, rpath);
+			break;
+		}
+		for (cp2 = rpath; *cp2 != 0; cp2++) {
+			stradd(name, BUFSIZ, *cp2);
+			stradd(name, BUFSIZ, nc);
+		}
+	}
+	optiboth(name);
+	prefer(name);
+}
+#endif	/* OPTIM */
+
+/*
+ * Return the network of the separator --
+ *	AN for arpa net
+ *	BN for Bell labs net	(e.g. UUCP, NOT Berknet)
+ *	SN for Schmidt net	(Berknet)
+ *	0 if we don't know.
+ */
+static int 
+ntype(register int nc)
+{
+	register struct ntypetab *np;
+
+	for (np = ntypetab; np->nt_char != 0; np++)
+		if (np->nt_char == nc)
+			return(np->nt_bcode);
+	return(0);
+}
+
+#ifdef	OPTIM
+/*
+ * Return the kind of routing used for the particular net
+ * EXPLICIT means explicitly routed
+ * IMPLICIT means implicitly routed
+ * 0 means don't know
+ */
+
+static int 
+netkind(register int nt)
+{
+	register struct nkindtab *np;
+
+	for (np = nkindtab; np->nk_type != 0; np++)
+		if (np->nk_type == nt)
+			return(np->nk_kind);
+	return(0);
+}
+
+/*
+ * Do name optimization for an explicitly routed network (eg uucp).
+ */
+
+static int 
+optimex(char net[], char name[])
+{
+	register char *cp, *rp;
+	register int m;
+
+	nstrcpy(name, STSIZ, net);
+	cp = name;
+	if (strlen(cp) == 0)
+		return(-1);
+	if (cp[strlen(cp)-1] == LOCAL) {
+		name[0] = 0;
+		return(0);
+	}
+	for (cp = name; *cp; cp++) {
+		m = *cp;
+		rp = strrchr(cp+1, m);
+		if (rp != NOSTR)
+			strcpy(cp, rp);
+	}
+	return(0);
+}
+
+/*
+ * Do name optimization for implicitly routed network (eg, arpanet).
+ */
+
+static int 
+optimimp(char net[], char name[])
+{
+	register char *cp;
+	register char m;
+
+	cp = net;
+	if (strlen(cp) == 0)
+		return(-1);
+	m = cp[strlen(cp) - 1];
+	if (m == LOCAL) {
+		*name = '\0';
+		return(0);
+	}
+	name[0] = m;
+	name[1] = 0;
+	return(0);
+}
+
+/*
+ * Perform global optimization on the given network path.
+ * The trick here is to look ahead to see if there are any loops
+ * in the path and remove them.  The interpretation of loops is
+ * more strict here than in optimex since both the machine and net
+ * type must match.
+ */
+
+static void 
+optiboth(char net[])
+{
+	register char *cp, *cp2;
+
+	cp = net;
+	if (strlen(cp) == 0)
+		return;
+	if (((int)strlen(cp) % 2) != 0) {
+		printf(gettext("Strange arg to optiboth\n"));
+		return;
+	}
+	while (*cp) {
+		cp2 = rpair(cp+2, *cp);
+		if (cp2 != NOSTR)
+			strcpy(cp, cp2);
+		cp += 2;
+	}
+}
+
+/*
+ * Find the rightmost instance of the given (machine, type) pair.
+ */
+
+static char *
+rpair(char str[], int mach)
+{
+	register char *cp, *last;
+
+	cp = str;
+	last = NOSTR;
+	while (*cp) {
+		if (*cp == mach)
+			last = cp;
+		cp += 2;
+	}
+	return(last);
+}
+
+/*
+ * Change the network separators in the given network path
+ * to the preferred network transmission means.
+ */
+
+static void 
+prefer(char name[])
+{
+	register char *cp, n;
+	register int state;
+
+	state = LOCAL;
+	for (cp = name; *cp; cp += 2) {
+		n = best(state, *cp);
+		if (n)
+			cp[1] = n;
+		state = *cp;
+	}
+}
+
+/*
+ * Return the best network separator for the given machine pair.
+ */
+
+static char 
+best(int src, int dest)
+{
+	register int dtype, stype;
+	register struct netorder *np;
+
+	stype = nettype(src);
+	dtype = nettype(dest);
+	fflush(stdout);
+	if (stype == 0 || dtype == 0) {
+		printf(gettext("ERROR:  unknown internal machine id\n"));
+		return(0);
+	}
+	if ((stype & dtype) == 0)
+		return(0);
+	np = &netorder[0];
+	while ((np->no_stat & stype & dtype) == 0)
+		np++;
+	return(np->no_char);
+}
+#endif	/* OPTIM */
+
+#ifdef notdef
+/*
+ * Code to twist around arpa net names.
+ */
+
+#define WORD 257			/* Token for a string */
+
+static	char netbuf[256];
+static	char *yylval;
+
+/*
+ * Reverse all of the arpa net addresses in the given name to
+ * be of the form "host @ user" instead of "user @ host"
+ * This function is its own inverse.
+ */
+
+char *
+revarpa(char str[])
+{
+
+	if (yyinit(str) < 0)
+		return(NOSTR);
+	if (name())
+		return(NOSTR);
+	if (strcmp(str, netbuf) == 0)
+		return(str);
+	return(savestr(netbuf));
+}
+
+/*
+ * Parse (by recursive descent) network names, using the following grammar:
+ *	name:
+ *		term {':' term}
+ *		term {'^' term}
+ *		term {'!' term}
+ *		term '@' name
+ *		term '%' name
+ *
+ *	term:
+ *		string of characters.
+ */
+
+static int 
+name(void)
+{
+	register int t;
+	register char *cp;
+
+	for (;;) {
+		t = yylex();
+		if (t != WORD)
+			return(-1);
+		cp = yylval;
+		t = yylex();
+		switch (t) {
+		case 0:
+			nstrcat(netbuf, sizeof (netbuf), cp);
+			return(0);
+
+		case '@':
+		case '%':
+			if (name())
+				return(-1);
+			stradd(netbuf, sizeof (netbuf), '@');
+			nstrcat(netbuf, sizeof (netbuf), cp);
+			return(0);	
+		case WORD:
+			return(-1);
+
+		default:
+			nstrcat(netbuf, sizeof (netbuf), cp);
+			stradd(netbuf, sizeof (netbuf), t);
+		}
+	}
+}
+
+/*
+ * Scanner for network names.
+ */
+
+static	char *charp;			/* Current input pointer */
+static	int nexttok;			/* Salted away next token */
+
+/*
+ * Initialize the network name scanner.
+ */
+
+int 
+yyinit(char str[])
+{
+	static char lexbuf[BUFSIZ];
+
+	netbuf[0] = 0;
+	if (strlen(str) >= sizeof lexbuf - 1)
+		return(-1);
+	nexttok = 0;
+	nstrcpy(lexbuf, sizeof (lexbuf), str);
+	charp = lexbuf;
+	return(0);
+}
+
+/*
+ * Scan and return a single token.
+ * yylval is set to point to a scanned string.
+ */
+
+int 
+yylex(void)
+{
+	register char *cp, *dotp;
+	register int s;
+
+	if (nexttok) {
+		s = nexttok;
+		nexttok = 0;
+		return(s);
+	}
+	cp = charp;
+	while (*cp && isspace(*cp))
+		cp++;
+	if (*cp == 0)
+		return(0);
+	if (any(*cp, metanet)) {
+		charp = cp+1;
+		return(*cp);
+	}
+	dotp = cp;
+	while (*cp && !any(*cp, metanet) && !any(*cp, " \t"))
+		cp++;
+	if (any(*cp, metanet))
+		nexttok = *cp;
+	if (*cp == 0)
+		charp = cp;
+	else
+		charp = cp+1;
+	*cp = 0;
+	yylval = dotp;
+	return(WORD);
+}
+#endif
+
+/*
+ * Add a single character onto a string. Here dstsize is the size of the 
+ * destnation buffer.
+ */
+
+static void 
+stradd(register char *dst, int dstsize, register int c)
+{
+	while (*dst != '\0') {
+		dst++;
+		dstsize--;
+	}
+	if (--dstsize > 0)
+		*dst++ = (char)c;
+	*dst = '\0';
+}