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