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[] = "@(#)envelope.c	8.40 (Berkeley) 08/21/94";
11 #endif /* not lint */
12 
13 #include "sendmail.h"
14 #include <pwd.h>
15 
16 /*
17 **  NEWENVELOPE -- allocate a new envelope
18 **
19 **	Supports inheritance.
20 **
21 **	Parameters:
22 **		e -- the new envelope to fill in.
23 **		parent -- the envelope to be the parent of e.
24 **
25 **	Returns:
26 **		e.
27 **
28 **	Side Effects:
29 **		none.
30 */
31 
32 ENVELOPE *
33 newenvelope(e, parent)
34 	register ENVELOPE *e;
35 	register ENVELOPE *parent;
36 {
37 	extern putheader(), putbody();
38 	extern ENVELOPE BlankEnvelope;
39 
40 	if (e == parent && e->e_parent != NULL)
41 		parent = e->e_parent;
42 	clearenvelope(e, TRUE);
43 	if (e == CurEnv)
44 		bcopy((char *) &NullAddress, (char *) &e->e_from, sizeof e->e_from);
45 	else
46 		bcopy((char *) &CurEnv->e_from, (char *) &e->e_from, sizeof e->e_from);
47 	e->e_parent = parent;
48 	e->e_ctime = curtime();
49 	if (parent != NULL)
50 		e->e_msgpriority = parent->e_msgsize;
51 	e->e_puthdr = putheader;
52 	e->e_putbody = putbody;
53 	if (CurEnv->e_xfp != NULL)
54 		(void) fflush(CurEnv->e_xfp);
55 
56 	return (e);
57 }
58 /*
59 **  DROPENVELOPE -- deallocate an envelope.
60 **
61 **	Parameters:
62 **		e -- the envelope to deallocate.
63 **
64 **	Returns:
65 **		none.
66 **
67 **	Side Effects:
68 **		housekeeping necessary to dispose of an envelope.
69 **		Unlocks this queue file.
70 */
71 
72 void
73 dropenvelope(e)
74 	register ENVELOPE *e;
75 {
76 	bool queueit = FALSE;
77 	bool saveit = bitset(EF_FATALERRS, e->e_flags);
78 	register ADDRESS *q;
79 	char *id = e->e_id;
80 	char buf[MAXLINE];
81 
82 	if (tTd(50, 1))
83 	{
84 		printf("dropenvelope %x: id=", e);
85 		xputs(e->e_id);
86 		printf(", flags=0x%x\n", e->e_flags);
87 		if (tTd(50, 10))
88 		{
89 			printf("sendq=");
90 			printaddr(e->e_sendqueue, TRUE);
91 		}
92 	}
93 
94 	/* we must have an id to remove disk files */
95 	if (id == NULL)
96 		return;
97 
98 #ifdef LOG
99 	if (LogLevel > 4 && bitset(EF_LOGSENDER, e->e_flags))
100 		logsender(e, NULL);
101 	if (LogLevel > 84)
102 		syslog(LOG_DEBUG, "dropenvelope, id=%s, flags=0x%x, pid=%d",
103 				  id, e->e_flags, getpid());
104 #endif /* LOG */
105 	e->e_flags &= ~EF_LOGSENDER;
106 
107 	/* post statistics */
108 	poststats(StatFile);
109 
110 	/*
111 	**  Extract state information from dregs of send list.
112 	*/
113 
114 	e->e_flags &= ~EF_QUEUERUN;
115 	for (q = e->e_sendqueue; q != NULL; q = q->q_next)
116 	{
117 		if (bitset(QQUEUEUP, q->q_flags))
118 			queueit = TRUE;
119 		if (!bitset(QDONTSEND, q->q_flags) &&
120 		    bitset(QBADADDR, q->q_flags))
121 		{
122 			if (q->q_owner == NULL &&
123 			    strcmp(e->e_from.q_paddr, "<>") != 0)
124 				(void) sendtolist(e->e_from.q_paddr, NULL,
125 						  &e->e_errorqueue, e);
126 		}
127 	}
128 
129 	/*
130 	**  See if the message timed out.
131 	*/
132 
133 	if (!queueit)
134 		/* nothing to do */ ;
135 	else if (curtime() > e->e_ctime + TimeOuts.to_q_return[e->e_timeoutclass])
136 	{
137 		(void) sprintf(buf, "Cannot send message for %s",
138 			pintvl(TimeOuts.to_q_return[e->e_timeoutclass], FALSE));
139 		if (e->e_message != NULL)
140 			free(e->e_message);
141 		e->e_message = newstr(buf);
142 		message(buf);
143 		e->e_flags |= EF_CLRQUEUE;
144 		saveit = TRUE;
145 		fprintf(e->e_xfp, "Message could not be delivered for %s\n",
146 			pintvl(TimeOuts.to_q_return[e->e_timeoutclass], FALSE));
147 		fprintf(e->e_xfp, "Message will be deleted from queue\n");
148 		for (q = e->e_sendqueue; q != NULL; q = q->q_next)
149 		{
150 			if (bitset(QQUEUEUP, q->q_flags))
151 				q->q_flags |= QBADADDR;
152 		}
153 	}
154 	else if (TimeOuts.to_q_warning[e->e_timeoutclass] > 0 &&
155 	    curtime() > e->e_ctime + TimeOuts.to_q_warning[e->e_timeoutclass])
156 	{
157 		if (!bitset(EF_WARNING|EF_RESPONSE, e->e_flags) &&
158 		    e->e_class >= 0 &&
159 		    strcmp(e->e_from.q_paddr, "<>") != 0 &&
160 		    strncasecmp(e->e_from.q_paddr, "owner-", 6) != 0 &&
161 		    (strlen(e->e_from.q_paddr) <= 8 ||
162 		     strcasecmp(&e->e_from.q_paddr[strlen(e->e_from.q_paddr) - 8], "-request") != 0))
163 		{
164 			(void) sprintf(buf,
165 				"Warning: cannot send message for %s",
166 				pintvl(TimeOuts.to_q_warning[e->e_timeoutclass], FALSE));
167 			if (e->e_message != NULL)
168 				free(e->e_message);
169 			e->e_message = newstr(buf);
170 			message(buf);
171 			e->e_flags |= EF_WARNING;
172 			saveit = TRUE;
173 		}
174 		fprintf(e->e_xfp,
175 			"Warning: message still undelivered after %s\n",
176 			pintvl(TimeOuts.to_q_warning[e->e_timeoutclass], FALSE));
177 		fprintf(e->e_xfp, "Will keep trying until message is %s old\n",
178 			pintvl(TimeOuts.to_q_return[e->e_timeoutclass], FALSE));
179 		for (q = e->e_sendqueue; q != NULL; q = q->q_next)
180 		{
181 			if (bitset(QQUEUEUP, q->q_flags))
182 				q->q_flags |= QREPORT;
183 		}
184 	}
185 
186 	/*
187 	**  Send back return receipts as requested.
188 	*/
189 
190 	if (e->e_receiptto != NULL && bitset(EF_SENDRECEIPT, e->e_flags)
191 	    && !bitset(PRIV_NORECEIPTS, PrivacyFlags))
192 	{
193 		auto ADDRESS *rlist = NULL;
194 
195 		(void) sendtolist(e->e_receiptto, NULLADDR, &rlist, e);
196 		(void) returntosender("Return receipt", rlist, FALSE, e);
197 	}
198 	e->e_flags &= ~EF_SENDRECEIPT;
199 
200 	/*
201 	**  Arrange to send error messages if there are fatal errors.
202 	*/
203 
204 	if (saveit && e->e_errormode != EM_QUIET)
205 		savemail(e);
206 
207 	/*
208 	**  Arrange to send warning messages to postmaster as requested.
209 	*/
210 
211 	if (bitset(EF_PM_NOTIFY, e->e_flags) && PostMasterCopy != NULL &&
212 	    !bitset(EF_RESPONSE, e->e_flags) && e->e_class >= 0)
213 	{
214 		auto ADDRESS *rlist = NULL;
215 
216 		(void) sendtolist(PostMasterCopy, NULLADDR, &rlist, e);
217 		(void) returntosender(e->e_message, rlist, FALSE, e);
218 	}
219 
220 	/*
221 	**  Instantiate or deinstantiate the queue.
222 	*/
223 
224 	if ((!queueit && !bitset(EF_KEEPQUEUE, e->e_flags)) ||
225 	    bitset(EF_CLRQUEUE, e->e_flags))
226 	{
227 		if (tTd(50, 1))
228 			printf("\n===== Dropping [dq]f%s =====\n\n", e->e_id);
229 		if (e->e_df != NULL)
230 			xunlink(e->e_df);
231 		xunlink(queuename(e, 'q'));
232 
233 #ifdef LOG
234 		if (LogLevel > 10)
235 			syslog(LOG_INFO, "%s: done", id);
236 #endif
237 	}
238 	else if (queueit || !bitset(EF_INQUEUE, e->e_flags))
239 	{
240 #ifdef QUEUE
241 		queueup(e, bitset(EF_KEEPQUEUE, e->e_flags), FALSE);
242 #else /* QUEUE */
243 		syserr("554 dropenvelope: queueup");
244 #endif /* QUEUE */
245 	}
246 
247 	/* now unlock the job */
248 	closexscript(e);
249 	unlockqueue(e);
250 
251 	/* make sure that this envelope is marked unused */
252 	if (e->e_dfp != NULL)
253 		(void) xfclose(e->e_dfp, "dropenvelope", e->e_df);
254 	e->e_dfp = NULL;
255 	e->e_id = e->e_df = NULL;
256 }
257 /*
258 **  CLEARENVELOPE -- clear an envelope without unlocking
259 **
260 **	This is normally used by a child process to get a clean
261 **	envelope without disturbing the parent.
262 **
263 **	Parameters:
264 **		e -- the envelope to clear.
265 **		fullclear - if set, the current envelope is total
266 **			garbage and should be ignored; otherwise,
267 **			release any resources it may indicate.
268 **
269 **	Returns:
270 **		none.
271 **
272 **	Side Effects:
273 **		Closes files associated with the envelope.
274 **		Marks the envelope as unallocated.
275 */
276 
277 void
278 clearenvelope(e, fullclear)
279 	register ENVELOPE *e;
280 	bool fullclear;
281 {
282 	register HDR *bh;
283 	register HDR **nhp;
284 	extern ENVELOPE BlankEnvelope;
285 
286 	if (!fullclear)
287 	{
288 		/* clear out any file information */
289 		if (e->e_xfp != NULL)
290 			(void) xfclose(e->e_xfp, "clearenvelope xfp", e->e_id);
291 		if (e->e_dfp != NULL)
292 			(void) xfclose(e->e_dfp, "clearenvelope dfp", e->e_df);
293 		e->e_xfp = e->e_dfp = NULL;
294 	}
295 
296 	/* now clear out the data */
297 	STRUCTCOPY(BlankEnvelope, *e);
298 	if (Verbose)
299 		e->e_sendmode = SM_DELIVER;
300 	bh = BlankEnvelope.e_header;
301 	nhp = &e->e_header;
302 	while (bh != NULL)
303 	{
304 		*nhp = (HDR *) xalloc(sizeof *bh);
305 		bcopy((char *) bh, (char *) *nhp, sizeof *bh);
306 		bh = bh->h_link;
307 		nhp = &(*nhp)->h_link;
308 	}
309 }
310 /*
311 **  INITSYS -- initialize instantiation of system
312 **
313 **	In Daemon mode, this is done in the child.
314 **
315 **	Parameters:
316 **		none.
317 **
318 **	Returns:
319 **		none.
320 **
321 **	Side Effects:
322 **		Initializes the system macros, some global variables,
323 **		etc.  In particular, the current time in various
324 **		forms is set.
325 */
326 
327 void
328 initsys(e)
329 	register ENVELOPE *e;
330 {
331 	char cbuf[5];				/* holds hop count */
332 	char pbuf[10];				/* holds pid */
333 #ifdef TTYNAME
334 	static char ybuf[60];			/* holds tty id */
335 	register char *p;
336 #endif /* TTYNAME */
337 	extern char *ttyname();
338 	extern void settime();
339 	extern char Version[];
340 
341 	/*
342 	**  Give this envelope a reality.
343 	**	I.e., an id, a transcript, and a creation time.
344 	*/
345 
346 	openxscript(e);
347 	e->e_ctime = curtime();
348 
349 	/*
350 	**  Set OutChannel to something useful if stdout isn't it.
351 	**	This arranges that any extra stuff the mailer produces
352 	**	gets sent back to the user on error (because it is
353 	**	tucked away in the transcript).
354 	*/
355 
356 	if (OpMode == MD_DAEMON && bitset(EF_QUEUERUN, e->e_flags) &&
357 	    e->e_xfp != NULL)
358 		OutChannel = e->e_xfp;
359 
360 	/*
361 	**  Set up some basic system macros.
362 	*/
363 
364 	/* process id */
365 	(void) sprintf(pbuf, "%d", getpid());
366 	define('p', newstr(pbuf), e);
367 
368 	/* hop count */
369 	(void) sprintf(cbuf, "%d", e->e_hopcount);
370 	define('c', newstr(cbuf), e);
371 
372 	/* time as integer, unix time, arpa time */
373 	settime(e);
374 
375 #ifdef TTYNAME
376 	/* tty name */
377 	if (macvalue('y', e) == NULL)
378 	{
379 		p = ttyname(2);
380 		if (p != NULL)
381 		{
382 			if (strrchr(p, '/') != NULL)
383 				p = strrchr(p, '/') + 1;
384 			(void) strcpy(ybuf, p);
385 			define('y', ybuf, e);
386 		}
387 	}
388 #endif /* TTYNAME */
389 }
390 /*
391 **  SETTIME -- set the current time.
392 **
393 **	Parameters:
394 **		none.
395 **
396 **	Returns:
397 **		none.
398 **
399 **	Side Effects:
400 **		Sets the various time macros -- $a, $b, $d, $t.
401 */
402 
403 void
404 settime(e)
405 	register ENVELOPE *e;
406 {
407 	register char *p;
408 	auto time_t now;
409 	char tbuf[20];				/* holds "current" time */
410 	char dbuf[30];				/* holds ctime(tbuf) */
411 	register struct tm *tm;
412 	extern char *arpadate();
413 	extern struct tm *gmtime();
414 
415 	now = curtime();
416 	tm = gmtime(&now);
417 	(void) sprintf(tbuf, "%04d%02d%02d%02d%02d", tm->tm_year + 1900,
418 			tm->tm_mon+1, tm->tm_mday, tm->tm_hour, tm->tm_min);
419 	define('t', newstr(tbuf), e);
420 	(void) strcpy(dbuf, ctime(&now));
421 	p = strchr(dbuf, '\n');
422 	if (p != NULL)
423 		*p = '\0';
424 	define('d', newstr(dbuf), e);
425 	p = arpadate(dbuf);
426 	p = newstr(p);
427 	if (macvalue('a', e) == NULL)
428 		define('a', p, e);
429 	define('b', p, e);
430 }
431 /*
432 **  OPENXSCRIPT -- Open transcript file
433 **
434 **	Creates a transcript file for possible eventual mailing or
435 **	sending back.
436 **
437 **	Parameters:
438 **		e -- the envelope to create the transcript in/for.
439 **
440 **	Returns:
441 **		none
442 **
443 **	Side Effects:
444 **		Creates the transcript file.
445 */
446 
447 #ifndef O_APPEND
448 #define O_APPEND	0
449 #endif
450 
451 void
452 openxscript(e)
453 	register ENVELOPE *e;
454 {
455 	register char *p;
456 	int fd;
457 
458 	if (e->e_xfp != NULL)
459 		return;
460 	p = queuename(e, 'x');
461 	fd = open(p, O_WRONLY|O_CREAT|O_APPEND, 0644);
462 	if (fd < 0)
463 	{
464 		syserr("Can't create transcript file %s", p);
465 		fd = open("/dev/null", O_WRONLY, 0644);
466 		if (fd < 0)
467 			syserr("!Can't open /dev/null");
468 	}
469 	e->e_xfp = fdopen(fd, "w");
470 	if (e->e_xfp == NULL)
471 	{
472 		syserr("!Can't create transcript stream %s", p);
473 	}
474 	if (tTd(46, 9))
475 	{
476 		printf("openxscript(%s):\n  ", p);
477 		dumpfd(fileno(e->e_xfp), TRUE, FALSE);
478 	}
479 }
480 /*
481 **  CLOSEXSCRIPT -- close the transcript file.
482 **
483 **	Parameters:
484 **		e -- the envelope containing the transcript to close.
485 **
486 **	Returns:
487 **		none.
488 **
489 **	Side Effects:
490 **		none.
491 */
492 
493 void
494 closexscript(e)
495 	register ENVELOPE *e;
496 {
497 	if (e->e_xfp == NULL)
498 		return;
499 	(void) xfclose(e->e_xfp, "closexscript", e->e_id);
500 	e->e_xfp = NULL;
501 }
502 /*
503 **  SETSENDER -- set the person who this message is from
504 **
505 **	Under certain circumstances allow the user to say who
506 **	s/he is (using -f or -r).  These are:
507 **	1.  The user's uid is zero (root).
508 **	2.  The user's login name is in an approved list (typically
509 **	    from a network server).
510 **	3.  The address the user is trying to claim has a
511 **	    "!" character in it (since #2 doesn't do it for
512 **	    us if we are dialing out for UUCP).
513 **	A better check to replace #3 would be if the
514 **	effective uid is "UUCP" -- this would require me
515 **	to rewrite getpwent to "grab" uucp as it went by,
516 **	make getname more nasty, do another passwd file
517 **	scan, or compile the UID of "UUCP" into the code,
518 **	all of which are reprehensible.
519 **
520 **	Assuming all of these fail, we figure out something
521 **	ourselves.
522 **
523 **	Parameters:
524 **		from -- the person we would like to believe this message
525 **			is from, as specified on the command line.
526 **		e -- the envelope in which we would like the sender set.
527 **		delimptr -- if non-NULL, set to the location of the
528 **			trailing delimiter.
529 **		internal -- set if this address is coming from an internal
530 **			source such as an owner alias.
531 **
532 **	Returns:
533 **		none.
534 **
535 **	Side Effects:
536 **		sets sendmail's notion of who the from person is.
537 */
538 
539 void
540 setsender(from, e, delimptr, internal)
541 	char *from;
542 	register ENVELOPE *e;
543 	char **delimptr;
544 	bool internal;
545 {
546 	register char **pvp;
547 	char *realname = NULL;
548 	register struct passwd *pw;
549 	char delimchar;
550 	char *bp;
551 	char buf[MAXNAME + 2];
552 	char pvpbuf[PSBUFSIZE];
553 	extern struct passwd *getpwnam();
554 	extern char *FullName;
555 
556 	if (tTd(45, 1))
557 		printf("setsender(%s)\n", from == NULL ? "" : from);
558 
559 	/*
560 	**  Figure out the real user executing us.
561 	**	Username can return errno != 0 on non-errors.
562 	*/
563 
564 	if (bitset(EF_QUEUERUN, e->e_flags) || OpMode == MD_SMTP ||
565 	    OpMode == MD_ARPAFTP || OpMode == MD_DAEMON)
566 		realname = from;
567 	if (realname == NULL || realname[0] == '\0')
568 		realname = username();
569 
570 	if (ConfigLevel < 2)
571 		SuprErrs = TRUE;
572 
573 	delimchar = internal ? '\0' : ' ';
574 	e->e_from.q_flags = QBADADDR;
575 	if (from == NULL ||
576 	    parseaddr(from, &e->e_from, RF_COPYALL|RF_SENDERADDR,
577 		      delimchar, delimptr, e) == NULL ||
578 	    bitset(QBADADDR, e->e_from.q_flags) ||
579 	    e->e_from.q_mailer == ProgMailer ||
580 	    e->e_from.q_mailer == FileMailer ||
581 	    e->e_from.q_mailer == InclMailer)
582 	{
583 		/* log garbage addresses for traceback */
584 # ifdef LOG
585 		if (from != NULL && LogLevel > 2)
586 		{
587 			char *p;
588 			char ebuf[MAXNAME * 2 + 2];
589 
590 			p = macvalue('_', e);
591 			if (p == NULL)
592 			{
593 				char *host = RealHostName;
594 				if (host == NULL)
595 					host = MyHostName;
596 				(void) sprintf(ebuf, "%s@%s", realname, host);
597 				p = ebuf;
598 			}
599 			syslog(LOG_NOTICE,
600 				"setsender: %s: invalid or unparseable, received from %s",
601 				shortenstring(from, 83), p);
602 		}
603 # endif /* LOG */
604 		if (from != NULL)
605 		{
606 			if (!bitset(QBADADDR, e->e_from.q_flags))
607 			{
608 				/* it was a bogus mailer in the from addr */
609 				usrerr("553 Invalid sender address");
610 			}
611 			SuprErrs = TRUE;
612 		}
613 		if (from == realname ||
614 		    parseaddr(from = newstr(realname), &e->e_from,
615 			      RF_COPYALL|RF_SENDERADDR, ' ', NULL, e) == NULL)
616 		{
617 			char nbuf[100];
618 
619 			SuprErrs = TRUE;
620 			expand("\201n", nbuf, &nbuf[sizeof nbuf], e);
621 			if (parseaddr(from = newstr(nbuf), &e->e_from,
622 				      RF_COPYALL, ' ', NULL, e) == NULL &&
623 			    parseaddr(from = "postmaster", &e->e_from,
624 			    	      RF_COPYALL, ' ', NULL, e) == NULL)
625 				syserr("553 setsender: can't even parse postmaster!");
626 		}
627 	}
628 	else
629 		FromFlag = TRUE;
630 	e->e_from.q_flags |= QDONTSEND;
631 	if (tTd(45, 5))
632 	{
633 		printf("setsender: QDONTSEND ");
634 		printaddr(&e->e_from, FALSE);
635 	}
636 	SuprErrs = FALSE;
637 
638 	pvp = NULL;
639 	if (bitnset(M_CHECKUDB, e->e_from.q_mailer->m_flags))
640 	{
641 # ifdef USERDB
642 		register char *p;
643 		extern char *udbsender();
644 # endif
645 
646 		if (!internal)
647 		{
648 			/* if the user has given fullname already, don't redefine */
649 			if (FullName == NULL)
650 				FullName = macvalue('x', e);
651 			if (FullName != NULL && FullName[0] == '\0')
652 				FullName = NULL;
653 
654 # ifdef USERDB
655 			p = udbsender(e->e_from.q_user);
656 
657 			if (p != NULL)
658 			{
659 				/*
660 				**  We have an alternate address for the sender
661 				*/
662 
663 				pvp = prescan(p, '\0', pvpbuf, sizeof pvpbuf, NULL);
664 			}
665 # endif /* USERDB */
666 		}
667 
668 		if ((pw = getpwnam(e->e_from.q_user)) != NULL)
669 		{
670 			/*
671 			**  Process passwd file entry.
672 			*/
673 
674 			/* extract home directory */
675 			if (strcmp(pw->pw_dir, "/") == 0)
676 				e->e_from.q_home = newstr("");
677 			else
678 				e->e_from.q_home = newstr(pw->pw_dir);
679 			define('z', e->e_from.q_home, e);
680 
681 			/* extract user and group id */
682 			e->e_from.q_uid = pw->pw_uid;
683 			e->e_from.q_gid = pw->pw_gid;
684 			e->e_from.q_flags |= QGOODUID;
685 
686 			/* extract full name from passwd file */
687 			if (FullName == NULL && pw->pw_gecos != NULL &&
688 			    strcmp(pw->pw_name, e->e_from.q_user) == 0 &&
689 			    !internal)
690 			{
691 				buildfname(pw->pw_gecos, e->e_from.q_user, buf);
692 				if (buf[0] != '\0')
693 					FullName = newstr(buf);
694 			}
695 		}
696 		if (FullName != NULL && !internal)
697 			define('x', FullName, e);
698 	}
699 	else if (!internal && OpMode != MD_DAEMON)
700 	{
701 		if (e->e_from.q_home == NULL)
702 		{
703 			e->e_from.q_home = getenv("HOME");
704 			if (e->e_from.q_home != NULL &&
705 			    strcmp(e->e_from.q_home, "/") == 0)
706 				e->e_from.q_home++;
707 		}
708 		e->e_from.q_uid = RealUid;
709 		e->e_from.q_gid = RealGid;
710 		e->e_from.q_flags |= QGOODUID;
711 	}
712 
713 	/*
714 	**  Rewrite the from person to dispose of possible implicit
715 	**	links in the net.
716 	*/
717 
718 	if (pvp == NULL)
719 		pvp = prescan(from, delimchar, pvpbuf, sizeof pvpbuf, NULL);
720 	if (pvp == NULL)
721 	{
722 		/* don't need to give error -- prescan did that already */
723 # ifdef LOG
724 		if (LogLevel > 2)
725 			syslog(LOG_NOTICE, "cannot prescan from (%s)", from);
726 # endif
727 		finis();
728 	}
729 	(void) rewrite(pvp, 3, 0, e);
730 	(void) rewrite(pvp, 1, 0, e);
731 	(void) rewrite(pvp, 4, 0, e);
732 	bp = buf + 1;
733 	cataddr(pvp, NULL, bp, sizeof buf - 2, '\0');
734 	if (*bp == '@' && !bitnset(M_NOBRACKET, e->e_from.q_mailer->m_flags))
735 	{
736 		/* heuristic: route-addr: add angle brackets */
737 		strcat(bp, ">");
738 		*--bp = '<';
739 	}
740 	e->e_sender = newstr(bp);
741 	define('f', e->e_sender, e);
742 
743 	/* save the domain spec if this mailer wants it */
744 	if (e->e_from.q_mailer != NULL &&
745 	    bitnset(M_CANONICAL, e->e_from.q_mailer->m_flags))
746 	{
747 		extern char **copyplist();
748 
749 		while (*pvp != NULL && strcmp(*pvp, "@") != 0)
750 			pvp++;
751 		if (*pvp != NULL)
752 			e->e_fromdomain = copyplist(pvp, TRUE);
753 	}
754 }
755