improve DSN handling somewhat + some bug fixes
[unix-history] / usr / src / usr.sbin / sendmail / src / deliver.c
index 59ac1bf..eeb6d58 100644 (file)
@@ -7,23 +7,19 @@
  */
 
 #ifndef lint
  */
 
 #ifndef lint
-static char sccsid[] = "@(#)deliver.c  8.23 (Berkeley) %G%";
+static char sccsid[] = "@(#)deliver.c  8.114 (Berkeley) %G%";
 #endif /* not lint */
 
 #include "sendmail.h"
 #include <netdb.h>
 #include <errno.h>
 #endif /* not lint */
 
 #include "sendmail.h"
 #include <netdb.h>
 #include <errno.h>
-#include <sys/wait.h>
-#ifdef NAMED_BIND
-#include <arpa/nameser.h>
+#if NAMED_BIND
 #include <resolv.h>
 
 extern int     h_errno;
 #endif
 
 #include <resolv.h>
 
 extern int     h_errno;
 #endif
 
-#ifndef WEXITSTATUS
-# define WEXITSTATUS(st)       (((st) >> 8) & 0377)
-#endif
+extern char    SmtpError[];
 
 /*
 **  SENDALL -- actually send all the messages.
 
 /*
 **  SENDALL -- actually send all the messages.
@@ -50,9 +46,10 @@ sendall(e, mode)
        register ADDRESS *q;
        char *owner;
        int otherowners;
        register ADDRESS *q;
        char *owner;
        int otherowners;
-       register ENVELOPE *ee;
-       ENVELOPE *splitenv = NULL;
        bool announcequeueup;
        bool announcequeueup;
+       bool oldverbose = Verbose;
+       int pid;
+       char *qid;
        int pid;
 #ifdef LOCKF
        struct flock lfd;
        int pid;
 #ifdef LOCKF
        struct flock lfd;
@@ -65,13 +62,15 @@ sendall(e, mode)
        **  addresses to be sent.
        */
 
        **  addresses to be sent.
        */
 
-       if (bitset(EF_FATALERRS, e->e_flags) && OpMode == MD_SMTP)
+       if (bitset(EF_FATALERRS, e->e_flags) &&
+           (OpMode == MD_SMTP || OpMode == MD_DAEMON))
        {
                e->e_flags |= EF_CLRQUEUE;
                return;
        }
 
        /* determine actual delivery mode */
        {
                e->e_flags |= EF_CLRQUEUE;
                return;
        }
 
        /* determine actual delivery mode */
+       CurrentLA = getla();
        if (mode == SM_DEFAULT)
        {
                mode = e->e_sendmode;
        if (mode == SM_DEFAULT)
        {
                mode = e->e_sendmode;
@@ -103,9 +102,11 @@ sendall(e, mode)
        if (e->e_hopcount > MaxHopCount)
        {
                errno = 0;
        if (e->e_hopcount > MaxHopCount)
        {
                errno = 0;
+               e->e_flags |= EF_FATALERRS|EF_PM_NOTIFY|EF_CLRQUEUE;
                syserr("554 too many hops %d (%d max): from %s via %s, to %s",
                        e->e_hopcount, MaxHopCount, e->e_from.q_paddr,
                syserr("554 too many hops %d (%d max): from %s via %s, to %s",
                        e->e_hopcount, MaxHopCount, e->e_from.q_paddr,
-                       RealHostName, e->e_sendqueue->q_paddr);
+                       RealHostName == NULL ? "localhost" : RealHostName,
+                       e->e_sendqueue->q_paddr);
                return;
        }
 
                return;
        }
 
@@ -127,7 +128,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);
        }
 
 # ifdef QUEUE
        }
 
 # ifdef QUEUE
@@ -324,6 +325,7 @@ sendall(e, mode)
 
                if (owner != NULL && otherowners > 0)
                {
 
                if (owner != NULL && otherowners > 0)
                {
+                       register ENVELOPE *ee;
                        extern HDR *copyheader();
                        extern ADDRESS *copyqueue();
 
                        extern HDR *copyheader();
                        extern ADDRESS *copyqueue();
 
@@ -343,7 +345,8 @@ 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);
+                       ee->e_flags = e->e_flags & ~(EF_INQUEUE|EF_CLRQUEUE|EF_FATALERRS|EF_SENDRECEIPT);
+                       ee->e_flags |= EF_NORECEIPT;
                        setsender(owner, ee, NULL, TRUE);
                        if (tTd(13, 5))
                        {
                        setsender(owner, ee, NULL, TRUE);
                        if (tTd(13, 5))
                        {
@@ -353,18 +356,21 @@ 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_lockfp = NULL;
                        ee->e_df = NULL;
                        ee->e_errormode = EM_MAIL;
                        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)
                                if (q->q_owner == owner)
                        
                        for (q = e->e_sendqueue; q != NULL; q = q->q_next)
                                if (q->q_owner == owner)
+                               {
                                        q->q_flags |= QDONTSEND;
                                        q->q_flags |= QDONTSEND;
+                                       q->q_flags &= ~QQUEUEUP;
+                               }
                        for (q = ee->e_sendqueue; q != NULL; q = q->q_next)
                                if (q->q_owner != owner)
                        for (q = ee->e_sendqueue; q != NULL; q = q->q_next)
                                if (q->q_owner != owner)
+                               {
                                        q->q_flags |= QDONTSEND;
                                        q->q_flags |= QDONTSEND;
+                                       q->q_flags &= ~QQUEUEUP;
+                               }
 
                        if (e->e_df != NULL && mode != SM_VERIFY)
                        {
 
                        if (e->e_df != NULL && mode != SM_VERIFY)
                        {
@@ -377,17 +383,21 @@ sendall(e, mode)
                                                e->e_df, ee->e_df);
                                }
                        }
                                                e->e_df, ee->e_df);
                                }
                        }
-
-                       if (mode != SM_VERIFY)
-                               openxscript(ee);
 #ifdef LOG
                        if (LogLevel > 4)
 #ifdef LOG
                        if (LogLevel > 4)
-                               syslog(LOG_INFO, "%s: clone %s",
-                                       ee->e_id, e->e_id);
+                               syslog(LOG_INFO, "%s: clone %s, owner=%s",
+                                       ee->e_id, e->e_id, owner);
 #endif
 #endif
+                       CurEnv = ee;
+                       sendenvelope(ee, mode, announcequeueup);
+                       dropenvelope(ee);
                }
        }
 
                }
        }
 
+       /*
+       **  Split off envelopes have been sent -- now send original
+       */
+
        if (owner != NULL)
        {
                setsender(owner, e, NULL, TRUE);
        if (owner != NULL)
        {
                setsender(owner, e, NULL, TRUE);
@@ -398,8 +408,11 @@ sendall(e, mode)
                }
                e->e_from.q_flags |= QDONTSEND;
                e->e_errormode = EM_MAIL;
                }
                e->e_from.q_flags |= QDONTSEND;
                e->e_errormode = EM_MAIL;
+               e->e_flags |= EF_NORECEIPT;
        }
 
        }
 
+       bool oldverbose = Verbose;
+
        if (splitenv != NULL)
        {
                if (tTd(13, 1))
        if (splitenv != NULL)
        {
                if (tTd(13, 1))
@@ -411,15 +424,16 @@ sendall(e, mode)
                for (ee = splitenv; ee != NULL; ee = ee->e_sibling)
                {
                        CurEnv = ee;
                for (ee = splitenv; ee != NULL; ee = ee->e_sibling)
                {
                        CurEnv = ee;
+                       if (mode != SM_VERIFY)
+                               openxscript(ee);
                        sendenvelope(ee, mode);
                        sendenvelope(ee, mode);
+                       dropenvelope(ee);
                }
 
                CurEnv = e;
        }
        sendenvelope(e, mode);
                }
 
                CurEnv = e;
        }
        sendenvelope(e, mode);
-
-       for (; splitenv != NULL; splitenv = splitenv->e_sibling)
-               dropenvelope(splitenv);
+       Verbose = oldverbose;
 }
 
 sendenvelope(e, mode)
 }
 
 sendenvelope(e, mode)
@@ -427,7 +441,22 @@ sendenvelope(e, mode)
        char mode;
 {
        register ADDRESS *q;
        char mode;
 {
        register ADDRESS *q;
-       bool oldverbose = Verbose;
+       char *qf;
+       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.
@@ -438,6 +467,9 @@ 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)
        {
 #ifdef XDEBUG
        for (q = e->e_sendqueue; q != NULL; q = q->q_next)
        {
 #ifdef XDEBUG
@@ -451,10 +483,15 @@ sendenvelope(e, mode)
                        e->e_to = q->q_paddr;
                        if (!bitset(QDONTSEND|QBADADDR, q->q_flags))
                        {
                        e->e_to = q->q_paddr;
                        if (!bitset(QDONTSEND|QBADADDR, q->q_flags))
                        {
-                               message("deliverable: mailer %s, host %s, user %s",
-                                       q->q_mailer->m_name,
-                                       q->q_host,
-                                       q->q_user);
+                               if (q->q_host != NULL && q->q_host[0] != '\0')
+                                       message("deliverable: mailer %s, host %s, user %s",
+                                               q->q_mailer->m_name,
+                                               q->q_host,
+                                               q->q_user);
+                               else
+                                       message("deliverable: mailer %s, user %s",
+                                               q->q_mailer->m_name,
+                                               q->q_user);
                        }
                }
                else if (!bitset(QDONTSEND|QBADADDR, q->q_flags))
                        }
                }
                else if (!bitset(QDONTSEND|QBADADDR, q->q_flags))
@@ -471,9 +508,14 @@ 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
        checkfd012("end of sendenvelope");
 
 #ifdef XDEBUG
        checkfd012("end of sendenvelope");
@@ -593,15 +635,15 @@ deliver(e, firstto)
        char buf[MAXNAME];
        char rpathbuf[MAXNAME];         /* translated return path */
        extern int checkcompat();
        char buf[MAXNAME];
        char rpathbuf[MAXNAME];         /* translated return path */
        extern int checkcompat();
-       extern FILE *fdopen();
 
        errno = 0;
        if (!ForceMail && bitset(QDONTSEND|QPSEUDO, to->q_flags))
                return (0);
 
 
        errno = 0;
        if (!ForceMail && bitset(QDONTSEND|QPSEUDO, to->q_flags))
                return (0);
 
-#ifdef NAMED_BIND
+#if NAMED_BIND
        /* unless interactive, try twice, over a minute */
        /* unless interactive, try twice, over a minute */
-       if (OpMode == MD_DAEMON || OpMode == MD_SMTP) {
+       if (OpMode == MD_DAEMON || OpMode == MD_SMTP)
+       {
                _res.retrans = 30;
                _res.retry = 2;
        }
                _res.retrans = 30;
                _res.retry = 2;
        }
@@ -611,10 +653,13 @@ deliver(e, firstto)
        host = to->q_host;
        CurEnv = e;                     /* just in case */
        e->e_statmsg = NULL;
        host = to->q_host;
        CurEnv = e;                     /* just in case */
        e->e_statmsg = NULL;
+       SmtpError[0] = '\0';
 
        if (tTd(10, 1))
 
        if (tTd(10, 1))
-               printf("\n--deliver, mailer=%d, host=`%s', first user=`%s'\n",
-                       m->m_mno, host, to->q_user);
+               printf("\n--deliver, id=%s, mailer=%s, host=`%s', first user=`%s'\n",
+                       e->e_id, m->m_name, host, to->q_user);
+       if (tTd(10, 100))
+               printopenfds(FALSE);
 
        /*
        **  If this mailer is expensive, and if we don't want to make
 
        /*
        **  If this mailer is expensive, and if we don't want to make
@@ -626,8 +671,7 @@ deliver(e, firstto)
        **              This should be on a per-mailer basis.
        */
 
        **              This should be on a per-mailer basis.
        */
 
-       if (NoConnect && !bitset(EF_QUEUERUN, e->e_flags) &&
-           bitnset(M_EXPENSIVE, m->m_flags) && !Verbose)
+       if (NoConnect && bitnset(M_EXPENSIVE, m->m_flags) && !Verbose)
        {
                for (; to != NULL; to = to->q_next)
                {
        {
                for (; to != NULL; to = to->q_next)
                {
@@ -638,7 +682,7 @@ deliver(e, firstto)
                        e->e_to = to->q_paddr;
                        message("queued");
                        if (LogLevel > 8)
                        e->e_to = to->q_paddr;
                        message("queued");
                        if (LogLevel > 8)
-                               logdelivery(m, NULL, "queued", e);
+                               logdelivery(m, NULL, "queued", NULL, e);
                }
                e->e_to = NULL;
                return (0);
                }
                e->e_to = NULL;
                return (0);
@@ -657,7 +701,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 */
@@ -722,7 +770,7 @@ deliver(e, firstto)
                *pvp = NULL;
 # else /* SMTP */
                /* oops!  we don't implement SMTP */
                *pvp = NULL;
 # else /* SMTP */
                /* oops!  we don't implement SMTP */
-               syserr("554 SMTP style mailer");
+               syserr("554 SMTP style mailer not implemented");
                return (EX_SOFTWARE);
 # endif /* SMTP */
        }
                return (EX_SOFTWARE);
 # endif /* SMTP */
        }
@@ -761,7 +809,7 @@ deliver(e, firstto)
                }
 
                /* compute effective uid/gid when sending */
                }
 
                /* compute effective uid/gid when sending */
-               if (to->q_mailer == ProgMailer)
+               if (bitnset(M_RUNASRCPT, to->q_mailer->m_flags))
                        ctladdr = getctladdr(to);
 
                user = to->q_user;
                        ctladdr = getctladdr(to);
 
                user = to->q_user;
@@ -780,16 +828,19 @@ 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_NORETURN;
                        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, e);
+                       giveresponse(EX_UNAVAILABLE, m, NULL, ctladdr, e);
                        continue;
                }
                        continue;
                }
+#if NAMED_BIND
+               h_errno = 0;
+#endif
                rcode = checkcompat(to, e);
                if (rcode != EX_OK)
                {
                        markfailure(e, to, rcode);
                rcode = checkcompat(to, e);
                if (rcode != EX_OK)
                {
                        markfailure(e, to, rcode);
-                       giveresponse(rcode, m, NULL, e);
+                       giveresponse(rcode, m, NULL, ctladdr, e);
                        continue;
                }
 
                        continue;
                }
 
@@ -833,10 +884,22 @@ deliver(e, firstto)
 
                if (m == FileMailer)
                {
 
                if (m == FileMailer)
                {
-                       rcode = mailfile(user, getctladdr(to), e);
-                       giveresponse(rcode, m, NULL, e);
+                       rcode = mailfile(user, ctladdr, e);
+                       giveresponse(rcode, m, NULL, ctladdr, 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 |= QREPORT;
+                                       fprintf(e->e_xfp, "%s... Successfully delivered\n",
+                                               to->q_paddr);
+                               }
+                       }
+                       to->q_statdate = curtime();
                        continue;
                }
 
                        continue;
                }
 
@@ -853,7 +916,10 @@ deliver(e, firstto)
                (void) strcat(tobuf, ",");
                (void) strcat(tobuf, to->q_paddr);
                define('u', user, e);           /* to user */
                (void) strcat(tobuf, ",");
                (void) strcat(tobuf, to->q_paddr);
                define('u', user, e);           /* to user */
-               define('z', to->q_home, e);     /* user's home */
+               p = to->q_home;
+               if (p == NULL && ctladdr != NULL)
+                       p = ctladdr->q_home;
+               define('z', p, e);      /* user's home */
 
                /*
                **  Expand out this user into argument list.
 
                /*
                **  Expand out this user into argument list.
@@ -902,9 +968,12 @@ deliver(e, firstto)
        **      If we are running SMTP, we just need to clean up.
        */
 
        **      If we are running SMTP, we just need to clean up.
        */
 
-       if (ctladdr == NULL && m != ProgMailer)
+       /*XXX this seems a bit wierd */
+       if (ctladdr == NULL && m != ProgMailer &&
+           bitset(QGOODUID, e->e_from.q_flags))
                ctladdr = &e->e_from;
                ctladdr = &e->e_from;
-#ifdef NAMED_BIND
+
+#if NAMED_BIND
        if (ConfigLevel < 2)
                _res.options &= ~(RES_DEFNAMES | RES_DNSRCH);   /* XXX */
 #endif
        if (ConfigLevel < 2)
                _res.options &= ~(RES_DEFNAMES | RES_DNSRCH);   /* XXX */
 #endif
@@ -915,6 +984,9 @@ deliver(e, firstto)
                printav(pv);
        }
        errno = 0;
                printav(pv);
        }
        errno = 0;
+#if NAMED_BIND
+       h_errno = 0;
+#endif
 
        CurHostName = m->m_mailer;
 
 
        CurHostName = m->m_mailer;
 
@@ -929,6 +1001,7 @@ deliver(e, firstto)
 
        curhost = NULL;
        SmtpPhase = NULL;
 
        curhost = NULL;
        SmtpPhase = NULL;
+       mci = NULL;
 
 #ifdef XDEBUG
        {
 
 #ifdef XDEBUG
        {
@@ -940,6 +1013,15 @@ 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))
+       {
+               usrerr("554 Cannot send 8-bit data to 7-bit destination");
+               rcode = EX_DATAERR;
+               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)
@@ -958,20 +1040,27 @@ deliver(e, firstto)
                register int i;
                register u_short port;
 
                register int i;
                register u_short port;
 
+               if (pv[0] == NULL || pv[1] == NULL || pv[1][0] == '\0')
+               {
+                       syserr("null host name for %s mailer", m->m_mailer);
+                       rcode = EX_CONFIG;
+                       goto give_up;
+               }
+
                CurHostName = pv[1];
                curhost = hostsignature(m, pv[1], e);
 
                if (curhost == NULL || curhost[0] == '\0')
                {
                CurHostName = pv[1];
                curhost = hostsignature(m, pv[1], e);
 
                if (curhost == NULL || curhost[0] == '\0')
                {
-                       syserr("null signature");
-                       rcode = EX_OSERR;
+                       syserr("null host signature for %s", pv[1]);
+                       rcode = EX_CONFIG;
                        goto give_up;
                }
 
                if (!clever)
                {
                        syserr("554 non-clever IPC");
                        goto give_up;
                }
 
                if (!clever)
                {
                        syserr("554 non-clever IPC");
-                       rcode = EX_OSERR;
+                       rcode = EX_CONFIG;
                        goto give_up;
                }
                if (pv[2] != NULL)
                        goto give_up;
                }
                if (pv[2] != NULL)
@@ -979,18 +1068,21 @@ deliver(e, firstto)
                else
                        port = 0;
 tryhost:
                else
                        port = 0;
 tryhost:
-               mci = NULL;
                while (*curhost != '\0')
                {
                        register char *p;
                        static char hostbuf[MAXNAME];
 
                while (*curhost != '\0')
                {
                        register char *p;
                        static char hostbuf[MAXNAME];
 
-                       mci = NULL;
-
                        /* pull the next host from the signature */
                        p = strchr(curhost, ':');
                        if (p == NULL)
                                p = &curhost[strlen(curhost)];
                        /* pull the next host from the signature */
                        p = strchr(curhost, ':');
                        if (p == NULL)
                                p = &curhost[strlen(curhost)];
+                       if (p == curhost)
+                       {
+                               syserr("deliver: null host name in signature");
+                               curhost++;
+                               continue;
+                       }
                        strncpy(hostbuf, curhost, p - curhost);
                        hostbuf[p - curhost] = '\0';
                        if (*p != '\0')
                        strncpy(hostbuf, curhost, p - curhost);
                        hostbuf[p - curhost] = '\0';
                        if (*p != '\0')
@@ -1005,9 +1097,11 @@ tryhost:
                                if (tTd(11, 1))
                                {
                                        printf("openmailer: ");
                                if (tTd(11, 1))
                                {
                                        printf("openmailer: ");
-                                       mci_dump(mci);
+                                       mci_dump(mci, FALSE);
                                }
                                CurHostName = mci->mci_host;
                                }
                                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;
@@ -1016,13 +1110,13 @@ 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));
                        mci->mci_exitstat = i;
                        mci->mci_errno = errno;
                                hostbuf, m->m_name);
                        i = makeconnection(hostbuf, port, mci,
                                bitnset(M_SECURE_PORT, m->m_flags));
                        mci->mci_exitstat = i;
                        mci->mci_errno = errno;
-#ifdef NAMED_BIND
+#if NAMED_BIND
                        mci->mci_herrno = h_errno;
 #endif
                        if (i == EX_OK)
                        mci->mci_herrno = h_errno;
 #endif
                        if (i == EX_OK)
@@ -1038,20 +1132,36 @@ tryhost:
                                printf("openmailer: makeconnection => stat=%d, errno=%d\n",
                                        i, errno);
 
                                printf("openmailer: makeconnection => stat=%d, errno=%d\n",
                                        i, errno);
 
-
                        /* enter status of this host */
                        setstat(i);
                        /* enter status of this host */
                        setstat(i);
+
+                       /* should print some message here for -v mode */
+               }
+               if (mci == NULL)
+               {
+                       syserr("deliver: no host name");
+                       rcode = EX_OSERR;
+                       goto give_up;
                }
                mci->mci_pid = 0;
 #else /* no DAEMON */
                syserr("554 openmailer: no IPC");
                if (tTd(11, 1))
                        printf("openmailer: NULL\n");
                }
                mci->mci_pid = 0;
 #else /* no DAEMON */
                syserr("554 openmailer: no IPC");
                if (tTd(11, 1))
                        printf("openmailer: NULL\n");
-               return NULL;
+               rcode = EX_UNAVAILABLE;
+               goto give_up;
 #endif /* DAEMON */
        }
        else
        {
 #endif /* DAEMON */
        }
        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;
@@ -1133,24 +1243,31 @@ tryhost:
                        (void) setsignal(SIGHUP, SIG_IGN);
                        (void) setsignal(SIGTERM, SIG_DFL);
 
                        (void) setsignal(SIGHUP, SIG_IGN);
                        (void) setsignal(SIGTERM, SIG_DFL);
 
-                       /* close any other cached connections */
-                       mci_flush(FALSE, mci);
-
                        /* reset user and group */
                        /* reset user and group */
-                       if (!bitnset(M_RESTR, m->m_flags))
+                       if (bitnset(M_SPECIFIC_UID, m->m_flags))
                        {
                        {
-                               if (ctladdr == NULL || ctladdr->q_uid == 0)
-                               {
-                                       (void) initgroups(DefUser, DefGid);
+                               (void) setgid(m->m_gid);
+                               (void) setuid(m->m_uid);
+                       }
+                       else if (ctladdr != NULL && ctladdr->q_uid != 0)
+                       {
+                               (void) initgroups(ctladdr->q_ruser?
+                                       ctladdr->q_ruser: ctladdr->q_user,
+                                       ctladdr->q_gid);
+                               (void) setgid(ctladdr->q_gid);
+                               (void) setuid(ctladdr->q_uid);
+                       }
+                       else
+                       {
+                               (void) initgroups(DefUser, DefGid);
+                               if (m->m_gid == 0)
+                                       (void) setgid(DefGid);
+                               else
+                                       (void) setgid(m->m_gid);
+                               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) setuid(ctladdr->q_uid);
-                               }
+                                       (void) setuid(m->m_uid);
                        }
 
                        if (tTd(11, 2))
                        }
 
                        if (tTd(11, 2))
@@ -1191,7 +1308,8 @@ tryhost:
                                }
                                (void) close(rpvect[1]);
                        }
                                }
                                (void) close(rpvect[1]);
                        }
-                       else if (OpMode == MD_SMTP || HoldErrs)
+                       else if (OpMode == MD_SMTP || OpMode == MD_DAEMON ||
+                                 HoldErrs || DisConnected)
                        {
                                /* put mailer output in transcript */
                                if (dup2(fileno(e->e_xfp), STDOUT_FILENO) < 0)
                        {
                                /* put mailer output in transcript */
                                if (dup2(fileno(e->e_xfp), STDOUT_FILENO) < 0)
@@ -1228,21 +1346,35 @@ tryhost:
                                        (void) fcntl(i, F_SETFD, j | 1);
                        }
 
                                        (void) fcntl(i, F_SETFD, j | 1);
                        }
 
-                       /* set up the mailer environment */
+                       /*
+                       **  Set up the mailer environment
+                       **      _FORCE_MAIL_LOCAL_ is DG-UX equiv of -d flag.
+                       **      TZ is timezone information.
+                       **      SYSTYPE is Apollo software sys type (required).
+                       **      ISP is Apollo hardware system type (required).
+                       */
+
                        i = 0;
                        env[i++] = "AGENT=sendmail";
                        i = 0;
                        env[i++] = "AGENT=sendmail";
+                       env[i++] = "_FORCE_MAIL_LOCAL_=yes";
                        for (ep = environ; *ep != NULL; ep++)
                        {
                        for (ep = environ; *ep != NULL; ep++)
                        {
-                               if (strncmp(*ep, "TZ=", 3) == 0)
+                               if (strncmp(*ep, "TZ=", 3) == 0 ||
+                                   strncmp(*ep, "ISP=", 4) == 0 ||
+                                   strncmp(*ep, "SYSTYPE=", 8) == 0)
                                        env[i++] = *ep;
                        }
                                        env[i++] = *ep;
                        }
-                       env[i++] = NULL;
+                       env[i] = NULL;
+
+                       /* run disconnected from terminal */
+                       (void) setsid();
 
                        /* try to execute the mailer */
                        execve(m->m_mailer, pv, env);
                        saveerrno = errno;
                        syserr("Cannot exec %s", m->m_mailer);
 
                        /* try to execute the mailer */
                        execve(m->m_mailer, pv, env);
                        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);
                }
@@ -1258,10 +1390,33 @@ tryhost:
                mci->mci_pid = pid;
                (void) close(mpvect[0]);
                mci->mci_out = fdopen(mpvect[1], "w");
                mci->mci_pid = pid;
                (void) close(mpvect[0]);
                mci->mci_out = fdopen(mpvect[1], "w");
+               if (mci->mci_out == NULL)
+               {
+                       syserr("deliver: cannot create mailer output channel, fd=%d",
+                               mpvect[1]);
+                       (void) close(mpvect[1]);
+                       if (clever)
+                       {
+                               (void) close(rpvect[0]);
+                               (void) close(rpvect[1]);
+                       }
+                       rcode = EX_OSERR;
+                       goto give_up;
+               }
                if (clever)
                {
                        (void) close(rpvect[1]);
                        mci->mci_in = fdopen(rpvect[0], "r");
                if (clever)
                {
                        (void) close(rpvect[1]);
                        mci->mci_in = fdopen(rpvect[0], "r");
+                       if (mci->mci_in == NULL)
+                       {
+                               syserr("deliver: cannot create mailer input channel, fd=%d",
+                                       mpvect[1]);
+                               (void) close(rpvect[0]);
+                               fclose(mci->mci_out);
+                               mci->mci_out = NULL;
+                               rcode = EX_OSERR;
+                               goto give_up;
+                       }
                }
                else
                {
                }
                else
                {
@@ -1278,10 +1433,16 @@ 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: ");
-               mci_dump(mci);
+               mci_dump(mci, FALSE);
        }
 
        if (mci->mci_state != MCIS_OPEN)
        }
 
        if (mci->mci_state != MCIS_OPEN)
@@ -1289,7 +1450,7 @@ tryhost:
                /* couldn't open the mailer */
                rcode = mci->mci_exitstat;
                errno = mci->mci_errno;
                /* couldn't open the mailer */
                rcode = mci->mci_exitstat;
                errno = mci->mci_errno;
-#ifdef NAMED_BIND
+#if NAMED_BIND
                h_errno = mci->mci_herrno;
 #endif
                if (rcode == EX_OK)
                h_errno = mci->mci_herrno;
 #endif
                if (rcode == EX_OK)
@@ -1299,7 +1460,7 @@ tryhost:
                                rcode, mci->mci_state, firstsig);
                        rcode = EX_SOFTWARE;
                }
                                rcode, mci->mci_state, firstsig);
                        rcode = EX_SOFTWARE;
                }
-               else if (rcode == EX_TEMPFAIL && *curhost != '\0')
+               else if (rcode == EX_TEMPFAIL && curhost != NULL && *curhost != '\0')
                {
                        /* try next MX site */
                        goto tryhost;
                {
                        /* try next MX site */
                        goto tryhost;
@@ -1311,10 +1472,9 @@ tryhost:
                **  Format and send message.
                */
 
                **  Format and send message.
                */
 
-               putfromline(mci->mci_out, m, e);
-               (*e->e_puthdr)(mci->mci_out, m, e);
-               putline("\n", mci->mci_out, m);
-               (*e->e_putbody)(mci->mci_out, m, e, NULL);
+               putfromline(mci, e);
+               (*e->e_puthdr)(mci, e->e_header, e, 0);
+               (*e->e_putbody)(mci, e, NULL, 0);
 
                /* get the exit status */
                rcode = endmailer(mci, e, pv);
 
                /* get the exit status */
                rcode = endmailer(mci, e, pv);
@@ -1340,7 +1500,7 @@ tryhost:
                                if ((i = smtprcpt(to, m, mci, e)) != EX_OK)
                                {
                                        markfailure(e, to, i);
                                if ((i = smtprcpt(to, m, mci, e)) != EX_OK)
                                {
                                        markfailure(e, to, i);
-                                       giveresponse(i, m, mci, e);
+                                       giveresponse(i, m, mci, ctladdr, e);
                                }
                                else
                                {
                                }
                                else
                                {
@@ -1369,7 +1529,7 @@ tryhost:
                        if (!bitset(MCIF_CACHED, mci->mci_flags))
                                smtpquit(m, mci, e);
                }
                        if (!bitset(MCIF_CACHED, mci->mci_flags))
                                smtpquit(m, mci, e);
                }
-               if (rcode != EX_OK && *curhost != '\0')
+               if (rcode != EX_OK && curhost != NULL && *curhost != '\0')
                {
                        /* try next MX site */
                        goto tryhost;
                {
                        /* try next MX site */
                        goto tryhost;
@@ -1382,13 +1542,14 @@ tryhost:
                goto give_up;
        }
 #endif /* SMTP */
                goto give_up;
        }
 #endif /* SMTP */
-#ifdef NAMED_BIND
+#if NAMED_BIND
        if (ConfigLevel < 2)
                _res.options |= RES_DEFNAMES | RES_DNSRCH;      /* XXX */
 #endif
 
        /* arrange a return receipt if requested */
        if (ConfigLevel < 2)
                _res.options |= RES_DEFNAMES | RES_DNSRCH;      /* XXX */
 #endif
 
        /* arrange a return receipt if requested */
-       if (e->e_receiptto != NULL && bitnset(M_LOCALMAILER, m->m_flags))
+       if (rcode == EX_OK && e->e_receiptto != NULL &&
+           bitnset(M_LOCALMAILER, m->m_flags))
        {
                e->e_flags |= EF_SENDRECEIPT;
                /* do we want to send back more info? */
        {
                e->e_flags |= EF_SENDRECEIPT;
                /* do we want to send back more info? */
@@ -1403,7 +1564,7 @@ tryhost:
 
   give_up:
        if (tobuf[0] != '\0')
 
   give_up:
        if (tobuf[0] != '\0')
-               giveresponse(rcode, m, mci, e);
+               giveresponse(rcode, m, mci, ctladdr, 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)
@@ -1411,7 +1572,16 @@ tryhost:
                else
                {
                        to->q_flags |= QSENT;
                else
                {
                        to->q_flags |= QSENT;
+                       to->q_statdate = curtime();
                        e->e_nsent++;
                        e->e_nsent++;
+                       if (bitnset(M_LOCALMAILER, m->m_flags) &&
+                           (e->e_receiptto != NULL ||
+                            bitset(QPINGONSUCCESS, to->q_flags)))
+                       {
+                               to->q_flags |= QREPORT;
+                               fprintf(e->e_xfp, "%s... Successfully delivered\n",
+                                       to->q_paddr);
+                       }
                }
        }
 
                }
        }
 
@@ -1424,7 +1594,9 @@ tryhost:
                char wbuf[MAXLINE];
 
                /* make absolutely certain 0, 1, and 2 are in use */
                char wbuf[MAXLINE];
 
                /* make absolutely certain 0, 1, and 2 are in use */
-               sprintf(wbuf, "%s... end of deliver(%s)", e->e_to, m->m_name);
+               sprintf(wbuf, "%s... end of deliver(%s)",
+                       e->e_to == NULL ? "NO-TO-LIST" : e->e_to,
+                       m->m_name);
                checkfd012(wbuf);
        }
 #endif
                checkfd012(wbuf);
        }
 #endif
@@ -1457,12 +1629,23 @@ markfailure(e, q, rcode)
 {
        char buf[MAXLINE];
 
 {
        char buf[MAXLINE];
 
-       if (rcode == EX_OK)
-               return;
-       else if (rcode == EX_TEMPFAIL)
+       switch (rcode)
+       {
+         case EX_OK:
+               break;
+
+         case EX_TEMPFAIL:
+         case EX_IOERR:
+         case EX_OSERR:
                q->q_flags |= QQUEUEUP;
                q->q_flags |= QQUEUEUP;
-       else if (rcode != EX_IOERR && rcode != EX_OSERR)
+               break;
+
+         default:
                q->q_flags |= QBADADDR;
                q->q_flags |= QBADADDR;
+               break;
+       }
+       q->q_statdate = curtime();
+       q->q_statmta = newstr(CurHostName);
 }
 \f/*
 **  ENDMAILER -- Wait for mailer to terminate.
 }
 \f/*
 **  ENDMAILER -- Wait for mailer to terminate.
@@ -1494,9 +1677,9 @@ endmailer(mci, e, pv)
 
        /* close any connections */
        if (mci->mci_in != NULL)
 
        /* close any connections */
        if (mci->mci_in != NULL)
-               (void) xfclose(mci->mci_in, pv[0], "mci_in");
+               (void) xfclose(mci->mci_in, mci->mci_mailer->m_name, "mci_in");
        if (mci->mci_out != NULL)
        if (mci->mci_out != NULL)
-               (void) xfclose(mci->mci_out, pv[0], "mci_out");
+               (void) xfclose(mci->mci_out, mci->mci_mailer->m_name, "mci_out");
        mci->mci_in = mci->mci_out = NULL;
        mci->mci_state = MCIS_CLOSED;
 
        mci->mci_in = mci->mci_out = NULL;
        mci->mci_state = MCIS_CLOSED;
 
@@ -1519,10 +1702,11 @@ endmailer(mci, e, pv)
        }
 
        /* it died a horrid death */
        }
 
        /* it died a horrid death */
-       syserr("mailer %s died with signal %o", pv[0], st);
+       syserr("451 mailer %s died with signal %o",
+               mci->mci_mailer->m_name, st);
 
        /* log the arguments */
 
        /* log the arguments */
-       if (e->e_xfp != NULL)
+       if (pv != NULL && e->e_xfp != NULL)
        {
                register char **av;
 
        {
                register char **av;
 
@@ -1545,6 +1729,8 @@ endmailer(mci, e, pv)
 **             m -- the mailer info for this mailer.
 **             mci -- the mailer connection info -- can be NULL if the
 **                     response is given before the connection is made.
 **             m -- the mailer info for this mailer.
 **             mci -- the mailer connection info -- can be NULL if the
 **                     response is given before the connection is made.
+**             ctladdr -- the controlling address for the recipient
+**                     address(es).
 **             e -- the current envelope.
 **
 **     Returns:
 **             e -- the current envelope.
 **
 **     Returns:
@@ -1555,10 +1741,11 @@ endmailer(mci, e, pv)
 **             ExitStat may be set.
 */
 
 **             ExitStat may be set.
 */
 
-giveresponse(stat, m, mci, e)
+giveresponse(stat, m, mci, ctladdr, e)
        int stat;
        register MAILER *m;
        register MCI *mci;
        int stat;
        register MAILER *m;
        register MCI *mci;
+       ADDRESS *ctladdr;
        ENVELOPE *e;
 {
        register const char *statmsg;
        ENVELOPE *e;
 {
        register const char *statmsg;
@@ -1590,7 +1777,7 @@ giveresponse(stat, m, mci, e)
        else if (stat == EX_TEMPFAIL)
        {
                (void) strcpy(buf, SysExMsg[i] + 1);
        else if (stat == EX_TEMPFAIL)
        {
                (void) strcpy(buf, SysExMsg[i] + 1);
-#ifdef NAMED_BIND
+#if NAMED_BIND
                if (h_errno == TRY_AGAIN)
                        statmsg = errstring(h_errno+E_DNSBASE);
                else
                if (h_errno == TRY_AGAIN)
                        statmsg = errstring(h_errno+E_DNSBASE);
                else
@@ -1601,8 +1788,6 @@ giveresponse(stat, m, mci, e)
                        else
                        {
 #ifdef SMTP
                        else
                        {
 #ifdef SMTP
-                               extern char SmtpError[];
-
                                statmsg = SmtpError;
 #else /* SMTP */
                                statmsg = NULL;
                                statmsg = SmtpError;
 #else /* SMTP */
                                statmsg = NULL;
@@ -1616,11 +1801,11 @@ giveresponse(stat, m, mci, e)
                }
                statmsg = buf;
        }
                }
                statmsg = buf;
        }
-#ifdef NAMED_BIND
+#if NAMED_BIND
        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
@@ -1639,11 +1824,20 @@ giveresponse(stat, m, mci, e)
        */
 
        if (stat == EX_OK || stat == EX_TEMPFAIL)
        */
 
        if (stat == EX_OK || stat == EX_TEMPFAIL)
-               message(&statmsg[4], errstring(errno));
+       {
+               extern char MsgBuf[];
+
+               message("%s", &statmsg[4]);
+               if (stat == EX_TEMPFAIL && e->e_xfp != NULL)
+                       fprintf(e->e_xfp, "%s\n", &MsgBuf[4]);
+       }
        else
        {
        else
        {
+               char mbuf[8];
+
                Errors++;
                Errors++;
-               usrerr(statmsg, errstring(errno));
+               sprintf(mbuf, "%.3s %%s", statmsg);
+               usrerr(mbuf, &statmsg[4]);
        }
 
        /*
        }
 
        /*
@@ -1654,29 +1848,38 @@ giveresponse(stat, m, mci, 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], e);
+               logdelivery(m, mci, &statmsg[4], ctladdr, e);
+
+       if (tTd(11, 2))
+               printf("giveresponse: stat=%d, e->e_message=%s\n",
+                       stat, e->e_message == NULL ? "<NULL>" : e->e_message);
 
        if (stat != EX_TEMPFAIL)
                setstat(stat);
 
        if (stat != EX_TEMPFAIL)
                setstat(stat);
-       if (stat != EX_OK)
+       if (stat != EX_OK && (stat != EX_TEMPFAIL || e->e_message == NULL))
        {
                if (e->e_message != NULL)
                        free(e->e_message);
                e->e_message = newstr(&statmsg[4]);
        }
        errno = 0;
        {
                if (e->e_message != NULL)
                        free(e->e_message);
                e->e_message = newstr(&statmsg[4]);
        }
        errno = 0;
-#ifdef NAMED_BIND
+#if NAMED_BIND
        h_errno = 0;
 #endif
 }
 \f/*
 **  LOGDELIVERY -- log the delivery in the system log
 **
        h_errno = 0;
 #endif
 }
 \f/*
 **  LOGDELIVERY -- log the delivery in the system log
 **
+**     Care is taken to avoid logging lines that are too long, because
+**     some versions of syslog have an unfortunate proclivity for core
+**     dumping.  This is a hack, to be sure, that is at best empirical.
+**
 **     Parameters:
 **             m -- the mailer info.  Can be NULL for initial queue.
 **             mci -- the mailer connection info -- can be NULL if the
 **                     log is occuring when no connection is active.
 **             stat -- the message to print for the status.
 **     Parameters:
 **             m -- the mailer info.  Can be NULL for initial queue.
 **             mci -- the mailer connection info -- can be NULL if the
 **                     log is occuring when no connection is active.
 **             stat -- the message to print for the status.
+**             ctladdr -- the controlling address for the to list.
 **             e -- the current envelope.
 **
 **     Returns:
 **             e -- the current envelope.
 **
 **     Returns:
@@ -1686,21 +1889,42 @@ giveresponse(stat, m, mci, e)
 **             none
 */
 
 **             none
 */
 
-logdelivery(m, mci, stat, e)
+logdelivery(m, mci, stat, ctladdr, e)
        MAILER *m;
        register MCI *mci;
        char *stat;
        MAILER *m;
        register MCI *mci;
        char *stat;
+       ADDRESS *ctladdr;
        register ENVELOPE *e;
 {
 # ifdef LOG
        register ENVELOPE *e;
 {
 # ifdef LOG
+       register char *bp;
+       register char *p;
+       int l;
        char buf[512];
 
        char buf[512];
 
-       (void) sprintf(buf, "delay=%s", pintvl(curtime() - e->e_ctime, TRUE));
+#  if (SYSLOG_BUFSIZE) >= 256
+       bp = buf;
+       if (ctladdr != NULL)
+       {
+               strcpy(bp, ", ctladdr=");
+               strcat(bp, shortenstring(ctladdr->q_paddr, 83));
+               bp += strlen(bp);
+               if (bitset(QGOODUID, ctladdr->q_flags))
+               {
+                       (void) sprintf(bp, " (%d/%d)",
+                                       ctladdr->q_uid, ctladdr->q_gid);
+                       bp += strlen(bp);
+               }
+       }
+
+       (void) sprintf(bp, ", delay=%s", pintvl(curtime() - e->e_ctime, TRUE));
+       bp += strlen(bp);
 
        if (m != NULL)
        {
 
        if (m != NULL)
        {
-               (void) strcat(buf, ", mailer=");
-               (void) strcat(buf, m->m_name);
+               (void) strcpy(bp, ", mailer=");
+               (void) strcat(bp, m->m_name);
+               bp += strlen(bp);
        }
 
        if (mci != NULL && mci->mci_host != NULL)
        }
 
        if (mci != NULL && mci->mci_host != NULL)
@@ -1709,28 +1933,133 @@ logdelivery(m, mci, stat, e)
                extern SOCKADDR CurHostAddr;
 # endif
 
                extern SOCKADDR CurHostAddr;
 # endif
 
-               (void) strcat(buf, ", relay=");
-               (void) strcat(buf, mci->mci_host);
+               (void) strcpy(bp, ", relay=");
+               (void) strcat(bp, mci->mci_host);
 
 # ifdef DAEMON
 
 # ifdef DAEMON
-               (void) strcat(buf, " (");
-               (void) strcat(buf, anynet_ntoa(&CurHostAddr));
-               (void) strcat(buf, ")");
+               (void) strcat(bp, " [");
+               (void) strcat(bp, anynet_ntoa(&CurHostAddr));
+               (void) strcat(bp, "]");
 # endif
        }
 # endif
        }
-       else
+       else if (strcmp(stat, "queued") != 0)
        {
                char *p = macvalue('h', e);
 
                if (p != NULL && p[0] != '\0')
                {
        {
                char *p = macvalue('h', e);
 
                if (p != NULL && p[0] != '\0')
                {
-                       (void) strcat(buf, ", relay=");
-                       (void) strcat(buf, p);
+                       (void) strcpy(bp, ", relay=");
+                       (void) strcat(bp, p);
                }
        }
                }
        }
+       bp += strlen(bp);
+
+#define STATLEN                (((SYSLOG_BUFSIZE) - 100) / 4)
+#if (STATLEN) < 63
+# undef STATLEN
+# define STATLEN       63
+#endif
+#if (STATLEN) > 203
+# undef STATLEN
+# define STATLEN       203
+#endif
+
+       if ((bp - buf) > (sizeof buf - ((STATLEN) + 20)))
+       {
+               /* desperation move -- truncate data */
+               bp = buf + sizeof buf - ((STATLEN) + 17);
+               strcpy(bp, "...");
+               bp += 3;
+       }
+
+       (void) strcpy(bp, ", stat=");
+       bp += strlen(bp);
+
+       (void) strcpy(bp, shortenstring(stat, (STATLEN)));
                
                
-       syslog(LOG_INFO, "%s: to=%s, %s, stat=%s",
-              e->e_id, e->e_to, buf, stat);
+       l = SYSLOG_BUFSIZE - 100 - strlen(buf);
+       p = e->e_to;
+       while (strlen(p) >= l)
+       {
+               register char *q = strchr(p + l, ',');
+
+               if (q == NULL)
+                       break;
+               syslog(LOG_INFO, "%s: to=%.*s [more]%s",
+                       e->e_id, ++q - p, p, buf);
+               p = q;
+       }
+       syslog(LOG_INFO, "%s: to=%s%s", e->e_id, p, buf);
+
+#  else                /* we have a very short log buffer size */
+
+       l = SYSLOG_BUFSIZE - 85;
+       p = e->e_to;
+       while (strlen(p) >= l)
+       {
+               register char *q = strchr(p + l, ',');
+
+               if (q == NULL)
+                       break;
+               syslog(LOG_INFO, "%s: to=%.*s [more]",
+                       e->e_id, ++q - p, p);
+               p = q;
+       }
+       syslog(LOG_INFO, "%s: to=%s", e->e_id, p);
+
+       if (ctladdr != NULL)
+       {
+               bp = buf;
+               strcpy(buf, "ctladdr=");
+               bp += strlen(buf);
+               strcpy(bp, shortenstring(ctladdr->q_paddr, 83));
+               bp += strlen(buf);
+               if (bitset(QGOODUID, ctladdr->q_flags))
+               {
+                       (void) sprintf(bp, " (%d/%d)",
+                                       ctladdr->q_uid, ctladdr->q_gid);
+                       bp += strlen(bp);
+               }
+               syslog(LOG_INFO, "%s: %s", e->e_id, buf);
+       }
+       bp = buf;
+       sprintf(bp, "delay=%s", pintvl(curtime() - e->e_ctime, TRUE));
+       bp += strlen(bp);
+
+       if (m != NULL)
+       {
+               sprintf(bp, ", mailer=%s", m->m_name);
+               bp += strlen(bp);
+       }
+       syslog(LOG_INFO, "%s: %s", e->e_id, buf);
+
+       buf[0] = '\0';
+       if (mci != NULL && mci->mci_host != NULL)
+       {
+# ifdef DAEMON
+               extern SOCKADDR CurHostAddr;
+# endif
+
+               sprintf(buf, "relay=%s", mci->mci_host);
+
+# ifdef DAEMON
+               (void) strcat(buf, " [");
+               (void) strcat(buf, anynet_ntoa(&CurHostAddr));
+               (void) strcat(buf, "]");
+# endif
+       }
+       else if (strcmp(stat, "queued") != 0)
+       {
+               char *p = macvalue('h', e);
+
+               if (p != NULL && p[0] != '\0')
+                       sprintf(buf, "relay=%s", p);
+       }
+       if (buf[0] != '\0')
+               syslog(LOG_INFO, "%s: %s", e->e_id, buf);
+
+       syslog(LOG_INFO, "%s: stat=%s", e->e_id, shortenstring(stat, 63));
+#  endif /* short log buffer */
 # endif /* LOG */
 }
 \f/*
 # endif /* LOG */
 }
 \f/*
@@ -1746,8 +2075,8 @@ logdelivery(m, mci, stat, e)
 **     this kind of antique garbage????
 **
 **     Parameters:
 **     this kind of antique garbage????
 **
 **     Parameters:
-**             fp -- the file to output to.
-**             m -- the mailer describing this entry.
+**             mci -- the connection information.
+**             e -- the envelope.
 **
 **     Returns:
 **             none
 **
 **     Returns:
 **             none
@@ -1756,20 +2085,19 @@ logdelivery(m, mci, stat, e)
 **             outputs some text to fp.
 */
 
 **             outputs some text to fp.
 */
 
-putfromline(fp, m, e)
-       register FILE *fp;
-       register MAILER *m;
+putfromline(mci, e)
+       register MCI *mci;
        ENVELOPE *e;
 {
        char *template = "\201l\n";
        char buf[MAXLINE];
        extern char SentDate[];
 
        ENVELOPE *e;
 {
        char *template = "\201l\n";
        char buf[MAXLINE];
        extern char SentDate[];
 
-       if (bitnset(M_NHDR, m->m_flags))
+       if (bitnset(M_NHDR, mci->mci_mailer->m_flags))
                return;
 
 # ifdef UGLYUUCP
                return;
 
 # ifdef UGLYUUCP
-       if (bitnset(M_UGLYUUCP, m->m_flags))
+       if (bitnset(M_UGLYUUCP, mci->mci_mailer->m_flags))
        {
                char *bang;
                char xbuf[MAXLINE];
        {
                char *bang;
                char xbuf[MAXLINE];
@@ -1790,17 +2118,17 @@ putfromline(fp, m, e)
        }
 # endif /* UGLYUUCP */
        expand(template, buf, &buf[sizeof buf - 1], e);
        }
 # endif /* UGLYUUCP */
        expand(template, buf, &buf[sizeof buf - 1], e);
-       putline(buf, fp, m);
+       putline(buf, mci);
 }
 \f/*
 **  PUTBODY -- put the body of a message.
 **
 **     Parameters:
 }
 \f/*
 **  PUTBODY -- put the body of a message.
 **
 **     Parameters:
-**             fp -- file to output onto.
-**             m -- a mailer descriptor to control output format.
+**             mci -- the connection information.
 **             e -- the envelope to put out.
 **             separator -- if non-NULL, a message separator that must
 **                     not be permitted in the resulting message.
 **             e -- the envelope to put out.
 **             separator -- if non-NULL, a message separator that must
 **                     not be permitted in the resulting message.
+**             flags -- to modify the behaviour.
 **
 **     Returns:
 **             none.
 **
 **     Returns:
 **             none.
@@ -1809,11 +2137,16 @@ putfromline(fp, m, e)
 **             The message is written onto fp.
 */
 
 **             The message is written onto fp.
 */
 
-putbody(fp, m, e, separator)
-       FILE *fp;
-       MAILER *m;
+/* 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 */
+
+putbody(mci, e, separator, flags)
+       register MCI *mci;
        register ENVELOPE *e;
        char *separator;
        register ENVELOPE *e;
        char *separator;
+       int flags;
 {
        char buf[MAXLINE];
 
 {
        char buf[MAXLINE];
 
@@ -1821,50 +2154,236 @@ putbody(fp, m, e, separator)
        **  Output the body of the message
        */
 
        **  Output the body of the message
        */
 
+       if (e->e_dfp == NULL && e->e_df != NULL)
+       {
+               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);
+       }
        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;
                }
                }
+               putline("<<< No Message Collected >>>", mci);
+               goto endofmessage;
+       }
+       if (e->e_dfino == (ino_t) 0)
+       {
+               struct stat stbuf;
+
+               if (fstat(fileno(e->e_dfp), &stbuf) < 0)
+                       e->e_dfino = -1;
                else
                else
-                       putline("<<< No Message Collected >>>", fp, m);
+               {
+                       e->e_dfdev = stbuf.st_dev;
+                       e->e_dfino = stbuf.st_ino;
+               }
        }
        }
-       if (e->e_dfp != NULL)
+       rewind(e->e_dfp);
+
+       if (bitset(MCIF_CVT8TO7, mci->mci_flags))
        {
        {
-               rewind(e->e_dfp);
-               while (!ferror(fp) && fgets(buf, sizeof buf, e->e_dfp) != NULL)
+               /*
+               **  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)
                {
                {
-                       if (buf[0] == 'F' && bitnset(M_ESCFROM, m->m_flags) &&
-                           strncmp(buf, "From ", 5) == 0)
-                               (void) putc('>', fp);
-                       if (buf[0] == '-' && buf[1] == '-' && separator != NULL)
-                       {
-                               /* possible separator */
-                               int sl = strlen(separator);
+                       sprintf(buf, "Content-Type: text/plain; charset=%s",
+                               defcharset(e));
+                       putline(buf, mci);
+               }
 
 
-                               if (strncmp(&buf[2], separator, sl) == 0)
-                                       (void) putc(' ', fp);
-                       }
-                       putline(buf, fp, m);
+               /* now do the hard work */
+               mime8to7(mci, e->e_header, e, NULL);
+       }
+       else
+       {
+               int ostate;
+               register char *bp;
+               register char *pbp;
+               register int c;
+               int padc;
+               char *buflim;
+               int pos;
+               char peekbuf[10];
+
+               /* we can pass it through unmodified */
+               if (bitset(MCIF_INHEADER, mci->mci_flags))
+               {
+                       putline("", mci);
+                       mci->mci_flags &= ~MCIF_INHEADER;
                }
 
                }
 
-               if (ferror(e->e_dfp))
+               /* 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: read error");
-                       ExitStat = EX_IOERR;
+                       register char *xp;
+
+                       if (pbp > peekbuf)
+                               c = *--pbp;
+                       else if ((c = fgetc(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)
+                                               fputc(padc, TrafficLogFile);
+                                       for (xp = buf; xp < bp; xp++)
+                                               fputc(*xp, TrafficLogFile);
+                                       if (c == '\n')
+                                               fputs(mci->mci_mailer->m_eol,
+                                                     TrafficLogFile);
+                               }
+                               if (padc != EOF)
+                               {
+                                       fputc(padc, mci->mci_out);
+                                       pos++;
+                               }
+                               for (xp = buf; xp < bp; xp++)
+                                       fputc(*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)
+                                       fputc(c, TrafficLogFile);
+                               putc(c, mci->mci_out);
+                               pos++;
+                               ostate = c == '\n' ? OS_HEAD : OS_INLINE;
+                               break;
+                       }
                }
        }
 
                }
        }
 
+       if (ferror(e->e_dfp))
+       {
+               syserr("putbody: %s: read error", e->e_df);
+               ExitStat = EX_IOERR;
+       }
+
+endofmessage:
        /* some mailers want extra blank line at end of message */
        /* some mailers want extra blank line at end of message */
-       if (bitnset(M_BLANKEND, m->m_flags) && buf[0] != '\0' && buf[0] != '\n')
-               putline("", fp, m);
+       if (bitnset(M_BLANKEND, mci->mci_mailer->m_flags) &&
+           buf[0] != '\0' && buf[0] != '\n')
+               putline("", mci);
 
 
-       (void) fflush(fp);
-       if (ferror(fp) && errno != EPIPE)
+       (void) fflush(mci->mci_out);
+       if (ferror(mci->mci_out) && errno != EPIPE)
        {
                syserr("putbody: write error");
                ExitStat = EX_IOERR;
        {
                syserr("putbody: write error");
                ExitStat = EX_IOERR;
@@ -1929,6 +2448,7 @@ mailfile(filename, ctladdr, e)
        {
                /* child -- actually write to file */
                struct stat stb;
        {
                /* child -- actually write to file */
                struct stat stb;
+               MCI mcibuf;
 
                (void) setsignal(SIGINT, SIG_DFL);
                (void) setsignal(SIGHUP, SIG_DFL);
 
                (void) setsignal(SIGINT, SIG_DFL);
                (void) setsignal(SIGHUP, SIG_DFL);
@@ -1945,9 +2465,7 @@ mailfile(filename, ctladdr, e)
 
                if (bitset(0111, stb.st_mode))
                        exit(EX_CANTCREAT);
 
                if (bitset(0111, stb.st_mode))
                        exit(EX_CANTCREAT);
-               if (ctladdr == NULL)
-                       ctladdr = &e->e_from;
-               else
+               if (ctladdr != NULL)
                {
                        /* ignore setuid and setgid bits */
                        mode &= ~(S_ISGID|S_ISUID);
                {
                        /* ignore setuid and setgid bits */
                        mode &= ~(S_ISGID|S_ISUID);
@@ -1966,23 +2484,23 @@ mailfile(filename, ctladdr, e)
 
                if (!bitset(S_ISGID, mode) || setgid(stb.st_gid) < 0)
                {
 
                if (!bitset(S_ISGID, mode) || setgid(stb.st_gid) < 0)
                {
-                       if (ctladdr->q_uid == 0)
-                       {
-                               (void) initgroups(DefUser, DefGid);
-                       }
-                       else
-                       {
+                       if (ctladdr != NULL && ctladdr->q_uid != 0)
                                (void) initgroups(ctladdr->q_ruser ?
                                        ctladdr->q_ruser : ctladdr->q_user,
                                        ctladdr->q_gid);
                                (void) initgroups(ctladdr->q_ruser ?
                                        ctladdr->q_ruser : ctladdr->q_user,
                                        ctladdr->q_gid);
-                       }
+                       else if (FileMailer != NULL && FileMailer->m_gid != 0)
+                               (void) initgroups(DefUser, FileMailer->m_gid);
+                       else
+                               (void) initgroups(DefUser, DefGid);
                }
                if (!bitset(S_ISUID, mode) || setuid(stb.st_uid) < 0)
                {
                }
                if (!bitset(S_ISUID, mode) || setuid(stb.st_uid) < 0)
                {
-                       if (ctladdr->q_uid == 0)
-                               (void) setuid(DefUid);
-                       else
+                       if (ctladdr != NULL && ctladdr->q_uid != 0)
                                (void) setuid(ctladdr->q_uid);
                                (void) setuid(ctladdr->q_uid);
+                       else if (FileMailer != NULL && FileMailer->m_uid != 0)
+                               (void) setuid(FileMailer->m_uid);
+                       else
+                               (void) setuid(DefUid);
                }
                FileName = filename;
                LineNumber = 0;
                }
                FileName = filename;
                LineNumber = 0;
@@ -1993,11 +2511,16 @@ mailfile(filename, ctladdr, e)
                        exit(EX_CANTCREAT);
                }
 
                        exit(EX_CANTCREAT);
                }
 
-               putfromline(f, FileMailer, e);
-               (*e->e_puthdr)(f, FileMailer, e);
-               putline("\n", f, FileMailer);
-               (*e->e_putbody)(f, FileMailer, e, NULL);
-               putline("\n", f, FileMailer);
+               bzero(&mcibuf, sizeof mcibuf);
+               mcibuf.mci_mailer = FileMailer;
+               mcibuf.mci_out = f;
+               if (bitnset(M_7BITS, FileMailer->m_flags))
+                       mcibuf.mci_flags |= MCIF_7BIT;
+
+               putfromline(&mcibuf, e);
+               (*e->e_puthdr)(&mcibuf, e->e_header, e, 0);
+               (*e->e_putbody)(&mcibuf, e, NULL, 0);
+               putline("\n", &mcibuf);
                if (ferror(f))
                {
                        message("451 I/O error: %s", errstring(errno));
                if (ferror(f))
                {
                        message("451 I/O error: %s", errstring(errno));
@@ -2056,7 +2579,7 @@ hostsignature(m, host, e)
        register STAB *s;
        int i;
        int len;
        register STAB *s;
        int i;
        int len;
-#ifdef NAMED_BIND
+#if NAMED_BIND
        int nmx;
        auto int rcode;
        char *hp;
        int nmx;
        auto int rcode;
        char *hp;
@@ -2076,13 +2599,6 @@ hostsignature(m, host, e)
                return host;
        }
 
                return host;
        }
 
-       /*
-       **  If it is a numeric address, just return it.
-       */
-
-       if (host[0] == '[')
-               return host;
-
        /*
        **  Look it up in the symbol table.
        */
        /*
        **  Look it up in the symbol table.
        */
@@ -2095,7 +2611,7 @@ hostsignature(m, host, e)
        **  Not already there -- create a signature.
        */
 
        **  Not already there -- create a signature.
        */
 
-#ifdef NAMED_BIND
+#if NAMED_BIND
        if (ConfigLevel < 2)
        {
                oldoptions = _res.options;
        if (ConfigLevel < 2)
        {
                oldoptions = _res.options;
@@ -2113,13 +2629,12 @@ hostsignature(m, host, e)
                if (nmx <= 0)
                {
                        register MCI *mci;
                if (nmx <= 0)
                {
                        register MCI *mci;
-                       extern int errno;
 
                        /* update the connection info for this host */
                        mci = mci_get(hp, m);
                        mci->mci_exitstat = rcode;
                        mci->mci_errno = errno;
 
                        /* update the connection info for this host */
                        mci = mci_get(hp, m);
                        mci->mci_exitstat = rcode;
                        mci->mci_errno = errno;
-#ifdef NAMED_BIND
+#if NAMED_BIND
                        mci->mci_herrno = h_errno;
 #endif
 
                        mci->mci_herrno = h_errno;
 #endif
 
@@ -2167,3 +2682,55 @@ hostsignature(m, host, e)
                printf("hostsignature(%s) = %s\n", host, s->s_hostsig);
        return s->s_hostsig;
 }
                printf("hostsignature(%s) = %s\n", host, s->s_hostsig);
        return s->s_hostsig;
 }
+\f/*
+**  SETSTATUS -- set the address status for return messages
+**
+**     Parameters:
+**             a -- the address to set.
+**             msg -- the text of the message, which must be in standard
+**                     SMTP form (3 digits, a space, and a message).
+**
+**     Returns:
+**             none.
+*/
+
+setstatus(a, msg)
+       register ADDRESS *a;
+       char *msg;
+{
+       char buf[MAXLINE];
+
+       if (a->q_rstatus != NULL)
+               free(a->q_rstatus);
+       if (strlen(msg) > 4)
+       {
+               register char *p, *q;
+               int parenlev = 0;
+
+               strncpy(buf, msg, 4);
+               p = &buf[4];
+               *p++ = '(';
+               for (q = &msg[4]; *q != '\0'; q++)
+               {
+                       switch (*q)
+                       {
+                         case '(':
+                               parenlev++;
+                               break;
+
+                         case ')':
+                               if (parenlev > 0)
+                                       parenlev--;
+                               else
+                                       *p++ = '\\';
+                               break;
+                       }
+                       *p++ = *q;
+               }
+               while (parenlev-- >= 0)
+                       *p++ = ')';
+               *p++ = '\0';
+               msg = buf;
+       }
+       a->q_rstatus = newstr(msg);
+}