1 # include "sendmail.h"
2 
3 SCCSID(@(#)parseaddr.c	3.53		09/06/82);
4 
5 /*
6 **  PARSE -- Parse an address
7 **
8 **	Parses an address and breaks it up into three parts: a
9 **	net to transmit the message on, the host to transmit it
10 **	to, and a user on that host.  These are loaded into an
11 **	ADDRESS header with the values squirreled away if necessary.
12 **	The "user" part may not be a real user; the process may
13 **	just reoccur on that machine.  For example, on a machine
14 **	with an arpanet connection, the address
15 **		csvax.bill@berkeley
16 **	will break up to a "user" of 'csvax.bill' and a host
17 **	of 'berkeley' -- to be transmitted over the arpanet.
18 **
19 **	Parameters:
20 **		addr -- the address to parse.
21 **		a -- a pointer to the address descriptor buffer.
22 **			If NULL, a header will be created.
23 **		copyf -- determines what shall be copied:
24 **			-1 -- don't copy anything.  The printname
25 **				(q_paddr) is just addr, and the
26 **				user & host are allocated internally
27 **				to parse.
28 **			0 -- copy out the parsed user & host, but
29 **				don't copy the printname.
30 **			+1 -- copy everything.
31 **
32 **	Returns:
33 **		A pointer to the address descriptor header (`a' if
34 **			`a' is non-NULL).
35 **		NULL on error.
36 **
37 **	Side Effects:
38 **		none
39 */
40 
41 # define DELIMCHARS	"$()<>,;\\\"\r\n"	/* word delimiters */
42 
43 ADDRESS *
44 parse(addr, a, copyf)
45 	char *addr;
46 	register ADDRESS *a;
47 	int copyf;
48 {
49 	register char **pvp;
50 	register struct mailer *m;
51 	extern char **prescan();
52 	extern ADDRESS *buildaddr();
53 	static char nbuf[MAXNAME];
54 
55 	/*
56 	**  Initialize and prescan address.
57 	*/
58 
59 	CurEnv->e_to = addr;
60 # ifdef DEBUG
61 	if (tTd(20, 1))
62 		printf("\n--parse(%s)\n", addr);
63 # endif DEBUG
64 
65 	pvp = prescan(addr, ',');
66 	if (pvp == NULL)
67 		return (NULL);
68 
69 	/*
70 	**  Apply rewriting rules.
71 	**	Ruleset 0 does basic parsing.  It must resolve.
72 	*/
73 
74 	rewrite(pvp, 0);
75 
76 	/*
77 	**  See if we resolved to a real mailer.
78 	*/
79 
80 	if (pvp[0][0] != CANONNET)
81 	{
82 		setstat(EX_USAGE);
83 		usrerr("cannot resolve name");
84 		return (NULL);
85 	}
86 
87 	/*
88 	**  Build canonical address from pvp.
89 	*/
90 
91 	a = buildaddr(pvp, a);
92 	if (a == NULL)
93 		return (NULL);
94 	m = a->q_mailer;
95 
96 	/*
97 	**  Make local copies of the host & user and then
98 	**  transport them out.
99 	*/
100 
101 	if (copyf > 0)
102 	{
103 		extern char *DelimChar;
104 		char savec = *DelimChar;
105 
106 		*DelimChar = '\0';
107 		a->q_paddr = newstr(addr);
108 		*DelimChar = savec;
109 	}
110 	else
111 		a->q_paddr = addr;
112 	if (copyf >= 0)
113 	{
114 		if (a->q_host != NULL)
115 			a->q_host = newstr(a->q_host);
116 		else
117 			a->q_host = "";
118 		if (a->q_user != a->q_paddr)
119 			a->q_user = newstr(a->q_user);
120 	}
121 
122 	/*
123 	**  Do UPPER->lower case mapping unless inhibited.
124 	*/
125 
126 	if (!bitset(M_HST_UPPER, m->m_flags))
127 		makelower(a->q_host);
128 	if (!bitset(M_USR_UPPER, m->m_flags))
129 		makelower(a->q_user);
130 
131 	/*
132 	**  Compute return value.
133 	*/
134 
135 # ifdef DEBUG
136 	if (tTd(20, 1))
137 	{
138 		printf("parse-->");
139 		printaddr(a, FALSE);
140 	}
141 # endif DEBUG
142 
143 	return (a);
144 }
145 /*
146 **  PRESCAN -- Prescan name and make it canonical
147 **
148 **	Scans a name and turns it into canonical form.  This involves
149 **	deleting blanks, comments (in parentheses), and turning the
150 **	word "at" into an at-sign ("@").  The name is copied as this
151 **	is done; it is legal to copy a name onto itself, since this
152 **	process can only make things smaller.
153 **
154 **	This routine knows about quoted strings and angle brackets.
155 **
156 **	There are certain subtleties to this routine.  The one that
157 **	comes to mind now is that backslashes on the ends of names
158 **	are silently stripped off; this is intentional.  The problem
159 **	is that some versions of sndmsg (like at LBL) set the kill
160 **	character to something other than @ when reading addresses;
161 **	so people type "csvax.eric\@berkeley" -- which screws up the
162 **	berknet mailer.
163 **
164 **	Parameters:
165 **		addr -- the name to chomp.
166 **		delim -- the delimiter for the address, normally
167 **			'\0' or ','; \0 is accepted in any case.
168 **
169 **	Returns:
170 **		A pointer to a vector of tokens.
171 **		NULL on error.
172 **
173 **	Side Effects:
174 **		none.
175 */
176 
177 /* states and character types */
178 # define OPR		0	/* operator */
179 # define ATM		1	/* atom */
180 # define QST		2	/* in quoted string */
181 # define SPC		3	/* chewing up spaces */
182 # define ONE		4	/* pick up one character */
183 
184 # define NSTATES	5	/* number of states */
185 # define TYPE		017	/* mask to select state type */
186 
187 /* meta bits for table */
188 # define M		020	/* meta character; don't pass through */
189 # define B		040	/* cause a break */
190 # define MB		M|B	/* meta-break */
191 
192 static short StateTab[NSTATES][NSTATES] =
193 {
194    /*	oldst	newst>	OPR	ATM	QST	SPC	ONE	*/
195 	/*OPR*/		OPR|B,	ATM|B,	QST|MB,	SPC|MB,	ONE|B,
196 	/*ATM*/		OPR|B,	ATM,	QST|MB,	SPC|MB,	ONE|B,
197 	/*QST*/		QST,	QST,	QST|MB,	QST,	QST,
198 	/*SPC*/		OPR,	ATM,	QST,	SPC|M,	ONE,
199 	/*ONE*/		OPR,	OPR,	OPR,	OPR,	OPR,
200 };
201 
202 # define NOCHAR		-1	/* signal nothing in lookahead token */
203 
204 char	*DelimChar;		/* set to point to the delimiter */
205 
206 char **
207 prescan(addr, delim)
208 	char *addr;
209 	char delim;
210 {
211 	register char *p;
212 	register char *q;
213 	register char c;
214 	char **avp;
215 	bool bslashmode;
216 	int cmntcnt;
217 	char *tok;
218 	int state;
219 	int newstate;
220 	static char buf[MAXNAME+MAXATOM];
221 	static char *av[MAXATOM+1];
222 
223 	q = buf;
224 	bslashmode = FALSE;
225 	cmntcnt = 0;
226 	avp = av;
227 	state = OPR;
228 	c = NOCHAR;
229 	p = addr;
230 # ifdef DEBUG
231 	if (tTd(22, 45))
232 	{
233 		printf("prescan: ");
234 		xputs(p);
235 		putchar('\n');
236 	}
237 # endif DEBUG
238 
239 	do
240 	{
241 		/* read a token */
242 		tok = q;
243 		for (;;)
244 		{
245 			/* store away any old lookahead character */
246 			if (c != NOCHAR)
247 			{
248 				/* squirrel it away */
249 				if (q >= &buf[sizeof buf - 5])
250 				{
251 					usrerr("Address too long");
252 					DelimChar = p;
253 					return (NULL);
254 				}
255 				*q++ = c;
256 			}
257 
258 			/* read a new input character */
259 			c = *p++;
260 			if (c == '\0')
261 				break;
262 # ifdef DEBUG
263 			if (tTd(22, 101))
264 				printf("c=%c, s=%d; ", c, state);
265 # endif DEBUG
266 
267 			/* chew up special characters */
268 			c &= ~0200;
269 			*q = '\0';
270 			if (bslashmode)
271 			{
272 				c |= 0200;
273 				bslashmode = FALSE;
274 			}
275 			else if (c == '\\')
276 			{
277 				bslashmode = TRUE;
278 				c = NOCHAR;
279 			}
280 			else if (c == '(')
281 			{
282 				cmntcnt++;
283 				c = NOCHAR;
284 			}
285 			else if (c == ')')
286 			{
287 				if (cmntcnt <= 0)
288 				{
289 					usrerr("Unbalanced ')'");
290 					DelimChar = p;
291 					return (NULL);
292 				}
293 				else
294 					cmntcnt--;
295 			}
296 			else if (cmntcnt > 0)
297 				c = NOCHAR;
298 
299 			if (c == NOCHAR)
300 				continue;
301 
302 			/* see if this is end of input */
303 			if (c == delim)
304 				break;
305 
306 			newstate = StateTab[state][toktype(c)];
307 # ifdef DEBUG
308 			if (tTd(22, 101))
309 				printf("ns=%02o\n", newstate);
310 # endif DEBUG
311 			state = newstate & TYPE;
312 			if (bitset(M, newstate))
313 				c = NOCHAR;
314 			if (bitset(B, newstate))
315 				break;
316 		}
317 
318 		/* new token */
319 		if (tok != q)
320 		{
321 			*q++ = '\0';
322 # ifdef DEBUG
323 			if (tTd(22, 36))
324 			{
325 				printf("tok=");
326 				xputs(tok);
327 				putchar('\n');
328 			}
329 # endif DEBUG
330 			if (avp >= &av[MAXATOM])
331 			{
332 				syserr("prescan: too many tokens");
333 				DelimChar = p;
334 				return (NULL);
335 			}
336 			*avp++ = tok;
337 		}
338 	} while (c != '\0' && c != delim);
339 	*avp = NULL;
340 	DelimChar = --p;
341 	if (cmntcnt > 0)
342 		usrerr("Unbalanced '('");
343 	else if (state == QST)
344 		usrerr("Unbalanced '\"'");
345 	else if (av[0] != NULL)
346 		return (av);
347 	return (NULL);
348 }
349 /*
350 **  TOKTYPE -- return token type
351 **
352 **	Parameters:
353 **		c -- the character in question.
354 **
355 **	Returns:
356 **		Its type.
357 **
358 **	Side Effects:
359 **		none.
360 */
361 
362 toktype(c)
363 	register char c;
364 {
365 	static char buf[50];
366 	static bool firstime = TRUE;
367 
368 	if (firstime)
369 	{
370 		firstime = FALSE;
371 		expand("$o", buf, &buf[sizeof buf - 1], CurEnv);
372 		(void) strcat(buf, DELIMCHARS);
373 	}
374 	if (c == MATCHCLASS || c == MATCHREPL)
375 		return (ONE);
376 	if (c == '"')
377 		return (QST);
378 	if (!isascii(c))
379 		return (ATM);
380 	if (isspace(c) || c == ')')
381 		return (SPC);
382 	if (iscntrl(c) || index(buf, c) != NULL)
383 		return (OPR);
384 	return (ATM);
385 }
386 /*
387 **  REWRITE -- apply rewrite rules to token vector.
388 **
389 **	This routine is an ordered production system.  Each rewrite
390 **	rule has a LHS (called the pattern) and a RHS (called the
391 **	rewrite); 'rwr' points the the current rewrite rule.
392 **
393 **	For each rewrite rule, 'avp' points the address vector we
394 **	are trying to match against, and 'pvp' points to the pattern.
395 **	If pvp points to a special match value (MATCHZANY, MATCHANY,
396 **	MATCHONE, MATCHCLASS) then the address in avp matched is
397 **	saved away in the match vector (pointed to by 'mvp').
398 **
399 **	When a match between avp & pvp does not match, we try to
400 **	back out.  If we back up over a MATCHONE or a MATCHCLASS
401 **	we must also back out the match in mvp.  If we reach a
402 **	MATCHANY or MATCHZANY we just extend the match and start
403 **	over again.
404 **
405 **	When we finally match, we rewrite the address vector
406 **	and try over again.
407 **
408 **	Parameters:
409 **		pvp -- pointer to token vector.
410 **
411 **	Returns:
412 **		none.
413 **
414 **	Side Effects:
415 **		pvp is modified.
416 */
417 
418 struct match
419 {
420 	char	**first;	/* first token matched */
421 	char	**last;		/* last token matched */
422 };
423 
424 # define MAXMATCH	9	/* max params per rewrite */
425 
426 
427 rewrite(pvp, ruleset)
428 	char **pvp;
429 	int ruleset;
430 {
431 	register char *ap;		/* address pointer */
432 	register char *rp;		/* rewrite pointer */
433 	register char **avp;		/* address vector pointer */
434 	register char **rvp;		/* rewrite vector pointer */
435 	register struct match *mlp;	/* cur ptr into mlist */
436 	register struct rewrite *rwr;	/* pointer to current rewrite rule */
437 	struct match mlist[MAXMATCH];	/* stores match on LHS */
438 	char *npvp[MAXATOM+1];		/* temporary space for rebuild */
439 	extern bool sameword();
440 
441 # ifdef DEBUG
442 	if (tTd(21, 2))
443 	{
444 		printf("rewrite: ruleset %d, original pvp:", ruleset);
445 		printav(pvp);
446 	}
447 # endif DEBUG
448 
449 	/*
450 	**  Run through the list of rewrite rules, applying
451 	**	any that match.
452 	*/
453 
454 	for (rwr = RewriteRules[ruleset]; rwr != NULL; )
455 	{
456 # ifdef DEBUG
457 		if (tTd(21, 12))
458 		{
459 			printf("-----trying rule:");
460 			printav(rwr->r_lhs);
461 		}
462 # endif DEBUG
463 
464 		/* try to match on this rule */
465 		mlp = mlist;
466 		rvp = rwr->r_lhs;
467 		avp = pvp;
468 		while ((ap = *avp) != NULL || *rvp != NULL)
469 		{
470 			rp = *rvp;
471 # ifdef DEBUG
472 			if (tTd(21, 35))
473 			{
474 				printf("ap=");
475 				xputs(ap);
476 				printf(", rp=");
477 				xputs(rp);
478 				printf("\n");
479 			}
480 # endif DEBUG
481 			if (rp == NULL)
482 			{
483 				/* end-of-pattern before end-of-address */
484 				goto backup;
485 			}
486 			if (ap == NULL && *rp != MATCHZANY)
487 			{
488 				/* end-of-input */
489 				break;
490 			}
491 
492 			switch (*rp)
493 			{
494 				register STAB *s;
495 				register int class;
496 
497 			  case MATCHCLASS:
498 				/* match any token in a class */
499 				class = rp[1];
500 				if (!isalpha(class))
501 					goto backup;
502 				if (isupper(class))
503 					class -= 'A';
504 				else
505 					class -= 'a';
506 				s = stab(ap, ST_CLASS, ST_FIND);
507 				if (s == NULL || (s->s_class & (1L << class)) == 0)
508 					goto backup;
509 
510 				/* explicit fall-through */
511 
512 			  case MATCHONE:
513 			  case MATCHANY:
514 				/* match exactly one token */
515 				mlp->first = avp;
516 				mlp->last = avp++;
517 				mlp++;
518 				break;
519 
520 			  case MATCHZANY:
521 				/* match zero or more tokens */
522 				mlp->first = avp;
523 				mlp->last = avp - 1;
524 				mlp++;
525 				break;
526 
527 			  default:
528 				/* must have exact match */
529 				if (!sameword(rp, ap))
530 					goto backup;
531 				avp++;
532 				break;
533 			}
534 
535 			/* successful match on this token */
536 			rvp++;
537 			continue;
538 
539 		  backup:
540 			/* match failed -- back up */
541 			while (--rvp >= rwr->r_lhs)
542 			{
543 				rp = *rvp;
544 				if (*rp == MATCHANY || *rp == MATCHZANY)
545 				{
546 					/* extend binding and continue */
547 					avp = ++mlp[-1].last;
548 					avp++;
549 					rvp++;
550 					break;
551 				}
552 				avp--;
553 				if (*rp == MATCHONE || *rp == MATCHCLASS)
554 				{
555 					/* back out binding */
556 					mlp--;
557 				}
558 			}
559 
560 			if (rvp < rwr->r_lhs)
561 			{
562 				/* total failure to match */
563 				break;
564 			}
565 		}
566 
567 		/*
568 		**  See if we successfully matched
569 		*/
570 
571 		if (rvp >= rwr->r_lhs && *rvp == NULL)
572 		{
573 			rvp = rwr->r_rhs;
574 # ifdef DEBUG
575 			if (tTd(21, 12))
576 			{
577 				printf("-----rule matches:");
578 				printav(rvp);
579 			}
580 # endif DEBUG
581 
582 			/* see if this is a "subroutine" call */
583 			rp = *rvp;
584 			if (*rp == CALLSUBR)
585 			{
586 				rp = *++rvp;
587 # ifdef DEBUG
588 				if (tTd(21, 3))
589 					printf("-----callsubr %s\n", rp);
590 # endif DEBUG
591 				rewrite(pvp, atoi(rp));
592 				rwr = rwr->r_next;
593 				continue;
594 			}
595 			else if (*rp == CANONUSER)
596 			{
597 				rvp++;
598 				rwr = rwr->r_next;
599 			}
600 			else if (*rp == CANONHOST)
601 			{
602 				rvp++;
603 				rwr = NULL;
604 			}
605 			else if (*rp == CANONNET)
606 				rwr = NULL;
607 
608 			/* substitute */
609 			for (avp = npvp; *rvp != NULL; rvp++)
610 			{
611 				rp = *rvp;
612 				if (*rp == MATCHREPL)
613 				{
614 					register struct match *m;
615 					register char **pp;
616 
617 					m = &mlist[rp[1] - '1'];
618 # ifdef DEBUG
619 					if (tTd(21, 15))
620 					{
621 						printf("$%c:", rp[1]);
622 						pp = m->first;
623 						while (pp <= m->last)
624 						{
625 							printf(" %x=\"", *pp);
626 							(void) fflush(stdout);
627 							printf("%s\"", *pp++);
628 						}
629 						printf("\n");
630 					}
631 # endif DEBUG
632 					pp = m->first;
633 					while (pp <= m->last)
634 					{
635 						if (avp >= &npvp[MAXATOM])
636 						{
637 							syserr("rewrite: expansion too long");
638 							return;
639 						}
640 						*avp++ = *pp++;
641 					}
642 				}
643 				else
644 				{
645 					if (avp >= &npvp[MAXATOM])
646 					{
647 						syserr("rewrite: expansion too long");
648 						return;
649 					}
650 					*avp++ = rp;
651 				}
652 			}
653 			*avp++ = NULL;
654 			bmove((char *) npvp, (char *) pvp, (avp - npvp) * sizeof *avp);
655 # ifdef DEBUG
656 			if (tTd(21, 4))
657 			{
658 				printf("rewritten as:");
659 				printav(pvp);
660 			}
661 # endif DEBUG
662 		}
663 		else
664 		{
665 # ifdef DEBUG
666 			if (tTd(21, 10))
667 				printf("----- rule fails\n");
668 # endif DEBUG
669 			rwr = rwr->r_next;
670 		}
671 	}
672 
673 # ifdef DEBUG
674 	if (tTd(21, 2))
675 	{
676 		printf("rewrite: ruleset %d returns:", ruleset);
677 		printav(pvp);
678 	}
679 # endif DEBUG
680 }
681 /*
682 **  BUILDADDR -- build address from token vector.
683 **
684 **	Parameters:
685 **		tv -- token vector.
686 **		a -- pointer to address descriptor to fill.
687 **			If NULL, one will be allocated.
688 **
689 **	Returns:
690 **		NULL if there was an error.
691 **		'a' otherwise.
692 **
693 **	Side Effects:
694 **		fills in 'a'
695 */
696 
697 ADDRESS *
698 buildaddr(tv, a)
699 	register char **tv;
700 	register ADDRESS *a;
701 {
702 	static char buf[MAXNAME];
703 	struct mailer **mp;
704 	register struct mailer *m;
705 	extern bool sameword();
706 
707 	if (a == NULL)
708 		a = (ADDRESS *) xalloc(sizeof *a);
709 	clear((char *) a, sizeof *a);
710 
711 	/* figure out what net/mailer to use */
712 	if (**tv != CANONNET)
713 	{
714 		syserr("buildaddr: no net");
715 		return (NULL);
716 	}
717 	tv++;
718 	if (sameword(*tv, "error"))
719 	{
720 		if (**++tv != CANONUSER)
721 			syserr("buildaddr: error: no user");
722 		buf[0] = '\0';
723 		while (*++tv != NULL)
724 		{
725 			if (buf[0] != '\0')
726 				(void) strcat(buf, " ");
727 			(void) strcat(buf, *tv);
728 		}
729 		usrerr(buf);
730 		return (NULL);
731 	}
732 	for (mp = Mailer; (m = *mp++) != NULL; )
733 	{
734 		if (sameword(m->m_name, *tv))
735 			break;
736 	}
737 	if (m == NULL)
738 	{
739 		syserr("buildaddr: unknown net %s", *tv);
740 		return (NULL);
741 	}
742 	a->q_mailer = m;
743 
744 	/* figure out what host (if any) */
745 	tv++;
746 	if (!bitset(M_LOCAL, m->m_flags))
747 	{
748 		if (**tv++ != CANONHOST)
749 		{
750 			syserr("buildaddr: no host");
751 			return (NULL);
752 		}
753 		buf[0] = '\0';
754 		while (*tv != NULL && **tv != CANONUSER)
755 			(void) strcat(buf, *tv++);
756 		a->q_host = newstr(buf);
757 	}
758 	else
759 		a->q_host = NULL;
760 
761 	/* figure out the user */
762 	if (**tv != CANONUSER)
763 	{
764 		syserr("buildaddr: no user");
765 		return (NULL);
766 	}
767 	cataddr(++tv, buf, sizeof buf);
768 	a->q_user = buf;
769 
770 	return (a);
771 }
772 /*
773 **  CATADDR -- concatenate pieces of addresses (putting in <LWSP> subs)
774 **
775 **	Parameters:
776 **		pvp -- parameter vector to rebuild.
777 **		buf -- buffer to build the string into.
778 **		sz -- size of buf.
779 **
780 **	Returns:
781 **		none.
782 **
783 **	Side Effects:
784 **		Destroys buf.
785 */
786 
787 cataddr(pvp, buf, sz)
788 	char **pvp;
789 	char *buf;
790 	register int sz;
791 {
792 	bool oatomtok = FALSE;
793 	bool natomtok = FALSE;
794 	register int i;
795 	register char *p;
796 
797 	p = buf;
798 	sz--;
799 	while (*pvp != NULL && (i = strlen(*pvp)) < sz)
800 	{
801 		natomtok = (toktype(**pvp) == ATM);
802 		if (oatomtok && natomtok)
803 			*p++ = SPACESUB;
804 		(void) strcpy(p, *pvp);
805 		oatomtok = natomtok;
806 		p += i;
807 		sz -= i;
808 		pvp++;
809 	}
810 	*p = '\0';
811 }
812 /*
813 **  SAMEADDR -- Determine if two addresses are the same
814 **
815 **	This is not just a straight comparison -- if the mailer doesn't
816 **	care about the host we just ignore it, etc.
817 **
818 **	Parameters:
819 **		a, b -- pointers to the internal forms to compare.
820 **		wildflg -- if TRUE, 'a' may have no user specified,
821 **			in which case it is to match anything.
822 **
823 **	Returns:
824 **		TRUE -- they represent the same mailbox.
825 **		FALSE -- they don't.
826 **
827 **	Side Effects:
828 **		none.
829 */
830 
831 bool
832 sameaddr(a, b, wildflg)
833 	register ADDRESS *a;
834 	register ADDRESS *b;
835 	bool wildflg;
836 {
837 	/* if they don't have the same mailer, forget it */
838 	if (a->q_mailer != b->q_mailer)
839 		return (FALSE);
840 
841 	/* if the user isn't the same, we can drop out */
842 	if ((!wildflg || a->q_user[0] != '\0') && strcmp(a->q_user, b->q_user) != 0)
843 		return (FALSE);
844 
845 	/* if the mailer ignores hosts, we have succeeded! */
846 	if (bitset(M_LOCAL, a->q_mailer->m_flags))
847 		return (TRUE);
848 
849 	/* otherwise compare hosts (but be careful for NULL ptrs) */
850 	if (a->q_host == NULL || b->q_host == NULL)
851 		return (FALSE);
852 	if (strcmp(a->q_host, b->q_host) != 0)
853 		return (FALSE);
854 
855 	return (TRUE);
856 }
857 /*
858 **  PRINTADDR -- print address (for debugging)
859 **
860 **	Parameters:
861 **		a -- the address to print
862 **		follow -- follow the q_next chain.
863 **
864 **	Returns:
865 **		none.
866 **
867 **	Side Effects:
868 **		none.
869 */
870 
871 # ifdef DEBUG
872 
873 printaddr(a, follow)
874 	register ADDRESS *a;
875 	bool follow;
876 {
877 	bool first = TRUE;
878 
879 	while (a != NULL)
880 	{
881 		first = FALSE;
882 		printf("%x=", a);
883 		(void) fflush(stdout);
884 		printf("%s: mailer %d (%s), host `%s', user `%s'\n", a->q_paddr,
885 		       a->q_mailer->m_mno, a->q_mailer->m_name, a->q_host, a->q_user);
886 		printf("\tnext=%x, flags=%o, rmailer %d, alias %x\n", a->q_next,
887 		       a->q_flags, a->q_rmailer, a->q_alias);
888 		printf("\thome=\"%s\", fullname=\"%s\"\n", a->q_home, a->q_fullname);
889 
890 		if (!follow)
891 			return;
892 		a = a->q_next;
893 	}
894 	if (first)
895 		printf("[NULL]\n");
896 }
897 
898 # endif DEBUG
899 /*
900 **  REMOTENAME -- return the name relative to the current mailer
901 **
902 **	Parameters:
903 **		name -- the name to translate.
904 **		m -- the mailer that we want to do rewriting relative
905 **			to.
906 **		senderaddress -- if set, uses the sender rewriting rules
907 **			rather than the recipient rewriting rules.
908 **
909 **	Returns:
910 **		the text string representing this address relative to
911 **			the receiving mailer.
912 **
913 **	Side Effects:
914 **		none.
915 **
916 **	Warnings:
917 **		The text string returned is tucked away locally;
918 **			copy it if you intend to save it.
919 */
920 
921 char *
922 remotename(name, m, senderaddress)
923 	char *name;
924 	struct mailer *m;
925 	bool senderaddress;
926 {
927 	register char **pvp;
928 	char *fancy;
929 	extern char *macvalue();
930 	char *oldg = macvalue('g');
931 	static char buf[MAXNAME];
932 	char lbuf[MAXNAME];
933 	extern char **prescan();
934 	extern char *crackaddr();
935 
936 # ifdef DEBUG
937 	if (tTd(12, 1))
938 		printf("remotename(%s)\n", name);
939 # endif DEBUG
940 
941 	/*
942 	**  First put this address into canonical form.
943 	**	First turn it into a macro.
944 	**	Then run it through ruleset 1 or 2, depending on whether
945 	**		it is a sender or a recipient address.
946 	**	If the mailer defines a rewriting set, run it through
947 	**		there next.
948 	*/
949 
950 	/* save away the extraneous pretty stuff */
951 	fancy = crackaddr(name);
952 
953 	/* now run through ruleset four */
954 	pvp = prescan(name, '\0');
955 	if (pvp == NULL)
956 		return (name);
957 	if (senderaddress)
958 	{
959 		rewrite(pvp, 1);
960 		if (m->m_s_rwset > 0)
961 			rewrite(pvp, m->m_s_rwset);
962 	}
963 	else
964 	{
965 		rewrite(pvp, 2);
966 		if (m->m_r_rwset > 0)
967 			rewrite(pvp, m->m_r_rwset);
968 	}
969 
970 	/* now add any comment info we had before back */
971 	cataddr(pvp, lbuf, sizeof lbuf);
972 	define('g', lbuf);
973 	expand(fancy, buf, &buf[sizeof buf - 1], CurEnv);
974 	define('g', oldg);
975 
976 # ifdef DEBUG
977 	if (tTd(12, 1))
978 		printf("remotename => `%s'\n", buf);
979 # endif DEBUG
980 	return (buf);
981 }
982 /*
983 **  CANONNAME -- make name canonical
984 **
985 **	This is used for SMTP and misc. printing.  Given a print
986 **	address, it strips out comments, etc., and puts on exactly
987 **	one set of brackets.
988 **
989 **	Parameters:
990 **		name -- the name to make canonical.
991 **
992 **	Returns:
993 **		pointer to canonical name.
994 **
995 **	Side Effects:
996 **		none.
997 **
998 **	Warning:
999 **		result is saved in static buf; future calls will trash it.
1000 */
1001 
1002 char *
1003 canonname(name)
1004 	char *name;
1005 {
1006 	static char nbuf[MAXNAME];
1007 	register char **pvp;
1008 
1009 	pvp = prescan(name, '\0');
1010 	rewrite(pvp, 3);
1011 	cataddr(pvp, nbuf, sizeof nbuf);
1012 	return (nbuf);
1013 }
1014