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