more cleanup for DSN drafts
[unix-history] / usr / src / usr.sbin / sendmail / src / envelope.c
index 7c01a1e..8523480 100644 (file)
@@ -1,21 +1,17 @@
 /*
  * Copyright (c) 1983 Eric P. Allman
 /*
  * Copyright (c) 1983 Eric P. Allman
- * Copyright (c) 1988 Regents of the University of California.
- * All rights reserved.
+ * Copyright (c) 1988, 1993
+ *     The Regents of the University of California.  All rights reserved.
  *
  * %sccs.include.redist.c%
  */
 
 #ifndef lint
  *
  * %sccs.include.redist.c%
  */
 
 #ifndef lint
-static char sccsid[] = "@(#)envelope.c 6.9 (Berkeley) %G%";
+static char sccsid[] = "@(#)envelope.c 8.56 (Berkeley) %G%";
 #endif /* not lint */
 
 #endif /* not lint */
 
-#include <sys/types.h>
-#include <sys/time.h>
-#include <sys/stat.h>
-#include <pwd.h>
-#include <fcntl.h>
 #include "sendmail.h"
 #include "sendmail.h"
+#include <pwd.h>
 
 /*
 **  NEWENVELOPE -- allocate a new envelope
 
 /*
 **  NEWENVELOPE -- allocate a new envelope
@@ -24,6 +20,7 @@ static char sccsid[] = "@(#)envelope.c        6.9 (Berkeley) %G%";
 **
 **     Parameters:
 **             e -- the new envelope to fill in.
 **
 **     Parameters:
 **             e -- the new envelope to fill in.
+**             parent -- the envelope to be the parent of e.
 **
 **     Returns:
 **             e.
 **
 **     Returns:
 **             e.
@@ -33,15 +30,14 @@ static char sccsid[] = "@(#)envelope.c      6.9 (Berkeley) %G%";
 */
 
 ENVELOPE *
 */
 
 ENVELOPE *
-newenvelope(e)
+newenvelope(e, parent)
        register ENVELOPE *e;
        register ENVELOPE *e;
-{
        register ENVELOPE *parent;
        register ENVELOPE *parent;
+{
        extern putheader(), putbody();
        extern ENVELOPE BlankEnvelope;
 
        extern putheader(), putbody();
        extern ENVELOPE BlankEnvelope;
 
-       parent = CurEnv;
-       if (e == CurEnv && e->e_parent != NULL)
+       if (e == parent && e->e_parent != NULL)
                parent = e->e_parent;
        clearenvelope(e, TRUE);
        if (e == CurEnv)
                parent = e->e_parent;
        clearenvelope(e, TRUE);
        if (e == CurEnv)
@@ -73,61 +69,203 @@ newenvelope(e)
 **             Unlocks this queue file.
 */
 
 **             Unlocks this queue file.
 */
 
+void
 dropenvelope(e)
        register ENVELOPE *e;
 {
        bool queueit = FALSE;
 dropenvelope(e)
        register ENVELOPE *e;
 {
        bool queueit = FALSE;
+       bool failure_return = FALSE;
+       bool success_return = FALSE;
        register ADDRESS *q;
        char *id = e->e_id;
        register ADDRESS *q;
        char *id = e->e_id;
+       char buf[MAXLINE];
 
        if (tTd(50, 1))
        {
 
        if (tTd(50, 1))
        {
-               printf("dropenvelope %x id=", e);
+               extern void printenvflags();
+
+               printf("dropenvelope %x: id=", e);
                xputs(e->e_id);
                xputs(e->e_id);
-               printf(" flags=%o\n", e->e_flags);
+               printf(", flags=");
+               printenvflags(e);
+               if (tTd(50, 10))
+               {
+                       printf("sendq=");
+                       printaddr(e->e_sendqueue, TRUE);
+               }
        }
 
        }
 
+       /* we must have an id to remove disk files */
        if (id == NULL)
        if (id == NULL)
-               id = "(none)";
+               return;
 
 #ifdef LOG
 
 #ifdef LOG
+       if (LogLevel > 4 && bitset(EF_LOGSENDER, e->e_flags))
+               logsender(e, NULL);
        if (LogLevel > 84)
        if (LogLevel > 84)
-               syslog(LOG_DEBUG, "dropenvelope, id=%s, flags=%o, pid=%d",
+               syslog(LOG_DEBUG, "dropenvelope, id=%s, flags=0x%x, pid=%d",
                                  id, e->e_flags, getpid());
 #endif /* LOG */
                                  id, e->e_flags, getpid());
 #endif /* LOG */
+       e->e_flags &= ~EF_LOGSENDER;
 
 
-       /* we must have an id to remove disk files */
-       if (e->e_id == NULL)
-               return;
+       /* post statistics */
+       poststats(StatFile);
 
        /*
        **  Extract state information from dregs of send list.
        */
 
 
        /*
        **  Extract state information from dregs of send list.
        */
 
+       e->e_flags &= ~EF_QUEUERUN;
        for (q = e->e_sendqueue; q != NULL; q = q->q_next)
        {
                if (bitset(QQUEUEUP, q->q_flags))
                        queueit = TRUE;
        for (q = e->e_sendqueue; q != NULL; q = q->q_next)
        {
                if (bitset(QQUEUEUP, q->q_flags))
                        queueit = TRUE;
+
+               /* see if a notification is needed */
+               if (bitset(QBADADDR, q->q_flags) &&
+                   bitset(QPINGONFAILURE, q->q_flags))
+               {
+                       failure_return = TRUE;
+                       if (q->q_owner == NULL && !emptyaddr(&e->e_from))
+                               (void) sendtolist(e->e_from.q_paddr, NULL,
+                                                 &e->e_errorqueue, 0, e);
+               }
+               else if (bitset(QPINGONSUCCESS, q->q_flags) &&
+                        ((bitset(QSENT, q->q_flags) &&
+                          bitnset(M_LOCALMAILER, q->q_mailer->m_flags)) ||
+                         bitset(QRELAYED|QEXPLODED, q->q_flags)))
+               {
+                       success_return = TRUE;
+               }
+       }
+
+       if (e->e_class < 0)
+               e->e_flags |= EF_NO_BODY_RETN;
+
+       /*
+       **  See if the message timed out.
+       */
+
+       if (!queueit)
+               /* nothing to do */ ;
+       else if (curtime() > e->e_ctime + TimeOuts.to_q_return[e->e_timeoutclass])
+       {
+               (void) sprintf(buf, "Cannot send message for %s",
+                       pintvl(TimeOuts.to_q_return[e->e_timeoutclass], FALSE));
+               if (e->e_message != NULL)
+                       free(e->e_message);
+               e->e_message = newstr(buf);
+               message(buf);
+               e->e_flags |= EF_CLRQUEUE;
+               failure_return = TRUE;
+               fprintf(e->e_xfp, "Message could not be delivered for %s\n",
+                       pintvl(TimeOuts.to_q_return[e->e_timeoutclass], FALSE));
+               fprintf(e->e_xfp, "Message will be deleted from queue\n");
+               for (q = e->e_sendqueue; q != NULL; q = q->q_next)
+               {
+                       if (bitset(QQUEUEUP, q->q_flags))
+                               q->q_flags |= QBADADDR;
+               }
+       }
+       else if (TimeOuts.to_q_warning[e->e_timeoutclass] > 0 &&
+           curtime() > e->e_ctime + TimeOuts.to_q_warning[e->e_timeoutclass])
+       {
+               bool delay_return = FALSE;
+
+               for (q = e->e_sendqueue; q != NULL; q = q->q_next)
+               {
+                       if (bitset(QQUEUEUP, q->q_flags) &&
+                           bitset(QPINGONDELAY, q->q_flags))
+                       {
+                               q->q_flags |= QREPORT;
+                               delay_return = TRUE;
+                       }
+               }
+               if (delay_return &&
+                   !bitset(EF_WARNING|EF_RESPONSE, e->e_flags) &&
+                   e->e_class >= 0 &&
+                   strcmp(e->e_from.q_paddr, "<>") != 0 &&
+                   strncasecmp(e->e_from.q_paddr, "owner-", 6) != 0 &&
+                   (strlen(e->e_from.q_paddr) <= 8 ||
+                    strcasecmp(&e->e_from.q_paddr[strlen(e->e_from.q_paddr) - 8], "-request") != 0))
+               {
+                       (void) sprintf(buf,
+                               "Warning: cannot send message for %s",
+                               pintvl(TimeOuts.to_q_warning[e->e_timeoutclass], FALSE));
+                       if (e->e_message != NULL)
+                               free(e->e_message);
+                       e->e_message = newstr(buf);
+                       message(buf);
+                       e->e_flags |= EF_WARNING;
+                       failure_return = TRUE;
+               }
+               fprintf(e->e_xfp,
+                       "Warning: message still undelivered after %s\n",
+                       pintvl(TimeOuts.to_q_warning[e->e_timeoutclass], FALSE));
+               fprintf(e->e_xfp, "Will keep trying until message is %s old\n",
+                       pintvl(TimeOuts.to_q_return[e->e_timeoutclass], FALSE));
+       }
+
+       if (tTd(50, 2))
+               printf("failure_return=%d success_return=%d queueit=%d\n",
+                       failure_return, success_return, queueit);
+
+       /*
+       **  If we had some fatal error, but no addresses are marked as
+       **  bad, mark them _all_ as bad.
+       */
+
+       if (bitset(EF_FATALERRS, e->e_flags) && !failure_return)
+       {
+               failure_return = TRUE;
+               for (q = e->e_sendqueue; q != NULL; q = q->q_next)
+               {
+                       if (!bitset(QDONTSEND, q->q_flags))
+                               q->q_flags |= QBADADDR;
+               }
        }
 
        /*
        **  Send back return receipts as requested.
        */
 
        }
 
        /*
        **  Send back return receipts as requested.
        */
 
-       if (e->e_receiptto != NULL && bitset(EF_SENDRECEIPT, e->e_flags))
+/*
+       if (e->e_receiptto != NULL && bitset(EF_SENDRECEIPT, e->e_flags)
+           && !bitset(PRIV_NORECEIPTS, PrivacyFlags))
+*/
+       if (e->e_receiptto == NULL)
+               e->e_receiptto = e->e_from.q_paddr;
+       if (success_return && !failure_return &&
+           !bitset(PRIV_NORECEIPTS, PrivacyFlags) &&
+           strcmp(e->e_receiptto, "<>") != 0)
        {
                auto ADDRESS *rlist = NULL;
 
        {
                auto ADDRESS *rlist = NULL;
 
-               sendtolist(e->e_receiptto, (ADDRESS *) NULL, &rlist, e);
+               e->e_flags |= EF_SENDRECEIPT;
+               (void) sendtolist(e->e_receiptto, NULLADDR, &rlist, 0, e);
                (void) returntosender("Return receipt", rlist, FALSE, e);
        }
                (void) returntosender("Return receipt", rlist, FALSE, e);
        }
+       e->e_flags &= ~EF_SENDRECEIPT;
 
        /*
        **  Arrange to send error messages if there are fatal errors.
        */
 
 
        /*
        **  Arrange to send error messages if there are fatal errors.
        */
 
-       if (bitset(EF_FATALERRS|EF_TIMEOUT, e->e_flags) && ErrorMode != EM_QUIET)
-               savemail(e);
+       if (failure_return && e->e_errormode != EM_QUIET)
+               savemail(e, !bitset(EF_NO_BODY_RETN, e->e_flags));
+
+       /*
+       **  Arrange to send warning messages to postmaster as requested.
+       */
+
+       if (bitset(EF_PM_NOTIFY, e->e_flags) && PostMasterCopy != NULL &&
+           !bitset(EF_RESPONSE, e->e_flags) && e->e_class >= 0)
+       {
+               auto ADDRESS *rlist = NULL;
+
+               (void) sendtolist(PostMasterCopy, NULLADDR, &rlist, 0, e);
+               (void) returntosender(e->e_message, rlist, FALSE, e);
+       }
 
        /*
        **  Instantiate or deinstantiate the queue.
 
        /*
        **  Instantiate or deinstantiate the queue.
@@ -136,16 +274,28 @@ dropenvelope(e)
        if ((!queueit && !bitset(EF_KEEPQUEUE, e->e_flags)) ||
            bitset(EF_CLRQUEUE, e->e_flags))
        {
        if ((!queueit && !bitset(EF_KEEPQUEUE, e->e_flags)) ||
            bitset(EF_CLRQUEUE, e->e_flags))
        {
-               if (e->e_df != NULL)
-                       xunlink(e->e_df);
+               if (tTd(50, 1))
+               {
+                       extern void printenvflags();
+
+                       printf("\n===== Dropping [dq]f%s... queueit=%d, e_flags=",
+                               e->e_id, queueit);
+                       printenvflags(e);
+               }
+               xunlink(queuename(e, 'd'));
                xunlink(queuename(e, 'q'));
                xunlink(queuename(e, 'q'));
+
+#ifdef LOG
+               if (LogLevel > 10)
+                       syslog(LOG_INFO, "%s: done", id);
+#endif
        }
        else if (queueit || !bitset(EF_INQUEUE, e->e_flags))
        {
 #ifdef QUEUE
        }
        else if (queueit || !bitset(EF_INQUEUE, e->e_flags))
        {
 #ifdef QUEUE
-               queueup(e, FALSE, FALSE);
+               queueup(e, bitset(EF_KEEPQUEUE, e->e_flags), FALSE);
 #else /* QUEUE */
 #else /* QUEUE */
-               syserr("dropenvelope: queueup");
+               syserr("554 dropenvelope: queueup");
 #endif /* QUEUE */
        }
 
 #endif /* QUEUE */
        }
 
@@ -154,15 +304,11 @@ dropenvelope(e)
        unlockqueue(e);
 
        /* make sure that this envelope is marked unused */
        unlockqueue(e);
 
        /* make sure that this envelope is marked unused */
-       e->e_id = e->e_df = NULL;
        if (e->e_dfp != NULL)
        if (e->e_dfp != NULL)
-               (void) fclose(e->e_dfp);
+               (void) xfclose(e->e_dfp, "dropenvelope df", e->e_id);
        e->e_dfp = NULL;
        e->e_dfp = NULL;
-
-#ifdef LOG
-       if (LogLevel > 74)
-               syslog(LOG_INFO, "%s: done", id);
-#endif /* LOG */
+       e->e_id = NULL;
+       e->e_flags &= ~EF_HAS_DF;
 }
 \f/*
 **  CLEARENVELOPE -- clear an envelope without unlocking
 }
 \f/*
 **  CLEARENVELOPE -- clear an envelope without unlocking
@@ -184,6 +330,7 @@ dropenvelope(e)
 **             Marks the envelope as unallocated.
 */
 
 **             Marks the envelope as unallocated.
 */
 
+void
 clearenvelope(e, fullclear)
        register ENVELOPE *e;
        bool fullclear;
 clearenvelope(e, fullclear)
        register ENVELOPE *e;
        bool fullclear;
@@ -196,13 +343,16 @@ clearenvelope(e, fullclear)
        {
                /* clear out any file information */
                if (e->e_xfp != NULL)
        {
                /* clear out any file information */
                if (e->e_xfp != NULL)
-                       (void) fclose(e->e_xfp);
+                       (void) xfclose(e->e_xfp, "clearenvelope xfp", e->e_id);
                if (e->e_dfp != NULL)
                if (e->e_dfp != NULL)
-                       (void) fclose(e->e_dfp);
+                       (void) xfclose(e->e_dfp, "clearenvelope dfp", e->e_id);
+               e->e_xfp = e->e_dfp = NULL;
        }
 
        /* now clear out the data */
        STRUCTCOPY(BlankEnvelope, *e);
        }
 
        /* now clear out the data */
        STRUCTCOPY(BlankEnvelope, *e);
+       if (Verbose)
+               e->e_sendmode = SM_DELIVER;
        bh = BlankEnvelope.e_header;
        nhp = &e->e_header;
        while (bh != NULL)
        bh = BlankEnvelope.e_header;
        nhp = &e->e_header;
        while (bh != NULL)
@@ -230,17 +380,18 @@ clearenvelope(e, fullclear)
 **             forms is set.
 */
 
 **             forms is set.
 */
 
+void
 initsys(e)
        register ENVELOPE *e;
 {
 initsys(e)
        register ENVELOPE *e;
 {
-       static char cbuf[5];                    /* holds hop count */
-       static char pbuf[10];                   /* holds pid */
+       char cbuf[5];                           /* holds hop count */
+       char pbuf[10];                          /* holds pid */
 #ifdef TTYNAME
 #ifdef TTYNAME
-       static char ybuf[10];                   /* holds tty id */
+       static char ybuf[60];                   /* holds tty id */
        register char *p;
 #endif /* TTYNAME */
        extern char *ttyname();
        register char *p;
 #endif /* TTYNAME */
        extern char *ttyname();
-       extern char *macvalue();
+       extern void settime();
        extern char Version[];
 
        /*
        extern char Version[];
 
        /*
@@ -258,7 +409,8 @@ initsys(e)
        **      tucked away in the transcript).
        */
 
        **      tucked away in the transcript).
        */
 
-       if (OpMode == MD_DAEMON && QueueRun && e->e_xfp != NULL)
+       if (OpMode == MD_DAEMON && bitset(EF_QUEUERUN, e->e_flags) &&
+           e->e_xfp != NULL)
                OutChannel = e->e_xfp;
 
        /*
                OutChannel = e->e_xfp;
 
        /*
@@ -267,11 +419,11 @@ initsys(e)
 
        /* process id */
        (void) sprintf(pbuf, "%d", getpid());
 
        /* process id */
        (void) sprintf(pbuf, "%d", getpid());
-       define('p', pbuf, e);
+       define('p', newstr(pbuf), e);
 
        /* hop count */
        (void) sprintf(cbuf, "%d", e->e_hopcount);
 
        /* hop count */
        (void) sprintf(cbuf, "%d", e->e_hopcount);
-       define('c', cbuf, e);
+       define('c', newstr(cbuf), e);
 
        /* time as integer, unix time, arpa time */
        settime(e);
 
        /* time as integer, unix time, arpa time */
        settime(e);
@@ -304,28 +456,30 @@ initsys(e)
 **             Sets the various time macros -- $a, $b, $d, $t.
 */
 
 **             Sets the various time macros -- $a, $b, $d, $t.
 */
 
+void
 settime(e)
        register ENVELOPE *e;
 {
        register char *p;
        auto time_t now;
 settime(e)
        register ENVELOPE *e;
 {
        register char *p;
        auto time_t now;
-       static char tbuf[20];                   /* holds "current" time */
-       static char dbuf[30];                   /* holds ctime(tbuf) */
+       char tbuf[20];                          /* holds "current" time */
+       char dbuf[30];                          /* holds ctime(tbuf) */
        register struct tm *tm;
        extern char *arpadate();
        extern struct tm *gmtime();
        register struct tm *tm;
        extern char *arpadate();
        extern struct tm *gmtime();
-       extern char *macvalue();
 
        now = curtime();
        tm = gmtime(&now);
        (void) sprintf(tbuf, "%04d%02d%02d%02d%02d", tm->tm_year + 1900,
                        tm->tm_mon+1, tm->tm_mday, tm->tm_hour, tm->tm_min);
 
        now = curtime();
        tm = gmtime(&now);
        (void) sprintf(tbuf, "%04d%02d%02d%02d%02d", tm->tm_year + 1900,
                        tm->tm_mon+1, tm->tm_mday, tm->tm_hour, tm->tm_min);
-       define('t', tbuf, e);
+       define('t', newstr(tbuf), e);
        (void) strcpy(dbuf, ctime(&now));
        (void) strcpy(dbuf, ctime(&now));
-       *strchr(dbuf, '\n') = '\0';
-       if (macvalue('d', e) == NULL)
-               define('d', dbuf, e);
-       p = newstr(arpadate(dbuf));
+       p = strchr(dbuf, '\n');
+       if (p != NULL)
+               *p = '\0';
+       define('d', newstr(dbuf), e);
+       p = arpadate(dbuf);
+       p = newstr(p);
        if (macvalue('a', e) == NULL)
                define('a', p, e);
        define('b', p, e);
        if (macvalue('a', e) == NULL)
                define('a', p, e);
        define('b', p, e);
@@ -346,6 +500,11 @@ settime(e)
 **             Creates the transcript file.
 */
 
 **             Creates the transcript file.
 */
 
+#ifndef O_APPEND
+#define O_APPEND       0
+#endif
+
+void
 openxscript(e)
        register ENVELOPE *e;
 {
 openxscript(e)
        register ENVELOPE *e;
 {
@@ -355,11 +514,27 @@ openxscript(e)
        if (e->e_xfp != NULL)
                return;
        p = queuename(e, 'x');
        if (e->e_xfp != NULL)
                return;
        p = queuename(e, 'x');
-       fd = open(p, O_WRONLY|O_CREAT, 0644);
+       fd = open(p, O_WRONLY|O_CREAT|O_APPEND, 0644);
        if (fd < 0)
        if (fd < 0)
-               syserr("Can't create %s", p);
-       else
-               e->e_xfp = fdopen(fd, "w");
+       {
+               syserr("Can't create transcript file %s", p);
+               fd = open("/dev/null", O_WRONLY, 0644);
+               if (fd < 0)
+                       syserr("!Can't open /dev/null");
+       }
+       e->e_xfp = fdopen(fd, "a");
+       if (e->e_xfp == NULL)
+               syserr("!Can't create transcript stream %s", p);
+#ifdef HASSETVBUF
+       setvbuf(e->e_xfp, NULL, _IOLBF, 0);
+#else
+       setlinebuf(e->e_xfp);
+#endif
+       if (tTd(46, 9))
+       {
+               printf("openxscript(%s):\n  ", p);
+               dumpfd(fileno(e->e_xfp), TRUE, FALSE);
+       }
 }
 \f/*
 **  CLOSEXSCRIPT -- close the transcript file.
 }
 \f/*
 **  CLOSEXSCRIPT -- close the transcript file.
@@ -374,12 +549,13 @@ openxscript(e)
 **             none.
 */
 
 **             none.
 */
 
+void
 closexscript(e)
        register ENVELOPE *e;
 {
        if (e->e_xfp == NULL)
                return;
 closexscript(e)
        register ENVELOPE *e;
 {
        if (e->e_xfp == NULL)
                return;
-       (void) fclose(e->e_xfp);
+       (void) xfclose(e->e_xfp, "closexscript", e->e_id);
        e->e_xfp = NULL;
 }
 \f/*
        e->e_xfp = NULL;
 }
 \f/*
@@ -407,6 +583,10 @@ closexscript(e)
 **             from -- the person we would like to believe this message
 **                     is from, as specified on the command line.
 **             e -- the envelope in which we would like the sender set.
 **             from -- the person we would like to believe this message
 **                     is from, as specified on the command line.
 **             e -- the envelope in which we would like the sender set.
+**             delimptr -- if non-NULL, set to the location of the
+**                     trailing delimiter.
+**             internal -- set if this address is coming from an internal
+**                     source such as an owner alias.
 **
 **     Returns:
 **             none.
 **
 **     Returns:
 **             none.
@@ -415,19 +595,21 @@ closexscript(e)
 **             sets sendmail's notion of who the from person is.
 */
 
 **             sets sendmail's notion of who the from person is.
 */
 
-setsender(from, e)
+void
+setsender(from, e, delimptr, internal)
        char *from;
        register ENVELOPE *e;
        char *from;
        register ENVELOPE *e;
+       char **delimptr;
+       bool internal;
 {
        register char **pvp;
        char *realname = NULL;
        register struct passwd *pw;
 {
        register char **pvp;
        char *realname = NULL;
        register struct passwd *pw;
-       char buf[MAXNAME];
+       char delimchar;
+       char *bp;
+       char buf[MAXNAME + 2];
        char pvpbuf[PSBUFSIZE];
        extern struct passwd *getpwnam();
        char pvpbuf[PSBUFSIZE];
        extern struct passwd *getpwnam();
-       extern char *macvalue();
-       extern char **prescan();
-       extern bool safefile();
        extern char *FullName;
 
        if (tTd(45, 1))
        extern char *FullName;
 
        if (tTd(45, 1))
@@ -438,58 +620,68 @@ setsender(from, e)
        **      Username can return errno != 0 on non-errors.
        */
 
        **      Username can return errno != 0 on non-errors.
        */
 
-       if (QueueRun || OpMode == MD_SMTP)
+       if (bitset(EF_QUEUERUN, e->e_flags) || OpMode == MD_SMTP ||
+           OpMode == MD_ARPAFTP || OpMode == MD_DAEMON)
                realname = from;
        if (realname == NULL || realname[0] == '\0')
                realname = from;
        if (realname == NULL || realname[0] == '\0')
-       {
-               extern char *username();
-
                realname = username();
                realname = username();
-       }
-
-       /*
-       **  Determine if this real person is allowed to alias themselves.
-       */
-
-       if (from != NULL)
-       {
-               extern bool trusteduser();
 
 
-               if (!trusteduser(realname) && getuid() != geteuid() &&
-                   strchr(from, '!') == NULL && getuid() != 0)
-               {
-                       /* network sends -r regardless (why why why?) */
-                       /* syserr("%s, you cannot use the -f flag", realname); */
-                       from = NULL;
-               }
-       }
-
-/*
-       SuprErrs = TRUE;
-*/
-       if (from == NULL || parseaddr(from, &e->e_from, 1, '\0', e) == NULL)
+       if (ConfigLevel < 2)
+               SuprErrs = TRUE;
+
+       delimchar = internal ? '\0' : ' ';
+       e->e_from.q_flags = QBADADDR;
+       if (from == NULL ||
+           parseaddr(from, &e->e_from, RF_COPYALL|RF_SENDERADDR,
+                     delimchar, delimptr, e) == NULL ||
+           bitset(QBADADDR, e->e_from.q_flags) ||
+           e->e_from.q_mailer == ProgMailer ||
+           e->e_from.q_mailer == FileMailer ||
+           e->e_from.q_mailer == InclMailer)
        {
                /* log garbage addresses for traceback */
 # ifdef LOG
                if (from != NULL && LogLevel > 2)
                {
        {
                /* log garbage addresses for traceback */
 # ifdef LOG
                if (from != NULL && LogLevel > 2)
                {
-                       char *host = RealHostName;
+                       char *p;
+                       char ebuf[MAXNAME * 2 + 2];
 
 
-                       if (host == NULL)
-                               host = MyHostName;
+                       p = macvalue('_', e);
+                       if (p == NULL)
+                       {
+                               char *host = RealHostName;
+                               if (host == NULL)
+                                       host = MyHostName;
+                               (void) sprintf(ebuf, "%s@%s", realname, host);
+                               p = ebuf;
+                       }
                        syslog(LOG_NOTICE,
                        syslog(LOG_NOTICE,
-                               "from=%s unparseable, received from %s@%s",
-                               from, realname, host);
+                               "setsender: %s: invalid or unparseable, received from %s",
+                               shortenstring(from, 83), p);
                }
 # endif /* LOG */
                if (from != NULL)
                }
 # endif /* LOG */
                if (from != NULL)
+               {
+                       if (!bitset(QBADADDR, e->e_from.q_flags))
+                       {
+                               /* it was a bogus mailer in the from addr */
+                               usrerr("553 Invalid sender address");
+                       }
                        SuprErrs = TRUE;
                        SuprErrs = TRUE;
+               }
                if (from == realname ||
                if (from == realname ||
-                   parseaddr(from = newstr(realname), &e->e_from, 1, '\0', e) == NULL)
+                   parseaddr(from = newstr(realname), &e->e_from,
+                             RF_COPYALL|RF_SENDERADDR, ' ', NULL, e) == NULL)
                {
                {
+                       char nbuf[100];
+
                        SuprErrs = TRUE;
                        SuprErrs = TRUE;
-                       if (parseaddr("postmaster", &e->e_from, 1, '\0', e) == NULL)
-                               syserr("setsender: can't even parse postmaster!");
+                       expand("\201n", nbuf, sizeof nbuf, e);
+                       if (parseaddr(from = newstr(nbuf), &e->e_from,
+                                     RF_COPYALL, ' ', NULL, e) == NULL &&
+                           parseaddr(from = "postmaster", &e->e_from,
+                                     RF_COPYALL, ' ', NULL, e) == NULL)
+                               syserr("553 setsender: can't even parse postmaster!");
                }
        }
        else
                }
        }
        else
@@ -500,35 +692,30 @@ setsender(from, e)
                printf("setsender: QDONTSEND ");
                printaddr(&e->e_from, FALSE);
        }
                printf("setsender: QDONTSEND ");
                printaddr(&e->e_from, FALSE);
        }
-       loweraddr(&e->e_from);
        SuprErrs = FALSE;
 
        SuprErrs = FALSE;
 
-       pvp = NULL;
-       if (e->e_from.q_mailer == LocalMailer)
-       {
 # ifdef USERDB
 # ifdef USERDB
+       if (bitnset(M_CHECKUDB, e->e_from.q_mailer->m_flags))
+       {
                register char *p;
                extern char *udbsender();
                register char *p;
                extern char *udbsender();
-# endif
-
-               /* if the user has given fullname already, don't redefine */
-               if (FullName == NULL)
-                       FullName = macvalue('x', e);
-               if (FullName != NULL && FullName[0] == '\0')
-                       FullName = NULL;
-
-# ifdef USERDB
-               p = udbsender(from);
 
 
+               p = udbsender(e->e_from.q_user);
                if (p != NULL)
                if (p != NULL)
-               {
-                       /*
-                       **  We have an alternate address for the sender
-                       */
+                       from = p;
+       }
+# endif /* USERDB */
 
 
-                       pvp = prescan(p, '\0', pvpbuf);
+       if (bitnset(M_HASPWENT, e->e_from.q_mailer->m_flags))
+       {
+               if (!internal)
+               {
+                       /* if the user already given fullname don't redefine */
+                       if (FullName == NULL)
+                               FullName = macvalue('x', e);
+                       if (FullName != NULL && FullName[0] == '\0')
+                               FullName = NULL;
                }
                }
-# endif /* USERDB */
 
                if ((pw = getpwnam(e->e_from.q_user)) != NULL)
                {
 
                if ((pw = getpwnam(e->e_from.q_user)) != NULL)
                {
@@ -536,33 +723,45 @@ setsender(from, e)
                        **  Process passwd file entry.
                        */
 
                        **  Process passwd file entry.
                        */
 
-
                        /* extract home directory */
                        /* extract home directory */
-                       e->e_from.q_home = newstr(pw->pw_dir);
+                       if (strcmp(pw->pw_dir, "/") == 0)
+                               e->e_from.q_home = newstr("");
+                       else
+                               e->e_from.q_home = newstr(pw->pw_dir);
                        define('z', e->e_from.q_home, e);
 
                        /* extract user and group id */
                        e->e_from.q_uid = pw->pw_uid;
                        e->e_from.q_gid = pw->pw_gid;
                        define('z', e->e_from.q_home, e);
 
                        /* extract user and group id */
                        e->e_from.q_uid = pw->pw_uid;
                        e->e_from.q_gid = pw->pw_gid;
+                       e->e_from.q_flags |= QGOODUID;
 
                        /* extract full name from passwd file */
                        if (FullName == NULL && pw->pw_gecos != NULL &&
 
                        /* extract full name from passwd file */
                        if (FullName == NULL && pw->pw_gecos != NULL &&
-                           strcmp(pw->pw_name, e->e_from.q_user) == 0)
+                           strcmp(pw->pw_name, e->e_from.q_user) == 0 &&
+                           !internal)
                        {
                        {
-                               buildfname(pw->pw_gecos, e->e_from.q_user, buf);
+                               if (buildfname(pw->pw_gecos, e->e_from.q_user, buf) &&
+                                       hvalue("MIME-Version", e) == NULL)
+                                               addheader("MIME-Version", "1.0", e);
                                if (buf[0] != '\0')
                                        FullName = newstr(buf);
                        }
                }
                                if (buf[0] != '\0')
                                        FullName = newstr(buf);
                        }
                }
-               if (FullName != NULL)
+               if (FullName != NULL && !internal)
                        define('x', FullName, e);
        }
                        define('x', FullName, e);
        }
-       else
+       else if (!internal && OpMode != MD_DAEMON)
        {
                if (e->e_from.q_home == NULL)
        {
                if (e->e_from.q_home == NULL)
+               {
                        e->e_from.q_home = getenv("HOME");
                        e->e_from.q_home = getenv("HOME");
-               e->e_from.q_uid = getuid();
-               e->e_from.q_gid = getgid();
+                       if (e->e_from.q_home != NULL &&
+                           strcmp(e->e_from.q_home, "/") == 0)
+                               e->e_from.q_home++;
+               }
+               e->e_from.q_uid = RealUid;
+               e->e_from.q_gid = RealGid;
+               e->e_from.q_flags |= QGOODUID;
        }
 
        /*
        }
 
        /*
@@ -570,23 +769,30 @@ setsender(from, e)
        **      links in the net.
        */
 
        **      links in the net.
        */
 
-       if (pvp == NULL)
-               pvp = prescan(from, '\0', pvpbuf);
+       pvp = prescan(from, delimchar, pvpbuf, sizeof pvpbuf, NULL);
        if (pvp == NULL)
        {
        if (pvp == NULL)
        {
+               /* don't need to give error -- prescan did that already */
 # ifdef LOG
                if (LogLevel > 2)
                        syslog(LOG_NOTICE, "cannot prescan from (%s)", from);
 # endif
 # ifdef LOG
                if (LogLevel > 2)
                        syslog(LOG_NOTICE, "cannot prescan from (%s)", from);
 # endif
-               usrerr("cannot prescan from (%s)", from);
                finis();
        }
                finis();
        }
-       rewrite(pvp, 3);
-       rewrite(pvp, 1);
-       rewrite(pvp, 4);
-       cataddr(pvp, buf, sizeof buf);
-       e->e_sender = e->e_returnpath = newstr(buf);
-
+/*
+       (void) rewrite(pvp, 3, 0, e);
+       (void) rewrite(pvp, 1, 0, e);
+       (void) rewrite(pvp, 4, 0, e);
+*/
+       bp = buf + 1;
+       cataddr(pvp, NULL, bp, sizeof buf - 2, '\0');
+       if (*bp == '@' && !bitnset(M_NOBRACKET, e->e_from.q_mailer->m_flags))
+       {
+               /* heuristic: route-addr: add angle brackets */
+               strcat(bp, ">");
+               *--bp = '<';
+       }
+       e->e_sender = newstr(bp);
        define('f', e->e_sender, e);
 
        /* save the domain spec if this mailer wants it */
        define('f', e->e_sender, e);
 
        /* save the domain spec if this mailer wants it */
@@ -602,28 +808,66 @@ setsender(from, e)
        }
 }
 \f/*
        }
 }
 \f/*
-**  TRUSTEDUSER -- tell us if this user is to be trusted.
+**  PRINTENVFLAGS -- print envelope flags for debugging
 **
 **     Parameters:
 **
 **     Parameters:
-**             user -- the user to be checked.
+**             e -- the envelope with the flags to be printed.
 **
 **     Returns:
 **
 **     Returns:
-**             TRUE if the user is in an approved list.
-**             FALSE otherwise.
-**
-**     Side Effects:
 **             none.
 */
 
 **             none.
 */
 
-bool
-trusteduser(user)
-       char *user;
+struct eflags
 {
 {
-       register char **ulist;
-       extern char *TrustedUsers[];
+       char    *ef_name;
+       u_long  ef_bit;
+};
 
 
-       for (ulist = TrustedUsers; *ulist != NULL; ulist++)
-               if (strcmp(*ulist, user) == 0)
-                       return (TRUE);
-       return (FALSE);
+struct eflags  EnvelopeFlags[] =
+{
+       "OLDSTYLE",     EF_OLDSTYLE,
+       "INQUEUE",      EF_INQUEUE,
+       "NO_BODY_RETN", EF_NO_BODY_RETN,
+       "CLRQUEUE",     EF_CLRQUEUE,
+       "SENDRECEIPT",  EF_SENDRECEIPT,
+       "FATALERRS",    EF_FATALERRS,
+       "KEEPQUEUE",    EF_KEEPQUEUE,
+       "RESPONSE",     EF_RESPONSE,
+       "RESENT",       EF_RESENT,
+       "VRFYONLY",     EF_VRFYONLY,
+       "WARNING",      EF_WARNING,
+       "QUEUERUN",     EF_QUEUERUN,
+       "GLOBALERRS",   EF_GLOBALERRS,
+       "PM_NOTIFY",    EF_PM_NOTIFY,
+       "METOO",        EF_METOO,
+       "LOGSENDER",    EF_LOGSENDER,
+       "NORECEIPT",    EF_NORECEIPT,
+       "HAS8BIT",      EF_HAS8BIT,
+       "NL_NOT_EOL",   EF_NL_NOT_EOL,
+       "CRLF_NOT_EOL", EF_CRLF_NOT_EOL,
+       "RET_PARAM",    EF_RET_PARAM,
+       "HAS_DF",       EF_HAS_DF,
+       NULL
+};
+
+void
+printenvflags(e)
+       register ENVELOPE *e;
+{
+       register struct eflags *ef;
+       bool first = TRUE;
+
+       printf("%lx", e->e_flags);
+       for (ef = EnvelopeFlags; ef->ef_name != NULL; ef++)
+       {
+               if (!bitset(ef->ef_bit, e->e_flags))
+                       continue;
+               if (first)
+                       printf("<%s", ef->ef_name);
+               else
+                       printf(",%s", ef->ef_name);
+               first = FALSE;
+       }
+       if (!first)
+               printf(">\n");
 }
 }