xref: /freebsd/contrib/sendmail/src/parseaddr.c (revision c2aa98e247e56d5266d789dfc9b90b524b0019fe)
1c2aa98e2SPeter Wemm /*
2c2aa98e2SPeter Wemm  * Copyright (c) 1998 Sendmail, Inc.  All rights reserved.
3c2aa98e2SPeter Wemm  * Copyright (c) 1983, 1995-1997 Eric P. Allman.  All rights reserved.
4c2aa98e2SPeter Wemm  * Copyright (c) 1988, 1993
5c2aa98e2SPeter Wemm  *	The Regents of the University of California.  All rights reserved.
6c2aa98e2SPeter Wemm  *
7c2aa98e2SPeter Wemm  * By using this file, you agree to the terms and conditions set
8c2aa98e2SPeter Wemm  * forth in the LICENSE file which can be found at the top level of
9c2aa98e2SPeter Wemm  * the sendmail distribution.
10c2aa98e2SPeter Wemm  *
11c2aa98e2SPeter Wemm  */
12c2aa98e2SPeter Wemm 
13c2aa98e2SPeter Wemm #ifndef lint
14c2aa98e2SPeter Wemm static char sccsid[] = "@(#)parseaddr.c	8.153 (Berkeley) 6/24/98";
15c2aa98e2SPeter Wemm #endif /* not lint */
16c2aa98e2SPeter Wemm 
17c2aa98e2SPeter Wemm # include "sendmail.h"
18c2aa98e2SPeter Wemm 
19c2aa98e2SPeter Wemm /*
20c2aa98e2SPeter Wemm **  PARSEADDR -- Parse an address
21c2aa98e2SPeter Wemm **
22c2aa98e2SPeter Wemm **	Parses an address and breaks it up into three parts: a
23c2aa98e2SPeter Wemm **	net to transmit the message on, the host to transmit it
24c2aa98e2SPeter Wemm **	to, and a user on that host.  These are loaded into an
25c2aa98e2SPeter Wemm **	ADDRESS header with the values squirreled away if necessary.
26c2aa98e2SPeter Wemm **	The "user" part may not be a real user; the process may
27c2aa98e2SPeter Wemm **	just reoccur on that machine.  For example, on a machine
28c2aa98e2SPeter Wemm **	with an arpanet connection, the address
29c2aa98e2SPeter Wemm **		csvax.bill@berkeley
30c2aa98e2SPeter Wemm **	will break up to a "user" of 'csvax.bill' and a host
31c2aa98e2SPeter Wemm **	of 'berkeley' -- to be transmitted over the arpanet.
32c2aa98e2SPeter Wemm **
33c2aa98e2SPeter Wemm **	Parameters:
34c2aa98e2SPeter Wemm **		addr -- the address to parse.
35c2aa98e2SPeter Wemm **		a -- a pointer to the address descriptor buffer.
36c2aa98e2SPeter Wemm **			If NULL, a header will be created.
37c2aa98e2SPeter Wemm **		flags -- describe detail for parsing.  See RF_ definitions
38c2aa98e2SPeter Wemm **			in sendmail.h.
39c2aa98e2SPeter Wemm **		delim -- the character to terminate the address, passed
40c2aa98e2SPeter Wemm **			to prescan.
41c2aa98e2SPeter Wemm **		delimptr -- if non-NULL, set to the location of the
42c2aa98e2SPeter Wemm **			delim character that was found.
43c2aa98e2SPeter Wemm **		e -- the envelope that will contain this address.
44c2aa98e2SPeter Wemm **
45c2aa98e2SPeter Wemm **	Returns:
46c2aa98e2SPeter Wemm **		A pointer to the address descriptor header (`a' if
47c2aa98e2SPeter Wemm **			`a' is non-NULL).
48c2aa98e2SPeter Wemm **		NULL on error.
49c2aa98e2SPeter Wemm **
50c2aa98e2SPeter Wemm **	Side Effects:
51c2aa98e2SPeter Wemm **		none
52c2aa98e2SPeter Wemm */
53c2aa98e2SPeter Wemm 
54c2aa98e2SPeter Wemm /* following delimiters are inherent to the internal algorithms */
55c2aa98e2SPeter Wemm # define DELIMCHARS	"()<>,;\r\n"	/* default word delimiters */
56c2aa98e2SPeter Wemm 
57c2aa98e2SPeter Wemm ADDRESS *
58c2aa98e2SPeter Wemm parseaddr(addr, a, flags, delim, delimptr, e)
59c2aa98e2SPeter Wemm 	char *addr;
60c2aa98e2SPeter Wemm 	register ADDRESS *a;
61c2aa98e2SPeter Wemm 	int flags;
62c2aa98e2SPeter Wemm 	int delim;
63c2aa98e2SPeter Wemm 	char **delimptr;
64c2aa98e2SPeter Wemm 	register ENVELOPE *e;
65c2aa98e2SPeter Wemm {
66c2aa98e2SPeter Wemm 	register char **pvp;
67c2aa98e2SPeter Wemm 	auto char *delimptrbuf;
68c2aa98e2SPeter Wemm 	bool queueup;
69c2aa98e2SPeter Wemm 	char pvpbuf[PSBUFSIZE];
70c2aa98e2SPeter Wemm 	extern ADDRESS *buildaddr __P((char **, ADDRESS *, int, ENVELOPE *));
71c2aa98e2SPeter Wemm 	extern bool invalidaddr __P((char *, char *));
72c2aa98e2SPeter Wemm 	extern void allocaddr __P((ADDRESS *, int, char *));
73c2aa98e2SPeter Wemm 
74c2aa98e2SPeter Wemm 	/*
75c2aa98e2SPeter Wemm 	**  Initialize and prescan address.
76c2aa98e2SPeter Wemm 	*/
77c2aa98e2SPeter Wemm 
78c2aa98e2SPeter Wemm 	e->e_to = addr;
79c2aa98e2SPeter Wemm 	if (tTd(20, 1))
80c2aa98e2SPeter Wemm 		printf("\n--parseaddr(%s)\n", addr);
81c2aa98e2SPeter Wemm 
82c2aa98e2SPeter Wemm 	if (delimptr == NULL)
83c2aa98e2SPeter Wemm 		delimptr = &delimptrbuf;
84c2aa98e2SPeter Wemm 
85c2aa98e2SPeter Wemm 	pvp = prescan(addr, delim, pvpbuf, sizeof pvpbuf, delimptr, NULL);
86c2aa98e2SPeter Wemm 	if (pvp == NULL)
87c2aa98e2SPeter Wemm 	{
88c2aa98e2SPeter Wemm 		if (tTd(20, 1))
89c2aa98e2SPeter Wemm 			printf("parseaddr-->NULL\n");
90c2aa98e2SPeter Wemm 		return (NULL);
91c2aa98e2SPeter Wemm 	}
92c2aa98e2SPeter Wemm 
93c2aa98e2SPeter Wemm 	if (invalidaddr(addr, delim == '\0' ? NULL : *delimptr))
94c2aa98e2SPeter Wemm 	{
95c2aa98e2SPeter Wemm 		if (tTd(20, 1))
96c2aa98e2SPeter Wemm 			printf("parseaddr-->bad address\n");
97c2aa98e2SPeter Wemm 		return NULL;
98c2aa98e2SPeter Wemm 	}
99c2aa98e2SPeter Wemm 
100c2aa98e2SPeter Wemm 	/*
101c2aa98e2SPeter Wemm 	**  Save addr if we are going to have to.
102c2aa98e2SPeter Wemm 	**
103c2aa98e2SPeter Wemm 	**	We have to do this early because there is a chance that
104c2aa98e2SPeter Wemm 	**	the map lookups in the rewriting rules could clobber
105c2aa98e2SPeter Wemm 	**	static memory somewhere.
106c2aa98e2SPeter Wemm 	*/
107c2aa98e2SPeter Wemm 
108c2aa98e2SPeter Wemm 	if (bitset(RF_COPYPADDR, flags) && addr != NULL)
109c2aa98e2SPeter Wemm 	{
110c2aa98e2SPeter Wemm 		char savec = **delimptr;
111c2aa98e2SPeter Wemm 
112c2aa98e2SPeter Wemm 		if (savec != '\0')
113c2aa98e2SPeter Wemm 			**delimptr = '\0';
114c2aa98e2SPeter Wemm 		e->e_to = addr = newstr(addr);
115c2aa98e2SPeter Wemm 		if (savec != '\0')
116c2aa98e2SPeter Wemm 			**delimptr = savec;
117c2aa98e2SPeter Wemm 	}
118c2aa98e2SPeter Wemm 
119c2aa98e2SPeter Wemm 	/*
120c2aa98e2SPeter Wemm 	**  Apply rewriting rules.
121c2aa98e2SPeter Wemm 	**	Ruleset 0 does basic parsing.  It must resolve.
122c2aa98e2SPeter Wemm 	*/
123c2aa98e2SPeter Wemm 
124c2aa98e2SPeter Wemm 	queueup = FALSE;
125c2aa98e2SPeter Wemm 	if (rewrite(pvp, 3, 0, e) == EX_TEMPFAIL)
126c2aa98e2SPeter Wemm 		queueup = TRUE;
127c2aa98e2SPeter Wemm 	if (rewrite(pvp, 0, 0, e) == EX_TEMPFAIL)
128c2aa98e2SPeter Wemm 		queueup = TRUE;
129c2aa98e2SPeter Wemm 
130c2aa98e2SPeter Wemm 
131c2aa98e2SPeter Wemm 	/*
132c2aa98e2SPeter Wemm 	**  Build canonical address from pvp.
133c2aa98e2SPeter Wemm 	*/
134c2aa98e2SPeter Wemm 
135c2aa98e2SPeter Wemm 	a = buildaddr(pvp, a, flags, e);
136c2aa98e2SPeter Wemm 
137c2aa98e2SPeter Wemm 	/*
138c2aa98e2SPeter Wemm 	**  Make local copies of the host & user and then
139c2aa98e2SPeter Wemm 	**  transport them out.
140c2aa98e2SPeter Wemm 	*/
141c2aa98e2SPeter Wemm 
142c2aa98e2SPeter Wemm 	allocaddr(a, flags, addr);
143c2aa98e2SPeter Wemm 	if (bitset(QBADADDR, a->q_flags))
144c2aa98e2SPeter Wemm 		return a;
145c2aa98e2SPeter Wemm 
146c2aa98e2SPeter Wemm 	/*
147c2aa98e2SPeter Wemm 	**  If there was a parsing failure, mark it for queueing.
148c2aa98e2SPeter Wemm 	*/
149c2aa98e2SPeter Wemm 
150c2aa98e2SPeter Wemm 	if (queueup && OpMode != MD_INITALIAS)
151c2aa98e2SPeter Wemm 	{
152c2aa98e2SPeter Wemm 		char *msg = "Transient parse error -- message queued for future delivery";
153c2aa98e2SPeter Wemm 
154c2aa98e2SPeter Wemm 		if (e->e_sendmode == SM_DEFER)
155c2aa98e2SPeter Wemm 			msg = "Deferring message until queue run";
156c2aa98e2SPeter Wemm 		if (tTd(20, 1))
157c2aa98e2SPeter Wemm 			printf("parseaddr: queuing message\n");
158c2aa98e2SPeter Wemm 		message(msg);
159c2aa98e2SPeter Wemm 		if (e->e_message == NULL && e->e_sendmode != SM_DEFER)
160c2aa98e2SPeter Wemm 			e->e_message = newstr(msg);
161c2aa98e2SPeter Wemm 		a->q_flags |= QQUEUEUP;
162c2aa98e2SPeter Wemm 		a->q_status = "4.4.3";
163c2aa98e2SPeter Wemm 	}
164c2aa98e2SPeter Wemm 
165c2aa98e2SPeter Wemm 	/*
166c2aa98e2SPeter Wemm 	**  Compute return value.
167c2aa98e2SPeter Wemm 	*/
168c2aa98e2SPeter Wemm 
169c2aa98e2SPeter Wemm 	if (tTd(20, 1))
170c2aa98e2SPeter Wemm 	{
171c2aa98e2SPeter Wemm 		printf("parseaddr-->");
172c2aa98e2SPeter Wemm 		printaddr(a, FALSE);
173c2aa98e2SPeter Wemm 	}
174c2aa98e2SPeter Wemm 
175c2aa98e2SPeter Wemm 	return (a);
176c2aa98e2SPeter Wemm }
177c2aa98e2SPeter Wemm /*
178c2aa98e2SPeter Wemm **  INVALIDADDR -- check for address containing meta-characters
179c2aa98e2SPeter Wemm **
180c2aa98e2SPeter Wemm **	Parameters:
181c2aa98e2SPeter Wemm **		addr -- the address to check.
182c2aa98e2SPeter Wemm **
183c2aa98e2SPeter Wemm **	Returns:
184c2aa98e2SPeter Wemm **		TRUE -- if the address has any "wierd" characters
185c2aa98e2SPeter Wemm **		FALSE -- otherwise.
186c2aa98e2SPeter Wemm */
187c2aa98e2SPeter Wemm 
188c2aa98e2SPeter Wemm bool
189c2aa98e2SPeter Wemm invalidaddr(addr, delimptr)
190c2aa98e2SPeter Wemm 	register char *addr;
191c2aa98e2SPeter Wemm 	char *delimptr;
192c2aa98e2SPeter Wemm {
193c2aa98e2SPeter Wemm 	char savedelim = '\0';
194c2aa98e2SPeter Wemm 
195c2aa98e2SPeter Wemm 	if (delimptr != NULL)
196c2aa98e2SPeter Wemm 	{
197c2aa98e2SPeter Wemm 		savedelim = *delimptr;
198c2aa98e2SPeter Wemm 		if (savedelim != '\0')
199c2aa98e2SPeter Wemm 			*delimptr = '\0';
200c2aa98e2SPeter Wemm 	}
201c2aa98e2SPeter Wemm 	if (strlen(addr) > TOBUFSIZE - 2)
202c2aa98e2SPeter Wemm 	{
203c2aa98e2SPeter Wemm 		usrerr("553 Address too long (%d bytes max)", TOBUFSIZE - 2);
204c2aa98e2SPeter Wemm 		goto failure;
205c2aa98e2SPeter Wemm 	}
206c2aa98e2SPeter Wemm 	for (; *addr != '\0'; addr++)
207c2aa98e2SPeter Wemm 	{
208c2aa98e2SPeter Wemm 		if ((*addr & 0340) == 0200)
209c2aa98e2SPeter Wemm 			break;
210c2aa98e2SPeter Wemm 	}
211c2aa98e2SPeter Wemm 	if (*addr == '\0')
212c2aa98e2SPeter Wemm 	{
213c2aa98e2SPeter Wemm 		if (delimptr != NULL && savedelim != '\0')
214c2aa98e2SPeter Wemm 			*delimptr = savedelim;
215c2aa98e2SPeter Wemm 		return FALSE;
216c2aa98e2SPeter Wemm 	}
217c2aa98e2SPeter Wemm 	setstat(EX_USAGE);
218c2aa98e2SPeter Wemm 	usrerr("553 Address contained invalid control characters");
219c2aa98e2SPeter Wemm failure:
220c2aa98e2SPeter Wemm 	if (delimptr != NULL && savedelim != '\0')
221c2aa98e2SPeter Wemm 		*delimptr = savedelim;
222c2aa98e2SPeter Wemm 	return TRUE;
223c2aa98e2SPeter Wemm }
224c2aa98e2SPeter Wemm /*
225c2aa98e2SPeter Wemm **  ALLOCADDR -- do local allocations of address on demand.
226c2aa98e2SPeter Wemm **
227c2aa98e2SPeter Wemm **	Also lowercases the host name if requested.
228c2aa98e2SPeter Wemm **
229c2aa98e2SPeter Wemm **	Parameters:
230c2aa98e2SPeter Wemm **		a -- the address to reallocate.
231c2aa98e2SPeter Wemm **		flags -- the copy flag (see RF_ definitions in sendmail.h
232c2aa98e2SPeter Wemm **			for a description).
233c2aa98e2SPeter Wemm **		paddr -- the printname of the address.
234c2aa98e2SPeter Wemm **
235c2aa98e2SPeter Wemm **	Returns:
236c2aa98e2SPeter Wemm **		none.
237c2aa98e2SPeter Wemm **
238c2aa98e2SPeter Wemm **	Side Effects:
239c2aa98e2SPeter Wemm **		Copies portions of a into local buffers as requested.
240c2aa98e2SPeter Wemm */
241c2aa98e2SPeter Wemm 
242c2aa98e2SPeter Wemm void
243c2aa98e2SPeter Wemm allocaddr(a, flags, paddr)
244c2aa98e2SPeter Wemm 	register ADDRESS *a;
245c2aa98e2SPeter Wemm 	int flags;
246c2aa98e2SPeter Wemm 	char *paddr;
247c2aa98e2SPeter Wemm {
248c2aa98e2SPeter Wemm 	if (tTd(24, 4))
249c2aa98e2SPeter Wemm 		printf("allocaddr(flags=%x, paddr=%s)\n", flags, paddr);
250c2aa98e2SPeter Wemm 
251c2aa98e2SPeter Wemm 	a->q_paddr = paddr;
252c2aa98e2SPeter Wemm 
253c2aa98e2SPeter Wemm 	if (a->q_user == NULL)
254c2aa98e2SPeter Wemm 		a->q_user = "";
255c2aa98e2SPeter Wemm 	if (a->q_host == NULL)
256c2aa98e2SPeter Wemm 		a->q_host = "";
257c2aa98e2SPeter Wemm 
258c2aa98e2SPeter Wemm 	if (bitset(RF_COPYPARSE, flags))
259c2aa98e2SPeter Wemm 	{
260c2aa98e2SPeter Wemm 		a->q_host = newstr(a->q_host);
261c2aa98e2SPeter Wemm 		if (a->q_user != a->q_paddr)
262c2aa98e2SPeter Wemm 			a->q_user = newstr(a->q_user);
263c2aa98e2SPeter Wemm 	}
264c2aa98e2SPeter Wemm 
265c2aa98e2SPeter Wemm 	if (a->q_paddr == NULL)
266c2aa98e2SPeter Wemm 		a->q_paddr = a->q_user;
267c2aa98e2SPeter Wemm }
268c2aa98e2SPeter Wemm /*
269c2aa98e2SPeter Wemm **  PRESCAN -- Prescan name and make it canonical
270c2aa98e2SPeter Wemm **
271c2aa98e2SPeter Wemm **	Scans a name and turns it into a set of tokens.  This process
272c2aa98e2SPeter Wemm **	deletes blanks and comments (in parentheses).
273c2aa98e2SPeter Wemm **
274c2aa98e2SPeter Wemm **	This routine knows about quoted strings and angle brackets.
275c2aa98e2SPeter Wemm **
276c2aa98e2SPeter Wemm **	There are certain subtleties to this routine.  The one that
277c2aa98e2SPeter Wemm **	comes to mind now is that backslashes on the ends of names
278c2aa98e2SPeter Wemm **	are silently stripped off; this is intentional.  The problem
279c2aa98e2SPeter Wemm **	is that some versions of sndmsg (like at LBL) set the kill
280c2aa98e2SPeter Wemm **	character to something other than @ when reading addresses;
281c2aa98e2SPeter Wemm **	so people type "csvax.eric\@berkeley" -- which screws up the
282c2aa98e2SPeter Wemm **	berknet mailer.
283c2aa98e2SPeter Wemm **
284c2aa98e2SPeter Wemm **	Parameters:
285c2aa98e2SPeter Wemm **		addr -- the name to chomp.
286c2aa98e2SPeter Wemm **		delim -- the delimiter for the address, normally
287c2aa98e2SPeter Wemm **			'\0' or ','; \0 is accepted in any case.
288c2aa98e2SPeter Wemm **			If '\t' then we are reading the .cf file.
289c2aa98e2SPeter Wemm **		pvpbuf -- place to put the saved text -- note that
290c2aa98e2SPeter Wemm **			the pointers are static.
291c2aa98e2SPeter Wemm **		pvpbsize -- size of pvpbuf.
292c2aa98e2SPeter Wemm **		delimptr -- if non-NULL, set to the location of the
293c2aa98e2SPeter Wemm **			terminating delimiter.
294c2aa98e2SPeter Wemm **		toktab -- if set, a token table to use for parsing.
295c2aa98e2SPeter Wemm **			If NULL, use the default table.
296c2aa98e2SPeter Wemm **
297c2aa98e2SPeter Wemm **	Returns:
298c2aa98e2SPeter Wemm **		A pointer to a vector of tokens.
299c2aa98e2SPeter Wemm **		NULL on error.
300c2aa98e2SPeter Wemm */
301c2aa98e2SPeter Wemm 
302c2aa98e2SPeter Wemm /* states and character types */
303c2aa98e2SPeter Wemm # define OPR		0	/* operator */
304c2aa98e2SPeter Wemm # define ATM		1	/* atom */
305c2aa98e2SPeter Wemm # define QST		2	/* in quoted string */
306c2aa98e2SPeter Wemm # define SPC		3	/* chewing up spaces */
307c2aa98e2SPeter Wemm # define ONE		4	/* pick up one character */
308c2aa98e2SPeter Wemm # define ILL		5	/* illegal character */
309c2aa98e2SPeter Wemm 
310c2aa98e2SPeter Wemm # define NSTATES	6	/* number of states */
311c2aa98e2SPeter Wemm # define TYPE		017	/* mask to select state type */
312c2aa98e2SPeter Wemm 
313c2aa98e2SPeter Wemm /* meta bits for table */
314c2aa98e2SPeter Wemm # define M		020	/* meta character; don't pass through */
315c2aa98e2SPeter Wemm # define B		040	/* cause a break */
316c2aa98e2SPeter Wemm # define MB		M|B	/* meta-break */
317c2aa98e2SPeter Wemm 
318c2aa98e2SPeter Wemm static short StateTab[NSTATES][NSTATES] =
319c2aa98e2SPeter Wemm {
320c2aa98e2SPeter Wemm    /*	oldst	chtype>	OPR	ATM	QST	SPC	ONE	ILL	*/
321c2aa98e2SPeter Wemm 	/*OPR*/	{	OPR|B,	ATM|B,	QST|B,	SPC|MB,	ONE|B,	ILL|MB	},
322c2aa98e2SPeter Wemm 	/*ATM*/	{	OPR|B,	ATM,	QST|B,	SPC|MB,	ONE|B,	ILL|MB	},
323c2aa98e2SPeter Wemm 	/*QST*/	{	QST,	QST,	OPR,	QST,	QST,	QST	},
324c2aa98e2SPeter Wemm 	/*SPC*/	{	OPR,	ATM,	QST,	SPC|M,	ONE,	ILL|MB	},
325c2aa98e2SPeter Wemm 	/*ONE*/	{	OPR,	OPR,	OPR,	OPR,	OPR,	ILL|MB	},
326c2aa98e2SPeter Wemm 	/*ILL*/	{	OPR|B,	ATM|B,	QST|B,	SPC|MB,	ONE|B,	ILL|M	},
327c2aa98e2SPeter Wemm };
328c2aa98e2SPeter Wemm 
329c2aa98e2SPeter Wemm /* token type table -- it gets modified with $o characters */
330c2aa98e2SPeter Wemm static u_char	TokTypeTab[256] =
331c2aa98e2SPeter Wemm {
332c2aa98e2SPeter Wemm     /*	nul soh stx etx eot enq ack bel  bs  ht  nl  vt  np  cr  so  si   */
333c2aa98e2SPeter Wemm 	ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, ATM,SPC,SPC,SPC,SPC,SPC,ATM,ATM,
334c2aa98e2SPeter Wemm     /*	dle dc1 dc2 dc3 dc4 nak syn etb  can em  sub esc fs  gs  rs  us   */
335c2aa98e2SPeter Wemm 	ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,
336c2aa98e2SPeter Wemm     /*  sp  !   "   #   $   %   &   '    (   )   *   +   ,   -   .   /    */
337c2aa98e2SPeter Wemm 	SPC,ATM,QST,ATM,ATM,ATM,ATM,ATM, ATM,SPC,ATM,ATM,ATM,ATM,ATM,ATM,
338c2aa98e2SPeter Wemm     /*	0   1   2   3   4   5   6   7    8   9   :   ;   <   =   >   ?    */
339c2aa98e2SPeter Wemm 	ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,
340c2aa98e2SPeter Wemm     /*	@   A   B   C   D   E   F   G    H   I   J   K   L   M   N   O    */
341c2aa98e2SPeter Wemm 	ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,
342c2aa98e2SPeter Wemm     /*  P   Q   R   S   T   U   V   W    X   Y   Z   [   \   ]   ^   _    */
343c2aa98e2SPeter Wemm 	ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,
344c2aa98e2SPeter Wemm     /*	`   a   b   c   d   e   f   g    h   i   j   k   l   m   n   o    */
345c2aa98e2SPeter Wemm 	ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,
346c2aa98e2SPeter Wemm     /*  p   q   r   s   t   u   v   w    x   y   z   {   |   }   ~   del  */
347c2aa98e2SPeter Wemm 	ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,
348c2aa98e2SPeter Wemm 
349c2aa98e2SPeter Wemm     /*	nul soh stx etx eot enq ack bel  bs  ht  nl  vt  np  cr  so  si   */
350c2aa98e2SPeter Wemm 	OPR,OPR,ONE,OPR,OPR,OPR,OPR,OPR, OPR,OPR,OPR,OPR,OPR,OPR,OPR,OPR,
351c2aa98e2SPeter Wemm     /*	dle dc1 dc2 dc3 dc4 nak syn etb  can em  sub esc fs  gs  rs  us   */
352c2aa98e2SPeter Wemm 	OPR,OPR,OPR,ONE,ONE,ONE,OPR,OPR, OPR,OPR,OPR,OPR,OPR,OPR,OPR,OPR,
353c2aa98e2SPeter Wemm     /*  sp  !   "   #   $   %   &   '    (   )   *   +   ,   -   .   /    */
354c2aa98e2SPeter Wemm 	ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,
355c2aa98e2SPeter Wemm     /*	0   1   2   3   4   5   6   7    8   9   :   ;   <   =   >   ?    */
356c2aa98e2SPeter Wemm 	ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,
357c2aa98e2SPeter Wemm     /*	@   A   B   C   D   E   F   G    H   I   J   K   L   M   N   O    */
358c2aa98e2SPeter Wemm 	ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,
359c2aa98e2SPeter Wemm     /*  P   Q   R   S   T   U   V   W    X   Y   Z   [   \   ]   ^   _    */
360c2aa98e2SPeter Wemm 	ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,
361c2aa98e2SPeter Wemm     /*	`   a   b   c   d   e   f   g    h   i   j   k   l   m   n   o    */
362c2aa98e2SPeter Wemm 	ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,
363c2aa98e2SPeter Wemm     /*  p   q   r   s   t   u   v   w    x   y   z   {   |   }   ~   del  */
364c2aa98e2SPeter Wemm 	ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,
365c2aa98e2SPeter Wemm };
366c2aa98e2SPeter Wemm 
367c2aa98e2SPeter Wemm /* token type table for MIME parsing */
368c2aa98e2SPeter Wemm u_char	MimeTokenTab[256] =
369c2aa98e2SPeter Wemm {
370c2aa98e2SPeter Wemm     /*	nul soh stx etx eot enq ack bel  bs  ht  nl  vt  np  cr  so  si   */
371c2aa98e2SPeter Wemm 	ILL,ILL,ILL,ILL,ILL,ILL,ILL,ILL, ILL,SPC,SPC,SPC,SPC,SPC,ILL,ILL,
372c2aa98e2SPeter Wemm     /*	dle dc1 dc2 dc3 dc4 nak syn etb  can em  sub esc fs  gs  rs  us   */
373c2aa98e2SPeter Wemm 	ILL,ILL,ILL,ILL,ILL,ILL,ILL,ILL, ILL,ILL,ILL,ILL,ILL,ILL,ILL,ILL,
374c2aa98e2SPeter Wemm     /*  sp  !   "   #   $   %   &   '    (   )   *   +   ,   -   .   /    */
375c2aa98e2SPeter Wemm 	SPC,ATM,QST,ATM,ATM,ATM,ATM,ATM, ATM,SPC,ATM,ATM,OPR,ATM,ATM,OPR,
376c2aa98e2SPeter Wemm     /*	0   1   2   3   4   5   6   7    8   9   :   ;   <   =   >   ?    */
377c2aa98e2SPeter Wemm 	ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, ATM,ATM,OPR,OPR,OPR,OPR,OPR,OPR,
378c2aa98e2SPeter Wemm     /*	@   A   B   C   D   E   F   G    H   I   J   K   L   M   N   O    */
379c2aa98e2SPeter Wemm 	OPR,ATM,ATM,ATM,ATM,ATM,ATM,ATM, ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,
380c2aa98e2SPeter Wemm     /*  P   Q   R   S   T   U   V   W    X   Y   Z   [   \   ]   ^   _    */
381c2aa98e2SPeter Wemm 	ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, ATM,ATM,ATM,OPR,OPR,OPR,ATM,ATM,
382c2aa98e2SPeter Wemm     /*	`   a   b   c   d   e   f   g    h   i   j   k   l   m   n   o    */
383c2aa98e2SPeter Wemm 	ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,
384c2aa98e2SPeter Wemm     /*  p   q   r   s   t   u   v   w    x   y   z   {   |   }   ~   del  */
385c2aa98e2SPeter Wemm 	ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,
386c2aa98e2SPeter Wemm 
387c2aa98e2SPeter Wemm     /*	nul soh stx etx eot enq ack bel  bs  ht  nl  vt  np  cr  so  si   */
388c2aa98e2SPeter Wemm 	ILL,ILL,ILL,ILL,ILL,ILL,ILL,ILL, ILL,ILL,ILL,ILL,ILL,ILL,ILL,ILL,
389c2aa98e2SPeter Wemm     /*	dle dc1 dc2 dc3 dc4 nak syn etb  can em  sub esc fs  gs  rs  us   */
390c2aa98e2SPeter Wemm 	ILL,ILL,ILL,ILL,ILL,ILL,ILL,ILL, ILL,ILL,ILL,ILL,ILL,ILL,ILL,ILL,
391c2aa98e2SPeter Wemm     /*  sp  !   "   #   $   %   &   '    (   )   *   +   ,   -   .   /    */
392c2aa98e2SPeter Wemm 	ILL,ILL,ILL,ILL,ILL,ILL,ILL,ILL, ILL,ILL,ILL,ILL,ILL,ILL,ILL,ILL,
393c2aa98e2SPeter Wemm     /*	0   1   2   3   4   5   6   7    8   9   :   ;   <   =   >   ?    */
394c2aa98e2SPeter Wemm 	ILL,ILL,ILL,ILL,ILL,ILL,ILL,ILL, ILL,ILL,ILL,ILL,ILL,ILL,ILL,ILL,
395c2aa98e2SPeter Wemm     /*	@   A   B   C   D   E   F   G    H   I   J   K   L   M   N   O    */
396c2aa98e2SPeter Wemm 	ILL,ILL,ILL,ILL,ILL,ILL,ILL,ILL, ILL,ILL,ILL,ILL,ILL,ILL,ILL,ILL,
397c2aa98e2SPeter Wemm     /*  P   Q   R   S   T   U   V   W    X   Y   Z   [   \   ]   ^   _    */
398c2aa98e2SPeter Wemm 	ILL,ILL,ILL,ILL,ILL,ILL,ILL,ILL, ILL,ILL,ILL,ILL,ILL,ILL,ILL,ILL,
399c2aa98e2SPeter Wemm     /*	`   a   b   c   d   e   f   g    h   i   j   k   l   m   n   o    */
400c2aa98e2SPeter Wemm 	ILL,ILL,ILL,ILL,ILL,ILL,ILL,ILL, ILL,ILL,ILL,ILL,ILL,ILL,ILL,ILL,
401c2aa98e2SPeter Wemm     /*  p   q   r   s   t   u   v   w    x   y   z   {   |   }   ~   del  */
402c2aa98e2SPeter Wemm 	ILL,ILL,ILL,ILL,ILL,ILL,ILL,ILL, ILL,ILL,ILL,ILL,ILL,ILL,ILL,ILL,
403c2aa98e2SPeter Wemm };
404c2aa98e2SPeter Wemm 
405c2aa98e2SPeter Wemm 
406c2aa98e2SPeter Wemm # define NOCHAR		-1	/* signal nothing in lookahead token */
407c2aa98e2SPeter Wemm 
408c2aa98e2SPeter Wemm char **
409c2aa98e2SPeter Wemm prescan(addr, delim, pvpbuf, pvpbsize, delimptr, toktab)
410c2aa98e2SPeter Wemm 	char *addr;
411c2aa98e2SPeter Wemm 	int delim;
412c2aa98e2SPeter Wemm 	char pvpbuf[];
413c2aa98e2SPeter Wemm 	int pvpbsize;
414c2aa98e2SPeter Wemm 	char **delimptr;
415c2aa98e2SPeter Wemm 	u_char *toktab;
416c2aa98e2SPeter Wemm {
417c2aa98e2SPeter Wemm 	register char *p;
418c2aa98e2SPeter Wemm 	register char *q;
419c2aa98e2SPeter Wemm 	register int c;
420c2aa98e2SPeter Wemm 	char **avp;
421c2aa98e2SPeter Wemm 	bool bslashmode;
422c2aa98e2SPeter Wemm 	bool route_syntax;
423c2aa98e2SPeter Wemm 	int cmntcnt;
424c2aa98e2SPeter Wemm 	int anglecnt;
425c2aa98e2SPeter Wemm 	char *tok;
426c2aa98e2SPeter Wemm 	int state;
427c2aa98e2SPeter Wemm 	int newstate;
428c2aa98e2SPeter Wemm 	char *saveto = CurEnv->e_to;
429c2aa98e2SPeter Wemm 	static char *av[MAXATOM+1];
430c2aa98e2SPeter Wemm 	static char firsttime = TRUE;
431c2aa98e2SPeter Wemm 	extern int errno;
432c2aa98e2SPeter Wemm 
433c2aa98e2SPeter Wemm 	if (firsttime)
434c2aa98e2SPeter Wemm 	{
435c2aa98e2SPeter Wemm 		/* initialize the token type table */
436c2aa98e2SPeter Wemm 		char obuf[50];
437c2aa98e2SPeter Wemm 
438c2aa98e2SPeter Wemm 		firsttime = FALSE;
439c2aa98e2SPeter Wemm 		if (OperatorChars == NULL)
440c2aa98e2SPeter Wemm 		{
441c2aa98e2SPeter Wemm 			if (ConfigLevel < 7)
442c2aa98e2SPeter Wemm 				OperatorChars = macvalue('o', CurEnv);
443c2aa98e2SPeter Wemm 			if (OperatorChars == NULL)
444c2aa98e2SPeter Wemm 				OperatorChars = ".:@[]";
445c2aa98e2SPeter Wemm 		}
446c2aa98e2SPeter Wemm 		expand(OperatorChars, obuf, sizeof obuf - sizeof DELIMCHARS, CurEnv);
447c2aa98e2SPeter Wemm 		strcat(obuf, DELIMCHARS);
448c2aa98e2SPeter Wemm 		for (p = obuf; *p != '\0'; p++)
449c2aa98e2SPeter Wemm 		{
450c2aa98e2SPeter Wemm 			if (TokTypeTab[*p & 0xff] == ATM)
451c2aa98e2SPeter Wemm 				TokTypeTab[*p & 0xff] = OPR;
452c2aa98e2SPeter Wemm 		}
453c2aa98e2SPeter Wemm 	}
454c2aa98e2SPeter Wemm 	if (toktab == NULL)
455c2aa98e2SPeter Wemm 		toktab = TokTypeTab;
456c2aa98e2SPeter Wemm 
457c2aa98e2SPeter Wemm 	/* make sure error messages don't have garbage on them */
458c2aa98e2SPeter Wemm 	errno = 0;
459c2aa98e2SPeter Wemm 
460c2aa98e2SPeter Wemm 	q = pvpbuf;
461c2aa98e2SPeter Wemm 	bslashmode = FALSE;
462c2aa98e2SPeter Wemm 	route_syntax = FALSE;
463c2aa98e2SPeter Wemm 	cmntcnt = 0;
464c2aa98e2SPeter Wemm 	anglecnt = 0;
465c2aa98e2SPeter Wemm 	avp = av;
466c2aa98e2SPeter Wemm 	state = ATM;
467c2aa98e2SPeter Wemm 	c = NOCHAR;
468c2aa98e2SPeter Wemm 	p = addr;
469c2aa98e2SPeter Wemm 	CurEnv->e_to = p;
470c2aa98e2SPeter Wemm 	if (tTd(22, 11))
471c2aa98e2SPeter Wemm 	{
472c2aa98e2SPeter Wemm 		printf("prescan: ");
473c2aa98e2SPeter Wemm 		xputs(p);
474c2aa98e2SPeter Wemm 		(void) putchar('\n');
475c2aa98e2SPeter Wemm 	}
476c2aa98e2SPeter Wemm 
477c2aa98e2SPeter Wemm 	do
478c2aa98e2SPeter Wemm 	{
479c2aa98e2SPeter Wemm 		/* read a token */
480c2aa98e2SPeter Wemm 		tok = q;
481c2aa98e2SPeter Wemm 		for (;;)
482c2aa98e2SPeter Wemm 		{
483c2aa98e2SPeter Wemm 			/* store away any old lookahead character */
484c2aa98e2SPeter Wemm 			if (c != NOCHAR && !bslashmode)
485c2aa98e2SPeter Wemm 			{
486c2aa98e2SPeter Wemm 				/* see if there is room */
487c2aa98e2SPeter Wemm 				if (q >= &pvpbuf[pvpbsize - 5])
488c2aa98e2SPeter Wemm 				{
489c2aa98e2SPeter Wemm 					usrerr("553 Address too long");
490c2aa98e2SPeter Wemm 					if (strlen(addr) > (SIZE_T) MAXNAME)
491c2aa98e2SPeter Wemm 						addr[MAXNAME] = '\0';
492c2aa98e2SPeter Wemm 	returnnull:
493c2aa98e2SPeter Wemm 					if (delimptr != NULL)
494c2aa98e2SPeter Wemm 						*delimptr = p;
495c2aa98e2SPeter Wemm 					CurEnv->e_to = saveto;
496c2aa98e2SPeter Wemm 					return (NULL);
497c2aa98e2SPeter Wemm 				}
498c2aa98e2SPeter Wemm 
499c2aa98e2SPeter Wemm 				/* squirrel it away */
500c2aa98e2SPeter Wemm 				*q++ = c;
501c2aa98e2SPeter Wemm 			}
502c2aa98e2SPeter Wemm 
503c2aa98e2SPeter Wemm 			/* read a new input character */
504c2aa98e2SPeter Wemm 			c = *p++;
505c2aa98e2SPeter Wemm 			if (c == '\0')
506c2aa98e2SPeter Wemm 			{
507c2aa98e2SPeter Wemm 				/* diagnose and patch up bad syntax */
508c2aa98e2SPeter Wemm 				if (state == QST)
509c2aa98e2SPeter Wemm 				{
510c2aa98e2SPeter Wemm 					usrerr("653 Unbalanced '\"'");
511c2aa98e2SPeter Wemm 					c = '"';
512c2aa98e2SPeter Wemm 				}
513c2aa98e2SPeter Wemm 				else if (cmntcnt > 0)
514c2aa98e2SPeter Wemm 				{
515c2aa98e2SPeter Wemm 					usrerr("653 Unbalanced '('");
516c2aa98e2SPeter Wemm 					c = ')';
517c2aa98e2SPeter Wemm 				}
518c2aa98e2SPeter Wemm 				else if (anglecnt > 0)
519c2aa98e2SPeter Wemm 				{
520c2aa98e2SPeter Wemm 					c = '>';
521c2aa98e2SPeter Wemm 					usrerr("653 Unbalanced '<'");
522c2aa98e2SPeter Wemm 				}
523c2aa98e2SPeter Wemm 				else
524c2aa98e2SPeter Wemm 					break;
525c2aa98e2SPeter Wemm 
526c2aa98e2SPeter Wemm 				p--;
527c2aa98e2SPeter Wemm 			}
528c2aa98e2SPeter Wemm 			else if (c == delim && cmntcnt <= 0 && state != QST)
529c2aa98e2SPeter Wemm 			{
530c2aa98e2SPeter Wemm 				if (anglecnt <= 0)
531c2aa98e2SPeter Wemm 					break;
532c2aa98e2SPeter Wemm 
533c2aa98e2SPeter Wemm 				/* special case for better error management */
534c2aa98e2SPeter Wemm 				if (delim == ',' && !route_syntax)
535c2aa98e2SPeter Wemm 				{
536c2aa98e2SPeter Wemm 					usrerr("653 Unbalanced '<'");
537c2aa98e2SPeter Wemm 					c = '>';
538c2aa98e2SPeter Wemm 					p--;
539c2aa98e2SPeter Wemm 				}
540c2aa98e2SPeter Wemm 			}
541c2aa98e2SPeter Wemm 
542c2aa98e2SPeter Wemm 			if (tTd(22, 101))
543c2aa98e2SPeter Wemm 				printf("c=%c, s=%d; ", c, state);
544c2aa98e2SPeter Wemm 
545c2aa98e2SPeter Wemm 			/* chew up special characters */
546c2aa98e2SPeter Wemm 			*q = '\0';
547c2aa98e2SPeter Wemm 			if (bslashmode)
548c2aa98e2SPeter Wemm 			{
549c2aa98e2SPeter Wemm 				bslashmode = FALSE;
550c2aa98e2SPeter Wemm 
551c2aa98e2SPeter Wemm 				/* kludge \! for naive users */
552c2aa98e2SPeter Wemm 				if (cmntcnt > 0)
553c2aa98e2SPeter Wemm 				{
554c2aa98e2SPeter Wemm 					c = NOCHAR;
555c2aa98e2SPeter Wemm 					continue;
556c2aa98e2SPeter Wemm 				}
557c2aa98e2SPeter Wemm 				else if (c != '!' || state == QST)
558c2aa98e2SPeter Wemm 				{
559c2aa98e2SPeter Wemm 					*q++ = '\\';
560c2aa98e2SPeter Wemm 					continue;
561c2aa98e2SPeter Wemm 				}
562c2aa98e2SPeter Wemm 			}
563c2aa98e2SPeter Wemm 
564c2aa98e2SPeter Wemm 			if (c == '\\')
565c2aa98e2SPeter Wemm 			{
566c2aa98e2SPeter Wemm 				bslashmode = TRUE;
567c2aa98e2SPeter Wemm 			}
568c2aa98e2SPeter Wemm 			else if (state == QST)
569c2aa98e2SPeter Wemm 			{
570c2aa98e2SPeter Wemm 				/* do nothing, just avoid next clauses */
571c2aa98e2SPeter Wemm 			}
572c2aa98e2SPeter Wemm 			else if (c == '(')
573c2aa98e2SPeter Wemm 			{
574c2aa98e2SPeter Wemm 				cmntcnt++;
575c2aa98e2SPeter Wemm 				c = NOCHAR;
576c2aa98e2SPeter Wemm 			}
577c2aa98e2SPeter Wemm 			else if (c == ')')
578c2aa98e2SPeter Wemm 			{
579c2aa98e2SPeter Wemm 				if (cmntcnt <= 0)
580c2aa98e2SPeter Wemm 				{
581c2aa98e2SPeter Wemm 					usrerr("653 Unbalanced ')'");
582c2aa98e2SPeter Wemm 					c = NOCHAR;
583c2aa98e2SPeter Wemm 				}
584c2aa98e2SPeter Wemm 				else
585c2aa98e2SPeter Wemm 					cmntcnt--;
586c2aa98e2SPeter Wemm 			}
587c2aa98e2SPeter Wemm 			else if (cmntcnt > 0)
588c2aa98e2SPeter Wemm 				c = NOCHAR;
589c2aa98e2SPeter Wemm 			else if (c == '<')
590c2aa98e2SPeter Wemm 			{
591c2aa98e2SPeter Wemm 				char *q = p;
592c2aa98e2SPeter Wemm 
593c2aa98e2SPeter Wemm 				anglecnt++;
594c2aa98e2SPeter Wemm 				while (isascii(*q) && isspace(*q))
595c2aa98e2SPeter Wemm 					q++;
596c2aa98e2SPeter Wemm 				if (*q == '@')
597c2aa98e2SPeter Wemm 					route_syntax = TRUE;
598c2aa98e2SPeter Wemm 			}
599c2aa98e2SPeter Wemm 			else if (c == '>')
600c2aa98e2SPeter Wemm 			{
601c2aa98e2SPeter Wemm 				if (anglecnt <= 0)
602c2aa98e2SPeter Wemm 				{
603c2aa98e2SPeter Wemm 					usrerr("653 Unbalanced '>'");
604c2aa98e2SPeter Wemm 					c = NOCHAR;
605c2aa98e2SPeter Wemm 				}
606c2aa98e2SPeter Wemm 				else
607c2aa98e2SPeter Wemm 					anglecnt--;
608c2aa98e2SPeter Wemm 				route_syntax = FALSE;
609c2aa98e2SPeter Wemm 			}
610c2aa98e2SPeter Wemm 			else if (delim == ' ' && isascii(c) && isspace(c))
611c2aa98e2SPeter Wemm 				c = ' ';
612c2aa98e2SPeter Wemm 
613c2aa98e2SPeter Wemm 			if (c == NOCHAR)
614c2aa98e2SPeter Wemm 				continue;
615c2aa98e2SPeter Wemm 
616c2aa98e2SPeter Wemm 			/* see if this is end of input */
617c2aa98e2SPeter Wemm 			if (c == delim && anglecnt <= 0 && state != QST)
618c2aa98e2SPeter Wemm 				break;
619c2aa98e2SPeter Wemm 
620c2aa98e2SPeter Wemm 			newstate = StateTab[state][toktab[c & 0xff]];
621c2aa98e2SPeter Wemm 			if (tTd(22, 101))
622c2aa98e2SPeter Wemm 				printf("ns=%02o\n", newstate);
623c2aa98e2SPeter Wemm 			state = newstate & TYPE;
624c2aa98e2SPeter Wemm 			if (state == ILL)
625c2aa98e2SPeter Wemm 			{
626c2aa98e2SPeter Wemm 				if (isascii(c) && isprint(c))
627c2aa98e2SPeter Wemm 					usrerr("653 Illegal character %c", c);
628c2aa98e2SPeter Wemm 				else
629c2aa98e2SPeter Wemm 					usrerr("653 Illegal character 0x%02x", c);
630c2aa98e2SPeter Wemm 			}
631c2aa98e2SPeter Wemm 			if (bitset(M, newstate))
632c2aa98e2SPeter Wemm 				c = NOCHAR;
633c2aa98e2SPeter Wemm 			if (bitset(B, newstate))
634c2aa98e2SPeter Wemm 				break;
635c2aa98e2SPeter Wemm 		}
636c2aa98e2SPeter Wemm 
637c2aa98e2SPeter Wemm 		/* new token */
638c2aa98e2SPeter Wemm 		if (tok != q)
639c2aa98e2SPeter Wemm 		{
640c2aa98e2SPeter Wemm 			*q++ = '\0';
641c2aa98e2SPeter Wemm 			if (tTd(22, 36))
642c2aa98e2SPeter Wemm 			{
643c2aa98e2SPeter Wemm 				printf("tok=");
644c2aa98e2SPeter Wemm 				xputs(tok);
645c2aa98e2SPeter Wemm 				(void) putchar('\n');
646c2aa98e2SPeter Wemm 			}
647c2aa98e2SPeter Wemm 			if (avp >= &av[MAXATOM])
648c2aa98e2SPeter Wemm 			{
649c2aa98e2SPeter Wemm 				usrerr("553 prescan: too many tokens");
650c2aa98e2SPeter Wemm 				goto returnnull;
651c2aa98e2SPeter Wemm 			}
652c2aa98e2SPeter Wemm 			if (q - tok > MAXNAME)
653c2aa98e2SPeter Wemm 			{
654c2aa98e2SPeter Wemm 				usrerr("553 prescan: token too long");
655c2aa98e2SPeter Wemm 				goto returnnull;
656c2aa98e2SPeter Wemm 			}
657c2aa98e2SPeter Wemm 			*avp++ = tok;
658c2aa98e2SPeter Wemm 		}
659c2aa98e2SPeter Wemm 	} while (c != '\0' && (c != delim || anglecnt > 0));
660c2aa98e2SPeter Wemm 	*avp = NULL;
661c2aa98e2SPeter Wemm 	p--;
662c2aa98e2SPeter Wemm 	if (delimptr != NULL)
663c2aa98e2SPeter Wemm 		*delimptr = p;
664c2aa98e2SPeter Wemm 	if (tTd(22, 12))
665c2aa98e2SPeter Wemm 	{
666c2aa98e2SPeter Wemm 		printf("prescan==>");
667c2aa98e2SPeter Wemm 		printav(av);
668c2aa98e2SPeter Wemm 	}
669c2aa98e2SPeter Wemm 	CurEnv->e_to = saveto;
670c2aa98e2SPeter Wemm 	if (av[0] == NULL)
671c2aa98e2SPeter Wemm 	{
672c2aa98e2SPeter Wemm 		if (tTd(22, 1))
673c2aa98e2SPeter Wemm 			printf("prescan: null leading token\n");
674c2aa98e2SPeter Wemm 		return (NULL);
675c2aa98e2SPeter Wemm 	}
676c2aa98e2SPeter Wemm 	return (av);
677c2aa98e2SPeter Wemm }
678c2aa98e2SPeter Wemm /*
679c2aa98e2SPeter Wemm **  REWRITE -- apply rewrite rules to token vector.
680c2aa98e2SPeter Wemm **
681c2aa98e2SPeter Wemm **	This routine is an ordered production system.  Each rewrite
682c2aa98e2SPeter Wemm **	rule has a LHS (called the pattern) and a RHS (called the
683c2aa98e2SPeter Wemm **	rewrite); 'rwr' points the the current rewrite rule.
684c2aa98e2SPeter Wemm **
685c2aa98e2SPeter Wemm **	For each rewrite rule, 'avp' points the address vector we
686c2aa98e2SPeter Wemm **	are trying to match against, and 'pvp' points to the pattern.
687c2aa98e2SPeter Wemm **	If pvp points to a special match value (MATCHZANY, MATCHANY,
688c2aa98e2SPeter Wemm **	MATCHONE, MATCHCLASS, MATCHNCLASS) then the address in avp
689c2aa98e2SPeter Wemm **	matched is saved away in the match vector (pointed to by 'mvp').
690c2aa98e2SPeter Wemm **
691c2aa98e2SPeter Wemm **	When a match between avp & pvp does not match, we try to
692c2aa98e2SPeter Wemm **	back out.  If we back up over MATCHONE, MATCHCLASS, or MATCHNCLASS
693c2aa98e2SPeter Wemm **	we must also back out the match in mvp.  If we reach a
694c2aa98e2SPeter Wemm **	MATCHANY or MATCHZANY we just extend the match and start
695c2aa98e2SPeter Wemm **	over again.
696c2aa98e2SPeter Wemm **
697c2aa98e2SPeter Wemm **	When we finally match, we rewrite the address vector
698c2aa98e2SPeter Wemm **	and try over again.
699c2aa98e2SPeter Wemm **
700c2aa98e2SPeter Wemm **	Parameters:
701c2aa98e2SPeter Wemm **		pvp -- pointer to token vector.
702c2aa98e2SPeter Wemm **		ruleset -- the ruleset to use for rewriting.
703c2aa98e2SPeter Wemm **		reclevel -- recursion level (to catch loops).
704c2aa98e2SPeter Wemm **		e -- the current envelope.
705c2aa98e2SPeter Wemm **
706c2aa98e2SPeter Wemm **	Returns:
707c2aa98e2SPeter Wemm **		A status code.  If EX_TEMPFAIL, higher level code should
708c2aa98e2SPeter Wemm **			attempt recovery.
709c2aa98e2SPeter Wemm **
710c2aa98e2SPeter Wemm **	Side Effects:
711c2aa98e2SPeter Wemm **		pvp is modified.
712c2aa98e2SPeter Wemm */
713c2aa98e2SPeter Wemm 
714c2aa98e2SPeter Wemm struct match
715c2aa98e2SPeter Wemm {
716c2aa98e2SPeter Wemm 	char	**first;	/* first token matched */
717c2aa98e2SPeter Wemm 	char	**last;		/* last token matched */
718c2aa98e2SPeter Wemm 	char	**pattern;	/* pointer to pattern */
719c2aa98e2SPeter Wemm };
720c2aa98e2SPeter Wemm 
721c2aa98e2SPeter Wemm # define MAXMATCH	9	/* max params per rewrite */
722c2aa98e2SPeter Wemm 
723c2aa98e2SPeter Wemm 
724c2aa98e2SPeter Wemm int
725c2aa98e2SPeter Wemm rewrite(pvp, ruleset, reclevel, e)
726c2aa98e2SPeter Wemm 	char **pvp;
727c2aa98e2SPeter Wemm 	int ruleset;
728c2aa98e2SPeter Wemm 	int reclevel;
729c2aa98e2SPeter Wemm 	register ENVELOPE *e;
730c2aa98e2SPeter Wemm {
731c2aa98e2SPeter Wemm 	register char *ap;		/* address pointer */
732c2aa98e2SPeter Wemm 	register char *rp;		/* rewrite pointer */
733c2aa98e2SPeter Wemm 	register char **avp;		/* address vector pointer */
734c2aa98e2SPeter Wemm 	register char **rvp;		/* rewrite vector pointer */
735c2aa98e2SPeter Wemm 	register struct match *mlp;	/* cur ptr into mlist */
736c2aa98e2SPeter Wemm 	register struct rewrite *rwr;	/* pointer to current rewrite rule */
737c2aa98e2SPeter Wemm 	int ruleno;			/* current rule number */
738c2aa98e2SPeter Wemm 	int rstat = EX_OK;		/* return status */
739c2aa98e2SPeter Wemm 	int loopcount;
740c2aa98e2SPeter Wemm 	struct match mlist[MAXMATCH];	/* stores match on LHS */
741c2aa98e2SPeter Wemm 	char *npvp[MAXATOM+1];		/* temporary space for rebuild */
742c2aa98e2SPeter Wemm 	char buf[MAXLINE];
743c2aa98e2SPeter Wemm 	extern int callsubr __P((char**, int, ENVELOPE *));
744c2aa98e2SPeter Wemm 	extern int sm_strcasecmp __P((char *, char *));
745c2aa98e2SPeter Wemm 
746c2aa98e2SPeter Wemm 	if (OpMode == MD_TEST || tTd(21, 1))
747c2aa98e2SPeter Wemm 	{
748c2aa98e2SPeter Wemm 		printf("rewrite: ruleset %3d   input:", ruleset);
749c2aa98e2SPeter Wemm 		printav(pvp);
750c2aa98e2SPeter Wemm 	}
751c2aa98e2SPeter Wemm 	if (ruleset < 0 || ruleset >= MAXRWSETS)
752c2aa98e2SPeter Wemm 	{
753c2aa98e2SPeter Wemm 		syserr("554 rewrite: illegal ruleset number %d", ruleset);
754c2aa98e2SPeter Wemm 		return EX_CONFIG;
755c2aa98e2SPeter Wemm 	}
756c2aa98e2SPeter Wemm 	if (reclevel++ > MaxRuleRecursion)
757c2aa98e2SPeter Wemm 	{
758c2aa98e2SPeter Wemm 		syserr("rewrite: excessive recursion (max %d), ruleset %d",
759c2aa98e2SPeter Wemm 			MaxRuleRecursion, ruleset);
760c2aa98e2SPeter Wemm 		return EX_CONFIG;
761c2aa98e2SPeter Wemm 	}
762c2aa98e2SPeter Wemm 	if (pvp == NULL)
763c2aa98e2SPeter Wemm 		return EX_USAGE;
764c2aa98e2SPeter Wemm 
765c2aa98e2SPeter Wemm 	/*
766c2aa98e2SPeter Wemm 	**  Run through the list of rewrite rules, applying
767c2aa98e2SPeter Wemm 	**	any that match.
768c2aa98e2SPeter Wemm 	*/
769c2aa98e2SPeter Wemm 
770c2aa98e2SPeter Wemm 	ruleno = 1;
771c2aa98e2SPeter Wemm 	loopcount = 0;
772c2aa98e2SPeter Wemm 	for (rwr = RewriteRules[ruleset]; rwr != NULL; )
773c2aa98e2SPeter Wemm 	{
774c2aa98e2SPeter Wemm 		int stat;
775c2aa98e2SPeter Wemm 
776c2aa98e2SPeter Wemm 		/* if already canonical, quit now */
777c2aa98e2SPeter Wemm 		if (pvp[0] != NULL && (pvp[0][0] & 0377) == CANONNET)
778c2aa98e2SPeter Wemm 			break;
779c2aa98e2SPeter Wemm 
780c2aa98e2SPeter Wemm 		if (tTd(21, 12))
781c2aa98e2SPeter Wemm 		{
782c2aa98e2SPeter Wemm 			printf("-----trying rule:");
783c2aa98e2SPeter Wemm 			printav(rwr->r_lhs);
784c2aa98e2SPeter Wemm 		}
785c2aa98e2SPeter Wemm 
786c2aa98e2SPeter Wemm 		/* try to match on this rule */
787c2aa98e2SPeter Wemm 		mlp = mlist;
788c2aa98e2SPeter Wemm 		rvp = rwr->r_lhs;
789c2aa98e2SPeter Wemm 		avp = pvp;
790c2aa98e2SPeter Wemm 		if (++loopcount > 100)
791c2aa98e2SPeter Wemm 		{
792c2aa98e2SPeter Wemm 			syserr("554 Infinite loop in ruleset %d, rule %d",
793c2aa98e2SPeter Wemm 				ruleset, ruleno);
794c2aa98e2SPeter Wemm 			if (tTd(21, 1))
795c2aa98e2SPeter Wemm 			{
796c2aa98e2SPeter Wemm 				printf("workspace: ");
797c2aa98e2SPeter Wemm 				printav(pvp);
798c2aa98e2SPeter Wemm 			}
799c2aa98e2SPeter Wemm 			break;
800c2aa98e2SPeter Wemm 		}
801c2aa98e2SPeter Wemm 
802c2aa98e2SPeter Wemm 		while ((ap = *avp) != NULL || *rvp != NULL)
803c2aa98e2SPeter Wemm 		{
804c2aa98e2SPeter Wemm 			rp = *rvp;
805c2aa98e2SPeter Wemm 			if (tTd(21, 35))
806c2aa98e2SPeter Wemm 			{
807c2aa98e2SPeter Wemm 				printf("ADVANCE rp=");
808c2aa98e2SPeter Wemm 				xputs(rp);
809c2aa98e2SPeter Wemm 				printf(", ap=");
810c2aa98e2SPeter Wemm 				xputs(ap);
811c2aa98e2SPeter Wemm 				printf("\n");
812c2aa98e2SPeter Wemm 			}
813c2aa98e2SPeter Wemm 			if (rp == NULL)
814c2aa98e2SPeter Wemm 			{
815c2aa98e2SPeter Wemm 				/* end-of-pattern before end-of-address */
816c2aa98e2SPeter Wemm 				goto backup;
817c2aa98e2SPeter Wemm 			}
818c2aa98e2SPeter Wemm 			if (ap == NULL && (*rp & 0377) != MATCHZANY &&
819c2aa98e2SPeter Wemm 			    (*rp & 0377) != MATCHZERO)
820c2aa98e2SPeter Wemm 			{
821c2aa98e2SPeter Wemm 				/* end-of-input with patterns left */
822c2aa98e2SPeter Wemm 				goto backup;
823c2aa98e2SPeter Wemm 			}
824c2aa98e2SPeter Wemm 
825c2aa98e2SPeter Wemm 			switch (*rp & 0377)
826c2aa98e2SPeter Wemm 			{
827c2aa98e2SPeter Wemm 			  case MATCHCLASS:
828c2aa98e2SPeter Wemm 				/* match any phrase in a class */
829c2aa98e2SPeter Wemm 				mlp->pattern = rvp;
830c2aa98e2SPeter Wemm 				mlp->first = avp;
831c2aa98e2SPeter Wemm 	extendclass:
832c2aa98e2SPeter Wemm 				ap = *avp;
833c2aa98e2SPeter Wemm 				if (ap == NULL)
834c2aa98e2SPeter Wemm 					goto backup;
835c2aa98e2SPeter Wemm 				mlp->last = avp++;
836c2aa98e2SPeter Wemm 				cataddr(mlp->first, mlp->last, buf, sizeof buf, '\0');
837c2aa98e2SPeter Wemm 				if (!wordinclass(buf, rp[1]))
838c2aa98e2SPeter Wemm 				{
839c2aa98e2SPeter Wemm 					if (tTd(21, 36))
840c2aa98e2SPeter Wemm 					{
841c2aa98e2SPeter Wemm 						printf("EXTEND  rp=");
842c2aa98e2SPeter Wemm 						xputs(rp);
843c2aa98e2SPeter Wemm 						printf(", ap=");
844c2aa98e2SPeter Wemm 						xputs(ap);
845c2aa98e2SPeter Wemm 						printf("\n");
846c2aa98e2SPeter Wemm 					}
847c2aa98e2SPeter Wemm 					goto extendclass;
848c2aa98e2SPeter Wemm 				}
849c2aa98e2SPeter Wemm 				if (tTd(21, 36))
850c2aa98e2SPeter Wemm 					printf("CLMATCH\n");
851c2aa98e2SPeter Wemm 				mlp++;
852c2aa98e2SPeter Wemm 				break;
853c2aa98e2SPeter Wemm 
854c2aa98e2SPeter Wemm 			  case MATCHNCLASS:
855c2aa98e2SPeter Wemm 				/* match any token not in a class */
856c2aa98e2SPeter Wemm 				if (wordinclass(ap, rp[1]))
857c2aa98e2SPeter Wemm 					goto backup;
858c2aa98e2SPeter Wemm 
859c2aa98e2SPeter Wemm 				/* fall through */
860c2aa98e2SPeter Wemm 
861c2aa98e2SPeter Wemm 			  case MATCHONE:
862c2aa98e2SPeter Wemm 			  case MATCHANY:
863c2aa98e2SPeter Wemm 				/* match exactly one token */
864c2aa98e2SPeter Wemm 				mlp->pattern = rvp;
865c2aa98e2SPeter Wemm 				mlp->first = avp;
866c2aa98e2SPeter Wemm 				mlp->last = avp++;
867c2aa98e2SPeter Wemm 				mlp++;
868c2aa98e2SPeter Wemm 				break;
869c2aa98e2SPeter Wemm 
870c2aa98e2SPeter Wemm 			  case MATCHZANY:
871c2aa98e2SPeter Wemm 				/* match zero or more tokens */
872c2aa98e2SPeter Wemm 				mlp->pattern = rvp;
873c2aa98e2SPeter Wemm 				mlp->first = avp;
874c2aa98e2SPeter Wemm 				mlp->last = avp - 1;
875c2aa98e2SPeter Wemm 				mlp++;
876c2aa98e2SPeter Wemm 				break;
877c2aa98e2SPeter Wemm 
878c2aa98e2SPeter Wemm 			  case MATCHZERO:
879c2aa98e2SPeter Wemm 				/* match zero tokens */
880c2aa98e2SPeter Wemm 				break;
881c2aa98e2SPeter Wemm 
882c2aa98e2SPeter Wemm 			  case MACRODEXPAND:
883c2aa98e2SPeter Wemm 				/*
884c2aa98e2SPeter Wemm 				**  Match against run-time macro.
885c2aa98e2SPeter Wemm 				**  This algorithm is broken for the
886c2aa98e2SPeter Wemm 				**  general case (no recursive macros,
887c2aa98e2SPeter Wemm 				**  improper tokenization) but should
888c2aa98e2SPeter Wemm 				**  work for the usual cases.
889c2aa98e2SPeter Wemm 				*/
890c2aa98e2SPeter Wemm 
891c2aa98e2SPeter Wemm 				ap = macvalue(rp[1], e);
892c2aa98e2SPeter Wemm 				mlp->first = avp;
893c2aa98e2SPeter Wemm 				if (tTd(21, 2))
894c2aa98e2SPeter Wemm 					printf("rewrite: LHS $&%s => \"%s\"\n",
895c2aa98e2SPeter Wemm 						macname(rp[1]),
896c2aa98e2SPeter Wemm 						ap == NULL ? "(NULL)" : ap);
897c2aa98e2SPeter Wemm 
898c2aa98e2SPeter Wemm 				if (ap == NULL)
899c2aa98e2SPeter Wemm 					break;
900c2aa98e2SPeter Wemm 				while (*ap != '\0')
901c2aa98e2SPeter Wemm 				{
902c2aa98e2SPeter Wemm 					if (*avp == NULL ||
903c2aa98e2SPeter Wemm 					    strncasecmp(ap, *avp, strlen(*avp)) != 0)
904c2aa98e2SPeter Wemm 					{
905c2aa98e2SPeter Wemm 						/* no match */
906c2aa98e2SPeter Wemm 						avp = mlp->first;
907c2aa98e2SPeter Wemm 						goto backup;
908c2aa98e2SPeter Wemm 					}
909c2aa98e2SPeter Wemm 					ap += strlen(*avp++);
910c2aa98e2SPeter Wemm 				}
911c2aa98e2SPeter Wemm 
912c2aa98e2SPeter Wemm 				/* match */
913c2aa98e2SPeter Wemm 				break;
914c2aa98e2SPeter Wemm 
915c2aa98e2SPeter Wemm 			  default:
916c2aa98e2SPeter Wemm 				/* must have exact match */
917c2aa98e2SPeter Wemm 				if (sm_strcasecmp(rp, ap))
918c2aa98e2SPeter Wemm 					goto backup;
919c2aa98e2SPeter Wemm 				avp++;
920c2aa98e2SPeter Wemm 				break;
921c2aa98e2SPeter Wemm 			}
922c2aa98e2SPeter Wemm 
923c2aa98e2SPeter Wemm 			/* successful match on this token */
924c2aa98e2SPeter Wemm 			rvp++;
925c2aa98e2SPeter Wemm 			continue;
926c2aa98e2SPeter Wemm 
927c2aa98e2SPeter Wemm 	  backup:
928c2aa98e2SPeter Wemm 			/* match failed -- back up */
929c2aa98e2SPeter Wemm 			while (--mlp >= mlist)
930c2aa98e2SPeter Wemm 			{
931c2aa98e2SPeter Wemm 				rvp = mlp->pattern;
932c2aa98e2SPeter Wemm 				rp = *rvp;
933c2aa98e2SPeter Wemm 				avp = mlp->last + 1;
934c2aa98e2SPeter Wemm 				ap = *avp;
935c2aa98e2SPeter Wemm 
936c2aa98e2SPeter Wemm 				if (tTd(21, 36))
937c2aa98e2SPeter Wemm 				{
938c2aa98e2SPeter Wemm 					printf("BACKUP  rp=");
939c2aa98e2SPeter Wemm 					xputs(rp);
940c2aa98e2SPeter Wemm 					printf(", ap=");
941c2aa98e2SPeter Wemm 					xputs(ap);
942c2aa98e2SPeter Wemm 					printf("\n");
943c2aa98e2SPeter Wemm 				}
944c2aa98e2SPeter Wemm 
945c2aa98e2SPeter Wemm 				if (ap == NULL)
946c2aa98e2SPeter Wemm 				{
947c2aa98e2SPeter Wemm 					/* run off the end -- back up again */
948c2aa98e2SPeter Wemm 					continue;
949c2aa98e2SPeter Wemm 				}
950c2aa98e2SPeter Wemm 				if ((*rp & 0377) == MATCHANY ||
951c2aa98e2SPeter Wemm 				    (*rp & 0377) == MATCHZANY)
952c2aa98e2SPeter Wemm 				{
953c2aa98e2SPeter Wemm 					/* extend binding and continue */
954c2aa98e2SPeter Wemm 					mlp->last = avp++;
955c2aa98e2SPeter Wemm 					rvp++;
956c2aa98e2SPeter Wemm 					mlp++;
957c2aa98e2SPeter Wemm 					break;
958c2aa98e2SPeter Wemm 				}
959c2aa98e2SPeter Wemm 				if ((*rp & 0377) == MATCHCLASS)
960c2aa98e2SPeter Wemm 				{
961c2aa98e2SPeter Wemm 					/* extend binding and try again */
962c2aa98e2SPeter Wemm 					mlp->last = avp;
963c2aa98e2SPeter Wemm 					goto extendclass;
964c2aa98e2SPeter Wemm 				}
965c2aa98e2SPeter Wemm 			}
966c2aa98e2SPeter Wemm 
967c2aa98e2SPeter Wemm 			if (mlp < mlist)
968c2aa98e2SPeter Wemm 			{
969c2aa98e2SPeter Wemm 				/* total failure to match */
970c2aa98e2SPeter Wemm 				break;
971c2aa98e2SPeter Wemm 			}
972c2aa98e2SPeter Wemm 		}
973c2aa98e2SPeter Wemm 
974c2aa98e2SPeter Wemm 		/*
975c2aa98e2SPeter Wemm 		**  See if we successfully matched
976c2aa98e2SPeter Wemm 		*/
977c2aa98e2SPeter Wemm 
978c2aa98e2SPeter Wemm 		if (mlp < mlist || *rvp != NULL)
979c2aa98e2SPeter Wemm 		{
980c2aa98e2SPeter Wemm 			if (tTd(21, 10))
981c2aa98e2SPeter Wemm 				printf("----- rule fails\n");
982c2aa98e2SPeter Wemm 			rwr = rwr->r_next;
983c2aa98e2SPeter Wemm 			ruleno++;
984c2aa98e2SPeter Wemm 			loopcount = 0;
985c2aa98e2SPeter Wemm 			continue;
986c2aa98e2SPeter Wemm 		}
987c2aa98e2SPeter Wemm 
988c2aa98e2SPeter Wemm 		rvp = rwr->r_rhs;
989c2aa98e2SPeter Wemm 		if (tTd(21, 12))
990c2aa98e2SPeter Wemm 		{
991c2aa98e2SPeter Wemm 			printf("-----rule matches:");
992c2aa98e2SPeter Wemm 			printav(rvp);
993c2aa98e2SPeter Wemm 		}
994c2aa98e2SPeter Wemm 
995c2aa98e2SPeter Wemm 		rp = *rvp;
996c2aa98e2SPeter Wemm 		if ((*rp & 0377) == CANONUSER)
997c2aa98e2SPeter Wemm 		{
998c2aa98e2SPeter Wemm 			rvp++;
999c2aa98e2SPeter Wemm 			rwr = rwr->r_next;
1000c2aa98e2SPeter Wemm 			ruleno++;
1001c2aa98e2SPeter Wemm 			loopcount = 0;
1002c2aa98e2SPeter Wemm 		}
1003c2aa98e2SPeter Wemm 		else if ((*rp & 0377) == CANONHOST)
1004c2aa98e2SPeter Wemm 		{
1005c2aa98e2SPeter Wemm 			rvp++;
1006c2aa98e2SPeter Wemm 			rwr = NULL;
1007c2aa98e2SPeter Wemm 		}
1008c2aa98e2SPeter Wemm 
1009c2aa98e2SPeter Wemm 		/* substitute */
1010c2aa98e2SPeter Wemm 		for (avp = npvp; *rvp != NULL; rvp++)
1011c2aa98e2SPeter Wemm 		{
1012c2aa98e2SPeter Wemm 			register struct match *m;
1013c2aa98e2SPeter Wemm 			register char **pp;
1014c2aa98e2SPeter Wemm 
1015c2aa98e2SPeter Wemm 			rp = *rvp;
1016c2aa98e2SPeter Wemm 			if ((*rp & 0377) == MATCHREPL)
1017c2aa98e2SPeter Wemm 			{
1018c2aa98e2SPeter Wemm 				/* substitute from LHS */
1019c2aa98e2SPeter Wemm 				m = &mlist[rp[1] - '1'];
1020c2aa98e2SPeter Wemm 				if (m < mlist || m >= mlp)
1021c2aa98e2SPeter Wemm 				{
1022c2aa98e2SPeter Wemm 					syserr("554 rewrite: ruleset %d: replacement $%c out of bounds",
1023c2aa98e2SPeter Wemm 						ruleset, rp[1]);
1024c2aa98e2SPeter Wemm 					return EX_CONFIG;
1025c2aa98e2SPeter Wemm 				}
1026c2aa98e2SPeter Wemm 				if (tTd(21, 15))
1027c2aa98e2SPeter Wemm 				{
1028c2aa98e2SPeter Wemm 					printf("$%c:", rp[1]);
1029c2aa98e2SPeter Wemm 					pp = m->first;
1030c2aa98e2SPeter Wemm 					while (pp <= m->last)
1031c2aa98e2SPeter Wemm 					{
1032c2aa98e2SPeter Wemm 						printf(" %lx=\"", (u_long) *pp);
1033c2aa98e2SPeter Wemm 						(void) fflush(stdout);
1034c2aa98e2SPeter Wemm 						printf("%s\"", *pp++);
1035c2aa98e2SPeter Wemm 					}
1036c2aa98e2SPeter Wemm 					printf("\n");
1037c2aa98e2SPeter Wemm 				}
1038c2aa98e2SPeter Wemm 				pp = m->first;
1039c2aa98e2SPeter Wemm 				while (pp <= m->last)
1040c2aa98e2SPeter Wemm 				{
1041c2aa98e2SPeter Wemm 					if (avp >= &npvp[MAXATOM])
1042c2aa98e2SPeter Wemm 					{
1043c2aa98e2SPeter Wemm 						syserr("554 rewrite: expansion too long");
1044c2aa98e2SPeter Wemm 						return EX_DATAERR;
1045c2aa98e2SPeter Wemm 					}
1046c2aa98e2SPeter Wemm 					*avp++ = *pp++;
1047c2aa98e2SPeter Wemm 				}
1048c2aa98e2SPeter Wemm 			}
1049c2aa98e2SPeter Wemm 			else
1050c2aa98e2SPeter Wemm 			{
1051c2aa98e2SPeter Wemm 				/* some sort of replacement */
1052c2aa98e2SPeter Wemm 				if (avp >= &npvp[MAXATOM])
1053c2aa98e2SPeter Wemm 				{
1054c2aa98e2SPeter Wemm 	toolong:
1055c2aa98e2SPeter Wemm 					syserr("554 rewrite: expansion too long");
1056c2aa98e2SPeter Wemm 					return EX_DATAERR;
1057c2aa98e2SPeter Wemm 				}
1058c2aa98e2SPeter Wemm 				if ((*rp & 0377) != MACRODEXPAND)
1059c2aa98e2SPeter Wemm 				{
1060c2aa98e2SPeter Wemm 					/* vanilla replacement */
1061c2aa98e2SPeter Wemm 					*avp++ = rp;
1062c2aa98e2SPeter Wemm 				}
1063c2aa98e2SPeter Wemm 				else
1064c2aa98e2SPeter Wemm 				{
1065c2aa98e2SPeter Wemm 					/* $&x replacement */
1066c2aa98e2SPeter Wemm 					char *mval = macvalue(rp[1], e);
1067c2aa98e2SPeter Wemm 					char **xpvp;
1068c2aa98e2SPeter Wemm 					int trsize = 0;
1069c2aa98e2SPeter Wemm 					static size_t pvpb1_size = 0;
1070c2aa98e2SPeter Wemm 					static char **pvpb1 = NULL;
1071c2aa98e2SPeter Wemm 					char pvpbuf[PSBUFSIZE];
1072c2aa98e2SPeter Wemm 
1073c2aa98e2SPeter Wemm 					if (tTd(21, 2))
1074c2aa98e2SPeter Wemm 						printf("rewrite: RHS $&%s => \"%s\"\n",
1075c2aa98e2SPeter Wemm 							macname(rp[1]),
1076c2aa98e2SPeter Wemm 							mval == NULL ? "(NULL)" : mval);
1077c2aa98e2SPeter Wemm 					if (mval == NULL || *mval == '\0')
1078c2aa98e2SPeter Wemm 						continue;
1079c2aa98e2SPeter Wemm 
1080c2aa98e2SPeter Wemm 					/* save the remainder of the input */
1081c2aa98e2SPeter Wemm 					for (xpvp = pvp; *xpvp != NULL; xpvp++)
1082c2aa98e2SPeter Wemm 						trsize += sizeof *xpvp;
1083c2aa98e2SPeter Wemm 					if (trsize > pvpb1_size)
1084c2aa98e2SPeter Wemm 					{
1085c2aa98e2SPeter Wemm 						if (pvpb1 != NULL)
1086c2aa98e2SPeter Wemm 							free(pvpb1);
1087c2aa98e2SPeter Wemm 						pvpb1 = (char **)xalloc(trsize);
1088c2aa98e2SPeter Wemm 						pvpb1_size = trsize;
1089c2aa98e2SPeter Wemm 					}
1090c2aa98e2SPeter Wemm 
1091c2aa98e2SPeter Wemm 					bcopy((char *) pvp, (char *) pvpb1, trsize);
1092c2aa98e2SPeter Wemm 
1093c2aa98e2SPeter Wemm 					/* scan the new replacement */
1094c2aa98e2SPeter Wemm 					xpvp = prescan(mval, '\0', pvpbuf,
1095c2aa98e2SPeter Wemm 						       sizeof pvpbuf, NULL, NULL);
1096c2aa98e2SPeter Wemm 					if (xpvp == NULL)
1097c2aa98e2SPeter Wemm 					{
1098c2aa98e2SPeter Wemm 						/* prescan pre-printed error */
1099c2aa98e2SPeter Wemm 						return EX_DATAERR;
1100c2aa98e2SPeter Wemm 					}
1101c2aa98e2SPeter Wemm 
1102c2aa98e2SPeter Wemm 					/* insert it into the output stream */
1103c2aa98e2SPeter Wemm 					while (*xpvp != NULL)
1104c2aa98e2SPeter Wemm 					{
1105c2aa98e2SPeter Wemm 						if (tTd(21, 19))
1106c2aa98e2SPeter Wemm 							printf(" ... %s\n", *xpvp);
1107c2aa98e2SPeter Wemm 						*avp++ = newstr(*xpvp);
1108c2aa98e2SPeter Wemm 						if (avp >= &npvp[MAXATOM])
1109c2aa98e2SPeter Wemm 							goto toolong;
1110c2aa98e2SPeter Wemm 						xpvp++;
1111c2aa98e2SPeter Wemm 					}
1112c2aa98e2SPeter Wemm 					if (tTd(21, 19))
1113c2aa98e2SPeter Wemm 						printf(" ... DONE\n");
1114c2aa98e2SPeter Wemm 
1115c2aa98e2SPeter Wemm 					/* restore the old trailing input */
1116c2aa98e2SPeter Wemm 					bcopy((char *) pvpb1, (char *) pvp, trsize);
1117c2aa98e2SPeter Wemm 				}
1118c2aa98e2SPeter Wemm 			}
1119c2aa98e2SPeter Wemm 		}
1120c2aa98e2SPeter Wemm 		*avp++ = NULL;
1121c2aa98e2SPeter Wemm 
1122c2aa98e2SPeter Wemm 		/*
1123c2aa98e2SPeter Wemm 		**  Check for any hostname/keyword lookups.
1124c2aa98e2SPeter Wemm 		*/
1125c2aa98e2SPeter Wemm 
1126c2aa98e2SPeter Wemm 		for (rvp = npvp; *rvp != NULL; rvp++)
1127c2aa98e2SPeter Wemm 		{
1128c2aa98e2SPeter Wemm 			char **hbrvp;
1129c2aa98e2SPeter Wemm 			char **xpvp;
1130c2aa98e2SPeter Wemm 			int trsize;
1131c2aa98e2SPeter Wemm 			char *replac;
1132c2aa98e2SPeter Wemm 			int endtoken;
1133c2aa98e2SPeter Wemm 			STAB *map;
1134c2aa98e2SPeter Wemm 			char *mapname;
1135c2aa98e2SPeter Wemm 			char **key_rvp;
1136c2aa98e2SPeter Wemm 			char **arg_rvp;
1137c2aa98e2SPeter Wemm 			char **default_rvp;
1138c2aa98e2SPeter Wemm 			char buf[MAXNAME + 1];
1139c2aa98e2SPeter Wemm 			char *pvpb1[MAXATOM + 1];
1140c2aa98e2SPeter Wemm 			char *argvect[10];
1141c2aa98e2SPeter Wemm 			char pvpbuf[PSBUFSIZE];
1142c2aa98e2SPeter Wemm 			char *nullpvp[1];
1143c2aa98e2SPeter Wemm 			extern char *map_lookup __P((STAB *, char *, char **, int *, ENVELOPE *));
1144c2aa98e2SPeter Wemm 
1145c2aa98e2SPeter Wemm 			if ((**rvp & 0377) != HOSTBEGIN &&
1146c2aa98e2SPeter Wemm 			    (**rvp & 0377) != LOOKUPBEGIN)
1147c2aa98e2SPeter Wemm 				continue;
1148c2aa98e2SPeter Wemm 
1149c2aa98e2SPeter Wemm 			/*
1150c2aa98e2SPeter Wemm 			**  Got a hostname/keyword lookup.
1151c2aa98e2SPeter Wemm 			**
1152c2aa98e2SPeter Wemm 			**	This could be optimized fairly easily.
1153c2aa98e2SPeter Wemm 			*/
1154c2aa98e2SPeter Wemm 
1155c2aa98e2SPeter Wemm 			hbrvp = rvp;
1156c2aa98e2SPeter Wemm 			if ((**rvp & 0377) == HOSTBEGIN)
1157c2aa98e2SPeter Wemm 			{
1158c2aa98e2SPeter Wemm 				endtoken = HOSTEND;
1159c2aa98e2SPeter Wemm 				mapname = "host";
1160c2aa98e2SPeter Wemm 			}
1161c2aa98e2SPeter Wemm 			else
1162c2aa98e2SPeter Wemm 			{
1163c2aa98e2SPeter Wemm 				endtoken = LOOKUPEND;
1164c2aa98e2SPeter Wemm 				mapname = *++rvp;
1165c2aa98e2SPeter Wemm 			}
1166c2aa98e2SPeter Wemm 			map = stab(mapname, ST_MAP, ST_FIND);
1167c2aa98e2SPeter Wemm 			if (map == NULL)
1168c2aa98e2SPeter Wemm 				syserr("554 rewrite: map %s not found", mapname);
1169c2aa98e2SPeter Wemm 
1170c2aa98e2SPeter Wemm 			/* extract the match part */
1171c2aa98e2SPeter Wemm 			key_rvp = ++rvp;
1172c2aa98e2SPeter Wemm 			default_rvp = NULL;
1173c2aa98e2SPeter Wemm 			arg_rvp = argvect;
1174c2aa98e2SPeter Wemm 			xpvp = NULL;
1175c2aa98e2SPeter Wemm 			replac = pvpbuf;
1176c2aa98e2SPeter Wemm 			while (*rvp != NULL && (**rvp & 0377) != endtoken)
1177c2aa98e2SPeter Wemm 			{
1178c2aa98e2SPeter Wemm 				int nodetype = **rvp & 0377;
1179c2aa98e2SPeter Wemm 
1180c2aa98e2SPeter Wemm 				if (nodetype != CANONHOST && nodetype != CANONUSER)
1181c2aa98e2SPeter Wemm 				{
1182c2aa98e2SPeter Wemm 					rvp++;
1183c2aa98e2SPeter Wemm 					continue;
1184c2aa98e2SPeter Wemm 				}
1185c2aa98e2SPeter Wemm 
1186c2aa98e2SPeter Wemm 				*rvp++ = NULL;
1187c2aa98e2SPeter Wemm 
1188c2aa98e2SPeter Wemm 				if (xpvp != NULL)
1189c2aa98e2SPeter Wemm 				{
1190c2aa98e2SPeter Wemm 					cataddr(xpvp, NULL, replac,
1191c2aa98e2SPeter Wemm 						&pvpbuf[sizeof pvpbuf] - replac,
1192c2aa98e2SPeter Wemm 						'\0');
1193c2aa98e2SPeter Wemm 					*++arg_rvp = replac;
1194c2aa98e2SPeter Wemm 					replac += strlen(replac) + 1;
1195c2aa98e2SPeter Wemm 					xpvp = NULL;
1196c2aa98e2SPeter Wemm 				}
1197c2aa98e2SPeter Wemm 				switch (nodetype)
1198c2aa98e2SPeter Wemm 				{
1199c2aa98e2SPeter Wemm 				  case CANONHOST:
1200c2aa98e2SPeter Wemm 					xpvp = rvp;
1201c2aa98e2SPeter Wemm 					break;
1202c2aa98e2SPeter Wemm 
1203c2aa98e2SPeter Wemm 				  case CANONUSER:
1204c2aa98e2SPeter Wemm 					default_rvp = rvp;
1205c2aa98e2SPeter Wemm 					break;
1206c2aa98e2SPeter Wemm 				}
1207c2aa98e2SPeter Wemm 			}
1208c2aa98e2SPeter Wemm 			if (*rvp != NULL)
1209c2aa98e2SPeter Wemm 				*rvp++ = NULL;
1210c2aa98e2SPeter Wemm 			if (xpvp != NULL)
1211c2aa98e2SPeter Wemm 			{
1212c2aa98e2SPeter Wemm 				cataddr(xpvp, NULL, replac,
1213c2aa98e2SPeter Wemm 					&pvpbuf[sizeof pvpbuf] - replac,
1214c2aa98e2SPeter Wemm 					'\0');
1215c2aa98e2SPeter Wemm 				*++arg_rvp = replac;
1216c2aa98e2SPeter Wemm 			}
1217c2aa98e2SPeter Wemm 			*++arg_rvp = NULL;
1218c2aa98e2SPeter Wemm 
1219c2aa98e2SPeter Wemm 			/* save the remainder of the input string */
1220c2aa98e2SPeter Wemm 			trsize = (int) (avp - rvp + 1) * sizeof *rvp;
1221c2aa98e2SPeter Wemm 			bcopy((char *) rvp, (char *) pvpb1, trsize);
1222c2aa98e2SPeter Wemm 
1223c2aa98e2SPeter Wemm 			/* look it up */
1224c2aa98e2SPeter Wemm 			cataddr(key_rvp, NULL, buf, sizeof buf, '\0');
1225c2aa98e2SPeter Wemm 			argvect[0] = buf;
1226c2aa98e2SPeter Wemm 			replac = map_lookup(map, buf, argvect, &rstat, e);
1227c2aa98e2SPeter Wemm 
1228c2aa98e2SPeter Wemm 			/* if no replacement, use default */
1229c2aa98e2SPeter Wemm 			if (replac == NULL && default_rvp != NULL)
1230c2aa98e2SPeter Wemm 			{
1231c2aa98e2SPeter Wemm 				/* create the default */
1232c2aa98e2SPeter Wemm 				cataddr(default_rvp, NULL, buf, sizeof buf, '\0');
1233c2aa98e2SPeter Wemm 				replac = buf;
1234c2aa98e2SPeter Wemm 			}
1235c2aa98e2SPeter Wemm 
1236c2aa98e2SPeter Wemm 			if (replac == NULL)
1237c2aa98e2SPeter Wemm 			{
1238c2aa98e2SPeter Wemm 				xpvp = key_rvp;
1239c2aa98e2SPeter Wemm 			}
1240c2aa98e2SPeter Wemm 			else if (*replac == '\0')
1241c2aa98e2SPeter Wemm 			{
1242c2aa98e2SPeter Wemm 				/* null replacement */
1243c2aa98e2SPeter Wemm 				nullpvp[0] = NULL;
1244c2aa98e2SPeter Wemm 				xpvp = nullpvp;
1245c2aa98e2SPeter Wemm 			}
1246c2aa98e2SPeter Wemm 			else
1247c2aa98e2SPeter Wemm 			{
1248c2aa98e2SPeter Wemm 				/* scan the new replacement */
1249c2aa98e2SPeter Wemm 				xpvp = prescan(replac, '\0', pvpbuf,
1250c2aa98e2SPeter Wemm 					       sizeof pvpbuf, NULL, NULL);
1251c2aa98e2SPeter Wemm 				if (xpvp == NULL)
1252c2aa98e2SPeter Wemm 				{
1253c2aa98e2SPeter Wemm 					/* prescan already printed error */
1254c2aa98e2SPeter Wemm 					return EX_DATAERR;
1255c2aa98e2SPeter Wemm 				}
1256c2aa98e2SPeter Wemm 			}
1257c2aa98e2SPeter Wemm 
1258c2aa98e2SPeter Wemm 			/* append it to the token list */
1259c2aa98e2SPeter Wemm 			for (avp = hbrvp; *xpvp != NULL; xpvp++)
1260c2aa98e2SPeter Wemm 			{
1261c2aa98e2SPeter Wemm 				*avp++ = newstr(*xpvp);
1262c2aa98e2SPeter Wemm 				if (avp >= &npvp[MAXATOM])
1263c2aa98e2SPeter Wemm 					goto toolong;
1264c2aa98e2SPeter Wemm 			}
1265c2aa98e2SPeter Wemm 
1266c2aa98e2SPeter Wemm 			/* restore the old trailing information */
1267c2aa98e2SPeter Wemm 			rvp = avp - 1;
1268c2aa98e2SPeter Wemm 			for (xpvp = pvpb1; (*avp++ = *xpvp++) != NULL; )
1269c2aa98e2SPeter Wemm 				if (avp >= &npvp[MAXATOM])
1270c2aa98e2SPeter Wemm 					goto toolong;
1271c2aa98e2SPeter Wemm 		}
1272c2aa98e2SPeter Wemm 
1273c2aa98e2SPeter Wemm 		/*
1274c2aa98e2SPeter Wemm 		**  Check for subroutine calls.
1275c2aa98e2SPeter Wemm 		*/
1276c2aa98e2SPeter Wemm 
1277c2aa98e2SPeter Wemm 		stat = callsubr(npvp, reclevel, e);
1278c2aa98e2SPeter Wemm 		if (rstat == EX_OK || stat == EX_TEMPFAIL)
1279c2aa98e2SPeter Wemm 			rstat = stat;
1280c2aa98e2SPeter Wemm 
1281c2aa98e2SPeter Wemm 		/* copy vector back into original space. */
1282c2aa98e2SPeter Wemm 		for (avp = npvp; *avp++ != NULL;)
1283c2aa98e2SPeter Wemm 			continue;
1284c2aa98e2SPeter Wemm 		bcopy((char *) npvp, (char *) pvp,
1285c2aa98e2SPeter Wemm 		      (int) (avp - npvp) * sizeof *avp);
1286c2aa98e2SPeter Wemm 
1287c2aa98e2SPeter Wemm 		if (tTd(21, 4))
1288c2aa98e2SPeter Wemm 		{
1289c2aa98e2SPeter Wemm 			printf("rewritten as:");
1290c2aa98e2SPeter Wemm 			printav(pvp);
1291c2aa98e2SPeter Wemm 		}
1292c2aa98e2SPeter Wemm 	}
1293c2aa98e2SPeter Wemm 
1294c2aa98e2SPeter Wemm 	if (OpMode == MD_TEST || tTd(21, 1))
1295c2aa98e2SPeter Wemm 	{
1296c2aa98e2SPeter Wemm 		printf("rewrite: ruleset %3d returns:", ruleset);
1297c2aa98e2SPeter Wemm 		printav(pvp);
1298c2aa98e2SPeter Wemm 	}
1299c2aa98e2SPeter Wemm 
1300c2aa98e2SPeter Wemm 	return rstat;
1301c2aa98e2SPeter Wemm }
1302c2aa98e2SPeter Wemm /*
1303c2aa98e2SPeter Wemm **  CALLSUBR -- call subroutines in rewrite vector
1304c2aa98e2SPeter Wemm **
1305c2aa98e2SPeter Wemm **	Parameters:
1306c2aa98e2SPeter Wemm **		pvp -- pointer to token vector.
1307c2aa98e2SPeter Wemm **		reclevel -- the current recursion level.
1308c2aa98e2SPeter Wemm **		e -- the current envelope.
1309c2aa98e2SPeter Wemm **
1310c2aa98e2SPeter Wemm **	Returns:
1311c2aa98e2SPeter Wemm **		The status from the subroutine call.
1312c2aa98e2SPeter Wemm **
1313c2aa98e2SPeter Wemm **	Side Effects:
1314c2aa98e2SPeter Wemm **		pvp is modified.
1315c2aa98e2SPeter Wemm */
1316c2aa98e2SPeter Wemm 
1317c2aa98e2SPeter Wemm int
1318c2aa98e2SPeter Wemm callsubr(pvp, reclevel, e)
1319c2aa98e2SPeter Wemm 	char **pvp;
1320c2aa98e2SPeter Wemm 	int reclevel;
1321c2aa98e2SPeter Wemm 	ENVELOPE *e;
1322c2aa98e2SPeter Wemm {
1323c2aa98e2SPeter Wemm     	char **avp;
1324c2aa98e2SPeter Wemm     	char **rvp;
1325c2aa98e2SPeter Wemm 	register int i;
1326c2aa98e2SPeter Wemm 	int subr;
1327c2aa98e2SPeter Wemm 	int stat;
1328c2aa98e2SPeter Wemm 	int rstat = EX_OK;
1329c2aa98e2SPeter Wemm 	char *tpvp[MAXATOM + 1];
1330c2aa98e2SPeter Wemm 
1331c2aa98e2SPeter Wemm 	for (avp = pvp; *avp != NULL; avp++)
1332c2aa98e2SPeter Wemm 	{
1333c2aa98e2SPeter Wemm 		if ((**avp & 0377) == CALLSUBR && avp[1] != NULL)
1334c2aa98e2SPeter Wemm 		{
1335c2aa98e2SPeter Wemm 			stripquotes(avp[1]);
1336c2aa98e2SPeter Wemm 			subr = strtorwset(avp[1], NULL, ST_FIND);
1337c2aa98e2SPeter Wemm 			if (subr < 0)
1338c2aa98e2SPeter Wemm 			{
1339c2aa98e2SPeter Wemm 				syserr("Unknown ruleset %s", avp[1]);
1340c2aa98e2SPeter Wemm 				return EX_CONFIG;
1341c2aa98e2SPeter Wemm 			}
1342c2aa98e2SPeter Wemm 
1343c2aa98e2SPeter Wemm 			if (tTd(21, 3))
1344c2aa98e2SPeter Wemm 				printf("-----callsubr %s (%d)\n", avp[1], subr);
1345c2aa98e2SPeter Wemm 
1346c2aa98e2SPeter Wemm 			/*
1347c2aa98e2SPeter Wemm 			**  Take care of possible inner calls first.
1348c2aa98e2SPeter Wemm 			**  use a full size temporary buffer to avoid
1349c2aa98e2SPeter Wemm 			**  overflows in rewrite, but strip off the
1350c2aa98e2SPeter Wemm 			**  subroutine call.
1351c2aa98e2SPeter Wemm 			*/
1352c2aa98e2SPeter Wemm 
1353c2aa98e2SPeter Wemm 			for (i = 2; avp[i] != NULL; i++)
1354c2aa98e2SPeter Wemm 				tpvp[i - 2] = avp[i];
1355c2aa98e2SPeter Wemm 			tpvp[i - 2] = NULL;
1356c2aa98e2SPeter Wemm 
1357c2aa98e2SPeter Wemm 			stat = callsubr(tpvp, reclevel, e);
1358c2aa98e2SPeter Wemm 			if (rstat == EX_OK || stat == EX_TEMPFAIL)
1359c2aa98e2SPeter Wemm 				rstat = stat;
1360c2aa98e2SPeter Wemm 
1361c2aa98e2SPeter Wemm 			/*
1362c2aa98e2SPeter Wemm 			**  Now we need to call the ruleset specified for
1363c2aa98e2SPeter Wemm 			**  the subroutine. we can do this with the
1364c2aa98e2SPeter Wemm 			**  temporary buffer that we set up earlier,
1365c2aa98e2SPeter Wemm 			**  since it has all the data we want to rewrite.
1366c2aa98e2SPeter Wemm 			*/
1367c2aa98e2SPeter Wemm 
1368c2aa98e2SPeter Wemm 			stat = rewrite(tpvp, subr, reclevel, e);
1369c2aa98e2SPeter Wemm 			if (rstat == EX_OK || stat == EX_TEMPFAIL)
1370c2aa98e2SPeter Wemm 				rstat = stat;
1371c2aa98e2SPeter Wemm 
1372c2aa98e2SPeter Wemm 			/*
1373c2aa98e2SPeter Wemm 			**  Find length of tpvp and current offset into
1374c2aa98e2SPeter Wemm 			**  pvp, if the total is greater than MAXATOM,
1375c2aa98e2SPeter Wemm 			**  then it would overflow the buffer if we copied
1376c2aa98e2SPeter Wemm 			**  it back in to pvp, in which case we throw a
1377c2aa98e2SPeter Wemm 			**  fit.
1378c2aa98e2SPeter Wemm 			*/
1379c2aa98e2SPeter Wemm 
1380c2aa98e2SPeter Wemm 			for (rvp = tpvp; *rvp != NULL; rvp++)
1381c2aa98e2SPeter Wemm 				continue;
1382c2aa98e2SPeter Wemm 			if (((rvp - tpvp) + (avp - pvp)) > MAXATOM)
1383c2aa98e2SPeter Wemm 			{
1384c2aa98e2SPeter Wemm 			    	syserr("554 callsubr: expansion too long");
1385c2aa98e2SPeter Wemm 				return EX_DATAERR;
1386c2aa98e2SPeter Wemm 			}
1387c2aa98e2SPeter Wemm 
1388c2aa98e2SPeter Wemm 			/*
1389c2aa98e2SPeter Wemm 			**  Now we can copy the rewritten code over
1390c2aa98e2SPeter Wemm 			**  the initial subroutine call in the buffer.
1391c2aa98e2SPeter Wemm 			*/
1392c2aa98e2SPeter Wemm 
1393c2aa98e2SPeter Wemm 			for (i = 0; tpvp[i] != NULL; i++)
1394c2aa98e2SPeter Wemm 				avp[i] = tpvp[i];
1395c2aa98e2SPeter Wemm 			avp[i] = NULL;
1396c2aa98e2SPeter Wemm 
1397c2aa98e2SPeter Wemm 			/*
1398c2aa98e2SPeter Wemm 			**  If we got this far, we've processed the left
1399c2aa98e2SPeter Wemm 			**  most subroutine, and recursively called ourselves
1400c2aa98e2SPeter Wemm 			**  to handle any other subroutines.  We're done.
1401c2aa98e2SPeter Wemm 			*/
1402c2aa98e2SPeter Wemm 
1403c2aa98e2SPeter Wemm 			break;
1404c2aa98e2SPeter Wemm 		}
1405c2aa98e2SPeter Wemm 	}
1406c2aa98e2SPeter Wemm 	return rstat;
1407c2aa98e2SPeter Wemm }
1408c2aa98e2SPeter Wemm /*
1409c2aa98e2SPeter Wemm **  MAP_LOOKUP -- do lookup in map
1410c2aa98e2SPeter Wemm **
1411c2aa98e2SPeter Wemm **	Parameters:
1412c2aa98e2SPeter Wemm **		map -- the map to use for the lookup.
1413c2aa98e2SPeter Wemm **		key -- the key to look up.
1414c2aa98e2SPeter Wemm **		argvect -- arguments to pass to the map lookup.
1415c2aa98e2SPeter Wemm **		pstat -- a pointer to an integer in which to store the
1416c2aa98e2SPeter Wemm **			status from the lookup.
1417c2aa98e2SPeter Wemm **		e -- the current envelope.
1418c2aa98e2SPeter Wemm **
1419c2aa98e2SPeter Wemm **	Returns:
1420c2aa98e2SPeter Wemm **		The result of the lookup.
1421c2aa98e2SPeter Wemm **		NULL -- if there was no data for the given key.
1422c2aa98e2SPeter Wemm */
1423c2aa98e2SPeter Wemm 
1424c2aa98e2SPeter Wemm char *
1425c2aa98e2SPeter Wemm map_lookup(map, key, argvect, pstat, e)
1426c2aa98e2SPeter Wemm 	STAB *map;
1427c2aa98e2SPeter Wemm 	char key[];
1428c2aa98e2SPeter Wemm 	char **argvect;
1429c2aa98e2SPeter Wemm 	int *pstat;
1430c2aa98e2SPeter Wemm 	ENVELOPE *e;
1431c2aa98e2SPeter Wemm {
1432c2aa98e2SPeter Wemm 	auto int stat = EX_OK;
1433c2aa98e2SPeter Wemm 	char *replac;
1434c2aa98e2SPeter Wemm 
1435c2aa98e2SPeter Wemm 	if (e->e_sendmode == SM_DEFER)
1436c2aa98e2SPeter Wemm 	{
1437c2aa98e2SPeter Wemm 		/* don't do any map lookups */
1438c2aa98e2SPeter Wemm 		if (tTd(60, 1))
1439c2aa98e2SPeter Wemm 			printf("map_lookup(%s, %s) => DEFERRED\n",
1440c2aa98e2SPeter Wemm 				map->s_name, key);
1441c2aa98e2SPeter Wemm 		*pstat = EX_TEMPFAIL;
1442c2aa98e2SPeter Wemm 		return NULL;
1443c2aa98e2SPeter Wemm 	}
1444c2aa98e2SPeter Wemm 	if (map == NULL || !bitset(MF_OPEN, map->s_map.map_mflags))
1445c2aa98e2SPeter Wemm 		return NULL;
1446c2aa98e2SPeter Wemm 
1447c2aa98e2SPeter Wemm 	if (!bitset(MF_KEEPQUOTES, map->s_map.map_mflags))
1448c2aa98e2SPeter Wemm 		stripquotes(key);
1449c2aa98e2SPeter Wemm 
1450c2aa98e2SPeter Wemm 	/* XXX should try to auto-open the map here */
1451c2aa98e2SPeter Wemm 
1452c2aa98e2SPeter Wemm 	if (tTd(60, 1))
1453c2aa98e2SPeter Wemm 		printf("map_lookup(%s, %s) => ",
1454c2aa98e2SPeter Wemm 			map->s_name, key);
1455c2aa98e2SPeter Wemm 	replac = (*map->s_map.map_class->map_lookup)(&map->s_map,
1456c2aa98e2SPeter Wemm 			key, argvect, &stat);
1457c2aa98e2SPeter Wemm 	if (tTd(60, 1))
1458c2aa98e2SPeter Wemm 		printf("%s (%d)\n",
1459c2aa98e2SPeter Wemm 			replac != NULL ? replac : "NOT FOUND",
1460c2aa98e2SPeter Wemm 			stat);
1461c2aa98e2SPeter Wemm 
1462c2aa98e2SPeter Wemm 	/* should recover if stat == EX_TEMPFAIL */
1463c2aa98e2SPeter Wemm 	if (stat == EX_TEMPFAIL && !bitset(MF_NODEFER, map->s_map.map_mflags))
1464c2aa98e2SPeter Wemm 	{
1465c2aa98e2SPeter Wemm 		*pstat = EX_TEMPFAIL;
1466c2aa98e2SPeter Wemm 		if (tTd(60, 1))
1467c2aa98e2SPeter Wemm 			printf("map_lookup(%s, %s) tempfail: errno=%d\n",
1468c2aa98e2SPeter Wemm 				map->s_name, key, errno);
1469c2aa98e2SPeter Wemm 		if (e->e_message == NULL)
1470c2aa98e2SPeter Wemm 		{
1471c2aa98e2SPeter Wemm 			char mbuf[320];
1472c2aa98e2SPeter Wemm 
1473c2aa98e2SPeter Wemm 			snprintf(mbuf, sizeof mbuf,
1474c2aa98e2SPeter Wemm 				"%.80s map: lookup (%s): deferred",
1475c2aa98e2SPeter Wemm 				map->s_name,
1476c2aa98e2SPeter Wemm 				shortenstring(key, MAXSHORTSTR));
1477c2aa98e2SPeter Wemm 			e->e_message = newstr(mbuf);
1478c2aa98e2SPeter Wemm 		}
1479c2aa98e2SPeter Wemm 	}
1480c2aa98e2SPeter Wemm 	if (stat == EX_TEMPFAIL && map->s_map.map_tapp != NULL)
1481c2aa98e2SPeter Wemm 	{
1482c2aa98e2SPeter Wemm 		size_t i = strlen(key) + strlen(map->s_map.map_tapp) + 1;
1483c2aa98e2SPeter Wemm 		static char *rwbuf = NULL;
1484c2aa98e2SPeter Wemm 		static size_t rwbuflen = 0;
1485c2aa98e2SPeter Wemm 
1486c2aa98e2SPeter Wemm 		if (i > rwbuflen)
1487c2aa98e2SPeter Wemm 		{
1488c2aa98e2SPeter Wemm 			if (rwbuf != NULL)
1489c2aa98e2SPeter Wemm 				free(rwbuf);
1490c2aa98e2SPeter Wemm 			rwbuflen = i;
1491c2aa98e2SPeter Wemm 			rwbuf = (char *) xalloc(rwbuflen);
1492c2aa98e2SPeter Wemm 		}
1493c2aa98e2SPeter Wemm 		snprintf(rwbuf, rwbuflen, "%s%s", key, map->s_map.map_tapp);
1494c2aa98e2SPeter Wemm 		if (tTd(60, 4))
1495c2aa98e2SPeter Wemm 			printf("map_lookup tempfail: returning \"%s\"\n",
1496c2aa98e2SPeter Wemm 				rwbuf);
1497c2aa98e2SPeter Wemm 		return rwbuf;
1498c2aa98e2SPeter Wemm 	}
1499c2aa98e2SPeter Wemm 	return replac;
1500c2aa98e2SPeter Wemm }
1501c2aa98e2SPeter Wemm /*
1502c2aa98e2SPeter Wemm **  BUILDADDR -- build address from token vector.
1503c2aa98e2SPeter Wemm **
1504c2aa98e2SPeter Wemm **	Parameters:
1505c2aa98e2SPeter Wemm **		tv -- token vector.
1506c2aa98e2SPeter Wemm **		a -- pointer to address descriptor to fill.
1507c2aa98e2SPeter Wemm **			If NULL, one will be allocated.
1508c2aa98e2SPeter Wemm **		flags -- info regarding whether this is a sender or
1509c2aa98e2SPeter Wemm **			a recipient.
1510c2aa98e2SPeter Wemm **		e -- the current envelope.
1511c2aa98e2SPeter Wemm **
1512c2aa98e2SPeter Wemm **	Returns:
1513c2aa98e2SPeter Wemm **		NULL if there was an error.
1514c2aa98e2SPeter Wemm **		'a' otherwise.
1515c2aa98e2SPeter Wemm **
1516c2aa98e2SPeter Wemm **	Side Effects:
1517c2aa98e2SPeter Wemm **		fills in 'a'
1518c2aa98e2SPeter Wemm */
1519c2aa98e2SPeter Wemm 
1520c2aa98e2SPeter Wemm struct errcodes
1521c2aa98e2SPeter Wemm {
1522c2aa98e2SPeter Wemm 	char	*ec_name;		/* name of error code */
1523c2aa98e2SPeter Wemm 	int	ec_code;		/* numeric code */
1524c2aa98e2SPeter Wemm } ErrorCodes[] =
1525c2aa98e2SPeter Wemm {
1526c2aa98e2SPeter Wemm 	{ "usage",		EX_USAGE	},
1527c2aa98e2SPeter Wemm 	{ "nouser",		EX_NOUSER	},
1528c2aa98e2SPeter Wemm 	{ "nohost",		EX_NOHOST	},
1529c2aa98e2SPeter Wemm 	{ "unavailable",	EX_UNAVAILABLE	},
1530c2aa98e2SPeter Wemm 	{ "software",		EX_SOFTWARE	},
1531c2aa98e2SPeter Wemm 	{ "tempfail",		EX_TEMPFAIL	},
1532c2aa98e2SPeter Wemm 	{ "protocol",		EX_PROTOCOL	},
1533c2aa98e2SPeter Wemm #ifdef EX_CONFIG
1534c2aa98e2SPeter Wemm 	{ "config",		EX_CONFIG	},
1535c2aa98e2SPeter Wemm #endif
1536c2aa98e2SPeter Wemm 	{ NULL,			EX_UNAVAILABLE	}
1537c2aa98e2SPeter Wemm };
1538c2aa98e2SPeter Wemm 
1539c2aa98e2SPeter Wemm ADDRESS *
1540c2aa98e2SPeter Wemm buildaddr(tv, a, flags, e)
1541c2aa98e2SPeter Wemm 	register char **tv;
1542c2aa98e2SPeter Wemm 	register ADDRESS *a;
1543c2aa98e2SPeter Wemm 	int flags;
1544c2aa98e2SPeter Wemm 	register ENVELOPE *e;
1545c2aa98e2SPeter Wemm {
1546c2aa98e2SPeter Wemm 	struct mailer **mp;
1547c2aa98e2SPeter Wemm 	register struct mailer *m;
1548c2aa98e2SPeter Wemm 	register char *p;
1549c2aa98e2SPeter Wemm 	char *mname;
1550c2aa98e2SPeter Wemm 	char **hostp;
1551c2aa98e2SPeter Wemm 	char hbuf[MAXNAME + 1];
1552c2aa98e2SPeter Wemm 	static MAILER discardmailer;
1553c2aa98e2SPeter Wemm 	static MAILER errormailer;
1554c2aa98e2SPeter Wemm 	static char *discardargv[] = { "DISCARD", NULL };
1555c2aa98e2SPeter Wemm 	static char *errorargv[] = { "ERROR", NULL };
1556c2aa98e2SPeter Wemm 	static char ubuf[MAXNAME + 1];
1557c2aa98e2SPeter Wemm 
1558c2aa98e2SPeter Wemm 	if (tTd(24, 5))
1559c2aa98e2SPeter Wemm 	{
1560c2aa98e2SPeter Wemm 		printf("buildaddr, flags=%x, tv=", flags);
1561c2aa98e2SPeter Wemm 		printav(tv);
1562c2aa98e2SPeter Wemm 	}
1563c2aa98e2SPeter Wemm 
1564c2aa98e2SPeter Wemm 	if (a == NULL)
1565c2aa98e2SPeter Wemm 		a = (ADDRESS *) xalloc(sizeof *a);
1566c2aa98e2SPeter Wemm 	bzero((char *) a, sizeof *a);
1567c2aa98e2SPeter Wemm 
1568c2aa98e2SPeter Wemm 	/* set up default error return flags */
1569c2aa98e2SPeter Wemm 	a->q_flags |= DefaultNotify;
1570c2aa98e2SPeter Wemm 
1571c2aa98e2SPeter Wemm 	if (discardmailer.m_name == NULL)
1572c2aa98e2SPeter Wemm 	{
1573c2aa98e2SPeter Wemm 		/* initialize the discard mailer */
1574c2aa98e2SPeter Wemm 		discardmailer.m_name = "*discard*";
1575c2aa98e2SPeter Wemm 		discardmailer.m_mailer = "DISCARD";
1576c2aa98e2SPeter Wemm 		discardmailer.m_argv = discardargv;
1577c2aa98e2SPeter Wemm 	}
1578c2aa98e2SPeter Wemm 
1579c2aa98e2SPeter Wemm 	/* figure out what net/mailer to use */
1580c2aa98e2SPeter Wemm 	if (*tv == NULL || (**tv & 0377) != CANONNET)
1581c2aa98e2SPeter Wemm 	{
1582c2aa98e2SPeter Wemm 		syserr("554 buildaddr: no mailer in parsed address");
1583c2aa98e2SPeter Wemm badaddr:
1584c2aa98e2SPeter Wemm 		a->q_flags |= QBADADDR;
1585c2aa98e2SPeter Wemm 		a->q_mailer = &errormailer;
1586c2aa98e2SPeter Wemm 		if (errormailer.m_name == NULL)
1587c2aa98e2SPeter Wemm 		{
1588c2aa98e2SPeter Wemm 			/* initialize the bogus mailer */
1589c2aa98e2SPeter Wemm 			errormailer.m_name = "*error*";
1590c2aa98e2SPeter Wemm 			errormailer.m_mailer = "ERROR";
1591c2aa98e2SPeter Wemm 			errormailer.m_argv = errorargv;
1592c2aa98e2SPeter Wemm 		}
1593c2aa98e2SPeter Wemm 		return a;
1594c2aa98e2SPeter Wemm 	}
1595c2aa98e2SPeter Wemm 	mname = *++tv;
1596c2aa98e2SPeter Wemm 
1597c2aa98e2SPeter Wemm 	/* extract host and user portions */
1598c2aa98e2SPeter Wemm 	if (*++tv != NULL && (**tv & 0377) == CANONHOST)
1599c2aa98e2SPeter Wemm 		hostp = ++tv;
1600c2aa98e2SPeter Wemm 	else
1601c2aa98e2SPeter Wemm 		hostp = NULL;
1602c2aa98e2SPeter Wemm 	while (*tv != NULL && (**tv & 0377) != CANONUSER)
1603c2aa98e2SPeter Wemm 		tv++;
1604c2aa98e2SPeter Wemm 	if (*tv == NULL)
1605c2aa98e2SPeter Wemm 	{
1606c2aa98e2SPeter Wemm 		syserr("554 buildaddr: no user");
1607c2aa98e2SPeter Wemm 		goto badaddr;
1608c2aa98e2SPeter Wemm 	}
1609c2aa98e2SPeter Wemm 	if (tv == hostp)
1610c2aa98e2SPeter Wemm 		hostp = NULL;
1611c2aa98e2SPeter Wemm 	else if (hostp != NULL)
1612c2aa98e2SPeter Wemm 		cataddr(hostp, tv - 1, hbuf, sizeof hbuf, '\0');
1613c2aa98e2SPeter Wemm 	cataddr(++tv, NULL, ubuf, sizeof ubuf, ' ');
1614c2aa98e2SPeter Wemm 
1615c2aa98e2SPeter Wemm 	/* save away the host name */
1616c2aa98e2SPeter Wemm 	if (strcasecmp(mname, "error") == 0)
1617c2aa98e2SPeter Wemm 	{
1618c2aa98e2SPeter Wemm 		if (hostp != NULL)
1619c2aa98e2SPeter Wemm 		{
1620c2aa98e2SPeter Wemm 			register struct errcodes *ep;
1621c2aa98e2SPeter Wemm 
1622c2aa98e2SPeter Wemm 			if (strchr(hbuf, '.') != NULL)
1623c2aa98e2SPeter Wemm 			{
1624c2aa98e2SPeter Wemm 				extern int dsntoexitstat __P((char *));
1625c2aa98e2SPeter Wemm 
1626c2aa98e2SPeter Wemm 				a->q_status = newstr(hbuf);
1627c2aa98e2SPeter Wemm 				setstat(dsntoexitstat(hbuf));
1628c2aa98e2SPeter Wemm 			}
1629c2aa98e2SPeter Wemm 			else if (isascii(hbuf[0]) && isdigit(hbuf[0]))
1630c2aa98e2SPeter Wemm 			{
1631c2aa98e2SPeter Wemm 				setstat(atoi(hbuf));
1632c2aa98e2SPeter Wemm 			}
1633c2aa98e2SPeter Wemm 			else
1634c2aa98e2SPeter Wemm 			{
1635c2aa98e2SPeter Wemm 				for (ep = ErrorCodes; ep->ec_name != NULL; ep++)
1636c2aa98e2SPeter Wemm 					if (strcasecmp(ep->ec_name, hbuf) == 0)
1637c2aa98e2SPeter Wemm 						break;
1638c2aa98e2SPeter Wemm 				setstat(ep->ec_code);
1639c2aa98e2SPeter Wemm 			}
1640c2aa98e2SPeter Wemm 		}
1641c2aa98e2SPeter Wemm 		else
1642c2aa98e2SPeter Wemm 			setstat(EX_UNAVAILABLE);
1643c2aa98e2SPeter Wemm 		stripquotes(ubuf);
1644c2aa98e2SPeter Wemm 		if (isascii(ubuf[0]) && isdigit(ubuf[0]) &&
1645c2aa98e2SPeter Wemm 		    isascii(ubuf[1]) && isdigit(ubuf[1]) &&
1646c2aa98e2SPeter Wemm 		    isascii(ubuf[2]) && isdigit(ubuf[2]) &&
1647c2aa98e2SPeter Wemm 		    ubuf[3] == ' ')
1648c2aa98e2SPeter Wemm 		{
1649c2aa98e2SPeter Wemm 			char fmt[10];
1650c2aa98e2SPeter Wemm 
1651c2aa98e2SPeter Wemm 			strncpy(fmt, ubuf, 3);
1652c2aa98e2SPeter Wemm 			strcpy(&fmt[3], " %s");
1653c2aa98e2SPeter Wemm 			usrerr(fmt, ubuf + 4);
1654c2aa98e2SPeter Wemm 
1655c2aa98e2SPeter Wemm 			/*
1656c2aa98e2SPeter Wemm 			**  If this is a 4xx code and we aren't running
1657c2aa98e2SPeter Wemm 			**  SMTP on our input, bounce this message;
1658c2aa98e2SPeter Wemm 			**  otherwise it disappears without a trace.
1659c2aa98e2SPeter Wemm 			*/
1660c2aa98e2SPeter Wemm 
1661c2aa98e2SPeter Wemm 			if (fmt[0] == '4' && OpMode != MD_SMTP &&
1662c2aa98e2SPeter Wemm 			    OpMode != MD_DAEMON)
1663c2aa98e2SPeter Wemm 			{
1664c2aa98e2SPeter Wemm 				e->e_flags |= EF_FATALERRS;
1665c2aa98e2SPeter Wemm 			}
1666c2aa98e2SPeter Wemm 		}
1667c2aa98e2SPeter Wemm 		else
1668c2aa98e2SPeter Wemm 		{
1669c2aa98e2SPeter Wemm 			usrerr("553 %s", ubuf);
1670c2aa98e2SPeter Wemm 		}
1671c2aa98e2SPeter Wemm 		goto badaddr;
1672c2aa98e2SPeter Wemm 	}
1673c2aa98e2SPeter Wemm 
1674c2aa98e2SPeter Wemm 	for (mp = Mailer; (m = *mp++) != NULL; )
1675c2aa98e2SPeter Wemm 	{
1676c2aa98e2SPeter Wemm 		if (strcasecmp(m->m_name, mname) == 0)
1677c2aa98e2SPeter Wemm 			break;
1678c2aa98e2SPeter Wemm 	}
1679c2aa98e2SPeter Wemm 	if (m == NULL)
1680c2aa98e2SPeter Wemm 	{
1681c2aa98e2SPeter Wemm 		syserr("554 buildaddr: unknown mailer %s", mname);
1682c2aa98e2SPeter Wemm 		goto badaddr;
1683c2aa98e2SPeter Wemm 	}
1684c2aa98e2SPeter Wemm 	a->q_mailer = m;
1685c2aa98e2SPeter Wemm 
1686c2aa98e2SPeter Wemm 	/* figure out what host (if any) */
1687c2aa98e2SPeter Wemm 	if (hostp == NULL)
1688c2aa98e2SPeter Wemm 	{
1689c2aa98e2SPeter Wemm 		if (!bitnset(M_LOCALMAILER, m->m_flags))
1690c2aa98e2SPeter Wemm 		{
1691c2aa98e2SPeter Wemm 			syserr("554 buildaddr: no host");
1692c2aa98e2SPeter Wemm 			goto badaddr;
1693c2aa98e2SPeter Wemm 		}
1694c2aa98e2SPeter Wemm 		a->q_host = NULL;
1695c2aa98e2SPeter Wemm 	}
1696c2aa98e2SPeter Wemm 	else
1697c2aa98e2SPeter Wemm 		a->q_host = newstr(hbuf);
1698c2aa98e2SPeter Wemm 
1699c2aa98e2SPeter Wemm 	/* figure out the user */
1700c2aa98e2SPeter Wemm 	p = ubuf;
1701c2aa98e2SPeter Wemm 	if (bitnset(M_CHECKUDB, m->m_flags) && *p == '@')
1702c2aa98e2SPeter Wemm 	{
1703c2aa98e2SPeter Wemm 		p++;
1704c2aa98e2SPeter Wemm 		tv++;
1705c2aa98e2SPeter Wemm 		a->q_flags |= QNOTREMOTE;
1706c2aa98e2SPeter Wemm 	}
1707c2aa98e2SPeter Wemm 
1708c2aa98e2SPeter Wemm 	/* do special mapping for local mailer */
1709c2aa98e2SPeter Wemm 	if (*p == '"')
1710c2aa98e2SPeter Wemm 		p++;
1711c2aa98e2SPeter Wemm 	if (*p == '|' && bitnset(M_CHECKPROG, m->m_flags))
1712c2aa98e2SPeter Wemm 		a->q_mailer = m = ProgMailer;
1713c2aa98e2SPeter Wemm 	else if (*p == '/' && bitnset(M_CHECKFILE, m->m_flags))
1714c2aa98e2SPeter Wemm 		a->q_mailer = m = FileMailer;
1715c2aa98e2SPeter Wemm 	else if (*p == ':' && bitnset(M_CHECKINCLUDE, m->m_flags))
1716c2aa98e2SPeter Wemm 	{
1717c2aa98e2SPeter Wemm 		/* may be :include: */
1718c2aa98e2SPeter Wemm 		stripquotes(ubuf);
1719c2aa98e2SPeter Wemm 		if (strncasecmp(ubuf, ":include:", 9) == 0)
1720c2aa98e2SPeter Wemm 		{
1721c2aa98e2SPeter Wemm 			/* if :include:, don't need further rewriting */
1722c2aa98e2SPeter Wemm 			a->q_mailer = m = InclMailer;
1723c2aa98e2SPeter Wemm 			a->q_user = newstr(&ubuf[9]);
1724c2aa98e2SPeter Wemm 			return a;
1725c2aa98e2SPeter Wemm 		}
1726c2aa98e2SPeter Wemm 	}
1727c2aa98e2SPeter Wemm 
1728c2aa98e2SPeter Wemm 	/* rewrite according recipient mailer rewriting rules */
1729c2aa98e2SPeter Wemm 	define('h', a->q_host, e);
1730c2aa98e2SPeter Wemm 	if (!bitset(RF_SENDERADDR|RF_HEADERADDR, flags))
1731c2aa98e2SPeter Wemm 	{
1732c2aa98e2SPeter Wemm 		/* sender addresses done later */
1733c2aa98e2SPeter Wemm 		(void) rewrite(tv, 2, 0, e);
1734c2aa98e2SPeter Wemm 		if (m->m_re_rwset > 0)
1735c2aa98e2SPeter Wemm 		       (void) rewrite(tv, m->m_re_rwset, 0, e);
1736c2aa98e2SPeter Wemm 	}
1737c2aa98e2SPeter Wemm 	(void) rewrite(tv, 4, 0, e);
1738c2aa98e2SPeter Wemm 
1739c2aa98e2SPeter Wemm 	/* save the result for the command line/RCPT argument */
1740c2aa98e2SPeter Wemm 	cataddr(tv, NULL, ubuf, sizeof ubuf, '\0');
1741c2aa98e2SPeter Wemm 	a->q_user = ubuf;
1742c2aa98e2SPeter Wemm 
1743c2aa98e2SPeter Wemm 	/*
1744c2aa98e2SPeter Wemm 	**  Do mapping to lower case as requested by mailer
1745c2aa98e2SPeter Wemm 	*/
1746c2aa98e2SPeter Wemm 
1747c2aa98e2SPeter Wemm 	if (a->q_host != NULL && !bitnset(M_HST_UPPER, m->m_flags))
1748c2aa98e2SPeter Wemm 		makelower(a->q_host);
1749c2aa98e2SPeter Wemm 	if (!bitnset(M_USR_UPPER, m->m_flags))
1750c2aa98e2SPeter Wemm 		makelower(a->q_user);
1751c2aa98e2SPeter Wemm 
1752c2aa98e2SPeter Wemm 	if (tTd(24, 6))
1753c2aa98e2SPeter Wemm 	{
1754c2aa98e2SPeter Wemm 		printf("buildaddr => ");
1755c2aa98e2SPeter Wemm 		printaddr(a, FALSE);
1756c2aa98e2SPeter Wemm 	}
1757c2aa98e2SPeter Wemm 	return a;
1758c2aa98e2SPeter Wemm }
1759c2aa98e2SPeter Wemm /*
1760c2aa98e2SPeter Wemm **  CATADDR -- concatenate pieces of addresses (putting in <LWSP> subs)
1761c2aa98e2SPeter Wemm **
1762c2aa98e2SPeter Wemm **	Parameters:
1763c2aa98e2SPeter Wemm **		pvp -- parameter vector to rebuild.
1764c2aa98e2SPeter Wemm **		evp -- last parameter to include.  Can be NULL to
1765c2aa98e2SPeter Wemm **			use entire pvp.
1766c2aa98e2SPeter Wemm **		buf -- buffer to build the string into.
1767c2aa98e2SPeter Wemm **		sz -- size of buf.
1768c2aa98e2SPeter Wemm **		spacesub -- the space separator character; if null,
1769c2aa98e2SPeter Wemm **			use SpaceSub.
1770c2aa98e2SPeter Wemm **
1771c2aa98e2SPeter Wemm **	Returns:
1772c2aa98e2SPeter Wemm **		none.
1773c2aa98e2SPeter Wemm **
1774c2aa98e2SPeter Wemm **	Side Effects:
1775c2aa98e2SPeter Wemm **		Destroys buf.
1776c2aa98e2SPeter Wemm */
1777c2aa98e2SPeter Wemm 
1778c2aa98e2SPeter Wemm void
1779c2aa98e2SPeter Wemm cataddr(pvp, evp, buf, sz, spacesub)
1780c2aa98e2SPeter Wemm 	char **pvp;
1781c2aa98e2SPeter Wemm 	char **evp;
1782c2aa98e2SPeter Wemm 	char *buf;
1783c2aa98e2SPeter Wemm 	register int sz;
1784c2aa98e2SPeter Wemm 	int spacesub;
1785c2aa98e2SPeter Wemm {
1786c2aa98e2SPeter Wemm 	bool oatomtok = FALSE;
1787c2aa98e2SPeter Wemm 	bool natomtok = FALSE;
1788c2aa98e2SPeter Wemm 	register int i;
1789c2aa98e2SPeter Wemm 	register char *p;
1790c2aa98e2SPeter Wemm 
1791c2aa98e2SPeter Wemm 	if (spacesub == '\0')
1792c2aa98e2SPeter Wemm 		spacesub = SpaceSub;
1793c2aa98e2SPeter Wemm 
1794c2aa98e2SPeter Wemm 	if (pvp == NULL)
1795c2aa98e2SPeter Wemm 	{
1796c2aa98e2SPeter Wemm 		(void) strcpy(buf, "");
1797c2aa98e2SPeter Wemm 		return;
1798c2aa98e2SPeter Wemm 	}
1799c2aa98e2SPeter Wemm 	p = buf;
1800c2aa98e2SPeter Wemm 	sz -= 2;
1801c2aa98e2SPeter Wemm 	while (*pvp != NULL && (i = strlen(*pvp)) < sz)
1802c2aa98e2SPeter Wemm 	{
1803c2aa98e2SPeter Wemm 		natomtok = (TokTypeTab[**pvp & 0xff] == ATM);
1804c2aa98e2SPeter Wemm 		if (oatomtok && natomtok)
1805c2aa98e2SPeter Wemm 			*p++ = spacesub;
1806c2aa98e2SPeter Wemm 		(void) strcpy(p, *pvp);
1807c2aa98e2SPeter Wemm 		oatomtok = natomtok;
1808c2aa98e2SPeter Wemm 		p += i;
1809c2aa98e2SPeter Wemm 		sz -= i + 1;
1810c2aa98e2SPeter Wemm 		if (pvp++ == evp)
1811c2aa98e2SPeter Wemm 			break;
1812c2aa98e2SPeter Wemm 	}
1813c2aa98e2SPeter Wemm 	*p = '\0';
1814c2aa98e2SPeter Wemm }
1815c2aa98e2SPeter Wemm /*
1816c2aa98e2SPeter Wemm **  SAMEADDR -- Determine if two addresses are the same
1817c2aa98e2SPeter Wemm **
1818c2aa98e2SPeter Wemm **	This is not just a straight comparison -- if the mailer doesn't
1819c2aa98e2SPeter Wemm **	care about the host we just ignore it, etc.
1820c2aa98e2SPeter Wemm **
1821c2aa98e2SPeter Wemm **	Parameters:
1822c2aa98e2SPeter Wemm **		a, b -- pointers to the internal forms to compare.
1823c2aa98e2SPeter Wemm **
1824c2aa98e2SPeter Wemm **	Returns:
1825c2aa98e2SPeter Wemm **		TRUE -- they represent the same mailbox.
1826c2aa98e2SPeter Wemm **		FALSE -- they don't.
1827c2aa98e2SPeter Wemm **
1828c2aa98e2SPeter Wemm **	Side Effects:
1829c2aa98e2SPeter Wemm **		none.
1830c2aa98e2SPeter Wemm */
1831c2aa98e2SPeter Wemm 
1832c2aa98e2SPeter Wemm bool
1833c2aa98e2SPeter Wemm sameaddr(a, b)
1834c2aa98e2SPeter Wemm 	register ADDRESS *a;
1835c2aa98e2SPeter Wemm 	register ADDRESS *b;
1836c2aa98e2SPeter Wemm {
1837c2aa98e2SPeter Wemm 	register ADDRESS *ca, *cb;
1838c2aa98e2SPeter Wemm 
1839c2aa98e2SPeter Wemm 	/* if they don't have the same mailer, forget it */
1840c2aa98e2SPeter Wemm 	if (a->q_mailer != b->q_mailer)
1841c2aa98e2SPeter Wemm 		return (FALSE);
1842c2aa98e2SPeter Wemm 
1843c2aa98e2SPeter Wemm 	/* if the user isn't the same, we can drop out */
1844c2aa98e2SPeter Wemm 	if (strcmp(a->q_user, b->q_user) != 0)
1845c2aa98e2SPeter Wemm 		return (FALSE);
1846c2aa98e2SPeter Wemm 
1847c2aa98e2SPeter Wemm 	/* if we have good uids for both but they differ, these are different */
1848c2aa98e2SPeter Wemm 	if (a->q_mailer == ProgMailer)
1849c2aa98e2SPeter Wemm 	{
1850c2aa98e2SPeter Wemm 		ca = getctladdr(a);
1851c2aa98e2SPeter Wemm 		cb = getctladdr(b);
1852c2aa98e2SPeter Wemm 		if (ca != NULL && cb != NULL &&
1853c2aa98e2SPeter Wemm 		    bitset(QGOODUID, ca->q_flags & cb->q_flags) &&
1854c2aa98e2SPeter Wemm 		    ca->q_uid != cb->q_uid)
1855c2aa98e2SPeter Wemm 			return (FALSE);
1856c2aa98e2SPeter Wemm 	}
1857c2aa98e2SPeter Wemm 
1858c2aa98e2SPeter Wemm 	/* otherwise compare hosts (but be careful for NULL ptrs) */
1859c2aa98e2SPeter Wemm 	if (a->q_host == b->q_host)
1860c2aa98e2SPeter Wemm 	{
1861c2aa98e2SPeter Wemm 		/* probably both null pointers */
1862c2aa98e2SPeter Wemm 		return (TRUE);
1863c2aa98e2SPeter Wemm 	}
1864c2aa98e2SPeter Wemm 	if (a->q_host == NULL || b->q_host == NULL)
1865c2aa98e2SPeter Wemm 	{
1866c2aa98e2SPeter Wemm 		/* only one is a null pointer */
1867c2aa98e2SPeter Wemm 		return (FALSE);
1868c2aa98e2SPeter Wemm 	}
1869c2aa98e2SPeter Wemm 	if (strcmp(a->q_host, b->q_host) != 0)
1870c2aa98e2SPeter Wemm 		return (FALSE);
1871c2aa98e2SPeter Wemm 
1872c2aa98e2SPeter Wemm 	return (TRUE);
1873c2aa98e2SPeter Wemm }
1874c2aa98e2SPeter Wemm /*
1875c2aa98e2SPeter Wemm **  PRINTADDR -- print address (for debugging)
1876c2aa98e2SPeter Wemm **
1877c2aa98e2SPeter Wemm **	Parameters:
1878c2aa98e2SPeter Wemm **		a -- the address to print
1879c2aa98e2SPeter Wemm **		follow -- follow the q_next chain.
1880c2aa98e2SPeter Wemm **
1881c2aa98e2SPeter Wemm **	Returns:
1882c2aa98e2SPeter Wemm **		none.
1883c2aa98e2SPeter Wemm **
1884c2aa98e2SPeter Wemm **	Side Effects:
1885c2aa98e2SPeter Wemm **		none.
1886c2aa98e2SPeter Wemm */
1887c2aa98e2SPeter Wemm 
1888c2aa98e2SPeter Wemm struct qflags
1889c2aa98e2SPeter Wemm {
1890c2aa98e2SPeter Wemm 	char	*qf_name;
1891c2aa98e2SPeter Wemm 	u_long	qf_bit;
1892c2aa98e2SPeter Wemm };
1893c2aa98e2SPeter Wemm 
1894c2aa98e2SPeter Wemm struct qflags	AddressFlags[] =
1895c2aa98e2SPeter Wemm {
1896c2aa98e2SPeter Wemm 	{ "QDONTSEND",		QDONTSEND	},
1897c2aa98e2SPeter Wemm 	{ "QBADADDR",		QBADADDR	},
1898c2aa98e2SPeter Wemm 	{ "QGOODUID",		QGOODUID	},
1899c2aa98e2SPeter Wemm 	{ "QPRIMARY",		QPRIMARY	},
1900c2aa98e2SPeter Wemm 	{ "QQUEUEUP",		QQUEUEUP	},
1901c2aa98e2SPeter Wemm 	{ "QSENT",		QSENT		},
1902c2aa98e2SPeter Wemm 	{ "QNOTREMOTE",		QNOTREMOTE	},
1903c2aa98e2SPeter Wemm 	{ "QSELFREF",		QSELFREF	},
1904c2aa98e2SPeter Wemm 	{ "QVERIFIED",		QVERIFIED	},
1905c2aa98e2SPeter Wemm 	{ "QBOGUSSHELL",	QBOGUSSHELL	},
1906c2aa98e2SPeter Wemm 	{ "QUNSAFEADDR",	QUNSAFEADDR	},
1907c2aa98e2SPeter Wemm 	{ "QPINGONSUCCESS",	QPINGONSUCCESS	},
1908c2aa98e2SPeter Wemm 	{ "QPINGONFAILURE",	QPINGONFAILURE	},
1909c2aa98e2SPeter Wemm 	{ "QPINGONDELAY",	QPINGONDELAY	},
1910c2aa98e2SPeter Wemm 	{ "QHASNOTIFY",		QHASNOTIFY	},
1911c2aa98e2SPeter Wemm 	{ "QRELAYED",		QRELAYED	},
1912c2aa98e2SPeter Wemm 	{ "QEXPANDED",		QEXPANDED	},
1913c2aa98e2SPeter Wemm 	{ "QDELIVERED",		QDELIVERED	},
1914c2aa98e2SPeter Wemm 	{ "QDELAYED",		QDELAYED	},
1915c2aa98e2SPeter Wemm 	{ "QTHISPASS",		QTHISPASS	},
1916c2aa98e2SPeter Wemm 	{ "QRCPTOK",		QRCPTOK		},
1917c2aa98e2SPeter Wemm 	{ NULL }
1918c2aa98e2SPeter Wemm };
1919c2aa98e2SPeter Wemm 
1920c2aa98e2SPeter Wemm void
1921c2aa98e2SPeter Wemm printaddr(a, follow)
1922c2aa98e2SPeter Wemm 	register ADDRESS *a;
1923c2aa98e2SPeter Wemm 	bool follow;
1924c2aa98e2SPeter Wemm {
1925c2aa98e2SPeter Wemm 	register MAILER *m;
1926c2aa98e2SPeter Wemm 	MAILER pseudomailer;
1927c2aa98e2SPeter Wemm 	register struct qflags *qfp;
1928c2aa98e2SPeter Wemm 	bool firstone;
1929c2aa98e2SPeter Wemm 
1930c2aa98e2SPeter Wemm 	if (a == NULL)
1931c2aa98e2SPeter Wemm 	{
1932c2aa98e2SPeter Wemm 		printf("[NULL]\n");
1933c2aa98e2SPeter Wemm 		return;
1934c2aa98e2SPeter Wemm 	}
1935c2aa98e2SPeter Wemm 
1936c2aa98e2SPeter Wemm 	while (a != NULL)
1937c2aa98e2SPeter Wemm 	{
1938c2aa98e2SPeter Wemm 		printf("%lx=", (u_long) a);
1939c2aa98e2SPeter Wemm 		(void) fflush(stdout);
1940c2aa98e2SPeter Wemm 
1941c2aa98e2SPeter Wemm 		/* find the mailer -- carefully */
1942c2aa98e2SPeter Wemm 		m = a->q_mailer;
1943c2aa98e2SPeter Wemm 		if (m == NULL)
1944c2aa98e2SPeter Wemm 		{
1945c2aa98e2SPeter Wemm 			m = &pseudomailer;
1946c2aa98e2SPeter Wemm 			m->m_mno = -1;
1947c2aa98e2SPeter Wemm 			m->m_name = "NULL";
1948c2aa98e2SPeter Wemm 		}
1949c2aa98e2SPeter Wemm 
1950c2aa98e2SPeter Wemm 		printf("%s:\n\tmailer %d (%s), host `%s'\n",
1951c2aa98e2SPeter Wemm 		       a->q_paddr == NULL ? "<null>" : a->q_paddr,
1952c2aa98e2SPeter Wemm 		       m->m_mno, m->m_name,
1953c2aa98e2SPeter Wemm 		       a->q_host == NULL ? "<null>" : a->q_host);
1954c2aa98e2SPeter Wemm 		printf("\tuser `%s', ruser `%s'\n",
1955c2aa98e2SPeter Wemm 		       a->q_user,
1956c2aa98e2SPeter Wemm 		       a->q_ruser == NULL ? "<null>" : a->q_ruser);
1957c2aa98e2SPeter Wemm 		printf("\tnext=%lx, alias %lx, uid %d, gid %d\n",
1958c2aa98e2SPeter Wemm 		       (u_long) a->q_next, (u_long) a->q_alias,
1959c2aa98e2SPeter Wemm 		       (int) a->q_uid, (int) a->q_gid);
1960c2aa98e2SPeter Wemm 		printf("\tflags=%lx<", a->q_flags);
1961c2aa98e2SPeter Wemm 		firstone = TRUE;
1962c2aa98e2SPeter Wemm 		for (qfp = AddressFlags; qfp->qf_name != NULL; qfp++)
1963c2aa98e2SPeter Wemm 		{
1964c2aa98e2SPeter Wemm 			if (!bitset(qfp->qf_bit, a->q_flags))
1965c2aa98e2SPeter Wemm 				continue;
1966c2aa98e2SPeter Wemm 			if (!firstone)
1967c2aa98e2SPeter Wemm 				printf(",");
1968c2aa98e2SPeter Wemm 			firstone = FALSE;
1969c2aa98e2SPeter Wemm 			printf("%s", qfp->qf_name);
1970c2aa98e2SPeter Wemm 		}
1971c2aa98e2SPeter Wemm 		printf(">\n");
1972c2aa98e2SPeter Wemm 		printf("\towner=%s, home=\"%s\", fullname=\"%s\"\n",
1973c2aa98e2SPeter Wemm 		       a->q_owner == NULL ? "(none)" : a->q_owner,
1974c2aa98e2SPeter Wemm 		       a->q_home == NULL ? "(none)" : a->q_home,
1975c2aa98e2SPeter Wemm 		       a->q_fullname == NULL ? "(none)" : a->q_fullname);
1976c2aa98e2SPeter Wemm 		printf("\torcpt=\"%s\", statmta=%s, status=%s\n",
1977c2aa98e2SPeter Wemm 		       a->q_orcpt == NULL ? "(none)" : a->q_orcpt,
1978c2aa98e2SPeter Wemm 		       a->q_statmta == NULL ? "(none)" : a->q_statmta,
1979c2aa98e2SPeter Wemm 		       a->q_status == NULL ? "(none)" : a->q_status);
1980c2aa98e2SPeter Wemm 		printf("\trstatus=\"%s\"\n",
1981c2aa98e2SPeter Wemm 		       a->q_rstatus == NULL ? "(none)" : a->q_rstatus);
1982c2aa98e2SPeter Wemm 		printf("\tspecificity=%d, statdate=%s\n",
1983c2aa98e2SPeter Wemm 			a->q_specificity, ctime(&a->q_statdate));
1984c2aa98e2SPeter Wemm 
1985c2aa98e2SPeter Wemm 		if (!follow)
1986c2aa98e2SPeter Wemm 			return;
1987c2aa98e2SPeter Wemm 		a = a->q_next;
1988c2aa98e2SPeter Wemm 	}
1989c2aa98e2SPeter Wemm }
1990c2aa98e2SPeter Wemm /*
1991c2aa98e2SPeter Wemm **  EMPTYADDR -- return TRUE if this address is empty (``<>'')
1992c2aa98e2SPeter Wemm **
1993c2aa98e2SPeter Wemm **	Parameters:
1994c2aa98e2SPeter Wemm **		a -- pointer to the address
1995c2aa98e2SPeter Wemm **
1996c2aa98e2SPeter Wemm **	Returns:
1997c2aa98e2SPeter Wemm **		TRUE -- if this address is "empty" (i.e., no one should
1998c2aa98e2SPeter Wemm **			ever generate replies to it.
1999c2aa98e2SPeter Wemm **		FALSE -- if it is a "regular" (read: replyable) address.
2000c2aa98e2SPeter Wemm */
2001c2aa98e2SPeter Wemm 
2002c2aa98e2SPeter Wemm bool
2003c2aa98e2SPeter Wemm emptyaddr(a)
2004c2aa98e2SPeter Wemm 	register ADDRESS *a;
2005c2aa98e2SPeter Wemm {
2006c2aa98e2SPeter Wemm 	return a->q_paddr == NULL || strcmp(a->q_paddr, "<>") == 0 ||
2007c2aa98e2SPeter Wemm 	       a->q_user == NULL || strcmp(a->q_user, "<>") == 0;
2008c2aa98e2SPeter Wemm }
2009c2aa98e2SPeter Wemm /*
2010c2aa98e2SPeter Wemm **  REMOTENAME -- return the name relative to the current mailer
2011c2aa98e2SPeter Wemm **
2012c2aa98e2SPeter Wemm **	Parameters:
2013c2aa98e2SPeter Wemm **		name -- the name to translate.
2014c2aa98e2SPeter Wemm **		m -- the mailer that we want to do rewriting relative
2015c2aa98e2SPeter Wemm **			to.
2016c2aa98e2SPeter Wemm **		flags -- fine tune operations.
2017c2aa98e2SPeter Wemm **		pstat -- pointer to status word.
2018c2aa98e2SPeter Wemm **		e -- the current envelope.
2019c2aa98e2SPeter Wemm **
2020c2aa98e2SPeter Wemm **	Returns:
2021c2aa98e2SPeter Wemm **		the text string representing this address relative to
2022c2aa98e2SPeter Wemm **			the receiving mailer.
2023c2aa98e2SPeter Wemm **
2024c2aa98e2SPeter Wemm **	Side Effects:
2025c2aa98e2SPeter Wemm **		none.
2026c2aa98e2SPeter Wemm **
2027c2aa98e2SPeter Wemm **	Warnings:
2028c2aa98e2SPeter Wemm **		The text string returned is tucked away locally;
2029c2aa98e2SPeter Wemm **			copy it if you intend to save it.
2030c2aa98e2SPeter Wemm */
2031c2aa98e2SPeter Wemm 
2032c2aa98e2SPeter Wemm char *
2033c2aa98e2SPeter Wemm remotename(name, m, flags, pstat, e)
2034c2aa98e2SPeter Wemm 	char *name;
2035c2aa98e2SPeter Wemm 	struct mailer *m;
2036c2aa98e2SPeter Wemm 	int flags;
2037c2aa98e2SPeter Wemm 	int *pstat;
2038c2aa98e2SPeter Wemm 	register ENVELOPE *e;
2039c2aa98e2SPeter Wemm {
2040c2aa98e2SPeter Wemm 	register char **pvp;
2041c2aa98e2SPeter Wemm 	char *fancy;
2042c2aa98e2SPeter Wemm 	char *oldg = macvalue('g', e);
2043c2aa98e2SPeter Wemm 	int rwset;
2044c2aa98e2SPeter Wemm 	static char buf[MAXNAME + 1];
2045c2aa98e2SPeter Wemm 	char lbuf[MAXNAME + 1];
2046c2aa98e2SPeter Wemm 	char pvpbuf[PSBUFSIZE];
2047c2aa98e2SPeter Wemm 	extern char *crackaddr __P((char *));
2048c2aa98e2SPeter Wemm 
2049c2aa98e2SPeter Wemm 	if (tTd(12, 1))
2050c2aa98e2SPeter Wemm 		printf("remotename(%s)\n", name);
2051c2aa98e2SPeter Wemm 
2052c2aa98e2SPeter Wemm 	/* don't do anything if we are tagging it as special */
2053c2aa98e2SPeter Wemm 	if (bitset(RF_SENDERADDR, flags))
2054c2aa98e2SPeter Wemm 		rwset = bitset(RF_HEADERADDR, flags) ? m->m_sh_rwset
2055c2aa98e2SPeter Wemm 						     : m->m_se_rwset;
2056c2aa98e2SPeter Wemm 	else
2057c2aa98e2SPeter Wemm 		rwset = bitset(RF_HEADERADDR, flags) ? m->m_rh_rwset
2058c2aa98e2SPeter Wemm 						     : m->m_re_rwset;
2059c2aa98e2SPeter Wemm 	if (rwset < 0)
2060c2aa98e2SPeter Wemm 		return (name);
2061c2aa98e2SPeter Wemm 
2062c2aa98e2SPeter Wemm 	/*
2063c2aa98e2SPeter Wemm 	**  Do a heuristic crack of this name to extract any comment info.
2064c2aa98e2SPeter Wemm 	**	This will leave the name as a comment and a $g macro.
2065c2aa98e2SPeter Wemm 	*/
2066c2aa98e2SPeter Wemm 
2067c2aa98e2SPeter Wemm 	if (bitset(RF_CANONICAL, flags) || bitnset(M_NOCOMMENT, m->m_flags))
2068c2aa98e2SPeter Wemm 		fancy = "\201g";
2069c2aa98e2SPeter Wemm 	else
2070c2aa98e2SPeter Wemm 		fancy = crackaddr(name);
2071c2aa98e2SPeter Wemm 
2072c2aa98e2SPeter Wemm 	/*
2073c2aa98e2SPeter Wemm 	**  Turn the name into canonical form.
2074c2aa98e2SPeter Wemm 	**	Normally this will be RFC 822 style, i.e., "user@domain".
2075c2aa98e2SPeter Wemm 	**	If this only resolves to "user", and the "C" flag is
2076c2aa98e2SPeter Wemm 	**	specified in the sending mailer, then the sender's
2077c2aa98e2SPeter Wemm 	**	domain will be appended.
2078c2aa98e2SPeter Wemm 	*/
2079c2aa98e2SPeter Wemm 
2080c2aa98e2SPeter Wemm 	pvp = prescan(name, '\0', pvpbuf, sizeof pvpbuf, NULL, NULL);
2081c2aa98e2SPeter Wemm 	if (pvp == NULL)
2082c2aa98e2SPeter Wemm 		return (name);
2083c2aa98e2SPeter Wemm 	if (rewrite(pvp, 3, 0, e) == EX_TEMPFAIL)
2084c2aa98e2SPeter Wemm 		*pstat = EX_TEMPFAIL;
2085c2aa98e2SPeter Wemm 	if (bitset(RF_ADDDOMAIN, flags) && e->e_fromdomain != NULL)
2086c2aa98e2SPeter Wemm 	{
2087c2aa98e2SPeter Wemm 		/* append from domain to this address */
2088c2aa98e2SPeter Wemm 		register char **pxp = pvp;
2089c2aa98e2SPeter Wemm 
2090c2aa98e2SPeter Wemm 		/* see if there is an "@domain" in the current name */
2091c2aa98e2SPeter Wemm 		while (*pxp != NULL && strcmp(*pxp, "@") != 0)
2092c2aa98e2SPeter Wemm 			pxp++;
2093c2aa98e2SPeter Wemm 		if (*pxp == NULL)
2094c2aa98e2SPeter Wemm 		{
2095c2aa98e2SPeter Wemm 			/* no.... append the "@domain" from the sender */
2096c2aa98e2SPeter Wemm 			register char **qxq = e->e_fromdomain;
2097c2aa98e2SPeter Wemm 
2098c2aa98e2SPeter Wemm 			while ((*pxp++ = *qxq++) != NULL)
2099c2aa98e2SPeter Wemm 				continue;
2100c2aa98e2SPeter Wemm 			if (rewrite(pvp, 3, 0, e) == EX_TEMPFAIL)
2101c2aa98e2SPeter Wemm 				*pstat = EX_TEMPFAIL;
2102c2aa98e2SPeter Wemm 		}
2103c2aa98e2SPeter Wemm 	}
2104c2aa98e2SPeter Wemm 
2105c2aa98e2SPeter Wemm 	/*
2106c2aa98e2SPeter Wemm 	**  Do more specific rewriting.
2107c2aa98e2SPeter Wemm 	**	Rewrite using ruleset 1 or 2 depending on whether this is
2108c2aa98e2SPeter Wemm 	**		a sender address or not.
2109c2aa98e2SPeter Wemm 	**	Then run it through any receiving-mailer-specific rulesets.
2110c2aa98e2SPeter Wemm 	*/
2111c2aa98e2SPeter Wemm 
2112c2aa98e2SPeter Wemm 	if (bitset(RF_SENDERADDR, flags))
2113c2aa98e2SPeter Wemm 	{
2114c2aa98e2SPeter Wemm 		if (rewrite(pvp, 1, 0, e) == EX_TEMPFAIL)
2115c2aa98e2SPeter Wemm 			*pstat = EX_TEMPFAIL;
2116c2aa98e2SPeter Wemm 	}
2117c2aa98e2SPeter Wemm 	else
2118c2aa98e2SPeter Wemm 	{
2119c2aa98e2SPeter Wemm 		if (rewrite(pvp, 2, 0, e) == EX_TEMPFAIL)
2120c2aa98e2SPeter Wemm 			*pstat = EX_TEMPFAIL;
2121c2aa98e2SPeter Wemm 	}
2122c2aa98e2SPeter Wemm 	if (rwset > 0)
2123c2aa98e2SPeter Wemm 	{
2124c2aa98e2SPeter Wemm 		if (rewrite(pvp, rwset, 0, e) == EX_TEMPFAIL)
2125c2aa98e2SPeter Wemm 			*pstat = EX_TEMPFAIL;
2126c2aa98e2SPeter Wemm 	}
2127c2aa98e2SPeter Wemm 
2128c2aa98e2SPeter Wemm 	/*
2129c2aa98e2SPeter Wemm 	**  Do any final sanitation the address may require.
2130c2aa98e2SPeter Wemm 	**	This will normally be used to turn internal forms
2131c2aa98e2SPeter Wemm 	**	(e.g., user@host.LOCAL) into external form.  This
2132c2aa98e2SPeter Wemm 	**	may be used as a default to the above rules.
2133c2aa98e2SPeter Wemm 	*/
2134c2aa98e2SPeter Wemm 
2135c2aa98e2SPeter Wemm 	if (rewrite(pvp, 4, 0, e) == EX_TEMPFAIL)
2136c2aa98e2SPeter Wemm 		*pstat = EX_TEMPFAIL;
2137c2aa98e2SPeter Wemm 
2138c2aa98e2SPeter Wemm 	/*
2139c2aa98e2SPeter Wemm 	**  Now restore the comment information we had at the beginning.
2140c2aa98e2SPeter Wemm 	*/
2141c2aa98e2SPeter Wemm 
2142c2aa98e2SPeter Wemm 	cataddr(pvp, NULL, lbuf, sizeof lbuf, '\0');
2143c2aa98e2SPeter Wemm 	define('g', lbuf, e);
2144c2aa98e2SPeter Wemm 
2145c2aa98e2SPeter Wemm 	/* need to make sure route-addrs have <angle brackets> */
2146c2aa98e2SPeter Wemm 	if (bitset(RF_CANONICAL, flags) && lbuf[0] == '@')
2147c2aa98e2SPeter Wemm 		expand("<\201g>", buf, sizeof buf, e);
2148c2aa98e2SPeter Wemm 	else
2149c2aa98e2SPeter Wemm 		expand(fancy, buf, sizeof buf, e);
2150c2aa98e2SPeter Wemm 
2151c2aa98e2SPeter Wemm 	define('g', oldg, e);
2152c2aa98e2SPeter Wemm 
2153c2aa98e2SPeter Wemm 	if (tTd(12, 1))
2154c2aa98e2SPeter Wemm 		printf("remotename => `%s'\n", buf);
2155c2aa98e2SPeter Wemm 	return (buf);
2156c2aa98e2SPeter Wemm }
2157c2aa98e2SPeter Wemm /*
2158c2aa98e2SPeter Wemm **  MAPLOCALUSER -- run local username through ruleset 5 for final redirection
2159c2aa98e2SPeter Wemm **
2160c2aa98e2SPeter Wemm **	Parameters:
2161c2aa98e2SPeter Wemm **		a -- the address to map (but just the user name part).
2162c2aa98e2SPeter Wemm **		sendq -- the sendq in which to install any replacement
2163c2aa98e2SPeter Wemm **			addresses.
2164c2aa98e2SPeter Wemm **		aliaslevel -- the alias nesting depth.
2165c2aa98e2SPeter Wemm **		e -- the envelope.
2166c2aa98e2SPeter Wemm **
2167c2aa98e2SPeter Wemm **	Returns:
2168c2aa98e2SPeter Wemm **		none.
2169c2aa98e2SPeter Wemm */
2170c2aa98e2SPeter Wemm 
2171c2aa98e2SPeter Wemm #define Q_COPYFLAGS	(QPRIMARY|QBOGUSSHELL|QUNSAFEADDR|\
2172c2aa98e2SPeter Wemm 			 Q_PINGFLAGS|QHASNOTIFY|\
2173c2aa98e2SPeter Wemm 			 QRELAYED|QEXPANDED|QDELIVERED|QDELAYED)
2174c2aa98e2SPeter Wemm 
2175c2aa98e2SPeter Wemm void
2176c2aa98e2SPeter Wemm maplocaluser(a, sendq, aliaslevel, e)
2177c2aa98e2SPeter Wemm 	register ADDRESS *a;
2178c2aa98e2SPeter Wemm 	ADDRESS **sendq;
2179c2aa98e2SPeter Wemm 	int aliaslevel;
2180c2aa98e2SPeter Wemm 	ENVELOPE *e;
2181c2aa98e2SPeter Wemm {
2182c2aa98e2SPeter Wemm 	register char **pvp;
2183c2aa98e2SPeter Wemm 	register ADDRESS *a1 = NULL;
2184c2aa98e2SPeter Wemm 	auto char *delimptr;
2185c2aa98e2SPeter Wemm 	char pvpbuf[PSBUFSIZE];
2186c2aa98e2SPeter Wemm 
2187c2aa98e2SPeter Wemm 	if (tTd(29, 1))
2188c2aa98e2SPeter Wemm 	{
2189c2aa98e2SPeter Wemm 		printf("maplocaluser: ");
2190c2aa98e2SPeter Wemm 		printaddr(a, FALSE);
2191c2aa98e2SPeter Wemm 	}
2192c2aa98e2SPeter Wemm 	pvp = prescan(a->q_user, '\0', pvpbuf, sizeof pvpbuf, &delimptr, NULL);
2193c2aa98e2SPeter Wemm 	if (pvp == NULL)
2194c2aa98e2SPeter Wemm 	{
2195c2aa98e2SPeter Wemm 		if (tTd(29, 9))
2196c2aa98e2SPeter Wemm 			printf("maplocaluser: cannot prescan %s\n", a->q_user);
2197c2aa98e2SPeter Wemm 		return;
2198c2aa98e2SPeter Wemm 	}
2199c2aa98e2SPeter Wemm 
2200c2aa98e2SPeter Wemm 	define('h', a->q_host, e);
2201c2aa98e2SPeter Wemm 	define('u', a->q_user, e);
2202c2aa98e2SPeter Wemm 	define('z', a->q_home, e);
2203c2aa98e2SPeter Wemm 
2204c2aa98e2SPeter Wemm 	if (rewrite(pvp, 5, 0, e) == EX_TEMPFAIL)
2205c2aa98e2SPeter Wemm 	{
2206c2aa98e2SPeter Wemm 		if (tTd(29, 9))
2207c2aa98e2SPeter Wemm 			printf("maplocaluser: rewrite tempfail\n");
2208c2aa98e2SPeter Wemm 		a->q_flags |= QQUEUEUP;
2209c2aa98e2SPeter Wemm 		a->q_status = "4.4.3";
2210c2aa98e2SPeter Wemm 		return;
2211c2aa98e2SPeter Wemm 	}
2212c2aa98e2SPeter Wemm 	if (pvp[0] == NULL || (pvp[0][0] & 0377) != CANONNET)
2213c2aa98e2SPeter Wemm 	{
2214c2aa98e2SPeter Wemm 		if (tTd(29, 9))
2215c2aa98e2SPeter Wemm 			printf("maplocaluser: doesn't resolve\n");
2216c2aa98e2SPeter Wemm 		return;
2217c2aa98e2SPeter Wemm 	}
2218c2aa98e2SPeter Wemm 
2219c2aa98e2SPeter Wemm 	/* if non-null, mailer destination specified -- has it changed? */
2220c2aa98e2SPeter Wemm 	a1 = buildaddr(pvp, NULL, 0, e);
2221c2aa98e2SPeter Wemm 	if (a1 == NULL || sameaddr(a, a1))
2222c2aa98e2SPeter Wemm 	{
2223c2aa98e2SPeter Wemm 		if (tTd(29, 9))
2224c2aa98e2SPeter Wemm 			printf("maplocaluser: address unchanged\n");
2225c2aa98e2SPeter Wemm 		if (a1 != NULL)
2226c2aa98e2SPeter Wemm 			free(a1);
2227c2aa98e2SPeter Wemm 		return;
2228c2aa98e2SPeter Wemm 	}
2229c2aa98e2SPeter Wemm 
2230c2aa98e2SPeter Wemm 	/* make new address take on flags and print attributes of old */
2231c2aa98e2SPeter Wemm 	a1->q_flags &= ~Q_COPYFLAGS;
2232c2aa98e2SPeter Wemm 	a1->q_flags |= a->q_flags & Q_COPYFLAGS;
2233c2aa98e2SPeter Wemm 	a1->q_paddr = a->q_paddr;
2234c2aa98e2SPeter Wemm 
2235c2aa98e2SPeter Wemm 	/* mark old address as dead; insert new address */
2236c2aa98e2SPeter Wemm 	a->q_flags |= QDONTSEND;
2237c2aa98e2SPeter Wemm 	if (tTd(29, 5))
2238c2aa98e2SPeter Wemm 	{
2239c2aa98e2SPeter Wemm 		printf("maplocaluser: QDONTSEND ");
2240c2aa98e2SPeter Wemm 		printaddr(a, FALSE);
2241c2aa98e2SPeter Wemm 	}
2242c2aa98e2SPeter Wemm 	a1->q_alias = a;
2243c2aa98e2SPeter Wemm 	allocaddr(a1, RF_COPYALL, a->q_paddr);
2244c2aa98e2SPeter Wemm 	(void) recipient(a1, sendq, aliaslevel, e);
2245c2aa98e2SPeter Wemm }
2246c2aa98e2SPeter Wemm /*
2247c2aa98e2SPeter Wemm **  DEQUOTE_INIT -- initialize dequote map
2248c2aa98e2SPeter Wemm **
2249c2aa98e2SPeter Wemm **	This is a no-op.
2250c2aa98e2SPeter Wemm **
2251c2aa98e2SPeter Wemm **	Parameters:
2252c2aa98e2SPeter Wemm **		map -- the internal map structure.
2253c2aa98e2SPeter Wemm **		args -- arguments.
2254c2aa98e2SPeter Wemm **
2255c2aa98e2SPeter Wemm **	Returns:
2256c2aa98e2SPeter Wemm **		TRUE.
2257c2aa98e2SPeter Wemm */
2258c2aa98e2SPeter Wemm 
2259c2aa98e2SPeter Wemm bool
2260c2aa98e2SPeter Wemm dequote_init(map, args)
2261c2aa98e2SPeter Wemm 	MAP *map;
2262c2aa98e2SPeter Wemm 	char *args;
2263c2aa98e2SPeter Wemm {
2264c2aa98e2SPeter Wemm 	register char *p = args;
2265c2aa98e2SPeter Wemm 
2266c2aa98e2SPeter Wemm 	map->map_mflags |= MF_KEEPQUOTES;
2267c2aa98e2SPeter Wemm 	for (;;)
2268c2aa98e2SPeter Wemm 	{
2269c2aa98e2SPeter Wemm 		while (isascii(*p) && isspace(*p))
2270c2aa98e2SPeter Wemm 			p++;
2271c2aa98e2SPeter Wemm 		if (*p != '-')
2272c2aa98e2SPeter Wemm 			break;
2273c2aa98e2SPeter Wemm 		switch (*++p)
2274c2aa98e2SPeter Wemm 		{
2275c2aa98e2SPeter Wemm 		  case 'a':
2276c2aa98e2SPeter Wemm 			map->map_app = ++p;
2277c2aa98e2SPeter Wemm 			break;
2278c2aa98e2SPeter Wemm 
2279c2aa98e2SPeter Wemm 		  case 's':
2280c2aa98e2SPeter Wemm 			map->map_coldelim = *++p;
2281c2aa98e2SPeter Wemm 			break;
2282c2aa98e2SPeter Wemm 		}
2283c2aa98e2SPeter Wemm 		while (*p != '\0' && !(isascii(*p) && isspace(*p)))
2284c2aa98e2SPeter Wemm 			p++;
2285c2aa98e2SPeter Wemm 		if (*p != '\0')
2286c2aa98e2SPeter Wemm 			*p = '\0';
2287c2aa98e2SPeter Wemm 	}
2288c2aa98e2SPeter Wemm 	if (map->map_app != NULL)
2289c2aa98e2SPeter Wemm 		map->map_app = newstr(map->map_app);
2290c2aa98e2SPeter Wemm 
2291c2aa98e2SPeter Wemm 	return TRUE;
2292c2aa98e2SPeter Wemm }
2293c2aa98e2SPeter Wemm /*
2294c2aa98e2SPeter Wemm **  DEQUOTE_MAP -- unquote an address
2295c2aa98e2SPeter Wemm **
2296c2aa98e2SPeter Wemm **	Parameters:
2297c2aa98e2SPeter Wemm **		map -- the internal map structure (ignored).
2298c2aa98e2SPeter Wemm **		name -- the name to dequote.
2299c2aa98e2SPeter Wemm **		av -- arguments (ignored).
2300c2aa98e2SPeter Wemm **		statp -- pointer to status out-parameter.
2301c2aa98e2SPeter Wemm **
2302c2aa98e2SPeter Wemm **	Returns:
2303c2aa98e2SPeter Wemm **		NULL -- if there were no quotes, or if the resulting
2304c2aa98e2SPeter Wemm **			unquoted buffer would not be acceptable to prescan.
2305c2aa98e2SPeter Wemm **		else -- The dequoted buffer.
2306c2aa98e2SPeter Wemm */
2307c2aa98e2SPeter Wemm 
2308c2aa98e2SPeter Wemm /* ARGSUSED2 */
2309c2aa98e2SPeter Wemm char *
2310c2aa98e2SPeter Wemm dequote_map(map, name, av, statp)
2311c2aa98e2SPeter Wemm 	MAP *map;
2312c2aa98e2SPeter Wemm 	char *name;
2313c2aa98e2SPeter Wemm 	char **av;
2314c2aa98e2SPeter Wemm 	int *statp;
2315c2aa98e2SPeter Wemm {
2316c2aa98e2SPeter Wemm 	register char *p;
2317c2aa98e2SPeter Wemm 	register char *q;
2318c2aa98e2SPeter Wemm 	register char c;
2319c2aa98e2SPeter Wemm 	int anglecnt = 0;
2320c2aa98e2SPeter Wemm 	int cmntcnt = 0;
2321c2aa98e2SPeter Wemm 	int quotecnt = 0;
2322c2aa98e2SPeter Wemm 	int spacecnt = 0;
2323c2aa98e2SPeter Wemm 	bool quotemode = FALSE;
2324c2aa98e2SPeter Wemm 	bool bslashmode = FALSE;
2325c2aa98e2SPeter Wemm 	char spacesub = map->map_coldelim;
2326c2aa98e2SPeter Wemm 
2327c2aa98e2SPeter Wemm 	for (p = q = name; (c = *p++) != '\0'; )
2328c2aa98e2SPeter Wemm 	{
2329c2aa98e2SPeter Wemm 		if (bslashmode)
2330c2aa98e2SPeter Wemm 		{
2331c2aa98e2SPeter Wemm 			bslashmode = FALSE;
2332c2aa98e2SPeter Wemm 			*q++ = c;
2333c2aa98e2SPeter Wemm 			continue;
2334c2aa98e2SPeter Wemm 		}
2335c2aa98e2SPeter Wemm 
2336c2aa98e2SPeter Wemm 		if (c == ' ' && spacesub != '\0')
2337c2aa98e2SPeter Wemm 			c = spacesub;
2338c2aa98e2SPeter Wemm 
2339c2aa98e2SPeter Wemm 		switch (c)
2340c2aa98e2SPeter Wemm 		{
2341c2aa98e2SPeter Wemm 		  case '\\':
2342c2aa98e2SPeter Wemm 			bslashmode = TRUE;
2343c2aa98e2SPeter Wemm 			break;
2344c2aa98e2SPeter Wemm 
2345c2aa98e2SPeter Wemm 		  case '(':
2346c2aa98e2SPeter Wemm 			cmntcnt++;
2347c2aa98e2SPeter Wemm 			break;
2348c2aa98e2SPeter Wemm 
2349c2aa98e2SPeter Wemm 		  case ')':
2350c2aa98e2SPeter Wemm 			if (cmntcnt-- <= 0)
2351c2aa98e2SPeter Wemm 				return NULL;
2352c2aa98e2SPeter Wemm 			break;
2353c2aa98e2SPeter Wemm 
2354c2aa98e2SPeter Wemm 		  case ' ':
2355c2aa98e2SPeter Wemm 			spacecnt++;
2356c2aa98e2SPeter Wemm 			break;
2357c2aa98e2SPeter Wemm 		}
2358c2aa98e2SPeter Wemm 
2359c2aa98e2SPeter Wemm 		if (cmntcnt > 0)
2360c2aa98e2SPeter Wemm 		{
2361c2aa98e2SPeter Wemm 			*q++ = c;
2362c2aa98e2SPeter Wemm 			continue;
2363c2aa98e2SPeter Wemm 		}
2364c2aa98e2SPeter Wemm 
2365c2aa98e2SPeter Wemm 		switch (c)
2366c2aa98e2SPeter Wemm 		{
2367c2aa98e2SPeter Wemm 		  case '"':
2368c2aa98e2SPeter Wemm 			quotemode = !quotemode;
2369c2aa98e2SPeter Wemm 			quotecnt++;
2370c2aa98e2SPeter Wemm 			continue;
2371c2aa98e2SPeter Wemm 
2372c2aa98e2SPeter Wemm 		  case '<':
2373c2aa98e2SPeter Wemm 			anglecnt++;
2374c2aa98e2SPeter Wemm 			break;
2375c2aa98e2SPeter Wemm 
2376c2aa98e2SPeter Wemm 		  case '>':
2377c2aa98e2SPeter Wemm 			if (anglecnt-- <= 0)
2378c2aa98e2SPeter Wemm 				return NULL;
2379c2aa98e2SPeter Wemm 			break;
2380c2aa98e2SPeter Wemm 		}
2381c2aa98e2SPeter Wemm 		*q++ = c;
2382c2aa98e2SPeter Wemm 	}
2383c2aa98e2SPeter Wemm 
2384c2aa98e2SPeter Wemm 	if (anglecnt != 0 || cmntcnt != 0 || bslashmode ||
2385c2aa98e2SPeter Wemm 	    quotemode || quotecnt <= 0 || spacecnt != 0)
2386c2aa98e2SPeter Wemm 		return NULL;
2387c2aa98e2SPeter Wemm 	*q++ = '\0';
2388c2aa98e2SPeter Wemm 	return map_rewrite(map, name, strlen(name), NULL);
2389c2aa98e2SPeter Wemm }
2390c2aa98e2SPeter Wemm /*
2391c2aa98e2SPeter Wemm **  RSCHECK -- check string(s) for validity using rewriting sets
2392c2aa98e2SPeter Wemm **
2393c2aa98e2SPeter Wemm **	Parameters:
2394c2aa98e2SPeter Wemm **		rwset -- the rewriting set to use.
2395c2aa98e2SPeter Wemm **		p1 -- the first string to check.
2396c2aa98e2SPeter Wemm **		p2 -- the second string to check -- may be null.
2397c2aa98e2SPeter Wemm **		e -- the current envelope.
2398c2aa98e2SPeter Wemm **
2399c2aa98e2SPeter Wemm **	Returns:
2400c2aa98e2SPeter Wemm **		EX_OK -- if the rwset doesn't resolve to $#error
2401c2aa98e2SPeter Wemm **		else -- the failure status (message printed)
2402c2aa98e2SPeter Wemm */
2403c2aa98e2SPeter Wemm 
2404c2aa98e2SPeter Wemm int
2405c2aa98e2SPeter Wemm rscheck(rwset, p1, p2, e)
2406c2aa98e2SPeter Wemm 	char *rwset;
2407c2aa98e2SPeter Wemm 	char *p1;
2408c2aa98e2SPeter Wemm 	char *p2;
2409c2aa98e2SPeter Wemm 	ENVELOPE *e;
2410c2aa98e2SPeter Wemm {
2411c2aa98e2SPeter Wemm 	char *buf;
2412c2aa98e2SPeter Wemm 	int bufsize;
2413c2aa98e2SPeter Wemm 	int saveexitstat;
2414c2aa98e2SPeter Wemm 	int rstat = EX_OK;
2415c2aa98e2SPeter Wemm 	char **pvp;
2416c2aa98e2SPeter Wemm 	int rsno;
2417c2aa98e2SPeter Wemm 	bool discard = FALSE;
2418c2aa98e2SPeter Wemm 	auto ADDRESS a1;
2419c2aa98e2SPeter Wemm 	bool saveQuickAbort = QuickAbort;
2420c2aa98e2SPeter Wemm 	bool saveSuprErrs = SuprErrs;
2421c2aa98e2SPeter Wemm 	char buf0[MAXLINE];
2422c2aa98e2SPeter Wemm 	char pvpbuf[PSBUFSIZE];
2423c2aa98e2SPeter Wemm 	extern char MsgBuf[];
2424c2aa98e2SPeter Wemm 
2425c2aa98e2SPeter Wemm 	if (tTd(48, 2))
2426c2aa98e2SPeter Wemm 		printf("rscheck(%s, %s, %s)\n", rwset, p1,
2427c2aa98e2SPeter Wemm 			p2 == NULL ? "(NULL)" : p2);
2428c2aa98e2SPeter Wemm 
2429c2aa98e2SPeter Wemm 	rsno = strtorwset(rwset, NULL, ST_FIND);
2430c2aa98e2SPeter Wemm 	if (rsno < 0)
2431c2aa98e2SPeter Wemm 		return EX_OK;
2432c2aa98e2SPeter Wemm 
2433c2aa98e2SPeter Wemm 	if (p2 != NULL)
2434c2aa98e2SPeter Wemm 	{
2435c2aa98e2SPeter Wemm 		bufsize = strlen(p1) + strlen(p2) + 2;
2436c2aa98e2SPeter Wemm 		if (bufsize > sizeof buf0)
2437c2aa98e2SPeter Wemm 			buf = xalloc(bufsize);
2438c2aa98e2SPeter Wemm 		else
2439c2aa98e2SPeter Wemm 		{
2440c2aa98e2SPeter Wemm 			buf = buf0;
2441c2aa98e2SPeter Wemm 			bufsize = sizeof buf0;
2442c2aa98e2SPeter Wemm 		}
2443c2aa98e2SPeter Wemm 		(void) snprintf(buf, bufsize, "%s%c%s", p1, CONDELSE, p2);
2444c2aa98e2SPeter Wemm 	}
2445c2aa98e2SPeter Wemm 	else
2446c2aa98e2SPeter Wemm 	{
2447c2aa98e2SPeter Wemm 		bufsize = strlen(p1) + 1;
2448c2aa98e2SPeter Wemm 		if (bufsize > sizeof buf0)
2449c2aa98e2SPeter Wemm 			buf = xalloc(bufsize);
2450c2aa98e2SPeter Wemm 		else
2451c2aa98e2SPeter Wemm 		{
2452c2aa98e2SPeter Wemm 			buf = buf0;
2453c2aa98e2SPeter Wemm 			bufsize = sizeof buf0;
2454c2aa98e2SPeter Wemm 		}
2455c2aa98e2SPeter Wemm 		(void) snprintf(buf, bufsize, "%s", p1);
2456c2aa98e2SPeter Wemm 	}
2457c2aa98e2SPeter Wemm 	SuprErrs = TRUE;
2458c2aa98e2SPeter Wemm 	QuickAbort = FALSE;
2459c2aa98e2SPeter Wemm 	pvp = prescan(buf, '\0', pvpbuf, sizeof pvpbuf, NULL, NULL);
2460c2aa98e2SPeter Wemm 	SuprErrs = saveSuprErrs;
2461c2aa98e2SPeter Wemm 	if (pvp == NULL)
2462c2aa98e2SPeter Wemm 	{
2463c2aa98e2SPeter Wemm 		if (tTd(48, 2))
2464c2aa98e2SPeter Wemm 			printf("rscheck: cannot prescan input\n");
2465c2aa98e2SPeter Wemm /*
2466c2aa98e2SPeter Wemm 		syserr("rscheck: cannot prescan input: \"%s\"",
2467c2aa98e2SPeter Wemm 			shortenstring(buf, MAXSHORTSTR));
2468c2aa98e2SPeter Wemm 		rstat = EX_DATAERR;
2469c2aa98e2SPeter Wemm */
2470c2aa98e2SPeter Wemm 		goto finis;
2471c2aa98e2SPeter Wemm 	}
2472c2aa98e2SPeter Wemm 	(void) rewrite(pvp, rsno, 0, e);
2473c2aa98e2SPeter Wemm 	if (pvp[0] == NULL || (pvp[0][0] & 0377) != CANONNET ||
2474c2aa98e2SPeter Wemm 	    pvp[1] == NULL || (strcmp(pvp[1], "error") != 0 &&
2475c2aa98e2SPeter Wemm 			       strcmp(pvp[1], "discard") != 0))
2476c2aa98e2SPeter Wemm 	{
2477c2aa98e2SPeter Wemm 		goto finis;
2478c2aa98e2SPeter Wemm 	}
2479c2aa98e2SPeter Wemm 
2480c2aa98e2SPeter Wemm 	if (strcmp(pvp[1], "discard") == 0)
2481c2aa98e2SPeter Wemm 	{
2482c2aa98e2SPeter Wemm 		if (tTd(48, 2))
2483c2aa98e2SPeter Wemm 			printf("rscheck: discard mailer selected\n");
2484c2aa98e2SPeter Wemm 		e->e_flags |= EF_DISCARD;
2485c2aa98e2SPeter Wemm 		discard = TRUE;
2486c2aa98e2SPeter Wemm 	}
2487c2aa98e2SPeter Wemm 	else
2488c2aa98e2SPeter Wemm 	{
2489c2aa98e2SPeter Wemm 		int savelogusrerrs = LogUsrErrs;
2490c2aa98e2SPeter Wemm 		static bool logged = FALSE;
2491c2aa98e2SPeter Wemm 
2492c2aa98e2SPeter Wemm 		/* got an error -- process it */
2493c2aa98e2SPeter Wemm 		saveexitstat = ExitStat;
2494c2aa98e2SPeter Wemm 		LogUsrErrs = FALSE;
2495c2aa98e2SPeter Wemm 		(void) buildaddr(pvp, &a1, 0, e);
2496c2aa98e2SPeter Wemm 		LogUsrErrs = savelogusrerrs;
2497c2aa98e2SPeter Wemm 		rstat = ExitStat;
2498c2aa98e2SPeter Wemm 		ExitStat = saveexitstat;
2499c2aa98e2SPeter Wemm 		if (!logged)
2500c2aa98e2SPeter Wemm 		{
2501c2aa98e2SPeter Wemm 			markstats(e, &a1, TRUE);
2502c2aa98e2SPeter Wemm 			logged = TRUE;
2503c2aa98e2SPeter Wemm 		}
2504c2aa98e2SPeter Wemm 	}
2505c2aa98e2SPeter Wemm 
2506c2aa98e2SPeter Wemm 	if (LogLevel >= 4)
2507c2aa98e2SPeter Wemm 	{
2508c2aa98e2SPeter Wemm 		char *relay;
2509c2aa98e2SPeter Wemm 		char *p;
2510c2aa98e2SPeter Wemm 		char lbuf[MAXLINE];
2511c2aa98e2SPeter Wemm 
2512c2aa98e2SPeter Wemm 		p = lbuf;
2513c2aa98e2SPeter Wemm 		if (p2 != NULL)
2514c2aa98e2SPeter Wemm 		{
2515c2aa98e2SPeter Wemm 			snprintf(p, SPACELEFT(lbuf, p),
2516c2aa98e2SPeter Wemm 				", arg2=%s",
2517c2aa98e2SPeter Wemm 				p2);
2518c2aa98e2SPeter Wemm 			p += strlen(p);
2519c2aa98e2SPeter Wemm 		}
2520c2aa98e2SPeter Wemm 		if ((relay = macvalue('_', e)) != NULL)
2521c2aa98e2SPeter Wemm 		{
2522c2aa98e2SPeter Wemm 			snprintf(p, SPACELEFT(lbuf, p),
2523c2aa98e2SPeter Wemm 				", relay=%s", relay);
2524c2aa98e2SPeter Wemm 			p += strlen(p);
2525c2aa98e2SPeter Wemm 		}
2526c2aa98e2SPeter Wemm 		*p = '\0';
2527c2aa98e2SPeter Wemm 		if (discard)
2528c2aa98e2SPeter Wemm 			sm_syslog(LOG_NOTICE, e->e_id,
2529c2aa98e2SPeter Wemm 				  "ruleset=%s, arg1=%s%s, discard",
2530c2aa98e2SPeter Wemm 				  rwset, p1, lbuf);
2531c2aa98e2SPeter Wemm 		else
2532c2aa98e2SPeter Wemm 			sm_syslog(LOG_NOTICE, e->e_id,
2533c2aa98e2SPeter Wemm 				  "ruleset=%s, arg1=%s%s, reject=%s",
2534c2aa98e2SPeter Wemm 				  rwset, p1, lbuf, MsgBuf);
2535c2aa98e2SPeter Wemm 	}
2536c2aa98e2SPeter Wemm 
2537c2aa98e2SPeter Wemm  finis:
2538c2aa98e2SPeter Wemm 	/* clean up */
2539c2aa98e2SPeter Wemm 	QuickAbort = saveQuickAbort;
2540c2aa98e2SPeter Wemm 	setstat(rstat);
2541c2aa98e2SPeter Wemm 	if (buf != buf0)
2542c2aa98e2SPeter Wemm 		free(buf);
2543c2aa98e2SPeter Wemm 
2544c2aa98e2SPeter Wemm 	if (rstat != EX_OK && QuickAbort)
2545c2aa98e2SPeter Wemm 		longjmp(TopFrame, 2);
2546c2aa98e2SPeter Wemm 	return rstat;
2547c2aa98e2SPeter Wemm }
2548