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.60 (Berkeley) 03/25/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, 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 + 1];
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 	"QHASNOTIFY",		QHASNOTIFY,
1605 	"QRELAYED",		QRELAYED,
1606 	NULL
1607 };
1608 
1609 void
1610 printaddr(a, follow)
1611 	register ADDRESS *a;
1612 	bool follow;
1613 {
1614 	register MAILER *m;
1615 	MAILER pseudomailer;
1616 	register struct qflags *qfp;
1617 	bool firstone;
1618 
1619 	if (a == NULL)
1620 	{
1621 		printf("[NULL]\n");
1622 		return;
1623 	}
1624 
1625 	while (a != NULL)
1626 	{
1627 		printf("%x=", a);
1628 		(void) fflush(stdout);
1629 
1630 		/* find the mailer -- carefully */
1631 		m = a->q_mailer;
1632 		if (m == NULL)
1633 		{
1634 			m = &pseudomailer;
1635 			m->m_mno = -1;
1636 			m->m_name = "NULL";
1637 		}
1638 
1639 		printf("%s:\n\tmailer %d (%s), host `%s', user `%s', ruser `%s'\n",
1640 		       a->q_paddr, m->m_mno, m->m_name,
1641 		       a->q_host == NULL ? "<null>" : a->q_host, a->q_user,
1642 		       a->q_ruser == NULL ? "<null>" : a->q_ruser);
1643 		printf("\tnext=%x, alias %x, uid %d, gid %d\n",
1644 		       a->q_next, a->q_alias, a->q_uid, a->q_gid);
1645 		printf("\tflags=%lx<", a->q_flags);
1646 		firstone = TRUE;
1647 		for (qfp = AddressFlags; qfp->qf_name != NULL; qfp++)
1648 		{
1649 			if (!bitset(qfp->qf_bit, a->q_flags))
1650 				continue;
1651 			if (!firstone)
1652 				printf(",");
1653 			firstone = FALSE;
1654 			printf("%s", qfp->qf_name);
1655 		}
1656 		printf(">\n");
1657 		printf("\towner=%s, home=\"%s\", fullname=\"%s\"\n",
1658 		       a->q_owner == NULL ? "(none)" : a->q_owner,
1659 		       a->q_home == NULL ? "(none)" : a->q_home,
1660 		       a->q_fullname == NULL ? "(none)" : a->q_fullname);
1661 		printf("\torcpt=\"%s\", statmta=%s, rstatus=%s\n",
1662 		       a->q_orcpt == NULL ? "(none)" : a->q_orcpt,
1663 		       a->q_statmta == NULL ? "(none)" : a->q_statmta,
1664 		       a->q_rstatus == NULL ? "(none)" : a->q_rstatus);
1665 
1666 		if (!follow)
1667 			return;
1668 		a = a->q_next;
1669 	}
1670 }
1671 /*
1672 **  EMPTYADDR -- return TRUE if this address is empty (``<>'')
1673 **
1674 **	Parameters:
1675 **		a -- pointer to the address
1676 **
1677 **	Returns:
1678 **		TRUE -- if this address is "empty" (i.e., no one should
1679 **			ever generate replies to it.
1680 **		FALSE -- if it is a "regular" (read: replyable) address.
1681 */
1682 
1683 bool
1684 emptyaddr(a)
1685 	register ADDRESS *a;
1686 {
1687 	return strcmp(a->q_paddr, "<>") == 0 || strcmp(a->q_user, "<>") == 0;
1688 }
1689 /*
1690 **  REMOTENAME -- return the name relative to the current mailer
1691 **
1692 **	Parameters:
1693 **		name -- the name to translate.
1694 **		m -- the mailer that we want to do rewriting relative
1695 **			to.
1696 **		flags -- fine tune operations.
1697 **		pstat -- pointer to status word.
1698 **		e -- the current envelope.
1699 **
1700 **	Returns:
1701 **		the text string representing this address relative to
1702 **			the receiving mailer.
1703 **
1704 **	Side Effects:
1705 **		none.
1706 **
1707 **	Warnings:
1708 **		The text string returned is tucked away locally;
1709 **			copy it if you intend to save it.
1710 */
1711 
1712 char *
1713 remotename(name, m, flags, pstat, e)
1714 	char *name;
1715 	struct mailer *m;
1716 	int flags;
1717 	int *pstat;
1718 	register ENVELOPE *e;
1719 {
1720 	register char **pvp;
1721 	char *fancy;
1722 	char *oldg = macvalue('g', e);
1723 	int rwset;
1724 	static char buf[MAXNAME + 1];
1725 	char lbuf[MAXNAME + 1];
1726 	char pvpbuf[PSBUFSIZE];
1727 	extern char *crackaddr();
1728 
1729 	if (tTd(12, 1))
1730 		printf("remotename(%s)\n", name);
1731 
1732 	/* don't do anything if we are tagging it as special */
1733 	if (bitset(RF_SENDERADDR, flags))
1734 		rwset = bitset(RF_HEADERADDR, flags) ? m->m_sh_rwset
1735 						     : m->m_se_rwset;
1736 	else
1737 		rwset = bitset(RF_HEADERADDR, flags) ? m->m_rh_rwset
1738 						     : m->m_re_rwset;
1739 	if (rwset < 0)
1740 		return (name);
1741 
1742 	/*
1743 	**  Do a heuristic crack of this name to extract any comment info.
1744 	**	This will leave the name as a comment and a $g macro.
1745 	*/
1746 
1747 	if (bitset(RF_CANONICAL, flags) || bitnset(M_NOCOMMENT, m->m_flags))
1748 		fancy = "\201g";
1749 	else
1750 		fancy = crackaddr(name);
1751 
1752 	/*
1753 	**  Turn the name into canonical form.
1754 	**	Normally this will be RFC 822 style, i.e., "user@domain".
1755 	**	If this only resolves to "user", and the "C" flag is
1756 	**	specified in the sending mailer, then the sender's
1757 	**	domain will be appended.
1758 	*/
1759 
1760 	pvp = prescan(name, '\0', pvpbuf, sizeof pvpbuf, NULL);
1761 	if (pvp == NULL)
1762 		return (name);
1763 	if (rewrite(pvp, 3, 0, e) == EX_TEMPFAIL)
1764 		*pstat = EX_TEMPFAIL;
1765 	if (bitset(RF_ADDDOMAIN, flags) && e->e_fromdomain != NULL)
1766 	{
1767 		/* append from domain to this address */
1768 		register char **pxp = pvp;
1769 
1770 		/* see if there is an "@domain" in the current name */
1771 		while (*pxp != NULL && strcmp(*pxp, "@") != 0)
1772 			pxp++;
1773 		if (*pxp == NULL)
1774 		{
1775 			/* no.... append the "@domain" from the sender */
1776 			register char **qxq = e->e_fromdomain;
1777 
1778 			while ((*pxp++ = *qxq++) != NULL)
1779 				continue;
1780 			if (rewrite(pvp, 3, 0, e) == EX_TEMPFAIL)
1781 				*pstat = EX_TEMPFAIL;
1782 		}
1783 	}
1784 
1785 	/*
1786 	**  Do more specific rewriting.
1787 	**	Rewrite using ruleset 1 or 2 depending on whether this is
1788 	**		a sender address or not.
1789 	**	Then run it through any receiving-mailer-specific rulesets.
1790 	*/
1791 
1792 	if (bitset(RF_SENDERADDR, flags))
1793 	{
1794 		if (rewrite(pvp, 1, 0, e) == EX_TEMPFAIL)
1795 			*pstat = EX_TEMPFAIL;
1796 	}
1797 	else
1798 	{
1799 		if (rewrite(pvp, 2, 0, e) == EX_TEMPFAIL)
1800 			*pstat = EX_TEMPFAIL;
1801 	}
1802 	if (rwset > 0)
1803 	{
1804 		if (rewrite(pvp, rwset, 0, e) == EX_TEMPFAIL)
1805 			*pstat = EX_TEMPFAIL;
1806 	}
1807 
1808 	/*
1809 	**  Do any final sanitation the address may require.
1810 	**	This will normally be used to turn internal forms
1811 	**	(e.g., user@host.LOCAL) into external form.  This
1812 	**	may be used as a default to the above rules.
1813 	*/
1814 
1815 	if (rewrite(pvp, 4, 0, e) == EX_TEMPFAIL)
1816 		*pstat = EX_TEMPFAIL;
1817 
1818 	/*
1819 	**  Now restore the comment information we had at the beginning.
1820 	*/
1821 
1822 	cataddr(pvp, NULL, lbuf, sizeof lbuf, '\0');
1823 	define('g', lbuf, e);
1824 
1825 	/* need to make sure route-addrs have <angle brackets> */
1826 	if (bitset(RF_CANONICAL, flags) && lbuf[0] == '@')
1827 		expand("<\201g>", buf, sizeof buf, e);
1828 	else
1829 		expand(fancy, buf, sizeof buf, e);
1830 
1831 	define('g', oldg, e);
1832 
1833 	if (tTd(12, 1))
1834 		printf("remotename => `%s'\n", buf);
1835 	return (buf);
1836 }
1837 /*
1838 **  MAPLOCALUSER -- run local username through ruleset 5 for final redirection
1839 **
1840 **	Parameters:
1841 **		a -- the address to map (but just the user name part).
1842 **		sendq -- the sendq in which to install any replacement
1843 **			addresses.
1844 **		aliaslevel -- the alias nesting depth.
1845 **		e -- the envelope.
1846 **
1847 **	Returns:
1848 **		none.
1849 */
1850 
1851 maplocaluser(a, sendq, aliaslevel, e)
1852 	register ADDRESS *a;
1853 	ADDRESS **sendq;
1854 	int aliaslevel;
1855 	ENVELOPE *e;
1856 {
1857 	register char **pvp;
1858 	register ADDRESS *a1 = NULL;
1859 	auto char *delimptr;
1860 	char pvpbuf[PSBUFSIZE];
1861 
1862 	if (tTd(29, 1))
1863 	{
1864 		printf("maplocaluser: ");
1865 		printaddr(a, FALSE);
1866 	}
1867 	pvp = prescan(a->q_user, '\0', pvpbuf, sizeof pvpbuf, &delimptr);
1868 	if (pvp == NULL)
1869 		return;
1870 
1871 	(void) rewrite(pvp, 5, 0, e);
1872 	if (pvp[0] == NULL || (pvp[0][0] & 0377) != CANONNET)
1873 		return;
1874 
1875 	/* if non-null, mailer destination specified -- has it changed? */
1876 	a1 = buildaddr(pvp, NULL, 0, e);
1877 	if (a1 == NULL || sameaddr(a, a1))
1878 		return;
1879 
1880 	/* mark old address as dead; insert new address */
1881 	a->q_flags |= QDONTSEND;
1882 	if (tTd(29, 5))
1883 	{
1884 		printf("maplocaluser: QDONTSEND ");
1885 		printaddr(a, FALSE);
1886 	}
1887 	a1->q_alias = a;
1888 	allocaddr(a1, RF_COPYALL, NULL);
1889 	(void) recipient(a1, sendq, aliaslevel, e);
1890 }
1891 /*
1892 **  DEQUOTE_INIT -- initialize dequote map
1893 **
1894 **	This is a no-op.
1895 **
1896 **	Parameters:
1897 **		map -- the internal map structure.
1898 **		args -- arguments.
1899 **
1900 **	Returns:
1901 **		TRUE.
1902 */
1903 
1904 bool
1905 dequote_init(map, args)
1906 	MAP *map;
1907 	char *args;
1908 {
1909 	register char *p = args;
1910 
1911 	for (;;)
1912 	{
1913 		while (isascii(*p) && isspace(*p))
1914 			p++;
1915 		if (*p != '-')
1916 			break;
1917 		switch (*++p)
1918 		{
1919 		  case 'a':
1920 			map->map_app = ++p;
1921 			break;
1922 
1923 		  case 's':
1924 			map->map_coldelim = *++p;
1925 			break;
1926 		}
1927 		while (*p != '\0' && !(isascii(*p) && isspace(*p)))
1928 			p++;
1929 		if (*p != '\0')
1930 			*p = '\0';
1931 	}
1932 	if (map->map_app != NULL)
1933 		map->map_app = newstr(map->map_app);
1934 
1935 	return TRUE;
1936 }
1937 /*
1938 **  DEQUOTE_MAP -- unquote an address
1939 **
1940 **	Parameters:
1941 **		map -- the internal map structure (ignored).
1942 **		name -- the name to dequote.
1943 **		av -- arguments (ignored).
1944 **		statp -- pointer to status out-parameter.
1945 **
1946 **	Returns:
1947 **		NULL -- if there were no quotes, or if the resulting
1948 **			unquoted buffer would not be acceptable to prescan.
1949 **		else -- The dequoted buffer.
1950 */
1951 
1952 char *
1953 dequote_map(map, name, av, statp)
1954 	MAP *map;
1955 	char *name;
1956 	char **av;
1957 	int *statp;
1958 {
1959 	register char *p;
1960 	register char *q;
1961 	register char c;
1962 	int anglecnt = 0;
1963 	int cmntcnt = 0;
1964 	int quotecnt = 0;
1965 	int spacecnt = 0;
1966 	bool quotemode = FALSE;
1967 	bool bslashmode = FALSE;
1968 	char spacesub = map->map_coldelim;
1969 
1970 	for (p = q = name; (c = *p++) != '\0'; )
1971 	{
1972 		if (bslashmode)
1973 		{
1974 			bslashmode = FALSE;
1975 			*q++ = c;
1976 			continue;
1977 		}
1978 
1979 		if (c == ' ' && spacesub != '\0')
1980 			c = spacesub;
1981 
1982 		switch (c)
1983 		{
1984 		  case '\\':
1985 			bslashmode = TRUE;
1986 			break;
1987 
1988 		  case '(':
1989 			cmntcnt++;
1990 			break;
1991 
1992 		  case ')':
1993 			if (cmntcnt-- <= 0)
1994 				return NULL;
1995 			break;
1996 
1997 		  case ' ':
1998 			spacecnt++;
1999 			break;
2000 		}
2001 
2002 		if (cmntcnt > 0)
2003 		{
2004 			*q++ = c;
2005 			continue;
2006 		}
2007 
2008 		switch (c)
2009 		{
2010 		  case '"':
2011 			quotemode = !quotemode;
2012 			quotecnt++;
2013 			continue;
2014 
2015 		  case '<':
2016 			anglecnt++;
2017 			break;
2018 
2019 		  case '>':
2020 			if (anglecnt-- <= 0)
2021 				return NULL;
2022 			break;
2023 		}
2024 		*q++ = c;
2025 	}
2026 
2027 	if (anglecnt != 0 || cmntcnt != 0 || bslashmode ||
2028 	    quotemode || quotecnt <= 0 || spacecnt != 0)
2029 		return NULL;
2030 	*q++ = '\0';
2031 	return name;
2032 }
2033