1 /*
2  * Copyright (c) 1983 Eric P. Allman
3  * Copyright (c) 1988, 1993
4  *	The Regents of the University of California.  All rights reserved.
5  *
6  * %sccs.include.redist.c%
7  */
8 
9 #ifndef lint
10 static char sccsid[] = "@(#)parseaddr.c	8.56 (Berkeley) 03/14/95";
11 #endif /* not lint */
12 
13 # include "sendmail.h"
14 
15 /*
16 **  PARSEADDR -- Parse an address
17 **
18 **	Parses an address and breaks it up into three parts: a
19 **	net to transmit the message on, the host to transmit it
20 **	to, and a user on that host.  These are loaded into an
21 **	ADDRESS header with the values squirreled away if necessary.
22 **	The "user" part may not be a real user; the process may
23 **	just reoccur on that machine.  For example, on a machine
24 **	with an arpanet connection, the address
25 **		csvax.bill@berkeley
26 **	will break up to a "user" of 'csvax.bill' and a host
27 **	of 'berkeley' -- to be transmitted over the arpanet.
28 **
29 **	Parameters:
30 **		addr -- the address to parse.
31 **		a -- a pointer to the address descriptor buffer.
32 **			If NULL, a header will be created.
33 **		flags -- describe detail for parsing.  See RF_ definitions
34 **			in sendmail.h.
35 **		delim -- the character to terminate the address, passed
36 **			to prescan.
37 **		delimptr -- if non-NULL, set to the location of the
38 **			delim character that was found.
39 **		e -- the envelope that will contain this address.
40 **
41 **	Returns:
42 **		A pointer to the address descriptor header (`a' if
43 **			`a' is non-NULL).
44 **		NULL on error.
45 **
46 **	Side Effects:
47 **		none
48 */
49 
50 /* following delimiters are inherent to the internal algorithms */
51 # define DELIMCHARS	"()<>,;\r\n"	/* default word delimiters */
52 
53 ADDRESS *
54 parseaddr(addr, a, flags, delim, delimptr, e)
55 	char *addr;
56 	register ADDRESS *a;
57 	int flags;
58 	int delim;
59 	char **delimptr;
60 	register ENVELOPE *e;
61 {
62 	register char **pvp;
63 	auto char *delimptrbuf;
64 	bool queueup;
65 	char pvpbuf[PSBUFSIZE];
66 	extern ADDRESS *buildaddr();
67 	extern bool invalidaddr();
68 
69 	/*
70 	**  Initialize and prescan address.
71 	*/
72 
73 	e->e_to = addr;
74 	if (tTd(20, 1))
75 		printf("\n--parseaddr(%s)\n", addr);
76 
77 	if (delimptr == NULL)
78 		delimptr = &delimptrbuf;
79 
80 	pvp = prescan(addr, delim, pvpbuf, sizeof pvpbuf, delimptr);
81 	if (pvp == NULL)
82 	{
83 		if (tTd(20, 1))
84 			printf("parseaddr-->NULL\n");
85 		return (NULL);
86 	}
87 
88 	if (invalidaddr(addr, delim == '\0' ? NULL : *delimptr))
89 	{
90 		if (tTd(20, 1))
91 			printf("parseaddr-->bad address\n");
92 		return NULL;
93 	}
94 
95 	/*
96 	**  Save addr if we are going to have to.
97 	**
98 	**	We have to do this early because there is a chance that
99 	**	the map lookups in the rewriting rules could clobber
100 	**	static memory somewhere.
101 	*/
102 
103 	if (bitset(RF_COPYPADDR, flags) && addr != NULL)
104 	{
105 		char savec = **delimptr;
106 
107 		if (savec != '\0')
108 			**delimptr = '\0';
109 		e->e_to = addr = newstr(addr);
110 		if (savec != '\0')
111 			**delimptr = savec;
112 	}
113 
114 	/*
115 	**  Apply rewriting rules.
116 	**	Ruleset 0 does basic parsing.  It must resolve.
117 	*/
118 
119 	queueup = FALSE;
120 	if (rewrite(pvp, 3, 0, e) == EX_TEMPFAIL)
121 		queueup = TRUE;
122 	if (rewrite(pvp, 0, 0, e) == EX_TEMPFAIL)
123 		queueup = TRUE;
124 
125 
126 	/*
127 	**  Build canonical address from pvp.
128 	*/
129 
130 	a = buildaddr(pvp, a, flags, e);
131 
132 	/*
133 	**  Make local copies of the host & user and then
134 	**  transport them out.
135 	*/
136 
137 	allocaddr(a, flags, addr);
138 	if (bitset(QBADADDR, a->q_flags))
139 		return a;
140 
141 	/*
142 	**  If there was a parsing failure, mark it for queueing.
143 	*/
144 
145 	if (queueup)
146 	{
147 		char *msg = "Transient parse error -- message queued for future delivery";
148 
149 		if (tTd(20, 1))
150 			printf("parseaddr: queuing message\n");
151 		message(msg);
152 		if (e->e_message == NULL)
153 			e->e_message = newstr(msg);
154 		a->q_flags |= QQUEUEUP;
155 		a->q_status = "4.4.3";
156 	}
157 
158 	/*
159 	**  Compute return value.
160 	*/
161 
162 	if (tTd(20, 1))
163 	{
164 		printf("parseaddr-->");
165 		printaddr(a, FALSE);
166 	}
167 
168 	return (a);
169 }
170 /*
171 **  INVALIDADDR -- check for address containing meta-characters
172 **
173 **	Parameters:
174 **		addr -- the address to check.
175 **
176 **	Returns:
177 **		TRUE -- if the address has any "wierd" characters
178 **		FALSE -- otherwise.
179 */
180 
181 bool
182 invalidaddr(addr, delimptr)
183 	register char *addr;
184 	char *delimptr;
185 {
186 	char savedelim = '\0';
187 
188 	if (delimptr != NULL)
189 	{
190 		savedelim = *delimptr;
191 		if (savedelim != '\0')
192 			*delimptr = '\0';
193 	}
194 #if 0
195 	/* for testing.... */
196 	if (strcmp(addr, "INvalidADDR") == 0)
197 	{
198 		usrerr("553 INvalid ADDRess");
199 		goto addrfailure;
200 	}
201 #endif
202 	for (; *addr != '\0'; addr++)
203 	{
204 		if ((*addr & 0340) == 0200)
205 			break;
206 	}
207 	if (*addr == '\0')
208 	{
209 		if (delimptr != NULL && savedelim != '\0')
210 			*delimptr = savedelim;
211 		return FALSE;
212 	}
213 	setstat(EX_USAGE);
214 	usrerr("553 Address contained invalid control characters");
215   addrfailure:
216 	if (delimptr != NULL && savedelim != '\0')
217 		*delimptr = savedelim;
218 	return TRUE;
219 }
220 /*
221 **  ALLOCADDR -- do local allocations of address on demand.
222 **
223 **	Also lowercases the host name if requested.
224 **
225 **	Parameters:
226 **		a -- the address to reallocate.
227 **		flags -- the copy flag (see RF_ definitions in sendmail.h
228 **			for a description).
229 **		paddr -- the printname of the address.
230 **
231 **	Returns:
232 **		none.
233 **
234 **	Side Effects:
235 **		Copies portions of a into local buffers as requested.
236 */
237 
238 allocaddr(a, flags, paddr)
239 	register ADDRESS *a;
240 	int flags;
241 	char *paddr;
242 {
243 	if (tTd(24, 4))
244 		printf("allocaddr(flags=%x, paddr=%s)\n", flags, paddr);
245 
246 	a->q_paddr = paddr;
247 
248 	if (a->q_user == NULL)
249 		a->q_user = "";
250 	if (a->q_host == NULL)
251 		a->q_host = "";
252 
253 	if (bitset(RF_COPYPARSE, flags))
254 	{
255 		a->q_host = newstr(a->q_host);
256 		if (a->q_user != a->q_paddr)
257 			a->q_user = newstr(a->q_user);
258 	}
259 
260 	if (a->q_paddr == NULL)
261 		a->q_paddr = a->q_user;
262 }
263 /*
264 **  PRESCAN -- Prescan name and make it canonical
265 **
266 **	Scans a name and turns it into a set of tokens.  This process
267 **	deletes blanks and comments (in parentheses).
268 **
269 **	This routine knows about quoted strings and angle brackets.
270 **
271 **	There are certain subtleties to this routine.  The one that
272 **	comes to mind now is that backslashes on the ends of names
273 **	are silently stripped off; this is intentional.  The problem
274 **	is that some versions of sndmsg (like at LBL) set the kill
275 **	character to something other than @ when reading addresses;
276 **	so people type "csvax.eric\@berkeley" -- which screws up the
277 **	berknet mailer.
278 **
279 **	Parameters:
280 **		addr -- the name to chomp.
281 **		delim -- the delimiter for the address, normally
282 **			'\0' or ','; \0 is accepted in any case.
283 **			If '\t' then we are reading the .cf file.
284 **		pvpbuf -- place to put the saved text -- note that
285 **			the pointers are static.
286 **		pvpbsize -- size of pvpbuf.
287 **		delimptr -- if non-NULL, set to the location of the
288 **			terminating delimiter.
289 **
290 **	Returns:
291 **		A pointer to a vector of tokens.
292 **		NULL on error.
293 */
294 
295 /* states and character types */
296 # define OPR		0	/* operator */
297 # define ATM		1	/* atom */
298 # define QST		2	/* in quoted string */
299 # define SPC		3	/* chewing up spaces */
300 # define ONE		4	/* pick up one character */
301 
302 # define NSTATES	5	/* number of states */
303 # define TYPE		017	/* mask to select state type */
304 
305 /* meta bits for table */
306 # define M		020	/* meta character; don't pass through */
307 # define B		040	/* cause a break */
308 # define MB		M|B	/* meta-break */
309 
310 static short StateTab[NSTATES][NSTATES] =
311 {
312    /*	oldst	chtype>	OPR	ATM	QST	SPC	ONE	*/
313 	/*OPR*/		OPR|B,	ATM|B,	QST|B,	SPC|MB,	ONE|B,
314 	/*ATM*/		OPR|B,	ATM,	QST|B,	SPC|MB,	ONE|B,
315 	/*QST*/		QST,	QST,	OPR,	QST,	QST,
316 	/*SPC*/		OPR,	ATM,	QST,	SPC|M,	ONE,
317 	/*ONE*/		OPR,	OPR,	OPR,	OPR,	OPR,
318 };
319 
320 /* token type table -- it gets modified with $o characters */
321 static TokTypeTab[256] =
322 {
323 	ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,SPC,SPC,SPC,SPC,SPC,ATM,ATM,
324 	ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,
325 	SPC,ATM,QST,ATM,ATM,ATM,ATM,ATM,ATM,SPC,ATM,ATM,ATM,ATM,ATM,ATM,
326 	ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,
327 	ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,
328 	ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,
329 	ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,
330 	ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,
331 	OPR,OPR,ONE,OPR,OPR,OPR,OPR,OPR,OPR,OPR,OPR,OPR,OPR,OPR,OPR,OPR,
332 	OPR,OPR,OPR,ONE,ONE,ONE,OPR,OPR,OPR,OPR,OPR,OPR,OPR,OPR,OPR,OPR,
333 	ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,
334 	ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,
335 	ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,
336 	ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,
337 	ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,
338 	ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,
339 };
340 
341 #define toktype(c)	((int) TokTypeTab[(c) & 0xff])
342 
343 
344 # define NOCHAR		-1	/* signal nothing in lookahead token */
345 
346 char **
347 prescan(addr, delim, pvpbuf, pvpbsize, delimptr)
348 	char *addr;
349 	int delim;
350 	char pvpbuf[];
351 	char **delimptr;
352 {
353 	register char *p;
354 	register char *q;
355 	register int c;
356 	char **avp;
357 	bool bslashmode;
358 	int cmntcnt;
359 	int anglecnt;
360 	char *tok;
361 	int state;
362 	int newstate;
363 	char *saveto = CurEnv->e_to;
364 	static char *av[MAXATOM+1];
365 	static char firsttime = TRUE;
366 	extern int errno;
367 
368 	if (firsttime)
369 	{
370 		/* initialize the token type table */
371 		char obuf[50];
372 
373 		firsttime = FALSE;
374 		expand("\201o", obuf, &obuf[sizeof obuf - sizeof DELIMCHARS], CurEnv);
375 		strcat(obuf, DELIMCHARS);
376 		for (p = obuf; *p != '\0'; p++)
377 		{
378 			if (TokTypeTab[*p & 0xff] == ATM)
379 				TokTypeTab[*p & 0xff] = OPR;
380 		}
381 	}
382 
383 	/* make sure error messages don't have garbage on them */
384 	errno = 0;
385 
386 	q = pvpbuf;
387 	bslashmode = FALSE;
388 	cmntcnt = 0;
389 	anglecnt = 0;
390 	avp = av;
391 	state = ATM;
392 	c = NOCHAR;
393 	p = addr;
394 	CurEnv->e_to = p;
395 	if (tTd(22, 11))
396 	{
397 		printf("prescan: ");
398 		xputs(p);
399 		(void) putchar('\n');
400 	}
401 
402 	do
403 	{
404 		/* read a token */
405 		tok = q;
406 		for (;;)
407 		{
408 			/* store away any old lookahead character */
409 			if (c != NOCHAR && !bslashmode)
410 			{
411 				/* see if there is room */
412 				if (q >= &pvpbuf[pvpbsize - 5])
413 				{
414 					usrerr("553 Address too long");
415 					if (strlen(addr) > MAXNAME)
416 						addr[MAXNAME] = '\0';
417 	returnnull:
418 					if (delimptr != NULL)
419 						*delimptr = p;
420 					CurEnv->e_to = saveto;
421 					return (NULL);
422 				}
423 
424 				/* squirrel it away */
425 				*q++ = c;
426 			}
427 
428 			/* read a new input character */
429 			c = *p++;
430 			if (c == '\0')
431 			{
432 				/* diagnose and patch up bad syntax */
433 				if (state == QST)
434 				{
435 					usrerr("653 Unbalanced '\"'");
436 					c = '"';
437 				}
438 				else if (cmntcnt > 0)
439 				{
440 					usrerr("653 Unbalanced '('");
441 					c = ')';
442 				}
443 				else if (anglecnt > 0)
444 				{
445 					c = '>';
446 					usrerr("653 Unbalanced '<'");
447 				}
448 				else
449 					break;
450 
451 				p--;
452 			}
453 			else if (c == delim && anglecnt <= 0 &&
454 					cmntcnt <= 0 && state != QST)
455 				break;
456 
457 			if (tTd(22, 101))
458 				printf("c=%c, s=%d; ", c, state);
459 
460 			/* chew up special characters */
461 			*q = '\0';
462 			if (bslashmode)
463 			{
464 				bslashmode = FALSE;
465 
466 				/* kludge \! for naive users */
467 				if (cmntcnt > 0)
468 				{
469 					c = NOCHAR;
470 					continue;
471 				}
472 				else if (c != '!' || state == QST)
473 				{
474 					*q++ = '\\';
475 					continue;
476 				}
477 			}
478 
479 			if (c == '\\')
480 			{
481 				bslashmode = TRUE;
482 			}
483 			else if (state == QST)
484 			{
485 				/* do nothing, just avoid next clauses */
486 			}
487 			else if (c == '(')
488 			{
489 				cmntcnt++;
490 				c = NOCHAR;
491 			}
492 			else if (c == ')')
493 			{
494 				if (cmntcnt <= 0)
495 				{
496 					usrerr("653 Unbalanced ')'");
497 					c = NOCHAR;
498 				}
499 				else
500 					cmntcnt--;
501 			}
502 			else if (cmntcnt > 0)
503 				c = NOCHAR;
504 			else if (c == '<')
505 				anglecnt++;
506 			else if (c == '>')
507 			{
508 				if (anglecnt <= 0)
509 				{
510 					usrerr("653 Unbalanced '>'");
511 					c = NOCHAR;
512 				}
513 				else
514 					anglecnt--;
515 			}
516 			else if (delim == ' ' && isascii(c) && isspace(c))
517 				c = ' ';
518 
519 			if (c == NOCHAR)
520 				continue;
521 
522 			/* see if this is end of input */
523 			if (c == delim && anglecnt <= 0 && state != QST)
524 				break;
525 
526 			newstate = StateTab[state][toktype(c)];
527 			if (tTd(22, 101))
528 				printf("ns=%02o\n", newstate);
529 			state = newstate & TYPE;
530 			if (bitset(M, newstate))
531 				c = NOCHAR;
532 			if (bitset(B, newstate))
533 				break;
534 		}
535 
536 		/* new token */
537 		if (tok != q)
538 		{
539 			*q++ = '\0';
540 			if (tTd(22, 36))
541 			{
542 				printf("tok=");
543 				xputs(tok);
544 				(void) putchar('\n');
545 			}
546 			if (avp >= &av[MAXATOM])
547 			{
548 				syserr("553 prescan: too many tokens");
549 				goto returnnull;
550 			}
551 			if (q - tok > MAXNAME)
552 			{
553 				syserr("553 prescan: token too long");
554 				goto returnnull;
555 			}
556 			*avp++ = tok;
557 		}
558 	} while (c != '\0' && (c != delim || anglecnt > 0));
559 	*avp = NULL;
560 	p--;
561 	if (delimptr != NULL)
562 		*delimptr = p;
563 	if (tTd(22, 12))
564 	{
565 		printf("prescan==>");
566 		printav(av);
567 	}
568 	CurEnv->e_to = saveto;
569 	if (av[0] == NULL)
570 	{
571 		if (tTd(22, 1))
572 			printf("prescan: null leading token\n");
573 		return (NULL);
574 	}
575 	return (av);
576 }
577 /*
578 **  REWRITE -- apply rewrite rules to token vector.
579 **
580 **	This routine is an ordered production system.  Each rewrite
581 **	rule has a LHS (called the pattern) and a RHS (called the
582 **	rewrite); 'rwr' points the the current rewrite rule.
583 **
584 **	For each rewrite rule, 'avp' points the address vector we
585 **	are trying to match against, and 'pvp' points to the pattern.
586 **	If pvp points to a special match value (MATCHZANY, MATCHANY,
587 **	MATCHONE, MATCHCLASS, MATCHNCLASS) then the address in avp
588 **	matched is saved away in the match vector (pointed to by 'mvp').
589 **
590 **	When a match between avp & pvp does not match, we try to
591 **	back out.  If we back up over MATCHONE, MATCHCLASS, or MATCHNCLASS
592 **	we must also back out the match in mvp.  If we reach a
593 **	MATCHANY or MATCHZANY we just extend the match and start
594 **	over again.
595 **
596 **	When we finally match, we rewrite the address vector
597 **	and try over again.
598 **
599 **	Parameters:
600 **		pvp -- pointer to token vector.
601 **		ruleset -- the ruleset to use for rewriting.
602 **		reclevel -- recursion level (to catch loops).
603 **		e -- the current envelope.
604 **
605 **	Returns:
606 **		A status code.  If EX_TEMPFAIL, higher level code should
607 **			attempt recovery.
608 **
609 **	Side Effects:
610 **		pvp is modified.
611 */
612 
613 struct match
614 {
615 	char	**first;	/* first token matched */
616 	char	**last;		/* last token matched */
617 	char	**pattern;	/* pointer to pattern */
618 };
619 
620 # define MAXMATCH	9	/* max params per rewrite */
621 
622 # ifndef MAXRULERECURSION
623 #  define MAXRULERECURSION	50	/* max recursion depth */
624 # endif
625 
626 
627 int
628 rewrite(pvp, ruleset, reclevel, e)
629 	char **pvp;
630 	int ruleset;
631 	int reclevel;
632 	register ENVELOPE *e;
633 {
634 	register char *ap;		/* address pointer */
635 	register char *rp;		/* rewrite pointer */
636 	register char **avp;		/* address vector pointer */
637 	register char **rvp;		/* rewrite vector pointer */
638 	register struct match *mlp;	/* cur ptr into mlist */
639 	register struct rewrite *rwr;	/* pointer to current rewrite rule */
640 	int ruleno;			/* current rule number */
641 	int rstat = EX_OK;		/* return status */
642 	int loopcount;
643 	struct match mlist[MAXMATCH];	/* stores match on LHS */
644 	char *npvp[MAXATOM+1];		/* temporary space for rebuild */
645 
646 	if (OpMode == MD_TEST || tTd(21, 1))
647 	{
648 		printf("rewrite: ruleset %2d   input:", ruleset);
649 		printav(pvp);
650 	}
651 	if (ruleset < 0 || ruleset >= MAXRWSETS)
652 	{
653 		syserr("554 rewrite: illegal ruleset number %d", ruleset);
654 		return EX_CONFIG;
655 	}
656 	if (reclevel++ > MAXRULERECURSION)
657 	{
658 		syserr("rewrite: infinite recursion, ruleset %d", ruleset);
659 		return EX_CONFIG;
660 	}
661 	if (pvp == NULL)
662 		return EX_USAGE;
663 
664 	/*
665 	**  Run through the list of rewrite rules, applying
666 	**	any that match.
667 	*/
668 
669 	ruleno = 1;
670 	loopcount = 0;
671 	for (rwr = RewriteRules[ruleset]; rwr != NULL; )
672 	{
673 		if (tTd(21, 12))
674 		{
675 			printf("-----trying rule:");
676 			printav(rwr->r_lhs);
677 		}
678 
679 		/* try to match on this rule */
680 		mlp = mlist;
681 		rvp = rwr->r_lhs;
682 		avp = pvp;
683 		if (++loopcount > 100)
684 		{
685 			syserr("554 Infinite loop in ruleset %d, rule %d",
686 				ruleset, ruleno);
687 			if (tTd(21, 1))
688 			{
689 				printf("workspace: ");
690 				printav(pvp);
691 			}
692 			break;
693 		}
694 
695 		while ((ap = *avp) != NULL || *rvp != NULL)
696 		{
697 			rp = *rvp;
698 			if (tTd(21, 35))
699 			{
700 				printf("ADVANCE rp=");
701 				xputs(rp);
702 				printf(", ap=");
703 				xputs(ap);
704 				printf("\n");
705 			}
706 			if (rp == NULL)
707 			{
708 				/* end-of-pattern before end-of-address */
709 				goto backup;
710 			}
711 			if (ap == NULL && (*rp & 0377) != MATCHZANY &&
712 			    (*rp & 0377) != MATCHZERO)
713 			{
714 				/* end-of-input with patterns left */
715 				goto backup;
716 			}
717 
718 			switch (*rp & 0377)
719 			{
720 				char buf[MAXLINE];
721 
722 			  case MATCHCLASS:
723 				/* match any phrase in a class */
724 				mlp->pattern = rvp;
725 				mlp->first = avp;
726 	extendclass:
727 				ap = *avp;
728 				if (ap == NULL)
729 					goto backup;
730 				mlp->last = avp++;
731 				cataddr(mlp->first, mlp->last, buf, sizeof buf, '\0');
732 				if (!wordinclass(buf, rp[1]))
733 				{
734 					if (tTd(21, 36))
735 					{
736 						printf("EXTEND  rp=");
737 						xputs(rp);
738 						printf(", ap=");
739 						xputs(ap);
740 						printf("\n");
741 					}
742 					goto extendclass;
743 				}
744 				if (tTd(21, 36))
745 					printf("CLMATCH\n");
746 				mlp++;
747 				break;
748 
749 			  case MATCHNCLASS:
750 				/* match any token not in a class */
751 				if (wordinclass(ap, rp[1]))
752 					goto backup;
753 
754 				/* fall through */
755 
756 			  case MATCHONE:
757 			  case MATCHANY:
758 				/* match exactly one token */
759 				mlp->pattern = rvp;
760 				mlp->first = avp;
761 				mlp->last = avp++;
762 				mlp++;
763 				break;
764 
765 			  case MATCHZANY:
766 				/* match zero or more tokens */
767 				mlp->pattern = rvp;
768 				mlp->first = avp;
769 				mlp->last = avp - 1;
770 				mlp++;
771 				break;
772 
773 			  case MATCHZERO:
774 				/* match zero tokens */
775 				break;
776 
777 			  case MACRODEXPAND:
778 				/*
779 				**  Match against run-time macro.
780 				**  This algorithm is broken for the
781 				**  general case (no recursive macros,
782 				**  improper tokenization) but should
783 				**  work for the usual cases.
784 				*/
785 
786 				ap = macvalue(rp[1], e);
787 				mlp->first = avp;
788 				if (tTd(21, 2))
789 					printf("rewrite: LHS $&%c => \"%s\"\n",
790 						rp[1],
791 						ap == NULL ? "(NULL)" : ap);
792 
793 				if (ap == NULL)
794 					break;
795 				while (*ap != '\0')
796 				{
797 					if (*avp == NULL ||
798 					    strncasecmp(ap, *avp, strlen(*avp)) != 0)
799 					{
800 						/* no match */
801 						avp = mlp->first;
802 						goto backup;
803 					}
804 					ap += strlen(*avp++);
805 				}
806 
807 				/* match */
808 				break;
809 
810 			  default:
811 				/* must have exact match */
812 				if (strcasecmp(rp, ap))
813 					goto backup;
814 				avp++;
815 				break;
816 			}
817 
818 			/* successful match on this token */
819 			rvp++;
820 			continue;
821 
822 	  backup:
823 			/* match failed -- back up */
824 			while (--mlp >= mlist)
825 			{
826 				rvp = mlp->pattern;
827 				rp = *rvp;
828 				avp = mlp->last + 1;
829 				ap = *avp;
830 
831 				if (tTd(21, 36))
832 				{
833 					printf("BACKUP  rp=");
834 					xputs(rp);
835 					printf(", ap=");
836 					xputs(ap);
837 					printf("\n");
838 				}
839 
840 				if (ap == NULL)
841 				{
842 					/* run off the end -- back up again */
843 					continue;
844 				}
845 				if ((*rp & 0377) == MATCHANY ||
846 				    (*rp & 0377) == MATCHZANY)
847 				{
848 					/* extend binding and continue */
849 					mlp->last = avp++;
850 					rvp++;
851 					mlp++;
852 					break;
853 				}
854 				if ((*rp & 0377) == MATCHCLASS)
855 				{
856 					/* extend binding and try again */
857 					mlp->last = avp;
858 					goto extendclass;
859 				}
860 			}
861 
862 			if (mlp < mlist)
863 			{
864 				/* total failure to match */
865 				break;
866 			}
867 		}
868 
869 		/*
870 		**  See if we successfully matched
871 		*/
872 
873 		if (mlp < mlist || *rvp != NULL)
874 		{
875 			if (tTd(21, 10))
876 				printf("----- rule fails\n");
877 			rwr = rwr->r_next;
878 			ruleno++;
879 			loopcount = 0;
880 			continue;
881 		}
882 
883 		rvp = rwr->r_rhs;
884 		if (tTd(21, 12))
885 		{
886 			printf("-----rule matches:");
887 			printav(rvp);
888 		}
889 
890 		rp = *rvp;
891 		if ((*rp & 0377) == CANONUSER)
892 		{
893 			rvp++;
894 			rwr = rwr->r_next;
895 			ruleno++;
896 			loopcount = 0;
897 		}
898 		else if ((*rp & 0377) == CANONHOST)
899 		{
900 			rvp++;
901 			rwr = NULL;
902 		}
903 		else if ((*rp & 0377) == CANONNET)
904 			rwr = NULL;
905 
906 		/* substitute */
907 		for (avp = npvp; *rvp != NULL; rvp++)
908 		{
909 			register struct match *m;
910 			register char **pp;
911 
912 			rp = *rvp;
913 			if ((*rp & 0377) == MATCHREPL)
914 			{
915 				/* substitute from LHS */
916 				m = &mlist[rp[1] - '1'];
917 				if (m < mlist || m >= mlp)
918 				{
919 					syserr("554 rewrite: ruleset %d: replacement $%c out of bounds",
920 						ruleset, rp[1]);
921 					return EX_CONFIG;
922 				}
923 				if (tTd(21, 15))
924 				{
925 					printf("$%c:", rp[1]);
926 					pp = m->first;
927 					while (pp <= m->last)
928 					{
929 						printf(" %x=\"", *pp);
930 						(void) fflush(stdout);
931 						printf("%s\"", *pp++);
932 					}
933 					printf("\n");
934 				}
935 				pp = m->first;
936 				while (pp <= m->last)
937 				{
938 					if (avp >= &npvp[MAXATOM])
939 					{
940 						syserr("554 rewrite: expansion too long");
941 						return EX_DATAERR;
942 					}
943 					*avp++ = *pp++;
944 				}
945 			}
946 			else
947 			{
948 				/* vanilla replacement */
949 				if (avp >= &npvp[MAXATOM])
950 				{
951 	toolong:
952 					syserr("554 rewrite: expansion too long");
953 					return EX_DATAERR;
954 				}
955 				if ((*rp & 0377) != MACRODEXPAND)
956 					*avp++ = rp;
957 				else
958 				{
959 					*avp = macvalue(rp[1], e);
960 					if (tTd(21, 2))
961 						printf("rewrite: RHS $&%c => \"%s\"\n",
962 							rp[1],
963 							*avp == NULL ? "(NULL)" : *avp);
964 					if (*avp != NULL)
965 						avp++;
966 				}
967 			}
968 		}
969 		*avp++ = NULL;
970 
971 		/*
972 		**  Check for any hostname/keyword lookups.
973 		*/
974 
975 		for (rvp = npvp; *rvp != NULL; rvp++)
976 		{
977 			char **hbrvp;
978 			char **xpvp;
979 			int trsize;
980 			char *replac;
981 			int endtoken;
982 			STAB *map;
983 			char *mapname;
984 			char **key_rvp;
985 			char **arg_rvp;
986 			char **default_rvp;
987 			char buf[MAXNAME + 1];
988 			char *pvpb1[MAXATOM + 1];
989 			char *argvect[10];
990 			char pvpbuf[PSBUFSIZE];
991 			char *nullpvp[1];
992 
993 			if ((**rvp & 0377) != HOSTBEGIN &&
994 			    (**rvp & 0377) != LOOKUPBEGIN)
995 				continue;
996 
997 			/*
998 			**  Got a hostname/keyword lookup.
999 			**
1000 			**	This could be optimized fairly easily.
1001 			*/
1002 
1003 			hbrvp = rvp;
1004 			if ((**rvp & 0377) == HOSTBEGIN)
1005 			{
1006 				endtoken = HOSTEND;
1007 				mapname = "host";
1008 			}
1009 			else
1010 			{
1011 				endtoken = LOOKUPEND;
1012 				mapname = *++rvp;
1013 			}
1014 			map = stab(mapname, ST_MAP, ST_FIND);
1015 			if (map == NULL)
1016 				syserr("554 rewrite: map %s not found", mapname);
1017 
1018 			/* extract the match part */
1019 			key_rvp = ++rvp;
1020 			default_rvp = NULL;
1021 			arg_rvp = argvect;
1022 			xpvp = NULL;
1023 			replac = pvpbuf;
1024 			while (*rvp != NULL && (**rvp & 0377) != endtoken)
1025 			{
1026 				int nodetype = **rvp & 0377;
1027 
1028 				if (nodetype != CANONHOST && nodetype != CANONUSER)
1029 				{
1030 					rvp++;
1031 					continue;
1032 				}
1033 
1034 				*rvp++ = NULL;
1035 
1036 				if (xpvp != NULL)
1037 				{
1038 					cataddr(xpvp, NULL, replac,
1039 						&pvpbuf[sizeof pvpbuf] - replac,
1040 						'\0');
1041 					*++arg_rvp = replac;
1042 					replac += strlen(replac) + 1;
1043 					xpvp = NULL;
1044 				}
1045 				switch (nodetype)
1046 				{
1047 				  case CANONHOST:
1048 					xpvp = rvp;
1049 					break;
1050 
1051 				  case CANONUSER:
1052 					default_rvp = rvp;
1053 					break;
1054 				}
1055 			}
1056 			if (*rvp != NULL)
1057 				*rvp++ = NULL;
1058 			if (xpvp != NULL)
1059 			{
1060 				cataddr(xpvp, NULL, replac,
1061 					&pvpbuf[sizeof pvpbuf] - replac,
1062 					'\0');
1063 				*++arg_rvp = replac;
1064 			}
1065 			*++arg_rvp = NULL;
1066 
1067 			/* save the remainder of the input string */
1068 			trsize = (int) (avp - rvp + 1) * sizeof *rvp;
1069 			bcopy((char *) rvp, (char *) pvpb1, trsize);
1070 
1071 			/* look it up */
1072 			cataddr(key_rvp, NULL, buf, sizeof buf, '\0');
1073 			argvect[0] = buf;
1074 			if (map != NULL && bitset(MF_OPEN, map->s_map.map_mflags))
1075 			{
1076 				auto int stat = EX_OK;
1077 
1078 				/* XXX should try to auto-open the map here */
1079 
1080 				if (tTd(60, 1))
1081 					printf("map_lookup(%s, %s) => ",
1082 						mapname, buf);
1083 				replac = (*map->s_map.map_class->map_lookup)(&map->s_map,
1084 						buf, argvect, &stat);
1085 				if (tTd(60, 1))
1086 					printf("%s (%d)\n",
1087 						replac ? replac : "NOT FOUND",
1088 						stat);
1089 
1090 				/* should recover if stat == EX_TEMPFAIL */
1091 				if (stat == EX_TEMPFAIL)
1092 					rstat = stat;
1093 			}
1094 			else
1095 				replac = NULL;
1096 
1097 			/* if no replacement, use default */
1098 			if (replac == NULL && default_rvp != NULL)
1099 			{
1100 				/* create the default */
1101 				cataddr(default_rvp, NULL, buf, sizeof buf, '\0');
1102 				replac = buf;
1103 			}
1104 
1105 			if (replac == NULL)
1106 			{
1107 				xpvp = key_rvp;
1108 			}
1109 			else if (*replac == '\0')
1110 			{
1111 				/* null replacement */
1112 				nullpvp[0] = NULL;
1113 				xpvp = nullpvp;
1114 			}
1115 			else
1116 			{
1117 				/* scan the new replacement */
1118 				xpvp = prescan(replac, '\0', pvpbuf,
1119 					       sizeof pvpbuf, NULL);
1120 				if (xpvp == NULL)
1121 				{
1122 					/* prescan already printed error */
1123 					return EX_DATAERR;
1124 				}
1125 			}
1126 
1127 			/* append it to the token list */
1128 			for (avp = hbrvp; *xpvp != NULL; xpvp++)
1129 			{
1130 				*avp++ = newstr(*xpvp);
1131 				if (avp >= &npvp[MAXATOM])
1132 					goto toolong;
1133 			}
1134 
1135 			/* restore the old trailing information */
1136 			for (xpvp = pvpb1; (*avp++ = *xpvp++) != NULL; )
1137 				if (avp >= &npvp[MAXATOM])
1138 					goto toolong;
1139 
1140 			break;
1141 		}
1142 
1143 		/*
1144 		**  Check for subroutine calls.
1145 		*/
1146 
1147 		if (*npvp != NULL && (**npvp & 0377) == CALLSUBR)
1148 		{
1149 			int stat;
1150 
1151 			if (npvp[1] == NULL)
1152 			{
1153 				syserr("parseaddr: NULL subroutine call in ruleset %d, rule %d",
1154 					ruleset, ruleno);
1155 				*pvp = NULL;
1156 			}
1157 			else
1158 			{
1159 				int ruleset;
1160 				STAB *s;
1161 
1162 				bcopy((char *) &npvp[2], (char *) pvp,
1163 					(int) (avp - npvp - 2) * sizeof *avp);
1164 				if (tTd(21, 3))
1165 					printf("-----callsubr %s\n", npvp[1]);
1166 				s = stab(npvp[1], ST_RULESET, ST_FIND);
1167 				if (s == NULL)
1168 					ruleset = atoi(npvp[1]);
1169 				else
1170 					ruleset = s->s_ruleset;
1171 				stat = rewrite(pvp, ruleset, reclevel, e);
1172 				if (rstat == EX_OK || stat == EX_TEMPFAIL)
1173 					rstat = stat;
1174 				if (*pvp != NULL && (**pvp & 0377) == CANONNET)
1175 				rwr = NULL;
1176 			}
1177 		}
1178 		else
1179 		{
1180 			bcopy((char *) npvp, (char *) pvp,
1181 				(int) (avp - npvp) * sizeof *avp);
1182 		}
1183 		if (tTd(21, 4))
1184 		{
1185 			printf("rewritten as:");
1186 			printav(pvp);
1187 		}
1188 	}
1189 
1190 	if (OpMode == MD_TEST || tTd(21, 1))
1191 	{
1192 		printf("rewrite: ruleset %2d returns:", ruleset);
1193 		printav(pvp);
1194 	}
1195 
1196 	return rstat;
1197 }
1198 /*
1199 **  BUILDADDR -- build address from token vector.
1200 **
1201 **	Parameters:
1202 **		tv -- token vector.
1203 **		a -- pointer to address descriptor to fill.
1204 **			If NULL, one will be allocated.
1205 **		flags -- info regarding whether this is a sender or
1206 **			a recipient.
1207 **		e -- the current envelope.
1208 **
1209 **	Returns:
1210 **		NULL if there was an error.
1211 **		'a' otherwise.
1212 **
1213 **	Side Effects:
1214 **		fills in 'a'
1215 */
1216 
1217 struct errcodes
1218 {
1219 	char	*ec_name;		/* name of error code */
1220 	int	ec_code;		/* numeric code */
1221 } ErrorCodes[] =
1222 {
1223 	"usage",	EX_USAGE,
1224 	"nouser",	EX_NOUSER,
1225 	"nohost",	EX_NOHOST,
1226 	"unavailable",	EX_UNAVAILABLE,
1227 	"software",	EX_SOFTWARE,
1228 	"tempfail",	EX_TEMPFAIL,
1229 	"protocol",	EX_PROTOCOL,
1230 #ifdef EX_CONFIG
1231 	"config",	EX_CONFIG,
1232 #endif
1233 	NULL,		EX_UNAVAILABLE,
1234 };
1235 
1236 ADDRESS *
1237 buildaddr(tv, a, flags, e)
1238 	register char **tv;
1239 	register ADDRESS *a;
1240 	int flags;
1241 	register ENVELOPE *e;
1242 {
1243 	struct mailer **mp;
1244 	register struct mailer *m;
1245 	char *bp;
1246 	int spaceleft;
1247 	static MAILER errormailer;
1248 	static char *errorargv[] = { "ERROR", NULL };
1249 	static char buf[MAXNAME];
1250 
1251 	if (tTd(24, 5))
1252 	{
1253 		printf("buildaddr, flags=%x, tv=", flags);
1254 		printav(tv);
1255 	}
1256 
1257 	if (a == NULL)
1258 		a = (ADDRESS *) xalloc(sizeof *a);
1259 	bzero((char *) a, sizeof *a);
1260 
1261 	/* set up default error return flags */
1262 	a->q_flags |= QPINGONFAILURE|QPINGONDELAY;
1263 
1264 	/* figure out what net/mailer to use */
1265 	if (*tv == NULL || (**tv & 0377) != CANONNET)
1266 	{
1267 		syserr("554 buildaddr: no net");
1268 badaddr:
1269 		a->q_flags |= QBADADDR;
1270 		a->q_mailer = &errormailer;
1271 		if (errormailer.m_name == NULL)
1272 		{
1273 			/* initialize the bogus mailer */
1274 			errormailer.m_name = "*error*";
1275 			errormailer.m_mailer = "ERROR";
1276 			errormailer.m_argv = errorargv;
1277 		}
1278 		return a;
1279 	}
1280 	tv++;
1281 	if (strcasecmp(*tv, "error") == 0)
1282 	{
1283 		if ((**++tv & 0377) == CANONHOST)
1284 		{
1285 			register struct errcodes *ep;
1286 
1287 			if (isascii(**++tv) && isdigit(**tv))
1288 			{
1289 				setstat(atoi(*tv));
1290 			}
1291 			else
1292 			{
1293 				for (ep = ErrorCodes; ep->ec_name != NULL; ep++)
1294 					if (strcasecmp(ep->ec_name, *tv) == 0)
1295 						break;
1296 				setstat(ep->ec_code);
1297 			}
1298 			tv++;
1299 		}
1300 		else
1301 			setstat(EX_UNAVAILABLE);
1302 		if ((**tv & 0377) != CANONUSER)
1303 			syserr("554 buildaddr: error: no user");
1304 		cataddr(++tv, NULL, buf, sizeof buf, ' ');
1305 		stripquotes(buf);
1306 		if (isascii(buf[0]) && isdigit(buf[0]) &&
1307 		    isascii(buf[1]) && isdigit(buf[1]) &&
1308 		    isascii(buf[2]) && isdigit(buf[2]) &&
1309 		    buf[3] == ' ')
1310 		{
1311 			char fmt[10];
1312 
1313 			strncpy(fmt, buf, 3);
1314 			strcpy(&fmt[3], " %s");
1315 			usrerr(fmt, buf + 4);
1316 
1317 			/*
1318 			**  If this is a 4xx code and we aren't running
1319 			**  SMTP on our input, bounce this message;
1320 			**  otherwise it disappears without a trace.
1321 			*/
1322 
1323 			if (fmt[0] == '4' && OpMode != MD_SMTP &&
1324 			    OpMode != MD_DAEMON)
1325 			{
1326 				e->e_flags |= EF_FATALERRS;
1327 			}
1328 		}
1329 		else
1330 		{
1331 			usrerr("553 %s", buf);
1332 		}
1333 		goto badaddr;
1334 	}
1335 
1336 	for (mp = Mailer; (m = *mp++) != NULL; )
1337 	{
1338 		if (strcasecmp(m->m_name, *tv) == 0)
1339 			break;
1340 	}
1341 	if (m == NULL)
1342 	{
1343 		syserr("554 buildaddr: unknown mailer %s", *tv);
1344 		goto badaddr;
1345 	}
1346 	a->q_mailer = m;
1347 
1348 	/* figure out what host (if any) */
1349 	tv++;
1350 	if ((**tv & 0377) == CANONHOST)
1351 	{
1352 		bp = buf;
1353 		spaceleft = sizeof buf - 1;
1354 		while (*++tv != NULL && (**tv & 0377) != CANONUSER)
1355 		{
1356 			int i = strlen(*tv);
1357 
1358 			if (i > spaceleft)
1359 			{
1360 				/* out of space for this address */
1361 				if (spaceleft >= 0)
1362 					syserr("554 buildaddr: host too long (%.40s...)",
1363 						buf);
1364 				i = spaceleft;
1365 				spaceleft = 0;
1366 			}
1367 			if (i <= 0)
1368 				continue;
1369 			bcopy(*tv, bp, i);
1370 			bp += i;
1371 			spaceleft -= i;
1372 		}
1373 		*bp = '\0';
1374 		a->q_host = newstr(buf);
1375 	}
1376 	else
1377 	{
1378 		if (!bitnset(M_LOCALMAILER, m->m_flags))
1379 		{
1380 			syserr("554 buildaddr: no host");
1381 			goto badaddr;
1382 		}
1383 		a->q_host = NULL;
1384 	}
1385 
1386 	/* figure out the user */
1387 	if (*tv == NULL || (**tv & 0377) != CANONUSER)
1388 	{
1389 		syserr("554 buildaddr: no user");
1390 		goto badaddr;
1391 	}
1392 	tv++;
1393 
1394 	if (bitnset(M_CHECKUDB, m->m_flags) && *tv != NULL &&
1395 	    strcmp(*tv, "@") == 0)
1396 	{
1397 		tv++;
1398 		a->q_flags |= QNOTREMOTE;
1399 	}
1400 
1401 	/* do special mapping for local mailer */
1402 	if (*tv != NULL)
1403 	{
1404 		register char *p = *tv;
1405 
1406 		if (*p == '"')
1407 			p++;
1408 		if (*p == '|' && bitnset(M_CHECKPROG, m->m_flags))
1409 			a->q_mailer = m = ProgMailer;
1410 		else if (*p == '/' && bitnset(M_CHECKFILE, m->m_flags))
1411 			a->q_mailer = m = FileMailer;
1412 		else if (*p == ':' && bitnset(M_CHECKINCLUDE, m->m_flags))
1413 		{
1414 			/* may be :include: */
1415 			cataddr(tv, NULL, buf, sizeof buf, '\0');
1416 			stripquotes(buf);
1417 			if (strncasecmp(buf, ":include:", 9) == 0)
1418 			{
1419 				/* if :include:, don't need further rewriting */
1420 				a->q_mailer = m = InclMailer;
1421 				a->q_user = &buf[9];
1422 				return (a);
1423 			}
1424 		}
1425 	}
1426 
1427 	/* rewrite according recipient mailer rewriting rules */
1428 	define('h', a->q_host, e);
1429 	if (!bitset(RF_SENDERADDR|RF_HEADERADDR, flags))
1430 	{
1431 		/* sender addresses done later */
1432 		(void) rewrite(tv, 2, 0, e);
1433 		if (m->m_re_rwset > 0)
1434 		       (void) rewrite(tv, m->m_re_rwset, 0, e);
1435 	}
1436 	(void) rewrite(tv, 4, 0, e);
1437 
1438 	/* save the result for the command line/RCPT argument */
1439 	cataddr(tv, NULL, buf, sizeof buf, '\0');
1440 	a->q_user = buf;
1441 
1442 	/*
1443 	**  Do mapping to lower case as requested by mailer
1444 	*/
1445 
1446 	if (a->q_host != NULL && !bitnset(M_HST_UPPER, m->m_flags))
1447 		makelower(a->q_host);
1448 	if (!bitnset(M_USR_UPPER, m->m_flags))
1449 		makelower(a->q_user);
1450 
1451 	return (a);
1452 }
1453 /*
1454 **  CATADDR -- concatenate pieces of addresses (putting in <LWSP> subs)
1455 **
1456 **	Parameters:
1457 **		pvp -- parameter vector to rebuild.
1458 **		evp -- last parameter to include.  Can be NULL to
1459 **			use entire pvp.
1460 **		buf -- buffer to build the string into.
1461 **		sz -- size of buf.
1462 **		spacesub -- the space separator character; if null,
1463 **			use SpaceSub.
1464 **
1465 **	Returns:
1466 **		none.
1467 **
1468 **	Side Effects:
1469 **		Destroys buf.
1470 */
1471 
1472 cataddr(pvp, evp, buf, sz, spacesub)
1473 	char **pvp;
1474 	char **evp;
1475 	char *buf;
1476 	register int sz;
1477 	char spacesub;
1478 {
1479 	bool oatomtok = FALSE;
1480 	bool natomtok = FALSE;
1481 	register int i;
1482 	register char *p;
1483 
1484 	if (spacesub == '\0')
1485 		spacesub = SpaceSub;
1486 
1487 	if (pvp == NULL)
1488 	{
1489 		(void) strcpy(buf, "");
1490 		return;
1491 	}
1492 	p = buf;
1493 	sz -= 2;
1494 	while (*pvp != NULL && (i = strlen(*pvp)) < sz)
1495 	{
1496 		natomtok = (toktype(**pvp) == ATM);
1497 		if (oatomtok && natomtok)
1498 			*p++ = spacesub;
1499 		(void) strcpy(p, *pvp);
1500 		oatomtok = natomtok;
1501 		p += i;
1502 		sz -= i + 1;
1503 		if (pvp++ == evp)
1504 			break;
1505 	}
1506 	*p = '\0';
1507 }
1508 /*
1509 **  SAMEADDR -- Determine if two addresses are the same
1510 **
1511 **	This is not just a straight comparison -- if the mailer doesn't
1512 **	care about the host we just ignore it, etc.
1513 **
1514 **	Parameters:
1515 **		a, b -- pointers to the internal forms to compare.
1516 **
1517 **	Returns:
1518 **		TRUE -- they represent the same mailbox.
1519 **		FALSE -- they don't.
1520 **
1521 **	Side Effects:
1522 **		none.
1523 */
1524 
1525 bool
1526 sameaddr(a, b)
1527 	register ADDRESS *a;
1528 	register ADDRESS *b;
1529 {
1530 	register ADDRESS *ca, *cb;
1531 
1532 	/* if they don't have the same mailer, forget it */
1533 	if (a->q_mailer != b->q_mailer)
1534 		return (FALSE);
1535 
1536 	/* if the user isn't the same, we can drop out */
1537 	if (strcmp(a->q_user, b->q_user) != 0)
1538 		return (FALSE);
1539 
1540 	/* if we have good uids for both but they differ, these are different */
1541 	if (a->q_mailer == ProgMailer)
1542 	{
1543 		ca = getctladdr(a);
1544 		cb = getctladdr(b);
1545 		if (ca != NULL && cb != NULL &&
1546 		    bitset(QGOODUID, ca->q_flags & cb->q_flags) &&
1547 		    ca->q_uid != cb->q_uid)
1548 			return (FALSE);
1549 	}
1550 
1551 	/* otherwise compare hosts (but be careful for NULL ptrs) */
1552 	if (a->q_host == b->q_host)
1553 	{
1554 		/* probably both null pointers */
1555 		return (TRUE);
1556 	}
1557 	if (a->q_host == NULL || b->q_host == NULL)
1558 	{
1559 		/* only one is a null pointer */
1560 		return (FALSE);
1561 	}
1562 	if (strcmp(a->q_host, b->q_host) != 0)
1563 		return (FALSE);
1564 
1565 	return (TRUE);
1566 }
1567 /*
1568 **  PRINTADDR -- print address (for debugging)
1569 **
1570 **	Parameters:
1571 **		a -- the address to print
1572 **		follow -- follow the q_next chain.
1573 **
1574 **	Returns:
1575 **		none.
1576 **
1577 **	Side Effects:
1578 **		none.
1579 */
1580 
1581 struct qflags
1582 {
1583 	char	*qf_name;
1584 	u_long	qf_bit;
1585 };
1586 
1587 struct qflags	AddressFlags[] =
1588 {
1589 	"QDONTSEND",		QDONTSEND,
1590 	"QBADADDR",		QBADADDR,
1591 	"QGOODUID",		QGOODUID,
1592 	"QPRIMARY",		QPRIMARY,
1593 	"QQUEUEUP",		QQUEUEUP,
1594 	"QSENT",		QSENT,
1595 	"QNOTREMOTE",		QNOTREMOTE,
1596 	"QSELFREF",		QSELFREF,
1597 	"QVERIFIED",		QVERIFIED,
1598 	"QREPORT",		QREPORT,
1599 	"QBOGUSSHELL",		QBOGUSSHELL,
1600 	"QUNSAFEADDR",		QUNSAFEADDR,
1601 	"QPINGONSUCCESS",	QPINGONSUCCESS,
1602 	"QPINGONFAILURE",	QPINGONFAILURE,
1603 	"QPINGONDELAY",		QPINGONDELAY,
1604 	"QHAS_RET_PARAM",	QHAS_RET_PARAM,
1605 	"QRET_HDRS",		QRET_HDRS,
1606 	"QRELAYED",		QRELAYED,
1607 	NULL
1608 };
1609 
1610 void
1611 printaddr(a, follow)
1612 	register ADDRESS *a;
1613 	bool follow;
1614 {
1615 	register MAILER *m;
1616 	MAILER pseudomailer;
1617 	register struct qflags *qfp;
1618 	bool firstone;
1619 
1620 	if (a == NULL)
1621 	{
1622 		printf("[NULL]\n");
1623 		return;
1624 	}
1625 
1626 	while (a != NULL)
1627 	{
1628 		printf("%x=", a);
1629 		(void) fflush(stdout);
1630 
1631 		/* find the mailer -- carefully */
1632 		m = a->q_mailer;
1633 		if (m == NULL)
1634 		{
1635 			m = &pseudomailer;
1636 			m->m_mno = -1;
1637 			m->m_name = "NULL";
1638 		}
1639 
1640 		printf("%s:\n\tmailer %d (%s), host `%s', user `%s', ruser `%s'\n",
1641 		       a->q_paddr, m->m_mno, m->m_name,
1642 		       a->q_host == NULL ? "<null>" : a->q_host, a->q_user,
1643 		       a->q_ruser == NULL ? "<null>" : a->q_ruser);
1644 		printf("\tnext=%x, alias %x, uid %d, gid %d\n",
1645 		       a->q_next, a->q_alias, a->q_uid, a->q_gid);
1646 		printf("\tflags=%lx<", a->q_flags);
1647 		firstone = TRUE;
1648 		for (qfp = AddressFlags; qfp->qf_name != NULL; qfp++)
1649 		{
1650 			if (!bitset(qfp->qf_bit, a->q_flags))
1651 				continue;
1652 			if (!firstone)
1653 				printf(",");
1654 			firstone = FALSE;
1655 			printf("%s", qfp->qf_name);
1656 		}
1657 		printf(">\n");
1658 		printf("\towner=%s, home=\"%s\", fullname=\"%s\"\n",
1659 		       a->q_owner == NULL ? "(none)" : a->q_owner,
1660 		       a->q_home == NULL ? "(none)" : a->q_home,
1661 		       a->q_fullname == NULL ? "(none)" : a->q_fullname);
1662 		printf("\torcpt=\"%s\", statmta=%s, rstatus=%s\n",
1663 		       a->q_orcpt == NULL ? "(none)" : a->q_orcpt,
1664 		       a->q_statmta == NULL ? "(none)" : a->q_statmta,
1665 		       a->q_rstatus == NULL ? "(none)" : a->q_rstatus);
1666 
1667 		if (!follow)
1668 			return;
1669 		a = a->q_next;
1670 	}
1671 }
1672 /*
1673 **  EMPTYADDR -- return TRUE if this address is empty (``<>'')
1674 **
1675 **	Parameters:
1676 **		a -- pointer to the address
1677 **
1678 **	Returns:
1679 **		TRUE -- if this address is "empty" (i.e., no one should
1680 **			ever generate replies to it.
1681 **		FALSE -- if it is a "regular" (read: replyable) address.
1682 */
1683 
1684 bool
1685 emptyaddr(a)
1686 	register ADDRESS *a;
1687 {
1688 	return strcmp(a->q_paddr, "<>") == 0 || strcmp(a->q_user, "<>") == 0;
1689 }
1690 /*
1691 **  REMOTENAME -- return the name relative to the current mailer
1692 **
1693 **	Parameters:
1694 **		name -- the name to translate.
1695 **		m -- the mailer that we want to do rewriting relative
1696 **			to.
1697 **		flags -- fine tune operations.
1698 **		pstat -- pointer to status word.
1699 **		e -- the current envelope.
1700 **
1701 **	Returns:
1702 **		the text string representing this address relative to
1703 **			the receiving mailer.
1704 **
1705 **	Side Effects:
1706 **		none.
1707 **
1708 **	Warnings:
1709 **		The text string returned is tucked away locally;
1710 **			copy it if you intend to save it.
1711 */
1712 
1713 char *
1714 remotename(name, m, flags, pstat, e)
1715 	char *name;
1716 	struct mailer *m;
1717 	int flags;
1718 	int *pstat;
1719 	register ENVELOPE *e;
1720 {
1721 	register char **pvp;
1722 	char *fancy;
1723 	char *oldg = macvalue('g', e);
1724 	int rwset;
1725 	static char buf[MAXNAME];
1726 	char lbuf[MAXNAME];
1727 	char pvpbuf[PSBUFSIZE];
1728 	extern char *crackaddr();
1729 
1730 	if (tTd(12, 1))
1731 		printf("remotename(%s)\n", name);
1732 
1733 	/* don't do anything if we are tagging it as special */
1734 	if (bitset(RF_SENDERADDR, flags))
1735 		rwset = bitset(RF_HEADERADDR, flags) ? m->m_sh_rwset
1736 						     : m->m_se_rwset;
1737 	else
1738 		rwset = bitset(RF_HEADERADDR, flags) ? m->m_rh_rwset
1739 						     : m->m_re_rwset;
1740 	if (rwset < 0)
1741 		return (name);
1742 
1743 	/*
1744 	**  Do a heuristic crack of this name to extract any comment info.
1745 	**	This will leave the name as a comment and a $g macro.
1746 	*/
1747 
1748 	if (bitset(RF_CANONICAL, flags) || bitnset(M_NOCOMMENT, m->m_flags))
1749 		fancy = "\201g";
1750 	else
1751 		fancy = crackaddr(name);
1752 
1753 	/*
1754 	**  Turn the name into canonical form.
1755 	**	Normally this will be RFC 822 style, i.e., "user@domain".
1756 	**	If this only resolves to "user", and the "C" flag is
1757 	**	specified in the sending mailer, then the sender's
1758 	**	domain will be appended.
1759 	*/
1760 
1761 	pvp = prescan(name, '\0', pvpbuf, sizeof pvpbuf, NULL);
1762 	if (pvp == NULL)
1763 		return (name);
1764 	if (rewrite(pvp, 3, 0, e) == EX_TEMPFAIL)
1765 		*pstat = EX_TEMPFAIL;
1766 	if (bitset(RF_ADDDOMAIN, flags) && e->e_fromdomain != NULL)
1767 	{
1768 		/* append from domain to this address */
1769 		register char **pxp = pvp;
1770 
1771 		/* see if there is an "@domain" in the current name */
1772 		while (*pxp != NULL && strcmp(*pxp, "@") != 0)
1773 			pxp++;
1774 		if (*pxp == NULL)
1775 		{
1776 			/* no.... append the "@domain" from the sender */
1777 			register char **qxq = e->e_fromdomain;
1778 
1779 			while ((*pxp++ = *qxq++) != NULL)
1780 				continue;
1781 			if (rewrite(pvp, 3, 0, e) == EX_TEMPFAIL)
1782 				*pstat = EX_TEMPFAIL;
1783 		}
1784 	}
1785 
1786 	/*
1787 	**  Do more specific rewriting.
1788 	**	Rewrite using ruleset 1 or 2 depending on whether this is
1789 	**		a sender address or not.
1790 	**	Then run it through any receiving-mailer-specific rulesets.
1791 	*/
1792 
1793 	if (bitset(RF_SENDERADDR, flags))
1794 	{
1795 		if (rewrite(pvp, 1, 0, e) == EX_TEMPFAIL)
1796 			*pstat = EX_TEMPFAIL;
1797 	}
1798 	else
1799 	{
1800 		if (rewrite(pvp, 2, 0, e) == EX_TEMPFAIL)
1801 			*pstat = EX_TEMPFAIL;
1802 	}
1803 	if (rwset > 0)
1804 	{
1805 		if (rewrite(pvp, rwset, 0, e) == EX_TEMPFAIL)
1806 			*pstat = EX_TEMPFAIL;
1807 	}
1808 
1809 	/*
1810 	**  Do any final sanitation the address may require.
1811 	**	This will normally be used to turn internal forms
1812 	**	(e.g., user@host.LOCAL) into external form.  This
1813 	**	may be used as a default to the above rules.
1814 	*/
1815 
1816 	if (rewrite(pvp, 4, 0, e) == EX_TEMPFAIL)
1817 		*pstat = EX_TEMPFAIL;
1818 
1819 	/*
1820 	**  Now restore the comment information we had at the beginning.
1821 	*/
1822 
1823 	cataddr(pvp, NULL, lbuf, sizeof lbuf, '\0');
1824 	define('g', lbuf, e);
1825 
1826 	/* need to make sure route-addrs have <angle brackets> */
1827 	if (bitset(RF_CANONICAL, flags) && lbuf[0] == '@')
1828 		expand("<\201g>", buf, &buf[sizeof buf - 1], e);
1829 	else
1830 		expand(fancy, buf, &buf[sizeof buf - 1], e);
1831 
1832 	define('g', oldg, e);
1833 
1834 	if (tTd(12, 1))
1835 		printf("remotename => `%s'\n", buf);
1836 	return (buf);
1837 }
1838 /*
1839 **  MAPLOCALUSER -- run local username through ruleset 5 for final redirection
1840 **
1841 **	Parameters:
1842 **		a -- the address to map (but just the user name part).
1843 **		sendq -- the sendq in which to install any replacement
1844 **			addresses.
1845 **		aliaslevel -- the alias nesting depth.
1846 **		e -- the envelope.
1847 **
1848 **	Returns:
1849 **		none.
1850 */
1851 
1852 maplocaluser(a, sendq, aliaslevel, e)
1853 	register ADDRESS *a;
1854 	ADDRESS **sendq;
1855 	int aliaslevel;
1856 	ENVELOPE *e;
1857 {
1858 	register char **pvp;
1859 	register ADDRESS *a1 = NULL;
1860 	auto char *delimptr;
1861 	char pvpbuf[PSBUFSIZE];
1862 
1863 	if (tTd(29, 1))
1864 	{
1865 		printf("maplocaluser: ");
1866 		printaddr(a, FALSE);
1867 	}
1868 	pvp = prescan(a->q_user, '\0', pvpbuf, sizeof pvpbuf, &delimptr);
1869 	if (pvp == NULL)
1870 		return;
1871 
1872 	(void) rewrite(pvp, 5, 0, e);
1873 	if (pvp[0] == NULL || (pvp[0][0] & 0377) != CANONNET)
1874 		return;
1875 
1876 	/* if non-null, mailer destination specified -- has it changed? */
1877 	a1 = buildaddr(pvp, NULL, 0, e);
1878 	if (a1 == NULL || sameaddr(a, a1))
1879 		return;
1880 
1881 	/* mark old address as dead; insert new address */
1882 	a->q_flags |= QDONTSEND;
1883 	if (tTd(29, 5))
1884 	{
1885 		printf("maplocaluser: QDONTSEND ");
1886 		printaddr(a, FALSE);
1887 	}
1888 	a1->q_alias = a;
1889 	allocaddr(a1, RF_COPYALL, NULL);
1890 	(void) recipient(a1, sendq, aliaslevel, e);
1891 }
1892 /*
1893 **  DEQUOTE_INIT -- initialize dequote map
1894 **
1895 **	This is a no-op.
1896 **
1897 **	Parameters:
1898 **		map -- the internal map structure.
1899 **		args -- arguments.
1900 **
1901 **	Returns:
1902 **		TRUE.
1903 */
1904 
1905 bool
1906 dequote_init(map, args)
1907 	MAP *map;
1908 	char *args;
1909 {
1910 	register char *p = args;
1911 
1912 	for (;;)
1913 	{
1914 		while (isascii(*p) && isspace(*p))
1915 			p++;
1916 		if (*p != '-')
1917 			break;
1918 		switch (*++p)
1919 		{
1920 		  case 'a':
1921 			map->map_app = ++p;
1922 			break;
1923 
1924 		  case 's':
1925 			map->map_coldelim = *++p;
1926 			break;
1927 		}
1928 		while (*p != '\0' && !(isascii(*p) && isspace(*p)))
1929 			p++;
1930 		if (*p != '\0')
1931 			*p = '\0';
1932 	}
1933 	if (map->map_app != NULL)
1934 		map->map_app = newstr(map->map_app);
1935 
1936 	return TRUE;
1937 }
1938 /*
1939 **  DEQUOTE_MAP -- unquote an address
1940 **
1941 **	Parameters:
1942 **		map -- the internal map structure (ignored).
1943 **		name -- the name to dequote.
1944 **		av -- arguments (ignored).
1945 **		statp -- pointer to status out-parameter.
1946 **
1947 **	Returns:
1948 **		NULL -- if there were no quotes, or if the resulting
1949 **			unquoted buffer would not be acceptable to prescan.
1950 **		else -- The dequoted buffer.
1951 */
1952 
1953 char *
1954 dequote_map(map, name, av, statp)
1955 	MAP *map;
1956 	char *name;
1957 	char **av;
1958 	int *statp;
1959 {
1960 	register char *p;
1961 	register char *q;
1962 	register char c;
1963 	int anglecnt = 0;
1964 	int cmntcnt = 0;
1965 	int quotecnt = 0;
1966 	int spacecnt = 0;
1967 	bool quotemode = FALSE;
1968 	bool bslashmode = FALSE;
1969 	char spacesub = map->map_coldelim;
1970 
1971 	for (p = q = name; (c = *p++) != '\0'; )
1972 	{
1973 		if (bslashmode)
1974 		{
1975 			bslashmode = FALSE;
1976 			*q++ = c;
1977 			continue;
1978 		}
1979 
1980 		if (c == ' ' && spacesub != '\0')
1981 			c = spacesub;
1982 
1983 		switch (c)
1984 		{
1985 		  case '\\':
1986 			bslashmode = TRUE;
1987 			break;
1988 
1989 		  case '(':
1990 			cmntcnt++;
1991 			break;
1992 
1993 		  case ')':
1994 			if (cmntcnt-- <= 0)
1995 				return NULL;
1996 			break;
1997 
1998 		  case ' ':
1999 			spacecnt++;
2000 			break;
2001 		}
2002 
2003 		if (cmntcnt > 0)
2004 		{
2005 			*q++ = c;
2006 			continue;
2007 		}
2008 
2009 		switch (c)
2010 		{
2011 		  case '"':
2012 			quotemode = !quotemode;
2013 			quotecnt++;
2014 			continue;
2015 
2016 		  case '<':
2017 			anglecnt++;
2018 			break;
2019 
2020 		  case '>':
2021 			if (anglecnt-- <= 0)
2022 				return NULL;
2023 			break;
2024 		}
2025 		*q++ = c;
2026 	}
2027 
2028 	if (anglecnt != 0 || cmntcnt != 0 || bslashmode ||
2029 	    quotemode || quotecnt <= 0 || spacecnt != 0)
2030 		return NULL;
2031 	*q++ = '\0';
2032 	return name;
2033 }
2034