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