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.47 (Berkeley) 12/28/94";
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 = "466";
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;
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 (savedelim != '\0' && delimptr != NULL)
210 			*delimptr = savedelim;
211 		return FALSE;
212 	}
213 	setstat(EX_USAGE);
214 	usrerr("553 Address contained invalid control characters");
215   addrfailure:
216 	if (savedelim != '\0' && delimptr != NULL)
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 	char 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 	returnnull:
416 					if (delimptr != NULL)
417 						*delimptr = p;
418 					CurEnv->e_to = saveto;
419 					return (NULL);
420 				}
421 
422 				/* squirrel it away */
423 				*q++ = c;
424 			}
425 
426 			/* read a new input character */
427 			c = *p++;
428 			if (c == '\0')
429 			{
430 				/* diagnose and patch up bad syntax */
431 				if (state == QST)
432 				{
433 					usrerr("653 Unbalanced '\"'");
434 					c = '"';
435 				}
436 				else if (cmntcnt > 0)
437 				{
438 					usrerr("653 Unbalanced '('");
439 					c = ')';
440 				}
441 				else if (anglecnt > 0)
442 				{
443 					c = '>';
444 					usrerr("653 Unbalanced '<'");
445 				}
446 				else
447 					break;
448 
449 				p--;
450 			}
451 			else if (c == delim && anglecnt <= 0 &&
452 					cmntcnt <= 0 && state != QST)
453 				break;
454 
455 			if (tTd(22, 101))
456 				printf("c=%c, s=%d; ", c, state);
457 
458 			/* chew up special characters */
459 			*q = '\0';
460 			if (bslashmode)
461 			{
462 				bslashmode = FALSE;
463 
464 				/* kludge \! for naive users */
465 				if (cmntcnt > 0)
466 				{
467 					c = NOCHAR;
468 					continue;
469 				}
470 				else if (c != '!' || state == QST)
471 				{
472 					*q++ = '\\';
473 					continue;
474 				}
475 			}
476 
477 			if (c == '\\')
478 			{
479 				bslashmode = TRUE;
480 			}
481 			else if (state == QST)
482 			{
483 				/* do nothing, just avoid next clauses */
484 			}
485 			else if (c == '(')
486 			{
487 				cmntcnt++;
488 				c = NOCHAR;
489 			}
490 			else if (c == ')')
491 			{
492 				if (cmntcnt <= 0)
493 				{
494 					usrerr("653 Unbalanced ')'");
495 					c = NOCHAR;
496 				}
497 				else
498 					cmntcnt--;
499 			}
500 			else if (cmntcnt > 0)
501 				c = NOCHAR;
502 			else if (c == '<')
503 				anglecnt++;
504 			else if (c == '>')
505 			{
506 				if (anglecnt <= 0)
507 				{
508 					usrerr("653 Unbalanced '>'");
509 					c = NOCHAR;
510 				}
511 				else
512 					anglecnt--;
513 			}
514 			else if (delim == ' ' && isascii(c) && isspace(c))
515 				c = ' ';
516 
517 			if (c == NOCHAR)
518 				continue;
519 
520 			/* see if this is end of input */
521 			if (c == delim && anglecnt <= 0 && state != QST)
522 				break;
523 
524 			newstate = StateTab[state][toktype(c)];
525 			if (tTd(22, 101))
526 				printf("ns=%02o\n", newstate);
527 			state = newstate & TYPE;
528 			if (bitset(M, newstate))
529 				c = NOCHAR;
530 			if (bitset(B, newstate))
531 				break;
532 		}
533 
534 		/* new token */
535 		if (tok != q)
536 		{
537 			*q++ = '\0';
538 			if (tTd(22, 36))
539 			{
540 				printf("tok=");
541 				xputs(tok);
542 				(void) putchar('\n');
543 			}
544 			if (avp >= &av[MAXATOM])
545 			{
546 				syserr("553 prescan: too many tokens");
547 				goto returnnull;
548 			}
549 			if (q - tok > MAXNAME)
550 			{
551 				syserr("553 prescan: token too long");
552 				goto returnnull;
553 			}
554 			*avp++ = tok;
555 		}
556 	} while (c != '\0' && (c != delim || anglecnt > 0));
557 	*avp = NULL;
558 	p--;
559 	if (delimptr != NULL)
560 		*delimptr = p;
561 	if (tTd(22, 12))
562 	{
563 		printf("prescan==>");
564 		printav(av);
565 	}
566 	CurEnv->e_to = saveto;
567 	if (av[0] == NULL)
568 	{
569 		if (tTd(22, 1))
570 			printf("prescan: null leading token\n");
571 		return (NULL);
572 	}
573 	return (av);
574 }
575 /*
576 **  REWRITE -- apply rewrite rules to token vector.
577 **
578 **	This routine is an ordered production system.  Each rewrite
579 **	rule has a LHS (called the pattern) and a RHS (called the
580 **	rewrite); 'rwr' points the the current rewrite rule.
581 **
582 **	For each rewrite rule, 'avp' points the address vector we
583 **	are trying to match against, and 'pvp' points to the pattern.
584 **	If pvp points to a special match value (MATCHZANY, MATCHANY,
585 **	MATCHONE, MATCHCLASS, MATCHNCLASS) then the address in avp
586 **	matched is saved away in the match vector (pointed to by 'mvp').
587 **
588 **	When a match between avp & pvp does not match, we try to
589 **	back out.  If we back up over MATCHONE, MATCHCLASS, or MATCHNCLASS
590 **	we must also back out the match in mvp.  If we reach a
591 **	MATCHANY or MATCHZANY we just extend the match and start
592 **	over again.
593 **
594 **	When we finally match, we rewrite the address vector
595 **	and try over again.
596 **
597 **	Parameters:
598 **		pvp -- pointer to token vector.
599 **		ruleset -- the ruleset to use for rewriting.
600 **		reclevel -- recursion level (to catch loops).
601 **		e -- the current envelope.
602 **
603 **	Returns:
604 **		A status code.  If EX_TEMPFAIL, higher level code should
605 **			attempt recovery.
606 **
607 **	Side Effects:
608 **		pvp is modified.
609 */
610 
611 struct match
612 {
613 	char	**first;	/* first token matched */
614 	char	**last;		/* last token matched */
615 	char	**pattern;	/* pointer to pattern */
616 };
617 
618 # define MAXMATCH	9	/* max params per rewrite */
619 
620 # ifndef MAXRULERECURSION
621 #  define MAXRULERECURSION	50	/* max recursion depth */
622 # endif
623 
624 
625 int
626 rewrite(pvp, ruleset, reclevel, e)
627 	char **pvp;
628 	int ruleset;
629 	int reclevel;
630 	register ENVELOPE *e;
631 {
632 	register char *ap;		/* address pointer */
633 	register char *rp;		/* rewrite pointer */
634 	register char **avp;		/* address vector pointer */
635 	register char **rvp;		/* rewrite vector pointer */
636 	register struct match *mlp;	/* cur ptr into mlist */
637 	register struct rewrite *rwr;	/* pointer to current rewrite rule */
638 	int ruleno;			/* current rule number */
639 	int rstat = EX_OK;		/* return status */
640 	int loopcount;
641 	struct match mlist[MAXMATCH];	/* stores match on LHS */
642 	char *npvp[MAXATOM+1];		/* temporary space for rebuild */
643 
644 	if (OpMode == MD_TEST || tTd(21, 1))
645 	{
646 		printf("rewrite: ruleset %2d   input:", ruleset);
647 		printav(pvp);
648 	}
649 	if (ruleset < 0 || ruleset >= MAXRWSETS)
650 	{
651 		syserr("554 rewrite: illegal ruleset number %d", ruleset);
652 		return EX_CONFIG;
653 	}
654 	if (reclevel++ > MAXRULERECURSION)
655 	{
656 		syserr("rewrite: infinite recursion, ruleset %d", ruleset);
657 		return EX_CONFIG;
658 	}
659 	if (pvp == NULL)
660 		return EX_USAGE;
661 
662 	/*
663 	**  Run through the list of rewrite rules, applying
664 	**	any that match.
665 	*/
666 
667 	ruleno = 1;
668 	loopcount = 0;
669 	for (rwr = RewriteRules[ruleset]; rwr != NULL; )
670 	{
671 		if (tTd(21, 12))
672 		{
673 			printf("-----trying rule:");
674 			printav(rwr->r_lhs);
675 		}
676 
677 		/* try to match on this rule */
678 		mlp = mlist;
679 		rvp = rwr->r_lhs;
680 		avp = pvp;
681 		if (++loopcount > 100)
682 		{
683 			syserr("554 Infinite loop in ruleset %d, rule %d",
684 				ruleset, ruleno);
685 			if (tTd(21, 1))
686 			{
687 				printf("workspace: ");
688 				printav(pvp);
689 			}
690 			break;
691 		}
692 
693 		while ((ap = *avp) != NULL || *rvp != NULL)
694 		{
695 			rp = *rvp;
696 			if (tTd(21, 35))
697 			{
698 				printf("ADVANCE rp=");
699 				xputs(rp);
700 				printf(", ap=");
701 				xputs(ap);
702 				printf("\n");
703 			}
704 			if (rp == NULL)
705 			{
706 				/* end-of-pattern before end-of-address */
707 				goto backup;
708 			}
709 			if (ap == NULL && (*rp & 0377) != MATCHZANY &&
710 			    (*rp & 0377) != MATCHZERO)
711 			{
712 				/* end-of-input with patterns left */
713 				goto backup;
714 			}
715 
716 			switch (*rp & 0377)
717 			{
718 				register STAB *s;
719 				char buf[MAXLINE];
720 
721 			  case MATCHCLASS:
722 				/* match any phrase in a class */
723 				mlp->pattern = rvp;
724 				mlp->first = avp;
725 	extendclass:
726 				ap = *avp;
727 				if (ap == NULL)
728 					goto backup;
729 				mlp->last = avp++;
730 				cataddr(mlp->first, mlp->last, buf, sizeof buf, '\0');
731 				s = stab(buf, ST_CLASS, ST_FIND);
732 				if (s == NULL || !bitnset(rp[1], s->s_class))
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 				s = stab(ap, ST_CLASS, ST_FIND);
752 				if (s != NULL && bitnset(rp[1], s->s_class))
753 					goto backup;
754 
755 				/* fall through */
756 
757 			  case MATCHONE:
758 			  case MATCHANY:
759 				/* match exactly one token */
760 				mlp->pattern = rvp;
761 				mlp->first = avp;
762 				mlp->last = avp++;
763 				mlp++;
764 				break;
765 
766 			  case MATCHZANY:
767 				/* match zero or more tokens */
768 				mlp->pattern = rvp;
769 				mlp->first = avp;
770 				mlp->last = avp - 1;
771 				mlp++;
772 				break;
773 
774 			  case MATCHZERO:
775 				/* match zero tokens */
776 				break;
777 
778 			  case MACRODEXPAND:
779 				/*
780 				**  Match against run-time macro.
781 				**  This algorithm is broken for the
782 				**  general case (no recursive macros,
783 				**  improper tokenization) but should
784 				**  work for the usual cases.
785 				*/
786 
787 				ap = macvalue(rp[1], e);
788 				mlp->first = avp;
789 				if (tTd(21, 2))
790 					printf("rewrite: LHS $&%c => \"%s\"\n",
791 						rp[1],
792 						ap == NULL ? "(NULL)" : ap);
793 
794 				if (ap == NULL)
795 					break;
796 				while (*ap != '\0')
797 				{
798 					if (*avp == NULL ||
799 					    strncasecmp(ap, *avp, strlen(*avp)) != 0)
800 					{
801 						/* no match */
802 						avp = mlp->first;
803 						goto backup;
804 					}
805 					ap += strlen(*avp++);
806 				}
807 
808 				/* match */
809 				break;
810 
811 			  default:
812 				/* must have exact match */
813 				if (strcasecmp(rp, ap))
814 					goto backup;
815 				avp++;
816 				break;
817 			}
818 
819 			/* successful match on this token */
820 			rvp++;
821 			continue;
822 
823 	  backup:
824 			/* match failed -- back up */
825 			while (--mlp >= mlist)
826 			{
827 				rvp = mlp->pattern;
828 				rp = *rvp;
829 				avp = mlp->last + 1;
830 				ap = *avp;
831 
832 				if (tTd(21, 36))
833 				{
834 					printf("BACKUP  rp=");
835 					xputs(rp);
836 					printf(", ap=");
837 					xputs(ap);
838 					printf("\n");
839 				}
840 
841 				if (ap == NULL)
842 				{
843 					/* run off the end -- back up again */
844 					continue;
845 				}
846 				if ((*rp & 0377) == MATCHANY ||
847 				    (*rp & 0377) == MATCHZANY)
848 				{
849 					/* extend binding and continue */
850 					mlp->last = avp++;
851 					rvp++;
852 					mlp++;
853 					break;
854 				}
855 				if ((*rp & 0377) == MATCHCLASS)
856 				{
857 					/* extend binding and try again */
858 					mlp->last = avp;
859 					goto extendclass;
860 				}
861 			}
862 
863 			if (mlp < mlist)
864 			{
865 				/* total failure to match */
866 				break;
867 			}
868 		}
869 
870 		/*
871 		**  See if we successfully matched
872 		*/
873 
874 		if (mlp < mlist || *rvp != NULL)
875 		{
876 			if (tTd(21, 10))
877 				printf("----- rule fails\n");
878 			rwr = rwr->r_next;
879 			ruleno++;
880 			loopcount = 0;
881 			continue;
882 		}
883 
884 		rvp = rwr->r_rhs;
885 		if (tTd(21, 12))
886 		{
887 			printf("-----rule matches:");
888 			printav(rvp);
889 		}
890 
891 		rp = *rvp;
892 		if ((*rp & 0377) == CANONUSER)
893 		{
894 			rvp++;
895 			rwr = rwr->r_next;
896 			ruleno++;
897 			loopcount = 0;
898 		}
899 		else if ((*rp & 0377) == CANONHOST)
900 		{
901 			rvp++;
902 			rwr = NULL;
903 		}
904 		else if ((*rp & 0377) == CANONNET)
905 			rwr = NULL;
906 
907 		/* substitute */
908 		for (avp = npvp; *rvp != NULL; rvp++)
909 		{
910 			register struct match *m;
911 			register char **pp;
912 
913 			rp = *rvp;
914 			if ((*rp & 0377) == MATCHREPL)
915 			{
916 				/* substitute from LHS */
917 				m = &mlist[rp[1] - '1'];
918 				if (m < mlist || m >= mlp)
919 				{
920 					syserr("554 rewrite: ruleset %d: replacement $%c out of bounds",
921 						ruleset, rp[1]);
922 					return EX_CONFIG;
923 				}
924 				if (tTd(21, 15))
925 				{
926 					printf("$%c:", rp[1]);
927 					pp = m->first;
928 					while (pp <= m->last)
929 					{
930 						printf(" %x=\"", *pp);
931 						(void) fflush(stdout);
932 						printf("%s\"", *pp++);
933 					}
934 					printf("\n");
935 				}
936 				pp = m->first;
937 				while (pp <= m->last)
938 				{
939 					if (avp >= &npvp[MAXATOM])
940 					{
941 						syserr("554 rewrite: expansion too long");
942 						return EX_DATAERR;
943 					}
944 					*avp++ = *pp++;
945 				}
946 			}
947 			else
948 			{
949 				/* vanilla replacement */
950 				if (avp >= &npvp[MAXATOM])
951 				{
952 	toolong:
953 					syserr("554 rewrite: expansion too long");
954 					return EX_DATAERR;
955 				}
956 				if ((*rp & 0377) != MACRODEXPAND)
957 					*avp++ = rp;
958 				else
959 				{
960 					*avp = macvalue(rp[1], e);
961 					if (tTd(21, 2))
962 						printf("rewrite: RHS $&%c => \"%s\"\n",
963 							rp[1],
964 							*avp == NULL ? "(NULL)" : *avp);
965 					if (*avp != NULL)
966 						avp++;
967 				}
968 			}
969 		}
970 		*avp++ = NULL;
971 
972 		/*
973 		**  Check for any hostname/keyword lookups.
974 		*/
975 
976 		for (rvp = npvp; *rvp != NULL; rvp++)
977 		{
978 			char **hbrvp;
979 			char **xpvp;
980 			int trsize;
981 			char *replac;
982 			int endtoken;
983 			STAB *map;
984 			char *mapname;
985 			char **key_rvp;
986 			char **arg_rvp;
987 			char **default_rvp;
988 			char buf[MAXNAME + 1];
989 			char *pvpb1[MAXATOM + 1];
990 			char *argvect[10];
991 			char pvpbuf[PSBUFSIZE];
992 			char *nullpvp[1];
993 
994 			if ((**rvp & 0377) != HOSTBEGIN &&
995 			    (**rvp & 0377) != LOOKUPBEGIN)
996 				continue;
997 
998 			/*
999 			**  Got a hostname/keyword lookup.
1000 			**
1001 			**	This could be optimized fairly easily.
1002 			*/
1003 
1004 			hbrvp = rvp;
1005 			if ((**rvp & 0377) == HOSTBEGIN)
1006 			{
1007 				endtoken = HOSTEND;
1008 				mapname = "host";
1009 			}
1010 			else
1011 			{
1012 				endtoken = LOOKUPEND;
1013 				mapname = *++rvp;
1014 			}
1015 			map = stab(mapname, ST_MAP, ST_FIND);
1016 			if (map == NULL)
1017 				syserr("554 rewrite: map %s not found", mapname);
1018 
1019 			/* extract the match part */
1020 			key_rvp = ++rvp;
1021 			default_rvp = NULL;
1022 			arg_rvp = argvect;
1023 			xpvp = NULL;
1024 			replac = pvpbuf;
1025 			while (*rvp != NULL && (**rvp & 0377) != endtoken)
1026 			{
1027 				int nodetype = **rvp & 0377;
1028 
1029 				if (nodetype != CANONHOST && nodetype != CANONUSER)
1030 				{
1031 					rvp++;
1032 					continue;
1033 				}
1034 
1035 				*rvp++ = NULL;
1036 
1037 				if (xpvp != NULL)
1038 				{
1039 					cataddr(xpvp, NULL, replac,
1040 						&pvpbuf[sizeof pvpbuf] - replac,
1041 						'\0');
1042 					*++arg_rvp = replac;
1043 					replac += strlen(replac) + 1;
1044 					xpvp = NULL;
1045 				}
1046 				switch (nodetype)
1047 				{
1048 				  case CANONHOST:
1049 					xpvp = rvp;
1050 					break;
1051 
1052 				  case CANONUSER:
1053 					default_rvp = rvp;
1054 					break;
1055 				}
1056 			}
1057 			if (*rvp != NULL)
1058 				*rvp++ = NULL;
1059 			if (xpvp != NULL)
1060 			{
1061 				cataddr(xpvp, NULL, replac,
1062 					&pvpbuf[sizeof pvpbuf] - replac,
1063 					'\0');
1064 				*++arg_rvp = replac;
1065 			}
1066 			*++arg_rvp = NULL;
1067 
1068 			/* save the remainder of the input string */
1069 			trsize = (int) (avp - rvp + 1) * sizeof *rvp;
1070 			bcopy((char *) rvp, (char *) pvpb1, trsize);
1071 
1072 			/* look it up */
1073 			cataddr(key_rvp, NULL, buf, sizeof buf, '\0');
1074 			argvect[0] = buf;
1075 			if (map != NULL && bitset(MF_OPEN, map->s_map.map_mflags))
1076 			{
1077 				auto int stat = EX_OK;
1078 
1079 				/* XXX should try to auto-open the map here */
1080 
1081 				if (tTd(60, 1))
1082 					printf("map_lookup(%s, %s) => ",
1083 						mapname, buf);
1084 				replac = (*map->s_map.map_class->map_lookup)(&map->s_map,
1085 						buf, argvect, &stat);
1086 				if (tTd(60, 1))
1087 					printf("%s (%d)\n",
1088 						replac ? replac : "NOT FOUND",
1089 						stat);
1090 
1091 				/* should recover if stat == EX_TEMPFAIL */
1092 				if (stat == EX_TEMPFAIL)
1093 					rstat = stat;
1094 			}
1095 			else
1096 				replac = NULL;
1097 
1098 			/* if no replacement, use default */
1099 			if (replac == NULL && default_rvp != NULL)
1100 			{
1101 				/* create the default */
1102 				cataddr(default_rvp, NULL, buf, sizeof buf, '\0');
1103 				replac = buf;
1104 			}
1105 
1106 			if (replac == NULL)
1107 			{
1108 				xpvp = key_rvp;
1109 			}
1110 			else if (*replac == '\0')
1111 			{
1112 				/* null replacement */
1113 				nullpvp[0] = NULL;
1114 				xpvp = nullpvp;
1115 			}
1116 			else
1117 			{
1118 				/* scan the new replacement */
1119 				xpvp = prescan(replac, '\0', pvpbuf,
1120 					       sizeof pvpbuf, NULL);
1121 				if (xpvp == NULL)
1122 				{
1123 					/* prescan already printed error */
1124 					return EX_DATAERR;
1125 				}
1126 			}
1127 
1128 			/* append it to the token list */
1129 			for (avp = hbrvp; *xpvp != NULL; xpvp++)
1130 			{
1131 				*avp++ = newstr(*xpvp);
1132 				if (avp >= &npvp[MAXATOM])
1133 					goto toolong;
1134 			}
1135 
1136 			/* restore the old trailing information */
1137 			for (xpvp = pvpb1; (*avp++ = *xpvp++) != NULL; )
1138 				if (avp >= &npvp[MAXATOM])
1139 					goto toolong;
1140 
1141 			break;
1142 		}
1143 
1144 		/*
1145 		**  Check for subroutine calls.
1146 		*/
1147 
1148 		if (*npvp != NULL && (**npvp & 0377) == CALLSUBR)
1149 		{
1150 			int stat;
1151 
1152 			if (npvp[1] == NULL)
1153 			{
1154 				syserr("parseaddr: NULL subroutine call in ruleset %d, rule %d",
1155 					ruleset, ruleno);
1156 				*pvp = NULL;
1157 			}
1158 			else
1159 			{
1160 				bcopy((char *) &npvp[2], (char *) pvp,
1161 					(int) (avp - npvp - 2) * sizeof *avp);
1162 				if (tTd(21, 3))
1163 					printf("-----callsubr %s\n", npvp[1]);
1164 				stat = rewrite(pvp, atoi(npvp[1]), reclevel, e);
1165 				if (rstat == EX_OK || stat == EX_TEMPFAIL)
1166 					rstat = stat;
1167 				if (*pvp != NULL && (**pvp & 0377) == CANONNET)
1168 				rwr = NULL;
1169 			}
1170 		}
1171 		else
1172 		{
1173 			bcopy((char *) npvp, (char *) pvp,
1174 				(int) (avp - npvp) * sizeof *avp);
1175 		}
1176 		if (tTd(21, 4))
1177 		{
1178 			printf("rewritten as:");
1179 			printav(pvp);
1180 		}
1181 	}
1182 
1183 	if (OpMode == MD_TEST || tTd(21, 1))
1184 	{
1185 		printf("rewrite: ruleset %2d returns:", ruleset);
1186 		printav(pvp);
1187 	}
1188 
1189 	return rstat;
1190 }
1191 /*
1192 **  BUILDADDR -- build address from token vector.
1193 **
1194 **	Parameters:
1195 **		tv -- token vector.
1196 **		a -- pointer to address descriptor to fill.
1197 **			If NULL, one will be allocated.
1198 **		flags -- info regarding whether this is a sender or
1199 **			a recipient.
1200 **		e -- the current envelope.
1201 **
1202 **	Returns:
1203 **		NULL if there was an error.
1204 **		'a' otherwise.
1205 **
1206 **	Side Effects:
1207 **		fills in 'a'
1208 */
1209 
1210 struct errcodes
1211 {
1212 	char	*ec_name;		/* name of error code */
1213 	int	ec_code;		/* numeric code */
1214 } ErrorCodes[] =
1215 {
1216 	"usage",	EX_USAGE,
1217 	"nouser",	EX_NOUSER,
1218 	"nohost",	EX_NOHOST,
1219 	"unavailable",	EX_UNAVAILABLE,
1220 	"software",	EX_SOFTWARE,
1221 	"tempfail",	EX_TEMPFAIL,
1222 	"protocol",	EX_PROTOCOL,
1223 #ifdef EX_CONFIG
1224 	"config",	EX_CONFIG,
1225 #endif
1226 	NULL,		EX_UNAVAILABLE,
1227 };
1228 
1229 ADDRESS *
1230 buildaddr(tv, a, flags, e)
1231 	register char **tv;
1232 	register ADDRESS *a;
1233 	int flags;
1234 	register ENVELOPE *e;
1235 {
1236 	struct mailer **mp;
1237 	register struct mailer *m;
1238 	char *bp;
1239 	int spaceleft;
1240 	static MAILER errormailer;
1241 	static char *errorargv[] = { "ERROR", NULL };
1242 	static char buf[MAXNAME];
1243 
1244 	if (tTd(24, 5))
1245 	{
1246 		printf("buildaddr, flags=%x, tv=", flags);
1247 		printav(tv);
1248 	}
1249 
1250 	if (a == NULL)
1251 		a = (ADDRESS *) xalloc(sizeof *a);
1252 	bzero((char *) a, sizeof *a);
1253 
1254 	/* set up default error return flags */
1255 	a->q_flags |= QPINGONFAILURE|QPINGONDELAY;
1256 
1257 	/* figure out what net/mailer to use */
1258 	if (*tv == NULL || (**tv & 0377) != CANONNET)
1259 	{
1260 		syserr("554 buildaddr: no net");
1261 badaddr:
1262 		a->q_flags |= QBADADDR;
1263 		a->q_mailer = &errormailer;
1264 		if (errormailer.m_name == NULL)
1265 		{
1266 			/* initialize the bogus mailer */
1267 			errormailer.m_name = "*error*";
1268 			errormailer.m_mailer = "ERROR";
1269 			errormailer.m_argv = errorargv;
1270 		}
1271 		return a;
1272 	}
1273 	tv++;
1274 	if (strcasecmp(*tv, "error") == 0)
1275 	{
1276 		if ((**++tv & 0377) == CANONHOST)
1277 		{
1278 			register struct errcodes *ep;
1279 
1280 			if (isascii(**++tv) && isdigit(**tv))
1281 			{
1282 				setstat(atoi(*tv));
1283 			}
1284 			else
1285 			{
1286 				for (ep = ErrorCodes; ep->ec_name != NULL; ep++)
1287 					if (strcasecmp(ep->ec_name, *tv) == 0)
1288 						break;
1289 				setstat(ep->ec_code);
1290 			}
1291 			tv++;
1292 		}
1293 		else
1294 			setstat(EX_UNAVAILABLE);
1295 		if ((**tv & 0377) != CANONUSER)
1296 			syserr("554 buildaddr: error: no user");
1297 		cataddr(++tv, NULL, buf, sizeof buf, ' ');
1298 		stripquotes(buf);
1299 		if (isascii(buf[0]) && isdigit(buf[0]) &&
1300 		    isascii(buf[1]) && isdigit(buf[1]) &&
1301 		    isascii(buf[2]) && isdigit(buf[2]) &&
1302 		    buf[3] == ' ')
1303 		{
1304 			char fmt[10];
1305 
1306 			strncpy(fmt, buf, 3);
1307 			strcpy(&fmt[3], " %s");
1308 			usrerr(fmt, buf + 4);
1309 
1310 			/*
1311 			**  If this is a 4xx code and we aren't running
1312 			**  SMTP on our input, bounce this message;
1313 			**  otherwise it disappears without a trace.
1314 			*/
1315 
1316 			if (fmt[0] == '4' && OpMode != MD_SMTP &&
1317 			    OpMode != MD_DAEMON)
1318 			{
1319 				e->e_flags |= EF_FATALERRS;
1320 			}
1321 		}
1322 		else
1323 		{
1324 			usrerr("553 %s", buf);
1325 		}
1326 		goto badaddr;
1327 	}
1328 
1329 	for (mp = Mailer; (m = *mp++) != NULL; )
1330 	{
1331 		if (strcasecmp(m->m_name, *tv) == 0)
1332 			break;
1333 	}
1334 	if (m == NULL)
1335 	{
1336 		syserr("554 buildaddr: unknown mailer %s", *tv);
1337 		goto badaddr;
1338 	}
1339 	a->q_mailer = m;
1340 
1341 	/* figure out what host (if any) */
1342 	tv++;
1343 	if ((**tv & 0377) == CANONHOST)
1344 	{
1345 		bp = buf;
1346 		spaceleft = sizeof buf - 1;
1347 		while (*++tv != NULL && (**tv & 0377) != CANONUSER)
1348 		{
1349 			int i = strlen(*tv);
1350 
1351 			if (i > spaceleft)
1352 			{
1353 				/* out of space for this address */
1354 				if (spaceleft >= 0)
1355 					syserr("554 buildaddr: host too long (%.40s...)",
1356 						buf);
1357 				i = spaceleft;
1358 				spaceleft = 0;
1359 			}
1360 			if (i <= 0)
1361 				continue;
1362 			bcopy(*tv, bp, i);
1363 			bp += i;
1364 			spaceleft -= i;
1365 		}
1366 		*bp = '\0';
1367 		a->q_host = newstr(buf);
1368 	}
1369 	else
1370 	{
1371 		if (!bitnset(M_LOCALMAILER, m->m_flags))
1372 		{
1373 			syserr("554 buildaddr: no host");
1374 			goto badaddr;
1375 		}
1376 		a->q_host = NULL;
1377 	}
1378 
1379 	/* figure out the user */
1380 	if (*tv == NULL || (**tv & 0377) != CANONUSER)
1381 	{
1382 		syserr("554 buildaddr: no user");
1383 		goto badaddr;
1384 	}
1385 	tv++;
1386 
1387 	if (bitnset(M_CHECKUDB, m->m_flags) && *tv != NULL &&
1388 	    strcmp(*tv, "@") == 0)
1389 	{
1390 		tv++;
1391 		a->q_flags |= QNOTREMOTE;
1392 	}
1393 
1394 	/* do special mapping for local mailer */
1395 	if (*tv != NULL)
1396 	{
1397 		register char *p = *tv;
1398 
1399 		if (*p == '"')
1400 			p++;
1401 		if (*p == '|' && bitnset(M_CHECKPROG, m->m_flags))
1402 			a->q_mailer = m = ProgMailer;
1403 		else if (*p == '/' && bitnset(M_CHECKFILE, m->m_flags))
1404 			a->q_mailer = m = FileMailer;
1405 		else if (*p == ':' && bitnset(M_CHECKINCLUDE, m->m_flags))
1406 		{
1407 			/* may be :include: */
1408 			cataddr(tv, NULL, buf, sizeof buf, '\0');
1409 			stripquotes(buf);
1410 			if (strncasecmp(buf, ":include:", 9) == 0)
1411 			{
1412 				/* if :include:, don't need further rewriting */
1413 				a->q_mailer = m = InclMailer;
1414 				a->q_user = &buf[9];
1415 				return (a);
1416 			}
1417 		}
1418 	}
1419 
1420 	/* rewrite according recipient mailer rewriting rules */
1421 	define('h', a->q_host, e);
1422 	if (!bitset(RF_SENDERADDR|RF_HEADERADDR, flags))
1423 	{
1424 		/* sender addresses done later */
1425 		(void) rewrite(tv, 2, 0, e);
1426 		if (m->m_re_rwset > 0)
1427 		       (void) rewrite(tv, m->m_re_rwset, 0, e);
1428 	}
1429 	(void) rewrite(tv, 4, 0, e);
1430 
1431 	/* save the result for the command line/RCPT argument */
1432 	cataddr(tv, NULL, buf, sizeof buf, '\0');
1433 	a->q_user = buf;
1434 
1435 	/*
1436 	**  Do mapping to lower case as requested by mailer
1437 	*/
1438 
1439 	if (a->q_host != NULL && !bitnset(M_HST_UPPER, m->m_flags))
1440 		makelower(a->q_host);
1441 	if (!bitnset(M_USR_UPPER, m->m_flags))
1442 		makelower(a->q_user);
1443 
1444 	return (a);
1445 }
1446 /*
1447 **  CATADDR -- concatenate pieces of addresses (putting in <LWSP> subs)
1448 **
1449 **	Parameters:
1450 **		pvp -- parameter vector to rebuild.
1451 **		evp -- last parameter to include.  Can be NULL to
1452 **			use entire pvp.
1453 **		buf -- buffer to build the string into.
1454 **		sz -- size of buf.
1455 **		spacesub -- the space separator character; if null,
1456 **			use SpaceSub.
1457 **
1458 **	Returns:
1459 **		none.
1460 **
1461 **	Side Effects:
1462 **		Destroys buf.
1463 */
1464 
1465 cataddr(pvp, evp, buf, sz, spacesub)
1466 	char **pvp;
1467 	char **evp;
1468 	char *buf;
1469 	register int sz;
1470 	char spacesub;
1471 {
1472 	bool oatomtok = FALSE;
1473 	bool natomtok = FALSE;
1474 	register int i;
1475 	register char *p;
1476 
1477 	if (spacesub == '\0')
1478 		spacesub = SpaceSub;
1479 
1480 	if (pvp == NULL)
1481 	{
1482 		(void) strcpy(buf, "");
1483 		return;
1484 	}
1485 	p = buf;
1486 	sz -= 2;
1487 	while (*pvp != NULL && (i = strlen(*pvp)) < sz)
1488 	{
1489 		natomtok = (toktype(**pvp) == ATM);
1490 		if (oatomtok && natomtok)
1491 			*p++ = spacesub;
1492 		(void) strcpy(p, *pvp);
1493 		oatomtok = natomtok;
1494 		p += i;
1495 		sz -= i + 1;
1496 		if (pvp++ == evp)
1497 			break;
1498 	}
1499 	*p = '\0';
1500 }
1501 /*
1502 **  SAMEADDR -- Determine if two addresses are the same
1503 **
1504 **	This is not just a straight comparison -- if the mailer doesn't
1505 **	care about the host we just ignore it, etc.
1506 **
1507 **	Parameters:
1508 **		a, b -- pointers to the internal forms to compare.
1509 **
1510 **	Returns:
1511 **		TRUE -- they represent the same mailbox.
1512 **		FALSE -- they don't.
1513 **
1514 **	Side Effects:
1515 **		none.
1516 */
1517 
1518 bool
1519 sameaddr(a, b)
1520 	register ADDRESS *a;
1521 	register ADDRESS *b;
1522 {
1523 	register ADDRESS *ca, *cb;
1524 
1525 	/* if they don't have the same mailer, forget it */
1526 	if (a->q_mailer != b->q_mailer)
1527 		return (FALSE);
1528 
1529 	/* if the user isn't the same, we can drop out */
1530 	if (strcmp(a->q_user, b->q_user) != 0)
1531 		return (FALSE);
1532 
1533 	/* if we have good uids for both but they differ, these are different */
1534 	if (a->q_mailer == ProgMailer)
1535 	{
1536 		ca = getctladdr(a);
1537 		cb = getctladdr(b);
1538 		if (ca != NULL && cb != NULL &&
1539 		    bitset(QGOODUID, ca->q_flags & cb->q_flags) &&
1540 		    ca->q_uid != cb->q_uid)
1541 			return (FALSE);
1542 	}
1543 
1544 	/* otherwise compare hosts (but be careful for NULL ptrs) */
1545 	if (a->q_host == b->q_host)
1546 	{
1547 		/* probably both null pointers */
1548 		return (TRUE);
1549 	}
1550 	if (a->q_host == NULL || b->q_host == NULL)
1551 	{
1552 		/* only one is a null pointer */
1553 		return (FALSE);
1554 	}
1555 	if (strcmp(a->q_host, b->q_host) != 0)
1556 		return (FALSE);
1557 
1558 	return (TRUE);
1559 }
1560 /*
1561 **  PRINTADDR -- print address (for debugging)
1562 **
1563 **	Parameters:
1564 **		a -- the address to print
1565 **		follow -- follow the q_next chain.
1566 **
1567 **	Returns:
1568 **		none.
1569 **
1570 **	Side Effects:
1571 **		none.
1572 */
1573 
1574 struct qflags
1575 {
1576 	char	*qf_name;
1577 	u_long	qf_bit;
1578 };
1579 
1580 struct qflags	AddressFlags[] =
1581 {
1582 	"QDONTSEND",		QDONTSEND,
1583 	"QBADADDR",		QBADADDR,
1584 	"QGOODUID",		QGOODUID,
1585 	"QPRIMARY",		QPRIMARY,
1586 	"QQUEUEUP",		QQUEUEUP,
1587 	"QSENT",		QSENT,
1588 	"QNOTREMOTE",		QNOTREMOTE,
1589 	"QSELFREF",		QSELFREF,
1590 	"QVERIFIED",		QVERIFIED,
1591 	"QREPORT",		QREPORT,
1592 	"QBOGUSSHELL",		QBOGUSSHELL,
1593 	"QUNSAFEADDR",		QUNSAFEADDR,
1594 	"QPINGONSUCCESS",	QPINGONSUCCESS,
1595 	"QPINGONFAILURE",	QPINGONFAILURE,
1596 	"QPINGONDELAY",		QPINGONDELAY,
1597 	"QHAS_RET_PARAM",	QHAS_RET_PARAM,
1598 	"QRET_HDRS",		QRET_HDRS,
1599 	"QRELAYED",		QRELAYED,
1600 	NULL
1601 };
1602 
1603 printaddr(a, follow)
1604 	register ADDRESS *a;
1605 	bool follow;
1606 {
1607 	register MAILER *m;
1608 	MAILER pseudomailer;
1609 	register struct qflags *qfp;
1610 	bool firstone;
1611 
1612 	if (a == NULL)
1613 	{
1614 		printf("[NULL]\n");
1615 		return;
1616 	}
1617 
1618 	while (a != NULL)
1619 	{
1620 		printf("%x=", a);
1621 		(void) fflush(stdout);
1622 
1623 		/* find the mailer -- carefully */
1624 		m = a->q_mailer;
1625 		if (m == NULL)
1626 		{
1627 			m = &pseudomailer;
1628 			m->m_mno = -1;
1629 			m->m_name = "NULL";
1630 		}
1631 
1632 		printf("%s:\n\tmailer %d (%s), host `%s', user `%s', ruser `%s'\n",
1633 		       a->q_paddr, m->m_mno, m->m_name,
1634 		       a->q_host == NULL ? "<null>" : a->q_host, a->q_user,
1635 		       a->q_ruser == NULL ? "<null>" : a->q_ruser);
1636 		printf("\tnext=%x, alias %x, uid %d, gid %d\n",
1637 		       a->q_next, a->q_alias, a->q_uid, a->q_gid);
1638 		printf("\tflags=%lx<", a->q_flags);
1639 		firstone = TRUE;
1640 		for (qfp = AddressFlags; qfp->qf_name != NULL; qfp++)
1641 		{
1642 			if (!bitset(qfp->qf_bit, a->q_flags))
1643 				continue;
1644 			if (!firstone)
1645 				printf(",");
1646 			firstone = FALSE;
1647 			printf("%s", qfp->qf_name);
1648 		}
1649 		printf(">\n");
1650 		printf("\towner=%s, home=\"%s\", fullname=\"%s\"\n",
1651 		       a->q_owner == NULL ? "(none)" : a->q_owner,
1652 		       a->q_home == NULL ? "(none)" : a->q_home,
1653 		       a->q_fullname == NULL ? "(none)" : a->q_fullname);
1654 		printf("\torcpt=\"%s\", statmta=%s, fstatus=%s, rstatus=%s\n",
1655 		       a->q_orcpt == NULL ? "(none)" : a->q_orcpt,
1656 		       a->q_statmta == NULL ? "(none)" : a->q_statmta,
1657 		       a->q_fstatus == NULL ? "(none)" : a->q_fstatus,
1658 		       a->q_rstatus == NULL ? "(none)" : a->q_rstatus);
1659 
1660 		if (!follow)
1661 			return;
1662 		a = a->q_next;
1663 	}
1664 }
1665 /*
1666 **  EMPTYADDR -- return TRUE if this address is empty (``<>'')
1667 **
1668 **	Parameters:
1669 **		a -- pointer to the address
1670 **
1671 **	Returns:
1672 **		TRUE -- if this address is "empty" (i.e., no one should
1673 **			ever generate replies to it.
1674 **		FALSE -- if it is a "regular" (read: replyable) address.
1675 */
1676 
1677 bool
1678 emptyaddr(a)
1679 	register ADDRESS *a;
1680 {
1681 	return strcmp(a->q_paddr, "<>") == 0 || strcmp(a->q_user, "<>") == 0;
1682 }
1683 /*
1684 **  REMOTENAME -- return the name relative to the current mailer
1685 **
1686 **	Parameters:
1687 **		name -- the name to translate.
1688 **		m -- the mailer that we want to do rewriting relative
1689 **			to.
1690 **		flags -- fine tune operations.
1691 **		pstat -- pointer to status word.
1692 **		e -- the current envelope.
1693 **
1694 **	Returns:
1695 **		the text string representing this address relative to
1696 **			the receiving mailer.
1697 **
1698 **	Side Effects:
1699 **		none.
1700 **
1701 **	Warnings:
1702 **		The text string returned is tucked away locally;
1703 **			copy it if you intend to save it.
1704 */
1705 
1706 char *
1707 remotename(name, m, flags, pstat, e)
1708 	char *name;
1709 	struct mailer *m;
1710 	int flags;
1711 	int *pstat;
1712 	register ENVELOPE *e;
1713 {
1714 	register char **pvp;
1715 	char *fancy;
1716 	char *oldg = macvalue('g', e);
1717 	int rwset;
1718 	static char buf[MAXNAME];
1719 	char lbuf[MAXNAME];
1720 	char pvpbuf[PSBUFSIZE];
1721 	extern char *crackaddr();
1722 
1723 	if (tTd(12, 1))
1724 		printf("remotename(%s)\n", name);
1725 
1726 	/* don't do anything if we are tagging it as special */
1727 	if (bitset(RF_SENDERADDR, flags))
1728 		rwset = bitset(RF_HEADERADDR, flags) ? m->m_sh_rwset
1729 						     : m->m_se_rwset;
1730 	else
1731 		rwset = bitset(RF_HEADERADDR, flags) ? m->m_rh_rwset
1732 						     : m->m_re_rwset;
1733 	if (rwset < 0)
1734 		return (name);
1735 
1736 	/*
1737 	**  Do a heuristic crack of this name to extract any comment info.
1738 	**	This will leave the name as a comment and a $g macro.
1739 	*/
1740 
1741 	if (bitset(RF_CANONICAL, flags) || bitnset(M_NOCOMMENT, m->m_flags))
1742 		fancy = "\201g";
1743 	else
1744 		fancy = crackaddr(name);
1745 
1746 	/*
1747 	**  Turn the name into canonical form.
1748 	**	Normally this will be RFC 822 style, i.e., "user@domain".
1749 	**	If this only resolves to "user", and the "C" flag is
1750 	**	specified in the sending mailer, then the sender's
1751 	**	domain will be appended.
1752 	*/
1753 
1754 	pvp = prescan(name, '\0', pvpbuf, sizeof pvpbuf, NULL);
1755 	if (pvp == NULL)
1756 		return (name);
1757 	if (rewrite(pvp, 3, 0, e) == EX_TEMPFAIL)
1758 		*pstat = EX_TEMPFAIL;
1759 	if (bitset(RF_ADDDOMAIN, flags) && e->e_fromdomain != NULL)
1760 	{
1761 		/* append from domain to this address */
1762 		register char **pxp = pvp;
1763 
1764 		/* see if there is an "@domain" in the current name */
1765 		while (*pxp != NULL && strcmp(*pxp, "@") != 0)
1766 			pxp++;
1767 		if (*pxp == NULL)
1768 		{
1769 			/* no.... append the "@domain" from the sender */
1770 			register char **qxq = e->e_fromdomain;
1771 
1772 			while ((*pxp++ = *qxq++) != NULL)
1773 				continue;
1774 			if (rewrite(pvp, 3, 0, e) == EX_TEMPFAIL)
1775 				*pstat = EX_TEMPFAIL;
1776 		}
1777 	}
1778 
1779 	/*
1780 	**  Do more specific rewriting.
1781 	**	Rewrite using ruleset 1 or 2 depending on whether this is
1782 	**		a sender address or not.
1783 	**	Then run it through any receiving-mailer-specific rulesets.
1784 	*/
1785 
1786 	if (bitset(RF_SENDERADDR, flags))
1787 	{
1788 		if (rewrite(pvp, 1, 0, e) == EX_TEMPFAIL)
1789 			*pstat = EX_TEMPFAIL;
1790 	}
1791 	else
1792 	{
1793 		if (rewrite(pvp, 2, 0, e) == EX_TEMPFAIL)
1794 			*pstat = EX_TEMPFAIL;
1795 	}
1796 	if (rwset > 0)
1797 	{
1798 		if (rewrite(pvp, rwset, 0, e) == EX_TEMPFAIL)
1799 			*pstat = EX_TEMPFAIL;
1800 	}
1801 
1802 	/*
1803 	**  Do any final sanitation the address may require.
1804 	**	This will normally be used to turn internal forms
1805 	**	(e.g., user@host.LOCAL) into external form.  This
1806 	**	may be used as a default to the above rules.
1807 	*/
1808 
1809 	if (rewrite(pvp, 4, 0, e) == EX_TEMPFAIL)
1810 		*pstat = EX_TEMPFAIL;
1811 
1812 	/*
1813 	**  Now restore the comment information we had at the beginning.
1814 	*/
1815 
1816 	cataddr(pvp, NULL, lbuf, sizeof lbuf, '\0');
1817 	define('g', lbuf, e);
1818 
1819 	/* need to make sure route-addrs have <angle brackets> */
1820 	if (bitset(RF_CANONICAL, flags) && lbuf[0] == '@')
1821 		expand("<\201g>", buf, &buf[sizeof buf - 1], e);
1822 	else
1823 		expand(fancy, buf, &buf[sizeof buf - 1], e);
1824 
1825 	define('g', oldg, e);
1826 
1827 	if (tTd(12, 1))
1828 		printf("remotename => `%s'\n", buf);
1829 	return (buf);
1830 }
1831 /*
1832 **  MAPLOCALUSER -- run local username through ruleset 5 for final redirection
1833 **
1834 **	Parameters:
1835 **		a -- the address to map (but just the user name part).
1836 **		sendq -- the sendq in which to install any replacement
1837 **			addresses.
1838 **		aliaslevel -- the alias nesting depth.
1839 **		e -- the envelope.
1840 **
1841 **	Returns:
1842 **		none.
1843 */
1844 
1845 maplocaluser(a, sendq, aliaslevel, e)
1846 	register ADDRESS *a;
1847 	ADDRESS **sendq;
1848 	int aliaslevel;
1849 	ENVELOPE *e;
1850 {
1851 	register char **pvp;
1852 	register ADDRESS *a1 = NULL;
1853 	auto char *delimptr;
1854 	char pvpbuf[PSBUFSIZE];
1855 
1856 	if (tTd(29, 1))
1857 	{
1858 		printf("maplocaluser: ");
1859 		printaddr(a, FALSE);
1860 	}
1861 	pvp = prescan(a->q_user, '\0', pvpbuf, sizeof pvpbuf, &delimptr);
1862 	if (pvp == NULL)
1863 		return;
1864 
1865 	(void) rewrite(pvp, 5, 0, e);
1866 	if (pvp[0] == NULL || (pvp[0][0] & 0377) != CANONNET)
1867 		return;
1868 
1869 	/* if non-null, mailer destination specified -- has it changed? */
1870 	a1 = buildaddr(pvp, NULL, 0, e);
1871 	if (a1 == NULL || sameaddr(a, a1))
1872 		return;
1873 
1874 	/* mark old address as dead; insert new address */
1875 	a->q_flags |= QDONTSEND;
1876 	if (tTd(29, 5))
1877 	{
1878 		printf("maplocaluser: QDONTSEND ");
1879 		printaddr(a, FALSE);
1880 	}
1881 	a1->q_alias = a;
1882 	allocaddr(a1, RF_COPYALL, NULL);
1883 	(void) recipient(a1, sendq, aliaslevel, e);
1884 }
1885 /*
1886 **  DEQUOTE_INIT -- initialize dequote map
1887 **
1888 **	This is a no-op.
1889 **
1890 **	Parameters:
1891 **		map -- the internal map structure.
1892 **		args -- arguments.
1893 **
1894 **	Returns:
1895 **		TRUE.
1896 */
1897 
1898 bool
1899 dequote_init(map, args)
1900 	MAP *map;
1901 	char *args;
1902 {
1903 	register char *p = args;
1904 
1905 	for (;;)
1906 	{
1907 		while (isascii(*p) && isspace(*p))
1908 			p++;
1909 		if (*p != '-')
1910 			break;
1911 		switch (*++p)
1912 		{
1913 		  case 'a':
1914 			map->map_app = ++p;
1915 			break;
1916 
1917 		  case 's':
1918 			map->map_coldelim = *++p;
1919 			break;
1920 		}
1921 		while (*p != '\0' && !(isascii(*p) && isspace(*p)))
1922 			p++;
1923 		if (*p != '\0')
1924 			*p = '\0';
1925 	}
1926 	if (map->map_app != NULL)
1927 		map->map_app = newstr(map->map_app);
1928 
1929 	return TRUE;
1930 }
1931 /*
1932 **  DEQUOTE_MAP -- unquote an address
1933 **
1934 **	Parameters:
1935 **		map -- the internal map structure (ignored).
1936 **		name -- the name to dequote.
1937 **		av -- arguments (ignored).
1938 **		statp -- pointer to status out-parameter.
1939 **
1940 **	Returns:
1941 **		NULL -- if there were no quotes, or if the resulting
1942 **			unquoted buffer would not be acceptable to prescan.
1943 **		else -- The dequoted buffer.
1944 */
1945 
1946 char *
1947 dequote_map(map, name, av, statp)
1948 	MAP *map;
1949 	char *name;
1950 	char **av;
1951 	int *statp;
1952 {
1953 	register char *p;
1954 	register char *q;
1955 	register char c;
1956 	int anglecnt = 0;
1957 	int cmntcnt = 0;
1958 	int quotecnt = 0;
1959 	int spacecnt = 0;
1960 	bool quotemode = FALSE;
1961 	bool bslashmode = FALSE;
1962 	char spacesub = map->map_coldelim;
1963 
1964 	for (p = q = name; (c = *p++) != '\0'; )
1965 	{
1966 		if (bslashmode)
1967 		{
1968 			bslashmode = FALSE;
1969 			*q++ = c;
1970 			continue;
1971 		}
1972 
1973 		if (c == ' ' && spacesub != '\0')
1974 			c = spacesub;
1975 
1976 		switch (c)
1977 		{
1978 		  case '\\':
1979 			bslashmode = TRUE;
1980 			break;
1981 
1982 		  case '(':
1983 			cmntcnt++;
1984 			break;
1985 
1986 		  case ')':
1987 			if (cmntcnt-- <= 0)
1988 				return NULL;
1989 			break;
1990 
1991 		  case ' ':
1992 			spacecnt++;
1993 			break;
1994 		}
1995 
1996 		if (cmntcnt > 0)
1997 		{
1998 			*q++ = c;
1999 			continue;
2000 		}
2001 
2002 		switch (c)
2003 		{
2004 		  case '"':
2005 			quotemode = !quotemode;
2006 			quotecnt++;
2007 			continue;
2008 
2009 		  case '<':
2010 			anglecnt++;
2011 			break;
2012 
2013 		  case '>':
2014 			if (anglecnt-- <= 0)
2015 				return NULL;
2016 			break;
2017 		}
2018 		*q++ = c;
2019 	}
2020 
2021 	if (anglecnt != 0 || cmntcnt != 0 || bslashmode ||
2022 	    quotemode || quotecnt <= 0 || spacecnt != 0)
2023 		return NULL;
2024 	*q++ = '\0';
2025 	return name;
2026 }
2027