13312Seric # include "sendmail.h"
2297Seric 
3*8069Seric SCCSID(@(#)parseaddr.c	3.52		09/05/82);
4407Seric 
5297Seric /*
6297Seric **  PARSE -- Parse an address
7297Seric **
8297Seric **	Parses an address and breaks it up into three parts: a
9297Seric **	net to transmit the message on, the host to transmit it
10297Seric **	to, and a user on that host.  These are loaded into an
112973Seric **	ADDRESS header with the values squirreled away if necessary.
12297Seric **	The "user" part may not be a real user; the process may
13297Seric **	just reoccur on that machine.  For example, on a machine
14297Seric **	with an arpanet connection, the address
15297Seric **		csvax.bill@berkeley
16297Seric **	will break up to a "user" of 'csvax.bill' and a host
17297Seric **	of 'berkeley' -- to be transmitted over the arpanet.
18297Seric **
19297Seric **	Parameters:
20297Seric **		addr -- the address to parse.
21297Seric **		a -- a pointer to the address descriptor buffer.
22297Seric **			If NULL, a header will be created.
23297Seric **		copyf -- determines what shall be copied:
24297Seric **			-1 -- don't copy anything.  The printname
25297Seric **				(q_paddr) is just addr, and the
26297Seric **				user & host are allocated internally
27297Seric **				to parse.
28297Seric **			0 -- copy out the parsed user & host, but
29297Seric **				don't copy the printname.
30297Seric **			+1 -- copy everything.
31297Seric **
32297Seric **	Returns:
33297Seric **		A pointer to the address descriptor header (`a' if
34297Seric **			`a' is non-NULL).
35297Seric **		NULL on error.
36297Seric **
37297Seric **	Side Effects:
38297Seric **		none
39297Seric */
40297Seric 
413380Seric # define DELIMCHARS	"$()<>,;\\\"\r\n"	/* word delimiters */
422091Seric 
432973Seric ADDRESS *
44297Seric parse(addr, a, copyf)
45297Seric 	char *addr;
462973Seric 	register ADDRESS *a;
47297Seric 	int copyf;
48297Seric {
493149Seric 	register char **pvp;
503149Seric 	register struct mailer *m;
513149Seric 	extern char **prescan();
523149Seric 	extern ADDRESS *buildaddr();
537889Seric 	static char nbuf[MAXNAME];
54297Seric 
55297Seric 	/*
56297Seric 	**  Initialize and prescan address.
57297Seric 	*/
58297Seric 
596903Seric 	CurEnv->e_to = addr;
603188Seric # ifdef DEBUG
617675Seric 	if (tTd(20, 1))
623188Seric 		printf("\n--parse(%s)\n", addr);
633188Seric # endif DEBUG
643188Seric 
653149Seric 	pvp = prescan(addr, '\0');
663149Seric 	if (pvp == NULL)
67297Seric 		return (NULL);
68297Seric 
69297Seric 	/*
703149Seric 	**  Apply rewriting rules.
717889Seric 	**	Ruleset 0 does basic parsing.  It must resolve.
72297Seric 	*/
73297Seric 
744070Seric 	rewrite(pvp, 0);
75297Seric 
763149Seric 	/*
773149Seric 	**  See if we resolved to a real mailer.
783149Seric 	*/
79297Seric 
803149Seric 	if (pvp[0][0] != CANONNET)
813149Seric 	{
823149Seric 		setstat(EX_USAGE);
833149Seric 		usrerr("cannot resolve name");
843149Seric 		return (NULL);
85297Seric 	}
86297Seric 
87297Seric 	/*
883149Seric 	**  Build canonical address from pvp.
89297Seric 	*/
90297Seric 
913149Seric 	a = buildaddr(pvp, a);
924279Seric 	if (a == NULL)
934279Seric 		return (NULL);
944598Seric 	m = a->q_mailer;
95297Seric 
96297Seric 	/*
973149Seric 	**  Make local copies of the host & user and then
983149Seric 	**  transport them out.
99297Seric 	*/
100297Seric 
101297Seric 	if (copyf > 0)
1022973Seric 		a->q_paddr = newstr(addr);
103297Seric 	else
104297Seric 		a->q_paddr = addr;
1053149Seric 	if (copyf >= 0)
106297Seric 	{
1073149Seric 		if (a->q_host != NULL)
1083149Seric 			a->q_host = newstr(a->q_host);
109297Seric 		else
1103149Seric 			a->q_host = "";
1113149Seric 		if (a->q_user != a->q_paddr)
1123149Seric 			a->q_user = newstr(a->q_user);
113297Seric 	}
114297Seric 
115297Seric 	/*
116297Seric 	**  Do UPPER->lower case mapping unless inhibited.
117297Seric 	*/
118297Seric 
1193149Seric 	if (!bitset(M_HST_UPPER, m->m_flags))
120297Seric 		makelower(a->q_host);
1213149Seric 	if (!bitset(M_USR_UPPER, m->m_flags))
122297Seric 		makelower(a->q_user);
123297Seric 
124297Seric 	/*
125297Seric 	**  Compute return value.
126297Seric 	*/
127297Seric 
128297Seric # ifdef DEBUG
1297675Seric 	if (tTd(20, 1))
1304443Seric 	{
1314443Seric 		printf("parse-->");
1324443Seric 		printaddr(a, FALSE);
1334443Seric 	}
134297Seric # endif DEBUG
135297Seric 
136297Seric 	return (a);
137297Seric }
138297Seric /*
139297Seric **  PRESCAN -- Prescan name and make it canonical
140297Seric **
141297Seric **	Scans a name and turns it into canonical form.  This involves
142297Seric **	deleting blanks, comments (in parentheses), and turning the
143297Seric **	word "at" into an at-sign ("@").  The name is copied as this
144297Seric **	is done; it is legal to copy a name onto itself, since this
145297Seric **	process can only make things smaller.
146297Seric **
147297Seric **	This routine knows about quoted strings and angle brackets.
148297Seric **
149297Seric **	There are certain subtleties to this routine.  The one that
150297Seric **	comes to mind now is that backslashes on the ends of names
151297Seric **	are silently stripped off; this is intentional.  The problem
152297Seric **	is that some versions of sndmsg (like at LBL) set the kill
153297Seric **	character to something other than @ when reading addresses;
154297Seric **	so people type "csvax.eric\@berkeley" -- which screws up the
155297Seric **	berknet mailer.
156297Seric **
157297Seric **	Parameters:
158297Seric **		addr -- the name to chomp.
159297Seric **		delim -- the delimiter for the address, normally
160297Seric **			'\0' or ','; \0 is accepted in any case.
161297Seric **			are moving in place; set buflim to high core.
162297Seric **
163297Seric **	Returns:
1643149Seric **		A pointer to a vector of tokens.
165297Seric **		NULL on error.
166297Seric **
167297Seric **	Side Effects:
1683149Seric **		none.
169297Seric */
170297Seric 
1713149Seric # define OPER		1
1723149Seric # define ATOM		2
1733149Seric # define EOTOK		3
1743149Seric # define QSTRING	4
1753149Seric # define SPACE		5
1766053Seric # define ONEMORE	6
1773149Seric # define GETONE		7
1784424Seric # define MACRO		8
1793149Seric 
1803149Seric char **
1813149Seric prescan(addr, delim)
182297Seric 	char *addr;
183297Seric 	char delim;
184297Seric {
185297Seric 	register char *p;
1863149Seric 	static char buf[MAXNAME+MAXATOM];
1873149Seric 	static char *av[MAXATOM+1];
1883149Seric 	char **avp;
189297Seric 	bool bslashmode;
190297Seric 	int cmntcnt;
191297Seric 	register char c;
1923149Seric 	char *tok;
193297Seric 	register char *q;
1943149Seric 	register int state;
1953149Seric 	int nstate;
1964085Seric 	extern char lower();
197297Seric 
198297Seric 	q = buf;
1993149Seric 	bslashmode = FALSE;
2007800Seric 	cmntcnt = 0;
2013149Seric 	avp = av;
2023149Seric 	state = OPER;
2033149Seric 	for (p = addr; *p != '\0' && *p != delim; )
204297Seric 	{
2053149Seric 		/* read a token */
2063149Seric 		tok = q;
2073149Seric 		while ((c = *p++) != '\0' && c != delim)
208297Seric 		{
2093149Seric 			/* chew up special characters */
2104100Seric 			c &= ~0200;
2113149Seric 			*q = '\0';
2123149Seric 			if (bslashmode)
2133149Seric 			{
2143149Seric 				c |= 0200;
2153149Seric 				bslashmode = FALSE;
2163149Seric 			}
2173149Seric 			else if (c == '\\')
2183149Seric 			{
2193149Seric 				bslashmode = TRUE;
2203149Seric 				continue;
2213149Seric 			}
2224100Seric 			else if (c == '"')
2234100Seric 			{
2244100Seric 				if (state == QSTRING)
2254100Seric 					state = OPER;
2264100Seric 				else
2274100Seric 					state = QSTRING;
2284100Seric 				break;
2294100Seric 			}
2303149Seric 
2316053Seric 			nstate = toktype(c);
2323149Seric 			switch (state)
2333149Seric 			{
2343149Seric 			  case QSTRING:		/* in quoted string */
2353149Seric 				break;
2363149Seric 
2373149Seric 			  case ATOM:		/* regular atom */
2384228Seric 				if (nstate != ATOM)
2393149Seric 				{
2403149Seric 					state = EOTOK;
2413149Seric 					p--;
2423149Seric 				}
2433149Seric 				break;
2443149Seric 
2453149Seric 			  case GETONE:		/* grab one character */
2463149Seric 				state = OPER;
2473149Seric 				break;
2483149Seric 
2493149Seric 			  case EOTOK:		/* after atom or q-string */
2503149Seric 				state = nstate;
2513149Seric 				if (state == SPACE)
2523149Seric 					continue;
2533149Seric 				break;
2543149Seric 
2553149Seric 			  case SPACE:		/* linear white space */
2563149Seric 				state = nstate;
2574228Seric 				break;
2583149Seric 
2593149Seric 			  case OPER:		/* operator */
2603149Seric 				if (nstate == SPACE)
2613149Seric 					continue;
2623149Seric 				state = nstate;
2633149Seric 				break;
2643149Seric 
2656053Seric 			  case ONEMORE:		/* $- etc. */
2666053Seric 				state = GETONE;
2673149Seric 				break;
2683149Seric 
2693149Seric 			  default:
2703149Seric 				syserr("prescan: unknown state %d", state);
2713149Seric 			}
2723149Seric 
2734228Seric 			if (state == EOTOK || state == SPACE)
2743149Seric 				break;
2753149Seric 
2763149Seric 			/* squirrel it away */
2773149Seric 			if (q >= &buf[sizeof buf - 5])
2783149Seric 			{
2793149Seric 				usrerr("Address too long");
2803149Seric 				return (NULL);
2813149Seric 			}
2823149Seric 			*q++ = c;
2833149Seric 
2843149Seric 			/* decide whether this represents end of token */
2856053Seric 			if (state == OPER || state == GETONE)
2863149Seric 				break;
287297Seric 		}
2883149Seric 		if (c == '\0' || c == delim)
2893149Seric 			p--;
2903149Seric 
2913149Seric 		/* new token */
2923149Seric 		if (tok == q)
293297Seric 			continue;
2943149Seric 		*q++ = '\0';
2953149Seric 
2963149Seric 		c = tok[0];
2973149Seric 		if (c == '(')
2981378Seric 		{
299297Seric 			cmntcnt++;
3001378Seric 			continue;
3011378Seric 		}
302297Seric 		else if (c == ')')
303297Seric 		{
304297Seric 			if (cmntcnt <= 0)
305297Seric 			{
306297Seric 				usrerr("Unbalanced ')'");
307297Seric 				return (NULL);
308297Seric 			}
309297Seric 			else
310297Seric 			{
311297Seric 				cmntcnt--;
312297Seric 				continue;
313297Seric 			}
314297Seric 		}
3153149Seric 		else if (cmntcnt > 0)
3162091Seric 			continue;
3173149Seric 
3184448Seric 		if (avp >= &av[MAXATOM])
3194448Seric 		{
3204448Seric 			syserr("prescan: too many tokens");
3214448Seric 			return (NULL);
3224448Seric 		}
3234448Seric 		*avp++ = tok;
3243149Seric 	}
3253149Seric 	*avp = NULL;
3263149Seric 	if (cmntcnt > 0)
3273149Seric 		usrerr("Unbalanced '('");
3283149Seric 	else if (state == QSTRING)
3293149Seric 		usrerr("Unbalanced '\"'");
3303149Seric 	else if (av[0] != NULL)
3313149Seric 		return (av);
3323149Seric 	return (NULL);
3333149Seric }
3343149Seric /*
3353149Seric **  TOKTYPE -- return token type
3363149Seric **
3373149Seric **	Parameters:
3383149Seric **		c -- the character in question.
3393149Seric **
3403149Seric **	Returns:
3413149Seric **		Its type.
3423149Seric **
3433149Seric **	Side Effects:
3443149Seric **		none.
3453149Seric */
346297Seric 
3473149Seric toktype(c)
3483149Seric 	register char c;
3493149Seric {
3503380Seric 	static char buf[50];
3513382Seric 	static bool firstime = TRUE;
3523380Seric 
3533382Seric 	if (firstime)
3543380Seric 	{
3553382Seric 		firstime = FALSE;
3566977Seric 		expand("$o", buf, &buf[sizeof buf - 1], CurEnv);
3577005Seric 		(void) strcat(buf, DELIMCHARS);
3583380Seric 	}
3596053Seric 	if (c == MATCHCLASS || c == MATCHREPL)
3606053Seric 		return (ONEMORE);
3614100Seric 	if (!isascii(c))
3624100Seric 		return (ATOM);
3633149Seric 	if (isspace(c))
3643149Seric 		return (SPACE);
3653380Seric 	if (iscntrl(c) || index(buf, c) != NULL)
3663149Seric 		return (OPER);
3673149Seric 	return (ATOM);
3683149Seric }
3693149Seric /*
3703149Seric **  REWRITE -- apply rewrite rules to token vector.
3713149Seric **
3724476Seric **	This routine is an ordered production system.  Each rewrite
3734476Seric **	rule has a LHS (called the pattern) and a RHS (called the
3744476Seric **	rewrite); 'rwr' points the the current rewrite rule.
3754476Seric **
3764476Seric **	For each rewrite rule, 'avp' points the address vector we
3774476Seric **	are trying to match against, and 'pvp' points to the pattern.
3788058Seric **	If pvp points to a special match value (MATCHZANY, MATCHANY,
3798058Seric **	MATCHONE, MATCHCLASS) then the address in avp matched is
3808058Seric **	saved away in the match vector (pointed to by 'mvp').
3814476Seric **
3824476Seric **	When a match between avp & pvp does not match, we try to
3834476Seric **	back out.  If we back up over a MATCHONE or a MATCHCLASS
3844476Seric **	we must also back out the match in mvp.  If we reach a
3858058Seric **	MATCHANY or MATCHZANY we just extend the match and start
3868058Seric **	over again.
3874476Seric **
3884476Seric **	When we finally match, we rewrite the address vector
3894476Seric **	and try over again.
3904476Seric **
3913149Seric **	Parameters:
3923149Seric **		pvp -- pointer to token vector.
3933149Seric **
3943149Seric **	Returns:
3953149Seric **		none.
3963149Seric **
3973149Seric **	Side Effects:
3983149Seric **		pvp is modified.
3993149Seric */
4002091Seric 
4013149Seric struct match
4023149Seric {
4034468Seric 	char	**first;	/* first token matched */
4044468Seric 	char	**last;		/* last token matched */
4053149Seric };
4063149Seric 
4074468Seric # define MAXMATCH	9	/* max params per rewrite */
4083149Seric 
4093149Seric 
4104070Seric rewrite(pvp, ruleset)
4113149Seric 	char **pvp;
4124070Seric 	int ruleset;
4133149Seric {
4143149Seric 	register char *ap;		/* address pointer */
4153149Seric 	register char *rp;		/* rewrite pointer */
4163149Seric 	register char **avp;		/* address vector pointer */
4173149Seric 	register char **rvp;		/* rewrite vector pointer */
4188058Seric 	register struct match *mlp;	/* cur ptr into mlist */
4198058Seric 	register struct rewrite *rwr;	/* pointer to current rewrite rule */
4204468Seric 	struct match mlist[MAXMATCH];	/* stores match on LHS */
4213149Seric 	char *npvp[MAXATOM+1];		/* temporary space for rebuild */
4224060Seric 	extern bool sameword();
4233149Seric 
4244100Seric # ifdef DEBUG
425*8069Seric 	if (tTd(21, 2))
4263149Seric 	{
427*8069Seric 		printf("rewrite: ruleset %d, original pvp:", ruleset);
4283149Seric 		printav(pvp);
4293149Seric 	}
4304100Seric # endif DEBUG
4313149Seric 
4323149Seric 	/*
4333149Seric 	**  Run through the list of rewrite rules, applying
4343149Seric 	**	any that match.
4353149Seric 	*/
4363149Seric 
4374070Seric 	for (rwr = RewriteRules[ruleset]; rwr != NULL; )
4383149Seric 	{
4394100Seric # ifdef DEBUG
4407675Seric 		if (tTd(21, 12))
441297Seric 		{
442*8069Seric 			printf("-----trying rule:");
4433149Seric 			printav(rwr->r_lhs);
4443149Seric 		}
4454100Seric # endif DEBUG
4463149Seric 
4473149Seric 		/* try to match on this rule */
4484468Seric 		mlp = mlist;
4498058Seric 		rvp = rwr->r_lhs;
4508058Seric 		avp = pvp;
4518058Seric 		while ((ap = *avp) != NULL || *rvp != NULL)
4523149Seric 		{
4533149Seric 			rp = *rvp;
4548058Seric # ifdef DEBUG
4558058Seric 			if (tTd(21, 35))
4568058Seric 			{
457*8069Seric 				printf("ap=");
4588058Seric 				xputs(ap);
459*8069Seric 				printf(", rp=");
4608058Seric 				xputs(rp);
461*8069Seric 				printf("\n");
4628058Seric 			}
4638058Seric # endif DEBUG
4643149Seric 			if (rp == NULL)
465297Seric 			{
4663149Seric 				/* end-of-pattern before end-of-address */
4678058Seric 				goto backup;
468297Seric 			}
4698058Seric 			if (ap == NULL && *rp != MATCHZANY)
4708058Seric 			{
4718058Seric 				/* end-of-input */
4728058Seric 				break;
4738058Seric 			}
4743149Seric 
4753149Seric 			switch (*rp)
4763149Seric 			{
4774060Seric 				register STAB *s;
4784060Seric 				register int class;
4794060Seric 
4804060Seric 			  case MATCHCLASS:
4814060Seric 				/* match any token in a class */
4824060Seric 				class = rp[1];
4834060Seric 				if (!isalpha(class))
4848058Seric 					goto backup;
4854060Seric 				if (isupper(class))
4864060Seric 					class -= 'A';
4874060Seric 				else
4884060Seric 					class -= 'a';
4894100Seric 				s = stab(ap, ST_CLASS, ST_FIND);
4906273Seric 				if (s == NULL || (s->s_class & (1L << class)) == 0)
4918058Seric 					goto backup;
4924468Seric 
4934476Seric 				/* explicit fall-through */
4944476Seric 
4954476Seric 			  case MATCHONE:
4964476Seric 			  case MATCHANY:
4974476Seric 				/* match exactly one token */
4988058Seric 				mlp->first = avp;
4998058Seric 				mlp->last = avp++;
5004468Seric 				mlp++;
5014060Seric 				break;
5024060Seric 
5038058Seric 			  case MATCHZANY:
5048058Seric 				/* match zero or more tokens */
5058058Seric 				mlp->first = avp;
5068058Seric 				mlp->last = avp - 1;
5078058Seric 				mlp++;
5088058Seric 				break;
5098058Seric 
5103149Seric 			  default:
5113149Seric 				/* must have exact match */
5124060Seric 				if (!sameword(rp, ap))
5138058Seric 					goto backup;
5144468Seric 				avp++;
5153149Seric 				break;
5163149Seric 			}
5173149Seric 
5183149Seric 			/* successful match on this token */
5193149Seric 			rvp++;
5203149Seric 			continue;
5213149Seric 
5228058Seric 		  backup:
5233149Seric 			/* match failed -- back up */
5243149Seric 			while (--rvp >= rwr->r_lhs)
5253149Seric 			{
5263149Seric 				rp = *rvp;
5278058Seric 				if (*rp == MATCHANY || *rp == MATCHZANY)
5284468Seric 				{
5294476Seric 					/* extend binding and continue */
5308058Seric 					avp = ++mlp[-1].last;
5318058Seric 					avp++;
5324476Seric 					rvp++;
5333149Seric 					break;
5344468Seric 				}
5354476Seric 				avp--;
5364476Seric 				if (*rp == MATCHONE || *rp == MATCHCLASS)
5373149Seric 				{
5384468Seric 					/* back out binding */
5394468Seric 					mlp--;
5403149Seric 				}
5413149Seric 			}
5423149Seric 
5433149Seric 			if (rvp < rwr->r_lhs)
5443149Seric 			{
5453149Seric 				/* total failure to match */
5463149Seric 				break;
5473149Seric 			}
548297Seric 		}
5493149Seric 
5503149Seric 		/*
5513149Seric 		**  See if we successfully matched
5523149Seric 		*/
5533149Seric 
5543149Seric 		if (rvp >= rwr->r_lhs && *rvp == NULL)
5553149Seric 		{
5568058Seric 			rvp = rwr->r_rhs;
5574100Seric # ifdef DEBUG
5587675Seric 			if (tTd(21, 12))
5593149Seric 			{
560*8069Seric 				printf("-----rule matches:");
5618058Seric 				printav(rvp);
5623149Seric 			}
5634100Seric # endif DEBUG
5643149Seric 
5658058Seric 			/* see if this is a "subroutine" call */
5668058Seric 			rp = *rvp;
5678058Seric 			if (*rp == CALLSUBR)
5688058Seric 			{
5698058Seric 				rp = *++rvp;
5708058Seric # ifdef DEBUG
571*8069Seric 				if (tTd(21, 3))
5728058Seric 					printf("-----callsubr %s\n", rp);
5738058Seric # endif DEBUG
5748058Seric 				rewrite(pvp, atoi(rp));
5758058Seric 				rwr = rwr->r_next;
5768058Seric 				continue;
5778058Seric 			}
578*8069Seric 			else if (*rp == CANONUSER)
579*8069Seric 			{
580*8069Seric 				rvp++;
581*8069Seric 				rwr = rwr->r_next;
582*8069Seric 			}
583*8069Seric 			else if (*rp == CANONHOST)
584*8069Seric 			{
585*8069Seric 				rvp++;
586*8069Seric 				rwr = NULL;
587*8069Seric 			}
588*8069Seric 			else if (*rp == CANONNET)
589*8069Seric 				rwr = NULL;
5908058Seric 
5913149Seric 			/* substitute */
592*8069Seric 			for (avp = npvp; *rvp != NULL; rvp++)
5933149Seric 			{
5943149Seric 				rp = *rvp;
5954468Seric 				if (*rp == MATCHREPL)
5963149Seric 				{
5973149Seric 					register struct match *m;
5983149Seric 					register char **pp;
5993149Seric 
6004468Seric 					m = &mlist[rp[1] - '1'];
6014476Seric # ifdef DEBUG
6027675Seric 					if (tTd(21, 15))
6034476Seric 					{
6044476Seric 						printf("$%c:", rp[1]);
6054476Seric 						pp = m->first;
6068058Seric 						while (pp <= m->last)
6074476Seric 						{
6084476Seric 							printf(" %x=\"", *pp);
6094625Seric 							(void) fflush(stdout);
6108058Seric 							printf("%s\"", *pp++);
6118058Seric 						}
6124476Seric 						printf("\n");
6134476Seric 					}
6144476Seric # endif DEBUG
6154468Seric 					pp = m->first;
6168058Seric 					while (pp <= m->last)
6173149Seric 					{
6184468Seric 						if (avp >= &npvp[MAXATOM])
6193149Seric 						{
6204468Seric 							syserr("rewrite: expansion too long");
6214468Seric 							return;
6224468Seric 						}
6238058Seric 						*avp++ = *pp++;
6248058Seric 					}
6253149Seric 				}
6263149Seric 				else
6274385Seric 				{
6284385Seric 					if (avp >= &npvp[MAXATOM])
6294385Seric 					{
6304385Seric 						syserr("rewrite: expansion too long");
6314385Seric 						return;
6324385Seric 					}
6333149Seric 					*avp++ = rp;
6344385Seric 				}
6353149Seric 			}
6363149Seric 			*avp++ = NULL;
6374085Seric 			bmove((char *) npvp, (char *) pvp, (avp - npvp) * sizeof *avp);
6383149Seric # ifdef DEBUG
6397675Seric 			if (tTd(21, 4))
6403149Seric 			{
641*8069Seric 				printf("rewritten as:");
642*8069Seric 				printav(pvp);
6433149Seric 			}
6443149Seric # endif DEBUG
6453149Seric 		}
6463149Seric 		else
6473149Seric 		{
6484100Seric # ifdef DEBUG
6497675Seric 			if (tTd(21, 10))
6503149Seric 				printf("----- rule fails\n");
6514100Seric # endif DEBUG
6523149Seric 			rwr = rwr->r_next;
6533149Seric 		}
654297Seric 	}
655*8069Seric 
656*8069Seric # ifdef DEBUG
657*8069Seric 	if (tTd(21, 2))
658*8069Seric 	{
659*8069Seric 		printf("rewrite: ruleset %d returns:", ruleset);
660*8069Seric 		printav(pvp);
661*8069Seric 	}
662*8069Seric # endif DEBUG
6633149Seric }
6643149Seric /*
6653149Seric **  BUILDADDR -- build address from token vector.
6663149Seric **
6673149Seric **	Parameters:
6683149Seric **		tv -- token vector.
6693149Seric **		a -- pointer to address descriptor to fill.
6703149Seric **			If NULL, one will be allocated.
6713149Seric **
6723149Seric **	Returns:
6734279Seric **		NULL if there was an error.
6744279Seric **		'a' otherwise.
6753149Seric **
6763149Seric **	Side Effects:
6773149Seric **		fills in 'a'
6783149Seric */
6793149Seric 
6803149Seric ADDRESS *
6813149Seric buildaddr(tv, a)
6823149Seric 	register char **tv;
6833149Seric 	register ADDRESS *a;
6843149Seric {
6853149Seric 	static char buf[MAXNAME];
6863149Seric 	struct mailer **mp;
6873149Seric 	register struct mailer *m;
6884635Seric 	extern bool sameword();
6893149Seric 
6903149Seric 	if (a == NULL)
6913149Seric 		a = (ADDRESS *) xalloc(sizeof *a);
6924988Seric 	clear((char *) a, sizeof *a);
6933149Seric 
6943149Seric 	/* figure out what net/mailer to use */
6953149Seric 	if (**tv != CANONNET)
6964279Seric 	{
6973149Seric 		syserr("buildaddr: no net");
6984279Seric 		return (NULL);
6994279Seric 	}
7003149Seric 	tv++;
7014635Seric 	if (sameword(*tv, "error"))
7024279Seric 	{
7034279Seric 		if (**++tv != CANONUSER)
7044279Seric 			syserr("buildaddr: error: no user");
7054279Seric 		buf[0] = '\0';
7064279Seric 		while (*++tv != NULL)
7074279Seric 		{
7084279Seric 			if (buf[0] != '\0')
7097005Seric 				(void) strcat(buf, " ");
7107005Seric 			(void) strcat(buf, *tv);
7114279Seric 		}
7124279Seric 		usrerr(buf);
7134279Seric 		return (NULL);
7144279Seric 	}
7154598Seric 	for (mp = Mailer; (m = *mp++) != NULL; )
7163149Seric 	{
7174635Seric 		if (sameword(m->m_name, *tv))
7183149Seric 			break;
7193149Seric 	}
7203149Seric 	if (m == NULL)
7214279Seric 	{
7223149Seric 		syserr("buildaddr: unknown net %s", *tv);
7234279Seric 		return (NULL);
7244279Seric 	}
7254598Seric 	a->q_mailer = m;
7263149Seric 
7273149Seric 	/* figure out what host (if any) */
7283149Seric 	tv++;
7294195Seric 	if (!bitset(M_LOCAL, m->m_flags))
7303149Seric 	{
7315704Seric 		if (**tv++ != CANONHOST)
7324279Seric 		{
7333149Seric 			syserr("buildaddr: no host");
7344279Seric 			return (NULL);
7354279Seric 		}
7365704Seric 		buf[0] = '\0';
7375704Seric 		while (*tv != NULL && **tv != CANONUSER)
7387005Seric 			(void) strcat(buf, *tv++);
7395704Seric 		a->q_host = newstr(buf);
7403149Seric 	}
7413149Seric 	else
7423149Seric 		a->q_host = NULL;
7433149Seric 
7443149Seric 	/* figure out the user */
7453149Seric 	if (**tv != CANONUSER)
7464279Seric 	{
7473149Seric 		syserr("buildaddr: no user");
7484279Seric 		return (NULL);
7494279Seric 	}
7504228Seric 	cataddr(++tv, buf, sizeof buf);
7513149Seric 	a->q_user = buf;
7523149Seric 
7533149Seric 	return (a);
7543149Seric }
7553188Seric /*
7564228Seric **  CATADDR -- concatenate pieces of addresses (putting in <LWSP> subs)
7574228Seric **
7584228Seric **	Parameters:
7594228Seric **		pvp -- parameter vector to rebuild.
7604228Seric **		buf -- buffer to build the string into.
7614228Seric **		sz -- size of buf.
7624228Seric **
7634228Seric **	Returns:
7644228Seric **		none.
7654228Seric **
7664228Seric **	Side Effects:
7674228Seric **		Destroys buf.
7684228Seric */
7694228Seric 
7704228Seric cataddr(pvp, buf, sz)
7714228Seric 	char **pvp;
7724228Seric 	char *buf;
7734228Seric 	register int sz;
7744228Seric {
7754228Seric 	bool oatomtok = FALSE;
7764228Seric 	bool natomtok = FALSE;
7774228Seric 	register int i;
7784228Seric 	register char *p;
7794228Seric 
7804228Seric 	p = buf;
7814228Seric 	sz--;
7824228Seric 	while (*pvp != NULL && (i = strlen(*pvp)) < sz)
7834228Seric 	{
7844228Seric 		natomtok = (toktype(**pvp) == ATOM);
7854228Seric 		if (oatomtok && natomtok)
7864228Seric 			*p++ = SPACESUB;
7874228Seric 		(void) strcpy(p, *pvp);
7884228Seric 		oatomtok = natomtok;
7894228Seric 		p += i;
7904228Seric 		sz -= i;
7914228Seric 		pvp++;
7924228Seric 	}
7934228Seric 	*p = '\0';
7944228Seric }
7954228Seric /*
7963188Seric **  SAMEADDR -- Determine if two addresses are the same
7973188Seric **
7983188Seric **	This is not just a straight comparison -- if the mailer doesn't
7993188Seric **	care about the host we just ignore it, etc.
8003188Seric **
8013188Seric **	Parameters:
8023188Seric **		a, b -- pointers to the internal forms to compare.
8033188Seric **		wildflg -- if TRUE, 'a' may have no user specified,
8043188Seric **			in which case it is to match anything.
8053188Seric **
8063188Seric **	Returns:
8073188Seric **		TRUE -- they represent the same mailbox.
8083188Seric **		FALSE -- they don't.
8093188Seric **
8103188Seric **	Side Effects:
8113188Seric **		none.
8123188Seric */
8133188Seric 
8143188Seric bool
8153188Seric sameaddr(a, b, wildflg)
8163188Seric 	register ADDRESS *a;
8173188Seric 	register ADDRESS *b;
8183188Seric 	bool wildflg;
8193188Seric {
8203188Seric 	/* if they don't have the same mailer, forget it */
8213188Seric 	if (a->q_mailer != b->q_mailer)
8223188Seric 		return (FALSE);
8233188Seric 
8243188Seric 	/* if the user isn't the same, we can drop out */
8253188Seric 	if ((!wildflg || a->q_user[0] != '\0') && strcmp(a->q_user, b->q_user) != 0)
8263188Seric 		return (FALSE);
8273188Seric 
8283188Seric 	/* if the mailer ignores hosts, we have succeeded! */
8294598Seric 	if (bitset(M_LOCAL, a->q_mailer->m_flags))
8303188Seric 		return (TRUE);
8313188Seric 
8323188Seric 	/* otherwise compare hosts (but be careful for NULL ptrs) */
8333188Seric 	if (a->q_host == NULL || b->q_host == NULL)
8343188Seric 		return (FALSE);
8353188Seric 	if (strcmp(a->q_host, b->q_host) != 0)
8363188Seric 		return (FALSE);
8373188Seric 
8383188Seric 	return (TRUE);
8393188Seric }
8403234Seric /*
8413234Seric **  PRINTADDR -- print address (for debugging)
8423234Seric **
8433234Seric **	Parameters:
8443234Seric **		a -- the address to print
8453234Seric **		follow -- follow the q_next chain.
8463234Seric **
8473234Seric **	Returns:
8483234Seric **		none.
8493234Seric **
8503234Seric **	Side Effects:
8513234Seric **		none.
8523234Seric */
8533234Seric 
8544317Seric # ifdef DEBUG
8554317Seric 
8563234Seric printaddr(a, follow)
8573234Seric 	register ADDRESS *a;
8583234Seric 	bool follow;
8593234Seric {
8605001Seric 	bool first = TRUE;
8615001Seric 
8623234Seric 	while (a != NULL)
8633234Seric 	{
8645001Seric 		first = FALSE;
8654443Seric 		printf("%x=", a);
8664085Seric 		(void) fflush(stdout);
8673234Seric 		printf("%s: mailer %d (%s), host `%s', user `%s'\n", a->q_paddr,
8684598Seric 		       a->q_mailer->m_mno, a->q_mailer->m_name, a->q_host, a->q_user);
8695035Seric 		printf("\tnext=%x, flags=%o, rmailer %d, alias %x\n", a->q_next,
8705035Seric 		       a->q_flags, a->q_rmailer, a->q_alias);
8715001Seric 		printf("\thome=\"%s\", fullname=\"%s\"\n", a->q_home, a->q_fullname);
8724996Seric 
8733234Seric 		if (!follow)
8743234Seric 			return;
8754996Seric 		a = a->q_next;
8763234Seric 	}
8775001Seric 	if (first)
8784443Seric 		printf("[NULL]\n");
8793234Seric }
8804317Seric 
8814317Seric # endif DEBUG
8827682Seric /*
8837682Seric **  REMOTENAME -- return the name relative to the current mailer
8847682Seric **
8857682Seric **	Parameters:
8867682Seric **		name -- the name to translate.
887*8069Seric **		m -- the mailer that we want to do rewriting relative
888*8069Seric **			to.
889*8069Seric **		senderaddress -- if set, uses the sender rewriting rules
890*8069Seric **			rather than the recipient rewriting rules.
8917682Seric **
8927682Seric **	Returns:
8937682Seric **		the text string representing this address relative to
8947682Seric **			the receiving mailer.
8957682Seric **
8967682Seric **	Side Effects:
8977682Seric **		none.
8987682Seric **
8997682Seric **	Warnings:
9007682Seric **		The text string returned is tucked away locally;
9017682Seric **			copy it if you intend to save it.
9027682Seric */
9037682Seric 
9047682Seric char *
905*8069Seric remotename(name, m, senderaddress)
9067682Seric 	char *name;
9077682Seric 	struct mailer *m;
908*8069Seric 	bool senderaddress;
9097682Seric {
910*8069Seric 	register char **pvp;
911*8069Seric 	char *fancy;
912*8069Seric 	extern char *macvalue();
913*8069Seric 	char *oldg = macvalue('g');
9147682Seric 	static char buf[MAXNAME];
9157682Seric 	char lbuf[MAXNAME];
9167682Seric 	extern char **prescan();
9177889Seric 	extern char *crackaddr();
9187682Seric 
9197755Seric # ifdef DEBUG
9207755Seric 	if (tTd(12, 1))
9217755Seric 		printf("remotename(%s)\n", name);
9227755Seric # endif DEBUG
9237755Seric 
9247682Seric 	/*
9257889Seric 	**  First put this address into canonical form.
9267889Seric 	**	First turn it into a macro.
927*8069Seric 	**	Then run it through ruleset 1 or 2, depending on whether
928*8069Seric 	**		it is a sender or a recipient address.
9298058Seric 	**	If the mailer defines a rewriting set, run it through
9308058Seric 	**		there next.
9317889Seric 	*/
9327889Seric 
9337889Seric 	/* save away the extraneous pretty stuff */
9347889Seric 	fancy = crackaddr(name);
9357889Seric 
9367889Seric 	/* now run through ruleset four */
9377889Seric 	pvp = prescan(name, '\0');
9387889Seric 	if (pvp == NULL)
9397889Seric 		return (name);
940*8069Seric 	if (senderaddress)
9417755Seric 	{
9427889Seric 		rewrite(pvp, 1);
943*8069Seric 		if (m->m_s_rwset > 0)
944*8069Seric 			rewrite(pvp, m->m_s_rwset);
945*8069Seric 	}
946*8069Seric 	else
947*8069Seric 	{
9487889Seric 		rewrite(pvp, 2);
949*8069Seric 		if (m->m_r_rwset > 0)
950*8069Seric 			rewrite(pvp, m->m_r_rwset);
9517682Seric 	}
9527682Seric 
9537889Seric 	/* now add any comment info we had before back */
9547682Seric 	cataddr(pvp, lbuf, sizeof lbuf);
9557682Seric 	define('g', lbuf);
9567889Seric 	expand(fancy, buf, &buf[sizeof buf - 1], CurEnv);
9577682Seric 	define('g', oldg);
9587682Seric 
9597682Seric # ifdef DEBUG
9607682Seric 	if (tTd(12, 1))
9617755Seric 		printf("remotename => `%s'\n", buf);
9627682Seric # endif DEBUG
9637682Seric 	return (buf);
9647682Seric }
9657682Seric /*
9667682Seric **  CANONNAME -- make name canonical
9677682Seric **
9687682Seric **	This is used for SMTP and misc. printing.  Given a print
9697682Seric **	address, it strips out comments, etc., and puts on exactly
9707682Seric **	one set of brackets.
9717682Seric **
9727682Seric **	Parameters:
9737682Seric **		name -- the name to make canonical.
9747682Seric **
9757682Seric **	Returns:
9767682Seric **		pointer to canonical name.
9777682Seric **
9787682Seric **	Side Effects:
9797682Seric **		none.
9807682Seric **
9817682Seric **	Warning:
9827682Seric **		result is saved in static buf; future calls will trash it.
9837682Seric */
9847682Seric 
9857682Seric char *
9867682Seric canonname(name)
9877682Seric 	char *name;
9887682Seric {
989*8069Seric 	static char nbuf[MAXNAME];
9907940Seric 	register char **pvp;
9917682Seric 
9927940Seric 	pvp = prescan(name, '\0');
993*8069Seric 	rewrite(pvp, 3);
994*8069Seric 	cataddr(pvp, nbuf, sizeof nbuf);
9957682Seric 	return (nbuf);
9967682Seric }
997