first cut at DSN implementation
authorEric Allman <eric@ucbvax.Berkeley.EDU>
Sat, 5 Nov 1994 00:40:42 +0000 (16:40 -0800)
committerEric Allman <eric@ucbvax.Berkeley.EDU>
Sat, 5 Nov 1994 00:40:42 +0000 (16:40 -0800)
SCCS-vsn: usr.sbin/sendmail/src/usersmtp.c 8.23
SCCS-vsn: usr.sbin/sendmail/src/recipient.c 8.51
SCCS-vsn: usr.sbin/sendmail/src/envelope.c 8.42
SCCS-vsn: usr.sbin/sendmail/src/parseaddr.c 8.39
SCCS-vsn: usr.sbin/sendmail/src/sendmail.h 8.66
SCCS-vsn: usr.sbin/sendmail/src/savemail.c 8.36
SCCS-vsn: usr.sbin/sendmail/src/srvrsmtp.c 8.45
SCCS-vsn: usr.sbin/sendmail/src/deliver.c 8.103
SCCS-vsn: usr.sbin/sendmail/src/queue.c 8.51
SCCS-vsn: usr.sbin/sendmail/src/conf.c 8.113

usr/src/usr.sbin/sendmail/src/conf.c
usr/src/usr.sbin/sendmail/src/deliver.c
usr/src/usr.sbin/sendmail/src/envelope.c
usr/src/usr.sbin/sendmail/src/parseaddr.c
usr/src/usr.sbin/sendmail/src/queue.c
usr/src/usr.sbin/sendmail/src/recipient.c
usr/src/usr.sbin/sendmail/src/savemail.c
usr/src/usr.sbin/sendmail/src/sendmail.h
usr/src/usr.sbin/sendmail/src/srvrsmtp.c
usr/src/usr.sbin/sendmail/src/usersmtp.c

index 5b665d9..6427cc0 100644 (file)
@@ -7,7 +7,7 @@
  */
 
 #ifndef lint
  */
 
 #ifndef lint
-static char sccsid[] = "@(#)conf.c     8.112 (Berkeley) %G%";
+static char sccsid[] = "@(#)conf.c     8.113 (Berkeley) %G%";
 #endif /* not lint */
 
 # include "sendmail.h"
 #endif /* not lint */
 
 # include "sendmail.h"
@@ -539,6 +539,7 @@ switch_map_find(service, maptype, mapreturn)
                if (lk->actions[__NSW_UNAVAIL] == __NSW_RETURN)
                        mapreturn[MA_TRYAGAIN] |= 1 << svcno;
                svcno++;
                if (lk->actions[__NSW_UNAVAIL] == __NSW_RETURN)
                        mapreturn[MA_TRYAGAIN] |= 1 << svcno;
                svcno++;
+               lk = lk->next;
        }
        return svcno;
 #endif
        }
        return svcno;
 #endif
@@ -547,7 +548,9 @@ switch_map_find(service, maptype, mapreturn)
        struct svcinfo *svcinfo;
        int svc;
 
        struct svcinfo *svcinfo;
        int svc;
 
-       svc = getsvc();
+       svcinfo = getsvc();
+       if (svcinfo == NULL)
+               goto punt;
        if (strcmp(service, "hosts") == 0)
                svc = SVC_HOSTS;
        else if (strcmp(service, "aliases") == 0)
        if (strcmp(service, "hosts") == 0)
                svc = SVC_HOSTS;
        else if (strcmp(service, "aliases") == 0)
@@ -579,8 +582,7 @@ switch_map_find(service, maptype, mapreturn)
 #endif
 
                  case SVC_LAST:
 #endif
 
                  case SVC_LAST:
-                       svcno = SVC_PATHSIZE;
-                       break;
+                       return svcno;
                }
        }
        return svcno;
                }
        }
        return svcno;
@@ -625,8 +627,10 @@ switch_map_find(service, maptype, mapreturn)
                fclose(fp);
                return svcno;
        }
                fclose(fp);
                return svcno;
        }
+#endif
 
        /* if the service file doesn't work, use an absolute fallback */
 
        /* if the service file doesn't work, use an absolute fallback */
+  punt:
        if (strcmp(service, "aliases") == 0)
        {
                maptype[0] = "files";
        if (strcmp(service, "aliases") == 0)
        {
                maptype[0] = "files";
@@ -646,7 +650,6 @@ switch_map_find(service, maptype, mapreturn)
                return svcno;
        }
        return -1;
                return svcno;
        }
        return -1;
-#endif
 }
 \f/*
 **  USERNAME -- return the user id of the logged in user.
 }
 \f/*
 **  USERNAME -- return the user id of the logged in user.
index a37de77..096ef91 100644 (file)
@@ -7,7 +7,7 @@
  */
 
 #ifndef lint
  */
 
 #ifndef lint
-static char sccsid[] = "@(#)deliver.c  8.102 (Berkeley) %G%";
+static char sccsid[] = "@(#)deliver.c  8.103 (Berkeley) %G%";
 #endif /* not lint */
 
 #include "sendmail.h"
 #endif /* not lint */
 
 #include "sendmail.h"
@@ -851,6 +851,7 @@ deliver(e, firstto)
                        giveresponse(rcode, m, NULL, ctladdr, e);
                        if (rcode == EX_OK)
                                to->q_flags |= QSENT;
                        giveresponse(rcode, m, NULL, ctladdr, e);
                        if (rcode == EX_OK)
                                to->q_flags |= QSENT;
+                       to->q_statdate = curtime();
                        continue;
                }
 
                        continue;
                }
 
@@ -1521,9 +1522,11 @@ tryhost:
                {
                        to->q_flags |= QSENT;
                        e->e_nsent++;
                {
                        to->q_flags |= QSENT;
                        e->e_nsent++;
-                       if (e->e_receiptto != NULL &&
-                           bitnset(M_LOCALMAILER, m->m_flags))
+                       if (bitnset(M_LOCALMAILER, m->m_flags) &&
+                           (e->e_receiptto != NULL ||
+                            bitset(QPINGONSUCCESS, to->q_flags)))
                        {
                        {
+                               to->q_flags |= QREPORT;
                                fprintf(e->e_xfp, "%s... Successfully delivered\n",
                                        to->q_paddr);
                        }
                                fprintf(e->e_xfp, "%s... Successfully delivered\n",
                                        to->q_paddr);
                        }
@@ -1589,6 +1592,8 @@ markfailure(e, q, rcode)
                q->q_flags |= QBADADDR;
                break;
        }
                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.
@@ -2631,3 +2636,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_status != NULL)
+               free(a->q_status);
+       if (strlen(msg) > 4)
+       {
+               register char *p, *q;
+               int parenlev = 0;
+
+               strncpy(buf, msg, 4);
+               p = &buf[4];
+               *p++ = '(';
+               for (q = &msg[4]; *q != NULL; 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_status = newstr(msg);
+}
index 7bd47b4..2151c82 100644 (file)
@@ -7,7 +7,7 @@
  */
 
 #ifndef lint
  */
 
 #ifndef lint
-static char sccsid[] = "@(#)envelope.c 8.41 (Berkeley) %G%";
+static char sccsid[] = "@(#)envelope.c 8.42 (Berkeley) %G%";
 #endif /* not lint */
 
 #include "sendmail.h"
 #endif /* not lint */
 
 #include "sendmail.h"
@@ -74,9 +74,11 @@ dropenvelope(e)
        register ENVELOPE *e;
 {
        bool queueit = FALSE;
        register ENVELOPE *e;
 {
        bool queueit = FALSE;
-       bool saveit = bitset(EF_FATALERRS, e->e_flags);
+       bool failure_return = FALSE;
+       bool success_return = FALSE;
        register ADDRESS *q;
        char *id = e->e_id;
        register ADDRESS *q;
        char *id = e->e_id;
+       bool return_no, return_yes;
        char buf[MAXLINE];
 
        if (tTd(50, 1))
        char buf[MAXLINE];
 
        if (tTd(50, 1))
@@ -112,19 +114,46 @@ dropenvelope(e)
        */
 
        e->e_flags &= ~EF_QUEUERUN;
        */
 
        e->e_flags &= ~EF_QUEUERUN;
+       return_no = return_yes = FALSE;
        for (q = e->e_sendqueue; q != NULL; q = q->q_next)
        {
                if (bitset(QQUEUEUP, q->q_flags))
                        queueit = TRUE;
        for (q = e->e_sendqueue; q != NULL; q = q->q_next)
        {
                if (bitset(QQUEUEUP, q->q_flags))
                        queueit = TRUE;
-               if (!bitset(QDONTSEND, q->q_flags) &&
-                   bitset(QBADADDR, q->q_flags))
+
+               /* see if a notification is needed */
+               if (bitset(QBADADDR, q->q_flags) &&
+                   bitset(QPINGONFAILURE, q->q_flags))
                {
                {
+                       failure_return = TRUE;
                        if (q->q_owner == NULL &&
                            strcmp(e->e_from.q_paddr, "<>") != 0)
                                (void) sendtolist(e->e_from.q_paddr, NULL,
                                                  &e->e_errorqueue, e);
                }
                        if (q->q_owner == NULL &&
                            strcmp(e->e_from.q_paddr, "<>") != 0)
                                (void) sendtolist(e->e_from.q_paddr, NULL,
                                                  &e->e_errorqueue, e);
                }
+               else if (bitset(QSENT, q->q_flags) &&
+                   bitnset(M_LOCALMAILER, q->q_mailer->m_flags) &&
+                   bitset(QPINGONSUCCESS, q->q_flags))
+               {
+                       success_return = TRUE;
+               }
+               else
+                       continue;
+
+               /* common code for error returns and return receipts */
+
+               /* test for returning the body */
+               if (!bitset(QHASRETPARAM, q->q_flags))
+               {
+                       if (!bitset(EF_NORETURN, e->e_flags))
+                               return_yes = TRUE;
+               }
+               else if (bitset(QNOBODYRETURN, q->q_flags))
+                       return_no = TRUE;
+               else
+                       return_yes = TRUE;
        }
        }
+       if (return_no && !return_yes)
+               e->e_flags |= EF_NORETURN;
 
        /*
        **  See if the message timed out.
 
        /*
        **  See if the message timed out.
@@ -141,7 +170,7 @@ dropenvelope(e)
                e->e_message = newstr(buf);
                message(buf);
                e->e_flags |= EF_CLRQUEUE;
                e->e_message = newstr(buf);
                message(buf);
                e->e_flags |= EF_CLRQUEUE;
-               saveit = TRUE;
+               failure_return = TRUE;
                fprintf(e->e_xfp, "Message could not be delivered for %s\n",
                        pintvl(TimeOuts.to_q_return[e->e_timeoutclass], FALSE));
                fprintf(e->e_xfp, "Message will be deleted from queue\n");
                fprintf(e->e_xfp, "Message could not be delivered for %s\n",
                        pintvl(TimeOuts.to_q_return[e->e_timeoutclass], FALSE));
                fprintf(e->e_xfp, "Message will be deleted from queue\n");
@@ -169,7 +198,7 @@ dropenvelope(e)
                        e->e_message = newstr(buf);
                        message(buf);
                        e->e_flags |= EF_WARNING;
                        e->e_message = newstr(buf);
                        message(buf);
                        e->e_flags |= EF_WARNING;
-                       saveit = TRUE;
+                       failure_return = TRUE;
                }
                fprintf(e->e_xfp,
                        "Warning: message still undelivered after %s\n",
                }
                fprintf(e->e_xfp,
                        "Warning: message still undelivered after %s\n",
@@ -183,15 +212,25 @@ dropenvelope(e)
                }
        }
 
                }
        }
 
+       if (tTd(50, 2))
+               printf("failure_return=%d success_return=%d queueit=%d\n",
+                       failure_return, success_return, queueit);
+
        /*
        **  Send back return receipts as requested.
        */
 
        /*
        **  Send back return receipts as requested.
        */
 
+/*
        if (e->e_receiptto != NULL && bitset(EF_SENDRECEIPT, e->e_flags)
            && !bitset(PRIV_NORECEIPTS, PrivacyFlags))
        if (e->e_receiptto != NULL && bitset(EF_SENDRECEIPT, e->e_flags)
            && !bitset(PRIV_NORECEIPTS, PrivacyFlags))
+*/
+       if (e->e_receiptto == NULL)
+               e->e_receiptto = e->e_from.q_paddr;
+       if (success_return && strcmp(e->e_receiptto, "<>") != 0)
        {
                auto ADDRESS *rlist = NULL;
 
        {
                auto ADDRESS *rlist = NULL;
 
+               e->e_flags |= EF_SENDRECEIPT;
                (void) sendtolist(e->e_receiptto, NULLADDR, &rlist, e);
                (void) returntosender("Return receipt", rlist, FALSE, e);
        }
                (void) sendtolist(e->e_receiptto, NULLADDR, &rlist, e);
                (void) returntosender("Return receipt", rlist, FALSE, e);
        }
@@ -201,7 +240,7 @@ dropenvelope(e)
        **  Arrange to send error messages if there are fatal errors.
        */
 
        **  Arrange to send error messages if there are fatal errors.
        */
 
-       if (saveit && e->e_errormode != EM_QUIET)
+       if (failure_return && e->e_errormode != EM_QUIET)
                savemail(e);
 
        /*
                savemail(e);
 
        /*
@@ -225,7 +264,8 @@ dropenvelope(e)
            bitset(EF_CLRQUEUE, e->e_flags))
        {
                if (tTd(50, 1))
            bitset(EF_CLRQUEUE, e->e_flags))
        {
                if (tTd(50, 1))
-                       printf("\n===== Dropping [dq]f%s =====\n\n", e->e_id);
+                       printf("\n===== Dropping [dq]f%s (queueit=%d, e_flags=%x) =====\n\n",
+                               e->e_id, queueit, e->e_flags);
                if (e->e_df != NULL)
                        xunlink(e->e_df);
                xunlink(queuename(e, 'q'));
                if (e->e_df != NULL)
                        xunlink(e->e_df);
                xunlink(queuename(e, 'q'));
index 3980e66..36c5bf7 100644 (file)
@@ -7,7 +7,7 @@
  */
 
 #ifndef lint
  */
 
 #ifndef lint
-static char sccsid[] = "@(#)parseaddr.c        8.38 (Berkeley) %G%";
+static char sccsid[] = "@(#)parseaddr.c        8.39 (Berkeley) %G%";
 #endif /* not lint */
 
 #include "sendmail.h"
 #endif /* not lint */
 
 #include "sendmail.h"
@@ -1590,6 +1590,9 @@ buildaddr(tv, a, flags, e)
                a = (ADDRESS *) xalloc(sizeof *a);
        clear((char *) a, sizeof *a);
 
                a = (ADDRESS *) xalloc(sizeof *a);
        clear((char *) a, sizeof *a);
 
+       /* set up default error return flags */
+       a->q_flags |= QPINGONFAILURE;
+
        /* figure out what net/mailer to use */
        if (*tv == NULL || **tv != CANONNET)
        {
        /* figure out what net/mailer to use */
        if (*tv == NULL || **tv != CANONNET)
        {
index 421cca1..d8289c5 100644 (file)
@@ -10,9 +10,9 @@
 
 #ifndef lint
 #ifdef QUEUE
 
 #ifndef lint
 #ifdef QUEUE
-static char sccsid[] = "@(#)queue.c    8.50 (Berkeley) %G% (with queueing)";
+static char sccsid[] = "@(#)queue.c    8.51 (Berkeley) %G% (with queueing)";
 #else
 #else
-static char sccsid[] = "@(#)queue.c    8.50 (Berkeley) %G% (without queueing)";
+static char sccsid[] = "@(#)queue.c    8.51 (Berkeley) %G% (without queueing)";
 #endif
 #endif /* not lint */
 
 #endif
 #endif /* not lint */
 
@@ -39,6 +39,8 @@ struct work
 typedef struct work    WORK;
 
 WORK   *WorkQ;                 /* queue of things to be done */
 typedef struct work    WORK;
 
 WORK   *WorkQ;                 /* queue of things to be done */
+
+#define QF_VERSION     1       /* version number of this queue format */
 \f/*
 **  QUEUEUP -- queue a message up for future transmission.
 **
 \f/*
 **  QUEUEUP -- queue a message up for future transmission.
 **
@@ -131,8 +133,13 @@ queueup(e, queueall, announce)
        }
 
        if (tTd(40, 1))
        }
 
        if (tTd(40, 1))
-               printf("\n>>>>> queueing %s%s >>>>>\n", e->e_id,
-                       newid ? " (new id)" : "");
+               printf("\n>>>>> queueing %s%s queueall=%d >>>>>\n", e->e_id,
+                       newid ? " (new id)" : "", queueall);
+       if (tTd(40, 32))
+       {
+               printf("  sendq=");
+               printaddr(e->e_sendqueue, TRUE);
+       }
        if (tTd(40, 9))
        {
                printf("  tfp=");
        if (tTd(40, 9))
        {
                printf("  tfp=");
@@ -181,6 +188,9 @@ queueup(e, queueall, announce)
        **      they are required by orderq.
        */
 
        **      they are required by orderq.
        */
 
+       /* output queue version number (must be first!) */
+       fprintf(tfp, "V%d\n", QF_VERSION);
+
        /* output message priority */
        fprintf(tfp, "P%ld\n", e->e_msgpriority);
 
        /* output message priority */
        fprintf(tfp, "P%ld\n", e->e_msgpriority);
 
@@ -253,7 +263,24 @@ queueup(e, queueall, announce)
                    (queueall && !bitset(QDONTSEND|QBADADDR|QSENT, q->q_flags)))
                {
                        printctladdr(q, tfp);
                    (queueall && !bitset(QDONTSEND|QBADADDR|QSENT, q->q_flags)))
                {
                        printctladdr(q, tfp);
-                       fprintf(tfp, "R%s\n", q->q_paddr);
+                       putc('R', tfp);
+                       if (bitset(QPRIMARY, q->q_flags))
+                               putc('P', tfp);
+                       if (bitset(QPINGONSUCCESS, q->q_flags))
+                               putc('S', tfp);
+                       if (bitset(QPINGONFAILURE, q->q_flags))
+                               putc('F', tfp);
+                       if (bitset(QPINGONDELAY, q->q_flags))
+                               putc('D', tfp);
+                       if (bitset(QHASRETPARAM, q->q_flags))
+                       {
+                               if (bitset(QNOBODYRETURN, q->q_flags))
+                                       putc('N', tfp);
+                               else
+                                       putc('B', tfp);
+                       }
+                       putc(':', tfp);
+                       fprintf(tfp, "%s\n", q->q_paddr);
                        if (announce)
                        {
                                e->e_to = q->q_paddr;
                        if (announce)
                        {
                                e->e_to = q->q_paddr;
@@ -431,7 +458,6 @@ printctladdr(a, tfp)
 
        fprintf(tfp, "C%s:%s\n", uname, a->q_paddr);
 }
 
        fprintf(tfp, "C%s:%s\n", uname, a->q_paddr);
 }
-
 \f/*
 **  RUNQUEUE -- run the jobs in the queue.
 **
 \f/*
 **  RUNQUEUE -- run the jobs in the queue.
 **
@@ -1148,6 +1174,8 @@ readqf(e)
        ADDRESS *ctladdr;
        struct stat st;
        char *bp;
        ADDRESS *ctladdr;
        struct stat st;
        char *bp;
+       int qfver = 0;
+       register char *p;
        char qf[20];
        char buf[MAXLINE];
        extern long atol();
        char qf[20];
        char buf[MAXLINE];
        extern long atol();
@@ -1250,11 +1278,22 @@ readqf(e)
        {
                register char *p;
                struct stat st;
        {
                register char *p;
                struct stat st;
+               u_long qflags;
+               ADDRESS *q;
 
                if (tTd(40, 4))
                        printf("+++++ %s\n", bp);
                switch (bp[0])
                {
 
                if (tTd(40, 4))
                        printf("+++++ %s\n", bp);
                switch (bp[0])
                {
+                 case 'V':             /* queue file version number */
+                       qfver = atoi(&bp[1]);
+                       if (qfver > QF_VERSION)
+                       {
+                               syserr("Version number in qf (%d) greater than max (%d)",
+                                       qfver, QF_VERSION);
+                       }
+                       break;
+
                  case 'C':             /* specify controlling user */
                        ctladdr = setctluser(&bp[1]);
                        break;
                  case 'C':             /* specify controlling user */
                        ctladdr = setctluser(&bp[1]);
                        break;
@@ -1458,6 +1497,7 @@ printqueue()
                auto time_t submittime = 0;
                long dfsize = -1;
                int flags = 0;
                auto time_t submittime = 0;
                long dfsize = -1;
                int flags = 0;
+               int qfver;
                char message[MAXLINE];
                char bodytype[MAXNAME];
 
                char message[MAXLINE];
                char bodytype[MAXNAME];
 
@@ -1478,6 +1518,7 @@ printqueue()
                errno = 0;
 
                message[0] = bodytype[0] = '\0';
                errno = 0;
 
                message[0] = bodytype[0] = '\0';
+               qfver = 0;
                while (fgets(buf, sizeof buf, f) != NULL)
                {
                        register int i;
                while (fgets(buf, sizeof buf, f) != NULL)
                {
                        register int i;
@@ -1486,6 +1527,10 @@ printqueue()
                        fixcrlf(buf, TRUE);
                        switch (buf[0])
                        {
                        fixcrlf(buf, TRUE);
                        switch (buf[0])
                        {
+                         case 'V':     /* queue file version */
+                               qfver = atoi(&buf[1]);
+                               break;
+
                          case 'M':     /* error message */
                                if ((i = strlen(&buf[1])) >= sizeof message)
                                        i = sizeof message - 1;
                          case 'M':     /* error message */
                                if ((i = strlen(&buf[1])) >= sizeof message)
                                        i = sizeof message - 1;
@@ -1526,10 +1571,18 @@ printqueue()
                                break;
 
                          case 'R':     /* recipient name */
                                break;
 
                          case 'R':     /* recipient name */
+                               p = &buf[1];
+                               if (qfver >= 1)
+                               {
+                                       p = strchr(p, ':');
+                                       if (p == NULL)
+                                               break;
+                                       p++;
+                               }
                                if (Verbose)
                                if (Verbose)
-                                       printf("\n\t\t\t\t\t  %.38s", &buf[1]);
+                                       printf("\n\t\t\t\t\t  %.38s", p);
                                else
                                else
-                                       printf("\n\t\t\t\t   %.45s", &buf[1]);
+                                       printf("\n\t\t\t\t   %.45s", p);
                                break;
 
                          case 'T':     /* creation time */
                                break;
 
                          case 'T':     /* creation time */
index 755d6be..b2077be 100644 (file)
@@ -7,7 +7,7 @@
  */
 
 #ifndef lint
  */
 
 #ifndef lint
-static char sccsid[] = "@(#)recipient.c        8.50 (Berkeley) %G%";
+static char sccsid[] = "@(#)recipient.c        8.51 (Berkeley) %G%";
 #endif /* not lint */
 
 # include "sendmail.h"
 #endif /* not lint */
 
 # include "sendmail.h"
@@ -43,7 +43,10 @@ static char sccsid[] = "@(#)recipient.c      8.50 (Berkeley) %G%";
 **             none.
 */
 
 **             none.
 */
 
-# define MAXRCRSN      10
+#define MAXRCRSN       10      /* maximum levels of alias recursion */
+
+/* q_flags bits inherited from ctladdr */
+#define QINHERITEDBITS (QPINGONSUCCESS|QPINGONFAILURE|QPINGONDELAY|QHASRETPARAM|QNOBODYRETURN)
 
 ADDRESS *
 sendto(list, copyf, ctladdr, qflags)
 
 ADDRESS *
 sendto(list, copyf, ctladdr, qflags)
index c1e348b..39a6a44 100644 (file)
@@ -7,7 +7,7 @@
  */
 
 #ifndef lint
  */
 
 #ifndef lint
-static char sccsid[] = "@(#)savemail.c 8.35 (Berkeley) %G%";
+static char sccsid[] = "@(#)savemail.c 8.36 (Berkeley) %G%";
 #endif /* not lint */
 
 # include "sendmail.h"
 #endif /* not lint */
 
 # include "sendmail.h"
@@ -457,6 +457,8 @@ returntosender(msg, returnq, sendbody, e)
        SendBody = sendbody;
        define('g', e->e_from.q_paddr, e);
        define('u', NULL, e);
        SendBody = sendbody;
        define('g', e->e_from.q_paddr, e);
        define('u', NULL, e);
+
+       /* initialize error envelope */
        ee = newenvelope(&errenvelope, e);
        define('a', "\201b", ee);
        define('r', "internal", ee);
        ee = newenvelope(&errenvelope, e);
        define('a', "\201b", ee);
        define('r', "internal", ee);
@@ -505,8 +507,9 @@ returntosender(msg, returnq, sendbody, e)
                (void) sprintf(buf, "%s.%ld/%s",
                        ee->e_id, curtime(), MyHostName);
                ee->e_msgboundary = newstr(buf);
                (void) sprintf(buf, "%s.%ld/%s",
                        ee->e_id, curtime(), MyHostName);
                ee->e_msgboundary = newstr(buf);
-               (void) sprintf(buf, "multipart/mixed; boundary=\"%s\"",
-                                       ee->e_msgboundary);
+               (void) sprintf(buf,
+                       "multipart/report; report-type=delivery-status; boundary=\"%s\"",
+                       ee->e_msgboundary);
                addheader("Content-Type", buf, &ee->e_header);
        }
 
                addheader("Content-Type", buf, &ee->e_header);
        }
 
@@ -661,13 +664,15 @@ errbody(mci, e, separator)
                {
                        if (printheader)
                        {
                {
                        if (printheader)
                        {
-                               putline("   ----- The following addresses had delivery problems -----",
+                               putline("   ----- The following addresses have delivery notifications -----",
                                        mci);
                                printheader = FALSE;
                        }
                        strcpy(buf, q->q_paddr);
                        if (bitset(QBADADDR, q->q_flags))
                                strcat(buf, "  (unrecoverable error)");
                                        mci);
                                printheader = FALSE;
                        }
                        strcpy(buf, q->q_paddr);
                        if (bitset(QBADADDR, q->q_flags))
                                strcat(buf, "  (unrecoverable error)");
+                       else if (bitset(QSENT, q->q_flags))
+                               strcat(buf, "  (successfully delivered)");
                        else
                                strcat(buf, "  (transient failure)");
                        putline(buf, mci);
                        else
                                strcat(buf, "  (transient failure)");
                        putline(buf, mci);
@@ -705,22 +710,143 @@ errbody(mci, e, separator)
        }
        errno = 0;
 
        }
        errno = 0;
 
+       /*
+       **  Output machine-readable version.
+       */
+
+       if (e->e_msgboundary != NULL)
+       {
+               putline("", mci);
+               (void) sprintf(buf, "--%s", e->e_msgboundary);
+               putline(buf, mci);
+               putline("Content-Type: message/delivery-status", mci);
+               putline("", mci);
+
+               /*
+               **  Output per-message information.
+               */
+
+               /* Original-MTS-Type: is optional */
+
+               /* original envelope id from MAIL FROM: line */
+               if (e->e_parent->e_envid != NULL)
+               {
+                       (void) sprintf(buf, "Original-Envelope-Id: %s",
+                               e->e_parent->e_envid);
+                       putline(buf, mci);
+               }
+
+               /* Final-MTS-Type: is optional (always INET?) */
+
+               /* Final-MTA: seems silly -- this is in the From: line */
+               (void) sprintf(buf, "Final-MTA: %s", MyHostName);
+               putline(buf, mci);
+
+               /*
+               **  Output per-address information.
+               */
+
+               for (q = e->e_parent->e_sendqueue; q != NULL; q = q->q_next)
+               {
+                       register ADDRESS *r;
+
+                       if (!bitset(QBADADDR|QREPORT|QRELAYED, q->q_flags))
+                               continue;
+                       putline("", mci);
+
+                       /* Rcpt: -- the name from the RCPT command */
+                       for (r = q; r->q_alias != NULL; r = r->q_alias)
+                               continue;
+                       (void) sprintf(buf, "Rcpt: %s", r->q_paddr);
+                       putline(buf, mci);
+
+                       /* Action: -- what happened? */
+                       if (bitset(QBADADDR, q->q_flags))
+                               putline("Action: failed", mci);
+                       else if (bitset(QQUEUEUP, q->q_flags))
+                               putline("Action: delayed", mci);
+                       else if (bitset(QRELAYED, q->q_flags))
+                               putline("Action: relayed", mci);
+                       else
+                               putline("Action: delivered", mci);
+
+                       /* Status: -- what _really_ happened? */
+                       strcpy(buf, "Status: ");
+                       if (q->q_status != NULL)
+                               strcat(buf, q->q_status);
+                       else if (bitset(QBADADDR, q->q_flags))
+                               strcat(buf, "500");
+                       else if (bitset(QQUEUEUP, q->q_flags))
+                               strcat(buf, "400");
+                       else if (bitset(QRELAYED, q->q_flags))
+                               strcat(buf, "601");
+                       else
+                               strcat(buf, "200");
+                       putline(buf, mci);
+
+                       /* Date: -- fine granularity */
+                       if (q->q_statdate == (time_t) 0L)
+                               q->q_statdate = curtime();
+                       (void) sprintf(buf, "Date: %s",
+                               arpadate(ctime(&q->q_statdate)));
+                       putline(buf, mci);
+
+                       /* Final-Log-Id: -- why isn't this per-message? */
+                       (void) sprintf(buf, "Final-Log-Id: %s", e->e_id);
+                       putline(buf, mci);
+
+                       /* Original-Rcpt: -- passed from on high */
+                       if (q->q_orcpt != NULL)
+                       {
+                               (void) sprintf(buf, "Original-Rcpt: %s",
+                                       q->q_orcpt);
+                               putline(buf, mci);
+                       }
+
+                       /* Final-Rcpt: -- if through alias */
+                       if (q->q_alias != NULL)
+                       {
+                               (void) sprintf(buf, "Final-Rcpt: %s",
+                                       q->q_paddr);
+                               putline(buf, mci);
+                       }
+
+                       /* Final-Status: -- same as Status?  XXX */
+
+                       /* Remote-MTS-Type: -- always INET?  XXX */
+
+                       /* Remote-MTA: -- who was I talking to? */
+                       if (q->q_statmta != NULL)
+                       {
+                               (void) sprintf(buf, "Remote-MTA: %s",
+                                       q->q_statmta);
+                               putline(buf, mci);
+                       }
+
+                       /* Remote-Rcpt: -- same as Final-Rcpt?  XXX */
+
+                       /* Remote-Status: -- same as Final-Status?  XXX */
+               }
+       }
+
        /*
        **  Output text of original message
        */
 
        /*
        **  Output text of original message
        */
 
-       if (bitset(EF_NORETURN, e->e_flags))
+       if (bitset(EF_NORETURN, e->e_parent->e_flags))
                SendBody = FALSE;
        putline("", mci);
        if (e->e_parent->e_df != NULL)
        {
                SendBody = FALSE;
        putline("", mci);
        if (e->e_parent->e_df != NULL)
        {
-               if (SendBody)
-                       putline("   ----- Original message follows -----\n", mci);
+               if (e->e_msgboundary == NULL)
+               {
+                       if (SendBody)
+                               putline("   ----- Original message follows -----\n", mci);
+                       else
+                               putline("   ----- Message header follows -----\n", mci);
+                       (void) fflush(mci->mci_out);
+               }
                else
                else
-                       putline("   ----- Message header follows -----\n", mci);
-               (void) fflush(mci->mci_out);
-
-               if (e->e_msgboundary != NULL)
                {
                        putline("", mci);
                        (void) sprintf(buf, "--%s", e->e_msgboundary);
                {
                        putline("", mci);
                        (void) sprintf(buf, "--%s", e->e_msgboundary);
index 7ce5446..fceb113 100644 (file)
@@ -5,7 +5,7 @@
  *
  * %sccs.include.redist.c%
  *
  *
  * %sccs.include.redist.c%
  *
- *     @(#)sendmail.h  8.65 (Berkeley) %G%
+ *     @(#)sendmail.h  8.66 (Berkeley) %G%
  */
 
 /*
  */
 
 /*
@@ -15,7 +15,7 @@
 # ifdef _DEFINE
 # define EXTERN
 # ifndef lint
 # ifdef _DEFINE
 # define EXTERN
 # ifndef lint
-static char SmailSccsId[] =    "@(#)sendmail.h 8.65            %G%";
+static char SmailSccsId[] =    "@(#)sendmail.h 8.66            %G%";
 # endif
 # else /*  _DEFINE */
 # define EXTERN extern
 # endif
 # else /*  _DEFINE */
 # define EXTERN extern
@@ -112,7 +112,7 @@ struct address
        char            *q_ruser;       /* real user name, or NULL if q_user */
        char            *q_host;        /* host name */
        struct mailer   *q_mailer;      /* mailer to use */
        char            *q_ruser;       /* real user name, or NULL if q_user */
        char            *q_host;        /* host name */
        struct mailer   *q_mailer;      /* mailer to use */
-       u_short         q_flags;        /* status flags, see below */
+       u_long          q_flags;        /* status flags, see below */
        uid_t           q_uid;          /* user-id of receiver (if known) */
        gid_t           q_gid;          /* group-id of receiver (if known) */
        char            *q_home;        /* home dir (local mailer only) */
        uid_t           q_uid;          /* user-id of receiver (if known) */
        gid_t           q_gid;          /* group-id of receiver (if known) */
        char            *q_home;        /* home dir (local mailer only) */
@@ -126,18 +126,24 @@ struct address
 
 typedef struct address ADDRESS;
 
 
 typedef struct address ADDRESS;
 
-# define QDONTSEND     0x0001  /* don't send to this address */
-# define QBADADDR      0x0002  /* this address is verified bad */
-# define QGOODUID      0x0004  /* the q_uid q_gid fields are good */
-# define QPRIMARY      0x0008  /* set from argv */
-# define QQUEUEUP      0x0010  /* queue for later transmission */
-# define QSENT         0x0020  /* has been successfully delivered */
-# define QNOTREMOTE    0x0040  /* not an address for remote forwarding */
-# define QSELFREF      0x0080  /* this address references itself */
-# define QVERIFIED     0x0100  /* verified, but not expanded */
-# define QREPORT       0x0200  /* report this address in return message */
-# define QBOGUSSHELL   0x0400  /* this entry has an invalid shell listed */
-# define QUNSAFEADDR   0x0800  /* address aquired through an unsafe path */
+# define QDONTSEND     0x00000001      /* don't send to this address */
+# define QBADADDR      0x00000002      /* this address is verified bad */
+# define QGOODUID      0x00000004      /* the q_uid q_gid fields are good */
+# define QPRIMARY      0x00000008      /* set from argv */
+# define QQUEUEUP      0x00000010      /* queue for later transmission */
+# define QSENT         0x00000020      /* has been successfully delivered */
+# define QNOTREMOTE    0x00000040      /* address not for remote forwarding */
+# define QSELFREF      0x00000080      /* this address references itself */
+# define QVERIFIED     0x00000100      /* verified, but not expanded */
+# define QREPORT       0x00000200      /* report this addr in return message */
+# define QBOGUSSHELL   0x00000400      /* user has no valid shell listed */
+# define QUNSAFEADDR   0x00000800      /* address aquired via unsafe path */
+# define QPINGONSUCCESS        0x00001000      /* give return on successful delivery */
+# define QPINGONFAILURE        0x00002000      /* give return on failure */
+# define QPINGONDELAY  0x00004000      /* give return on message delay */
+# define QHASRETPARAM  0x00008000      /* RCPT command had RET argument */
+# define QNOBODYRETURN 0x00010000      /* don't return message body */
+# define QRELAYED      0x00020000      /* relayed to non-DSN aware mailer */
 
 # define NULLADDR      ((ADDRESS *) NULL)
 # define QPSEUDO       000040  /* only on the list for verification */
 
 # define NULLADDR      ((ADDRESS *) NULL)
 # define QPSEUDO       000040  /* only on the list for verification */
@@ -305,6 +311,7 @@ MCI
 #define MCIF_MULTSTAT  0x0100          /* MAIL11V3: handles MULT status */
 #define MCIF_INHEADER  0x0200          /* currently outputing header */
 #define MCIF_CVT8TO7   0x0400          /* convert from 8 to 7 bits */
 #define MCIF_MULTSTAT  0x0100          /* MAIL11V3: handles MULT status */
 #define MCIF_INHEADER  0x0200          /* currently outputing header */
 #define MCIF_CVT8TO7   0x0400          /* convert from 8 to 7 bits */
+#define MCIF_DSN       0x0800          /* DSN extension supported */
 
 /* states */
 #define MCIS_CLOSED    0               /* no traffic on this connection */
 
 /* states */
 #define MCIS_CLOSED    0               /* no traffic on this connection */
@@ -364,6 +371,7 @@ ENVELOPE
        char            *e_statmsg;     /* stat msg (changes per delivery) */
        char            *e_msgboundary; /* MIME-style message part boundary */
        char            *e_origrcpt;    /* original recipient (one only) */
        char            *e_statmsg;     /* stat msg (changes per delivery) */
        char            *e_msgboundary; /* MIME-style message part boundary */
        char            *e_origrcpt;    /* original recipient (one only) */
+       char            *e_envid;       /* envelope id from MAIL FROM: line */
        time_t          e_dtime;        /* time of last delivery attempt */
        int             e_ntries;       /* number of delivery attempts */
        dev_t           e_dfdev;        /* df file's device, for crash recov */
        time_t          e_dtime;        /* time of last delivery attempt */
        int             e_ntries;       /* number of delivery attempts */
        dev_t           e_dfdev;        /* df file's device, for crash recov */
index eed76dd..20fd024 100644 (file)
@@ -10,9 +10,9 @@
 
 #ifndef lint
 #ifdef SMTP
 
 #ifndef lint
 #ifdef SMTP
-static char sccsid[] = "@(#)srvrsmtp.c 8.44 (Berkeley) %G% (with SMTP)";
+static char sccsid[] = "@(#)srvrsmtp.c 8.45 (Berkeley) %G% (with SMTP)";
 #else
 #else
-static char sccsid[] = "@(#)srvrsmtp.c 8.44 (Berkeley) %G% (without SMTP)";
+static char sccsid[] = "@(#)srvrsmtp.c 8.45 (Berkeley) %G% (without SMTP)";
 #endif
 #endif /* not lint */
 
 #endif
 #endif /* not lint */
 
@@ -443,6 +443,15 @@ smtp(e)
                                                /* NOTREACHED */
                                        }
                                }
                                                /* NOTREACHED */
                                        }
                                }
+                               else if (strcasecmp(kp, "envid") == 0)
+                               {
+                                       if (vp == NULL)
+                                       {
+                                               usrerr("501 ENVID requires a value");
+                                               /* NOTREACHED */
+                                       }
+                                       e->e_envid = newstr(vp);
+                               }
                                else
                                {
                                        usrerr("501 %s parameter unrecognized", kp);
                                else
                                {
                                        usrerr("501 %s parameter unrecognized", kp);
index 493a6da..3eb7d38 100644 (file)
@@ -10,9 +10,9 @@
 
 #ifndef lint
 #ifdef SMTP
 
 #ifndef lint
 #ifdef SMTP
-static char sccsid[] = "@(#)usersmtp.c 8.22 (Berkeley) %G% (with SMTP)";
+static char sccsid[] = "@(#)usersmtp.c 8.23 (Berkeley) %G% (with SMTP)";
 #else
 #else
-static char sccsid[] = "@(#)usersmtp.c 8.22 (Berkeley) %G% (without SMTP)";
+static char sccsid[] = "@(#)usersmtp.c 8.23 (Berkeley) %G% (without SMTP)";
 #endif
 #endif /* not lint */
 
 #endif
 #endif /* not lint */
 
@@ -281,6 +281,8 @@ helo_options(line, m, mci, e)
        }
        else if (strcasecmp(line, "expn") == 0)
                mci->mci_flags |= MCIF_EXPN;
        }
        else if (strcasecmp(line, "expn") == 0)
                mci->mci_flags |= MCIF_EXPN;
+       else if (strcasecmp(line, "dsn") == 0)
+               mci->mci_flags |= MCIF_DSN;
 }
 \f/*
 **  SMTPMAILFROM -- send MAIL command
 }
 \f/*
 **  SMTPMAILFROM -- send MAIL command
@@ -326,6 +328,12 @@ smtpmailfrom(m, mci, e)
                }
        }
 
                }
        }
 
+       if (e->e_envid != NULL && bitset(MCIF_DSN, mci->mci_flags))
+       {
+               strcat(optbuf, " ENVID=");
+               strcat(optbuf, e->e_envid);
+       }
+
        /*
        **  Send the HOPS command.
        **      This is non-standard and may give an "unknown command".
        /*
        **  Send the HOPS command.
        **      This is non-standard and may give an "unknown command".
@@ -425,12 +433,48 @@ smtprcpt(to, m, mci, e)
        ENVELOPE *e;
 {
        register int r;
        ENVELOPE *e;
 {
        register int r;
+       char optbuf[MAXLINE];
+
+       strcpy(optbuf, "");
+       if (bitset(MCIF_DSN, mci->mci_flags))
+       {
+               strcat(optbuf, " NOTIFY=");
+               if (bitset(QPINGONFAILURE, to->q_flags))
+               {
+                       if (bitset(QPINGONSUCCESS, to->q_flags))
+                               strcat(optbuf, "ALWAYS");
+                       else
+                               strcat(optbuf, "FAILURE");
+               }
+               else
+               {
+                       if (bitset(QPINGONSUCCESS, to->q_flags))
+                               strcat(optbuf, "SUCCESS");
+                       else
+                               strcat(optbuf, "NEVER");
+               }
+               if (bitset(QHASRETPARAM, to->q_flags))
+               {
+                       strcat(optbuf, " RET=");
+                       if (bitset(QNOBODYRETURN, to->q_flags))
+                               strcat(optbuf, "NO");
+                       else
+                               strcat(optbuf, "YES");
+               }
+       }
+       else if (bitset(QPINGONSUCCESS, to->q_flags))
+       {
+               to->q_flags |= QRELAYED;
+               fprintf(e->e_xfp, "%s... relayed; expect no further notifications\n",
+                       to->q_paddr);
+       }
 
 
-       smtpmessage("RCPT To:<%s>", m, mci, to->q_user);
+       smtpmessage("RCPT To:<%s>%s", m, mci, to->q_user, optbuf);
 
        SmtpPhase = mci->mci_phase = "client RCPT";
        setproctitle("%s %s: %s", e->e_id, CurHostName, mci->mci_phase);
        r = reply(m, mci, e, TimeOuts.to_rcpt, NULL);
 
        SmtpPhase = mci->mci_phase = "client RCPT";
        setproctitle("%s %s: %s", e->e_id, CurHostName, mci->mci_phase);
        r = reply(m, mci, e, TimeOuts.to_rcpt, NULL);
+       setstatus(to, SmtpReplyBuffer);
        if (r < 0 || REPLYTYPE(r) == 4)
                return (EX_TEMPFAIL);
        else if (REPLYTYPE(r) == 2)
        if (r < 0 || REPLYTYPE(r) == 4)
                return (EX_TEMPFAIL);
        else if (REPLYTYPE(r) == 2)