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*68098Seric static char sccsid[] = "@(#)parseaddr.c	8.47 (Berkeley) 12/28/94";
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;
15567998Seric 		a->q_status = "466";
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 {
18664726Seric 	char savedelim;
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 	{
20964764Seric 		if (savedelim != '\0' && delimptr != NULL)
21064764Seric 			*delimptr = savedelim;
21164726Seric 		return FALSE;
21264764Seric 	}
21364726Seric 	setstat(EX_USAGE);
21464726Seric 	usrerr("553 Address contained invalid control characters");
21564764Seric   addrfailure:
21664764Seric 	if (savedelim != '\0' && delimptr != NULL)
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;
349297Seric 	char 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;
37465092Seric 		expand("\201o", obuf, &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");
41565015Seric 	returnnull:
41658333Seric 					if (delimptr != NULL)
41758333Seric 						*delimptr = p;
41859747Seric 					CurEnv->e_to = saveto;
4198078Seric 					return (NULL);
4208078Seric 				}
42115284Seric 
42215284Seric 				/* squirrel it away */
4238078Seric 				*q++ = c;
4248078Seric 			}
4258078Seric 
4268078Seric 			/* read a new input character */
4278078Seric 			c = *p++;
42857631Seric 			if (c == '\0')
42956764Seric 			{
43056764Seric 				/* diagnose and patch up bad syntax */
43156764Seric 				if (state == QST)
43256764Seric 				{
43364767Seric 					usrerr("653 Unbalanced '\"'");
43456764Seric 					c = '"';
43556764Seric 				}
43656764Seric 				else if (cmntcnt > 0)
43756764Seric 				{
43864767Seric 					usrerr("653 Unbalanced '('");
43956764Seric 					c = ')';
44056764Seric 				}
44156764Seric 				else if (anglecnt > 0)
44256764Seric 				{
44356764Seric 					c = '>';
44464767Seric 					usrerr("653 Unbalanced '<'");
44556764Seric 				}
44656764Seric 				else
44756764Seric 					break;
44815284Seric 
44956764Seric 				p--;
45056764Seric 			}
45157631Seric 			else if (c == delim && anglecnt <= 0 &&
45257631Seric 					cmntcnt <= 0 && state != QST)
45357631Seric 				break;
45456764Seric 
4558078Seric 			if (tTd(22, 101))
4568078Seric 				printf("c=%c, s=%d; ", c, state);
4578078Seric 
4583149Seric 			/* chew up special characters */
4593149Seric 			*q = '\0';
4603149Seric 			if (bslashmode)
4613149Seric 			{
46259105Seric 				bslashmode = FALSE;
46359105Seric 
46424944Seric 				/* kludge \! for naive users */
46558061Seric 				if (cmntcnt > 0)
46659105Seric 				{
46758061Seric 					c = NOCHAR;
46859105Seric 					continue;
46959105Seric 				}
47059105Seric 				else if (c != '!' || state == QST)
47159105Seric 				{
47256678Seric 					*q++ = '\\';
47359105Seric 					continue;
47459105Seric 				}
4753149Seric 			}
47656678Seric 
47756678Seric 			if (c == '\\')
4783149Seric 			{
4793149Seric 				bslashmode = TRUE;
4803149Seric 			}
48156678Seric 			else if (state == QST)
4828514Seric 			{
4838514Seric 				/* do nothing, just avoid next clauses */
4848514Seric 			}
4858078Seric 			else if (c == '(')
4864100Seric 			{
4878078Seric 				cmntcnt++;
4888078Seric 				c = NOCHAR;
4894100Seric 			}
4908078Seric 			else if (c == ')')
4913149Seric 			{
4928078Seric 				if (cmntcnt <= 0)
4933149Seric 				{
49464767Seric 					usrerr("653 Unbalanced ')'");
49563844Seric 					c = NOCHAR;
4963149Seric 				}
4978078Seric 				else
4988078Seric 					cmntcnt--;
4998078Seric 			}
5008078Seric 			else if (cmntcnt > 0)
5018078Seric 				c = NOCHAR;
5028423Seric 			else if (c == '<')
5038423Seric 				anglecnt++;
5048423Seric 			else if (c == '>')
5058423Seric 			{
5068423Seric 				if (anglecnt <= 0)
5078423Seric 				{
50864767Seric 					usrerr("653 Unbalanced '>'");
50963844Seric 					c = NOCHAR;
5108423Seric 				}
51163844Seric 				else
51263844Seric 					anglecnt--;
5138423Seric 			}
51458050Seric 			else if (delim == ' ' && isascii(c) && isspace(c))
51511423Seric 				c = ' ';
5163149Seric 
5178078Seric 			if (c == NOCHAR)
5188078Seric 				continue;
5193149Seric 
5208078Seric 			/* see if this is end of input */
52111405Seric 			if (c == delim && anglecnt <= 0 && state != QST)
5223149Seric 				break;
5233149Seric 
5248078Seric 			newstate = StateTab[state][toktype(c)];
5258078Seric 			if (tTd(22, 101))
5268078Seric 				printf("ns=%02o\n", newstate);
5278078Seric 			state = newstate & TYPE;
5288078Seric 			if (bitset(M, newstate))
5298078Seric 				c = NOCHAR;
5308078Seric 			if (bitset(B, newstate))
5314228Seric 				break;
532297Seric 		}
5333149Seric 
5343149Seric 		/* new token */
5358078Seric 		if (tok != q)
5361378Seric 		{
5378078Seric 			*q++ = '\0';
5388078Seric 			if (tTd(22, 36))
539297Seric 			{
5408078Seric 				printf("tok=");
5418078Seric 				xputs(tok);
54223109Seric 				(void) putchar('\n');
543297Seric 			}
5448078Seric 			if (avp >= &av[MAXATOM])
545297Seric 			{
54658151Seric 				syserr("553 prescan: too many tokens");
54765015Seric 				goto returnnull;
548297Seric 			}
54965015Seric 			if (q - tok > MAXNAME)
55065015Seric 			{
55165015Seric 				syserr("553 prescan: token too long");
55265015Seric 				goto returnnull;
55365015Seric 			}
5548078Seric 			*avp++ = tok;
555297Seric 		}
5568423Seric 	} while (c != '\0' && (c != delim || anglecnt > 0));
5573149Seric 	*avp = NULL;
55858333Seric 	p--;
55958333Seric 	if (delimptr != NULL)
56058333Seric 		*delimptr = p;
56156764Seric 	if (tTd(22, 12))
56256764Seric 	{
56356764Seric 		printf("prescan==>");
56456764Seric 		printav(av);
56556764Seric 	}
56659747Seric 	CurEnv->e_to = saveto;
56758546Seric 	if (av[0] == NULL)
56864966Seric 	{
56964966Seric 		if (tTd(22, 1))
57064966Seric 			printf("prescan: null leading token\n");
57158546Seric 		return (NULL);
57264966Seric 	}
57358403Seric 	return (av);
5743149Seric }
5753149Seric /*
5763149Seric **  REWRITE -- apply rewrite rules to token vector.
5773149Seric **
5784476Seric **	This routine is an ordered production system.  Each rewrite
5794476Seric **	rule has a LHS (called the pattern) and a RHS (called the
5804476Seric **	rewrite); 'rwr' points the the current rewrite rule.
5814476Seric **
5824476Seric **	For each rewrite rule, 'avp' points the address vector we
5834476Seric **	are trying to match against, and 'pvp' points to the pattern.
5848058Seric **	If pvp points to a special match value (MATCHZANY, MATCHANY,
5859585Seric **	MATCHONE, MATCHCLASS, MATCHNCLASS) then the address in avp
5869585Seric **	matched is saved away in the match vector (pointed to by 'mvp').
5874476Seric **
5884476Seric **	When a match between avp & pvp does not match, we try to
5899585Seric **	back out.  If we back up over MATCHONE, MATCHCLASS, or MATCHNCLASS
5904476Seric **	we must also back out the match in mvp.  If we reach a
5918058Seric **	MATCHANY or MATCHZANY we just extend the match and start
5928058Seric **	over again.
5934476Seric **
5944476Seric **	When we finally match, we rewrite the address vector
5954476Seric **	and try over again.
5964476Seric **
5973149Seric **	Parameters:
5983149Seric **		pvp -- pointer to token vector.
59959027Seric **		ruleset -- the ruleset to use for rewriting.
60065071Seric **		reclevel -- recursion level (to catch loops).
60159027Seric **		e -- the current envelope.
6023149Seric **
6033149Seric **	Returns:
60459084Seric **		A status code.  If EX_TEMPFAIL, higher level code should
60559084Seric **			attempt recovery.
6063149Seric **
6073149Seric **	Side Effects:
6083149Seric **		pvp is modified.
6093149Seric */
6102091Seric 
6113149Seric struct match
6123149Seric {
6134468Seric 	char	**first;	/* first token matched */
6144468Seric 	char	**last;		/* last token matched */
61558825Seric 	char	**pattern;	/* pointer to pattern */
6163149Seric };
6173149Seric 
6184468Seric # define MAXMATCH	9	/* max params per rewrite */
6193149Seric 
62065136Seric # ifndef MAXRULERECURSION
62165136Seric #  define MAXRULERECURSION	50	/* max recursion depth */
62265136Seric # endif
6233149Seric 
62465136Seric 
62559084Seric int
62665071Seric rewrite(pvp, ruleset, reclevel, e)
6273149Seric 	char **pvp;
6284070Seric 	int ruleset;
62965071Seric 	int reclevel;
63059027Seric 	register ENVELOPE *e;
6313149Seric {
6323149Seric 	register char *ap;		/* address pointer */
6333149Seric 	register char *rp;		/* rewrite pointer */
6343149Seric 	register char **avp;		/* address vector pointer */
6353149Seric 	register char **rvp;		/* rewrite vector pointer */
6368058Seric 	register struct match *mlp;	/* cur ptr into mlist */
6378058Seric 	register struct rewrite *rwr;	/* pointer to current rewrite rule */
63858866Seric 	int ruleno;			/* current rule number */
63959084Seric 	int rstat = EX_OK;		/* return status */
64064740Seric 	int loopcount;
64156678Seric 	struct match mlist[MAXMATCH];	/* stores match on LHS */
6423149Seric 	char *npvp[MAXATOM+1];		/* temporary space for rebuild */
6433149Seric 
64467262Seric 	if (OpMode == MD_TEST || tTd(21, 1))
6453149Seric 	{
6468959Seric 		printf("rewrite: ruleset %2d   input:", ruleset);
64756678Seric 		printav(pvp);
6483149Seric 	}
64956678Seric 	if (ruleset < 0 || ruleset >= MAXRWSETS)
65056326Seric 	{
65158151Seric 		syserr("554 rewrite: illegal ruleset number %d", ruleset);
65259084Seric 		return EX_CONFIG;
65356326Seric 	}
65465136Seric 	if (reclevel++ > MAXRULERECURSION)
65565071Seric 	{
65665071Seric 		syserr("rewrite: infinite recursion, ruleset %d", ruleset);
65765071Seric 		return EX_CONFIG;
65865071Seric 	}
65956678Seric 	if (pvp == NULL)
66059084Seric 		return EX_USAGE;
66156326Seric 
6623149Seric 	/*
66356678Seric 	**  Run through the list of rewrite rules, applying
66456678Seric 	**	any that match.
6653149Seric 	*/
6663149Seric 
66758866Seric 	ruleno = 1;
66864740Seric 	loopcount = 0;
6694070Seric 	for (rwr = RewriteRules[ruleset]; rwr != NULL; )
6703149Seric 	{
6717675Seric 		if (tTd(21, 12))
672297Seric 		{
6738069Seric 			printf("-----trying rule:");
67456678Seric 			printav(rwr->r_lhs);
6753149Seric 		}
6763149Seric 
6773149Seric 		/* try to match on this rule */
6784468Seric 		mlp = mlist;
6798058Seric 		rvp = rwr->r_lhs;
6808058Seric 		avp = pvp;
68158866Seric 		if (++loopcount > 100)
6823149Seric 		{
68358866Seric 			syserr("554 Infinite loop in ruleset %d, rule %d",
68458866Seric 				ruleset, ruleno);
68558866Seric 			if (tTd(21, 1))
68652637Seric 			{
68756678Seric 				printf("workspace: ");
68856678Seric 				printav(pvp);
68952637Seric 			}
69058866Seric 			break;
69158866Seric 		}
69258866Seric 
69358866Seric 		while ((ap = *avp) != NULL || *rvp != NULL)
69458866Seric 		{
6953149Seric 			rp = *rvp;
6968058Seric 			if (tTd(21, 35))
6978058Seric 			{
69858825Seric 				printf("ADVANCE rp=");
69957531Seric 				xputs(rp);
70057532Seric 				printf(", ap=");
7018058Seric 				xputs(ap);
7028069Seric 				printf("\n");
7038058Seric 			}
70456678Seric 			if (rp == NULL)
70556326Seric 			{
7063149Seric 				/* end-of-pattern before end-of-address */
7078058Seric 				goto backup;
70856678Seric 			}
70958173Seric 			if (ap == NULL && (*rp & 0377) != MATCHZANY &&
71058827Seric 			    (*rp & 0377) != MATCHZERO)
71156326Seric 			{
71258825Seric 				/* end-of-input with patterns left */
71358825Seric 				goto backup;
714297Seric 			}
71556326Seric 
71658050Seric 			switch (*rp & 0377)
7178058Seric 			{
71856678Seric 				register STAB *s;
71958814Seric 				char buf[MAXLINE];
72056326Seric 
72156678Seric 			  case MATCHCLASS:
72258825Seric 				/* match any phrase in a class */
72358825Seric 				mlp->pattern = rvp;
72458814Seric 				mlp->first = avp;
72558814Seric 	extendclass:
72658825Seric 				ap = *avp;
72758825Seric 				if (ap == NULL)
72858814Seric 					goto backup;
72958814Seric 				mlp->last = avp++;
73058814Seric 				cataddr(mlp->first, mlp->last, buf, sizeof buf, '\0');
73158814Seric 				s = stab(buf, ST_CLASS, ST_FIND);
73256678Seric 				if (s == NULL || !bitnset(rp[1], s->s_class))
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 */
75158825Seric 				s = stab(ap, ST_CLASS, ST_FIND);
75258825Seric 				if (s != NULL && bitnset(rp[1], s->s_class))
75358825Seric 					goto backup;
75458825Seric 
75558825Seric 				/* fall through */
75658825Seric 
75756678Seric 			  case MATCHONE:
75856678Seric 			  case MATCHANY:
75956678Seric 				/* match exactly one token */
76058825Seric 				mlp->pattern = rvp;
76156678Seric 				mlp->first = avp;
76256678Seric 				mlp->last = avp++;
7638058Seric 				mlp++;
76456678Seric 				break;
7658058Seric 
76656678Seric 			  case MATCHZANY:
76756678Seric 				/* match zero or more tokens */
76858825Seric 				mlp->pattern = rvp;
76956678Seric 				mlp->first = avp;
77056678Seric 				mlp->last = avp - 1;
77156678Seric 				mlp++;
77256678Seric 				break;
77356326Seric 
77458827Seric 			  case MATCHZERO:
77558173Seric 				/* match zero tokens */
77658173Seric 				break;
77758173Seric 
77859027Seric 			  case MACRODEXPAND:
77959027Seric 				/*
78059027Seric 				**  Match against run-time macro.
78159027Seric 				**  This algorithm is broken for the
78259027Seric 				**  general case (no recursive macros,
78359027Seric 				**  improper tokenization) but should
78459027Seric 				**  work for the usual cases.
78559027Seric 				*/
78659027Seric 
78759027Seric 				ap = macvalue(rp[1], e);
78859027Seric 				mlp->first = avp;
78959027Seric 				if (tTd(21, 2))
79059027Seric 					printf("rewrite: LHS $&%c => \"%s\"\n",
79159027Seric 						rp[1],
79259027Seric 						ap == NULL ? "(NULL)" : ap);
79359027Seric 
79459027Seric 				if (ap == NULL)
79559027Seric 					break;
79660502Seric 				while (*ap != '\0')
79759027Seric 				{
79859027Seric 					if (*avp == NULL ||
79959027Seric 					    strncasecmp(ap, *avp, strlen(*avp)) != 0)
80059027Seric 					{
80159027Seric 						/* no match */
80259027Seric 						avp = mlp->first;
80359027Seric 						goto backup;
80459027Seric 					}
80559027Seric 					ap += strlen(*avp++);
80659027Seric 				}
80759027Seric 
80859027Seric 				/* match */
80959027Seric 				break;
81059027Seric 
81156678Seric 			  default:
81256678Seric 				/* must have exact match */
81356678Seric 				if (strcasecmp(rp, ap))
8148058Seric 					goto backup;
8154468Seric 				avp++;
81656678Seric 				break;
8173149Seric 			}
8183149Seric 
81956678Seric 			/* successful match on this token */
8203149Seric 			rvp++;
8213149Seric 			continue;
8223149Seric 
82358825Seric 	  backup:
82456678Seric 			/* match failed -- back up */
82558825Seric 			while (--mlp >= mlist)
8263149Seric 			{
82758825Seric 				rvp = mlp->pattern;
82856678Seric 				rp = *rvp;
82958825Seric 				avp = mlp->last + 1;
83058825Seric 				ap = *avp;
83158825Seric 
83258825Seric 				if (tTd(21, 36))
83358825Seric 				{
83458825Seric 					printf("BACKUP  rp=");
83558825Seric 					xputs(rp);
83658825Seric 					printf(", ap=");
83758825Seric 					xputs(ap);
83858825Seric 					printf("\n");
83958825Seric 				}
84058825Seric 
84158825Seric 				if (ap == NULL)
84258825Seric 				{
84358825Seric 					/* run off the end -- back up again */
84458825Seric 					continue;
84558825Seric 				}
84658050Seric 				if ((*rp & 0377) == MATCHANY ||
84758050Seric 				    (*rp & 0377) == MATCHZANY)
8484468Seric 				{
84956678Seric 					/* extend binding and continue */
85058825Seric 					mlp->last = avp++;
85156678Seric 					rvp++;
85258825Seric 					mlp++;
85356678Seric 					break;
8544468Seric 				}
85558825Seric 				if ((*rp & 0377) == MATCHCLASS)
85656678Seric 				{
85758814Seric 					/* extend binding and try again */
85863397Seric 					mlp->last = avp;
85958814Seric 					goto extendclass;
86058814Seric 				}
8613149Seric 			}
8623149Seric 
86358825Seric 			if (mlp < mlist)
86456678Seric 			{
86556678Seric 				/* total failure to match */
86656326Seric 				break;
8673149Seric 			}
868297Seric 		}
8693149Seric 
8703149Seric 		/*
87156678Seric 		**  See if we successfully matched
8723149Seric 		*/
8733149Seric 
87458827Seric 		if (mlp < mlist || *rvp != NULL)
8753149Seric 		{
8769374Seric 			if (tTd(21, 10))
8779374Seric 				printf("----- rule fails\n");
8789374Seric 			rwr = rwr->r_next;
87958866Seric 			ruleno++;
88064740Seric 			loopcount = 0;
8819374Seric 			continue;
8829374Seric 		}
8833149Seric 
8849374Seric 		rvp = rwr->r_rhs;
8859374Seric 		if (tTd(21, 12))
8869374Seric 		{
8879374Seric 			printf("-----rule matches:");
88856678Seric 			printav(rvp);
8899374Seric 		}
8909374Seric 
8919374Seric 		rp = *rvp;
89258050Seric 		if ((*rp & 0377) == CANONUSER)
8939374Seric 		{
8949374Seric 			rvp++;
8959374Seric 			rwr = rwr->r_next;
89658866Seric 			ruleno++;
89764740Seric 			loopcount = 0;
8989374Seric 		}
89958050Seric 		else if ((*rp & 0377) == CANONHOST)
9009374Seric 		{
9019374Seric 			rvp++;
9029374Seric 			rwr = NULL;
9039374Seric 		}
90458050Seric 		else if ((*rp & 0377) == CANONNET)
9059374Seric 			rwr = NULL;
9069374Seric 
9079374Seric 		/* substitute */
9089374Seric 		for (avp = npvp; *rvp != NULL; rvp++)
9099374Seric 		{
9109374Seric 			register struct match *m;
9119374Seric 			register char **pp;
9129374Seric 
9138058Seric 			rp = *rvp;
91458050Seric 			if ((*rp & 0377) == MATCHREPL)
9158058Seric 			{
91616914Seric 				/* substitute from LHS */
91716914Seric 				m = &mlist[rp[1] - '1'];
91856678Seric 				if (m < mlist || m >= mlp)
9199374Seric 				{
92058151Seric 					syserr("554 rewrite: ruleset %d: replacement $%c out of bounds",
92156326Seric 						ruleset, rp[1]);
92259084Seric 					return EX_CONFIG;
9239374Seric 				}
92416914Seric 				if (tTd(21, 15))
92516914Seric 				{
92616914Seric 					printf("$%c:", rp[1]);
92716914Seric 					pp = m->first;
92856678Seric 					while (pp <= m->last)
92916914Seric 					{
93016914Seric 						printf(" %x=\"", *pp);
93116914Seric 						(void) fflush(stdout);
93216914Seric 						printf("%s\"", *pp++);
93316914Seric 					}
93416914Seric 					printf("\n");
93516914Seric 				}
9369374Seric 				pp = m->first;
93756678Seric 				while (pp <= m->last)
9383149Seric 				{
93916914Seric 					if (avp >= &npvp[MAXATOM])
94056678Seric 					{
94158151Seric 						syserr("554 rewrite: expansion too long");
94259084Seric 						return EX_DATAERR;
94356678Seric 					}
94416914Seric 					*avp++ = *pp++;
9453149Seric 				}
9463149Seric 			}
94716914Seric 			else
9488226Seric 			{
94916914Seric 				/* vanilla replacement */
9509374Seric 				if (avp >= &npvp[MAXATOM])
95116889Seric 				{
95256678Seric 	toolong:
95358151Seric 					syserr("554 rewrite: expansion too long");
95459084Seric 					return EX_DATAERR;
95516889Seric 				}
95659027Seric 				if ((*rp & 0377) != MACRODEXPAND)
95759027Seric 					*avp++ = rp;
95859027Seric 				else
95959027Seric 				{
96059027Seric 					*avp = macvalue(rp[1], e);
96159027Seric 					if (tTd(21, 2))
96259027Seric 						printf("rewrite: RHS $&%c => \"%s\"\n",
96359027Seric 							rp[1],
96459027Seric 							*avp == NULL ? "(NULL)" : *avp);
96559027Seric 					if (*avp != NULL)
96659027Seric 						avp++;
96759027Seric 				}
9688226Seric 			}
9699374Seric 		}
9709374Seric 		*avp++ = NULL;
97116914Seric 
97216914Seric 		/*
97356678Seric 		**  Check for any hostname/keyword lookups.
97416914Seric 		*/
97516914Seric 
97616914Seric 		for (rvp = npvp; *rvp != NULL; rvp++)
97716914Seric 		{
97856678Seric 			char **hbrvp;
97916914Seric 			char **xpvp;
98016914Seric 			int trsize;
98156678Seric 			char *replac;
98256678Seric 			int endtoken;
98356678Seric 			STAB *map;
98456678Seric 			char *mapname;
98556678Seric 			char **key_rvp;
98656678Seric 			char **arg_rvp;
98756678Seric 			char **default_rvp;
98856678Seric 			char buf[MAXNAME + 1];
98916914Seric 			char *pvpb1[MAXATOM + 1];
99056823Seric 			char *argvect[10];
99117174Seric 			char pvpbuf[PSBUFSIZE];
99264404Seric 			char *nullpvp[1];
99316914Seric 
99458050Seric 			if ((**rvp & 0377) != HOSTBEGIN &&
99558050Seric 			    (**rvp & 0377) != LOOKUPBEGIN)
99616914Seric 				continue;
99716914Seric 
99816914Seric 			/*
99956678Seric 			**  Got a hostname/keyword lookup.
100016914Seric 			**
100116914Seric 			**	This could be optimized fairly easily.
100216914Seric 			*/
100316914Seric 
100416914Seric 			hbrvp = rvp;
100558050Seric 			if ((**rvp & 0377) == HOSTBEGIN)
100656327Seric 			{
100756678Seric 				endtoken = HOSTEND;
100856678Seric 				mapname = "host";
100956327Seric 			}
101056326Seric 			else
101156327Seric 			{
101256678Seric 				endtoken = LOOKUPEND;
101356678Seric 				mapname = *++rvp;
101456327Seric 			}
101556678Seric 			map = stab(mapname, ST_MAP, ST_FIND);
101656678Seric 			if (map == NULL)
101758151Seric 				syserr("554 rewrite: map %s not found", mapname);
101856678Seric 
101956678Seric 			/* extract the match part */
102056678Seric 			key_rvp = ++rvp;
102156823Seric 			default_rvp = NULL;
102256823Seric 			arg_rvp = argvect;
102356823Seric 			xpvp = NULL;
102456823Seric 			replac = pvpbuf;
102558050Seric 			while (*rvp != NULL && (**rvp & 0377) != endtoken)
102653654Seric 			{
102758050Seric 				int nodetype = **rvp & 0377;
102856823Seric 
102956823Seric 				if (nodetype != CANONHOST && nodetype != CANONUSER)
103056678Seric 				{
103156823Seric 					rvp++;
103256823Seric 					continue;
103356823Seric 				}
103456823Seric 
103556823Seric 				*rvp++ = NULL;
103656823Seric 
103756823Seric 				if (xpvp != NULL)
103856823Seric 				{
103958814Seric 					cataddr(xpvp, NULL, replac,
104058082Seric 						&pvpbuf[sizeof pvpbuf] - replac,
104158082Seric 						'\0');
104256823Seric 					*++arg_rvp = replac;
104356823Seric 					replac += strlen(replac) + 1;
104456823Seric 					xpvp = NULL;
104556823Seric 				}
104656823Seric 				switch (nodetype)
104756823Seric 				{
104856678Seric 				  case CANONHOST:
104956823Seric 					xpvp = rvp;
105056678Seric 					break;
105156678Seric 
105256678Seric 				  case CANONUSER:
105356678Seric 					default_rvp = rvp;
105456678Seric 					break;
105556678Seric 				}
105653654Seric 			}
105716914Seric 			if (*rvp != NULL)
105816914Seric 				*rvp++ = NULL;
105956823Seric 			if (xpvp != NULL)
106056823Seric 			{
106158814Seric 				cataddr(xpvp, NULL, replac,
106258082Seric 					&pvpbuf[sizeof pvpbuf] - replac,
106358082Seric 					'\0');
106456823Seric 				*++arg_rvp = replac;
106556823Seric 			}
106656823Seric 			*++arg_rvp = NULL;
106716914Seric 
106816914Seric 			/* save the remainder of the input string */
106916914Seric 			trsize = (int) (avp - rvp + 1) * sizeof *rvp;
107016914Seric 			bcopy((char *) rvp, (char *) pvpb1, trsize);
107116914Seric 
107256678Seric 			/* look it up */
107358814Seric 			cataddr(key_rvp, NULL, buf, sizeof buf, '\0');
107456823Seric 			argvect[0] = buf;
107560538Seric 			if (map != NULL && bitset(MF_OPEN, map->s_map.map_mflags))
107656836Seric 			{
107759084Seric 				auto int stat = EX_OK;
107856836Seric 
107960215Seric 				/* XXX should try to auto-open the map here */
108060215Seric 
108158796Seric 				if (tTd(60, 1))
108258796Seric 					printf("map_lookup(%s, %s) => ",
108358796Seric 						mapname, buf);
108456836Seric 				replac = (*map->s_map.map_class->map_lookup)(&map->s_map,
108560089Seric 						buf, argvect, &stat);
108658796Seric 				if (tTd(60, 1))
108759084Seric 					printf("%s (%d)\n",
108859084Seric 						replac ? replac : "NOT FOUND",
108959084Seric 						stat);
109059084Seric 
109159084Seric 				/* should recover if stat == EX_TEMPFAIL */
109259084Seric 				if (stat == EX_TEMPFAIL)
109359084Seric 					rstat = stat;
109456836Seric 			}
109553654Seric 			else
109656678Seric 				replac = NULL;
109756678Seric 
109856678Seric 			/* if no replacement, use default */
109956823Seric 			if (replac == NULL && default_rvp != NULL)
110056823Seric 			{
110160089Seric 				/* create the default */
110260089Seric 				cataddr(default_rvp, NULL, buf, sizeof buf, '\0');
110356823Seric 				replac = buf;
110456823Seric 			}
110556823Seric 
110656678Seric 			if (replac == NULL)
110751317Seric 			{
110856823Seric 				xpvp = key_rvp;
110953654Seric 			}
111064404Seric 			else if (*replac == '\0')
111164404Seric 			{
111264404Seric 				/* null replacement */
111364404Seric 				nullpvp[0] = NULL;
111464404Seric 				xpvp = nullpvp;
111564404Seric 			}
111656678Seric 			else
111753654Seric 			{
111856678Seric 				/* scan the new replacement */
111965066Seric 				xpvp = prescan(replac, '\0', pvpbuf,
112065066Seric 					       sizeof pvpbuf, NULL);
112153654Seric 				if (xpvp == NULL)
112251317Seric 				{
112358403Seric 					/* prescan already printed error */
112459084Seric 					return EX_DATAERR;
112556678Seric 				}
112651317Seric 			}
112751317Seric 
112816914Seric 			/* append it to the token list */
112956678Seric 			for (avp = hbrvp; *xpvp != NULL; xpvp++)
113056678Seric 			{
113117174Seric 				*avp++ = newstr(*xpvp);
113216920Seric 				if (avp >= &npvp[MAXATOM])
113316914Seric 					goto toolong;
113417174Seric 			}
113516914Seric 
113616914Seric 			/* restore the old trailing information */
113756678Seric 			for (xpvp = pvpb1; (*avp++ = *xpvp++) != NULL; )
113816920Seric 				if (avp >= &npvp[MAXATOM])
113916914Seric 					goto toolong;
114017174Seric 
114156678Seric 			break;
114216914Seric 		}
114316914Seric 
114416914Seric 		/*
114516914Seric 		**  Check for subroutine calls.
114616914Seric 		*/
114716914Seric 
114858050Seric 		if (*npvp != NULL && (**npvp & 0377) == CALLSUBR)
114956678Seric 		{
115059084Seric 			int stat;
115159084Seric 
115265379Seric 			if (npvp[1] == NULL)
115365379Seric 			{
115465379Seric 				syserr("parseaddr: NULL subroutine call in ruleset %d, rule %d",
115565379Seric 					ruleset, ruleno);
115665379Seric 				*pvp = NULL;
115765379Seric 			}
115865379Seric 			else
115965379Seric 			{
116065379Seric 				bcopy((char *) &npvp[2], (char *) pvp,
116165379Seric 					(int) (avp - npvp - 2) * sizeof *avp);
116265379Seric 				if (tTd(21, 3))
116365379Seric 					printf("-----callsubr %s\n", npvp[1]);
116465379Seric 				stat = rewrite(pvp, atoi(npvp[1]), reclevel, e);
116565379Seric 				if (rstat == EX_OK || stat == EX_TEMPFAIL)
116665379Seric 					rstat = stat;
116765379Seric 				if (*pvp != NULL && (**pvp & 0377) == CANONNET)
116863581Seric 				rwr = NULL;
116965379Seric 			}
117056678Seric 		}
117156678Seric 		else
117256678Seric 		{
117317348Seric 			bcopy((char *) npvp, (char *) pvp,
117416900Seric 				(int) (avp - npvp) * sizeof *avp);
117556678Seric 		}
11769374Seric 		if (tTd(21, 4))
11779374Seric 		{
11789374Seric 			printf("rewritten as:");
117956678Seric 			printav(pvp);
11809374Seric 		}
1181297Seric 	}
11828069Seric 
118367262Seric 	if (OpMode == MD_TEST || tTd(21, 1))
11848069Seric 	{
11858959Seric 		printf("rewrite: ruleset %2d returns:", ruleset);
118656678Seric 		printav(pvp);
11878069Seric 	}
118859084Seric 
118959084Seric 	return rstat;
11903149Seric }
11913149Seric /*
11923149Seric **  BUILDADDR -- build address from token vector.
11933149Seric **
11943149Seric **	Parameters:
11953149Seric **		tv -- token vector.
11963149Seric **		a -- pointer to address descriptor to fill.
11973149Seric **			If NULL, one will be allocated.
119864284Seric **		flags -- info regarding whether this is a sender or
119964284Seric **			a recipient.
120058966Seric **		e -- the current envelope.
12013149Seric **
12023149Seric **	Returns:
12034279Seric **		NULL if there was an error.
12044279Seric **		'a' otherwise.
12053149Seric **
12063149Seric **	Side Effects:
12073149Seric **		fills in 'a'
12083149Seric */
12093149Seric 
121057249Seric struct errcodes
121157249Seric {
121257249Seric 	char	*ec_name;		/* name of error code */
121357249Seric 	int	ec_code;		/* numeric code */
121457249Seric } ErrorCodes[] =
121557249Seric {
121657249Seric 	"usage",	EX_USAGE,
121757249Seric 	"nouser",	EX_NOUSER,
121857249Seric 	"nohost",	EX_NOHOST,
121957249Seric 	"unavailable",	EX_UNAVAILABLE,
122057249Seric 	"software",	EX_SOFTWARE,
122157249Seric 	"tempfail",	EX_TEMPFAIL,
122257249Seric 	"protocol",	EX_PROTOCOL,
122357249Seric #ifdef EX_CONFIG
122457249Seric 	"config",	EX_CONFIG,
122557249Seric #endif
122657249Seric 	NULL,		EX_UNAVAILABLE,
122757249Seric };
122857249Seric 
122956678Seric ADDRESS *
123064284Seric buildaddr(tv, a, flags, e)
12313149Seric 	register char **tv;
12323149Seric 	register ADDRESS *a;
123364284Seric 	int flags;
123458966Seric 	register ENVELOPE *e;
12353149Seric {
12363149Seric 	struct mailer **mp;
12373149Seric 	register struct mailer *m;
123858008Seric 	char *bp;
123958008Seric 	int spaceleft;
124064306Seric 	static MAILER errormailer;
124164306Seric 	static char *errorargv[] = { "ERROR", NULL };
124257402Seric 	static char buf[MAXNAME];
12433149Seric 
124464791Seric 	if (tTd(24, 5))
124564791Seric 	{
124667693Seric 		printf("buildaddr, flags=%x, tv=", flags);
124764791Seric 		printav(tv);
124864791Seric 	}
124964791Seric 
12503149Seric 	if (a == NULL)
12513149Seric 		a = (ADDRESS *) xalloc(sizeof *a);
125216889Seric 	bzero((char *) a, sizeof *a);
12533149Seric 
125467880Seric 	/* set up default error return flags */
125567963Seric 	a->q_flags |= QPINGONFAILURE|QPINGONDELAY;
125667880Seric 
12573149Seric 	/* figure out what net/mailer to use */
125864306Seric 	if (*tv == NULL || (**tv & 0377) != CANONNET)
12594279Seric 	{
126058151Seric 		syserr("554 buildaddr: no net");
126164306Seric badaddr:
126264306Seric 		a->q_flags |= QBADADDR;
126364306Seric 		a->q_mailer = &errormailer;
126464306Seric 		if (errormailer.m_name == NULL)
126564306Seric 		{
126664306Seric 			/* initialize the bogus mailer */
126764306Seric 			errormailer.m_name = "*error*";
126864306Seric 			errormailer.m_mailer = "ERROR";
126964306Seric 			errormailer.m_argv = errorargv;
127064306Seric 		}
127164306Seric 		return a;
12724279Seric 	}
12733149Seric 	tv++;
127458680Seric 	if (strcasecmp(*tv, "error") == 0)
12754279Seric 	{
127658050Seric 		if ((**++tv & 0377) == CANONHOST)
127710183Seric 		{
127857249Seric 			register struct errcodes *ep;
127957249Seric 
128058050Seric 			if (isascii(**++tv) && isdigit(**tv))
128157249Seric 			{
128257249Seric 				setstat(atoi(*tv));
128357249Seric 			}
128457249Seric 			else
128557249Seric 			{
128657249Seric 				for (ep = ErrorCodes; ep->ec_name != NULL; ep++)
128757249Seric 					if (strcasecmp(ep->ec_name, *tv) == 0)
128857249Seric 						break;
128957249Seric 				setstat(ep->ec_code);
129057249Seric 			}
129110183Seric 			tv++;
129210183Seric 		}
129364928Seric 		else
129464928Seric 			setstat(EX_UNAVAILABLE);
129558050Seric 		if ((**tv & 0377) != CANONUSER)
129658151Seric 			syserr("554 buildaddr: error: no user");
129758814Seric 		cataddr(++tv, NULL, buf, sizeof buf, ' ');
129858082Seric 		stripquotes(buf);
129964659Seric 		if (isascii(buf[0]) && isdigit(buf[0]) &&
130064659Seric 		    isascii(buf[1]) && isdigit(buf[1]) &&
130164659Seric 		    isascii(buf[2]) && isdigit(buf[2]) &&
130264659Seric 		    buf[3] == ' ')
130364659Seric 		{
130464659Seric 			char fmt[10];
130564659Seric 
130664659Seric 			strncpy(fmt, buf, 3);
130764659Seric 			strcpy(&fmt[3], " %s");
130864659Seric 			usrerr(fmt, buf + 4);
130967786Seric 
131067786Seric 			/*
131167786Seric 			**  If this is a 4xx code and we aren't running
131267786Seric 			**  SMTP on our input, bounce this message;
131367786Seric 			**  otherwise it disappears without a trace.
131467786Seric 			*/
131567786Seric 
131667786Seric 			if (fmt[0] == '4' && OpMode != MD_SMTP &&
131767786Seric 			    OpMode != MD_DAEMON)
131867786Seric 			{
131967786Seric 				e->e_flags |= EF_FATALERRS;
132067786Seric 			}
132164659Seric 		}
132264659Seric 		else
132364659Seric 		{
132466039Seric 			usrerr("553 %s", buf);
132564659Seric 		}
132664306Seric 		goto badaddr;
13274279Seric 	}
132857402Seric 
13294598Seric 	for (mp = Mailer; (m = *mp++) != NULL; )
13303149Seric 	{
133158680Seric 		if (strcasecmp(m->m_name, *tv) == 0)
13323149Seric 			break;
13333149Seric 	}
13343149Seric 	if (m == NULL)
13354279Seric 	{
133658151Seric 		syserr("554 buildaddr: unknown mailer %s", *tv);
133764306Seric 		goto badaddr;
13384279Seric 	}
13394598Seric 	a->q_mailer = m;
13403149Seric 
13413149Seric 	/* figure out what host (if any) */
134256678Seric 	tv++;
134358509Seric 	if ((**tv & 0377) == CANONHOST)
13443149Seric 	{
134558008Seric 		bp = buf;
134658008Seric 		spaceleft = sizeof buf - 1;
134758050Seric 		while (*++tv != NULL && (**tv & 0377) != CANONUSER)
134858008Seric 		{
134958008Seric 			int i = strlen(*tv);
135058008Seric 
135158008Seric 			if (i > spaceleft)
135258008Seric 			{
135358008Seric 				/* out of space for this address */
135458008Seric 				if (spaceleft >= 0)
135558151Seric 					syserr("554 buildaddr: host too long (%.40s...)",
135658008Seric 						buf);
135758008Seric 				i = spaceleft;
135858008Seric 				spaceleft = 0;
135958008Seric 			}
136058008Seric 			if (i <= 0)
136158008Seric 				continue;
136258008Seric 			bcopy(*tv, bp, i);
136358008Seric 			bp += i;
136458008Seric 			spaceleft -= i;
136558008Seric 		}
136658010Seric 		*bp = '\0';
13675704Seric 		a->q_host = newstr(buf);
13683149Seric 	}
136957249Seric 	else
137058509Seric 	{
137158509Seric 		if (!bitnset(M_LOCALMAILER, m->m_flags))
137258509Seric 		{
137358509Seric 			syserr("554 buildaddr: no host");
137464306Seric 			goto badaddr;
137558509Seric 		}
137657249Seric 		a->q_host = NULL;
137758509Seric 	}
13783149Seric 
13793149Seric 	/* figure out the user */
138058050Seric 	if (*tv == NULL || (**tv & 0377) != CANONUSER)
13814279Seric 	{
138258151Seric 		syserr("554 buildaddr: no user");
138364306Seric 		goto badaddr;
13844279Seric 	}
138557402Seric 	tv++;
138651317Seric 
1387*68098Seric 	if (bitnset(M_CHECKUDB, m->m_flags) && *tv != NULL &&
1388*68098Seric 	    strcmp(*tv, "@") == 0)
1389*68098Seric 	{
1390*68098Seric 		tv++;
1391*68098Seric 		a->q_flags |= QNOTREMOTE;
1392*68098Seric 	}
1393*68098Seric 
139457402Seric 	/* do special mapping for local mailer */
139567472Seric 	if (*tv != NULL)
139657402Seric 	{
139757454Seric 		register char *p = *tv;
139857454Seric 
139957454Seric 		if (*p == '"')
140057454Seric 			p++;
140167472Seric 		if (*p == '|' && bitnset(M_CHECKPROG, m->m_flags))
140257402Seric 			a->q_mailer = m = ProgMailer;
140367472Seric 		else if (*p == '/' && bitnset(M_CHECKFILE, m->m_flags))
140457402Seric 			a->q_mailer = m = FileMailer;
140567472Seric 		else if (*p == ':' && bitnset(M_CHECKINCLUDE, m->m_flags))
140657402Seric 		{
140757402Seric 			/* may be :include: */
140858814Seric 			cataddr(tv, NULL, buf, sizeof buf, '\0');
140958008Seric 			stripquotes(buf);
141058008Seric 			if (strncasecmp(buf, ":include:", 9) == 0)
141158008Seric 			{
141258008Seric 				/* if :include:, don't need further rewriting */
141357402Seric 				a->q_mailer = m = InclMailer;
141458008Seric 				a->q_user = &buf[9];
141558008Seric 				return (a);
141658008Seric 			}
141757402Seric 		}
141857402Seric 	}
141957402Seric 
142064284Seric 	/* rewrite according recipient mailer rewriting rules */
142164284Seric 	define('h', a->q_host, e);
142264284Seric 	if (!bitset(RF_SENDERADDR|RF_HEADERADDR, flags))
142364284Seric 	{
142464284Seric 		/* sender addresses done later */
142565071Seric 		(void) rewrite(tv, 2, 0, e);
142664284Seric 		if (m->m_re_rwset > 0)
142765071Seric 		       (void) rewrite(tv, m->m_re_rwset, 0, e);
142864284Seric 	}
142965071Seric 	(void) rewrite(tv, 4, 0, e);
143019040Seric 
143119040Seric 	/* save the result for the command line/RCPT argument */
143258814Seric 	cataddr(tv, NULL, buf, sizeof buf, '\0');
14333149Seric 	a->q_user = buf;
14343149Seric 
143558670Seric 	/*
143658670Seric 	**  Do mapping to lower case as requested by mailer
143758670Seric 	*/
143858670Seric 
143958670Seric 	if (a->q_host != NULL && !bitnset(M_HST_UPPER, m->m_flags))
144058670Seric 		makelower(a->q_host);
144158670Seric 	if (!bitnset(M_USR_UPPER, m->m_flags))
144258670Seric 		makelower(a->q_user);
144358670Seric 
14443149Seric 	return (a);
14453149Seric }
14463188Seric /*
14474228Seric **  CATADDR -- concatenate pieces of addresses (putting in <LWSP> subs)
14484228Seric **
14494228Seric **	Parameters:
14504228Seric **		pvp -- parameter vector to rebuild.
145158814Seric **		evp -- last parameter to include.  Can be NULL to
145258814Seric **			use entire pvp.
14534228Seric **		buf -- buffer to build the string into.
14544228Seric **		sz -- size of buf.
145558082Seric **		spacesub -- the space separator character; if null,
145658082Seric **			use SpaceSub.
14574228Seric **
14584228Seric **	Returns:
14594228Seric **		none.
14604228Seric **
14614228Seric **	Side Effects:
14624228Seric **		Destroys buf.
14634228Seric */
14644228Seric 
146558814Seric cataddr(pvp, evp, buf, sz, spacesub)
14664228Seric 	char **pvp;
146758814Seric 	char **evp;
14684228Seric 	char *buf;
14694228Seric 	register int sz;
147058082Seric 	char spacesub;
14714228Seric {
14724228Seric 	bool oatomtok = FALSE;
147356678Seric 	bool natomtok = FALSE;
14744228Seric 	register int i;
14754228Seric 	register char *p;
14764228Seric 
147758082Seric 	if (spacesub == '\0')
147858082Seric 		spacesub = SpaceSub;
147958082Seric 
14808423Seric 	if (pvp == NULL)
14818423Seric 	{
148223109Seric 		(void) strcpy(buf, "");
14838423Seric 		return;
14848423Seric 	}
14854228Seric 	p = buf;
148611156Seric 	sz -= 2;
14874228Seric 	while (*pvp != NULL && (i = strlen(*pvp)) < sz)
14884228Seric 	{
14898078Seric 		natomtok = (toktype(**pvp) == ATM);
14904228Seric 		if (oatomtok && natomtok)
149158082Seric 			*p++ = spacesub;
14924228Seric 		(void) strcpy(p, *pvp);
14934228Seric 		oatomtok = natomtok;
14944228Seric 		p += i;
149511156Seric 		sz -= i + 1;
149658814Seric 		if (pvp++ == evp)
149758814Seric 			break;
14984228Seric 	}
14994228Seric 	*p = '\0';
15004228Seric }
15014228Seric /*
15023188Seric **  SAMEADDR -- Determine if two addresses are the same
15033188Seric **
15043188Seric **	This is not just a straight comparison -- if the mailer doesn't
15053188Seric **	care about the host we just ignore it, etc.
15063188Seric **
15073188Seric **	Parameters:
15083188Seric **		a, b -- pointers to the internal forms to compare.
15093188Seric **
15103188Seric **	Returns:
15113188Seric **		TRUE -- they represent the same mailbox.
15123188Seric **		FALSE -- they don't.
15133188Seric **
15143188Seric **	Side Effects:
15153188Seric **		none.
15163188Seric */
15173188Seric 
15183188Seric bool
15199374Seric sameaddr(a, b)
15203188Seric 	register ADDRESS *a;
15213188Seric 	register ADDRESS *b;
15223188Seric {
152365093Seric 	register ADDRESS *ca, *cb;
152465093Seric 
15253188Seric 	/* if they don't have the same mailer, forget it */
15263188Seric 	if (a->q_mailer != b->q_mailer)
15273188Seric 		return (FALSE);
15283188Seric 
15293188Seric 	/* if the user isn't the same, we can drop out */
153056678Seric 	if (strcmp(a->q_user, b->q_user) != 0)
15313188Seric 		return (FALSE);
15323188Seric 
153365093Seric 	/* if we have good uids for both but they differ, these are different */
153465379Seric 	if (a->q_mailer == ProgMailer)
153565379Seric 	{
153665379Seric 		ca = getctladdr(a);
153765379Seric 		cb = getctladdr(b);
153865379Seric 		if (ca != NULL && cb != NULL &&
153965379Seric 		    bitset(QGOODUID, ca->q_flags & cb->q_flags) &&
154065379Seric 		    ca->q_uid != cb->q_uid)
154165379Seric 			return (FALSE);
154265379Seric 	}
154358438Seric 
154458509Seric 	/* otherwise compare hosts (but be careful for NULL ptrs) */
154558509Seric 	if (a->q_host == b->q_host)
154658509Seric 	{
154758509Seric 		/* probably both null pointers */
15483188Seric 		return (TRUE);
154958509Seric 	}
15503188Seric 	if (a->q_host == NULL || b->q_host == NULL)
155158509Seric 	{
155258509Seric 		/* only one is a null pointer */
15533188Seric 		return (FALSE);
155458509Seric 	}
155556678Seric 	if (strcmp(a->q_host, b->q_host) != 0)
15563188Seric 		return (FALSE);
15573188Seric 
15583188Seric 	return (TRUE);
15593188Seric }
15603234Seric /*
15613234Seric **  PRINTADDR -- print address (for debugging)
15623234Seric **
15633234Seric **	Parameters:
15643234Seric **		a -- the address to print
15653234Seric **		follow -- follow the q_next chain.
15663234Seric **
15673234Seric **	Returns:
15683234Seric **		none.
15693234Seric **
15703234Seric **	Side Effects:
15713234Seric **		none.
15723234Seric */
15733234Seric 
157467994Seric struct qflags
157567994Seric {
157667994Seric 	char	*qf_name;
157767994Seric 	u_long	qf_bit;
157867994Seric };
157967994Seric 
158067994Seric struct qflags	AddressFlags[] =
158167994Seric {
158267994Seric 	"QDONTSEND",		QDONTSEND,
158367994Seric 	"QBADADDR",		QBADADDR,
158467994Seric 	"QGOODUID",		QGOODUID,
158567994Seric 	"QPRIMARY",		QPRIMARY,
158667994Seric 	"QQUEUEUP",		QQUEUEUP,
158767994Seric 	"QSENT",		QSENT,
158867994Seric 	"QNOTREMOTE",		QNOTREMOTE,
158967994Seric 	"QSELFREF",		QSELFREF,
159067994Seric 	"QVERIFIED",		QVERIFIED,
159167994Seric 	"QREPORT",		QREPORT,
159267994Seric 	"QBOGUSSHELL",		QBOGUSSHELL,
159367994Seric 	"QUNSAFEADDR",		QUNSAFEADDR,
159467994Seric 	"QPINGONSUCCESS",	QPINGONSUCCESS,
159567994Seric 	"QPINGONFAILURE",	QPINGONFAILURE,
159667994Seric 	"QPINGONDELAY",		QPINGONDELAY,
159767994Seric 	"QHAS_RET_PARAM",	QHAS_RET_PARAM,
159867994Seric 	"QRET_HDRS",		QRET_HDRS,
159967994Seric 	"QRELAYED",		QRELAYED,
160067994Seric 	NULL
160167994Seric };
160267994Seric 
16033234Seric printaddr(a, follow)
16043234Seric 	register ADDRESS *a;
16053234Seric 	bool follow;
16063234Seric {
160757731Seric 	register MAILER *m;
160857731Seric 	MAILER pseudomailer;
160967994Seric 	register struct qflags *qfp;
161067994Seric 	bool firstone;
16115001Seric 
161267994Seric 	if (a == NULL)
161367994Seric 	{
161467994Seric 		printf("[NULL]\n");
161567994Seric 		return;
161667994Seric 	}
161767994Seric 
16183234Seric 	while (a != NULL)
16193234Seric 	{
16204443Seric 		printf("%x=", a);
16214085Seric 		(void) fflush(stdout);
162257731Seric 
162357731Seric 		/* find the mailer -- carefully */
162457731Seric 		m = a->q_mailer;
162557731Seric 		if (m == NULL)
162657731Seric 		{
162757731Seric 			m = &pseudomailer;
162857731Seric 			m->m_mno = -1;
162957731Seric 			m->m_name = "NULL";
163057731Seric 		}
163157731Seric 
163258680Seric 		printf("%s:\n\tmailer %d (%s), host `%s', user `%s', ruser `%s'\n",
163357731Seric 		       a->q_paddr, m->m_mno, m->m_name,
163467172Seric 		       a->q_host == NULL ? "<null>" : a->q_host, a->q_user,
163567172Seric 		       a->q_ruser == NULL ? "<null>" : a->q_ruser);
163667994Seric 		printf("\tnext=%x, alias %x, uid %d, gid %d\n",
163767994Seric 		       a->q_next, a->q_alias, a->q_uid, a->q_gid);
163867994Seric 		printf("\tflags=%lx<", a->q_flags);
163967994Seric 		firstone = TRUE;
164067994Seric 		for (qfp = AddressFlags; qfp->qf_name != NULL; qfp++)
164167994Seric 		{
164267994Seric 			if (!bitset(qfp->qf_bit, a->q_flags))
164367994Seric 				continue;
164467994Seric 			if (!firstone)
164567994Seric 				printf(",");
164667994Seric 			firstone = FALSE;
164767994Seric 			printf("%s", qfp->qf_name);
164867994Seric 		}
164967994Seric 		printf(">\n");
165059269Seric 		printf("\towner=%s, home=\"%s\", fullname=\"%s\"\n",
165159269Seric 		       a->q_owner == NULL ? "(none)" : a->q_owner,
165263756Seric 		       a->q_home == NULL ? "(none)" : a->q_home,
165363756Seric 		       a->q_fullname == NULL ? "(none)" : a->q_fullname);
165467990Seric 		printf("\torcpt=\"%s\", statmta=%s, fstatus=%s, rstatus=%s\n",
165567987Seric 		       a->q_orcpt == NULL ? "(none)" : a->q_orcpt,
165667987Seric 		       a->q_statmta == NULL ? "(none)" : a->q_statmta,
165767990Seric 		       a->q_fstatus == NULL ? "(none)" : a->q_fstatus,
165867990Seric 		       a->q_rstatus == NULL ? "(none)" : a->q_rstatus);
16594996Seric 
16603234Seric 		if (!follow)
16613234Seric 			return;
16624996Seric 		a = a->q_next;
16633234Seric 	}
16643234Seric }
166567939Seric /*
166667939Seric **  EMPTYADDR -- return TRUE if this address is empty (``<>'')
166767939Seric **
166867939Seric **	Parameters:
166967939Seric **		a -- pointer to the address
167067939Seric **
167167939Seric **	Returns:
167267939Seric **		TRUE -- if this address is "empty" (i.e., no one should
167367939Seric **			ever generate replies to it.
167467939Seric **		FALSE -- if it is a "regular" (read: replyable) address.
167567939Seric */
16764317Seric 
167767939Seric bool
167867939Seric emptyaddr(a)
167967939Seric 	register ADDRESS *a;
168067939Seric {
168167939Seric 	return strcmp(a->q_paddr, "<>") == 0 || strcmp(a->q_user, "<>") == 0;
168267939Seric }
16837682Seric /*
16847682Seric **  REMOTENAME -- return the name relative to the current mailer
16857682Seric **
16867682Seric **	Parameters:
16877682Seric **		name -- the name to translate.
16888069Seric **		m -- the mailer that we want to do rewriting relative
16898069Seric **			to.
169059163Seric **		flags -- fine tune operations.
169159163Seric **		pstat -- pointer to status word.
169258020Seric **		e -- the current envelope.
16937682Seric **
16947682Seric **	Returns:
16957682Seric **		the text string representing this address relative to
16967682Seric **			the receiving mailer.
16977682Seric **
16987682Seric **	Side Effects:
16997682Seric **		none.
17007682Seric **
17017682Seric **	Warnings:
17027682Seric **		The text string returned is tucked away locally;
17037682Seric **			copy it if you intend to save it.
17047682Seric */
17057682Seric 
17067682Seric char *
170759163Seric remotename(name, m, flags, pstat, e)
17087682Seric 	char *name;
170956678Seric 	struct mailer *m;
171059163Seric 	int flags;
171159163Seric 	int *pstat;
171256678Seric 	register ENVELOPE *e;
17137682Seric {
17148069Seric 	register char **pvp;
17158069Seric 	char *fancy;
171656678Seric 	char *oldg = macvalue('g', e);
171758020Seric 	int rwset;
17187682Seric 	static char buf[MAXNAME];
17197682Seric 	char lbuf[MAXNAME];
172016914Seric 	char pvpbuf[PSBUFSIZE];
172156678Seric 	extern char *crackaddr();
17227682Seric 
17237755Seric 	if (tTd(12, 1))
17247755Seric 		printf("remotename(%s)\n", name);
17257755Seric 
172610177Seric 	/* don't do anything if we are tagging it as special */
172759163Seric 	if (bitset(RF_SENDERADDR, flags))
172859163Seric 		rwset = bitset(RF_HEADERADDR, flags) ? m->m_sh_rwset
172959163Seric 						     : m->m_se_rwset;
173058020Seric 	else
173159163Seric 		rwset = bitset(RF_HEADERADDR, flags) ? m->m_rh_rwset
173259163Seric 						     : m->m_re_rwset;
173358020Seric 	if (rwset < 0)
173410177Seric 		return (name);
173510177Seric 
17367682Seric 	/*
17378181Seric 	**  Do a heuristic crack of this name to extract any comment info.
17388181Seric 	**	This will leave the name as a comment and a $g macro.
17397889Seric 	*/
17407889Seric 
174159163Seric 	if (bitset(RF_CANONICAL, flags) || bitnset(M_NOCOMMENT, m->m_flags))
174258050Seric 		fancy = "\201g";
174310310Seric 	else
174410310Seric 		fancy = crackaddr(name);
17457889Seric 
17468181Seric 	/*
17478181Seric 	**  Turn the name into canonical form.
17488181Seric 	**	Normally this will be RFC 822 style, i.e., "user@domain".
17498181Seric 	**	If this only resolves to "user", and the "C" flag is
17508181Seric 	**	specified in the sending mailer, then the sender's
17518181Seric 	**	domain will be appended.
17528181Seric 	*/
17538181Seric 
175465066Seric 	pvp = prescan(name, '\0', pvpbuf, sizeof pvpbuf, NULL);
17557889Seric 	if (pvp == NULL)
17567889Seric 		return (name);
175765071Seric 	if (rewrite(pvp, 3, 0, e) == EX_TEMPFAIL)
175859163Seric 		*pstat = EX_TEMPFAIL;
175959163Seric 	if (bitset(RF_ADDDOMAIN, flags) && e->e_fromdomain != NULL)
17608181Seric 	{
17618181Seric 		/* append from domain to this address */
17628181Seric 		register char **pxp = pvp;
17638181Seric 
17649594Seric 		/* see if there is an "@domain" in the current name */
17658181Seric 		while (*pxp != NULL && strcmp(*pxp, "@") != 0)
17668181Seric 			pxp++;
17678181Seric 		if (*pxp == NULL)
17688181Seric 		{
17699594Seric 			/* no.... append the "@domain" from the sender */
177056678Seric 			register char **qxq = e->e_fromdomain;
17718181Seric 
17729594Seric 			while ((*pxp++ = *qxq++) != NULL)
17739594Seric 				continue;
177465071Seric 			if (rewrite(pvp, 3, 0, e) == EX_TEMPFAIL)
177559163Seric 				*pstat = EX_TEMPFAIL;
17768181Seric 		}
17778181Seric 	}
17788181Seric 
17798181Seric 	/*
17808959Seric 	**  Do more specific rewriting.
178156678Seric 	**	Rewrite using ruleset 1 or 2 depending on whether this is
178256678Seric 	**		a sender address or not.
17838181Seric 	**	Then run it through any receiving-mailer-specific rulesets.
17848181Seric 	*/
17858181Seric 
178659163Seric 	if (bitset(RF_SENDERADDR, flags))
178759541Seric 	{
178865071Seric 		if (rewrite(pvp, 1, 0, e) == EX_TEMPFAIL)
178959163Seric 			*pstat = EX_TEMPFAIL;
179059541Seric 	}
17918069Seric 	else
179259541Seric 	{
179365071Seric 		if (rewrite(pvp, 2, 0, e) == EX_TEMPFAIL)
179459163Seric 			*pstat = EX_TEMPFAIL;
179559541Seric 	}
179658020Seric 	if (rwset > 0)
179759541Seric 	{
179865071Seric 		if (rewrite(pvp, rwset, 0, e) == EX_TEMPFAIL)
179959163Seric 			*pstat = EX_TEMPFAIL;
180059541Seric 	}
18017682Seric 
18028181Seric 	/*
18038959Seric 	**  Do any final sanitation the address may require.
18048959Seric 	**	This will normally be used to turn internal forms
18058959Seric 	**	(e.g., user@host.LOCAL) into external form.  This
18068959Seric 	**	may be used as a default to the above rules.
18078959Seric 	*/
18088959Seric 
180965071Seric 	if (rewrite(pvp, 4, 0, e) == EX_TEMPFAIL)
181059163Seric 		*pstat = EX_TEMPFAIL;
18118959Seric 
18128959Seric 	/*
18138181Seric 	**  Now restore the comment information we had at the beginning.
18148181Seric 	*/
18158181Seric 
181658825Seric 	cataddr(pvp, NULL, lbuf, sizeof lbuf, '\0');
181756678Seric 	define('g', lbuf, e);
181865494Seric 
181965494Seric 	/* need to make sure route-addrs have <angle brackets> */
182065494Seric 	if (bitset(RF_CANONICAL, flags) && lbuf[0] == '@')
182165494Seric 		expand("<\201g>", buf, &buf[sizeof buf - 1], e);
182265494Seric 	else
182365494Seric 		expand(fancy, buf, &buf[sizeof buf - 1], e);
182465494Seric 
182556678Seric 	define('g', oldg, e);
18267682Seric 
18277682Seric 	if (tTd(12, 1))
18287755Seric 		printf("remotename => `%s'\n", buf);
18297682Seric 	return (buf);
18307682Seric }
183151317Seric /*
183256678Seric **  MAPLOCALUSER -- run local username through ruleset 5 for final redirection
183351317Seric **
183451317Seric **	Parameters:
183556678Seric **		a -- the address to map (but just the user name part).
183656678Seric **		sendq -- the sendq in which to install any replacement
183756678Seric **			addresses.
183867982Seric **		aliaslevel -- the alias nesting depth.
183967982Seric **		e -- the envelope.
184051317Seric **
184151317Seric **	Returns:
184251317Seric **		none.
184351317Seric */
184451317Seric 
184567982Seric maplocaluser(a, sendq, aliaslevel, e)
184656678Seric 	register ADDRESS *a;
184756678Seric 	ADDRESS **sendq;
184867982Seric 	int aliaslevel;
184956678Seric 	ENVELOPE *e;
185051317Seric {
185156678Seric 	register char **pvp;
185256678Seric 	register ADDRESS *a1 = NULL;
185358333Seric 	auto char *delimptr;
185456678Seric 	char pvpbuf[PSBUFSIZE];
185551317Seric 
185656678Seric 	if (tTd(29, 1))
185756678Seric 	{
185856678Seric 		printf("maplocaluser: ");
185956678Seric 		printaddr(a, FALSE);
186056678Seric 	}
186165066Seric 	pvp = prescan(a->q_user, '\0', pvpbuf, sizeof pvpbuf, &delimptr);
186256678Seric 	if (pvp == NULL)
186356678Seric 		return;
186451317Seric 
186565071Seric 	(void) rewrite(pvp, 5, 0, e);
186658050Seric 	if (pvp[0] == NULL || (pvp[0][0] & 0377) != CANONNET)
186756678Seric 		return;
186851317Seric 
186956678Seric 	/* if non-null, mailer destination specified -- has it changed? */
187064284Seric 	a1 = buildaddr(pvp, NULL, 0, e);
187156678Seric 	if (a1 == NULL || sameaddr(a, a1))
187256678Seric 		return;
187351317Seric 
187456678Seric 	/* mark old address as dead; insert new address */
187556678Seric 	a->q_flags |= QDONTSEND;
187657731Seric 	if (tTd(29, 5))
187757731Seric 	{
187857731Seric 		printf("maplocaluser: QDONTSEND ");
187957731Seric 		printaddr(a, FALSE);
188057731Seric 	}
188156678Seric 	a1->q_alias = a;
188264348Seric 	allocaddr(a1, RF_COPYALL, NULL);
188367982Seric 	(void) recipient(a1, sendq, aliaslevel, e);
188451317Seric }
188558802Seric /*
188658802Seric **  DEQUOTE_INIT -- initialize dequote map
188758802Seric **
188858802Seric **	This is a no-op.
188958802Seric **
189058802Seric **	Parameters:
189158802Seric **		map -- the internal map structure.
189258802Seric **		args -- arguments.
189358802Seric **
189458802Seric **	Returns:
189558802Seric **		TRUE.
189658802Seric */
189758802Seric 
189858802Seric bool
189960219Seric dequote_init(map, args)
190058802Seric 	MAP *map;
190158802Seric 	char *args;
190258802Seric {
190358805Seric 	register char *p = args;
190458805Seric 
190558805Seric 	for (;;)
190658805Seric 	{
190758805Seric 		while (isascii(*p) && isspace(*p))
190858805Seric 			p++;
190958805Seric 		if (*p != '-')
191058805Seric 			break;
191158805Seric 		switch (*++p)
191258805Seric 		{
191358805Seric 		  case 'a':
191458805Seric 			map->map_app = ++p;
191558805Seric 			break;
191667824Seric 
191767824Seric 		  case 's':
191867824Seric 			map->map_coldelim = *++p;
191967824Seric 			break;
192058805Seric 		}
192158805Seric 		while (*p != '\0' && !(isascii(*p) && isspace(*p)))
192258805Seric 			p++;
192358805Seric 		if (*p != '\0')
192458805Seric 			*p = '\0';
192558805Seric 	}
192658805Seric 	if (map->map_app != NULL)
192758805Seric 		map->map_app = newstr(map->map_app);
192858805Seric 
192958802Seric 	return TRUE;
193058802Seric }
193158802Seric /*
193258802Seric **  DEQUOTE_MAP -- unquote an address
193358802Seric **
193458802Seric **	Parameters:
193558802Seric **		map -- the internal map structure (ignored).
193660089Seric **		name -- the name to dequote.
193758802Seric **		av -- arguments (ignored).
193859084Seric **		statp -- pointer to status out-parameter.
193958802Seric **
194058802Seric **	Returns:
194158802Seric **		NULL -- if there were no quotes, or if the resulting
194258802Seric **			unquoted buffer would not be acceptable to prescan.
194358802Seric **		else -- The dequoted buffer.
194458802Seric */
194558802Seric 
194658802Seric char *
194760089Seric dequote_map(map, name, av, statp)
194858802Seric 	MAP *map;
194960089Seric 	char *name;
195058802Seric 	char **av;
195159084Seric 	int *statp;
195258802Seric {
195358802Seric 	register char *p;
195458802Seric 	register char *q;
195558802Seric 	register char c;
195667824Seric 	int anglecnt = 0;
195767824Seric 	int cmntcnt = 0;
195867824Seric 	int quotecnt = 0;
195967824Seric 	int spacecnt = 0;
196067824Seric 	bool quotemode = FALSE;
196167824Seric 	bool bslashmode = FALSE;
196267824Seric 	char spacesub = map->map_coldelim;
196358802Seric 
196460089Seric 	for (p = q = name; (c = *p++) != '\0'; )
196558802Seric 	{
196658802Seric 		if (bslashmode)
196758802Seric 		{
196858802Seric 			bslashmode = FALSE;
196958802Seric 			*q++ = c;
197058802Seric 			continue;
197158802Seric 		}
197258802Seric 
197367824Seric 		if (c == ' ' && spacesub != '\0')
197467824Seric 			c = spacesub;
197567764Seric 
197658802Seric 		switch (c)
197758802Seric 		{
197858802Seric 		  case '\\':
197958802Seric 			bslashmode = TRUE;
198058802Seric 			break;
198158802Seric 
198258802Seric 		  case '(':
198358802Seric 			cmntcnt++;
198458802Seric 			break;
198558802Seric 
198658802Seric 		  case ')':
198758802Seric 			if (cmntcnt-- <= 0)
198858802Seric 				return NULL;
198958802Seric 			break;
199059089Seric 
199159089Seric 		  case ' ':
199259089Seric 			spacecnt++;
199359089Seric 			break;
199458802Seric 		}
199558802Seric 
199658802Seric 		if (cmntcnt > 0)
199758802Seric 		{
199858802Seric 			*q++ = c;
199958802Seric 			continue;
200058802Seric 		}
200158802Seric 
200258802Seric 		switch (c)
200358802Seric 		{
200458802Seric 		  case '"':
200558802Seric 			quotemode = !quotemode;
200658802Seric 			quotecnt++;
200758802Seric 			continue;
200858802Seric 
200958802Seric 		  case '<':
201058802Seric 			anglecnt++;
201158802Seric 			break;
201258802Seric 
201358802Seric 		  case '>':
201458802Seric 			if (anglecnt-- <= 0)
201558802Seric 				return NULL;
201658802Seric 			break;
201758802Seric 		}
201858802Seric 		*q++ = c;
201958802Seric 	}
202058802Seric 
202158802Seric 	if (anglecnt != 0 || cmntcnt != 0 || bslashmode ||
202259089Seric 	    quotemode || quotecnt <= 0 || spacecnt != 0)
202358802Seric 		return NULL;
202458802Seric 	*q++ = '\0';
202560089Seric 	return name;
202658802Seric }
2027