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