BSD 4_4_Lite2 release
[unix-history] / usr / src / usr.sbin / sendmail / src / deliver.c
index 4266122..88286d0 100644 (file)
@@ -1,5 +1,5 @@
 /*
 /*
- * Copyright (c) 1983 Eric P. Allman
+ * Copyright (c) 1983, 1995 Eric P. Allman
  * Copyright (c) 1988, 1993
  *     The Regents of the University of California.  All rights reserved.
  *
  * Copyright (c) 1988, 1993
  *     The Regents of the University of California.  All rights reserved.
  *
  */
 
 #ifndef lint
  */
 
 #ifndef lint
-static char sccsid[] = "@(#)deliver.c  8.82 (Berkeley) 4/18/94";
+static char sccsid[] = "@(#)deliver.c  8.160 (Berkeley) 6/21/95";
 #endif /* not lint */
 
 #include "sendmail.h"
 #endif /* not lint */
 
 #include "sendmail.h"
-#include <netdb.h>
 #include <errno.h>
 #if NAMED_BIND
 #include <errno.h>
 #if NAMED_BIND
-#include <arpa/nameser.h>
 #include <resolv.h>
 
 extern int     h_errno;
 #include <resolv.h>
 
 extern int     h_errno;
@@ -66,6 +64,7 @@ extern char   SmtpError[];
 **                     appropriate action.
 */
 
 **                     appropriate action.
 */
 
+void
 sendall(e, mode)
        ENVELOPE *e;
        char mode;
 sendall(e, mode)
        ENVELOPE *e;
        char mode;
@@ -75,7 +74,10 @@ sendall(e, mode)
        int otherowners;
        register ENVELOPE *ee;
        ENVELOPE *splitenv = NULL;
        int otherowners;
        register ENVELOPE *ee;
        ENVELOPE *splitenv = NULL;
-       bool announcequeueup;
+       bool oldverbose = Verbose;
+       bool somedeliveries = FALSE;
+       int pid;
+       extern void sendenvelope();
 
        /*
        **  If we have had global, fatal errors, don't bother sending
 
        /*
        **  If we have had global, fatal errors, don't bother sending
@@ -99,16 +101,17 @@ sendall(e, mode)
                if (mode != SM_VERIFY &&
                    shouldqueue(e->e_msgpriority, e->e_ctime))
                        mode = SM_QUEUE;
                if (mode != SM_VERIFY &&
                    shouldqueue(e->e_msgpriority, e->e_ctime))
                        mode = SM_QUEUE;
-               announcequeueup = mode == SM_QUEUE;
        }
        }
-       else
-               announcequeueup = FALSE;
 
        if (tTd(13, 1))
        {
 
        if (tTd(13, 1))
        {
+               extern void printenvflags();
+
                printf("\n===== SENDALL: mode %c, id %s, e_from ",
                        mode, e->e_id);
                printaddr(&e->e_from, FALSE);
                printf("\n===== SENDALL: mode %c, id %s, e_from ",
                        mode, e->e_id);
                printaddr(&e->e_from, FALSE);
+               printf("\te_flags = ");
+               printenvflags(e);
                printf("sendqueue:\n");
                printaddr(e->e_sendqueue, TRUE);
        }
                printf("sendqueue:\n");
                printaddr(e->e_sendqueue, TRUE);
        }
@@ -124,11 +127,13 @@ sendall(e, mode)
        if (e->e_hopcount > MaxHopCount)
        {
                errno = 0;
        if (e->e_hopcount > MaxHopCount)
        {
                errno = 0;
+               queueup(e, TRUE, mode == SM_QUEUE);
                e->e_flags |= EF_FATALERRS|EF_PM_NOTIFY|EF_CLRQUEUE;
                e->e_flags |= EF_FATALERRS|EF_PM_NOTIFY|EF_CLRQUEUE;
-               syserr("554 too many hops %d (%d max): from %s via %s, to %s",
+               syserr("554 Too many hops %d (%d max): from %s via %s, to %s",
                        e->e_hopcount, MaxHopCount, e->e_from.q_paddr,
                        RealHostName == NULL ? "localhost" : RealHostName,
                        e->e_sendqueue->q_paddr);
                        e->e_hopcount, MaxHopCount, e->e_from.q_paddr,
                        RealHostName == NULL ? "localhost" : RealHostName,
                        e->e_sendqueue->q_paddr);
+               e->e_sendqueue->q_status = "5.4.6";
                return;
        }
 
                return;
        }
 
@@ -150,7 +155,7 @@ sendall(e, mode)
                        printaddr(&e->e_from, FALSE);
                }
                e->e_from.q_flags |= QDONTSEND;
                        printaddr(&e->e_from, FALSE);
                }
                e->e_from.q_flags |= QDONTSEND;
-               (void) recipient(&e->e_from, &e->e_sendqueue, e);
+               (void) recipient(&e->e_from, &e->e_sendqueue, 0, e);
        }
 
        /*
        }
 
        /*
@@ -209,6 +214,34 @@ sendall(e, mode)
                        {
                                otherowners++;
                        }
                        {
                                otherowners++;
                        }
+
+                       /*
+                       **  If this mailer is expensive, and if we don't
+                       **  want to make connections now, just mark these
+                       **  addresses and return.  This is useful if we
+                       **  want to batch connections to reduce load.  This
+                       **  will cause the messages to be queued up, and a
+                       **  daemon will come along to send the messages later.
+                       */
+
+                       if (bitset(QBADADDR|QQUEUEUP, q->q_flags))
+                               continue;
+                       if (NoConnect && !Verbose &&
+                           bitnset(M_EXPENSIVE, q->q_mailer->m_flags))
+                       {
+                               q->q_flags |= QQUEUEUP;
+                               e->e_to = q->q_paddr;
+                               message("queued");
+                               if (LogLevel > 8)
+                                       logdelivery(q->q_mailer, NULL,
+                                                   "queued", NULL,
+                                                   (time_t) 0, e);
+                               e->e_to = NULL;
+                       }
+                       else
+                       {
+                               somedeliveries = TRUE;
+                       }
                }
 
                if (owner != NULL && otherowners > 0)
                }
 
                if (owner != NULL && otherowners > 0)
@@ -232,7 +265,7 @@ sendall(e, mode)
                        ee->e_header = copyheader(e->e_header);
                        ee->e_sendqueue = copyqueue(e->e_sendqueue);
                        ee->e_errorqueue = copyqueue(e->e_errorqueue);
                        ee->e_header = copyheader(e->e_header);
                        ee->e_sendqueue = copyqueue(e->e_sendqueue);
                        ee->e_errorqueue = copyqueue(e->e_errorqueue);
-                       ee->e_flags = e->e_flags & ~(EF_INQUEUE|EF_CLRQUEUE|EF_FATALERRS|EF_SENDRECEIPT);
+                       ee->e_flags = e->e_flags & ~(EF_INQUEUE|EF_CLRQUEUE|EF_FATALERRS|EF_SENDRECEIPT|EF_RET_PARAM);
                        ee->e_flags |= EF_NORECEIPT;
                        setsender(owner, ee, NULL, TRUE);
                        if (tTd(13, 5))
                        ee->e_flags |= EF_NORECEIPT;
                        setsender(owner, ee, NULL, TRUE);
                        if (tTd(13, 5))
@@ -243,33 +276,44 @@ sendall(e, mode)
                        ee->e_from.q_flags |= QDONTSEND;
                        ee->e_dfp = NULL;
                        ee->e_xfp = NULL;
                        ee->e_from.q_flags |= QDONTSEND;
                        ee->e_dfp = NULL;
                        ee->e_xfp = NULL;
-                       ee->e_df = NULL;
                        ee->e_errormode = EM_MAIL;
                        ee->e_sibling = splitenv;
                        splitenv = ee;
                        
                        for (q = e->e_sendqueue; q != NULL; q = q->q_next)
                        ee->e_errormode = EM_MAIL;
                        ee->e_sibling = splitenv;
                        splitenv = ee;
                        
                        for (q = e->e_sendqueue; q != NULL; q = q->q_next)
+                       {
                                if (q->q_owner == owner)
                                {
                                        q->q_flags |= QDONTSEND;
                                        q->q_flags &= ~QQUEUEUP;
                                }
                                if (q->q_owner == owner)
                                {
                                        q->q_flags |= QDONTSEND;
                                        q->q_flags &= ~QQUEUEUP;
                                }
+                       }
                        for (q = ee->e_sendqueue; q != NULL; q = q->q_next)
                        for (q = ee->e_sendqueue; q != NULL; q = q->q_next)
+                       {
                                if (q->q_owner != owner)
                                {
                                        q->q_flags |= QDONTSEND;
                                        q->q_flags &= ~QQUEUEUP;
                                }
                                if (q->q_owner != owner)
                                {
                                        q->q_flags |= QDONTSEND;
                                        q->q_flags &= ~QQUEUEUP;
                                }
+                               else
+                               {
+                                       /* clear DSN parameters */
+                                       q->q_flags &= ~(QHASNOTIFY|QPINGONSUCCESS);
+                                       q->q_flags |= QPINGONFAILURE|QPINGONDELAY;
+                               }
+                       }
 
 
-                       if (e->e_df != NULL && mode != SM_VERIFY)
+                       if (mode != SM_VERIFY && bitset(EF_HAS_DF, e->e_flags))
                        {
                        {
+                               char df1buf[20], df2buf[20];
+
                                ee->e_dfp = NULL;
                                ee->e_dfp = NULL;
-                               ee->e_df = queuename(ee, 'd');
-                               ee->e_df = newstr(ee->e_df);
-                               if (link(e->e_df, ee->e_df) < 0)
+                               strcpy(df1buf, queuename(e, 'd'));
+                               strcpy(df2buf, queuename(ee, 'd'));
+                               if (link(df1buf, df2buf) < 0)
                                {
                                        syserr("sendall: link(%s, %s)",
                                {
                                        syserr("sendall: link(%s, %s)",
-                                               e->e_df, ee->e_df);
+                                               df1buf, df2buf);
                                }
                        }
 #ifdef LOG
                                }
                        }
 #ifdef LOG
@@ -293,65 +337,26 @@ sendall(e, mode)
                e->e_flags |= EF_NORECEIPT;
        }
 
                e->e_flags |= EF_NORECEIPT;
        }
 
+       /* if nothing to be delivered, just queue up everything */
+       if (!somedeliveries && mode != SM_QUEUE && mode != SM_VERIFY)
+               mode = SM_QUEUE;
+
 # ifdef QUEUE
        if ((mode == SM_QUEUE || mode == SM_FORK ||
             (mode != SM_VERIFY && SuperSafe)) &&
            !bitset(EF_INQUEUE, e->e_flags))
        {
                /* be sure everything is instantiated in the queue */
 # ifdef QUEUE
        if ((mode == SM_QUEUE || mode == SM_FORK ||
             (mode != SM_VERIFY && SuperSafe)) &&
            !bitset(EF_INQUEUE, e->e_flags))
        {
                /* be sure everything is instantiated in the queue */
-               queueup(e, TRUE, announcequeueup);
+               queueup(e, TRUE, mode == SM_QUEUE);
                for (ee = splitenv; ee != NULL; ee = ee->e_sibling)
                for (ee = splitenv; ee != NULL; ee = ee->e_sibling)
-                       queueup(ee, TRUE, announcequeueup);
+                       queueup(ee, TRUE, mode == SM_QUEUE);
        }
 #endif /* QUEUE */
 
        }
 #endif /* QUEUE */
 
-       if (splitenv != NULL)
-       {
-               if (tTd(13, 1))
-               {
-                       printf("\nsendall: Split queue; remaining queue:\n");
-                       printaddr(e->e_sendqueue, TRUE);
-               }
-
-               for (ee = splitenv; ee != NULL; ee = ee->e_sibling)
-               {
-                       CurEnv = ee;
-                       if (mode != SM_VERIFY)
-                               openxscript(ee);
-                       sendenvelope(ee, mode);
-                       dropenvelope(ee);
-               }
-
-               CurEnv = e;
-       }
-       sendenvelope(e, mode);
-}
-
-sendenvelope(e, mode)
-       register ENVELOPE *e;
-       char mode;
-{
-       bool oldverbose;
-       int pid;
-       register ADDRESS *q;
-       char *qf;
-       char *id;
-
        /*
        /*
-       **  If we have had global, fatal errors, don't bother sending
-       **  the message at all if we are in SMTP mode.  Local errors
-       **  (e.g., a single address failing) will still cause the other
-       **  addresses to be sent.
+       **  If we belong in background, fork now.
        */
 
        */
 
-       if (bitset(EF_FATALERRS, e->e_flags) &&
-           (OpMode == MD_SMTP || OpMode == MD_DAEMON))
-       {
-               e->e_flags |= EF_CLRQUEUE;
-               return;
-       }
-
-       oldverbose = Verbose;
        switch (mode)
        {
          case SM_VERIFY:
        switch (mode)
        {
          case SM_VERIFY:
@@ -360,7 +365,8 @@ sendenvelope(e, mode)
 
          case SM_QUEUE:
   queueonly:
 
          case SM_QUEUE:
   queueonly:
-               e->e_flags |= EF_INQUEUE|EF_KEEPQUEUE;
+               if (e->e_nrcpts > 0)
+                       e->e_flags |= EF_INQUEUE|EF_KEEPQUEUE;
                return;
 
          case SM_FORK:
                return;
 
          case SM_FORK:
@@ -375,15 +381,17 @@ sendenvelope(e, mode)
                **  then restart from scratch in the child.
                */
 
                **  then restart from scratch in the child.
                */
 
-               /* save id for future use */
-               id = e->e_id;
+               {
+                       /* save id for future use */
+                       char *qid = e->e_id;
 
 
-               /* now drop the envelope in the parent */
-               e->e_flags |= EF_INQUEUE|EF_KEEPQUEUE;
-               dropenvelope(e);
+                       /* now drop the envelope in the parent */
+                       e->e_flags |= EF_INQUEUE|EF_KEEPQUEUE;
+                       dropenvelope(e);
 
 
-               /* and reacquire in the child */
-               (void) dowork(id, TRUE, FALSE, e);
+                       /* and reacquire in the child */
+                       (void) dowork(qid, TRUE, FALSE, e);
+               }
 
                return;
 
 
                return;
 
@@ -399,15 +407,16 @@ sendenvelope(e, mode)
                        /* be sure we leave the temp files to our child */
                        /* can't call unlockqueue to avoid unlink of xfp */
                        if (e->e_lockfp != NULL)
                        /* be sure we leave the temp files to our child */
                        /* can't call unlockqueue to avoid unlink of xfp */
                        if (e->e_lockfp != NULL)
-                               (void) xfclose(e->e_lockfp, "sendenvelope", "lockfp");
+                               (void) xfclose(e->e_lockfp, "sendenvelope lockfp", e->e_id);
                        e->e_lockfp = NULL;
 
                        /* close any random open files in the envelope */
                        closexscript(e);
                        if (e->e_dfp != NULL)
                        e->e_lockfp = NULL;
 
                        /* close any random open files in the envelope */
                        closexscript(e);
                        if (e->e_dfp != NULL)
-                               (void) xfclose(e->e_dfp, "sendenvelope", e->e_df);
+                               (void) xfclose(e->e_dfp, "sendenvelope dfp", e->e_id);
                        e->e_dfp = NULL;
                        e->e_dfp = NULL;
-                       e->e_id = e->e_df = NULL;
+                       e->e_id = NULL;
+                       e->e_flags &= ~EF_HAS_DF;
 
                        /* catch intermediate zombie */
                        (void) waitfor(pid);
 
                        /* catch intermediate zombie */
                        (void) waitfor(pid);
@@ -446,6 +455,51 @@ sendenvelope(e, mode)
                break;
        }
 
                break;
        }
 
+       if (splitenv != NULL)
+       {
+               if (tTd(13, 1))
+               {
+                       printf("\nsendall: Split queue; remaining queue:\n");
+                       printaddr(e->e_sendqueue, TRUE);
+               }
+
+               for (ee = splitenv; ee != NULL; ee = ee->e_sibling)
+               {
+                       CurEnv = ee;
+                       if (mode != SM_VERIFY)
+                               openxscript(ee);
+                       sendenvelope(ee, mode);
+                       dropenvelope(ee);
+               }
+
+               CurEnv = e;
+       }
+       sendenvelope(e, mode);
+       Verbose = oldverbose;
+}
+
+void
+sendenvelope(e, mode)
+       register ENVELOPE *e;
+       char mode;
+{
+       register ADDRESS *q;
+       bool didany;
+
+       /*
+       **  If we have had global, fatal errors, don't bother sending
+       **  the message at all if we are in SMTP mode.  Local errors
+       **  (e.g., a single address failing) will still cause the other
+       **  addresses to be sent.
+       */
+
+       if (bitset(EF_FATALERRS, e->e_flags) &&
+           (OpMode == MD_SMTP || OpMode == MD_DAEMON))
+       {
+               e->e_flags |= EF_CLRQUEUE;
+               return;
+       }
+
        /*
        **  Run through the list and send everything.
        **
        /*
        **  Run through the list and send everything.
        **
@@ -455,11 +509,12 @@ sendenvelope(e, mode)
 
        e->e_nsent = 0;
        e->e_flags |= EF_GLOBALERRS;
 
        e->e_nsent = 0;
        e->e_flags |= EF_GLOBALERRS;
+       didany = FALSE;
 
        /* now run through the queue */
        for (q = e->e_sendqueue; q != NULL; q = q->q_next)
        {
 
        /* now run through the queue */
        for (q = e->e_sendqueue; q != NULL; q = q->q_next)
        {
-#ifdef XDEBUG
+#if XDEBUG
                char wbuf[MAXNAME + 20];
 
                (void) sprintf(wbuf, "sendall(%s)", q->q_paddr);
                char wbuf[MAXNAME + 20];
 
                (void) sprintf(wbuf, "sendall(%s)", q->q_paddr);
@@ -495,11 +550,16 @@ sendenvelope(e, mode)
                        }
 # endif /* QUEUE */
                        (void) deliver(e, q);
                        }
 # endif /* QUEUE */
                        (void) deliver(e, q);
+                       didany = TRUE;
                }
        }
                }
        }
-       Verbose = oldverbose;
+       if (didany)
+       {
+               e->e_dtime = curtime();
+               e->e_ntries++;
+       }
 
 
-#ifdef XDEBUG
+#if XDEBUG
        checkfd012("end of sendenvelope");
 #endif
 
        checkfd012("end of sendenvelope");
 #endif
 
@@ -562,9 +622,10 @@ sendenvelope(e, mode)
 **             returns twice, once in parent and once in child.
 */
 
 **             returns twice, once in parent and once in child.
 */
 
+int
 dofork()
 {
 dofork()
 {
-       register int pid;
+       register int pid = -1;
 
        DOFORK(fork);
        return (pid);
 
        DOFORK(fork);
        return (pid);
@@ -591,6 +652,7 @@ dofork()
 **             The standard input is passed off to someone.
 */
 
 **             The standard input is passed off to someone.
 */
 
+int
 deliver(e, firstto)
        register ENVELOPE *e;
        ADDRESS *firstto;
 deliver(e, firstto)
        register ENVELOPE *e;
        ADDRESS *firstto;
@@ -605,18 +667,20 @@ deliver(e, firstto)
        register MCI *mci;
        register ADDRESS *to = firstto;
        bool clever = FALSE;            /* running user smtp to this mailer */
        register MCI *mci;
        register ADDRESS *to = firstto;
        bool clever = FALSE;            /* running user smtp to this mailer */
-       ADDRESS *tochain = NULL;        /* chain of users in this mailer call */
+       ADDRESS *tochain = NULL;        /* users chain in this mailer call */
        int rcode;                      /* response code */
        char *firstsig;                 /* signature of firstto */
        int rcode;                      /* response code */
        char *firstsig;                 /* signature of firstto */
-       int pid;
+       int pid = -1;
        char *curhost;
        char *curhost;
+       time_t xstart;
        int mpvect[2];
        int rpvect[2];
        char *pv[MAXPV+1];
        char tobuf[TOBUFSIZE];          /* text line of to people */
        int mpvect[2];
        int rpvect[2];
        char *pv[MAXPV+1];
        char tobuf[TOBUFSIZE];          /* text line of to people */
-       char buf[MAXNAME];
-       char rpathbuf[MAXNAME];         /* translated return path */
+       char buf[MAXNAME + 1];
+       char rpathbuf[MAXNAME + 1];     /* translated return path */
        extern int checkcompat();
        extern int checkcompat();
+       extern void markfailure __P((ENVELOPE *, ADDRESS *, MCI *, int));
 
        errno = 0;
        if (bitset(QDONTSEND|QBADADDR|QQUEUEUP, to->q_flags))
 
        errno = 0;
        if (bitset(QDONTSEND|QBADADDR|QQUEUEUP, to->q_flags))
@@ -636,6 +700,7 @@ deliver(e, firstto)
        CurEnv = e;                     /* just in case */
        e->e_statmsg = NULL;
        SmtpError[0] = '\0';
        CurEnv = e;                     /* just in case */
        e->e_statmsg = NULL;
        SmtpError[0] = '\0';
+       xstart = curtime();
 
        if (tTd(10, 1))
                printf("\n--deliver, id=%s, mailer=%s, host=`%s', first user=`%s'\n",
 
        if (tTd(10, 1))
                printf("\n--deliver, id=%s, mailer=%s, host=`%s', first user=`%s'\n",
@@ -643,33 +708,6 @@ deliver(e, firstto)
        if (tTd(10, 100))
                printopenfds(FALSE);
 
        if (tTd(10, 100))
                printopenfds(FALSE);
 
-       /*
-       **  If this mailer is expensive, and if we don't want to make
-       **  connections now, just mark these addresses and return.
-       **      This is useful if we want to batch connections to
-       **      reduce load.  This will cause the messages to be
-       **      queued up, and a daemon will come along to send the
-       **      messages later.
-       **              This should be on a per-mailer basis.
-       */
-
-       if (NoConnect && bitnset(M_EXPENSIVE, m->m_flags) && !Verbose)
-       {
-               for (; to != NULL; to = to->q_next)
-               {
-                       if (bitset(QDONTSEND|QBADADDR|QQUEUEUP, to->q_flags) ||
-                           to->q_mailer != m)
-                               continue;
-                       to->q_flags |= QQUEUEUP;
-                       e->e_to = to->q_paddr;
-                       message("queued");
-                       if (LogLevel > 8)
-                               logdelivery(m, NULL, "queued", NULL, e);
-               }
-               e->e_to = NULL;
-               return (0);
-       }
-
        /*
        **  Do initial argv setup.
        **      Insert the mailer name.  Notice that $x expansion is
        /*
        **  Do initial argv setup.
        **      Insert the mailer name.  Notice that $x expansion is
@@ -683,7 +721,11 @@ deliver(e, firstto)
 
        /* rewrite from address, using rewriting rules */
        rcode = EX_OK;
 
        /* rewrite from address, using rewriting rules */
        rcode = EX_OK;
-       (void) strcpy(rpathbuf, remotename(e->e_from.q_paddr, m,
+       if (bitnset(M_UDBENVELOPE, e->e_from.q_mailer->m_flags))
+               p = e->e_sender;
+       else
+               p = e->e_from.q_paddr;
+       (void) strcpy(rpathbuf, remotename(p, m,
                                           RF_SENDERADDR|RF_CANONICAL,
                                           &rcode, e));
        define('g', rpathbuf, e);               /* translated return path */
                                           RF_SENDERADDR|RF_CANONICAL,
                                           &rcode, e));
        define('g', rpathbuf, e);               /* translated return path */
@@ -725,7 +767,7 @@ deliver(e, firstto)
                        break;
 
                /* this entry is safe -- go ahead and process it */
                        break;
 
                /* this entry is safe -- go ahead and process it */
-               expand(*mvp, buf, &buf[sizeof buf - 1], e);
+               expand(*mvp, buf, sizeof buf, e);
                *pvp++ = newstr(buf);
                if (pvp >= &pv[MAXPV - 3])
                {
                *pvp++ = newstr(buf);
                if (pvp >= &pv[MAXPV - 3])
                {
@@ -787,11 +829,15 @@ deliver(e, firstto)
                }
 
                /* compute effective uid/gid when sending */
                }
 
                /* compute effective uid/gid when sending */
-               /* XXX perhaps this should be to->q_mailer != LocalMailer ?? */
-               /* XXX perhaps it should be a mailer flag? */
-               if (to->q_mailer == ProgMailer || to->q_mailer == FileMailer)
+               if (bitnset(M_RUNASRCPT, to->q_mailer->m_flags))
                        ctladdr = getctladdr(to);
 
                        ctladdr = getctladdr(to);
 
+               if (tTd(10, 2))
+               {
+                       printf("ctladdr=");
+                       printaddr(ctladdr, FALSE);
+               }
+
                user = to->q_user;
                e->e_to = to->q_paddr;
                if (tTd(10, 5))
                user = to->q_user;
                e->e_to = to->q_paddr;
                if (tTd(10, 5))
@@ -808,16 +854,20 @@ deliver(e, firstto)
 
                if (m->m_maxsize != 0 && e->e_msgsize > m->m_maxsize)
                {
 
                if (m->m_maxsize != 0 && e->e_msgsize > m->m_maxsize)
                {
-                       NoReturn = TRUE;
+                       e->e_flags |= EF_NO_BODY_RETN;
+                       to->q_status = "5.2.3";
                        usrerr("552 Message is too large; %ld bytes max", m->m_maxsize);
                        usrerr("552 Message is too large; %ld bytes max", m->m_maxsize);
-                       giveresponse(EX_UNAVAILABLE, m, NULL, ctladdr, e);
+                       giveresponse(EX_UNAVAILABLE, m, NULL, ctladdr, xstart, e);
                        continue;
                }
                        continue;
                }
+#if NAMED_BIND
+               h_errno = 0;
+#endif
                rcode = checkcompat(to, e);
                if (rcode != EX_OK)
                {
                rcode = checkcompat(to, e);
                if (rcode != EX_OK)
                {
-                       markfailure(e, to, rcode);
-                       giveresponse(rcode, m, NULL, ctladdr, e);
+                       markfailure(e, to, NULL, rcode);
+                       giveresponse(rcode, m, NULL, ctladdr, xstart, e);
                        continue;
                }
 
                        continue;
                }
 
@@ -859,12 +909,25 @@ deliver(e, firstto)
                **      with the others, so we fudge on the To person.
                */
 
                **      with the others, so we fudge on the To person.
                */
 
-               if (m == FileMailer)
+               if (strcmp(m->m_mailer, "[FILE]") == 0)
                {
                {
-                       rcode = mailfile(user, ctladdr, e);
-                       giveresponse(rcode, m, NULL, ctladdr, e);
+                       rcode = mailfile(user, ctladdr, SFF_CREAT, e);
+                       giveresponse(rcode, m, NULL, ctladdr, xstart, e);
+                       e->e_nsent++;
                        if (rcode == EX_OK)
                        if (rcode == EX_OK)
+                       {
                                to->q_flags |= QSENT;
                                to->q_flags |= QSENT;
+                               if (bitnset(M_LOCALMAILER, m->m_flags) &&
+                                   (e->e_receiptto != NULL ||
+                                    bitset(QPINGONSUCCESS, to->q_flags)))
+                               {
+                                       to->q_flags |= QDELIVERED;
+                                       to->q_status = "2.1.5";
+                                       fprintf(e->e_xfp, "%s... Successfully delivered\n",
+                                               to->q_paddr);
+                               }
+                       }
+                       to->q_statdate = curtime();
                        continue;
                }
 
                        continue;
                }
 
@@ -892,7 +955,7 @@ deliver(e, firstto)
 
                if (!clever)
                {
 
                if (!clever)
                {
-                       expand(*mvp, buf, &buf[sizeof buf - 1], e);
+                       expand(*mvp, buf, sizeof buf, e);
                        *pvp++ = newstr(buf);
                        if (pvp >= &pv[MAXPV - 2])
                        {
                        *pvp++ = newstr(buf);
                        if (pvp >= &pv[MAXPV - 2])
                        {
@@ -918,7 +981,7 @@ deliver(e, firstto)
 
        while (!clever && *++mvp != NULL)
        {
 
        while (!clever && *++mvp != NULL)
        {
-               expand(*mvp, buf, &buf[sizeof buf - 1], e);
+               expand(*mvp, buf, sizeof buf, e);
                *pvp++ = newstr(buf);
                if (pvp >= &pv[MAXPV])
                        syserr("554 deliver: pv overflow after $u for %s", pv[0]);
                *pvp++ = newstr(buf);
                if (pvp >= &pv[MAXPV])
                        syserr("554 deliver: pv overflow after $u for %s", pv[0]);
@@ -934,7 +997,7 @@ deliver(e, firstto)
        */
 
        /*XXX this seems a bit wierd */
        */
 
        /*XXX this seems a bit wierd */
-       if (ctladdr == NULL && m != ProgMailer &&
+       if (ctladdr == NULL && m != ProgMailer && m != FileMailer &&
            bitset(QGOODUID, e->e_from.q_flags))
                ctladdr = &e->e_from;
 
            bitset(QGOODUID, e->e_from.q_flags))
                ctladdr = &e->e_from;
 
@@ -949,8 +1012,11 @@ deliver(e, firstto)
                printav(pv);
        }
        errno = 0;
                printav(pv);
        }
        errno = 0;
+#if NAMED_BIND
+       h_errno = 0;
+#endif
 
 
-       CurHostName = m->m_mailer;
+       CurHostName = NULL;
 
        /*
        **  Deal with the special case of mail handled through an IPC
 
        /*
        **  Deal with the special case of mail handled through an IPC
@@ -965,7 +1031,7 @@ deliver(e, firstto)
        SmtpPhase = NULL;
        mci = NULL;
 
        SmtpPhase = NULL;
        mci = NULL;
 
-#ifdef XDEBUG
+#if XDEBUG
        {
                char wbuf[MAXLINE];
 
        {
                char wbuf[MAXLINE];
 
@@ -975,6 +1041,18 @@ deliver(e, firstto)
        }
 #endif
 
        }
 #endif
 
+       /* check for 8-bit available */
+       if (bitset(EF_HAS8BIT, e->e_flags) &&
+           bitnset(M_7BITS, m->m_flags) &&
+           (!bitset(MM_MIME8BIT, MimeMode) ||
+            bitset(EF_DONT_MIME, e->e_flags)))
+       {
+               usrerr("554 Cannot send 8-bit data to 7-bit destination");
+               rcode = EX_DATAERR;
+               e->e_status = "5.6.3";
+               goto give_up;
+       }
+
        /* check for Local Person Communication -- not for mortals!!! */
        if (strcmp(m->m_mailer, "[LPC]") == 0)
        {
        /* check for Local Person Communication -- not for mortals!!! */
        if (strcmp(m->m_mailer, "[LPC]") == 0)
        {
@@ -990,7 +1068,7 @@ deliver(e, firstto)
        {
 #ifdef DAEMON
                register int i;
        {
 #ifdef DAEMON
                register int i;
-               register u_short port;
+               register u_short port = 0;
 
                if (pv[0] == NULL || pv[1] == NULL || pv[1][0] == '\0')
                {
 
                if (pv[0] == NULL || pv[1] == NULL || pv[1][0] == '\0')
                {
@@ -1005,7 +1083,7 @@ deliver(e, firstto)
                if (curhost == NULL || curhost[0] == '\0')
                {
                        syserr("null host signature for %s", pv[1]);
                if (curhost == NULL || curhost[0] == '\0')
                {
                        syserr("null host signature for %s", pv[1]);
-                       rcode = EX_OSERR;
+                       rcode = EX_CONFIG;
                        goto give_up;
                }
 
                        goto give_up;
                }
 
@@ -1016,14 +1094,23 @@ deliver(e, firstto)
                        goto give_up;
                }
                if (pv[2] != NULL)
                        goto give_up;
                }
                if (pv[2] != NULL)
-                       port = atoi(pv[2]);
-               else
-                       port = 0;
+               {
+                       port = htons(atoi(pv[2]));
+                       if (port == 0)
+                       {
+                               struct servent *sp = getservbyname(pv[2], "tcp");
+
+                               if (sp == NULL)
+                                       syserr("Service %s unknown", pv[2]);
+                               else
+                                       port = sp->s_port;
+                       }
+               }
 tryhost:
                while (*curhost != '\0')
                {
                        register char *p;
 tryhost:
                while (*curhost != '\0')
                {
                        register char *p;
-                       static char hostbuf[MAXNAME];
+                       static char hostbuf[MAXNAME + 1];
 
                        /* pull the next host from the signature */
                        p = strchr(curhost, ':');
 
                        /* pull the next host from the signature */
                        p = strchr(curhost, ':');
@@ -1052,6 +1139,8 @@ tryhost:
                                        mci_dump(mci, FALSE);
                                }
                                CurHostName = mci->mci_host;
                                        mci_dump(mci, FALSE);
                                }
                                CurHostName = mci->mci_host;
+                               message("Using cached connection to %s via %s...",
+                                       hostbuf, m->m_name);
                                break;
                        }
                        mci->mci_mailer = m;
                                break;
                        }
                        mci->mci_mailer = m;
@@ -1060,7 +1149,7 @@ tryhost:
 
                        /* try the connection */
                        setproctitle("%s %s: %s", e->e_id, hostbuf, "user open");
 
                        /* try the connection */
                        setproctitle("%s %s: %s", e->e_id, hostbuf, "user open");
-                       message("Connecting to %s (%s)...",
+                       message("Connecting to %s via %s...",
                                hostbuf, m->m_name);
                        i = makeconnection(hostbuf, port, mci,
                                bitnset(M_SECURE_PORT, m->m_flags));
                                hostbuf, m->m_name);
                        i = makeconnection(hostbuf, port, mci,
                                bitnset(M_SECURE_PORT, m->m_flags));
@@ -1104,6 +1193,14 @@ tryhost:
        }
        else
        {
        }
        else
        {
+               /* flush any expired connections */
+               (void) mci_scan(NULL);
+
+               /* announce the connection to verbose listeners */
+               if (host == NULL || host[0] == '\0')
+                       message("Connecting to %s...", m->m_name);
+               else
+                       message("Connecting to %s via %s...", host, m->m_name);
                if (TrafficLogFile != NULL)
                {
                        char **av;
                if (TrafficLogFile != NULL)
                {
                        char **av;
@@ -1175,33 +1272,59 @@ tryhost:
                {
                        int i;
                        int saveerrno;
                {
                        int i;
                        int saveerrno;
-                       char **ep;
-                       char *env[MAXUSERENVIRON];
-                       extern char **environ;
+                       struct stat stb;
                        extern int DtableSize;
 
                        extern int DtableSize;
 
+                       if (e->e_lockfp != NULL)
+                               (void) close(fileno(e->e_lockfp));
+
                        /* child -- set up input & exec mailer */
                        (void) setsignal(SIGINT, SIG_IGN);
                        (void) setsignal(SIGHUP, SIG_IGN);
                        (void) setsignal(SIGTERM, SIG_DFL);
 
                        /* child -- set up input & exec mailer */
                        (void) setsignal(SIGINT, SIG_IGN);
                        (void) setsignal(SIGHUP, SIG_IGN);
                        (void) setsignal(SIGTERM, SIG_DFL);
 
-                       /* reset user and group */
-                       if (!bitnset(M_RESTR, m->m_flags))
+                       if (m != FileMailer || stat(tochain->q_user, &stb) < 0)
+                               stb.st_mode = 0;
+
+                       /* tweak niceness */
+                       if (m->m_nice != 0)
+                               nice(m->m_nice);
+
+                       /* reset group id */
+                       if (bitnset(M_SPECIFIC_UID, m->m_flags))
+                               (void) setgid(m->m_gid);
+                       else if (bitset(S_ISGID, stb.st_mode))
+                               (void) setgid(stb.st_gid);
+                       else if (ctladdr != NULL && ctladdr->q_gid != 0)
                        {
                        {
-                               if (ctladdr == NULL || ctladdr->q_uid == 0)
-                               {
-                                       (void) initgroups(DefUser, DefGid);
+                               (void) initgroups(ctladdr->q_ruser?
+                                       ctladdr->q_ruser: ctladdr->q_user,
+                                       ctladdr->q_gid);
+                               (void) setgid(ctladdr->q_gid);
+                       }
+                       else
+                       {
+                               (void) initgroups(DefUser, DefGid);
+                               if (m->m_gid == 0)
                                        (void) setgid(DefGid);
                                        (void) setgid(DefGid);
+                               else
+                                       (void) setgid(m->m_gid);
+                       }
+
+                       /* reset user id */
+                       endpwent();
+                       if (bitnset(M_SPECIFIC_UID, m->m_flags))
+                               (void) setuid(m->m_uid);
+                       else if (bitset(S_ISUID, stb.st_mode))
+                               (void) setuid(stb.st_uid);
+                       else if (ctladdr != NULL && ctladdr->q_uid != 0)
+                               (void) setuid(ctladdr->q_uid);
+                       else
+                       {
+                               if (m->m_uid == 0)
                                        (void) setuid(DefUid);
                                        (void) setuid(DefUid);
-                               }
                                else
                                else
-                               {
-                                       (void) initgroups(ctladdr->q_ruser?
-                                               ctladdr->q_ruser: ctladdr->q_user,
-                                               ctladdr->q_gid);
-                                       (void) setgid(ctladdr->q_gid);
-                                       (void) setuid(ctladdr->q_uid);
-                               }
+                                       (void) setuid(m->m_uid);
                        }
 
                        if (tTd(11, 2))
                        }
 
                        if (tTd(11, 2))
@@ -1212,14 +1335,14 @@ tryhost:
                        if (m->m_execdir != NULL)
                        {
                                char *p, *q;
                        if (m->m_execdir != NULL)
                        {
                                char *p, *q;
-                               char buf[MAXLINE];
+                               char buf[MAXLINE + 1];
 
                                for (p = m->m_execdir; p != NULL; p = q)
                                {
                                        q = strchr(p, ':');
                                        if (q != NULL)
                                                *q = '\0';
 
                                for (p = m->m_execdir; p != NULL; p = q)
                                {
                                        q = strchr(p, ':');
                                        if (q != NULL)
                                                *q = '\0';
-                                       expand(p, buf, &buf[sizeof buf] - 1, e);
+                                       expand(p, buf, sizeof buf, e);
                                        if (q != NULL)
                                                *q++ = ':';
                                        if (tTd(11, 20))
                                        if (q != NULL)
                                                *q++ = ':';
                                        if (tTd(11, 20))
@@ -1280,32 +1403,15 @@ tryhost:
                                        (void) fcntl(i, F_SETFD, j | 1);
                        }
 
                                        (void) fcntl(i, F_SETFD, j | 1);
                        }
 
-                       /*
-                       **  Set up the mailer environment
-                       **      TZ is timezone information.
-                       **      SYSTYPE is Apollo software sys type (required).
-                       **      ISP is Apollo hardware system type (required).
-                       */
-
-                       i = 0;
-                       env[i++] = "AGENT=sendmail";
-                       for (ep = environ; *ep != NULL; ep++)
-                       {
-                               if (strncmp(*ep, "TZ=", 3) == 0 ||
-                                   strncmp(*ep, "ISP=", 4) == 0 ||
-                                   strncmp(*ep, "SYSTYPE=", 8) == 0)
-                                       env[i++] = *ep;
-                       }
-                       env[i++] = NULL;
-
                        /* run disconnected from terminal */
                        (void) setsid();
 
                        /* try to execute the mailer */
                        /* run disconnected from terminal */
                        (void) setsid();
 
                        /* try to execute the mailer */
-                       execve(m->m_mailer, pv, env);
+                       execve(m->m_mailer, (ARGV_T) pv, (ARGV_T) UserEnviron);
                        saveerrno = errno;
                        syserr("Cannot exec %s", m->m_mailer);
                        saveerrno = errno;
                        syserr("Cannot exec %s", m->m_mailer);
-                       if (m == LocalMailer || transienterror(saveerrno))
+                       if (bitnset(M_LOCALMAILER, m->m_flags) ||
+                           transienterror(saveerrno))
                                _exit(EX_OSERR);
                        _exit(EX_UNAVAILABLE);
                }
                                _exit(EX_OSERR);
                        _exit(EX_UNAVAILABLE);
                }
@@ -1364,6 +1470,12 @@ tryhost:
        {
                smtpinit(m, mci, e);
        }
        {
                smtpinit(m, mci, e);
        }
+
+       if (bitset(EF_HAS8BIT, e->e_flags) && bitnset(M_7BITS, m->m_flags))
+               mci->mci_flags |= MCIF_CVT8TO7;
+       else
+               mci->mci_flags &= ~MCIF_CVT8TO7;
+
        if (tTd(11, 1))
        {
                printf("openmailer: ");
        if (tTd(11, 1))
        {
                printf("openmailer: ");
@@ -1385,7 +1497,7 @@ tryhost:
                                rcode, mci->mci_state, firstsig);
                        rcode = EX_SOFTWARE;
                }
                                rcode, mci->mci_state, firstsig);
                        rcode = EX_SOFTWARE;
                }
-               else if (rcode == EX_TEMPFAIL && curhost != NULL && *curhost != '\0')
+               else if (curhost != NULL && *curhost != '\0')
                {
                        /* try next MX site */
                        goto tryhost;
                {
                        /* try next MX site */
                        goto tryhost;
@@ -1398,8 +1510,7 @@ tryhost:
                */
 
                putfromline(mci, e);
                */
 
                putfromline(mci, e);
-               (*e->e_puthdr)(mci, e);
-               putline("\n", mci);
+               (*e->e_puthdr)(mci, e->e_header, e);
                (*e->e_putbody)(mci, e, NULL);
 
                /* get the exit status */
                (*e->e_putbody)(mci, e, NULL);
 
                /* get the exit status */
@@ -1425,8 +1536,8 @@ tryhost:
                                e->e_to = to->q_paddr;
                                if ((i = smtprcpt(to, m, mci, e)) != EX_OK)
                                {
                                e->e_to = to->q_paddr;
                                if ((i = smtprcpt(to, m, mci, e)) != EX_OK)
                                {
-                                       markfailure(e, to, i);
-                                       giveresponse(i, m, mci, ctladdr, e);
+                                       markfailure(e, to, mci, i);
+                                       giveresponse(i, m, mci, ctladdr, xstart, e);
                                }
                                else
                                {
                                }
                                else
                                {
@@ -1490,21 +1601,33 @@ tryhost:
 
   give_up:
        if (tobuf[0] != '\0')
 
   give_up:
        if (tobuf[0] != '\0')
-               giveresponse(rcode, m, mci, ctladdr, e);
+               giveresponse(rcode, m, mci, ctladdr, xstart, e);
        for (to = tochain; to != NULL; to = to->q_tchain)
        {
                if (rcode != EX_OK)
        for (to = tochain; to != NULL; to = to->q_tchain)
        {
                if (rcode != EX_OK)
-                       markfailure(e, to, rcode);
-               else
+                       markfailure(e, to, mci, rcode);
+               else if (!bitset(QBADADDR|QQUEUEUP, to->q_flags))
                {
                        to->q_flags |= QSENT;
                {
                        to->q_flags |= QSENT;
+                       to->q_statdate = curtime();
                        e->e_nsent++;
                        e->e_nsent++;
-                       if (e->e_receiptto != NULL &&
-                           bitnset(M_LOCALMAILER, m->m_flags))
+                       if (bitnset(M_LOCALMAILER, m->m_flags) &&
+                           (e->e_receiptto != NULL ||
+                            bitset(QPINGONSUCCESS, to->q_flags)))
                        {
                        {
+                               to->q_flags |= QDELIVERED;
+                               to->q_status = "2.1.5";
                                fprintf(e->e_xfp, "%s... Successfully delivered\n",
                                        to->q_paddr);
                        }
                                fprintf(e->e_xfp, "%s... Successfully delivered\n",
                                        to->q_paddr);
                        }
+                       else if (bitset(QPINGONSUCCESS, to->q_flags) &&
+                                bitset(QPRIMARY, to->q_flags) &&
+                                !bitset(MCIF_DSN, mci->mci_flags))
+                       {
+                               to->q_flags |= QRELAYED;
+                               fprintf(e->e_xfp, "%s... relayed; expect no further notifications\n",
+                                       to->q_paddr);
+                       }
                }
        }
 
                }
        }
 
@@ -1512,7 +1635,7 @@ tryhost:
        **  Restore state and return.
        */
 
        **  Restore state and return.
        */
 
-#ifdef XDEBUG
+#if XDEBUG
        {
                char wbuf[MAXLINE];
 
        {
                char wbuf[MAXLINE];
 
@@ -1534,6 +1657,7 @@ tryhost:
 **     Parameters:
 **             e -- the envelope we are sending.
 **             q -- the address to mark.
 **     Parameters:
 **             e -- the envelope we are sending.
 **             q -- the address to mark.
+**             mci -- mailer connection information.
 **             rcode -- the code signifying the particular failure.
 **
 **     Returns:
 **             rcode -- the code signifying the particular failure.
 **
 **     Returns:
@@ -1545,12 +1669,14 @@ tryhost:
 **                     the message will be queued, as appropriate.
 */
 
 **                     the message will be queued, as appropriate.
 */
 
-markfailure(e, q, rcode)
+void
+markfailure(e, q, mci, rcode)
        register ENVELOPE *e;
        register ADDRESS *q;
        register ENVELOPE *e;
        register ADDRESS *q;
+       register MCI *mci;
        int rcode;
 {
        int rcode;
 {
-       char buf[MAXLINE];
+       char *stat = NULL;
 
        switch (rcode)
        {
 
        switch (rcode)
        {
@@ -1567,6 +1693,69 @@ markfailure(e, q, rcode)
                q->q_flags |= QBADADDR;
                break;
        }
                q->q_flags |= QBADADDR;
                break;
        }
+
+       /* find most specific error code possible */
+       if (q->q_status == NULL && mci != NULL)
+               q->q_status = mci->mci_status;
+       if (q->q_status == NULL)
+               q->q_status = e->e_status;
+       if (q->q_status == NULL)
+       {
+               switch (rcode)
+               {
+                 case EX_USAGE:
+                       stat = "5.5.4";
+                       break;
+
+                 case EX_DATAERR:
+                       stat = "5.5.2";
+                       break;
+
+                 case EX_NOUSER:
+                       stat = "5.1.1";
+                       break;
+
+                 case EX_NOHOST:
+                       stat = "5.1.2";
+                       break;
+
+                 case EX_NOINPUT:
+                 case EX_CANTCREAT:
+                 case EX_NOPERM:
+                       stat = "5.3.0";
+                       break;
+
+                 case EX_UNAVAILABLE:
+                 case EX_SOFTWARE:
+                 case EX_OSFILE:
+                 case EX_PROTOCOL:
+                 case EX_CONFIG:
+                       stat = "5.5.0";
+                       break;
+
+                 case EX_OSERR:
+                 case EX_IOERR:
+                       stat = "4.5.0";
+                       break;
+
+                 case EX_TEMPFAIL:
+                       stat = "4.2.0";
+                       break;
+               }
+               if (stat != NULL)
+                       q->q_status = stat;
+       }
+
+       q->q_statdate = curtime();
+       if (CurHostName != NULL && CurHostName[0] != '\0')
+               q->q_statmta = newstr(CurHostName);
+       if (rcode != EX_OK && q->q_rstatus == NULL)
+       {
+               char buf[30];
+
+               (void) sprintf(buf, "%d", rcode);
+               q->q_rstatus = newstr(buf);
+       }
 }
 \f/*
 **  ENDMAILER -- Wait for mailer to terminate.
 }
 \f/*
 **  ENDMAILER -- Wait for mailer to terminate.
@@ -1589,6 +1778,7 @@ markfailure(e, q, rcode)
 **             none.
 */
 
 **             none.
 */
 
+int
 endmailer(mci, e, pv)
        register MCI *mci;
        register ENVELOPE *e;
 endmailer(mci, e, pv)
        register MCI *mci;
        register ENVELOPE *e;
@@ -1652,6 +1842,8 @@ endmailer(mci, e, pv)
 **                     response is given before the connection is made.
 **             ctladdr -- the controlling address for the recipient
 **                     address(es).
 **                     response is given before the connection is made.
 **             ctladdr -- the controlling address for the recipient
 **                     address(es).
+**             xstart -- the transaction start time, for computing
+**                     transaction delays.
 **             e -- the current envelope.
 **
 **     Returns:
 **             e -- the current envelope.
 **
 **     Returns:
@@ -1662,11 +1854,13 @@ endmailer(mci, e, pv)
 **             ExitStat may be set.
 */
 
 **             ExitStat may be set.
 */
 
-giveresponse(stat, m, mci, ctladdr, e)
+void
+giveresponse(stat, m, mci, ctladdr, xstart, e)
        int stat;
        register MAILER *m;
        register MCI *mci;
        ADDRESS *ctladdr;
        int stat;
        register MAILER *m;
        register MCI *mci;
        ADDRESS *ctladdr;
+       time_t xstart;
        ENVELOPE *e;
 {
        register const char *statmsg;
        ENVELOPE *e;
 {
        register const char *statmsg;
@@ -1726,7 +1920,7 @@ giveresponse(stat, m, mci, ctladdr, e)
        else if (stat == EX_NOHOST && h_errno != 0)
        {
                statmsg = errstring(h_errno + E_DNSBASE);
        else if (stat == EX_NOHOST && h_errno != 0)
        {
                statmsg = errstring(h_errno + E_DNSBASE);
-               (void) sprintf(buf, "%s (%s)", SysExMsg[i], statmsg);
+               (void) sprintf(buf, "%s (%s)", SysExMsg[i] + 1, statmsg);
                statmsg = buf;
        }
 #endif
                statmsg = buf;
        }
 #endif
@@ -1754,8 +1948,11 @@ giveresponse(stat, m, mci, ctladdr, e)
        }
        else
        {
        }
        else
        {
+               char mbuf[8];
+
                Errors++;
                Errors++;
-               usrerr(statmsg, errstring(errno));
+               sprintf(mbuf, "%.3s %%s", statmsg);
+               usrerr(mbuf, &statmsg[4]);
        }
 
        /*
        }
 
        /*
@@ -1766,11 +1963,11 @@ giveresponse(stat, m, mci, ctladdr, e)
        */
 
        if (LogLevel > ((stat == EX_TEMPFAIL) ? 8 : (stat == EX_OK) ? 7 : 6))
        */
 
        if (LogLevel > ((stat == EX_TEMPFAIL) ? 8 : (stat == EX_OK) ? 7 : 6))
-               logdelivery(m, mci, &statmsg[4], ctladdr, e);
+               logdelivery(m, mci, &statmsg[4], ctladdr, xstart, e);
 
        if (tTd(11, 2))
                printf("giveresponse: stat=%d, e->e_message=%s\n",
 
        if (tTd(11, 2))
                printf("giveresponse: stat=%d, e->e_message=%s\n",
-                       stat, e->e_message);
+                       stat, e->e_message == NULL ? "<NULL>" : e->e_message);
 
        if (stat != EX_TEMPFAIL)
                setstat(stat);
 
        if (stat != EX_TEMPFAIL)
                setstat(stat);
@@ -1798,6 +1995,8 @@ giveresponse(stat, m, mci, ctladdr, e)
 **                     log is occuring when no connection is active.
 **             stat -- the message to print for the status.
 **             ctladdr -- the controlling address for the to list.
 **                     log is occuring when no connection is active.
 **             stat -- the message to print for the status.
 **             ctladdr -- the controlling address for the to list.
+**             xstart -- the transaction start time, used for
+**                     computing transaction delay.
 **             e -- the current envelope.
 **
 **     Returns:
 **             e -- the current envelope.
 **
 **     Returns:
@@ -1807,11 +2006,13 @@ giveresponse(stat, m, mci, ctladdr, e)
 **             none
 */
 
 **             none
 */
 
-logdelivery(m, mci, stat, ctladdr, e)
+void
+logdelivery(m, mci, stat, ctladdr, xstart, e)
        MAILER *m;
        register MCI *mci;
        MAILER *m;
        register MCI *mci;
-       char *stat;
+       const char *stat;
        ADDRESS *ctladdr;
        ADDRESS *ctladdr;
+       time_t xstart;
        register ENVELOPE *e;
 {
 # ifdef LOG
        register ENVELOPE *e;
 {
 # ifdef LOG
@@ -1835,9 +2036,15 @@ logdelivery(m, mci, stat, ctladdr, e)
                }
        }
 
                }
        }
 
-       (void) sprintf(bp, ", delay=%s", pintvl(curtime() - e->e_ctime, TRUE));
+       sprintf(bp, ", delay=%s", pintvl(curtime() - e->e_ctime, TRUE));
        bp += strlen(bp);
 
        bp += strlen(bp);
 
+       if (xstart != (time_t) 0)
+       {
+               sprintf(bp, ", xdelay=%s", pintvl(curtime() - xstart, TRUE));
+               bp += strlen(bp);
+       }
+
        if (m != NULL)
        {
                (void) strcpy(bp, ", mailer=");
        if (m != NULL)
        {
                (void) strcpy(bp, ", mailer=");
@@ -1897,7 +2104,7 @@ logdelivery(m, mci, stat, ctladdr, e)
                
        l = SYSLOG_BUFSIZE - 100 - strlen(buf);
        p = e->e_to;
                
        l = SYSLOG_BUFSIZE - 100 - strlen(buf);
        p = e->e_to;
-       while (strlen(p) >= l)
+       while (strlen(p) >= (SIZE_T) l)
        {
                register char *q = strchr(p + l, ',');
 
        {
                register char *q = strchr(p + l, ',');
 
@@ -1943,6 +2150,11 @@ logdelivery(m, mci, stat, ctladdr, e)
        bp = buf;
        sprintf(bp, "delay=%s", pintvl(curtime() - e->e_ctime, TRUE));
        bp += strlen(bp);
        bp = buf;
        sprintf(bp, "delay=%s", pintvl(curtime() - e->e_ctime, TRUE));
        bp += strlen(bp);
+       if (xstart != (time_t) 0)
+       {
+               sprintf(bp, ", xdelay=%s", pintvl(curtime() - xstart, TRUE));
+               bp += strlen(bp);
+       }
 
        if (m != NULL)
        {
 
        if (m != NULL)
        {
@@ -2001,6 +2213,7 @@ logdelivery(m, mci, stat, ctladdr, e)
 **             outputs some text to fp.
 */
 
 **             outputs some text to fp.
 */
 
+void
 putfromline(mci, e)
        register MCI *mci;
        ENVELOPE *e;
 putfromline(mci, e)
        register MCI *mci;
        ENVELOPE *e;
@@ -2011,13 +2224,12 @@ putfromline(mci, e)
        if (bitnset(M_NHDR, mci->mci_mailer->m_flags))
                return;
 
        if (bitnset(M_NHDR, mci->mci_mailer->m_flags))
                return;
 
-# ifdef UGLYUUCP
        if (bitnset(M_UGLYUUCP, mci->mci_mailer->m_flags))
        {
                char *bang;
                char xbuf[MAXLINE];
 
        if (bitnset(M_UGLYUUCP, mci->mci_mailer->m_flags))
        {
                char *bang;
                char xbuf[MAXLINE];
 
-               expand("\201g", buf, &buf[sizeof buf - 1], e);
+               expand("\201g", buf, sizeof buf, e);
                bang = strchr(buf, '!');
                if (bang == NULL)
                {
                bang = strchr(buf, '!');
                if (bang == NULL)
                {
@@ -2031,9 +2243,8 @@ putfromline(mci, e)
                        template = xbuf;
                }
        }
                        template = xbuf;
                }
        }
-# endif /* UGLYUUCP */
-       expand(template, buf, &buf[sizeof buf - 1], e);
-       putline(buf, mci);
+       expand(template, buf, sizeof buf, e);
+       putxline(buf, mci, PXLF_NOTHINGSPECIAL);
 }
 \f/*
 **  PUTBODY -- put the body of a message.
 }
 \f/*
 **  PUTBODY -- put the body of a message.
@@ -2051,6 +2262,12 @@ putfromline(mci, e)
 **             The message is written onto fp.
 */
 
 **             The message is written onto fp.
 */
 
+/* values for output state variable */
+#define OS_HEAD                0       /* at beginning of line */
+#define OS_CR          1       /* read a carriage return */
+#define OS_INLINE      2       /* putting rest of line */
+
+void
 putbody(mci, e, separator)
        register MCI *mci;
        register ENVELOPE *e;
 putbody(mci, e, separator)
        register MCI *mci;
        register ENVELOPE *e;
@@ -2062,45 +2279,236 @@ putbody(mci, e, separator)
        **  Output the body of the message
        */
 
        **  Output the body of the message
        */
 
+       if (e->e_dfp == NULL && bitset(EF_HAS_DF, e->e_flags))
+       {
+               char *df = queuename(e, 'd');
+
+               e->e_dfp = fopen(df, "r");
+               if (e->e_dfp == NULL)
+                       syserr("putbody: Cannot open %s for %s from %s",
+                               df, e->e_to, e->e_from.q_paddr);
+       }
        if (e->e_dfp == NULL)
        {
        if (e->e_dfp == NULL)
        {
-               if (e->e_df != NULL)
+               if (bitset(MCIF_INHEADER, mci->mci_flags))
                {
                {
-                       e->e_dfp = fopen(e->e_df, "r");
-                       if (e->e_dfp == NULL)
-                               syserr("putbody: Cannot open %s for %s from %s",
-                               e->e_df, e->e_to, e->e_from.q_paddr);
+                       putline("", mci);
+                       mci->mci_flags &= ~MCIF_INHEADER;
                }
                }
-               else
-                       putline("<<< No Message Collected >>>", mci);
+               putline("<<< No Message Collected >>>", mci);
+               goto endofmessage;
        }
        }
-       if (e->e_dfp != NULL)
+       if (e->e_dfino == (ino_t) 0)
        {
        {
-               rewind(e->e_dfp);
-               while (!ferror(mci->mci_out) && fgets(buf, sizeof buf, e->e_dfp) != NULL)
+               struct stat stbuf;
+
+               if (fstat(fileno(e->e_dfp), &stbuf) < 0)
+                       e->e_dfino = -1;
+               else
                {
                {
-                       if (buf[0] == 'F' &&
-                           bitnset(M_ESCFROM, mci->mci_mailer->m_flags) &&
-                           strncmp(buf, "From ", 5) == 0)
-                               (void) putc('>', mci->mci_out);
-                       if (buf[0] == '-' && buf[1] == '-' && separator != NULL)
-                       {
-                               /* possible separator */
-                               int sl = strlen(separator);
+                       e->e_dfdev = stbuf.st_dev;
+                       e->e_dfino = stbuf.st_ino;
+               }
+       }
+       rewind(e->e_dfp);
 
 
-                               if (strncmp(&buf[2], separator, sl) == 0)
-                                       (void) putc(' ', mci->mci_out);
-                       }
+#if MIME8TO7
+       if (bitset(MCIF_CVT8TO7, mci->mci_flags))
+       {
+               char *boundaries[MAXMIMENESTING + 1];
+
+               /*
+               **  Do 8 to 7 bit MIME conversion.
+               */
+
+               /* make sure it looks like a MIME message */
+               if (hvalue("MIME-Version", e->e_header) == NULL)
+                       putline("MIME-Version: 1.0", mci);
+
+               if (hvalue("Content-Type", e->e_header) == NULL)
+               {
+                       sprintf(buf, "Content-Type: text/plain; charset=%s",
+                               defcharset(e));
                        putline(buf, mci);
                }
 
                        putline(buf, mci);
                }
 
-               if (ferror(e->e_dfp))
+               /* now do the hard work */
+               boundaries[0] = NULL;
+               mime8to7(mci, e->e_header, e, boundaries, M87F_OUTER);
+       }
+       else
+#endif
+       {
+               int ostate;
+               register char *bp;
+               register char *pbp;
+               register int c;
+               int padc;
+               char *buflim;
+               int pos = 0;
+               char peekbuf[10];
+
+               /* we can pass it through unmodified */
+               if (bitset(MCIF_INHEADER, mci->mci_flags))
+               {
+                       putline("", mci);
+                       mci->mci_flags &= ~MCIF_INHEADER;
+               }
+
+               /* determine end of buffer; allow for short mailer lines */
+               buflim = &buf[sizeof buf - 1];
+               if (mci->mci_mailer->m_linelimit > 0 &&
+                   mci->mci_mailer->m_linelimit < sizeof buf - 1)
+                       buflim = &buf[mci->mci_mailer->m_linelimit - 1];
+
+               /* copy temp file to output with mapping */
+               ostate = OS_HEAD;
+               bp = buf;
+               pbp = peekbuf;
+               while (!ferror(mci->mci_out))
                {
                {
-                       syserr("putbody: %s: read error", e->e_df);
-                       ExitStat = EX_IOERR;
+                       register char *xp;
+
+                       if (pbp > peekbuf)
+                               c = *--pbp;
+                       else if ((c = getc(e->e_dfp)) == EOF)
+                               break;
+                       if (bitset(MCIF_7BIT, mci->mci_flags))
+                               c &= 0x7f;
+                       switch (ostate)
+                       {
+                         case OS_HEAD:
+                               if (c != '\r' && c != '\n' && bp < buflim)
+                               {
+                                       *bp++ = c;
+                                       break;
+                               }
+
+                               /* check beginning of line for special cases */
+                               *bp = '\0';
+                               pos = 0;
+                               padc = EOF;
+                               if (buf[0] == 'F' &&
+                                   bitnset(M_ESCFROM, mci->mci_mailer->m_flags) &&
+                                   strncmp(buf, "From ", 5) == 0)
+                               {
+                                       padc = '>';
+                               }
+                               if (buf[0] == '-' && buf[1] == '-' &&
+                                   separator != NULL)
+                               {
+                                       /* possible separator */
+                                       int sl = strlen(separator);
+
+                                       if (strncmp(&buf[2], separator, sl) == 0)
+                                               padc = ' ';
+                               }
+                               if (buf[0] == '.' &&
+                                   bitnset(M_XDOT, mci->mci_mailer->m_flags))
+                               {
+                                       padc = '.';
+                               }
+
+                               /* now copy out saved line */
+                               if (TrafficLogFile != NULL)
+                               {
+                                       fprintf(TrafficLogFile, "%05d >>> ", getpid());
+                                       if (padc != EOF)
+                                               putc(padc, TrafficLogFile);
+                                       for (xp = buf; xp < bp; xp++)
+                                               putc(*xp, TrafficLogFile);
+                                       if (c == '\n')
+                                               fputs(mci->mci_mailer->m_eol,
+                                                     TrafficLogFile);
+                               }
+                               if (padc != EOF)
+                               {
+                                       putc(padc, mci->mci_out);
+                                       pos++;
+                               }
+                               for (xp = buf; xp < bp; xp++)
+                                       putc(*xp, mci->mci_out);
+                               if (c == '\n')
+                               {
+                                       fputs(mci->mci_mailer->m_eol,
+                                             mci->mci_out);
+                                       pos = 0;
+                               }
+                               else
+                               {
+                                       pos += bp - buf;
+                                       if (c != '\r')
+                                               *pbp++ = c;
+                               }
+                               bp = buf;
+
+                               /* determine next state */
+                               if (c == '\n')
+                                       ostate = OS_HEAD;
+                               else if (c == '\r')
+                                       ostate = OS_CR;
+                               else
+                                       ostate = OS_INLINE;
+                               continue;
+
+                         case OS_CR:
+                               if (c == '\n')
+                               {
+                                       /* got CRLF */
+                                       fputs(mci->mci_mailer->m_eol, mci->mci_out);
+                                       if (TrafficLogFile != NULL)
+                                       {
+                                               fputs(mci->mci_mailer->m_eol,
+                                                     TrafficLogFile);
+                                       }
+                                       ostate = OS_HEAD;
+                                       continue;
+                               }
+
+                               /* had a naked carriage return */
+                               *pbp++ = c;
+                               c = '\r';
+                               goto putch;
+
+                         case OS_INLINE:
+                               if (c == '\r')
+                               {
+                                       ostate = OS_CR;
+                                       continue;
+                               }
+putch:
+                               if (mci->mci_mailer->m_linelimit > 0 &&
+                                   pos > mci->mci_mailer->m_linelimit &&
+                                   c != '\n')
+                               {
+                                       putc('!', mci->mci_out);
+                                       fputs(mci->mci_mailer->m_eol, mci->mci_out);
+                                       if (TrafficLogFile != NULL)
+                                       {
+                                               fprintf(TrafficLogFile, "!%s",
+                                                       mci->mci_mailer->m_eol);
+                                       }
+                                       ostate = OS_HEAD;
+                                       *pbp++ = c;
+                                       continue;
+                               }
+                               if (TrafficLogFile != NULL)
+                                       putc(c, TrafficLogFile);
+                               putc(c, mci->mci_out);
+                               pos++;
+                               ostate = c == '\n' ? OS_HEAD : OS_INLINE;
+                               break;
+                       }
                }
        }
 
                }
        }
 
+       if (ferror(e->e_dfp))
+       {
+               syserr("putbody: df%s: read error", e->e_id);
+               ExitStat = EX_IOERR;
+       }
+
+endofmessage:
        /* some mailers want extra blank line at end of message */
        if (bitnset(M_BLANKEND, mci->mci_mailer->m_flags) &&
            buf[0] != '\0' && buf[0] != '\n')
        /* some mailers want extra blank line at end of message */
        if (bitnset(M_BLANKEND, mci->mci_mailer->m_flags) &&
            buf[0] != '\0' && buf[0] != '\n')
@@ -2132,6 +2540,8 @@ putbody(mci, e, separator)
 **             filename -- the name of the file to send to.
 **             ctladdr -- the controlling address header -- includes
 **                     the userid/groupid to be when sending.
 **             filename -- the name of the file to send to.
 **             ctladdr -- the controlling address header -- includes
 **                     the userid/groupid to be when sending.
+**             sfflags -- flags for opening.
+**             e -- the current envelope.
 **
 **     Returns:
 **             The exit code associated with the operation.
 **
 **     Returns:
 **             The exit code associated with the operation.
@@ -2140,13 +2550,15 @@ putbody(mci, e, separator)
 **             none.
 */
 
 **             none.
 */
 
-mailfile(filename, ctladdr, e)
+int
+mailfile(filename, ctladdr, sfflags, e)
        char *filename;
        ADDRESS *ctladdr;
        char *filename;
        ADDRESS *ctladdr;
+       int sfflags;
        register ENVELOPE *e;
 {
        register FILE *f;
        register ENVELOPE *e;
 {
        register FILE *f;
-       register int pid;
+       register int pid = -1;
        int mode;
 
        if (tTd(11, 1))
        int mode;
 
        if (tTd(11, 1))
@@ -2172,63 +2584,133 @@ mailfile(filename, ctladdr, e)
        {
                /* child -- actually write to file */
                struct stat stb;
        {
                /* child -- actually write to file */
                struct stat stb;
+               struct stat fsb;
                MCI mcibuf;
                MCI mcibuf;
+               int oflags = O_WRONLY|O_APPEND;
+
+               if (e->e_lockfp != NULL)
+                       (void) close(fileno(e->e_lockfp));
 
                (void) setsignal(SIGINT, SIG_DFL);
                (void) setsignal(SIGHUP, SIG_DFL);
                (void) setsignal(SIGTERM, SIG_DFL);
                (void) umask(OldUmask);
 
                (void) setsignal(SIGINT, SIG_DFL);
                (void) setsignal(SIGHUP, SIG_DFL);
                (void) setsignal(SIGTERM, SIG_DFL);
                (void) umask(OldUmask);
+               e->e_to = filename;
+               ExitStat = EX_OK;
 
 
+#ifdef HASLSTAT
+               if ((SafeFileEnv != NULL ? lstat(filename, &stb)
+                                        : stat(filename, &stb)) < 0)
+#else
                if (stat(filename, &stb) < 0)
                if (stat(filename, &stb) < 0)
+#endif
+               {
                        stb.st_mode = FileMode;
                        stb.st_mode = FileMode;
+                       oflags |= O_CREAT|O_EXCL;
+               }
+               else if (bitset(0111, stb.st_mode) || stb.st_nlink != 1 ||
+                        (SafeFileEnv != NULL && !S_ISREG(stb.st_mode)))
+                       exit(EX_CANTCREAT);
                mode = stb.st_mode;
 
                /* limit the errors to those actually caused in the child */
                errno = 0;
                ExitStat = EX_OK;
 
                mode = stb.st_mode;
 
                /* limit the errors to those actually caused in the child */
                errno = 0;
                ExitStat = EX_OK;
 
-               if (bitset(0111, stb.st_mode))
-                       exit(EX_CANTCREAT);
-               if (ctladdr != NULL)
+               if (ctladdr != NULL || bitset(SFF_RUNASREALUID, sfflags))
                {
                        /* ignore setuid and setgid bits */
                        mode &= ~(S_ISGID|S_ISUID);
                }
 
                /* we have to open the dfile BEFORE setuid */
                {
                        /* ignore setuid and setgid bits */
                        mode &= ~(S_ISGID|S_ISUID);
                }
 
                /* we have to open the dfile BEFORE setuid */
-               if (e->e_dfp == NULL && e->e_df != NULL)
+               if (e->e_dfp == NULL && bitset(EF_HAS_DF, e->e_flags))
                {
                {
-                       e->e_dfp = fopen(e->e_df, "r");
+                       char *df = queuename(e, 'd');
+
+                       e->e_dfp = fopen(df, "r");
                        if (e->e_dfp == NULL)
                        {
                                syserr("mailfile: Cannot open %s for %s from %s",
                        if (e->e_dfp == NULL)
                        {
                                syserr("mailfile: Cannot open %s for %s from %s",
-                                       e->e_df, e->e_to, e->e_from.q_paddr);
+                                       df, e->e_to, e->e_from.q_paddr);
                        }
                }
 
                        }
                }
 
-               if (!bitset(S_ISGID, mode) || setgid(stb.st_gid) < 0)
+               if (SafeFileEnv != NULL && SafeFileEnv[0] != '\0')
                {
                {
-                       if (ctladdr == NULL || ctladdr->q_uid == 0)
+                       int i;
+
+                       if (chroot(SafeFileEnv) < 0)
                        {
                        {
-                               (void) initgroups(DefUser, DefGid);
+                               syserr("mailfile: Cannot chroot(%s)",
+                                       SafeFileEnv);
+                               exit(EX_CANTCREAT);
+                       }
+                       i = strlen(SafeFileEnv);
+                       if (strncmp(SafeFileEnv, filename, i) == 0)
+                               filename += i;
+               }
+               if (chdir("/") < 0)
+                       syserr("mailfile: cannot chdir(/)");
+
+               /* select a new user to run as */
+               if (!bitset(SFF_RUNASREALUID, sfflags))
+               {
+                       if (bitset(S_ISUID, mode))
+                       {
+                               RealUserName = NULL;
+                               RealUid = stb.st_uid;
+                       }
+                       else if (ctladdr != NULL && ctladdr->q_uid != 0)
+                       {
+                               if (ctladdr->q_ruser != NULL)
+                                       RealUserName = ctladdr->q_ruser;
+                               else
+                                       RealUserName = ctladdr->q_user;
+                               RealUid = ctladdr->q_uid;
+                       }
+                       else if (FileMailer != NULL && FileMailer->m_uid != 0)
+                       {
+                               RealUserName = DefUser;
+                               RealUid = FileMailer->m_uid;
                        }
                        else
                        {
                        }
                        else
                        {
-                               (void) initgroups(ctladdr->q_ruser ?
-                                       ctladdr->q_ruser : ctladdr->q_user,
-                                       ctladdr->q_gid);
+                               RealUserName = DefUser;
+                               RealUid = DefUid;
                        }
                        }
+
+                       /* select a new group to run as */
+                       if (bitset(S_ISGID, mode))
+                               RealGid = stb.st_gid;
+                       else if (ctladdr != NULL && ctladdr->q_uid != 0)
+                               RealGid = ctladdr->q_gid;
+                       else if (FileMailer != NULL && FileMailer->m_gid != 0)
+                               RealGid = FileMailer->m_gid;
+                       else
+                               RealGid = DefGid;
                }
                }
-               if (!bitset(S_ISUID, mode) || setuid(stb.st_uid) < 0)
+
+               /* last ditch */
+               if (!bitset(SFF_ROOTOK, sfflags))
                {
                {
-                       if (ctladdr == NULL || ctladdr->q_uid == 0)
-                               (void) setuid(DefUid);
-                       else
-                               (void) setuid(ctladdr->q_uid);
+                       if (RealUid == 0)
+                               RealUid = DefUid;
+                       if (RealGid == 0)
+                               RealGid = DefGid;
                }
                }
-               FileName = filename;
-               LineNumber = 0;
-               f = dfopen(filename, O_WRONLY|O_CREAT|O_APPEND, FileMode);
+
+               /* now set the group and user ids */
+               endpwent();
+               if (RealUserName != NULL)
+                       (void) initgroups(RealUserName, RealGid);
+               else
+                       (void) setgid(RealGid);
+               (void) setuid(RealUid);
+
+               sfflags |= SFF_NOPATHCHECK;
+               sfflags &= ~SFF_OPENASROOT;
+               f = safefopen(filename, oflags, FileMode, sfflags);
                if (f == NULL)
                {
                        message("554 cannot open: %s", errstring(errno));
                if (f == NULL)
                {
                        message("554 cannot open: %s", errstring(errno));
@@ -2242,8 +2724,7 @@ mailfile(filename, ctladdr, e)
                        mcibuf.mci_flags |= MCIF_7BIT;
 
                putfromline(&mcibuf, e);
                        mcibuf.mci_flags |= MCIF_7BIT;
 
                putfromline(&mcibuf, e);
-               (*e->e_puthdr)(&mcibuf, e);
-               putline("\n", &mcibuf);
+               (*e->e_puthdr)(&mcibuf, e->e_header, e);
                (*e->e_putbody)(&mcibuf, e, NULL);
                putline("\n", &mcibuf);
                if (ferror(f))
                (*e->e_putbody)(&mcibuf, e, NULL);
                putline("\n", &mcibuf);
                if (ferror(f))
@@ -2309,7 +2790,7 @@ hostsignature(m, host, e)
        auto int rcode;
        char *hp;
        char *endp;
        auto int rcode;
        char *hp;
        char *endp;
-       int oldoptions;
+       int oldoptions = _res.options;
        char *mxhosts[MAXMXHOSTS + 1];
 #endif
 
        char *mxhosts[MAXMXHOSTS + 1];
 #endif
 
@@ -2338,10 +2819,7 @@ hostsignature(m, host, e)
 
 #if NAMED_BIND
        if (ConfigLevel < 2)
 
 #if NAMED_BIND
        if (ConfigLevel < 2)
-       {
-               oldoptions = _res.options;
                _res.options &= ~(RES_DEFNAMES | RES_DNSRCH);   /* XXX */
                _res.options &= ~(RES_DEFNAMES | RES_DNSRCH);   /* XXX */
-       }
 
        for (hp = host; hp != NULL; hp = endp)
        {
 
        for (hp = host; hp != NULL; hp = endp)
        {
@@ -2359,9 +2837,7 @@ hostsignature(m, host, e)
                        mci = mci_get(hp, m);
                        mci->mci_exitstat = rcode;
                        mci->mci_errno = errno;
                        mci = mci_get(hp, m);
                        mci->mci_exitstat = rcode;
                        mci->mci_errno = errno;
-#if NAMED_BIND
                        mci->mci_herrno = h_errno;
                        mci->mci_herrno = h_errno;
-#endif
 
                        /* and return the original host name as the signature */
                        nmx = 1;
 
                        /* and return the original host name as the signature */
                        nmx = 1;