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