fix wildcard MX handling (option W no longer needed); fix
[unix-history] / usr / src / usr.sbin / sendmail / src / deliver.c
index b5d583f..8733dba 100644 (file)
@@ -7,7 +7,7 @@
  */
 
 #ifndef lint
  */
 
 #ifndef lint
-static char sccsid[] = "@(#)deliver.c  5.56 (Berkeley) %G%";
+static char sccsid[] = "@(#)deliver.c  6.14 (Berkeley) %G%";
 #endif /* not lint */
 
 #include "sendmail.h"
 #endif /* not lint */
 
 #include "sendmail.h"
@@ -17,7 +17,6 @@ static char sccsid[] = "@(#)deliver.c 5.56 (Berkeley) %G%";
 #include <fcntl.h>
 #include <errno.h>
 #ifdef NAMED_BIND
 #include <fcntl.h>
 #include <errno.h>
 #ifdef NAMED_BIND
-#include <sys/param.h>
 #include <arpa/nameser.h>
 #include <resolv.h>
 #endif
 #include <arpa/nameser.h>
 #include <resolv.h>
 #endif
@@ -55,19 +54,23 @@ deliver(e, firstto)
        register char *p;
        register MAILER *m;             /* mailer for this recipient */
        ADDRESS *ctladdr;
        register char *p;
        register MAILER *m;             /* mailer for this recipient */
        ADDRESS *ctladdr;
+       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 */
        int rcode;                      /* response code */
        char *from;                     /* pointer to from person */
        register ADDRESS *to = firstto;
        bool clever = FALSE;            /* running user smtp to this mailer */
        ADDRESS *tochain = NULL;        /* chain of users in this mailer call */
        int rcode;                      /* response code */
        char *from;                     /* pointer to from person */
+       char *firstsig;                 /* signature of firstto */
        char *pv[MAXPV+1];
        char tobuf[MAXLINE-50];         /* text line of to people */
        char buf[MAXNAME];
        char tfrombuf[MAXNAME];         /* translated from person */
        char rpathbuf[MAXNAME];         /* translated return path */
        char *pv[MAXPV+1];
        char tobuf[MAXLINE-50];         /* text line of to people */
        char buf[MAXNAME];
        char tfrombuf[MAXNAME];         /* translated from person */
        char rpathbuf[MAXNAME];         /* translated return path */
-       extern bool checkcompat();
+       extern int checkcompat();
        extern ADDRESS *getctladdr();
        extern char *remotename();
        extern ADDRESS *getctladdr();
        extern char *remotename();
+       extern MCI *openmailer();
+       extern char *hostsignature();
 
        errno = 0;
        if (!ForceMail && bitset(QDONTSEND|QPSEUDO, to->q_flags))
 
        errno = 0;
        if (!ForceMail && bitset(QDONTSEND|QPSEUDO, to->q_flags))
@@ -109,7 +112,7 @@ deliver(e, firstto)
                        e->e_to = to->q_paddr;
                        message(Arpa_Info, "queued");
                        if (LogLevel > 4)
                        e->e_to = to->q_paddr;
                        message(Arpa_Info, "queued");
                        if (LogLevel > 4)
-                               logdelivery("queued");
+                               logdelivery("queued", e);
                }
                e->e_to = NULL;
                return (0);
                }
                e->e_to = NULL;
                return (0);
@@ -127,14 +130,14 @@ deliver(e, firstto)
        */
 
        /* rewrite from address, using rewriting rules */
        */
 
        /* rewrite from address, using rewriting rules */
-       (void) strcpy(rpathbuf, remotename(e->e_returnpath, m, TRUE, TRUE));
+       (void) strcpy(rpathbuf, remotename(e->e_returnpath, m, TRUE, TRUE, e));
        if (e->e_returnpath == e->e_sender)
        {
                from = rpathbuf;
        }
        else
        {
        if (e->e_returnpath == e->e_sender)
        {
                from = rpathbuf;
        }
        else
        {
-               (void) strcpy(tfrombuf, remotename(e->e_sender, m, TRUE, TRUE));
+               (void) strcpy(tfrombuf, remotename(e->e_sender, m, TRUE, TRUE, e));
                from = tfrombuf;
        }
 
                from = tfrombuf;
        }
 
@@ -165,7 +168,7 @@ deliver(e, firstto)
 
        for (mvp = m->m_argv; (p = *++mvp) != NULL; )
        {
 
        for (mvp = m->m_argv; (p = *++mvp) != NULL; )
        {
-               while ((p = index(p, '\001')) != NULL)
+               while ((p = strchr(p, '\001')) != NULL)
                        if (*++p == 'u')
                                break;
                if (p != NULL)
                        if (*++p == 'u')
                                break;
                if (p != NULL)
@@ -193,11 +196,11 @@ deliver(e, firstto)
 # ifdef SMTP
                clever = TRUE;
                *pvp = NULL;
 # ifdef SMTP
                clever = TRUE;
                *pvp = NULL;
-# else SMTP
+# else /* SMTP */
                /* oops!  we don't implement SMTP */
                syserr("SMTP style mailer");
                return (EX_SOFTWARE);
                /* oops!  we don't implement SMTP */
                syserr("SMTP style mailer");
                return (EX_SOFTWARE);
-# endif SMTP
+# endif /* SMTP */
        }
 
        /*
        }
 
        /*
@@ -210,6 +213,7 @@ deliver(e, firstto)
        tobuf[0] = '\0';
        e->e_to = tobuf;
        ctladdr = NULL;
        tobuf[0] = '\0';
        e->e_to = tobuf;
        ctladdr = NULL;
+       firstsig = hostsignature(firstto->q_mailer, firstto->q_host, e);
        for (; to != NULL; to = to->q_next)
        {
                /* avoid sending multiple recipients to dumb mailers */
        for (; to != NULL; to = to->q_next)
        {
                /* avoid sending multiple recipients to dumb mailers */
@@ -218,8 +222,8 @@ deliver(e, firstto)
 
                /* if already sent or not for this host, don't send */
                if (bitset(QDONTSEND, to->q_flags) ||
 
                /* if already sent or not for this host, don't send */
                if (bitset(QDONTSEND, to->q_flags) ||
-                   strcmp(to->q_host, host) != 0 ||
-                   to->q_mailer != firstto->q_mailer)
+                   to->q_mailer != firstto->q_mailer ||
+                   strcmp(hostsignature(to->q_mailer, to->q_host, e), firstsig) != 0)
                        continue;
 
                /* avoid overflowing tobuf */
                        continue;
 
                /* avoid overflowing tobuf */
@@ -239,6 +243,11 @@ deliver(e, firstto)
                user = to->q_user;
                e->e_to = to->q_paddr;
                to->q_flags |= QDONTSEND;
                user = to->q_user;
                e->e_to = to->q_paddr;
                to->q_flags |= QDONTSEND;
+               if (tTd(10, 5))
+               {
+                       printf("deliver: QDONTSEND ");
+                       printaddr(to, FALSE);
+               }
 
                /*
                **  Check to see that these people are allowed to
 
                /*
                **  Check to see that these people are allowed to
@@ -252,9 +261,10 @@ deliver(e, firstto)
                        giveresponse(EX_UNAVAILABLE, m, e);
                        continue;
                }
                        giveresponse(EX_UNAVAILABLE, m, e);
                        continue;
                }
-               if (!checkcompat(to))
+               rcode = checkcompat(to, e);
+               if (rcode != EX_OK)
                {
                {
-                       giveresponse(EX_UNAVAILABLE, m, e);
+                       giveresponse(rcode, m, e);
                        continue;
                }
 
                        continue;
                }
 
@@ -265,13 +275,8 @@ deliver(e, firstto)
 
                if (bitnset(M_STRIPQ, m->m_flags))
                {
 
                if (bitnset(M_STRIPQ, m->m_flags))
                {
-                       stripquotes(user, TRUE);
-                       stripquotes(host, TRUE);
-               }
-               else
-               {
-                       stripquotes(user, FALSE);
-                       stripquotes(host, FALSE);
+                       stripquotes(user);
+                       stripquotes(host);
                }
 
                /* hack attack -- delivermail compatibility */
                }
 
                /* hack attack -- delivermail compatibility */
@@ -301,16 +306,13 @@ 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 == LocalMailer)
+               if (m == FileMailer)
                {
                {
-                       if (user[0] == '/')
-                       {
-                               rcode = mailfile(user, getctladdr(to));
-                               giveresponse(rcode, m, e);
-                               if (rcode == EX_OK)
-                                       to->q_flags |= QSENT;
-                               continue;
-                       }
+                       rcode = mailfile(user, getctladdr(to), e);
+                       giveresponse(rcode, m, e);
+                       if (rcode == EX_OK)
+                               to->q_flags |= QSENT;
+                       continue;
                }
 
                /*
                }
 
                /*
@@ -382,81 +384,108 @@ deliver(e, firstto)
        if (ConfigLevel < 2)
                _res.options &= ~(RES_DEFNAMES | RES_DNSRCH);   /* XXX */
 #endif
        if (ConfigLevel < 2)
                _res.options &= ~(RES_DEFNAMES | RES_DNSRCH);   /* XXX */
 #endif
-#ifdef SMTP
-       if (clever)
+       mci = openmailer(m, pv, ctladdr, clever, e);
+       if (mci == NULL)
        {
        {
-               register MCONINFO *mci;
-
-               rcode = EX_OK;
-#ifdef NAMED_BIND
-               if (host[0] && host[0] != '[')
-               {
-                       expand("\001j", buf, &buf[sizeof(buf) - 1], e);
-                       Nmx = getmxrr(host, MxHosts, buf, &rcode);
-               }
-               else
-#endif
+               /* catastrophic error */
+               rcode = -1;
+               goto give_up;
+       }
+       else if (mci->mci_state != MCIS_OPEN)
+       {
+               /* couldn't open the mailer */
+               rcode = mci->mci_exitstat;
+               errno = mci->mci_errno;
+               if (rcode == EX_OK)
                {
                {
-                       Nmx = 1;
-                       MxHosts[0] = host;
+                       /* shouldn't happen */
+                       syserr("deliver: rcode=%d, mci_state=%d, sig=%s",
+                               rcode, mci->mci_state, firstsig);
+                       rcode = EX_SOFTWARE;
                }
                }
-               if (Nmx >= 0)
+       }
+       else if (!clever)
+       {
+               /*
+               **  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);
+
+               /* get the exit status */
+               rcode = endmailer(mci, pv[0]);
+       }
+       else
+#ifdef SMTP
+       {
+               /*
+               **  Send the MAIL FROM: protocol
+               */
+
+               rcode = smtpmailfrom(m, mci, e);
+               if (rcode == EX_OK)
                {
                {
-                       extern MCONINFO *smtpinit();
+                       register char *t = tobuf;
+                       register int i;
 
 
-                       mci = smtpinit(m, pv, e);
-                       if (mci != NULL &&
-                           mci->mci_state == MCIS_OPEN &&
-                           mci->mci_exitstat == EX_OK &&
-                           smtpmailfrom(m, mci, e) == EX_OK)
+                       /* send the recipient list */
+                       tobuf[0] = '\0';
+                       for (to = tochain; to != NULL; to = to->q_tchain)
                        {
                        {
-                               register char *t = tobuf;
-                               register int i;
-
-                               /* send the recipient list */
-                               tobuf[0] = '\0';
-                               for (to = tochain; to != NULL; to = to->q_tchain)
+                               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, e);
-                                       }
-                                       else
-                                       {
-                                               *t++ = ',';
-                                               for (p = to->q_paddr; *p; *t++ = *p++);
-                                       }
+                                       markfailure(e, to, i);
+                                       giveresponse(i, m, e);
                                }
                                }
-
-                               /* now send the data */
-                               if (tobuf[0] == '\0')
-                                       e->e_to = NULL;
                                else
                                {
                                else
                                {
-                                       e->e_to = tobuf + 1;
-                                       rcode = smtpdata(m, mci, e);
+                                       *t++ = ',';
+                                       for (p = to->q_paddr; *p; *t++ = *p++)
+                                               continue;
                                }
                                }
+                       }
 
 
-                               /* now close the connection */
-                               smtpquit(m, mci, e);
+                       /* now send the data */
+                       if (tobuf[0] == '\0')
+                       {
+                               e->e_to = NULL;
+                               if (bitset(MCIF_CACHED, mci->mci_flags))
+                                       smtprset(m, mci, e);
+                       }
+                       else
+                       {
+                               e->e_to = tobuf + 1;
+                               rcode = smtpdata(m, mci, e);
                        }
                        }
+
+                       /* now close the connection */
+                       if (!bitset(MCIF_CACHED, mci->mci_flags))
+                               smtpquit(m, mci, e);
                }
        }
                }
        }
-       else
-#endif /* SMTP */
+#else /* not SMTP */
        {
        {
-               static int sendoff();
-
-               message(Arpa_Info, "Connecting to %s (%s)...", host, m->m_name);
-               rcode = sendoff(e, m, pv, ctladdr);
+               syserr("deliver: need SMTP compiled to use clever mailer");
+               rcode = -1;
+               goto give_up;
        }
        }
+#endif /* SMTP */
 #ifdef NAMED_BIND
        if (ConfigLevel < 2)
                _res.options |= RES_DEFNAMES | RES_DNSRCH;      /* XXX */
 #endif
 
 #ifdef NAMED_BIND
        if (ConfigLevel < 2)
                _res.options |= RES_DEFNAMES | RES_DNSRCH;      /* XXX */
 #endif
 
+       /* arrange a return receipt if requested */
+       if (e->e_receiptto != NULL && bitnset(M_LOCAL, m->m_flags))
+       {
+               e->e_flags |= EF_SENDRECEIPT;
+               /* do we want to send back more info? */
+       }
+
        /*
        **  Do final status disposal.
        **      We check for something in tobuf for the SMTP case.
        /*
        **  Do final status disposal.
        **      We check for something in tobuf for the SMTP case.
@@ -464,13 +493,23 @@ deliver(e, firstto)
        **              addressees.
        */
 
        **              addressees.
        */
 
+  give_up:
        if (tobuf[0] != '\0')
                giveresponse(rcode, m, e);
        for (to = tochain; to != NULL; to = to->q_tchain)
        if (tobuf[0] != '\0')
                giveresponse(rcode, m, e);
        for (to = tochain; to != NULL; to = to->q_tchain)
+       {
                if (rcode != EX_OK)
                        markfailure(e, to, rcode);
                else
                if (rcode != EX_OK)
                        markfailure(e, to, rcode);
                else
+               {
                        to->q_flags |= QSENT;
                        to->q_flags |= QSENT;
+                       e->e_nsent++;
+               }
+       }
+
+       /*
+       **  Restore state and return.
+       */
 
        errno = 0;
        define('g', (char *) NULL, e);
 
        errno = 0;
        define('g', (char *) NULL, e);
@@ -519,6 +558,7 @@ markfailure(e, q, rcode)
                }
                q->q_flags |= QBADADDR;
                e->e_flags |= EF_TIMEOUT;
                }
                q->q_flags |= QBADADDR;
                e->e_flags |= EF_TIMEOUT;
+               fprintf(e->e_xfp, "421 %s... Message timed out\n", q->q_paddr);
        }
        else
                q->q_flags |= QQUEUEUP;
        }
        else
                q->q_flags |= QQUEUEUP;
@@ -587,61 +627,6 @@ dofork()
        return (pid);
 }
 \f/*
        return (pid);
 }
 \f/*
-**  SENDOFF -- send off call to mailer & collect response.
-**
-**     Parameters:
-**             e -- the envelope to mail.
-**             m -- mailer descriptor.
-**             pvp -- parameter vector to send to it.
-**             ctladdr -- an address pointer controlling the
-**                     user/groupid etc. of the mailer.
-**
-**     Returns:
-**             exit status of mailer.
-**
-**     Side Effects:
-**             none.
-*/
-static
-sendoff(e, m, pvp, ctladdr)
-       register ENVELOPE *e;
-       MAILER *m;
-       char **pvp;
-       ADDRESS *ctladdr;
-{
-       register int i;
-       register MCONINFO *mci;
-       extern MCONINFO *openmailer();
-
-       /*
-       **  Create connection to mailer.
-       */
-
-       mci = openmailer(m, pvp, ctladdr, FALSE);
-       if (mci == NULL)
-               return (-1);
-
-       /*
-       **  Format and send message.
-       */
-
-       putfromline(mci->mci_out, m);
-       (*e->e_puthdr)(mci->mci_out, m, e);
-       putline("\n", mci->mci_out, m);
-       (*e->e_putbody)(mci->mci_out, m, e);
-
-       i = endmailer(mci, pvp[0]);
-
-       /* arrange a return receipt if requested */
-       if (e->e_receiptto != NULL && bitnset(M_LOCAL, m->m_flags))
-       {
-               e->e_flags |= EF_SENDRECEIPT;
-               /* do we want to send back more info? */
-       }
-
-       return (i);
-}
-\f/*
 **  ENDMAILER -- Wait for mailer to terminate.
 **
 **     We should never get fatal errors (e.g., segmentation
 **  ENDMAILER -- Wait for mailer to terminate.
 **
 **     We should never get fatal errors (e.g., segmentation
@@ -661,7 +646,7 @@ sendoff(e, m, pvp, ctladdr)
 */
 
 endmailer(mci, name)
 */
 
 endmailer(mci, name)
-       register MCONINFO *mci;
+       register MCI *mci;
        char *name;
 {
        int st;
        char *name;
 {
        int st;
@@ -673,8 +658,6 @@ endmailer(mci, name)
                (void) fclose(mci->mci_out);
        mci->mci_in = mci->mci_out = NULL;
        mci->mci_state = MCIS_CLOSED;
                (void) fclose(mci->mci_out);
        mci->mci_in = mci->mci_out = NULL;
        mci->mci_state = MCIS_CLOSED;
-       if (bitset(MCIF_TEMP, mci->mci_flags))
-               free(mci);
 
        /* in the IPC case there is nothing to wait for */
        if (mci->mci_pid == 0)
 
        /* in the IPC case there is nothing to wait for */
        if (mci->mci_pid == 0)
@@ -717,15 +700,16 @@ endmailer(mci, name)
 **             creates a mailer in a subprocess.
 */
 
 **             creates a mailer in a subprocess.
 */
 
-MCONINFO *
-openmailer(m, pvp, ctladdr, clever)
+MCI *
+openmailer(m, pvp, ctladdr, clever, e)
        MAILER *m;
        char **pvp;
        ADDRESS *ctladdr;
        bool clever;
        MAILER *m;
        char **pvp;
        ADDRESS *ctladdr;
        bool clever;
+       ENVELOPE *e;
 {
        int pid;
 {
        int pid;
-       register MCONINFO *mci;
+       register MCI *mci;
        int mpvect[2];
        int rpvect[2];
        extern FILE *fdopen();
        int mpvect[2];
        int rpvect[2];
        extern FILE *fdopen();
@@ -751,222 +735,272 @@ openmailer(m, pvp, ctladdr, clever)
        /* 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)
        {
-               mci = (MCONINFO *) xalloc(sizeof *mci);
+               mci = (MCI *) xalloc(sizeof *mci);
+               bzero((char *) mci, sizeof *mci);
                mci->mci_in = stdin;
                mci->mci_out = stdout;
                mci->mci_in = stdin;
                mci->mci_out = stdout;
-               mci->mci_pid = 0;
-               mci->mci_state = MCIS_OPEN;
+               mci->mci_state = clever ? MCIS_OPENING : MCIS_OPEN;
                mci->mci_mailer = m;
                mci->mci_mailer = m;
-               return mci;
        }
        }
-
-       if (strcmp(m->m_mailer, "[IPC]") == 0 ||
-           strcmp(m->m_mailer, "[TCP]") == 0)
+       else if (strcmp(m->m_mailer, "[IPC]") == 0 ||
+                strcmp(m->m_mailer, "[TCP]") == 0)
        {
 #ifdef DAEMON
        {
 #ifdef DAEMON
-               register STAB *st;
-               extern STAB *stab();
-               register int i, j;
+               register int i;
                register u_short port;
                register u_short port;
+               char *curhost;
+               extern MCI *mci_get();
+               extern char *hostsignature();
 
                CurHostName = pvp[1];
 
                CurHostName = pvp[1];
+               curhost = hostsignature(m, pvp[1], e);
+
                if (!clever)
                        syserr("non-clever IPC");
                if (pvp[2] != NULL)
                        port = atoi(pvp[2]);
                else
                        port = 0;
                if (!clever)
                        syserr("non-clever IPC");
                if (pvp[2] != NULL)
                        port = atoi(pvp[2]);
                else
                        port = 0;
-               for (j = 0; j < Nmx; j++)
+               while (*curhost != '\0')
                {
                {
+                       register char *p;
+                       char hostbuf[MAXNAME];
+
+                       /* pull the next host from the signature */
+                       p = strchr(curhost, ':');
+                       if (p == NULL)
+                               p = &curhost[strlen(curhost)];
+                       strncpy(hostbuf, curhost, p - curhost);
+                       hostbuf[p - curhost] = '\0';
+                       if (*p != '\0')
+                               p++;
+                       curhost = p;
+
                        /* see if we already know that this host is fried */
                        /* see if we already know that this host is fried */
-                       CurHostName = MxHosts[j];
-                       st = stab(CurHostName,
-                                 ST_MCONINFO + m->m_mno,
-                                 ST_ENTER);
-                       mci = &st->s_mci;
-                       if (mci->mci_state == MCIS_OPEN)
-                               return mci;
-                       mci->mci_mailer = m;
-                       if (mci->mci_state == MCIS_CLOSED)
+                       CurHostName = hostbuf;
+                       mci = mci_get(hostbuf, m);
+                       if (mci->mci_state != MCIS_CLOSED)
                        {
                        {
-                               /* try the connection */
-                               message(Arpa_Info, "Connecting to %s (%s)...",
-                                       MxHosts[j], m->m_name);
-                               i = makeconnection(MxHosts[j], port, mci,
-                                       bitnset(M_SECURE_PORT, m->m_flags));
-                               mci->mci_exitstat = i;
-                               mci->mci_errno = errno;
-                               if (i == EX_TEMPFAIL)
-                                       mci->mci_state = MCIS_TEMPFAIL;
-                               else if (i != EX_OK)
-                                       mci->mci_state = MCIS_ERROR;
-                               else
-                                       mci->mci_state = MCIS_OPENING;
+                               if (tTd(11, 1))
+                               {
+                                       printf("openmailer: ");
+                                       mci_dump(mci);
+                               }
+                               CurHostName = mci->mci_host;
+                               return mci;
                        }
                        }
-                       else
+                       mci->mci_mailer = m;
+                       if (mci->mci_exitstat != EX_OK)
+                               continue;
+
+                       /* try the connection */
+                       setproctitle("%s %s: %s", e->e_id, hostbuf, "user open");
+                       message(Arpa_Info, "Connecting to %s (%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;
+                       if (i == EX_OK)
                        {
                        {
-                               i = mci->mci_exitstat;
-                               errno = mci->mci_errno;
+                               mci->mci_state = MCIS_OPENING;
+                               mci_cache(mci);
+                               break;
                        }
                        }
-                       if (i == EX_OK)
-                               return mci;
+                       else if (tTd(11, 1))
+                               printf("openmailer: makeconnection => stat=%d, errno=%d\n",
+                                       i, errno);
+
 
                        /* enter status of this host */
                        setstat(i);
                }
 
                        /* enter status of this host */
                        setstat(i);
                }
-               return NULL;
-#else DAEMON
+               mci->mci_pid = 0;
+#else /* no DAEMON */
                syserr("openmailer: no IPC");
                syserr("openmailer: no IPC");
+               if (tTd(11, 1))
+                       printf("openmailer: NULL\n");
                return NULL;
                return NULL;
-#endif DAEMON
-       }
-
-       /* create a pipe to shove the mail through */
-       if (pipe(mpvect) < 0)
-       {
-               syserr("openmailer: pipe (to mailer)");
-               return NULL;
-       }
-
-#ifdef SMTP
-       /* if this mailer speaks smtp, create a return pipe */
-       if (clever && pipe(rpvect) < 0)
-       {
-               syserr("openmailer: pipe (from mailer)");
-               (void) close(mpvect[0]);
-               (void) close(mpvect[1]);
-               return NULL;
+#endif /* DAEMON */
        }
        }
-#endif SMTP
-
-       /*
-       **  Actually fork the mailer process.
-       **      DOFORK is clever about retrying.
-       **
-       **      Dispose of SIGCHLD signal catchers that may be laying
-       **      around so that endmail will get it.
-       */
-
-       if (CurEnv->e_xfp != NULL)
-               (void) fflush(CurEnv->e_xfp);           /* for debugging */
-       (void) fflush(stdout);
-# ifdef SIGCHLD
-       (void) signal(SIGCHLD, SIG_DFL);
-# endif SIGCHLD
-       DOFORK(FORK);
-       /* pid is set by DOFORK */
-       if (pid < 0)
+       else
        {
        {
-               /* failure */
-               syserr("openmailer: cannot fork");
-               (void) close(mpvect[0]);
-               (void) close(mpvect[1]);
-#ifdef SMTP
-               if (clever)
+               /* create a pipe to shove the mail through */
+               if (pipe(mpvect) < 0)
                {
                {
-                       (void) close(rpvect[0]);
-                       (void) close(rpvect[1]);
+                       syserr("openmailer: pipe (to mailer)");
+                       if (tTd(11, 1))
+                               printf("openmailer: NULL\n");
+                       return NULL;
                }
                }
-#endif SMTP
-               return NULL;
-       }
-       else if (pid == 0)
-       {
-               int i;
-               extern int DtableSize;
-
-               /* child -- set up input & exec mailer */
-               /* make diagnostic output be standard output */
-               (void) signal(SIGINT, SIG_IGN);
-               (void) signal(SIGHUP, SIG_IGN);
-               (void) signal(SIGTERM, SIG_DFL);
 
 
-               /* arrange to filter standard & diag output of command */
-               if (clever)
-               {
-                       (void) close(rpvect[0]);
-                       (void) close(1);
-                       (void) dup(rpvect[1]);
-                       (void) close(rpvect[1]);
-               }
-               else if (OpMode == MD_SMTP || HoldErrs)
+               /* if this mailer speaks smtp, create a return pipe */
+               if (clever && pipe(rpvect) < 0)
                {
                {
-                       /* put mailer output in transcript */
-                       (void) close(1);
-                       (void) dup(fileno(CurEnv->e_xfp));
+                       syserr("openmailer: pipe (from mailer)");
+                       (void) close(mpvect[0]);
+                       (void) close(mpvect[1]);
+                       if (tTd(11, 1))
+                               printf("openmailer: NULL\n");
+                       return NULL;
                }
                }
-               (void) close(2);
-               (void) dup(1);
 
 
-               /* arrange to get standard input */
-               (void) close(mpvect[1]);
-               (void) close(0);
-               if (dup(mpvect[0]) < 0)
+               /*
+               **  Actually fork the mailer process.
+               **      DOFORK is clever about retrying.
+               **
+               **      Dispose of SIGCHLD signal catchers that may be laying
+               **      around so that endmail will get it.
+               */
+
+               if (e->e_xfp != NULL)
+                       (void) fflush(e->e_xfp);                /* for debugging */
+               (void) fflush(stdout);
+# ifdef SIGCHLD
+               (void) signal(SIGCHLD, SIG_DFL);
+# endif /* SIGCHLD */
+               DOFORK(FORK);
+               /* pid is set by DOFORK */
+               if (pid < 0)
                {
                {
-                       syserr("Cannot dup to zero!");
-                       _exit(EX_OSERR);
+                       /* failure */
+                       syserr("openmailer: cannot fork");
+                       (void) close(mpvect[0]);
+                       (void) close(mpvect[1]);
+                       if (clever)
+                       {
+                               (void) close(rpvect[0]);
+                               (void) close(rpvect[1]);
+                       }
+                       if (tTd(11, 1))
+                               printf("openmailer: NULL\n");
+                       return NULL;
                }
                }
-               (void) close(mpvect[0]);
-               if (!bitnset(M_RESTR, m->m_flags))
+               else if (pid == 0)
                {
                {
-                       if (ctladdr == NULL || ctladdr->q_uid == 0)
+                       int i;
+                       int saveerrno;
+                       char *env[2];
+                       extern int DtableSize;
+
+                       /* child -- set up input & exec mailer */
+                       /* make diagnostic output be standard output */
+                       (void) signal(SIGINT, SIG_IGN);
+                       (void) signal(SIGHUP, SIG_IGN);
+                       (void) signal(SIGTERM, SIG_DFL);
+
+                       /* arrange to filter std & diag output of command */
+                       if (clever)
                        {
                        {
-                               (void) setgid(DefGid);
-                               (void) initgroups(DefUser, DefGid);
-                               (void) setuid(DefUid);
+                               (void) close(rpvect[0]);
+                               (void) close(1);
+                               (void) dup(rpvect[1]);
+                               (void) close(rpvect[1]);
                        }
                        }
-                       else
+                       else if (OpMode == MD_SMTP || HoldErrs)
                        {
                        {
-                               (void) setgid(ctladdr->q_gid);
-                               (void) initgroups(ctladdr->q_ruser?
-                                       ctladdr->q_ruser: ctladdr->q_user,
-                                       ctladdr->q_gid);
-                               (void) setuid(ctladdr->q_uid);
+                               /* put mailer output in transcript */
+                               (void) close(1);
+                               (void) dup(fileno(e->e_xfp));
                        }
                        }
-               }
+                       (void) close(2);
+                       (void) dup(1);
 
 
-               /* arrange for all the files to be closed */
-               for (i = 3; i < DtableSize; i++) {
-                       register int j;
-                       if ((j = fcntl(i, F_GETFD, 0)) != -1)
-                               (void)fcntl(i, F_SETFD, j|1);
-               }
+                       /* arrange to get standard input */
+                       (void) close(mpvect[1]);
+                       (void) close(0);
+                       if (dup(mpvect[0]) < 0)
+                       {
+                               syserr("Cannot dup to zero!");
+                               _exit(EX_OSERR);
+                       }
+                       (void) close(mpvect[0]);
+                       if (!bitnset(M_RESTR, m->m_flags))
+                       {
+                               if (ctladdr == NULL || ctladdr->q_uid == 0)
+                               {
+                                       (void) setgid(DefGid);
+#ifndef SYSTEM5
+                                       (void) initgroups(DefUser, DefGid);
+#endif
+                                       (void) setuid(DefUid);
+                               }
+                               else
+                               {
+                                       (void) setgid(ctladdr->q_gid);
+#ifndef SYSTEM5
+                                       (void) initgroups(ctladdr->q_ruser?
+                                               ctladdr->q_ruser: ctladdr->q_user,
+                                               ctladdr->q_gid);
+#endif
+                                       (void) setuid(ctladdr->q_uid);
+                               }
+                       }
 
 
-               /* try to execute the mailer */
-               execve(m->m_mailer, pvp, UserEnviron);
-               syserr("Cannot exec %s", m->m_mailer);
-               if (m == LocalMailer)
-                       _exit(EX_TEMPFAIL);
-               switch (errno)
-               {
-                 case EIO:
-                 case EAGAIN:
-                 case ENOMEM:
+                       /* arrange for all the files to be closed */
+                       for (i = 3; i < DtableSize; i++)
+                       {
+                               register int j;
+                               if ((j = fcntl(i, F_GETFD, 0)) != -1)
+                                       (void)fcntl(i, F_SETFD, j|1);
+                       }
+
+                       /* try to execute the mailer */
+                       env[0] = "AGENT=sendmail";
+                       env[1] = NULL;
+                       execve(m->m_mailer, pvp, env);
+                       saveerrno = errno;
+                       syserr("Cannot exec %s", m->m_mailer);
+                       if (m == LocalMailer)
+                               _exit(EX_TEMPFAIL);
+                       switch (saveerrno)
+                       {
+                         case EIO:
+                         case EAGAIN:
+                         case ENOMEM:
 # ifdef EPROCLIM
 # ifdef EPROCLIM
-                 case EPROCLIM:
+                         case EPROCLIM:
 # endif
 # endif
-                       _exit(EX_TEMPFAIL);
+                               _exit(EX_TEMPFAIL);
+                       }
+                       _exit(EX_UNAVAILABLE);
+               }
+
+               /*
+               **  Set up return value.
+               */
+
+               mci = (MCI *) xalloc(sizeof *mci);
+               bzero((char *) mci, sizeof *mci);
+               mci->mci_mailer = m;
+               mci->mci_state = clever ? MCIS_OPENING : MCIS_OPEN;
+               mci->mci_pid = pid;
+               (void) close(mpvect[0]);
+               mci->mci_out = fdopen(mpvect[1], "w");
+               if (clever)
+               {
+                       (void) close(rpvect[1]);
+                       mci->mci_in = fdopen(rpvect[0], "r");
+               }
+               else
+               {
+                       mci->mci_flags |= MCIF_TEMP;
+                       mci->mci_in = NULL;
                }
                }
-               _exit(EX_UNAVAILABLE);
        }
 
        /*
        }
 
        /*
-       **  Set up return value.
+       **  If we are in SMTP opening state, send initial protocol.
        */
 
        */
 
-       mci = (MCONINFO *) xalloc(sizeof *mci);
-       mci->mci_mailer = m;
-       (void) close(mpvect[0]);
-       mci->mci_out = fdopen(mpvect[1], "w");
-       if (clever)
+       if (clever && mci->mci_state != MCIS_CLOSED)
        {
        {
-               (void) close(rpvect[1]);
-               mci->mci_in = fdopen(rpvect[0], "r");
+               smtpinit(m, mci, e);
        }
        }
-       else
+       if (tTd(11, 1))
        {
        {
-               mci->mci_flags |= MCIF_TEMP;
-               mci->mci_in = NULL;
+               printf("openmailer: ");
+               mci_dump(mci);
        }
 
        return mci;
        }
 
        return mci;
@@ -1045,9 +1079,9 @@ giveresponse(stat, m, e)
                                extern char SmtpError[];
 
                                statmsg = SmtpError;
                                extern char SmtpError[];
 
                                statmsg = SmtpError;
-#else SMTP
+#else /* SMTP */
                                statmsg = NULL;
                                statmsg = NULL;
-#endif SMTP
+#endif /* SMTP */
                        }
                }
                if (statmsg != NULL && statmsg[0] != '\0')
                        }
                }
                if (statmsg != NULL && statmsg[0] != '\0')
@@ -1082,7 +1116,7 @@ giveresponse(stat, m, e)
        */
 
        if (LogLevel > ((stat == 0 || stat == EX_TEMPFAIL) ? 3 : 2))
        */
 
        if (LogLevel > ((stat == 0 || stat == EX_TEMPFAIL) ? 3 : 2))
-               logdelivery(&statmsg[4]);
+               logdelivery(&statmsg[4], e);
 
        if (stat != EX_TEMPFAIL)
                setstat(stat);
 
        if (stat != EX_TEMPFAIL)
                setstat(stat);
@@ -1110,15 +1144,16 @@ giveresponse(stat, m, e)
 **             none
 */
 
 **             none
 */
 
-logdelivery(stat)
+logdelivery(stat, e)
        char *stat;
        char *stat;
+       register ENVELOPE *e;
 {
        extern char *pintvl();
 
 # ifdef LOG
 {
        extern char *pintvl();
 
 # ifdef LOG
-       syslog(LOG_INFO, "%s: to=%s, delay=%s, stat=%s", CurEnv->e_id,
-              CurEnv->e_to, pintvl(curtime() - CurEnv->e_ctime, TRUE), stat);
-# endif LOG
+       syslog(LOG_INFO, "%s: to=%s, delay=%s, stat=%s", e->e_id,
+              e->e_to, pintvl(curtime() - e->e_ctime, TRUE), stat);
+# endif /* LOG */
 }
 \f/*
 **  PUTFROMLINE -- output a UNIX-style from line (or whatever)
 }
 \f/*
 **  PUTFROMLINE -- output a UNIX-style from line (or whatever)
@@ -1143,9 +1178,10 @@ logdelivery(stat)
 **             outputs some text to fp.
 */
 
 **             outputs some text to fp.
 */
 
-putfromline(fp, m)
+putfromline(fp, m, e)
        register FILE *fp;
        register MAILER *m;
        register FILE *fp;
        register MAILER *m;
+       ENVELOPE *e;
 {
        char *template = "\001l\n";
        char buf[MAXLINE];
 {
        char *template = "\001l\n";
        char buf[MAXLINE];
@@ -1160,8 +1196,8 @@ putfromline(fp, m)
                char *bang;
                char xbuf[MAXLINE];
 
                char *bang;
                char xbuf[MAXLINE];
 
-               expand("\001<", buf, &buf[sizeof buf - 1], CurEnv);
-               bang = index(buf, '!');
+               expand("\001<", buf, &buf[sizeof buf - 1], e);
+               bang = strchr(buf, '!');
                if (bang == NULL)
                        syserr("No ! in UUCP! (%s)", buf);
                else
                if (bang == NULL)
                        syserr("No ! in UUCP! (%s)", buf);
                else
@@ -1171,8 +1207,8 @@ putfromline(fp, m)
                        template = xbuf;
                }
        }
                        template = xbuf;
                }
        }
-# endif UGLYUUCP
-       expand(template, buf, &buf[sizeof buf - 1], CurEnv);
+# endif /* UGLYUUCP */
+       expand(template, buf, &buf[sizeof buf - 1], e);
        putline(buf, fp, m);
 }
 \f/*
        putline(buf, fp, m);
 }
 \f/*
@@ -1265,13 +1301,13 @@ putbody(fp, m, e)
 **             none.
 */
 
 **             none.
 */
 
-mailfile(filename, ctladdr)
+mailfile(filename, ctladdr, e)
        char *filename;
        ADDRESS *ctladdr;
        char *filename;
        ADDRESS *ctladdr;
+       register ENVELOPE *e;
 {
        register FILE *f;
        register int pid;
 {
        register FILE *f;
        register int pid;
-       ENVELOPE *e = CurEnv;
        int mode;
 
        /*
        int mode;
 
        /*
@@ -1328,14 +1364,18 @@ mailfile(filename, ctladdr)
                        if (ctladdr->q_uid == 0)
                        {
                                (void) setgid(DefGid);
                        if (ctladdr->q_uid == 0)
                        {
                                (void) setgid(DefGid);
+#ifndef SYSTEM5
                                (void) initgroups(DefUser, DefGid);
                                (void) initgroups(DefUser, DefGid);
+#endif
                        }
                        else
                        {
                                (void) setgid(ctladdr->q_gid);
                        }
                        else
                        {
                                (void) setgid(ctladdr->q_gid);
+#ifndef SYSTEM5
                                (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);
+#endif
                        }
                }
                if (!bitset(S_ISUID, mode) || setuid(stb.st_uid) < 0)
                        }
                }
                if (!bitset(S_ISUID, mode) || setuid(stb.st_uid) < 0)
@@ -1354,10 +1394,10 @@ mailfile(filename, ctladdr)
                        exit(EX_CANTCREAT);
                }
 
                        exit(EX_CANTCREAT);
                }
 
-               putfromline(f, ProgMailer);
-               (*CurEnv->e_puthdr)(f, ProgMailer, CurEnv);
+               putfromline(f, ProgMailer, e);
+               (*e->e_puthdr)(f, ProgMailer, e);
                putline("\n", f, ProgMailer);
                putline("\n", f, ProgMailer);
-               (*CurEnv->e_putbody)(f, ProgMailer, CurEnv);
+               (*e->e_putbody)(f, ProgMailer, e);
                putline("\n", f, ProgMailer);
                if (ferror(f))
                {
                putline("\n", f, ProgMailer);
                if (ferror(f))
                {
@@ -1410,7 +1450,6 @@ sendall(e, mode)
        register ADDRESS *q;
        bool oldverbose;
        int pid;
        register ADDRESS *q;
        bool oldverbose;
        int pid;
-       int nsent;
 # ifdef LOCKF
        struct flock lfd;
 # endif
 # ifdef LOCKF
        struct flock lfd;
 # endif
@@ -1420,7 +1459,7 @@ sendall(e, mode)
        {
                extern bool shouldqueue();
 
        {
                extern bool shouldqueue();
 
-               if (shouldqueue(e->e_msgpriority))
+               if (shouldqueue(e->e_msgpriority, e->e_ctime))
                        mode = SM_QUEUE;
                else
                        mode = SendMode;
                        mode = SM_QUEUE;
                else
                        mode = SendMode;
@@ -1444,7 +1483,8 @@ sendall(e, mode)
        {
                errno = 0;
                syserr("sendall: too many hops %d (%d max): from %s, to %s",
        {
                errno = 0;
                syserr("sendall: too many hops %d (%d max): from %s, to %s",
-                       e->e_hopcount, MaxHopCount, e->e_from, e->e_to);
+                       e->e_hopcount, MaxHopCount, e->e_from.q_paddr,
+                       e->e_sendqueue->q_paddr);
                return;
        }
 
                return;
        }
 
@@ -1453,7 +1493,12 @@ sendall(e, mode)
                extern ADDRESS *recipient();
 
                e->e_from.q_flags |= QDONTSEND;
                extern ADDRESS *recipient();
 
                e->e_from.q_flags |= QDONTSEND;
-               (void) recipient(&e->e_from, &e->e_sendqueue);
+               if (tTd(13, 5))
+               {
+                       printf("sendall: QDONTSEND ");
+                       printaddr(&e->e_from, FALSE);
+               }
+               (void) recipient(&e->e_from, &e->e_sendqueue, e);
        }
 
 # ifdef QUEUE
        }
 
 # ifdef QUEUE
@@ -1461,7 +1506,7 @@ sendall(e, mode)
             (mode != SM_VERIFY && SuperSafe)) &&
            !bitset(EF_INQUEUE, e->e_flags))
                queueup(e, TRUE, mode == SM_QUEUE);
             (mode != SM_VERIFY && SuperSafe)) &&
            !bitset(EF_INQUEUE, e->e_flags))
                queueup(e, TRUE, mode == SM_QUEUE);
-#endif QUEUE
+#endif /* QUEUE */
 
        oldverbose = Verbose;
        switch (mode)
 
        oldverbose = Verbose;
        switch (mode)
@@ -1505,8 +1550,23 @@ sendall(e, mode)
                        e->e_id = e->e_df = NULL;
 # ifndef LOCKF
                        if (e->e_lockfp != NULL)
                        e->e_id = e->e_df = NULL;
 # ifndef LOCKF
                        if (e->e_lockfp != NULL)
+                       {
                                (void) fclose(e->e_lockfp);
                                (void) fclose(e->e_lockfp);
+                               e->e_lockfp = NULL;
+                       }
 # endif
 # endif
+
+                       /* close any random open files in the envelope */
+                       if (e->e_dfp != NULL)
+                       {
+                               (void) fclose(e->e_dfp);
+                               e->e_dfp = NULL;
+                       }
+                       if (e->e_xfp != NULL)
+                       {
+                               (void) fclose(e->e_xfp);
+                               e->e_xfp = NULL;
+                       }
                        return;
                }
 
                        return;
                }
 
@@ -1532,7 +1592,7 @@ sendall(e, mode)
 # ifdef LOG
                        if (LogLevel > 5)
                                syslog(LOG_NOTICE, "%s: lost lock: %m",
 # ifdef LOG
                        if (LogLevel > 5)
                                syslog(LOG_NOTICE, "%s: lost lock: %m",
-                                       CurEnv->e_id);
+                                       e->e_id);
 # endif /* LOG */
                        exit(EX_OK);
                }
 # endif /* LOG */
                        exit(EX_OK);
                }
@@ -1545,7 +1605,7 @@ sendall(e, mode)
        **  Run through the list and send everything.
        */
 
        **  Run through the list and send everything.
        */
 
-       nsent = 0;
+       e->e_nsent = 0;
        for (q = e->e_sendqueue; q != NULL; q = q->q_next)
        {
                if (mode == SM_VERIFY)
        for (q = e->e_sendqueue; q != NULL; q = q->q_next)
        {
                if (mode == SM_VERIFY)
@@ -1561,14 +1621,13 @@ sendall(e, mode)
                        **  Checkpoint the send list every few addresses
                        */
 
                        **  Checkpoint the send list every few addresses
                        */
 
-                       if (nsent >= CheckpointInterval)
+                       if (e->e_nsent >= CheckpointInterval)
                        {
                                queueup(e, TRUE, FALSE);
                        {
                                queueup(e, TRUE, FALSE);
-                               nsent = 0;
+                               e->e_nsent = 0;
                        }
 # endif /* QUEUE */
                        }
 # endif /* QUEUE */
-                       if (deliver(e, q) == EX_OK)
-                               nsent++;
+                       (void) deliver(e, q);
                }
        }
        Verbose = oldverbose;
                }
        }
        Verbose = oldverbose;
@@ -1610,7 +1669,8 @@ sendall(e, mode)
                                (void) strcat(obuf, "owner");
                        else
                                (void) strcat(obuf, qq->q_user);
                                (void) strcat(obuf, "owner");
                        else
                                (void) strcat(obuf, qq->q_user);
-                       makelower(obuf);
+                       if (!bitnset(M_USR_UPPER, qq->q_mailer->m_flags))
+                               makelower(obuf);
                        if (aliaslookup(obuf) == NULL)
                                continue;
 
                        if (aliaslookup(obuf) == NULL)
                                continue;
 
@@ -1618,16 +1678,129 @@ sendall(e, mode)
                                printf("Errors to %s\n", obuf);
 
                        /* owner list exists -- add it to the error queue */
                                printf("Errors to %s\n", obuf);
 
                        /* owner list exists -- add it to the error queue */
-                       sendtolist(obuf, (ADDRESS *) NULL, &e->e_errorqueue);
+                       sendtolist(obuf, (ADDRESS *) NULL, &e->e_errorqueue, e);
+
+                       /* and set the return path to point to it */
+                       e->e_returnpath = newstr(obuf);
+
                        ErrorMode = EM_MAIL;
                        break;
                }
 
                /* if we did not find an owner, send to the sender */
                if (qq == NULL && bitset(QBADADDR, q->q_flags))
                        ErrorMode = EM_MAIL;
                        break;
                }
 
                /* if we did not find an owner, send to the sender */
                if (qq == NULL && bitset(QBADADDR, q->q_flags))
-                       sendtolist(e->e_from.q_paddr, qq, &e->e_errorqueue);
+                       sendtolist(e->e_from.q_paddr, qq, &e->e_errorqueue, e);
        }
 
        if (mode == SM_FORK)
                finis();
 }
        }
 
        if (mode == SM_FORK)
                finis();
 }
+\f/*
+**  HOSTSIGNATURE -- return the "signature" for a host.
+**
+**     The signature describes how we are going to send this -- it
+**     can be just the hostname (for non-Internet hosts) or can be
+**     an ordered list of MX hosts.
+**
+**     Parameters:
+**             m -- the mailer describing this host.
+**             host -- the host name.
+**             e -- the current envelope.
+**
+**     Returns:
+**             The signature for this host.
+**
+**     Side Effects:
+**             Can tweak the symbol table.
+*/
+
+char *
+hostsignature(m, host, e)
+       register MAILER *m;
+       char *host;
+       ENVELOPE *e;
+{
+       register char *p;
+       register STAB *s;
+       int i;
+       int len;
+#ifdef NAMED_BIND
+       int nmx;
+       auto int rcode;
+       char *mxhosts[MAXMXHOSTS + 1];
+       static char myhostbuf[MAXNAME];
+#endif
+
+       /*
+       **  Check to see if this uses IPC -- if not, it can't have MX records.
+       */
+
+       p = m->m_mailer;
+       if (strcmp(p, "[IPC]") != 0 && strcmp(p, "[TCP]") != 0)
+       {
+               /* just an ordinary mailer */
+               return host;
+       }
+
+       /*
+       **  If it is a numeric address, just return it.
+       */
+
+       if (host[0] == '[')
+               return host;
+
+       /*
+       **  Look it up in the symbol table.
+       */
+
+       s = stab(host, ST_HOSTSIG, ST_ENTER);
+       if (s->s_hostsig != NULL)
+               return s->s_hostsig;
+
+       /*
+       **  Not already there -- create a signature.
+       */
+
+#ifdef NAMED_BIND
+       if (myhostbuf[0] == '\0')
+               expand("\001j", myhostbuf, &myhostbuf[sizeof myhostbuf - 1], e);
+
+       nmx = getmxrr(host, mxhosts, myhostbuf, &rcode);
+       if (nmx <= 0)
+       {
+               register MCI *mci;
+               extern int errno;
+               extern MCI *mci_get();
+
+               /* update the connection info for this host */
+               mci = mci_get(host, m);
+               mci->mci_exitstat = rcode;
+               mci->mci_errno = errno;
+
+               /* and return the original host name as the signature */
+               s->s_hostsig = host;
+               return host;
+       }
+
+       len = 0;
+       for (i = 0; i < nmx; i++)
+       {
+               len += strlen(mxhosts[i]) + 1;
+       }
+       s->s_hostsig = p = xalloc(len);
+       for (i = 0; i < nmx; i++)
+       {
+               if (i != 0)
+                       *p++ = ':';
+               strcpy(p, mxhosts[i]);
+               p += strlen(p);
+       }
+       makelower(s->s_hostsig);
+#else
+       /* not using BIND -- the signature is just the host name */
+       s->s_hostsig = host;
+#endif
+       if (tTd(17, 1))
+               printf("hostsignature(%s) = %s\n", host, s->s_hostsig);
+       return s->s_hostsig;
+}