xref: /onnv-gate/usr/src/cmd/mailx/optim.c (revision 18:7e2dc246c4e2)
10Sstevel@tonic-gate /*
20Sstevel@tonic-gate  * CDDL HEADER START
30Sstevel@tonic-gate  *
40Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
50Sstevel@tonic-gate  * Common Development and Distribution License, Version 1.0 only
60Sstevel@tonic-gate  * (the "License").  You may not use this file except in compliance
70Sstevel@tonic-gate  * with the License.
80Sstevel@tonic-gate  *
90Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
100Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
110Sstevel@tonic-gate  * See the License for the specific language governing permissions
120Sstevel@tonic-gate  * and limitations under the License.
130Sstevel@tonic-gate  *
140Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
150Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
160Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
170Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
180Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
190Sstevel@tonic-gate  *
200Sstevel@tonic-gate  * CDDL HEADER END
210Sstevel@tonic-gate  */
220Sstevel@tonic-gate /*
230Sstevel@tonic-gate  * Copyright 1998 Sun Microsystems, Inc.  All rights reserved.
240Sstevel@tonic-gate  * Use is subject to license terms.
250Sstevel@tonic-gate  */
260Sstevel@tonic-gate 
270Sstevel@tonic-gate /*	Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T	*/
280Sstevel@tonic-gate /*	  All Rights Reserved  	*/
290Sstevel@tonic-gate 
300Sstevel@tonic-gate 
310Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
320Sstevel@tonic-gate 
330Sstevel@tonic-gate /*
340Sstevel@tonic-gate  * mailx -- a modified version of a University of California at Berkeley
350Sstevel@tonic-gate  *	mail program
360Sstevel@tonic-gate  *
370Sstevel@tonic-gate  * Network name modification routines.
380Sstevel@tonic-gate  */
390Sstevel@tonic-gate 
400Sstevel@tonic-gate #include "rcv.h"
410Sstevel@tonic-gate #include "configdefs.h"
420Sstevel@tonic-gate #include <locale.h>
430Sstevel@tonic-gate 
440Sstevel@tonic-gate static char		*arpafix(char name[], char from[]);
450Sstevel@tonic-gate static char		*lasthost(char *addr);
460Sstevel@tonic-gate static char		*makeremote(char name[], char from[]);
470Sstevel@tonic-gate static int		mstash(char name[], int attnet);
480Sstevel@tonic-gate static int		mtype(int mid);
490Sstevel@tonic-gate static int		netlook(char machine[], int attnet);
500Sstevel@tonic-gate static int		nettype(int mid);
510Sstevel@tonic-gate static int		ntype(register int nc);
520Sstevel@tonic-gate static void		stradd(register char *str, int n, register int c);
530Sstevel@tonic-gate static char		*tackon(char *sys, char *rest);
540Sstevel@tonic-gate static struct xtrahash	*xlocate(char name[]);
550Sstevel@tonic-gate #ifdef OPTIM
560Sstevel@tonic-gate static char		best(int src, int dest);
570Sstevel@tonic-gate static char		*mlook(int mid);
580Sstevel@tonic-gate static int		netkind(register int nt);
590Sstevel@tonic-gate static void		optiboth(char net[]);
600Sstevel@tonic-gate static void		optim(char net[], char name[]);
610Sstevel@tonic-gate static void		optim1(char netstr[], char name[]);
620Sstevel@tonic-gate static int		optimex(char net[], char name[]);
630Sstevel@tonic-gate static int		optimimp(char net[], char name[]);
640Sstevel@tonic-gate static void		prefer(char name[]);
650Sstevel@tonic-gate static char		*rpair(char str[], int mach);
660Sstevel@tonic-gate #endif
670Sstevel@tonic-gate 
680Sstevel@tonic-gate /*
690Sstevel@tonic-gate  * Map a name into the correct network "view" of the
700Sstevel@tonic-gate  * name.  This is done by prepending the name with the
710Sstevel@tonic-gate  * network address of the sender, then optimizing away
720Sstevel@tonic-gate  * nonsense.
730Sstevel@tonic-gate  */
740Sstevel@tonic-gate 
750Sstevel@tonic-gate char *
netmap(char name[],char from[])760Sstevel@tonic-gate netmap(char name[], char from[])
770Sstevel@tonic-gate {
780Sstevel@tonic-gate 	char nbuf[BUFSIZ], ret[BUFSIZ];
790Sstevel@tonic-gate 	register char *cp, *oname;
800Sstevel@tonic-gate 
810Sstevel@tonic-gate 	if (debug) fprintf(stderr, "netmap(name '%s', from '%s')\n", name, from);
820Sstevel@tonic-gate 	if (strlen(from) == 0)
830Sstevel@tonic-gate 		return(name);	/* "from" is empty - can't do anything */
840Sstevel@tonic-gate 
850Sstevel@tonic-gate 	if (strcmp(from, name) == 0)
860Sstevel@tonic-gate 		return(name);	/* "from" and "name" are the same, do nothing */
870Sstevel@tonic-gate 
880Sstevel@tonic-gate 	/*
890Sstevel@tonic-gate 	 * If the name contains an "@" or a "%", remove it and the host
900Sstevel@tonic-gate 	 * following it if that host is "known".
910Sstevel@tonic-gate 	 */
920Sstevel@tonic-gate 	if (any('@', name) || any('%', name))
930Sstevel@tonic-gate 		return(arpafix(name, from));
940Sstevel@tonic-gate 
950Sstevel@tonic-gate 	/*
960Sstevel@tonic-gate 	 * If the sender contains a "@" or a "%", make "name" into an
970Sstevel@tonic-gate 	 * address on that host, on the presumption that it should
980Sstevel@tonic-gate 	 * really have read "name@from" when we received the message
990Sstevel@tonic-gate 	 * rather than just "name".
1000Sstevel@tonic-gate 	 */
1010Sstevel@tonic-gate 	if (any('@', from) || any('%', from))
1020Sstevel@tonic-gate 		return(unuucp(makeremote(name, from)));
1030Sstevel@tonic-gate 	if (value("onehop") && (cp = strchr(name, '!')) && cp > name) {
1040Sstevel@tonic-gate 		/*
1050Sstevel@tonic-gate 		 * "onehop" is set, meaning all machines are one UUCP
1060Sstevel@tonic-gate 		 * hop away (fat chance, in this day and age), and "name"
1070Sstevel@tonic-gate 		 * is a UUCP path rather than just a name.  Leave it alone.
1080Sstevel@tonic-gate 		 */
1090Sstevel@tonic-gate 		nstrcpy(nbuf, sizeof (nbuf), name);
1100Sstevel@tonic-gate 	} else {
1110Sstevel@tonic-gate 		from = tackon(host, from);
1120Sstevel@tonic-gate 		*strrchr(from, '!') = 0;
1130Sstevel@tonic-gate 		name = tackon(lasthost(from), name);
1140Sstevel@tonic-gate 		while (((cp = lasthost(from)) != 0) && ishost(cp, name)) {
1150Sstevel@tonic-gate 			oname = name;
1160Sstevel@tonic-gate 			name = strchr(name, '!') + 1;
1170Sstevel@tonic-gate 			if (cp == from) {
1180Sstevel@tonic-gate 				from[strlen(from)] = '!';
1190Sstevel@tonic-gate 				if (value("mustbang") && !strchr(name, '!'))
1200Sstevel@tonic-gate 					name = oname;
1210Sstevel@tonic-gate 				return(unuucp(name));
1220Sstevel@tonic-gate 			}
1230Sstevel@tonic-gate 			*--cp = 0;
1240Sstevel@tonic-gate 		}
1250Sstevel@tonic-gate 		from[strlen(from)] = '!';
1260Sstevel@tonic-gate 		from = strchr(from, '!') + 1;
1270Sstevel@tonic-gate 		snprintf(nbuf, sizeof (nbuf), "%s!%s", from, name);
1280Sstevel@tonic-gate 	}
1290Sstevel@tonic-gate 	if (debug) fprintf(stderr, "before optim, nbuf '%s'\n", name);
1300Sstevel@tonic-gate #ifdef	OPTIM
1310Sstevel@tonic-gate 	if ((cp = value("conv"))==NOSTR || strcmp(cp, "optimize") != 0)
1320Sstevel@tonic-gate 		nstrcpy(ret, sizeof (ret), nbuf);
1330Sstevel@tonic-gate 	else
1340Sstevel@tonic-gate 		optim(nbuf, ret);
1350Sstevel@tonic-gate #else
1360Sstevel@tonic-gate 	nstrcpy(ret, sizeof (ret), nbuf);
137*18Srobbin #endif	/* OPTIM */
1380Sstevel@tonic-gate 	if (debug) fprintf(stderr, "after  optim, nbuf '%s', ret '%s'\n", nbuf, ret);
1390Sstevel@tonic-gate 	cp = ret;
1400Sstevel@tonic-gate 	if (debug) fprintf(stderr, "wind up with '%s'\n", name);
1410Sstevel@tonic-gate 	if (!icequal(name, cp))
1420Sstevel@tonic-gate 		return(unuucp((char *) savestr(cp)));
1430Sstevel@tonic-gate 	return(unuucp(name));
1440Sstevel@tonic-gate }
1450Sstevel@tonic-gate 
1460Sstevel@tonic-gate /*
1470Sstevel@tonic-gate  * Stick a host on the beginning of a uucp
1480Sstevel@tonic-gate  * address if it isn't there already.
1490Sstevel@tonic-gate  */
1500Sstevel@tonic-gate static char *
tackon(char * sys,char * rest)1510Sstevel@tonic-gate tackon(char *sys, char *rest)
1520Sstevel@tonic-gate {
1530Sstevel@tonic-gate 	while (*rest == '!')
1540Sstevel@tonic-gate 		rest++;
1550Sstevel@tonic-gate 	if (!ishost(sys, rest)) {
1560Sstevel@tonic-gate 		char *r = (char *)salloc(strlen(sys) + strlen(rest) + 2);
1570Sstevel@tonic-gate 		sprintf(r, "%s!%s", sys, rest);
1580Sstevel@tonic-gate 		rest = r;
1590Sstevel@tonic-gate 	}
1600Sstevel@tonic-gate 	return rest;
1610Sstevel@tonic-gate }
1620Sstevel@tonic-gate 
1630Sstevel@tonic-gate /*
1640Sstevel@tonic-gate  * Check equality of the first host in a uucp address.
1650Sstevel@tonic-gate  */
1660Sstevel@tonic-gate int
ishost(char * sys,char * rest)1670Sstevel@tonic-gate ishost(char *sys, char *rest)
1680Sstevel@tonic-gate {
1690Sstevel@tonic-gate 	while (*sys && *sys == *rest)
1700Sstevel@tonic-gate 		sys++, rest++;
1710Sstevel@tonic-gate 	return(*sys == 0 && *rest == '!');
1720Sstevel@tonic-gate }
1730Sstevel@tonic-gate 
1740Sstevel@tonic-gate /*
1750Sstevel@tonic-gate  * Return last host in a uucp address.
1760Sstevel@tonic-gate  */
1770Sstevel@tonic-gate static char *
lasthost(char * addr)1780Sstevel@tonic-gate lasthost(char *addr)
1790Sstevel@tonic-gate {
1800Sstevel@tonic-gate 	char *r = strrchr(addr, '!');
1810Sstevel@tonic-gate 	return r ? ++r : addr;
1820Sstevel@tonic-gate }
1830Sstevel@tonic-gate 
1840Sstevel@tonic-gate /*
1850Sstevel@tonic-gate  * Optionally translate an old format uucp name into a new one, e.g.
1860Sstevel@tonic-gate  * "mach1!mach2!user" becomes "user@mach2.UUCP".  This optional because
1870Sstevel@tonic-gate  * some information is necessarily lost (e.g. the route it got here
1880Sstevel@tonic-gate  * via) and if we don't have the host in our routing tables, we lose.
1890Sstevel@tonic-gate  * XXX THIS IS NO LONGER VALID WITH THE NEW UUCP PROJECT PLANS TO
1900Sstevel@tonic-gate  * REGISTER UUCP HOSTS IN THE STANDARD INTERNET NAMESPACE, E.G.
1910Sstevel@tonic-gate  * ihnp4 BECOMES "ihnp4.att.com".
1920Sstevel@tonic-gate  */
1930Sstevel@tonic-gate char *
unuucp(char * name)1940Sstevel@tonic-gate unuucp(char *name)
1950Sstevel@tonic-gate {
1960Sstevel@tonic-gate 	register char *np, *hp, *cp;
1970Sstevel@tonic-gate 	char result[100];
1980Sstevel@tonic-gate 	char tname[300];
1990Sstevel@tonic-gate 
2000Sstevel@tonic-gate 	if (UnUUCP==0 &&
2010Sstevel@tonic-gate 	    ((cp = value("conv"))==NOSTR || strcmp(cp, "internet")))
2020Sstevel@tonic-gate 		return name;
2030Sstevel@tonic-gate 	if (debug) fprintf(stderr, "unuucp(%s)\n", name);
2040Sstevel@tonic-gate 	nstrcpy(tname, sizeof (tname), name);
2050Sstevel@tonic-gate 	np = strrchr(tname, '!');
2060Sstevel@tonic-gate 	if (np == NOSTR)
2070Sstevel@tonic-gate 		return name;
2080Sstevel@tonic-gate 	*np++ = 0;
2090Sstevel@tonic-gate 	hp = strrchr(tname, '!');
2100Sstevel@tonic-gate 	if (hp == NOSTR)
2110Sstevel@tonic-gate 		hp = tname;
2120Sstevel@tonic-gate 	else
2130Sstevel@tonic-gate 		*hp++ = 0;
2140Sstevel@tonic-gate 	cp = strchr(np, '@');
2150Sstevel@tonic-gate 	if (cp == NOSTR)
2160Sstevel@tonic-gate 		cp = strchr(np, '%');
2170Sstevel@tonic-gate 	if (cp)
2180Sstevel@tonic-gate 		*cp = 0;
2190Sstevel@tonic-gate 	if (debug) fprintf(stderr, "host %s, name %s\n", hp, np);
2200Sstevel@tonic-gate 	snprintf(result, sizeof (result), "%s@%s.UUCP", np, hp);
2210Sstevel@tonic-gate 	if (debug) fprintf(stderr, "unuucp returns %s\n", result);
2220Sstevel@tonic-gate 	return savestr(result);
2230Sstevel@tonic-gate }
2240Sstevel@tonic-gate 
2250Sstevel@tonic-gate /*
2260Sstevel@tonic-gate  * Turn a network machine name into a unique character
2270Sstevel@tonic-gate  */
2280Sstevel@tonic-gate static int
netlook(char machine[],int attnet)2290Sstevel@tonic-gate netlook(char machine[], int attnet)
2300Sstevel@tonic-gate {
2310Sstevel@tonic-gate 	register struct netmach *np;
2320Sstevel@tonic-gate 	register char *cp, *cp2;
2330Sstevel@tonic-gate 	char nbuf[BUFSIZ];
2340Sstevel@tonic-gate 
2350Sstevel@tonic-gate 	/*
2360Sstevel@tonic-gate 	 * Make into lower case.
2370Sstevel@tonic-gate 	 */
2380Sstevel@tonic-gate 	for (cp = machine, cp2 = nbuf;
2390Sstevel@tonic-gate 	     *cp && cp2 < &nbuf[BUFSIZ-1];
2400Sstevel@tonic-gate 	     *cp2++ = tolower(*cp++))
2410Sstevel@tonic-gate 		/*nothing*/;
2420Sstevel@tonic-gate 	*cp2 = 0;
2430Sstevel@tonic-gate 
2440Sstevel@tonic-gate 	/*
2450Sstevel@tonic-gate 	 * If a single letter machine, look through those first.
2460Sstevel@tonic-gate 	 */
2470Sstevel@tonic-gate 
2480Sstevel@tonic-gate 	if (strlen(nbuf) == 1)
2490Sstevel@tonic-gate 		for (np = netmach; np->nt_mid != 0; np++)
2500Sstevel@tonic-gate 			if (np->nt_mid == nbuf[0])
2510Sstevel@tonic-gate 				return(nbuf[0]);
2520Sstevel@tonic-gate 
2530Sstevel@tonic-gate 	/*
2540Sstevel@tonic-gate 	 * Look for usual name
2550Sstevel@tonic-gate 	 */
2560Sstevel@tonic-gate 
2570Sstevel@tonic-gate 	for (np = netmach; np->nt_mid != 0; np++)
2580Sstevel@tonic-gate 		if (strcmp(np->nt_machine, nbuf) == 0)
2590Sstevel@tonic-gate 			return(np->nt_mid);
2600Sstevel@tonic-gate 
2610Sstevel@tonic-gate 	/*
2620Sstevel@tonic-gate 	 * Look in side hash table.
2630Sstevel@tonic-gate 	 */
2640Sstevel@tonic-gate 
2650Sstevel@tonic-gate 	return(mstash(nbuf, attnet));
2660Sstevel@tonic-gate }
2670Sstevel@tonic-gate 
2680Sstevel@tonic-gate #ifdef OPTIM
2690Sstevel@tonic-gate /*
2700Sstevel@tonic-gate  * Turn a network unique character identifier into a network name.
2710Sstevel@tonic-gate  */
2720Sstevel@tonic-gate 
2730Sstevel@tonic-gate static char *
netname(int mid)2740Sstevel@tonic-gate netname(int mid)
2750Sstevel@tonic-gate {
2760Sstevel@tonic-gate 	register struct netmach *np;
2770Sstevel@tonic-gate 
2780Sstevel@tonic-gate 	if (mid & 0200)
2790Sstevel@tonic-gate 		return(mlook(mid));
2800Sstevel@tonic-gate 	for (np = netmach; np->nt_mid != 0; np++)
2810Sstevel@tonic-gate 		if (np->nt_mid == mid)
2820Sstevel@tonic-gate 			return(np->nt_machine);
2830Sstevel@tonic-gate 	return(NOSTR);
2840Sstevel@tonic-gate }
2850Sstevel@tonic-gate #endif
2860Sstevel@tonic-gate 
2870Sstevel@tonic-gate /*
2880Sstevel@tonic-gate  * Deal with arpa net addresses.  The way this is done is strange.
2890Sstevel@tonic-gate  * name contains an "@" or "%".  Look up the machine after it in
2900Sstevel@tonic-gate  * the hash table.  If it isn't found, return name unmolested.
2910Sstevel@tonic-gate  * If ???, return name unmolested.
2920Sstevel@tonic-gate  * Otherwise, delete the "@" or "%" and the machine after it from
2930Sstevel@tonic-gate  * name, and return the new string.
2940Sstevel@tonic-gate  */
2950Sstevel@tonic-gate static char *
arpafix(char name[],char from[])2960Sstevel@tonic-gate arpafix(char name[], char from[])
2970Sstevel@tonic-gate {
2980Sstevel@tonic-gate 	register char *cp;
2990Sstevel@tonic-gate 	register int arpamach;
3000Sstevel@tonic-gate 	char newname[BUFSIZ];
3010Sstevel@tonic-gate 
3020Sstevel@tonic-gate 	if (debug) {
3030Sstevel@tonic-gate 		fprintf(stderr, "arpafix(%s, %s)\n", name, from);
3040Sstevel@tonic-gate 	}
3050Sstevel@tonic-gate 	cp = strrchr(name, '@');
3060Sstevel@tonic-gate 	if (cp == NOSTR)
3070Sstevel@tonic-gate 		cp = strrchr(name, '%');
3080Sstevel@tonic-gate 	if (cp == NOSTR) {
3090Sstevel@tonic-gate 		fprintf(stderr,
3100Sstevel@tonic-gate 		    gettext("Something's amiss -- no @ or %% in arpafix\n"));
3110Sstevel@tonic-gate 		return(name);
3120Sstevel@tonic-gate 	}
3130Sstevel@tonic-gate 	cp++;
3140Sstevel@tonic-gate 	arpamach = netlook(cp, '@');
3150Sstevel@tonic-gate 	if (debug)
3160Sstevel@tonic-gate 		fprintf(stderr,
3170Sstevel@tonic-gate 		    "cp '%s', arpamach %o, nettypes arpamach %o LOCAL %o\n",
3180Sstevel@tonic-gate 		    cp, arpamach, nettype(arpamach), nettype(LOCAL));
3190Sstevel@tonic-gate 	if (arpamach == 0) {
3200Sstevel@tonic-gate 		if (debug)
3210Sstevel@tonic-gate 			fprintf(stderr, "machine %s unknown, uses: %s\n",
3220Sstevel@tonic-gate 			    cp, name);
3230Sstevel@tonic-gate 		return(name);
3240Sstevel@tonic-gate 	}
3250Sstevel@tonic-gate 	if (((nettype(arpamach) & nettype(LOCAL)) & ~AN) == 0) {
3260Sstevel@tonic-gate 		if (debug)
3270Sstevel@tonic-gate 			fprintf(stderr, "machine %s known but remote, uses: %s\n",
3280Sstevel@tonic-gate 			    cp, name);
3290Sstevel@tonic-gate 		return(name);
3300Sstevel@tonic-gate 	}
3310Sstevel@tonic-gate 	nstrcpy(newname, sizeof (newname), name);
3320Sstevel@tonic-gate 	cp = strrchr(newname, '@');
3330Sstevel@tonic-gate 	if (cp == NOSTR)
3340Sstevel@tonic-gate 		cp = strrchr(newname, '%');
3350Sstevel@tonic-gate 	*cp = 0;
3360Sstevel@tonic-gate 	if (debug) fprintf(stderr, "local address, return '%s'\n", newname);
3370Sstevel@tonic-gate 	return(savestr(newname));
3380Sstevel@tonic-gate }
3390Sstevel@tonic-gate 
3400Sstevel@tonic-gate /*
3410Sstevel@tonic-gate  * We have name with no @'s in it, and from with @'s.
3420Sstevel@tonic-gate  * Assume that name is meaningful only on the site in from,
3430Sstevel@tonic-gate  * and return "name@site_in_from".
3440Sstevel@tonic-gate  */
3450Sstevel@tonic-gate static char *
makeremote(char name[],char from[])3460Sstevel@tonic-gate makeremote(char name[], char from[])
3470Sstevel@tonic-gate {
3480Sstevel@tonic-gate 	register char *cp;
3490Sstevel@tonic-gate 	char rbuf[BUFSIZ];
3500Sstevel@tonic-gate 
3510Sstevel@tonic-gate 	if (!value("makeremote"))
3520Sstevel@tonic-gate 		return(name);
3530Sstevel@tonic-gate 	if (debug) fprintf(stderr, "makeremote(%s, %s) returns ", name, from);
3540Sstevel@tonic-gate 	cp = strrchr(from, '@');
3550Sstevel@tonic-gate 	if (cp == NOSTR)
3560Sstevel@tonic-gate 		cp = strrchr(from, '%');
3570Sstevel@tonic-gate 	snprintf(rbuf, sizeof (rbuf), "%s%s", name, cp);
3580Sstevel@tonic-gate 	if (debug) fprintf(stderr, "%s\n", rbuf);
3590Sstevel@tonic-gate 	return(savestr(rbuf));
3600Sstevel@tonic-gate }
3610Sstevel@tonic-gate 
3620Sstevel@tonic-gate /*
3630Sstevel@tonic-gate  * Take a network machine descriptor and find the types of connected
3640Sstevel@tonic-gate  * nets and return it.
3650Sstevel@tonic-gate  */
3660Sstevel@tonic-gate static int
nettype(int mid)3670Sstevel@tonic-gate nettype(int mid)
3680Sstevel@tonic-gate {
3690Sstevel@tonic-gate 	register struct netmach *np;
3700Sstevel@tonic-gate 
3710Sstevel@tonic-gate 	if (mid & 0200)
3720Sstevel@tonic-gate 		return(mtype(mid));
3730Sstevel@tonic-gate 	for (np = netmach; np->nt_mid != 0; np++)
3740Sstevel@tonic-gate 		if (np->nt_mid == mid)
3750Sstevel@tonic-gate 			return(np->nt_type);
3760Sstevel@tonic-gate 	return(0);
3770Sstevel@tonic-gate }
3780Sstevel@tonic-gate 
3790Sstevel@tonic-gate /*
3800Sstevel@tonic-gate  * Hashing routines to salt away machines seen scanning
3810Sstevel@tonic-gate  * networks paths that we don't know about.
3820Sstevel@tonic-gate  */
3830Sstevel@tonic-gate 
3840Sstevel@tonic-gate #define	XHSIZE		97		/* Size of extra hash table */
3850Sstevel@tonic-gate #define	NXMID		(XHSIZE*3/4)	/* Max extra machines */
3860Sstevel@tonic-gate 
3870Sstevel@tonic-gate struct xtrahash {
3880Sstevel@tonic-gate 	char	*xh_name;		/* Name of machine */
3890Sstevel@tonic-gate 	short	xh_mid;			/* Machine ID */
3900Sstevel@tonic-gate 	short	xh_attnet;		/* Attached networks */
3910Sstevel@tonic-gate } xtrahash[XHSIZE];
3920Sstevel@tonic-gate 
3930Sstevel@tonic-gate static struct xtrahash	*xtab[XHSIZE];		/* F: mid-->machine name */
3940Sstevel@tonic-gate 
3950Sstevel@tonic-gate static short	midfree;			/* Next free machine id */
3960Sstevel@tonic-gate 
3970Sstevel@tonic-gate /*
3980Sstevel@tonic-gate  * Initialize the extra host hash table.
3990Sstevel@tonic-gate  * Called by sreset.
4000Sstevel@tonic-gate  */
4010Sstevel@tonic-gate void
minit(void)4020Sstevel@tonic-gate minit(void)
4030Sstevel@tonic-gate {
4040Sstevel@tonic-gate 	register struct xtrahash *xp, **tp;
4050Sstevel@tonic-gate 
4060Sstevel@tonic-gate 	midfree = 0;
4070Sstevel@tonic-gate 	tp = &xtab[0];
4080Sstevel@tonic-gate 	for (xp = &xtrahash[0]; xp < &xtrahash[XHSIZE]; xp++) {
4090Sstevel@tonic-gate 		xp->xh_name = NOSTR;
4100Sstevel@tonic-gate 		xp->xh_mid = 0;
4110Sstevel@tonic-gate 		xp->xh_attnet = 0;
4120Sstevel@tonic-gate 		*tp++ = (struct xtrahash *) 0;
4130Sstevel@tonic-gate 	}
4140Sstevel@tonic-gate }
4150Sstevel@tonic-gate 
4160Sstevel@tonic-gate /*
4170Sstevel@tonic-gate  * Stash a net name in the extra host hash table.
4180Sstevel@tonic-gate  * If a new entry is put in the hash table, deduce what
4190Sstevel@tonic-gate  * net the machine is attached to from the net character.
4200Sstevel@tonic-gate  *
4210Sstevel@tonic-gate  * If the machine is already known, add the given attached
4220Sstevel@tonic-gate  * net to those already known.
4230Sstevel@tonic-gate  */
4240Sstevel@tonic-gate static int
mstash(char name[],int attnet)4250Sstevel@tonic-gate mstash(char name[], int attnet)
4260Sstevel@tonic-gate {
4270Sstevel@tonic-gate 	register struct xtrahash *xp;
4280Sstevel@tonic-gate 	int x;
4290Sstevel@tonic-gate 
4300Sstevel@tonic-gate 	xp = xlocate(name);
4310Sstevel@tonic-gate 	if (xp == (struct xtrahash *) 0) {
4320Sstevel@tonic-gate 		printf(gettext("Ran out of machine id spots\n"));
4330Sstevel@tonic-gate 		return(0);
4340Sstevel@tonic-gate 	}
4350Sstevel@tonic-gate 	if (xp->xh_name == NOSTR) {
4360Sstevel@tonic-gate 		if (midfree >= XHSIZE) {
4370Sstevel@tonic-gate 			printf(gettext("Out of machine ids\n"));
4380Sstevel@tonic-gate 			return(0);
4390Sstevel@tonic-gate 		}
4400Sstevel@tonic-gate 		xtab[midfree] = xp;
4410Sstevel@tonic-gate 		xp->xh_name = savestr(name);
4420Sstevel@tonic-gate 		xp->xh_mid = 0200 + midfree++;
4430Sstevel@tonic-gate 	}
4440Sstevel@tonic-gate 	x = ntype(attnet);
4450Sstevel@tonic-gate 	if (x == 0)
4460Sstevel@tonic-gate 		xp->xh_attnet |= AN;
4470Sstevel@tonic-gate 	else
4480Sstevel@tonic-gate 		xp->xh_attnet |= x;
4490Sstevel@tonic-gate 	return(xp->xh_mid);
4500Sstevel@tonic-gate }
4510Sstevel@tonic-gate 
4520Sstevel@tonic-gate /*
4530Sstevel@tonic-gate  * Search for the given name in the hash table
4540Sstevel@tonic-gate  * and return the pointer to it if found, or to the first
4550Sstevel@tonic-gate  * empty slot if not found.
4560Sstevel@tonic-gate  *
4570Sstevel@tonic-gate  * If no free slots can be found, return 0.
4580Sstevel@tonic-gate  */
4590Sstevel@tonic-gate 
4600Sstevel@tonic-gate static struct xtrahash *
xlocate(char name[])4610Sstevel@tonic-gate xlocate(char name[])
4620Sstevel@tonic-gate {
4630Sstevel@tonic-gate 	register int h, q, i;
4640Sstevel@tonic-gate 	register char *cp;
4650Sstevel@tonic-gate 	register struct xtrahash *xp;
4660Sstevel@tonic-gate 
4670Sstevel@tonic-gate 	for (h = 0, cp = name; *cp; h = (h << 2) + *cp++)
4680Sstevel@tonic-gate 		;
4690Sstevel@tonic-gate 	if (h < 0 && (h = -h) < 0)
4700Sstevel@tonic-gate 		h = 0;
4710Sstevel@tonic-gate 	h = h % XHSIZE;
4720Sstevel@tonic-gate 	cp = name;
4730Sstevel@tonic-gate 	for (i = 0, q = 0; q < XHSIZE; i++, q = i * i) {
4740Sstevel@tonic-gate 		xp = &xtrahash[(h + q) % XHSIZE];
4750Sstevel@tonic-gate 		if (xp->xh_name == NOSTR)
4760Sstevel@tonic-gate 			return(xp);
4770Sstevel@tonic-gate 		if (strcmp(cp, xp->xh_name) == 0)
4780Sstevel@tonic-gate 			return(xp);
4790Sstevel@tonic-gate 		if (h - q < 0)
4800Sstevel@tonic-gate 			h += XHSIZE;
4810Sstevel@tonic-gate 		xp = &xtrahash[(h - q) % XHSIZE];
4820Sstevel@tonic-gate 		if (xp->xh_name == NOSTR)
4830Sstevel@tonic-gate 			return(xp);
4840Sstevel@tonic-gate 		if (strcmp(cp, xp->xh_name) == 0)
4850Sstevel@tonic-gate 			return(xp);
4860Sstevel@tonic-gate 	}
4870Sstevel@tonic-gate 	return((struct xtrahash *) 0);
4880Sstevel@tonic-gate }
4890Sstevel@tonic-gate 
4900Sstevel@tonic-gate #ifdef OPTIM
4910Sstevel@tonic-gate /*
4920Sstevel@tonic-gate  * Return the name from the extra host hash table corresponding
4930Sstevel@tonic-gate  * to the passed machine id.
4940Sstevel@tonic-gate  */
4950Sstevel@tonic-gate 
4960Sstevel@tonic-gate static char *
mlook(int mid)4970Sstevel@tonic-gate mlook(int mid)
4980Sstevel@tonic-gate {
4990Sstevel@tonic-gate 	register int m;
5000Sstevel@tonic-gate 
5010Sstevel@tonic-gate 	if ((mid & 0200) == 0)
5020Sstevel@tonic-gate 		return(NOSTR);
5030Sstevel@tonic-gate 	m = mid & 0177;
5040Sstevel@tonic-gate 	if (m >= midfree) {
5050Sstevel@tonic-gate 		printf(gettext("Use made of undefined machine id\n"));
5060Sstevel@tonic-gate 		return(NOSTR);
5070Sstevel@tonic-gate 	}
5080Sstevel@tonic-gate 	return(xtab[m]->xh_name);
5090Sstevel@tonic-gate }
5100Sstevel@tonic-gate #endif
5110Sstevel@tonic-gate 
5120Sstevel@tonic-gate /*
5130Sstevel@tonic-gate  * Return the bit mask of net's that the given extra host machine
5140Sstevel@tonic-gate  * id has so far.
5150Sstevel@tonic-gate  */
5160Sstevel@tonic-gate static int
mtype(int mid)5170Sstevel@tonic-gate mtype(int mid)
5180Sstevel@tonic-gate {
5190Sstevel@tonic-gate 	register int m;
5200Sstevel@tonic-gate 
5210Sstevel@tonic-gate 	if ((mid & 0200) == 0)
5220Sstevel@tonic-gate 		return(0);
5230Sstevel@tonic-gate 	m = mid & 0177;
5240Sstevel@tonic-gate 	if (m >= midfree) {
5250Sstevel@tonic-gate 		printf(gettext("Use made of undefined machine id\n"));
5260Sstevel@tonic-gate 		return(0);
5270Sstevel@tonic-gate 	}
5280Sstevel@tonic-gate 	return(xtab[m]->xh_attnet);
5290Sstevel@tonic-gate }
5300Sstevel@tonic-gate 
5310Sstevel@tonic-gate #ifdef	OPTIM
5320Sstevel@tonic-gate /*
5330Sstevel@tonic-gate  * Take a network name and optimize it.  This gloriously messy
5340Sstevel@tonic-gate  * operation takes place as follows:  the name with machine names
5350Sstevel@tonic-gate  * in it is tokenized by mapping each machine name into a single
5360Sstevel@tonic-gate  * character machine id (netlook).  The separator characters (network
5370Sstevel@tonic-gate  * metacharacters) are left intact.  The last component of the network
5380Sstevel@tonic-gate  * name is stripped off and assumed to be the destination user name --
5390Sstevel@tonic-gate  * it does not participate in the optimization.  As an example, the
5400Sstevel@tonic-gate  * name "res!vax!res!uvax!bill" becomes, tokenized,
5410Sstevel@tonic-gate  * "r!x!r!v!" and "bill"  A low level routine, optim1, fixes up the
5420Sstevel@tonic-gate  * network part (eg, "r!x!r!v!"), then we convert back to network
5430Sstevel@tonic-gate  * machine names and tack the user name on the end.
5440Sstevel@tonic-gate  *
5450Sstevel@tonic-gate  * The result of this is copied into the parameter "name"
5460Sstevel@tonic-gate  */
5470Sstevel@tonic-gate 
5480Sstevel@tonic-gate static void
optim(char net[],char name[])5490Sstevel@tonic-gate optim(char net[], char name[])
5500Sstevel@tonic-gate {
5510Sstevel@tonic-gate 	char netcomp[BUFSIZ], netstr[STSIZ], xfstr[STSIZ];
5520Sstevel@tonic-gate 	register char *cp, *cp2;
5530Sstevel@tonic-gate 	register int c;
5540Sstevel@tonic-gate 
5550Sstevel@tonic-gate 	if (debug) fprintf(stderr, "optim(%s, %s) called\n", net, name);
5560Sstevel@tonic-gate 	*netstr = '\0';
5570Sstevel@tonic-gate 	cp = net;
5580Sstevel@tonic-gate 	for (;;) {
5590Sstevel@tonic-gate 		/*
5600Sstevel@tonic-gate 		 * Rip off next path component into netcomp
5610Sstevel@tonic-gate 		 */
5620Sstevel@tonic-gate 		cp2 = netcomp;
5630Sstevel@tonic-gate 		while (*cp && !any(*cp, metanet))
5640Sstevel@tonic-gate 			*cp2++ = *cp++;
5650Sstevel@tonic-gate 		*cp2 = 0;
5660Sstevel@tonic-gate 		/*
5670Sstevel@tonic-gate 		 * If we hit null byte, then we just scanned
5680Sstevel@tonic-gate 		 * the destination user name.  Go off and optimize
5690Sstevel@tonic-gate 		 * if its so.
5700Sstevel@tonic-gate 		 */
5710Sstevel@tonic-gate 		if (*cp == 0)
5720Sstevel@tonic-gate 			break;
5730Sstevel@tonic-gate 		if ((c = netlook(netcomp, *cp)) == 0) {
5740Sstevel@tonic-gate 			printf(gettext("No host named \"%s\"\n"), netcomp);
5750Sstevel@tonic-gate err:
5760Sstevel@tonic-gate 			nstrcpy(name, BUFSIZ, net);
5770Sstevel@tonic-gate 			return;
5780Sstevel@tonic-gate 		}
5790Sstevel@tonic-gate 		stradd(name, BUFSIZ, c);
5800Sstevel@tonic-gate 		stradd(name, BUFSIZ, *cp++);
5810Sstevel@tonic-gate 		/*
5820Sstevel@tonic-gate 		 * If multiple network separators given,
5830Sstevel@tonic-gate 		 * throw away the extras.
5840Sstevel@tonic-gate 		 */
5850Sstevel@tonic-gate 		while (any(*cp, metanet))
5860Sstevel@tonic-gate 			cp++;
5870Sstevel@tonic-gate 	}
5880Sstevel@tonic-gate 	if (strlen(netcomp) == 0) {
5890Sstevel@tonic-gate 		printf(gettext("net name syntax\n"));
5900Sstevel@tonic-gate 		goto err;
5910Sstevel@tonic-gate 	}
5920Sstevel@tonic-gate 	if (debug) fprintf(stderr, "optim1(%s,%s) called\n", netstr, xfstr);
5930Sstevel@tonic-gate 	optim1(netstr, xfstr);
5940Sstevel@tonic-gate 	if (debug) fprintf(stderr, "optim1(%s,%s) returns\n", netstr, xfstr);
5950Sstevel@tonic-gate 
5960Sstevel@tonic-gate 	/*
5970Sstevel@tonic-gate 	 * Convert back to machine names.
5980Sstevel@tonic-gate 	 */
5990Sstevel@tonic-gate 
6000Sstevel@tonic-gate 	cp = xfstr;
6010Sstevel@tonic-gate 	*name = '\0';
6020Sstevel@tonic-gate 	while (*cp) {
6030Sstevel@tonic-gate 		if ((cp2 = netname(*cp++)) == NOSTR) {
6040Sstevel@tonic-gate 			printf(gettext("Made up bad net name\n"));
6050Sstevel@tonic-gate 			printf(gettext("Machine code %c (0%o)\n"), cp[-1],
6060Sstevel@tonic-gate cp[-1]);
6070Sstevel@tonic-gate 			printf(gettext("Sorry.\n"));
6080Sstevel@tonic-gate 			goto err;
6090Sstevel@tonic-gate 		}
6100Sstevel@tonic-gate 		nstrcat(name, BUFSIZ, cp2);
6110Sstevel@tonic-gate 		stradd(name, BUFSIZ, *cp++);
6120Sstevel@tonic-gate 	}
6130Sstevel@tonic-gate 	nstrcat(name, BUFSIZ, netcomp);
6140Sstevel@tonic-gate 	if (debug) fprintf(stderr, "optim returns %s in name\n", name);
6150Sstevel@tonic-gate }
6160Sstevel@tonic-gate 
6170Sstevel@tonic-gate /*
6180Sstevel@tonic-gate  * Take a string of network machine id's and separators and
6190Sstevel@tonic-gate  * optimize them.  We process these by pulling off maximal
6200Sstevel@tonic-gate  * leading strings of the same type, passing these to the appropriate
6210Sstevel@tonic-gate  * optimizer and concatenating the results.
6220Sstevel@tonic-gate  */
6230Sstevel@tonic-gate 
6240Sstevel@tonic-gate static void
optim1(char netstr[],char name[])6250Sstevel@tonic-gate optim1(char netstr[], char name[])
6260Sstevel@tonic-gate {
6270Sstevel@tonic-gate 	char path[STSIZ], rpath[STSIZ];
6280Sstevel@tonic-gate 	register char *cp, *cp2;
6290Sstevel@tonic-gate 	register int tp, nc;
6300Sstevel@tonic-gate 
6310Sstevel@tonic-gate 	cp = netstr;
6320Sstevel@tonic-gate 	prefer(cp);
6330Sstevel@tonic-gate 	*name  = '\0';
6340Sstevel@tonic-gate 	/*
6350Sstevel@tonic-gate 	 * If the address ultimately points back to us,
6360Sstevel@tonic-gate 	 * just return a null network path.
6370Sstevel@tonic-gate 	 */
6380Sstevel@tonic-gate 	if ((int)strlen(cp) > 1 && cp[strlen(cp) - 2] == LOCAL)
6390Sstevel@tonic-gate 		return;
6400Sstevel@tonic-gate 	while (*cp != 0) {
6410Sstevel@tonic-gate 		*path = '\0';
6420Sstevel@tonic-gate 
6430Sstevel@tonic-gate 		tp = ntype(cp[1]);
6440Sstevel@tonic-gate 		nc = cp[1];
6450Sstevel@tonic-gate 		while (*cp && tp == ntype(cp[1])) {
6460Sstevel@tonic-gate 			stradd(path, sizeof (path), *cp++);
6470Sstevel@tonic-gate 			cp++;
6480Sstevel@tonic-gate 		}
6490Sstevel@tonic-gate 		switch (netkind(tp)) {
6500Sstevel@tonic-gate 		default:
6510Sstevel@tonic-gate 			nstrcpy(rpath, sizeof (rpath), path);
6520Sstevel@tonic-gate 			break;
6530Sstevel@tonic-gate 
6540Sstevel@tonic-gate 		case IMPLICIT:
6550Sstevel@tonic-gate 			optimimp(path, rpath);
6560Sstevel@tonic-gate 			break;
6570Sstevel@tonic-gate 
6580Sstevel@tonic-gate 		case EXPLICIT:
6590Sstevel@tonic-gate 			optimex(path, rpath);
6600Sstevel@tonic-gate 			break;
6610Sstevel@tonic-gate 		}
6620Sstevel@tonic-gate 		for (cp2 = rpath; *cp2 != 0; cp2++) {
6630Sstevel@tonic-gate 			stradd(name, BUFSIZ, *cp2);
6640Sstevel@tonic-gate 			stradd(name, BUFSIZ, nc);
6650Sstevel@tonic-gate 		}
6660Sstevel@tonic-gate 	}
6670Sstevel@tonic-gate 	optiboth(name);
6680Sstevel@tonic-gate 	prefer(name);
6690Sstevel@tonic-gate }
670*18Srobbin #endif	/* OPTIM */
6710Sstevel@tonic-gate 
6720Sstevel@tonic-gate /*
6730Sstevel@tonic-gate  * Return the network of the separator --
6740Sstevel@tonic-gate  *	AN for arpa net
6750Sstevel@tonic-gate  *	BN for Bell labs net	(e.g. UUCP, NOT Berknet)
6760Sstevel@tonic-gate  *	SN for Schmidt net	(Berknet)
6770Sstevel@tonic-gate  *	0 if we don't know.
6780Sstevel@tonic-gate  */
6790Sstevel@tonic-gate static int
ntype(register int nc)6800Sstevel@tonic-gate ntype(register int nc)
6810Sstevel@tonic-gate {
6820Sstevel@tonic-gate 	register struct ntypetab *np;
6830Sstevel@tonic-gate 
6840Sstevel@tonic-gate 	for (np = ntypetab; np->nt_char != 0; np++)
6850Sstevel@tonic-gate 		if (np->nt_char == nc)
6860Sstevel@tonic-gate 			return(np->nt_bcode);
6870Sstevel@tonic-gate 	return(0);
6880Sstevel@tonic-gate }
6890Sstevel@tonic-gate 
6900Sstevel@tonic-gate #ifdef	OPTIM
6910Sstevel@tonic-gate /*
6920Sstevel@tonic-gate  * Return the kind of routing used for the particular net
6930Sstevel@tonic-gate  * EXPLICIT means explicitly routed
6940Sstevel@tonic-gate  * IMPLICIT means implicitly routed
6950Sstevel@tonic-gate  * 0 means don't know
6960Sstevel@tonic-gate  */
6970Sstevel@tonic-gate 
6980Sstevel@tonic-gate static int
netkind(register int nt)6990Sstevel@tonic-gate netkind(register int nt)
7000Sstevel@tonic-gate {
7010Sstevel@tonic-gate 	register struct nkindtab *np;
7020Sstevel@tonic-gate 
7030Sstevel@tonic-gate 	for (np = nkindtab; np->nk_type != 0; np++)
7040Sstevel@tonic-gate 		if (np->nk_type == nt)
7050Sstevel@tonic-gate 			return(np->nk_kind);
7060Sstevel@tonic-gate 	return(0);
7070Sstevel@tonic-gate }
7080Sstevel@tonic-gate 
7090Sstevel@tonic-gate /*
7100Sstevel@tonic-gate  * Do name optimization for an explicitly routed network (eg uucp).
7110Sstevel@tonic-gate  */
7120Sstevel@tonic-gate 
7130Sstevel@tonic-gate static int
optimex(char net[],char name[])7140Sstevel@tonic-gate optimex(char net[], char name[])
7150Sstevel@tonic-gate {
7160Sstevel@tonic-gate 	register char *cp, *rp;
7170Sstevel@tonic-gate 	register int m;
7180Sstevel@tonic-gate 
7190Sstevel@tonic-gate 	nstrcpy(name, STSIZ, net);
7200Sstevel@tonic-gate 	cp = name;
7210Sstevel@tonic-gate 	if (strlen(cp) == 0)
7220Sstevel@tonic-gate 		return(-1);
7230Sstevel@tonic-gate 	if (cp[strlen(cp)-1] == LOCAL) {
7240Sstevel@tonic-gate 		name[0] = 0;
7250Sstevel@tonic-gate 		return(0);
7260Sstevel@tonic-gate 	}
7270Sstevel@tonic-gate 	for (cp = name; *cp; cp++) {
7280Sstevel@tonic-gate 		m = *cp;
7290Sstevel@tonic-gate 		rp = strrchr(cp+1, m);
7300Sstevel@tonic-gate 		if (rp != NOSTR)
7310Sstevel@tonic-gate 			strcpy(cp, rp);
7320Sstevel@tonic-gate 	}
7330Sstevel@tonic-gate 	return(0);
7340Sstevel@tonic-gate }
7350Sstevel@tonic-gate 
7360Sstevel@tonic-gate /*
7370Sstevel@tonic-gate  * Do name optimization for implicitly routed network (eg, arpanet).
7380Sstevel@tonic-gate  */
7390Sstevel@tonic-gate 
7400Sstevel@tonic-gate static int
optimimp(char net[],char name[])7410Sstevel@tonic-gate optimimp(char net[], char name[])
7420Sstevel@tonic-gate {
7430Sstevel@tonic-gate 	register char *cp;
7440Sstevel@tonic-gate 	register char m;
7450Sstevel@tonic-gate 
7460Sstevel@tonic-gate 	cp = net;
7470Sstevel@tonic-gate 	if (strlen(cp) == 0)
7480Sstevel@tonic-gate 		return(-1);
7490Sstevel@tonic-gate 	m = cp[strlen(cp) - 1];
7500Sstevel@tonic-gate 	if (m == LOCAL) {
7510Sstevel@tonic-gate 		*name = '\0';
7520Sstevel@tonic-gate 		return(0);
7530Sstevel@tonic-gate 	}
7540Sstevel@tonic-gate 	name[0] = m;
7550Sstevel@tonic-gate 	name[1] = 0;
7560Sstevel@tonic-gate 	return(0);
7570Sstevel@tonic-gate }
7580Sstevel@tonic-gate 
7590Sstevel@tonic-gate /*
7600Sstevel@tonic-gate  * Perform global optimization on the given network path.
7610Sstevel@tonic-gate  * The trick here is to look ahead to see if there are any loops
7620Sstevel@tonic-gate  * in the path and remove them.  The interpretation of loops is
7630Sstevel@tonic-gate  * more strict here than in optimex since both the machine and net
7640Sstevel@tonic-gate  * type must match.
7650Sstevel@tonic-gate  */
7660Sstevel@tonic-gate 
7670Sstevel@tonic-gate static void
optiboth(char net[])7680Sstevel@tonic-gate optiboth(char net[])
7690Sstevel@tonic-gate {
7700Sstevel@tonic-gate 	register char *cp, *cp2;
7710Sstevel@tonic-gate 
7720Sstevel@tonic-gate 	cp = net;
7730Sstevel@tonic-gate 	if (strlen(cp) == 0)
7740Sstevel@tonic-gate 		return;
7750Sstevel@tonic-gate 	if (((int)strlen(cp) % 2) != 0) {
7760Sstevel@tonic-gate 		printf(gettext("Strange arg to optiboth\n"));
7770Sstevel@tonic-gate 		return;
7780Sstevel@tonic-gate 	}
7790Sstevel@tonic-gate 	while (*cp) {
7800Sstevel@tonic-gate 		cp2 = rpair(cp+2, *cp);
7810Sstevel@tonic-gate 		if (cp2 != NOSTR)
7820Sstevel@tonic-gate 			strcpy(cp, cp2);
7830Sstevel@tonic-gate 		cp += 2;
7840Sstevel@tonic-gate 	}
7850Sstevel@tonic-gate }
7860Sstevel@tonic-gate 
7870Sstevel@tonic-gate /*
7880Sstevel@tonic-gate  * Find the rightmost instance of the given (machine, type) pair.
7890Sstevel@tonic-gate  */
7900Sstevel@tonic-gate 
7910Sstevel@tonic-gate static char *
rpair(char str[],int mach)7920Sstevel@tonic-gate rpair(char str[], int mach)
7930Sstevel@tonic-gate {
7940Sstevel@tonic-gate 	register char *cp, *last;
7950Sstevel@tonic-gate 
7960Sstevel@tonic-gate 	cp = str;
7970Sstevel@tonic-gate 	last = NOSTR;
7980Sstevel@tonic-gate 	while (*cp) {
7990Sstevel@tonic-gate 		if (*cp == mach)
8000Sstevel@tonic-gate 			last = cp;
8010Sstevel@tonic-gate 		cp += 2;
8020Sstevel@tonic-gate 	}
8030Sstevel@tonic-gate 	return(last);
8040Sstevel@tonic-gate }
8050Sstevel@tonic-gate 
8060Sstevel@tonic-gate /*
8070Sstevel@tonic-gate  * Change the network separators in the given network path
8080Sstevel@tonic-gate  * to the preferred network transmission means.
8090Sstevel@tonic-gate  */
8100Sstevel@tonic-gate 
8110Sstevel@tonic-gate static void
prefer(char name[])8120Sstevel@tonic-gate prefer(char name[])
8130Sstevel@tonic-gate {
8140Sstevel@tonic-gate 	register char *cp, n;
8150Sstevel@tonic-gate 	register int state;
8160Sstevel@tonic-gate 
8170Sstevel@tonic-gate 	state = LOCAL;
8180Sstevel@tonic-gate 	for (cp = name; *cp; cp += 2) {
8190Sstevel@tonic-gate 		n = best(state, *cp);
8200Sstevel@tonic-gate 		if (n)
8210Sstevel@tonic-gate 			cp[1] = n;
8220Sstevel@tonic-gate 		state = *cp;
8230Sstevel@tonic-gate 	}
8240Sstevel@tonic-gate }
8250Sstevel@tonic-gate 
8260Sstevel@tonic-gate /*
8270Sstevel@tonic-gate  * Return the best network separator for the given machine pair.
8280Sstevel@tonic-gate  */
8290Sstevel@tonic-gate 
8300Sstevel@tonic-gate static char
best(int src,int dest)8310Sstevel@tonic-gate best(int src, int dest)
8320Sstevel@tonic-gate {
8330Sstevel@tonic-gate 	register int dtype, stype;
8340Sstevel@tonic-gate 	register struct netorder *np;
8350Sstevel@tonic-gate 
8360Sstevel@tonic-gate 	stype = nettype(src);
8370Sstevel@tonic-gate 	dtype = nettype(dest);
8380Sstevel@tonic-gate 	fflush(stdout);
8390Sstevel@tonic-gate 	if (stype == 0 || dtype == 0) {
8400Sstevel@tonic-gate 		printf(gettext("ERROR:  unknown internal machine id\n"));
8410Sstevel@tonic-gate 		return(0);
8420Sstevel@tonic-gate 	}
8430Sstevel@tonic-gate 	if ((stype & dtype) == 0)
8440Sstevel@tonic-gate 		return(0);
8450Sstevel@tonic-gate 	np = &netorder[0];
8460Sstevel@tonic-gate 	while ((np->no_stat & stype & dtype) == 0)
8470Sstevel@tonic-gate 		np++;
8480Sstevel@tonic-gate 	return(np->no_char);
8490Sstevel@tonic-gate }
850*18Srobbin #endif	/* OPTIM */
8510Sstevel@tonic-gate 
8520Sstevel@tonic-gate #ifdef notdef
8530Sstevel@tonic-gate /*
8540Sstevel@tonic-gate  * Code to twist around arpa net names.
8550Sstevel@tonic-gate  */
8560Sstevel@tonic-gate 
8570Sstevel@tonic-gate #define WORD 257			/* Token for a string */
8580Sstevel@tonic-gate 
8590Sstevel@tonic-gate static	char netbuf[256];
8600Sstevel@tonic-gate static	char *yylval;
8610Sstevel@tonic-gate 
8620Sstevel@tonic-gate /*
8630Sstevel@tonic-gate  * Reverse all of the arpa net addresses in the given name to
8640Sstevel@tonic-gate  * be of the form "host @ user" instead of "user @ host"
8650Sstevel@tonic-gate  * This function is its own inverse.
8660Sstevel@tonic-gate  */
8670Sstevel@tonic-gate 
8680Sstevel@tonic-gate char *
revarpa(char str[])8690Sstevel@tonic-gate revarpa(char str[])
8700Sstevel@tonic-gate {
8710Sstevel@tonic-gate 
8720Sstevel@tonic-gate 	if (yyinit(str) < 0)
8730Sstevel@tonic-gate 		return(NOSTR);
8740Sstevel@tonic-gate 	if (name())
8750Sstevel@tonic-gate 		return(NOSTR);
8760Sstevel@tonic-gate 	if (strcmp(str, netbuf) == 0)
8770Sstevel@tonic-gate 		return(str);
8780Sstevel@tonic-gate 	return(savestr(netbuf));
8790Sstevel@tonic-gate }
8800Sstevel@tonic-gate 
8810Sstevel@tonic-gate /*
8820Sstevel@tonic-gate  * Parse (by recursive descent) network names, using the following grammar:
8830Sstevel@tonic-gate  *	name:
8840Sstevel@tonic-gate  *		term {':' term}
8850Sstevel@tonic-gate  *		term {'^' term}
8860Sstevel@tonic-gate  *		term {'!' term}
8870Sstevel@tonic-gate  *		term '@' name
8880Sstevel@tonic-gate  *		term '%' name
8890Sstevel@tonic-gate  *
8900Sstevel@tonic-gate  *	term:
8910Sstevel@tonic-gate  *		string of characters.
8920Sstevel@tonic-gate  */
8930Sstevel@tonic-gate 
8940Sstevel@tonic-gate static int
name(void)8950Sstevel@tonic-gate name(void)
8960Sstevel@tonic-gate {
8970Sstevel@tonic-gate 	register int t;
8980Sstevel@tonic-gate 	register char *cp;
8990Sstevel@tonic-gate 
9000Sstevel@tonic-gate 	for (;;) {
9010Sstevel@tonic-gate 		t = yylex();
9020Sstevel@tonic-gate 		if (t != WORD)
9030Sstevel@tonic-gate 			return(-1);
9040Sstevel@tonic-gate 		cp = yylval;
9050Sstevel@tonic-gate 		t = yylex();
9060Sstevel@tonic-gate 		switch (t) {
9070Sstevel@tonic-gate 		case 0:
9080Sstevel@tonic-gate 			nstrcat(netbuf, sizeof (netbuf), cp);
9090Sstevel@tonic-gate 			return(0);
9100Sstevel@tonic-gate 
9110Sstevel@tonic-gate 		case '@':
9120Sstevel@tonic-gate 		case '%':
9130Sstevel@tonic-gate 			if (name())
9140Sstevel@tonic-gate 				return(-1);
9150Sstevel@tonic-gate 			stradd(netbuf, sizeof (netbuf), '@');
9160Sstevel@tonic-gate 			nstrcat(netbuf, sizeof (netbuf), cp);
9170Sstevel@tonic-gate 			return(0);
9180Sstevel@tonic-gate 		case WORD:
9190Sstevel@tonic-gate 			return(-1);
9200Sstevel@tonic-gate 
9210Sstevel@tonic-gate 		default:
9220Sstevel@tonic-gate 			nstrcat(netbuf, sizeof (netbuf), cp);
9230Sstevel@tonic-gate 			stradd(netbuf, sizeof (netbuf), t);
9240Sstevel@tonic-gate 		}
9250Sstevel@tonic-gate 	}
9260Sstevel@tonic-gate }
9270Sstevel@tonic-gate 
9280Sstevel@tonic-gate /*
9290Sstevel@tonic-gate  * Scanner for network names.
9300Sstevel@tonic-gate  */
9310Sstevel@tonic-gate 
9320Sstevel@tonic-gate static	char *charp;			/* Current input pointer */
9330Sstevel@tonic-gate static	int nexttok;			/* Salted away next token */
9340Sstevel@tonic-gate 
9350Sstevel@tonic-gate /*
9360Sstevel@tonic-gate  * Initialize the network name scanner.
9370Sstevel@tonic-gate  */
9380Sstevel@tonic-gate 
9390Sstevel@tonic-gate int
yyinit(char str[])9400Sstevel@tonic-gate yyinit(char str[])
9410Sstevel@tonic-gate {
9420Sstevel@tonic-gate 	static char lexbuf[BUFSIZ];
9430Sstevel@tonic-gate 
9440Sstevel@tonic-gate 	netbuf[0] = 0;
9450Sstevel@tonic-gate 	if (strlen(str) >= sizeof lexbuf - 1)
9460Sstevel@tonic-gate 		return(-1);
9470Sstevel@tonic-gate 	nexttok = 0;
9480Sstevel@tonic-gate 	nstrcpy(lexbuf, sizeof (lexbuf), str);
9490Sstevel@tonic-gate 	charp = lexbuf;
9500Sstevel@tonic-gate 	return(0);
9510Sstevel@tonic-gate }
9520Sstevel@tonic-gate 
9530Sstevel@tonic-gate /*
9540Sstevel@tonic-gate  * Scan and return a single token.
9550Sstevel@tonic-gate  * yylval is set to point to a scanned string.
9560Sstevel@tonic-gate  */
9570Sstevel@tonic-gate 
9580Sstevel@tonic-gate int
yylex(void)9590Sstevel@tonic-gate yylex(void)
9600Sstevel@tonic-gate {
9610Sstevel@tonic-gate 	register char *cp, *dotp;
9620Sstevel@tonic-gate 	register int s;
9630Sstevel@tonic-gate 
9640Sstevel@tonic-gate 	if (nexttok) {
9650Sstevel@tonic-gate 		s = nexttok;
9660Sstevel@tonic-gate 		nexttok = 0;
9670Sstevel@tonic-gate 		return(s);
9680Sstevel@tonic-gate 	}
9690Sstevel@tonic-gate 	cp = charp;
9700Sstevel@tonic-gate 	while (*cp && isspace(*cp))
9710Sstevel@tonic-gate 		cp++;
9720Sstevel@tonic-gate 	if (*cp == 0)
9730Sstevel@tonic-gate 		return(0);
9740Sstevel@tonic-gate 	if (any(*cp, metanet)) {
9750Sstevel@tonic-gate 		charp = cp+1;
9760Sstevel@tonic-gate 		return(*cp);
9770Sstevel@tonic-gate 	}
9780Sstevel@tonic-gate 	dotp = cp;
9790Sstevel@tonic-gate 	while (*cp && !any(*cp, metanet) && !any(*cp, " \t"))
9800Sstevel@tonic-gate 		cp++;
9810Sstevel@tonic-gate 	if (any(*cp, metanet))
9820Sstevel@tonic-gate 		nexttok = *cp;
9830Sstevel@tonic-gate 	if (*cp == 0)
9840Sstevel@tonic-gate 		charp = cp;
9850Sstevel@tonic-gate 	else
9860Sstevel@tonic-gate 		charp = cp+1;
9870Sstevel@tonic-gate 	*cp = 0;
9880Sstevel@tonic-gate 	yylval = dotp;
9890Sstevel@tonic-gate 	return(WORD);
9900Sstevel@tonic-gate }
9910Sstevel@tonic-gate #endif
9920Sstevel@tonic-gate 
9930Sstevel@tonic-gate /*
9940Sstevel@tonic-gate  * Add a single character onto a string. Here dstsize is the size of the
9950Sstevel@tonic-gate  * destnation buffer.
9960Sstevel@tonic-gate  */
9970Sstevel@tonic-gate 
9980Sstevel@tonic-gate static void
stradd(register char * dst,int dstsize,register int c)9990Sstevel@tonic-gate stradd(register char *dst, int dstsize, register int c)
10000Sstevel@tonic-gate {
10010Sstevel@tonic-gate 	while (*dst != '\0') {
10020Sstevel@tonic-gate 		dst++;
10030Sstevel@tonic-gate 		dstsize--;
10040Sstevel@tonic-gate 	}
10050Sstevel@tonic-gate 	if (--dstsize > 0)
10060Sstevel@tonic-gate 		*dst++ = (char)c;
10070Sstevel@tonic-gate 	*dst = '\0';
10080Sstevel@tonic-gate }
1009