122976Smiriam /*
234921Sbostic  * Copyright (c) 1983 Eric P. Allman
363589Sbostic  * Copyright (c) 1988, 1993
463589Sbostic  *	The Regents of the University of California.  All rights reserved.
533730Sbostic  *
642828Sbostic  * %sccs.include.redist.c%
733730Sbostic  */
822976Smiriam 
922976Smiriam #ifndef lint
10*68708Seric static char sccsid[] = "@(#)parseaddr.c	8.63 (Berkeley) 03/31/95";
1133730Sbostic #endif /* not lint */
1222976Smiriam 
1356678Seric # include "sendmail.h"
14297Seric 
15297Seric /*
169888Seric **  PARSEADDR -- Parse an address
17297Seric **
18297Seric **	Parses an address and breaks it up into three parts: a
19297Seric **	net to transmit the message on, the host to transmit it
20297Seric **	to, and a user on that host.  These are loaded into an
212973Seric **	ADDRESS header with the values squirreled away if necessary.
22297Seric **	The "user" part may not be a real user; the process may
23297Seric **	just reoccur on that machine.  For example, on a machine
24297Seric **	with an arpanet connection, the address
25297Seric **		csvax.bill@berkeley
26297Seric **	will break up to a "user" of 'csvax.bill' and a host
27297Seric **	of 'berkeley' -- to be transmitted over the arpanet.
28297Seric **
29297Seric **	Parameters:
30297Seric **		addr -- the address to parse.
31297Seric **		a -- a pointer to the address descriptor buffer.
32297Seric **			If NULL, a header will be created.
3364284Seric **		flags -- describe detail for parsing.  See RF_ definitions
3464284Seric **			in sendmail.h.
3511445Seric **		delim -- the character to terminate the address, passed
3611445Seric **			to prescan.
3758333Seric **		delimptr -- if non-NULL, set to the location of the
3858333Seric **			delim character that was found.
3956678Seric **		e -- the envelope that will contain this address.
40297Seric **
41297Seric **	Returns:
42297Seric **		A pointer to the address descriptor header (`a' if
43297Seric **			`a' is non-NULL).
44297Seric **		NULL on error.
45297Seric **
46297Seric **	Side Effects:
47297Seric **		none
48297Seric */
49297Seric 
509374Seric /* following delimiters are inherent to the internal algorithms */
5159278Seric # define DELIMCHARS	"()<>,;\r\n"	/* default word delimiters */
522091Seric 
532973Seric ADDRESS *
5464284Seric parseaddr(addr, a, flags, delim, delimptr, e)
55297Seric 	char *addr;
562973Seric 	register ADDRESS *a;
5764284Seric 	int flags;
5859700Seric 	int delim;
5958333Seric 	char **delimptr;
6056678Seric 	register ENVELOPE *e;
61297Seric {
623149Seric 	register char **pvp;
6358333Seric 	auto char *delimptrbuf;
6459084Seric 	bool queueup;
6516914Seric 	char pvpbuf[PSBUFSIZE];
6656678Seric 	extern ADDRESS *buildaddr();
6757388Seric 	extern bool invalidaddr();
68297Seric 
69297Seric 	/*
70297Seric 	**  Initialize and prescan address.
71297Seric 	*/
72297Seric 
7356678Seric 	e->e_to = addr;
747675Seric 	if (tTd(20, 1))
759888Seric 		printf("\n--parseaddr(%s)\n", addr);
763188Seric 
7758333Seric 	if (delimptr == NULL)
7858333Seric 		delimptr = &delimptrbuf;
7958333Seric 
8065066Seric 	pvp = prescan(addr, delim, pvpbuf, sizeof pvpbuf, delimptr);
813149Seric 	if (pvp == NULL)
8256729Seric 	{
8356729Seric 		if (tTd(20, 1))
8456729Seric 			printf("parseaddr-->NULL\n");
85297Seric 		return (NULL);
8656729Seric 	}
87297Seric 
8864726Seric 	if (invalidaddr(addr, delim == '\0' ? NULL : *delimptr))
8964726Seric 	{
9064726Seric 		if (tTd(20, 1))
9164726Seric 			printf("parseaddr-->bad address\n");
9264726Seric 		return NULL;
9364726Seric 	}
9464726Seric 
95297Seric 	/*
9664348Seric 	**  Save addr if we are going to have to.
9764348Seric 	**
9864348Seric 	**	We have to do this early because there is a chance that
9964348Seric 	**	the map lookups in the rewriting rules could clobber
10064348Seric 	**	static memory somewhere.
10164348Seric 	*/
10264348Seric 
10364348Seric 	if (bitset(RF_COPYPADDR, flags) && addr != NULL)
10464348Seric 	{
10564348Seric 		char savec = **delimptr;
10664348Seric 
10764348Seric 		if (savec != '\0')
10864348Seric 			**delimptr = '\0';
10966794Seric 		e->e_to = addr = newstr(addr);
11064348Seric 		if (savec != '\0')
11164348Seric 			**delimptr = savec;
11264348Seric 	}
11364348Seric 
11464348Seric 	/*
1153149Seric 	**  Apply rewriting rules.
1167889Seric 	**	Ruleset 0 does basic parsing.  It must resolve.
117297Seric 	*/
118297Seric 
11959084Seric 	queueup = FALSE;
12065071Seric 	if (rewrite(pvp, 3, 0, e) == EX_TEMPFAIL)
12159084Seric 		queueup = TRUE;
12265071Seric 	if (rewrite(pvp, 0, 0, e) == EX_TEMPFAIL)
12359084Seric 		queueup = TRUE;
124297Seric 
125297Seric 
126297Seric 	/*
1273149Seric 	**  Build canonical address from pvp.
128297Seric 	*/
129297Seric 
13064284Seric 	a = buildaddr(pvp, a, flags, e);
131297Seric 
132297Seric 	/*
1333149Seric 	**  Make local copies of the host & user and then
1343149Seric 	**  transport them out.
135297Seric 	*/
136297Seric 
13764348Seric 	allocaddr(a, flags, addr);
13864306Seric 	if (bitset(QBADADDR, a->q_flags))
13964306Seric 		return a;
14056678Seric 
14156678Seric 	/*
14259084Seric 	**  If there was a parsing failure, mark it for queueing.
14359084Seric 	*/
14459084Seric 
14559084Seric 	if (queueup)
14659595Seric 	{
14759734Seric 		char *msg = "Transient parse error -- message queued for future delivery";
14859734Seric 
14959595Seric 		if (tTd(20, 1))
15059595Seric 			printf("parseaddr: queuing message\n");
15159734Seric 		message(msg);
15259734Seric 		if (e->e_message == NULL)
15360009Seric 			e->e_message = newstr(msg);
15459084Seric 		a->q_flags |= QQUEUEUP;
15568358Seric 		a->q_status = "4.4.3";
15659595Seric 	}
15759084Seric 
15859084Seric 	/*
15956678Seric 	**  Compute return value.
16056678Seric 	*/
16156678Seric 
16256678Seric 	if (tTd(20, 1))
1638078Seric 	{
16456678Seric 		printf("parseaddr-->");
16556678Seric 		printaddr(a, FALSE);
16656678Seric 	}
16756678Seric 
16856678Seric 	return (a);
16956678Seric }
17056678Seric /*
17157388Seric **  INVALIDADDR -- check for address containing meta-characters
17257388Seric **
17357388Seric **	Parameters:
17457388Seric **		addr -- the address to check.
17557388Seric **
17657388Seric **	Returns:
17757388Seric **		TRUE -- if the address has any "wierd" characters
17857388Seric **		FALSE -- otherwise.
17957388Seric */
18057388Seric 
18157388Seric bool
18264726Seric invalidaddr(addr, delimptr)
18357388Seric 	register char *addr;
18464726Seric 	char *delimptr;
18557388Seric {
18668433Seric 	char savedelim = '\0';
18764726Seric 
18864726Seric 	if (delimptr != NULL)
18964764Seric 	{
19064726Seric 		savedelim = *delimptr;
19164764Seric 		if (savedelim != '\0')
19264764Seric 			*delimptr = '\0';
19364764Seric 	}
19464726Seric #if 0
19564726Seric 	/* for testing.... */
19664726Seric 	if (strcmp(addr, "INvalidADDR") == 0)
19757388Seric 	{
19864726Seric 		usrerr("553 INvalid ADDRess");
19964764Seric 		goto addrfailure;
20057388Seric 	}
20164726Seric #endif
20264726Seric 	for (; *addr != '\0'; addr++)
20364726Seric 	{
20464726Seric 		if ((*addr & 0340) == 0200)
20564726Seric 			break;
20664726Seric 	}
20764726Seric 	if (*addr == '\0')
20864764Seric 	{
20968400Seric 		if (delimptr != NULL && savedelim != '\0')
21064764Seric 			*delimptr = savedelim;
21164726Seric 		return FALSE;
21264764Seric 	}
21364726Seric 	setstat(EX_USAGE);
21464726Seric 	usrerr("553 Address contained invalid control characters");
21564764Seric   addrfailure:
21668446Seric 	if (delimptr != NULL && savedelim != '\0')
21764764Seric 		*delimptr = savedelim;
21864726Seric 	return TRUE;
21957388Seric }
22057388Seric /*
22156678Seric **  ALLOCADDR -- do local allocations of address on demand.
22256678Seric **
22356678Seric **	Also lowercases the host name if requested.
22456678Seric **
22556678Seric **	Parameters:
22656678Seric **		a -- the address to reallocate.
22764284Seric **		flags -- the copy flag (see RF_ definitions in sendmail.h
22864284Seric **			for a description).
22956678Seric **		paddr -- the printname of the address.
23056678Seric **
23156678Seric **	Returns:
23256678Seric **		none.
23356678Seric **
23456678Seric **	Side Effects:
23556678Seric **		Copies portions of a into local buffers as requested.
23656678Seric */
23756678Seric 
23864348Seric allocaddr(a, flags, paddr)
23956678Seric 	register ADDRESS *a;
24064284Seric 	int flags;
24156678Seric 	char *paddr;
24256678Seric {
24358673Seric 	if (tTd(24, 4))
24467693Seric 		printf("allocaddr(flags=%x, paddr=%s)\n", flags, paddr);
24558673Seric 
24664348Seric 	a->q_paddr = paddr;
2478078Seric 
24824944Seric 	if (a->q_user == NULL)
24924944Seric 		a->q_user = "";
25024944Seric 	if (a->q_host == NULL)
25124944Seric 		a->q_host = "";
25224944Seric 
25364284Seric 	if (bitset(RF_COPYPARSE, flags))
254297Seric 	{
25524944Seric 		a->q_host = newstr(a->q_host);
2563149Seric 		if (a->q_user != a->q_paddr)
2573149Seric 			a->q_user = newstr(a->q_user);
258297Seric 	}
259297Seric 
26056678Seric 	if (a->q_paddr == NULL)
26156678Seric 		a->q_paddr = a->q_user;
262297Seric }
263297Seric /*
264297Seric **  PRESCAN -- Prescan name and make it canonical
265297Seric **
2669374Seric **	Scans a name and turns it into a set of tokens.  This process
2679374Seric **	deletes blanks and comments (in parentheses).
268297Seric **
269297Seric **	This routine knows about quoted strings and angle brackets.
270297Seric **
271297Seric **	There are certain subtleties to this routine.  The one that
272297Seric **	comes to mind now is that backslashes on the ends of names
273297Seric **	are silently stripped off; this is intentional.  The problem
274297Seric **	is that some versions of sndmsg (like at LBL) set the kill
275297Seric **	character to something other than @ when reading addresses;
276297Seric **	so people type "csvax.eric\@berkeley" -- which screws up the
277297Seric **	berknet mailer.
278297Seric **
279297Seric **	Parameters:
280297Seric **		addr -- the name to chomp.
281297Seric **		delim -- the delimiter for the address, normally
282297Seric **			'\0' or ','; \0 is accepted in any case.
28315284Seric **			If '\t' then we are reading the .cf file.
28416914Seric **		pvpbuf -- place to put the saved text -- note that
28516914Seric **			the pointers are static.
28665066Seric **		pvpbsize -- size of pvpbuf.
28758333Seric **		delimptr -- if non-NULL, set to the location of the
28858333Seric **			terminating delimiter.
289297Seric **
290297Seric **	Returns:
2913149Seric **		A pointer to a vector of tokens.
292297Seric **		NULL on error.
293297Seric */
294297Seric 
2958078Seric /* states and character types */
2968078Seric # define OPR		0	/* operator */
2978078Seric # define ATM		1	/* atom */
2988078Seric # define QST		2	/* in quoted string */
2998078Seric # define SPC		3	/* chewing up spaces */
3008078Seric # define ONE		4	/* pick up one character */
3013149Seric 
3028078Seric # define NSTATES	5	/* number of states */
3038078Seric # define TYPE		017	/* mask to select state type */
3048078Seric 
3058078Seric /* meta bits for table */
3068078Seric # define M		020	/* meta character; don't pass through */
3078078Seric # define B		040	/* cause a break */
3088078Seric # define MB		M|B	/* meta-break */
3098078Seric 
3108078Seric static short StateTab[NSTATES][NSTATES] =
3118078Seric {
3128087Seric    /*	oldst	chtype>	OPR	ATM	QST	SPC	ONE	*/
3139051Seric 	/*OPR*/		OPR|B,	ATM|B,	QST|B,	SPC|MB,	ONE|B,
3149051Seric 	/*ATM*/		OPR|B,	ATM,	QST|B,	SPC|MB,	ONE|B,
3159051Seric 	/*QST*/		QST,	QST,	OPR,	QST,	QST,
3168078Seric 	/*SPC*/		OPR,	ATM,	QST,	SPC|M,	ONE,
3178078Seric 	/*ONE*/		OPR,	OPR,	OPR,	OPR,	OPR,
3188078Seric };
3198078Seric 
32065092Seric /* token type table -- it gets modified with $o characters */
32165092Seric static TokTypeTab[256] =
32265092Seric {
32365092Seric 	ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,SPC,SPC,SPC,SPC,SPC,ATM,ATM,
32465092Seric 	ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,
32565092Seric 	SPC,ATM,QST,ATM,ATM,ATM,ATM,ATM,ATM,SPC,ATM,ATM,ATM,ATM,ATM,ATM,
32665092Seric 	ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,
32765092Seric 	ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,
32865092Seric 	ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,
32965092Seric 	ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,
33065092Seric 	ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,
33165092Seric 	OPR,OPR,ONE,OPR,OPR,OPR,OPR,OPR,OPR,OPR,OPR,OPR,OPR,OPR,OPR,OPR,
33265092Seric 	OPR,OPR,OPR,ONE,ONE,ONE,OPR,OPR,OPR,OPR,OPR,OPR,OPR,OPR,OPR,OPR,
33365092Seric 	ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,
33465092Seric 	ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,
33565092Seric 	ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,
33665092Seric 	ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,
33765092Seric 	ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,
33865092Seric 	ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,
33965092Seric };
34065092Seric 
34165092Seric #define toktype(c)	((int) TokTypeTab[(c) & 0xff])
34265092Seric 
34365092Seric 
3448078Seric # define NOCHAR		-1	/* signal nothing in lookahead token */
3458078Seric 
3463149Seric char **
34765066Seric prescan(addr, delim, pvpbuf, pvpbsize, delimptr)
348297Seric 	char *addr;
34968353Seric 	int delim;
35016914Seric 	char pvpbuf[];
35158333Seric 	char **delimptr;
352297Seric {
353297Seric 	register char *p;
3548078Seric 	register char *q;
3559346Seric 	register int c;
3563149Seric 	char **avp;
357297Seric 	bool bslashmode;
358297Seric 	int cmntcnt;
3598423Seric 	int anglecnt;
3603149Seric 	char *tok;
3618078Seric 	int state;
3628078Seric 	int newstate;
36359747Seric 	char *saveto = CurEnv->e_to;
3648078Seric 	static char *av[MAXATOM+1];
36565092Seric 	static char firsttime = TRUE;
36656678Seric 	extern int errno;
367297Seric 
36865092Seric 	if (firsttime)
36965092Seric 	{
37065092Seric 		/* initialize the token type table */
37165092Seric 		char obuf[50];
37265092Seric 
37365092Seric 		firsttime = FALSE;
37468529Seric 		expand("\201o", obuf, sizeof obuf - sizeof DELIMCHARS, CurEnv);
37565092Seric 		strcat(obuf, DELIMCHARS);
37665092Seric 		for (p = obuf; *p != '\0'; p++)
37765092Seric 		{
37865092Seric 			if (TokTypeTab[*p & 0xff] == ATM)
37965092Seric 				TokTypeTab[*p & 0xff] = OPR;
38065092Seric 		}
38165092Seric 	}
38265092Seric 
38315253Seric 	/* make sure error messages don't have garbage on them */
38415253Seric 	errno = 0;
38515253Seric 
38616914Seric 	q = pvpbuf;
3873149Seric 	bslashmode = FALSE;
3887800Seric 	cmntcnt = 0;
3898423Seric 	anglecnt = 0;
3903149Seric 	avp = av;
39156678Seric 	state = ATM;
3928078Seric 	c = NOCHAR;
3938078Seric 	p = addr;
39459747Seric 	CurEnv->e_to = p;
39556764Seric 	if (tTd(22, 11))
396297Seric 	{
3978078Seric 		printf("prescan: ");
3988078Seric 		xputs(p);
39923109Seric 		(void) putchar('\n');
4008078Seric 	}
4018078Seric 
4028078Seric 	do
4038078Seric 	{
4043149Seric 		/* read a token */
4053149Seric 		tok = q;
4068078Seric 		for (;;)
407297Seric 		{
4088078Seric 			/* store away any old lookahead character */
40959277Seric 			if (c != NOCHAR && !bslashmode)
4108078Seric 			{
41115284Seric 				/* see if there is room */
41265066Seric 				if (q >= &pvpbuf[pvpbsize - 5])
4138078Seric 				{
41458151Seric 					usrerr("553 Address too long");
41568526Seric 					if (strlen(addr) > MAXNAME)
41668526Seric 						addr[MAXNAME] = '\0';
41765015Seric 	returnnull:
41858333Seric 					if (delimptr != NULL)
41958333Seric 						*delimptr = p;
42059747Seric 					CurEnv->e_to = saveto;
4218078Seric 					return (NULL);
4228078Seric 				}
42315284Seric 
42415284Seric 				/* squirrel it away */
4258078Seric 				*q++ = c;
4268078Seric 			}
4278078Seric 
4288078Seric 			/* read a new input character */
4298078Seric 			c = *p++;
43057631Seric 			if (c == '\0')
43156764Seric 			{
43256764Seric 				/* diagnose and patch up bad syntax */
43356764Seric 				if (state == QST)
43456764Seric 				{
43564767Seric 					usrerr("653 Unbalanced '\"'");
43656764Seric 					c = '"';
43756764Seric 				}
43856764Seric 				else if (cmntcnt > 0)
43956764Seric 				{
44064767Seric 					usrerr("653 Unbalanced '('");
44156764Seric 					c = ')';
44256764Seric 				}
44356764Seric 				else if (anglecnt > 0)
44456764Seric 				{
44556764Seric 					c = '>';
44664767Seric 					usrerr("653 Unbalanced '<'");
44756764Seric 				}
44856764Seric 				else
44956764Seric 					break;
45015284Seric 
45156764Seric 				p--;
45256764Seric 			}
45357631Seric 			else if (c == delim && anglecnt <= 0 &&
45457631Seric 					cmntcnt <= 0 && state != QST)
45557631Seric 				break;
45656764Seric 
4578078Seric 			if (tTd(22, 101))
4588078Seric 				printf("c=%c, s=%d; ", c, state);
4598078Seric 
4603149Seric 			/* chew up special characters */
4613149Seric 			*q = '\0';
4623149Seric 			if (bslashmode)
4633149Seric 			{
46459105Seric 				bslashmode = FALSE;
46559105Seric 
46624944Seric 				/* kludge \! for naive users */
46758061Seric 				if (cmntcnt > 0)
46859105Seric 				{
46958061Seric 					c = NOCHAR;
47059105Seric 					continue;
47159105Seric 				}
47259105Seric 				else if (c != '!' || state == QST)
47359105Seric 				{
47456678Seric 					*q++ = '\\';
47559105Seric 					continue;
47659105Seric 				}
4773149Seric 			}
47856678Seric 
47956678Seric 			if (c == '\\')
4803149Seric 			{
4813149Seric 				bslashmode = TRUE;
4823149Seric 			}
48356678Seric 			else if (state == QST)
4848514Seric 			{
4858514Seric 				/* do nothing, just avoid next clauses */
4868514Seric 			}
4878078Seric 			else if (c == '(')
4884100Seric 			{
4898078Seric 				cmntcnt++;
4908078Seric 				c = NOCHAR;
4914100Seric 			}
4928078Seric 			else if (c == ')')
4933149Seric 			{
4948078Seric 				if (cmntcnt <= 0)
4953149Seric 				{
49664767Seric 					usrerr("653 Unbalanced ')'");
49763844Seric 					c = NOCHAR;
4983149Seric 				}
4998078Seric 				else
5008078Seric 					cmntcnt--;
5018078Seric 			}
5028078Seric 			else if (cmntcnt > 0)
5038078Seric 				c = NOCHAR;
5048423Seric 			else if (c == '<')
5058423Seric 				anglecnt++;
5068423Seric 			else if (c == '>')
5078423Seric 			{
5088423Seric 				if (anglecnt <= 0)
5098423Seric 				{
51064767Seric 					usrerr("653 Unbalanced '>'");
51163844Seric 					c = NOCHAR;
5128423Seric 				}
51363844Seric 				else
51463844Seric 					anglecnt--;
5158423Seric 			}
51658050Seric 			else if (delim == ' ' && isascii(c) && isspace(c))
51711423Seric 				c = ' ';
5183149Seric 
5198078Seric 			if (c == NOCHAR)
5208078Seric 				continue;
5213149Seric 
5228078Seric 			/* see if this is end of input */
52311405Seric 			if (c == delim && anglecnt <= 0 && state != QST)
5243149Seric 				break;
5253149Seric 
5268078Seric 			newstate = StateTab[state][toktype(c)];
5278078Seric 			if (tTd(22, 101))
5288078Seric 				printf("ns=%02o\n", newstate);
5298078Seric 			state = newstate & TYPE;
5308078Seric 			if (bitset(M, newstate))
5318078Seric 				c = NOCHAR;
5328078Seric 			if (bitset(B, newstate))
5334228Seric 				break;
534297Seric 		}
5353149Seric 
5363149Seric 		/* new token */
5378078Seric 		if (tok != q)
5381378Seric 		{
5398078Seric 			*q++ = '\0';
5408078Seric 			if (tTd(22, 36))
541297Seric 			{
5428078Seric 				printf("tok=");
5438078Seric 				xputs(tok);
54423109Seric 				(void) putchar('\n');
545297Seric 			}
5468078Seric 			if (avp >= &av[MAXATOM])
547297Seric 			{
54858151Seric 				syserr("553 prescan: too many tokens");
54965015Seric 				goto returnnull;
550297Seric 			}
55165015Seric 			if (q - tok > MAXNAME)
55265015Seric 			{
55365015Seric 				syserr("553 prescan: token too long");
55465015Seric 				goto returnnull;
55565015Seric 			}
5568078Seric 			*avp++ = tok;
557297Seric 		}
5588423Seric 	} while (c != '\0' && (c != delim || anglecnt > 0));
5593149Seric 	*avp = NULL;
56058333Seric 	p--;
56158333Seric 	if (delimptr != NULL)
56258333Seric 		*delimptr = p;
56356764Seric 	if (tTd(22, 12))
56456764Seric 	{
56556764Seric 		printf("prescan==>");
56656764Seric 		printav(av);
56756764Seric 	}
56859747Seric 	CurEnv->e_to = saveto;
56958546Seric 	if (av[0] == NULL)
57064966Seric 	{
57164966Seric 		if (tTd(22, 1))
57264966Seric 			printf("prescan: null leading token\n");
57358546Seric 		return (NULL);
57464966Seric 	}
57558403Seric 	return (av);
5763149Seric }
5773149Seric /*
5783149Seric **  REWRITE -- apply rewrite rules to token vector.
5793149Seric **
5804476Seric **	This routine is an ordered production system.  Each rewrite
5814476Seric **	rule has a LHS (called the pattern) and a RHS (called the
5824476Seric **	rewrite); 'rwr' points the the current rewrite rule.
5834476Seric **
5844476Seric **	For each rewrite rule, 'avp' points the address vector we
5854476Seric **	are trying to match against, and 'pvp' points to the pattern.
5868058Seric **	If pvp points to a special match value (MATCHZANY, MATCHANY,
5879585Seric **	MATCHONE, MATCHCLASS, MATCHNCLASS) then the address in avp
5889585Seric **	matched is saved away in the match vector (pointed to by 'mvp').
5894476Seric **
5904476Seric **	When a match between avp & pvp does not match, we try to
5919585Seric **	back out.  If we back up over MATCHONE, MATCHCLASS, or MATCHNCLASS
5924476Seric **	we must also back out the match in mvp.  If we reach a
5938058Seric **	MATCHANY or MATCHZANY we just extend the match and start
5948058Seric **	over again.
5954476Seric **
5964476Seric **	When we finally match, we rewrite the address vector
5974476Seric **	and try over again.
5984476Seric **
5993149Seric **	Parameters:
6003149Seric **		pvp -- pointer to token vector.
60159027Seric **		ruleset -- the ruleset to use for rewriting.
60265071Seric **		reclevel -- recursion level (to catch loops).
60359027Seric **		e -- the current envelope.
6043149Seric **
6053149Seric **	Returns:
60659084Seric **		A status code.  If EX_TEMPFAIL, higher level code should
60759084Seric **			attempt recovery.
6083149Seric **
6093149Seric **	Side Effects:
6103149Seric **		pvp is modified.
6113149Seric */
6122091Seric 
6133149Seric struct match
6143149Seric {
6154468Seric 	char	**first;	/* first token matched */
6164468Seric 	char	**last;		/* last token matched */
61758825Seric 	char	**pattern;	/* pointer to pattern */
6183149Seric };
6193149Seric 
6204468Seric # define MAXMATCH	9	/* max params per rewrite */
6213149Seric 
62265136Seric # ifndef MAXRULERECURSION
62365136Seric #  define MAXRULERECURSION	50	/* max recursion depth */
62465136Seric # endif
6253149Seric 
62665136Seric 
62759084Seric int
62865071Seric rewrite(pvp, ruleset, reclevel, e)
6293149Seric 	char **pvp;
6304070Seric 	int ruleset;
63165071Seric 	int reclevel;
63259027Seric 	register ENVELOPE *e;
6333149Seric {
6343149Seric 	register char *ap;		/* address pointer */
6353149Seric 	register char *rp;		/* rewrite pointer */
6363149Seric 	register char **avp;		/* address vector pointer */
6373149Seric 	register char **rvp;		/* rewrite vector pointer */
6388058Seric 	register struct match *mlp;	/* cur ptr into mlist */
6398058Seric 	register struct rewrite *rwr;	/* pointer to current rewrite rule */
64058866Seric 	int ruleno;			/* current rule number */
64159084Seric 	int rstat = EX_OK;		/* return status */
64264740Seric 	int loopcount;
64356678Seric 	struct match mlist[MAXMATCH];	/* stores match on LHS */
6443149Seric 	char *npvp[MAXATOM+1];		/* temporary space for rebuild */
6453149Seric 
64667262Seric 	if (OpMode == MD_TEST || tTd(21, 1))
6473149Seric 	{
6488959Seric 		printf("rewrite: ruleset %2d   input:", ruleset);
64956678Seric 		printav(pvp);
6503149Seric 	}
65156678Seric 	if (ruleset < 0 || ruleset >= MAXRWSETS)
65256326Seric 	{
65358151Seric 		syserr("554 rewrite: illegal ruleset number %d", ruleset);
65459084Seric 		return EX_CONFIG;
65556326Seric 	}
65665136Seric 	if (reclevel++ > MAXRULERECURSION)
65765071Seric 	{
65865071Seric 		syserr("rewrite: infinite recursion, ruleset %d", ruleset);
65965071Seric 		return EX_CONFIG;
66065071Seric 	}
66156678Seric 	if (pvp == NULL)
66259084Seric 		return EX_USAGE;
66356326Seric 
6643149Seric 	/*
66556678Seric 	**  Run through the list of rewrite rules, applying
66656678Seric 	**	any that match.
6673149Seric 	*/
6683149Seric 
66958866Seric 	ruleno = 1;
67064740Seric 	loopcount = 0;
6714070Seric 	for (rwr = RewriteRules[ruleset]; rwr != NULL; )
6723149Seric 	{
6737675Seric 		if (tTd(21, 12))
674297Seric 		{
6758069Seric 			printf("-----trying rule:");
67656678Seric 			printav(rwr->r_lhs);
6773149Seric 		}
6783149Seric 
6793149Seric 		/* try to match on this rule */
6804468Seric 		mlp = mlist;
6818058Seric 		rvp = rwr->r_lhs;
6828058Seric 		avp = pvp;
68358866Seric 		if (++loopcount > 100)
6843149Seric 		{
68558866Seric 			syserr("554 Infinite loop in ruleset %d, rule %d",
68658866Seric 				ruleset, ruleno);
68758866Seric 			if (tTd(21, 1))
68852637Seric 			{
68956678Seric 				printf("workspace: ");
69056678Seric 				printav(pvp);
69152637Seric 			}
69258866Seric 			break;
69358866Seric 		}
69458866Seric 
69558866Seric 		while ((ap = *avp) != NULL || *rvp != NULL)
69658866Seric 		{
6973149Seric 			rp = *rvp;
6988058Seric 			if (tTd(21, 35))
6998058Seric 			{
70058825Seric 				printf("ADVANCE rp=");
70157531Seric 				xputs(rp);
70257532Seric 				printf(", ap=");
7038058Seric 				xputs(ap);
7048069Seric 				printf("\n");
7058058Seric 			}
70656678Seric 			if (rp == NULL)
70756326Seric 			{
7083149Seric 				/* end-of-pattern before end-of-address */
7098058Seric 				goto backup;
71056678Seric 			}
71158173Seric 			if (ap == NULL && (*rp & 0377) != MATCHZANY &&
71258827Seric 			    (*rp & 0377) != MATCHZERO)
71356326Seric 			{
71458825Seric 				/* end-of-input with patterns left */
71558825Seric 				goto backup;
716297Seric 			}
71756326Seric 
71858050Seric 			switch (*rp & 0377)
7198058Seric 			{
72058814Seric 				char buf[MAXLINE];
72156326Seric 
72256678Seric 			  case MATCHCLASS:
72358825Seric 				/* match any phrase in a class */
72458825Seric 				mlp->pattern = rvp;
72558814Seric 				mlp->first = avp;
72658814Seric 	extendclass:
72758825Seric 				ap = *avp;
72858825Seric 				if (ap == NULL)
72958814Seric 					goto backup;
73058814Seric 				mlp->last = avp++;
73158814Seric 				cataddr(mlp->first, mlp->last, buf, sizeof buf, '\0');
73268199Seric 				if (!wordinclass(buf, rp[1]))
73356326Seric 				{
73458825Seric 					if (tTd(21, 36))
73558825Seric 					{
73658825Seric 						printf("EXTEND  rp=");
73758825Seric 						xputs(rp);
73858825Seric 						printf(", ap=");
73958825Seric 						xputs(ap);
74058825Seric 						printf("\n");
74158825Seric 					}
74258825Seric 					goto extendclass;
74356326Seric 				}
74458825Seric 				if (tTd(21, 36))
74558825Seric 					printf("CLMATCH\n");
74658814Seric 				mlp++;
74758814Seric 				break;
7484060Seric 
74958825Seric 			  case MATCHNCLASS:
75058825Seric 				/* match any token not in a class */
75168199Seric 				if (wordinclass(ap, rp[1]))
75258825Seric 					goto backup;
75358825Seric 
75458825Seric 				/* fall through */
75558825Seric 
75656678Seric 			  case MATCHONE:
75756678Seric 			  case MATCHANY:
75856678Seric 				/* match exactly one token */
75958825Seric 				mlp->pattern = rvp;
76056678Seric 				mlp->first = avp;
76156678Seric 				mlp->last = avp++;
7628058Seric 				mlp++;
76356678Seric 				break;
7648058Seric 
76556678Seric 			  case MATCHZANY:
76656678Seric 				/* match zero or more tokens */
76758825Seric 				mlp->pattern = rvp;
76856678Seric 				mlp->first = avp;
76956678Seric 				mlp->last = avp - 1;
77056678Seric 				mlp++;
77156678Seric 				break;
77256326Seric 
77358827Seric 			  case MATCHZERO:
77458173Seric 				/* match zero tokens */
77558173Seric 				break;
77658173Seric 
77759027Seric 			  case MACRODEXPAND:
77859027Seric 				/*
77959027Seric 				**  Match against run-time macro.
78059027Seric 				**  This algorithm is broken for the
78159027Seric 				**  general case (no recursive macros,
78259027Seric 				**  improper tokenization) but should
78359027Seric 				**  work for the usual cases.
78459027Seric 				*/
78559027Seric 
78659027Seric 				ap = macvalue(rp[1], e);
78759027Seric 				mlp->first = avp;
78859027Seric 				if (tTd(21, 2))
78959027Seric 					printf("rewrite: LHS $&%c => \"%s\"\n",
79059027Seric 						rp[1],
79159027Seric 						ap == NULL ? "(NULL)" : ap);
79259027Seric 
79359027Seric 				if (ap == NULL)
79459027Seric 					break;
79560502Seric 				while (*ap != '\0')
79659027Seric 				{
79759027Seric 					if (*avp == NULL ||
79859027Seric 					    strncasecmp(ap, *avp, strlen(*avp)) != 0)
79959027Seric 					{
80059027Seric 						/* no match */
80159027Seric 						avp = mlp->first;
80259027Seric 						goto backup;
80359027Seric 					}
80459027Seric 					ap += strlen(*avp++);
80559027Seric 				}
80659027Seric 
80759027Seric 				/* match */
80859027Seric 				break;
80959027Seric 
81056678Seric 			  default:
81156678Seric 				/* must have exact match */
81256678Seric 				if (strcasecmp(rp, ap))
8138058Seric 					goto backup;
8144468Seric 				avp++;
81556678Seric 				break;
8163149Seric 			}
8173149Seric 
81856678Seric 			/* successful match on this token */
8193149Seric 			rvp++;
8203149Seric 			continue;
8213149Seric 
82258825Seric 	  backup:
82356678Seric 			/* match failed -- back up */
82458825Seric 			while (--mlp >= mlist)
8253149Seric 			{
82658825Seric 				rvp = mlp->pattern;
82756678Seric 				rp = *rvp;
82858825Seric 				avp = mlp->last + 1;
82958825Seric 				ap = *avp;
83058825Seric 
83158825Seric 				if (tTd(21, 36))
83258825Seric 				{
83358825Seric 					printf("BACKUP  rp=");
83458825Seric 					xputs(rp);
83558825Seric 					printf(", ap=");
83658825Seric 					xputs(ap);
83758825Seric 					printf("\n");
83858825Seric 				}
83958825Seric 
84058825Seric 				if (ap == NULL)
84158825Seric 				{
84258825Seric 					/* run off the end -- back up again */
84358825Seric 					continue;
84458825Seric 				}
84558050Seric 				if ((*rp & 0377) == MATCHANY ||
84658050Seric 				    (*rp & 0377) == MATCHZANY)
8474468Seric 				{
84856678Seric 					/* extend binding and continue */
84958825Seric 					mlp->last = avp++;
85056678Seric 					rvp++;
85158825Seric 					mlp++;
85256678Seric 					break;
8534468Seric 				}
85458825Seric 				if ((*rp & 0377) == MATCHCLASS)
85556678Seric 				{
85658814Seric 					/* extend binding and try again */
85763397Seric 					mlp->last = avp;
85858814Seric 					goto extendclass;
85958814Seric 				}
8603149Seric 			}
8613149Seric 
86258825Seric 			if (mlp < mlist)
86356678Seric 			{
86456678Seric 				/* total failure to match */
86556326Seric 				break;
8663149Seric 			}
867297Seric 		}
8683149Seric 
8693149Seric 		/*
87056678Seric 		**  See if we successfully matched
8713149Seric 		*/
8723149Seric 
87358827Seric 		if (mlp < mlist || *rvp != NULL)
8743149Seric 		{
8759374Seric 			if (tTd(21, 10))
8769374Seric 				printf("----- rule fails\n");
8779374Seric 			rwr = rwr->r_next;
87858866Seric 			ruleno++;
87964740Seric 			loopcount = 0;
8809374Seric 			continue;
8819374Seric 		}
8823149Seric 
8839374Seric 		rvp = rwr->r_rhs;
8849374Seric 		if (tTd(21, 12))
8859374Seric 		{
8869374Seric 			printf("-----rule matches:");
88756678Seric 			printav(rvp);
8889374Seric 		}
8899374Seric 
8909374Seric 		rp = *rvp;
89158050Seric 		if ((*rp & 0377) == CANONUSER)
8929374Seric 		{
8939374Seric 			rvp++;
8949374Seric 			rwr = rwr->r_next;
89558866Seric 			ruleno++;
89664740Seric 			loopcount = 0;
8979374Seric 		}
89858050Seric 		else if ((*rp & 0377) == CANONHOST)
8999374Seric 		{
9009374Seric 			rvp++;
9019374Seric 			rwr = NULL;
9029374Seric 		}
90358050Seric 		else if ((*rp & 0377) == CANONNET)
9049374Seric 			rwr = NULL;
9059374Seric 
9069374Seric 		/* substitute */
9079374Seric 		for (avp = npvp; *rvp != NULL; rvp++)
9089374Seric 		{
9099374Seric 			register struct match *m;
9109374Seric 			register char **pp;
9119374Seric 
9128058Seric 			rp = *rvp;
91358050Seric 			if ((*rp & 0377) == MATCHREPL)
9148058Seric 			{
91516914Seric 				/* substitute from LHS */
91616914Seric 				m = &mlist[rp[1] - '1'];
91756678Seric 				if (m < mlist || m >= mlp)
9189374Seric 				{
91958151Seric 					syserr("554 rewrite: ruleset %d: replacement $%c out of bounds",
92056326Seric 						ruleset, rp[1]);
92159084Seric 					return EX_CONFIG;
9229374Seric 				}
92316914Seric 				if (tTd(21, 15))
92416914Seric 				{
92516914Seric 					printf("$%c:", rp[1]);
92616914Seric 					pp = m->first;
92756678Seric 					while (pp <= m->last)
92816914Seric 					{
92916914Seric 						printf(" %x=\"", *pp);
93016914Seric 						(void) fflush(stdout);
93116914Seric 						printf("%s\"", *pp++);
93216914Seric 					}
93316914Seric 					printf("\n");
93416914Seric 				}
9359374Seric 				pp = m->first;
93656678Seric 				while (pp <= m->last)
9373149Seric 				{
93816914Seric 					if (avp >= &npvp[MAXATOM])
93956678Seric 					{
94058151Seric 						syserr("554 rewrite: expansion too long");
94159084Seric 						return EX_DATAERR;
94256678Seric 					}
94316914Seric 					*avp++ = *pp++;
9443149Seric 				}
9453149Seric 			}
94616914Seric 			else
9478226Seric 			{
94816914Seric 				/* vanilla replacement */
9499374Seric 				if (avp >= &npvp[MAXATOM])
95016889Seric 				{
95156678Seric 	toolong:
95258151Seric 					syserr("554 rewrite: expansion too long");
95359084Seric 					return EX_DATAERR;
95416889Seric 				}
95559027Seric 				if ((*rp & 0377) != MACRODEXPAND)
95659027Seric 					*avp++ = rp;
95759027Seric 				else
95859027Seric 				{
95959027Seric 					*avp = macvalue(rp[1], e);
96059027Seric 					if (tTd(21, 2))
96159027Seric 						printf("rewrite: RHS $&%c => \"%s\"\n",
96259027Seric 							rp[1],
96359027Seric 							*avp == NULL ? "(NULL)" : *avp);
96459027Seric 					if (*avp != NULL)
96559027Seric 						avp++;
96659027Seric 				}
9678226Seric 			}
9689374Seric 		}
9699374Seric 		*avp++ = NULL;
97016914Seric 
97116914Seric 		/*
97256678Seric 		**  Check for any hostname/keyword lookups.
97316914Seric 		*/
97416914Seric 
97516914Seric 		for (rvp = npvp; *rvp != NULL; rvp++)
97616914Seric 		{
97756678Seric 			char **hbrvp;
97816914Seric 			char **xpvp;
97916914Seric 			int trsize;
98056678Seric 			char *replac;
98156678Seric 			int endtoken;
98256678Seric 			STAB *map;
98356678Seric 			char *mapname;
98456678Seric 			char **key_rvp;
98556678Seric 			char **arg_rvp;
98656678Seric 			char **default_rvp;
98756678Seric 			char buf[MAXNAME + 1];
98816914Seric 			char *pvpb1[MAXATOM + 1];
98956823Seric 			char *argvect[10];
99017174Seric 			char pvpbuf[PSBUFSIZE];
99164404Seric 			char *nullpvp[1];
99216914Seric 
99358050Seric 			if ((**rvp & 0377) != HOSTBEGIN &&
99458050Seric 			    (**rvp & 0377) != LOOKUPBEGIN)
99516914Seric 				continue;
99616914Seric 
99716914Seric 			/*
99856678Seric 			**  Got a hostname/keyword lookup.
99916914Seric 			**
100016914Seric 			**	This could be optimized fairly easily.
100116914Seric 			*/
100216914Seric 
100316914Seric 			hbrvp = rvp;
100458050Seric 			if ((**rvp & 0377) == HOSTBEGIN)
100556327Seric 			{
100656678Seric 				endtoken = HOSTEND;
100756678Seric 				mapname = "host";
100856327Seric 			}
100956326Seric 			else
101056327Seric 			{
101156678Seric 				endtoken = LOOKUPEND;
101256678Seric 				mapname = *++rvp;
101356327Seric 			}
101456678Seric 			map = stab(mapname, ST_MAP, ST_FIND);
101556678Seric 			if (map == NULL)
101658151Seric 				syserr("554 rewrite: map %s not found", mapname);
101756678Seric 
101856678Seric 			/* extract the match part */
101956678Seric 			key_rvp = ++rvp;
102056823Seric 			default_rvp = NULL;
102156823Seric 			arg_rvp = argvect;
102256823Seric 			xpvp = NULL;
102356823Seric 			replac = pvpbuf;
102458050Seric 			while (*rvp != NULL && (**rvp & 0377) != endtoken)
102553654Seric 			{
102658050Seric 				int nodetype = **rvp & 0377;
102756823Seric 
102856823Seric 				if (nodetype != CANONHOST && nodetype != CANONUSER)
102956678Seric 				{
103056823Seric 					rvp++;
103156823Seric 					continue;
103256823Seric 				}
103356823Seric 
103456823Seric 				*rvp++ = NULL;
103556823Seric 
103656823Seric 				if (xpvp != NULL)
103756823Seric 				{
103858814Seric 					cataddr(xpvp, NULL, replac,
103958082Seric 						&pvpbuf[sizeof pvpbuf] - replac,
104058082Seric 						'\0');
104156823Seric 					*++arg_rvp = replac;
104256823Seric 					replac += strlen(replac) + 1;
104356823Seric 					xpvp = NULL;
104456823Seric 				}
104556823Seric 				switch (nodetype)
104656823Seric 				{
104756678Seric 				  case CANONHOST:
104856823Seric 					xpvp = rvp;
104956678Seric 					break;
105056678Seric 
105156678Seric 				  case CANONUSER:
105256678Seric 					default_rvp = rvp;
105356678Seric 					break;
105456678Seric 				}
105553654Seric 			}
105616914Seric 			if (*rvp != NULL)
105716914Seric 				*rvp++ = NULL;
105856823Seric 			if (xpvp != NULL)
105956823Seric 			{
106058814Seric 				cataddr(xpvp, NULL, replac,
106158082Seric 					&pvpbuf[sizeof pvpbuf] - replac,
106258082Seric 					'\0');
106356823Seric 				*++arg_rvp = replac;
106456823Seric 			}
106556823Seric 			*++arg_rvp = NULL;
106616914Seric 
106716914Seric 			/* save the remainder of the input string */
106816914Seric 			trsize = (int) (avp - rvp + 1) * sizeof *rvp;
106916914Seric 			bcopy((char *) rvp, (char *) pvpb1, trsize);
107016914Seric 
107156678Seric 			/* look it up */
107258814Seric 			cataddr(key_rvp, NULL, buf, sizeof buf, '\0');
107356823Seric 			argvect[0] = buf;
107460538Seric 			if (map != NULL && bitset(MF_OPEN, map->s_map.map_mflags))
107556836Seric 			{
107659084Seric 				auto int stat = EX_OK;
107756836Seric 
107860215Seric 				/* XXX should try to auto-open the map here */
107960215Seric 
108058796Seric 				if (tTd(60, 1))
108158796Seric 					printf("map_lookup(%s, %s) => ",
108258796Seric 						mapname, buf);
108356836Seric 				replac = (*map->s_map.map_class->map_lookup)(&map->s_map,
108460089Seric 						buf, argvect, &stat);
108558796Seric 				if (tTd(60, 1))
108659084Seric 					printf("%s (%d)\n",
108759084Seric 						replac ? replac : "NOT FOUND",
108859084Seric 						stat);
108959084Seric 
109059084Seric 				/* should recover if stat == EX_TEMPFAIL */
109168706Seric 				if (stat == EX_TEMPFAIL || stat == EX_UNAVAILABLE)
109268706Seric 				{
109368706Seric 					rstat = EX_TEMPFAIL;
1094*68708Seric 					if (tTd(50, 1))
109568706Seric 						printf("map_lookup(%s, %s) failed (stat = %d)\n",
109668706Seric 							mapname, buf, stat);
109768706Seric 					if (e->e_message == NULL)
109868706Seric 					{
109968706Seric 						char mbuf[300];
110068706Seric 
110168706Seric 						sprintf(mbuf, "map %s: lookup (%s) failed",
110268706Seric 							mapname, buf);
110368706Seric 						e->e_message = newstr(mbuf);
110468706Seric 					}
110568706Seric 				}
110656836Seric 			}
110753654Seric 			else
110856678Seric 				replac = NULL;
110956678Seric 
111056678Seric 			/* if no replacement, use default */
111156823Seric 			if (replac == NULL && default_rvp != NULL)
111256823Seric 			{
111360089Seric 				/* create the default */
111460089Seric 				cataddr(default_rvp, NULL, buf, sizeof buf, '\0');
111556823Seric 				replac = buf;
111656823Seric 			}
111756823Seric 
111856678Seric 			if (replac == NULL)
111951317Seric 			{
112056823Seric 				xpvp = key_rvp;
112153654Seric 			}
112264404Seric 			else if (*replac == '\0')
112364404Seric 			{
112464404Seric 				/* null replacement */
112564404Seric 				nullpvp[0] = NULL;
112664404Seric 				xpvp = nullpvp;
112764404Seric 			}
112856678Seric 			else
112953654Seric 			{
113056678Seric 				/* scan the new replacement */
113165066Seric 				xpvp = prescan(replac, '\0', pvpbuf,
113265066Seric 					       sizeof pvpbuf, NULL);
113353654Seric 				if (xpvp == NULL)
113451317Seric 				{
113558403Seric 					/* prescan already printed error */
113659084Seric 					return EX_DATAERR;
113756678Seric 				}
113851317Seric 			}
113951317Seric 
114016914Seric 			/* append it to the token list */
114156678Seric 			for (avp = hbrvp; *xpvp != NULL; xpvp++)
114256678Seric 			{
114317174Seric 				*avp++ = newstr(*xpvp);
114416920Seric 				if (avp >= &npvp[MAXATOM])
114516914Seric 					goto toolong;
114617174Seric 			}
114716914Seric 
114816914Seric 			/* restore the old trailing information */
114956678Seric 			for (xpvp = pvpb1; (*avp++ = *xpvp++) != NULL; )
115016920Seric 				if (avp >= &npvp[MAXATOM])
115116914Seric 					goto toolong;
115217174Seric 
115356678Seric 			break;
115416914Seric 		}
115516914Seric 
115616914Seric 		/*
115716914Seric 		**  Check for subroutine calls.
115816914Seric 		*/
115916914Seric 
116068559Seric 		if (*npvp != NULL && (**npvp & 0377) == CALLSUBR)
116168559Seric 		{
116268559Seric 			int stat;
116359084Seric 
116468559Seric 			if (npvp[1] == NULL)
116568559Seric 			{
116668559Seric 				syserr("parseaddr: NULL subroutine call in ruleset %d, rule %d",
116768559Seric 					ruleset, ruleno);
116868559Seric 				*pvp = NULL;
116968559Seric 			}
117068559Seric 			else
117168559Seric 			{
117268559Seric 				int ruleset;
117368559Seric 				STAB *s;
117468385Seric 
117568559Seric 				bcopy((char *) &npvp[2], (char *) pvp,
117668559Seric 					(int) (avp - npvp - 2) * sizeof *avp);
117768559Seric 				if (tTd(21, 3))
117868559Seric 					printf("-----callsubr %s\n", npvp[1]);
117968559Seric 				s = stab(npvp[1], ST_RULESET, ST_FIND);
118068559Seric 				if (s == NULL)
118168559Seric 					ruleset = atoi(npvp[1]);
118268559Seric 				else
118368559Seric 					ruleset = s->s_ruleset;
118468559Seric 				stat = rewrite(pvp, ruleset, reclevel, e);
118568559Seric 				if (rstat == EX_OK || stat == EX_TEMPFAIL)
118668559Seric 					rstat = stat;
118768559Seric 				if (*pvp != NULL && (**pvp & 0377) == CANONNET)
118868559Seric 				rwr = NULL;
118968559Seric 			}
119068559Seric 		}
119168559Seric 		else
119268559Seric 		{
119368559Seric 			bcopy((char *) npvp, (char *) pvp,
119468559Seric 				(int) (avp - npvp) * sizeof *avp);
119568559Seric 		}
11969374Seric 		if (tTd(21, 4))
11979374Seric 		{
11989374Seric 			printf("rewritten as:");
119956678Seric 			printav(pvp);
12009374Seric 		}
1201297Seric 	}
12028069Seric 
120367262Seric 	if (OpMode == MD_TEST || tTd(21, 1))
12048069Seric 	{
12058959Seric 		printf("rewrite: ruleset %2d returns:", ruleset);
120656678Seric 		printav(pvp);
12078069Seric 	}
120859084Seric 
120959084Seric 	return rstat;
12103149Seric }
12113149Seric /*
12123149Seric **  BUILDADDR -- build address from token vector.
12133149Seric **
12143149Seric **	Parameters:
12153149Seric **		tv -- token vector.
12163149Seric **		a -- pointer to address descriptor to fill.
12173149Seric **			If NULL, one will be allocated.
121864284Seric **		flags -- info regarding whether this is a sender or
121964284Seric **			a recipient.
122058966Seric **		e -- the current envelope.
12213149Seric **
12223149Seric **	Returns:
12234279Seric **		NULL if there was an error.
12244279Seric **		'a' otherwise.
12253149Seric **
12263149Seric **	Side Effects:
12273149Seric **		fills in 'a'
12283149Seric */
12293149Seric 
123057249Seric struct errcodes
123157249Seric {
123257249Seric 	char	*ec_name;		/* name of error code */
123357249Seric 	int	ec_code;		/* numeric code */
123457249Seric } ErrorCodes[] =
123557249Seric {
123657249Seric 	"usage",	EX_USAGE,
123757249Seric 	"nouser",	EX_NOUSER,
123857249Seric 	"nohost",	EX_NOHOST,
123957249Seric 	"unavailable",	EX_UNAVAILABLE,
124057249Seric 	"software",	EX_SOFTWARE,
124157249Seric 	"tempfail",	EX_TEMPFAIL,
124257249Seric 	"protocol",	EX_PROTOCOL,
124357249Seric #ifdef EX_CONFIG
124457249Seric 	"config",	EX_CONFIG,
124557249Seric #endif
124657249Seric 	NULL,		EX_UNAVAILABLE,
124757249Seric };
124857249Seric 
124956678Seric ADDRESS *
125064284Seric buildaddr(tv, a, flags, e)
12513149Seric 	register char **tv;
12523149Seric 	register ADDRESS *a;
125364284Seric 	int flags;
125458966Seric 	register ENVELOPE *e;
12553149Seric {
12563149Seric 	struct mailer **mp;
12573149Seric 	register struct mailer *m;
125858008Seric 	char *bp;
125958008Seric 	int spaceleft;
126064306Seric 	static MAILER errormailer;
126164306Seric 	static char *errorargv[] = { "ERROR", NULL };
126268528Seric 	static char buf[MAXNAME + 1];
12633149Seric 
126464791Seric 	if (tTd(24, 5))
126564791Seric 	{
126667693Seric 		printf("buildaddr, flags=%x, tv=", flags);
126764791Seric 		printav(tv);
126864791Seric 	}
126964791Seric 
12703149Seric 	if (a == NULL)
12713149Seric 		a = (ADDRESS *) xalloc(sizeof *a);
127216889Seric 	bzero((char *) a, sizeof *a);
12733149Seric 
127467880Seric 	/* set up default error return flags */
127567963Seric 	a->q_flags |= QPINGONFAILURE|QPINGONDELAY;
127667880Seric 
12773149Seric 	/* figure out what net/mailer to use */
127864306Seric 	if (*tv == NULL || (**tv & 0377) != CANONNET)
12794279Seric 	{
128058151Seric 		syserr("554 buildaddr: no net");
128164306Seric badaddr:
128264306Seric 		a->q_flags |= QBADADDR;
128364306Seric 		a->q_mailer = &errormailer;
128464306Seric 		if (errormailer.m_name == NULL)
128564306Seric 		{
128664306Seric 			/* initialize the bogus mailer */
128764306Seric 			errormailer.m_name = "*error*";
128864306Seric 			errormailer.m_mailer = "ERROR";
128964306Seric 			errormailer.m_argv = errorargv;
129064306Seric 		}
129164306Seric 		return a;
12924279Seric 	}
12933149Seric 	tv++;
129458680Seric 	if (strcasecmp(*tv, "error") == 0)
12954279Seric 	{
129658050Seric 		if ((**++tv & 0377) == CANONHOST)
129710183Seric 		{
129857249Seric 			register struct errcodes *ep;
129957249Seric 
130058050Seric 			if (isascii(**++tv) && isdigit(**tv))
130157249Seric 			{
130257249Seric 				setstat(atoi(*tv));
130357249Seric 			}
130457249Seric 			else
130557249Seric 			{
130657249Seric 				for (ep = ErrorCodes; ep->ec_name != NULL; ep++)
130757249Seric 					if (strcasecmp(ep->ec_name, *tv) == 0)
130857249Seric 						break;
130957249Seric 				setstat(ep->ec_code);
131057249Seric 			}
131110183Seric 			tv++;
131210183Seric 		}
131364928Seric 		else
131464928Seric 			setstat(EX_UNAVAILABLE);
131558050Seric 		if ((**tv & 0377) != CANONUSER)
131658151Seric 			syserr("554 buildaddr: error: no user");
131758814Seric 		cataddr(++tv, NULL, buf, sizeof buf, ' ');
131858082Seric 		stripquotes(buf);
131964659Seric 		if (isascii(buf[0]) && isdigit(buf[0]) &&
132064659Seric 		    isascii(buf[1]) && isdigit(buf[1]) &&
132164659Seric 		    isascii(buf[2]) && isdigit(buf[2]) &&
132264659Seric 		    buf[3] == ' ')
132364659Seric 		{
132464659Seric 			char fmt[10];
132564659Seric 
132664659Seric 			strncpy(fmt, buf, 3);
132764659Seric 			strcpy(&fmt[3], " %s");
132864659Seric 			usrerr(fmt, buf + 4);
132967786Seric 
133067786Seric 			/*
133167786Seric 			**  If this is a 4xx code and we aren't running
133267786Seric 			**  SMTP on our input, bounce this message;
133367786Seric 			**  otherwise it disappears without a trace.
133467786Seric 			*/
133567786Seric 
133667786Seric 			if (fmt[0] == '4' && OpMode != MD_SMTP &&
133767786Seric 			    OpMode != MD_DAEMON)
133867786Seric 			{
133967786Seric 				e->e_flags |= EF_FATALERRS;
134067786Seric 			}
134164659Seric 		}
134264659Seric 		else
134364659Seric 		{
134466039Seric 			usrerr("553 %s", buf);
134564659Seric 		}
134664306Seric 		goto badaddr;
13474279Seric 	}
134857402Seric 
13494598Seric 	for (mp = Mailer; (m = *mp++) != NULL; )
13503149Seric 	{
135158680Seric 		if (strcasecmp(m->m_name, *tv) == 0)
13523149Seric 			break;
13533149Seric 	}
13543149Seric 	if (m == NULL)
13554279Seric 	{
135658151Seric 		syserr("554 buildaddr: unknown mailer %s", *tv);
135764306Seric 		goto badaddr;
13584279Seric 	}
13594598Seric 	a->q_mailer = m;
13603149Seric 
13613149Seric 	/* figure out what host (if any) */
136256678Seric 	tv++;
136358509Seric 	if ((**tv & 0377) == CANONHOST)
13643149Seric 	{
136558008Seric 		bp = buf;
136658008Seric 		spaceleft = sizeof buf - 1;
136758050Seric 		while (*++tv != NULL && (**tv & 0377) != CANONUSER)
136858008Seric 		{
136958008Seric 			int i = strlen(*tv);
137058008Seric 
137158008Seric 			if (i > spaceleft)
137258008Seric 			{
137358008Seric 				/* out of space for this address */
137458008Seric 				if (spaceleft >= 0)
137558151Seric 					syserr("554 buildaddr: host too long (%.40s...)",
137658008Seric 						buf);
137758008Seric 				i = spaceleft;
137858008Seric 				spaceleft = 0;
137958008Seric 			}
138058008Seric 			if (i <= 0)
138158008Seric 				continue;
138258008Seric 			bcopy(*tv, bp, i);
138358008Seric 			bp += i;
138458008Seric 			spaceleft -= i;
138558008Seric 		}
138658010Seric 		*bp = '\0';
13875704Seric 		a->q_host = newstr(buf);
13883149Seric 	}
138957249Seric 	else
139058509Seric 	{
139158509Seric 		if (!bitnset(M_LOCALMAILER, m->m_flags))
139258509Seric 		{
139358509Seric 			syserr("554 buildaddr: no host");
139464306Seric 			goto badaddr;
139558509Seric 		}
139657249Seric 		a->q_host = NULL;
139758509Seric 	}
13983149Seric 
13993149Seric 	/* figure out the user */
140058050Seric 	if (*tv == NULL || (**tv & 0377) != CANONUSER)
14014279Seric 	{
140258151Seric 		syserr("554 buildaddr: no user");
140364306Seric 		goto badaddr;
14044279Seric 	}
140557402Seric 	tv++;
140651317Seric 
140768098Seric 	if (bitnset(M_CHECKUDB, m->m_flags) && *tv != NULL &&
140868098Seric 	    strcmp(*tv, "@") == 0)
140968098Seric 	{
141068098Seric 		tv++;
141168098Seric 		a->q_flags |= QNOTREMOTE;
141268098Seric 	}
141368098Seric 
141457402Seric 	/* do special mapping for local mailer */
141567472Seric 	if (*tv != NULL)
141657402Seric 	{
141757454Seric 		register char *p = *tv;
141857454Seric 
141957454Seric 		if (*p == '"')
142057454Seric 			p++;
142167472Seric 		if (*p == '|' && bitnset(M_CHECKPROG, m->m_flags))
142257402Seric 			a->q_mailer = m = ProgMailer;
142367472Seric 		else if (*p == '/' && bitnset(M_CHECKFILE, m->m_flags))
142457402Seric 			a->q_mailer = m = FileMailer;
142567472Seric 		else if (*p == ':' && bitnset(M_CHECKINCLUDE, m->m_flags))
142657402Seric 		{
142757402Seric 			/* may be :include: */
142858814Seric 			cataddr(tv, NULL, buf, sizeof buf, '\0');
142958008Seric 			stripquotes(buf);
143058008Seric 			if (strncasecmp(buf, ":include:", 9) == 0)
143158008Seric 			{
143258008Seric 				/* if :include:, don't need further rewriting */
143357402Seric 				a->q_mailer = m = InclMailer;
143458008Seric 				a->q_user = &buf[9];
143558008Seric 				return (a);
143658008Seric 			}
143757402Seric 		}
143857402Seric 	}
143957402Seric 
144064284Seric 	/* rewrite according recipient mailer rewriting rules */
144164284Seric 	define('h', a->q_host, e);
144264284Seric 	if (!bitset(RF_SENDERADDR|RF_HEADERADDR, flags))
144364284Seric 	{
144464284Seric 		/* sender addresses done later */
144565071Seric 		(void) rewrite(tv, 2, 0, e);
144664284Seric 		if (m->m_re_rwset > 0)
144765071Seric 		       (void) rewrite(tv, m->m_re_rwset, 0, e);
144864284Seric 	}
144965071Seric 	(void) rewrite(tv, 4, 0, e);
145019040Seric 
145119040Seric 	/* save the result for the command line/RCPT argument */
145258814Seric 	cataddr(tv, NULL, buf, sizeof buf, '\0');
14533149Seric 	a->q_user = buf;
14543149Seric 
145558670Seric 	/*
145658670Seric 	**  Do mapping to lower case as requested by mailer
145758670Seric 	*/
145858670Seric 
145958670Seric 	if (a->q_host != NULL && !bitnset(M_HST_UPPER, m->m_flags))
146058670Seric 		makelower(a->q_host);
146158670Seric 	if (!bitnset(M_USR_UPPER, m->m_flags))
146258670Seric 		makelower(a->q_user);
146358670Seric 
14643149Seric 	return (a);
14653149Seric }
14663188Seric /*
14674228Seric **  CATADDR -- concatenate pieces of addresses (putting in <LWSP> subs)
14684228Seric **
14694228Seric **	Parameters:
14704228Seric **		pvp -- parameter vector to rebuild.
147158814Seric **		evp -- last parameter to include.  Can be NULL to
147258814Seric **			use entire pvp.
14734228Seric **		buf -- buffer to build the string into.
14744228Seric **		sz -- size of buf.
147558082Seric **		spacesub -- the space separator character; if null,
147658082Seric **			use SpaceSub.
14774228Seric **
14784228Seric **	Returns:
14794228Seric **		none.
14804228Seric **
14814228Seric **	Side Effects:
14824228Seric **		Destroys buf.
14834228Seric */
14844228Seric 
148558814Seric cataddr(pvp, evp, buf, sz, spacesub)
14864228Seric 	char **pvp;
148758814Seric 	char **evp;
14884228Seric 	char *buf;
14894228Seric 	register int sz;
149058082Seric 	char spacesub;
14914228Seric {
14924228Seric 	bool oatomtok = FALSE;
149356678Seric 	bool natomtok = FALSE;
14944228Seric 	register int i;
14954228Seric 	register char *p;
14964228Seric 
149758082Seric 	if (spacesub == '\0')
149858082Seric 		spacesub = SpaceSub;
149958082Seric 
15008423Seric 	if (pvp == NULL)
15018423Seric 	{
150223109Seric 		(void) strcpy(buf, "");
15038423Seric 		return;
15048423Seric 	}
15054228Seric 	p = buf;
150611156Seric 	sz -= 2;
15074228Seric 	while (*pvp != NULL && (i = strlen(*pvp)) < sz)
15084228Seric 	{
15098078Seric 		natomtok = (toktype(**pvp) == ATM);
15104228Seric 		if (oatomtok && natomtok)
151158082Seric 			*p++ = spacesub;
15124228Seric 		(void) strcpy(p, *pvp);
15134228Seric 		oatomtok = natomtok;
15144228Seric 		p += i;
151511156Seric 		sz -= i + 1;
151658814Seric 		if (pvp++ == evp)
151758814Seric 			break;
15184228Seric 	}
15194228Seric 	*p = '\0';
15204228Seric }
15214228Seric /*
15223188Seric **  SAMEADDR -- Determine if two addresses are the same
15233188Seric **
15243188Seric **	This is not just a straight comparison -- if the mailer doesn't
15253188Seric **	care about the host we just ignore it, etc.
15263188Seric **
15273188Seric **	Parameters:
15283188Seric **		a, b -- pointers to the internal forms to compare.
15293188Seric **
15303188Seric **	Returns:
15313188Seric **		TRUE -- they represent the same mailbox.
15323188Seric **		FALSE -- they don't.
15333188Seric **
15343188Seric **	Side Effects:
15353188Seric **		none.
15363188Seric */
15373188Seric 
15383188Seric bool
15399374Seric sameaddr(a, b)
15403188Seric 	register ADDRESS *a;
15413188Seric 	register ADDRESS *b;
15423188Seric {
154365093Seric 	register ADDRESS *ca, *cb;
154465093Seric 
15453188Seric 	/* if they don't have the same mailer, forget it */
15463188Seric 	if (a->q_mailer != b->q_mailer)
15473188Seric 		return (FALSE);
15483188Seric 
15493188Seric 	/* if the user isn't the same, we can drop out */
155056678Seric 	if (strcmp(a->q_user, b->q_user) != 0)
15513188Seric 		return (FALSE);
15523188Seric 
155365093Seric 	/* if we have good uids for both but they differ, these are different */
155465379Seric 	if (a->q_mailer == ProgMailer)
155565379Seric 	{
155665379Seric 		ca = getctladdr(a);
155765379Seric 		cb = getctladdr(b);
155865379Seric 		if (ca != NULL && cb != NULL &&
155965379Seric 		    bitset(QGOODUID, ca->q_flags & cb->q_flags) &&
156065379Seric 		    ca->q_uid != cb->q_uid)
156165379Seric 			return (FALSE);
156265379Seric 	}
156358438Seric 
156458509Seric 	/* otherwise compare hosts (but be careful for NULL ptrs) */
156558509Seric 	if (a->q_host == b->q_host)
156658509Seric 	{
156758509Seric 		/* probably both null pointers */
15683188Seric 		return (TRUE);
156958509Seric 	}
15703188Seric 	if (a->q_host == NULL || b->q_host == NULL)
157158509Seric 	{
157258509Seric 		/* only one is a null pointer */
15733188Seric 		return (FALSE);
157458509Seric 	}
157556678Seric 	if (strcmp(a->q_host, b->q_host) != 0)
15763188Seric 		return (FALSE);
15773188Seric 
15783188Seric 	return (TRUE);
15793188Seric }
15803234Seric /*
15813234Seric **  PRINTADDR -- print address (for debugging)
15823234Seric **
15833234Seric **	Parameters:
15843234Seric **		a -- the address to print
15853234Seric **		follow -- follow the q_next chain.
15863234Seric **
15873234Seric **	Returns:
15883234Seric **		none.
15893234Seric **
15903234Seric **	Side Effects:
15913234Seric **		none.
15923234Seric */
15933234Seric 
159467994Seric struct qflags
159567994Seric {
159667994Seric 	char	*qf_name;
159767994Seric 	u_long	qf_bit;
159867994Seric };
159967994Seric 
160067994Seric struct qflags	AddressFlags[] =
160167994Seric {
160267994Seric 	"QDONTSEND",		QDONTSEND,
160367994Seric 	"QBADADDR",		QBADADDR,
160467994Seric 	"QGOODUID",		QGOODUID,
160567994Seric 	"QPRIMARY",		QPRIMARY,
160667994Seric 	"QQUEUEUP",		QQUEUEUP,
160767994Seric 	"QSENT",		QSENT,
160867994Seric 	"QNOTREMOTE",		QNOTREMOTE,
160967994Seric 	"QSELFREF",		QSELFREF,
161067994Seric 	"QVERIFIED",		QVERIFIED,
161167994Seric 	"QREPORT",		QREPORT,
161267994Seric 	"QBOGUSSHELL",		QBOGUSSHELL,
161367994Seric 	"QUNSAFEADDR",		QUNSAFEADDR,
161467994Seric 	"QPINGONSUCCESS",	QPINGONSUCCESS,
161567994Seric 	"QPINGONFAILURE",	QPINGONFAILURE,
161667994Seric 	"QPINGONDELAY",		QPINGONDELAY,
161768595Seric 	"QHASNOTIFY",		QHASNOTIFY,
161867994Seric 	"QRELAYED",		QRELAYED,
161968603Seric 	"QEXPLODED",		QEXPLODED,
162068603Seric 	"QTHISPASS",		QTHISPASS,
162167994Seric 	NULL
162267994Seric };
162367994Seric 
162468433Seric void
16253234Seric printaddr(a, follow)
16263234Seric 	register ADDRESS *a;
16273234Seric 	bool follow;
16283234Seric {
162957731Seric 	register MAILER *m;
163057731Seric 	MAILER pseudomailer;
163167994Seric 	register struct qflags *qfp;
163267994Seric 	bool firstone;
16335001Seric 
163467994Seric 	if (a == NULL)
163567994Seric 	{
163667994Seric 		printf("[NULL]\n");
163767994Seric 		return;
163867994Seric 	}
163967994Seric 
16403234Seric 	while (a != NULL)
16413234Seric 	{
16424443Seric 		printf("%x=", a);
16434085Seric 		(void) fflush(stdout);
164457731Seric 
164557731Seric 		/* find the mailer -- carefully */
164657731Seric 		m = a->q_mailer;
164757731Seric 		if (m == NULL)
164857731Seric 		{
164957731Seric 			m = &pseudomailer;
165057731Seric 			m->m_mno = -1;
165157731Seric 			m->m_name = "NULL";
165257731Seric 		}
165357731Seric 
165468603Seric 		printf("%s:\n\tmailer %d (%s), host `%s'\n",
165557731Seric 		       a->q_paddr, m->m_mno, m->m_name,
165668603Seric 		       a->q_host == NULL ? "<null>" : a->q_host);
165768603Seric 		printf("\tuser `%s', ruser `%s'\n",
165868603Seric 		       a->q_user,
165967172Seric 		       a->q_ruser == NULL ? "<null>" : a->q_ruser);
166067994Seric 		printf("\tnext=%x, alias %x, uid %d, gid %d\n",
166167994Seric 		       a->q_next, a->q_alias, a->q_uid, a->q_gid);
166267994Seric 		printf("\tflags=%lx<", a->q_flags);
166367994Seric 		firstone = TRUE;
166467994Seric 		for (qfp = AddressFlags; qfp->qf_name != NULL; qfp++)
166567994Seric 		{
166667994Seric 			if (!bitset(qfp->qf_bit, a->q_flags))
166767994Seric 				continue;
166867994Seric 			if (!firstone)
166967994Seric 				printf(",");
167067994Seric 			firstone = FALSE;
167167994Seric 			printf("%s", qfp->qf_name);
167267994Seric 		}
167367994Seric 		printf(">\n");
167459269Seric 		printf("\towner=%s, home=\"%s\", fullname=\"%s\"\n",
167559269Seric 		       a->q_owner == NULL ? "(none)" : a->q_owner,
167663756Seric 		       a->q_home == NULL ? "(none)" : a->q_home,
167763756Seric 		       a->q_fullname == NULL ? "(none)" : a->q_fullname);
167868228Seric 		printf("\torcpt=\"%s\", statmta=%s, rstatus=%s\n",
167967987Seric 		       a->q_orcpt == NULL ? "(none)" : a->q_orcpt,
168067987Seric 		       a->q_statmta == NULL ? "(none)" : a->q_statmta,
168167990Seric 		       a->q_rstatus == NULL ? "(none)" : a->q_rstatus);
16824996Seric 
16833234Seric 		if (!follow)
16843234Seric 			return;
16854996Seric 		a = a->q_next;
16863234Seric 	}
16873234Seric }
168867939Seric /*
168967939Seric **  EMPTYADDR -- return TRUE if this address is empty (``<>'')
169067939Seric **
169167939Seric **	Parameters:
169267939Seric **		a -- pointer to the address
169367939Seric **
169467939Seric **	Returns:
169567939Seric **		TRUE -- if this address is "empty" (i.e., no one should
169667939Seric **			ever generate replies to it.
169767939Seric **		FALSE -- if it is a "regular" (read: replyable) address.
169867939Seric */
16994317Seric 
170067939Seric bool
170167939Seric emptyaddr(a)
170267939Seric 	register ADDRESS *a;
170367939Seric {
170467939Seric 	return strcmp(a->q_paddr, "<>") == 0 || strcmp(a->q_user, "<>") == 0;
170567939Seric }
17067682Seric /*
17077682Seric **  REMOTENAME -- return the name relative to the current mailer
17087682Seric **
17097682Seric **	Parameters:
17107682Seric **		name -- the name to translate.
17118069Seric **		m -- the mailer that we want to do rewriting relative
17128069Seric **			to.
171359163Seric **		flags -- fine tune operations.
171459163Seric **		pstat -- pointer to status word.
171558020Seric **		e -- the current envelope.
17167682Seric **
17177682Seric **	Returns:
17187682Seric **		the text string representing this address relative to
17197682Seric **			the receiving mailer.
17207682Seric **
17217682Seric **	Side Effects:
17227682Seric **		none.
17237682Seric **
17247682Seric **	Warnings:
17257682Seric **		The text string returned is tucked away locally;
17267682Seric **			copy it if you intend to save it.
17277682Seric */
17287682Seric 
17297682Seric char *
173059163Seric remotename(name, m, flags, pstat, e)
17317682Seric 	char *name;
173256678Seric 	struct mailer *m;
173359163Seric 	int flags;
173459163Seric 	int *pstat;
173556678Seric 	register ENVELOPE *e;
17367682Seric {
17378069Seric 	register char **pvp;
17388069Seric 	char *fancy;
173956678Seric 	char *oldg = macvalue('g', e);
174058020Seric 	int rwset;
174168528Seric 	static char buf[MAXNAME + 1];
174268528Seric 	char lbuf[MAXNAME + 1];
174316914Seric 	char pvpbuf[PSBUFSIZE];
174456678Seric 	extern char *crackaddr();
17457682Seric 
17467755Seric 	if (tTd(12, 1))
17477755Seric 		printf("remotename(%s)\n", name);
17487755Seric 
174910177Seric 	/* don't do anything if we are tagging it as special */
175059163Seric 	if (bitset(RF_SENDERADDR, flags))
175159163Seric 		rwset = bitset(RF_HEADERADDR, flags) ? m->m_sh_rwset
175259163Seric 						     : m->m_se_rwset;
175358020Seric 	else
175459163Seric 		rwset = bitset(RF_HEADERADDR, flags) ? m->m_rh_rwset
175559163Seric 						     : m->m_re_rwset;
175658020Seric 	if (rwset < 0)
175710177Seric 		return (name);
175810177Seric 
17597682Seric 	/*
17608181Seric 	**  Do a heuristic crack of this name to extract any comment info.
17618181Seric 	**	This will leave the name as a comment and a $g macro.
17627889Seric 	*/
17637889Seric 
176459163Seric 	if (bitset(RF_CANONICAL, flags) || bitnset(M_NOCOMMENT, m->m_flags))
176558050Seric 		fancy = "\201g";
176610310Seric 	else
176710310Seric 		fancy = crackaddr(name);
17687889Seric 
17698181Seric 	/*
17708181Seric 	**  Turn the name into canonical form.
17718181Seric 	**	Normally this will be RFC 822 style, i.e., "user@domain".
17728181Seric 	**	If this only resolves to "user", and the "C" flag is
17738181Seric 	**	specified in the sending mailer, then the sender's
17748181Seric 	**	domain will be appended.
17758181Seric 	*/
17768181Seric 
177765066Seric 	pvp = prescan(name, '\0', pvpbuf, sizeof pvpbuf, NULL);
17787889Seric 	if (pvp == NULL)
17797889Seric 		return (name);
178065071Seric 	if (rewrite(pvp, 3, 0, e) == EX_TEMPFAIL)
178159163Seric 		*pstat = EX_TEMPFAIL;
178259163Seric 	if (bitset(RF_ADDDOMAIN, flags) && e->e_fromdomain != NULL)
17838181Seric 	{
17848181Seric 		/* append from domain to this address */
17858181Seric 		register char **pxp = pvp;
17868181Seric 
17879594Seric 		/* see if there is an "@domain" in the current name */
17888181Seric 		while (*pxp != NULL && strcmp(*pxp, "@") != 0)
17898181Seric 			pxp++;
17908181Seric 		if (*pxp == NULL)
17918181Seric 		{
17929594Seric 			/* no.... append the "@domain" from the sender */
179356678Seric 			register char **qxq = e->e_fromdomain;
17948181Seric 
17959594Seric 			while ((*pxp++ = *qxq++) != NULL)
17969594Seric 				continue;
179765071Seric 			if (rewrite(pvp, 3, 0, e) == EX_TEMPFAIL)
179859163Seric 				*pstat = EX_TEMPFAIL;
17998181Seric 		}
18008181Seric 	}
18018181Seric 
18028181Seric 	/*
18038959Seric 	**  Do more specific rewriting.
180456678Seric 	**	Rewrite using ruleset 1 or 2 depending on whether this is
180556678Seric 	**		a sender address or not.
18068181Seric 	**	Then run it through any receiving-mailer-specific rulesets.
18078181Seric 	*/
18088181Seric 
180959163Seric 	if (bitset(RF_SENDERADDR, flags))
181059541Seric 	{
181165071Seric 		if (rewrite(pvp, 1, 0, e) == EX_TEMPFAIL)
181259163Seric 			*pstat = EX_TEMPFAIL;
181359541Seric 	}
18148069Seric 	else
181559541Seric 	{
181665071Seric 		if (rewrite(pvp, 2, 0, e) == EX_TEMPFAIL)
181759163Seric 			*pstat = EX_TEMPFAIL;
181859541Seric 	}
181958020Seric 	if (rwset > 0)
182059541Seric 	{
182165071Seric 		if (rewrite(pvp, rwset, 0, e) == EX_TEMPFAIL)
182259163Seric 			*pstat = EX_TEMPFAIL;
182359541Seric 	}
18247682Seric 
18258181Seric 	/*
18268959Seric 	**  Do any final sanitation the address may require.
18278959Seric 	**	This will normally be used to turn internal forms
18288959Seric 	**	(e.g., user@host.LOCAL) into external form.  This
18298959Seric 	**	may be used as a default to the above rules.
18308959Seric 	*/
18318959Seric 
183265071Seric 	if (rewrite(pvp, 4, 0, e) == EX_TEMPFAIL)
183359163Seric 		*pstat = EX_TEMPFAIL;
18348959Seric 
18358959Seric 	/*
18368181Seric 	**  Now restore the comment information we had at the beginning.
18378181Seric 	*/
18388181Seric 
183958825Seric 	cataddr(pvp, NULL, lbuf, sizeof lbuf, '\0');
184056678Seric 	define('g', lbuf, e);
184165494Seric 
184265494Seric 	/* need to make sure route-addrs have <angle brackets> */
184365494Seric 	if (bitset(RF_CANONICAL, flags) && lbuf[0] == '@')
184468529Seric 		expand("<\201g>", buf, sizeof buf, e);
184565494Seric 	else
184668529Seric 		expand(fancy, buf, sizeof buf, e);
184765494Seric 
184856678Seric 	define('g', oldg, e);
18497682Seric 
18507682Seric 	if (tTd(12, 1))
18517755Seric 		printf("remotename => `%s'\n", buf);
18527682Seric 	return (buf);
18537682Seric }
185451317Seric /*
185556678Seric **  MAPLOCALUSER -- run local username through ruleset 5 for final redirection
185651317Seric **
185751317Seric **	Parameters:
185856678Seric **		a -- the address to map (but just the user name part).
185956678Seric **		sendq -- the sendq in which to install any replacement
186056678Seric **			addresses.
186167982Seric **		aliaslevel -- the alias nesting depth.
186267982Seric **		e -- the envelope.
186351317Seric **
186451317Seric **	Returns:
186551317Seric **		none.
186651317Seric */
186751317Seric 
186867982Seric maplocaluser(a, sendq, aliaslevel, e)
186956678Seric 	register ADDRESS *a;
187056678Seric 	ADDRESS **sendq;
187167982Seric 	int aliaslevel;
187256678Seric 	ENVELOPE *e;
187351317Seric {
187456678Seric 	register char **pvp;
187556678Seric 	register ADDRESS *a1 = NULL;
187658333Seric 	auto char *delimptr;
187756678Seric 	char pvpbuf[PSBUFSIZE];
187851317Seric 
187956678Seric 	if (tTd(29, 1))
188056678Seric 	{
188156678Seric 		printf("maplocaluser: ");
188256678Seric 		printaddr(a, FALSE);
188356678Seric 	}
188465066Seric 	pvp = prescan(a->q_user, '\0', pvpbuf, sizeof pvpbuf, &delimptr);
188556678Seric 	if (pvp == NULL)
188656678Seric 		return;
188751317Seric 
188865071Seric 	(void) rewrite(pvp, 5, 0, e);
188958050Seric 	if (pvp[0] == NULL || (pvp[0][0] & 0377) != CANONNET)
189056678Seric 		return;
189151317Seric 
189256678Seric 	/* if non-null, mailer destination specified -- has it changed? */
189364284Seric 	a1 = buildaddr(pvp, NULL, 0, e);
189456678Seric 	if (a1 == NULL || sameaddr(a, a1))
189556678Seric 		return;
189651317Seric 
189756678Seric 	/* mark old address as dead; insert new address */
189856678Seric 	a->q_flags |= QDONTSEND;
189957731Seric 	if (tTd(29, 5))
190057731Seric 	{
190157731Seric 		printf("maplocaluser: QDONTSEND ");
190257731Seric 		printaddr(a, FALSE);
190357731Seric 	}
190456678Seric 	a1->q_alias = a;
190564348Seric 	allocaddr(a1, RF_COPYALL, NULL);
190667982Seric 	(void) recipient(a1, sendq, aliaslevel, e);
190751317Seric }
190858802Seric /*
190958802Seric **  DEQUOTE_INIT -- initialize dequote map
191058802Seric **
191158802Seric **	This is a no-op.
191258802Seric **
191358802Seric **	Parameters:
191458802Seric **		map -- the internal map structure.
191558802Seric **		args -- arguments.
191658802Seric **
191758802Seric **	Returns:
191858802Seric **		TRUE.
191958802Seric */
192058802Seric 
192158802Seric bool
192260219Seric dequote_init(map, args)
192358802Seric 	MAP *map;
192458802Seric 	char *args;
192558802Seric {
192658805Seric 	register char *p = args;
192758805Seric 
192858805Seric 	for (;;)
192958805Seric 	{
193058805Seric 		while (isascii(*p) && isspace(*p))
193158805Seric 			p++;
193258805Seric 		if (*p != '-')
193358805Seric 			break;
193458805Seric 		switch (*++p)
193558805Seric 		{
193658805Seric 		  case 'a':
193758805Seric 			map->map_app = ++p;
193858805Seric 			break;
193967824Seric 
194067824Seric 		  case 's':
194167824Seric 			map->map_coldelim = *++p;
194267824Seric 			break;
194358805Seric 		}
194458805Seric 		while (*p != '\0' && !(isascii(*p) && isspace(*p)))
194558805Seric 			p++;
194658805Seric 		if (*p != '\0')
194758805Seric 			*p = '\0';
194858805Seric 	}
194958805Seric 	if (map->map_app != NULL)
195058805Seric 		map->map_app = newstr(map->map_app);
195158805Seric 
195258802Seric 	return TRUE;
195358802Seric }
195458802Seric /*
195558802Seric **  DEQUOTE_MAP -- unquote an address
195658802Seric **
195758802Seric **	Parameters:
195858802Seric **		map -- the internal map structure (ignored).
195960089Seric **		name -- the name to dequote.
196058802Seric **		av -- arguments (ignored).
196159084Seric **		statp -- pointer to status out-parameter.
196258802Seric **
196358802Seric **	Returns:
196458802Seric **		NULL -- if there were no quotes, or if the resulting
196558802Seric **			unquoted buffer would not be acceptable to prescan.
196658802Seric **		else -- The dequoted buffer.
196758802Seric */
196858802Seric 
196958802Seric char *
197060089Seric dequote_map(map, name, av, statp)
197158802Seric 	MAP *map;
197260089Seric 	char *name;
197358802Seric 	char **av;
197459084Seric 	int *statp;
197558802Seric {
197658802Seric 	register char *p;
197758802Seric 	register char *q;
197858802Seric 	register char c;
197967824Seric 	int anglecnt = 0;
198067824Seric 	int cmntcnt = 0;
198167824Seric 	int quotecnt = 0;
198267824Seric 	int spacecnt = 0;
198367824Seric 	bool quotemode = FALSE;
198467824Seric 	bool bslashmode = FALSE;
198567824Seric 	char spacesub = map->map_coldelim;
198658802Seric 
198760089Seric 	for (p = q = name; (c = *p++) != '\0'; )
198858802Seric 	{
198958802Seric 		if (bslashmode)
199058802Seric 		{
199158802Seric 			bslashmode = FALSE;
199258802Seric 			*q++ = c;
199358802Seric 			continue;
199458802Seric 		}
199558802Seric 
199667824Seric 		if (c == ' ' && spacesub != '\0')
199767824Seric 			c = spacesub;
199867764Seric 
199958802Seric 		switch (c)
200058802Seric 		{
200158802Seric 		  case '\\':
200258802Seric 			bslashmode = TRUE;
200358802Seric 			break;
200458802Seric 
200558802Seric 		  case '(':
200658802Seric 			cmntcnt++;
200758802Seric 			break;
200858802Seric 
200958802Seric 		  case ')':
201058802Seric 			if (cmntcnt-- <= 0)
201158802Seric 				return NULL;
201258802Seric 			break;
201359089Seric 
201459089Seric 		  case ' ':
201559089Seric 			spacecnt++;
201659089Seric 			break;
201758802Seric 		}
201858802Seric 
201958802Seric 		if (cmntcnt > 0)
202058802Seric 		{
202158802Seric 			*q++ = c;
202258802Seric 			continue;
202358802Seric 		}
202458802Seric 
202558802Seric 		switch (c)
202658802Seric 		{
202758802Seric 		  case '"':
202858802Seric 			quotemode = !quotemode;
202958802Seric 			quotecnt++;
203058802Seric 			continue;
203158802Seric 
203258802Seric 		  case '<':
203358802Seric 			anglecnt++;
203458802Seric 			break;
203558802Seric 
203658802Seric 		  case '>':
203758802Seric 			if (anglecnt-- <= 0)
203858802Seric 				return NULL;
203958802Seric 			break;
204058802Seric 		}
204158802Seric 		*q++ = c;
204258802Seric 	}
204358802Seric 
204458802Seric 	if (anglecnt != 0 || cmntcnt != 0 || bslashmode ||
204559089Seric 	    quotemode || quotecnt <= 0 || spacecnt != 0)
204658802Seric 		return NULL;
204758802Seric 	*q++ = '\0';
204860089Seric 	return name;
204958802Seric }
2050