]> git.ipfire.org Git - thirdparty/postfix.git/commitdiff
postfix-1.1.11-20021025
authorWietse Venema <wietse@porcupine.org>
Fri, 25 Oct 2002 05:00:00 +0000 (00:00 -0500)
committerViktor Dukhovni <viktor@dukhovni.org>
Tue, 5 Feb 2013 06:28:20 +0000 (06:28 +0000)
68 files changed:
postfix/HISTORY
postfix/conf/aliases
postfix/html/error.8.html
postfix/html/lmtp.8.html
postfix/html/pipe.8.html
postfix/html/smtp.8.html
postfix/html/smtpd.8.html
postfix/man/man8/lmtp.8
postfix/man/man8/pipe.8
postfix/man/man8/smtp.8
postfix/man/man8/smtpd.8
postfix/src/bounce/bounce.c
postfix/src/cleanup/cleanup.h
postfix/src/cleanup/cleanup_api.c
postfix/src/cleanup/cleanup_envelope.c
postfix/src/cleanup/cleanup_extracted.c
postfix/src/cleanup/cleanup_map1n.c
postfix/src/cleanup/cleanup_out_recipient.c
postfix/src/cleanup/cleanup_state.c
postfix/src/error/error.c
postfix/src/global/bounce.c
postfix/src/global/bounce.h
postfix/src/global/defer.c
postfix/src/global/defer.h
postfix/src/global/deliver_pass.c
postfix/src/global/deliver_pass.h
postfix/src/global/deliver_request.c
postfix/src/global/deliver_request.h
postfix/src/global/mail_copy.c
postfix/src/global/mail_copy.h
postfix/src/global/mail_proto.h
postfix/src/global/mail_version.h
postfix/src/global/pipe_command.c
postfix/src/global/pipe_command.h
postfix/src/global/recipient_list.c
postfix/src/global/recipient_list.h
postfix/src/global/sent.c
postfix/src/global/sent.h
postfix/src/lmtp/lmtp.c
postfix/src/lmtp/lmtp_proto.c
postfix/src/lmtp/lmtp_trouble.c
postfix/src/local/local.c
postfix/src/local/local.h
postfix/src/local/mailbox.c
postfix/src/local/unknown.c
postfix/src/master/Makefile.in
postfix/src/nqmgr/qmgr.h
postfix/src/nqmgr/qmgr_bounce.c
postfix/src/nqmgr/qmgr_defer.c
postfix/src/nqmgr/qmgr_deliver.c
postfix/src/nqmgr/qmgr_message.c
postfix/src/nqmgr/qmgr_rcpt_list.c
postfix/src/pickup/pickup.c
postfix/src/pipe/pipe.c
postfix/src/qmgr/qmgr.h
postfix/src/qmgr/qmgr_bounce.c
postfix/src/qmgr/qmgr_defer.c
postfix/src/qmgr/qmgr_deliver.c
postfix/src/qmgr/qmgr_message.c
postfix/src/qmgr/qmgr_rcpt_list.c
postfix/src/qmqpd/Makefile.in
postfix/src/smtp/smtp.c
postfix/src/smtp/smtp_proto.c
postfix/src/smtp/smtp_trouble.c
postfix/src/smtpd/smtpd.c
postfix/src/util/safe_open.c
postfix/src/virtual/virtual.c
postfix/src/virtual/virtual.h

index 3192c07e726e94c385f9e685e1541fc9061cf421..ff08a78fb8944992fc52cbe3a26bd6d44df2ff33 100644 (file)
@@ -7075,6 +7075,14 @@ Apologies for any names omitted.
        Files: global/mail_params.[hc] global/own_inet_addr.[hc]
        global/resolve_local.c smtp/smtp_addr.c smtpd/smtpd_check.c.
 
+       Paranoia: defend against a very unlikely false alarm in
+       safe_open().
+
+20020125
+
+       Feature: X-Original-To: message headers with the raw original
+       envelope recipient.
+
 Open problems:
 
        Low: smtpd should log queue ID with reject/warn/hold/discard
index 9e43ebc241d01ade731240c545749b3b3da27d32..2b44b3aa111c9efe1e1972ccc40ae7a258b6819c 100644 (file)
@@ -8,6 +8,9 @@
 #      >>>>>>>>>>      show through to Postfix.
 #
 
+# Person who should get root's mail. Don't receive mail as root!
+#root:         you
+
 # Basic system aliases -- these MUST be present
 MAILER-DAEMON: postmaster
 postmaster:    root
@@ -33,9 +36,6 @@ abuse:                postmaster
 # trap decode to catch security attacks
 decode:                root
 
-# Person who should get root's mail
-#root:         you
-
 # 
 # ALIASES(5)                                             ALIASES(5)
 # 
index a96801b32503d60260e29e6da87e7288d89e7c1e..308870567f770f535f581cfd59319362acb3132c 100644 (file)
@@ -1,5 +1,4 @@
 <html> <head> </head> <body> <pre>
-
 ERROR(8)                                                 ERROR(8)
 
 <b>NAME</b>
@@ -72,6 +71,5 @@ ERROR(8)                                                 ERROR(8)
        P.O. Box 704
        Yorktown Heights, NY 10598, USA
 
-                                                                1
-
+                                                         ERROR(8)
 </pre> </body> </html>
index 08e1947523dba575123e8bfc9328639bce886e30..1f9342a088be080daef972168269f825e700f3f2 100644 (file)
@@ -58,9 +58,9 @@ LMTP(8)                                                   LMTP(8)
        <a href="http://www.faqs.org/rfcs/rfc1652.html">RFC 1652</a> (8bit-MIME transport)
        <a href="http://www.faqs.org/rfcs/rfc1870.html">RFC 1870</a> (Message Size Declaration)
        <a href="http://www.faqs.org/rfcs/rfc2033.html">RFC 2033</a> (LMTP protocol)
-       <a href="http://www.faqs.org/rfcs/rfc2197.html">RFC 2197</a> (Pipelining)
        <a href="http://www.faqs.org/rfcs/rfc2554.html">RFC 2554</a> (AUTH command)
        <a href="http://www.faqs.org/rfcs/rfc2821.html">RFC 2821</a> (SMTP protocol)
+       <a href="http://www.faqs.org/rfcs/rfc2920.html">RFC 2920</a> (SMTP Pipelining)
 
 <b>DIAGNOSTICS</b>
        Problems  and transactions are logged to <b>syslogd</b>(8).  Cor-
index d74f25b3e10bc8ce1ab6a4ee09860b549fa8a8bb..bb6a6561c91257629da93f8eeb3f173d18064625 100644 (file)
@@ -43,7 +43,7 @@ PIPE(8)                                                   PIPE(8)
        file at the end of a service definition.  The syntax is as
        follows:
 
-       <b>flags=BDFRhqu.</b>&gt; (optional)
+       <b>flags=BDFORhqu.</b>&gt; (optional)
               Optional message processing flags.  By  default,  a
               message is copied unchanged.
 
@@ -61,6 +61,12 @@ PIPE(8)                                                   PIPE(8)
                      header to  the  message  content.   This  is
                      expected by, for example, <b>UUCP</b> software.
 
+              <b>O</b>      Prepend  an  "<b>X-Original-To:</b> <i>recipient</i>" mes-
+                     sage  header  with  the  original   envelope
+                     recipient  address.  Note: for this to work,
+                     the    <i>transport_</i><b>destination</b><i>_</i><b>recipient</b><i>_</i><b>limit</b>
+                     must be 1.
+
               <b>R</b>      Prepend  a  <b>Return-Path:</b> message header with
                      the envelope sender address.
 
index d6f733457f6da956fbab8c80d20fe1e909a16034..7e6267be3518f4542e0a11632fac609cf4d38b2b 100644 (file)
@@ -48,9 +48,9 @@ SMTP(8)                                                   SMTP(8)
        <a href="http://www.faqs.org/rfcs/rfc1870.html">RFC 1870</a> (Message Size Declaration)
        <a href="http://www.faqs.org/rfcs/rfc2045.html">RFC 2045</a> (MIME: Format of Internet Message Bodies)
        <a href="http://www.faqs.org/rfcs/rfc2046.html">RFC 2046</a> (MIME: Media Types)
-       <a href="http://www.faqs.org/rfcs/rfc2197.html">RFC 2197</a> (Pipelining)
        <a href="http://www.faqs.org/rfcs/rfc2554.html">RFC 2554</a> (AUTH command)
        <a href="http://www.faqs.org/rfcs/rfc2821.html">RFC 2821</a> (SMTP protocol)
+       <a href="http://www.faqs.org/rfcs/rfc2920.html">RFC 2920</a> (SMTP Pipelining)
 
 <b>DIAGNOSTICS</b>
        Problems and transactions are logged to <b>syslogd</b>(8).   Cor-
index a040d0ae3757e2984a6bc895bd95157462ed7c8f..77245cdc76bc2e9b77d18b2c73dbb6e8598f48ab 100644 (file)
@@ -36,11 +36,11 @@ SMTPD(8)                                                 SMTPD(8)
        <a href="http://www.faqs.org/rfcs/rfc1123.html">RFC 1123</a> (Host requirements)
        <a href="http://www.faqs.org/rfcs/rfc1652.html">RFC 1652</a> (8bit-MIME transport)
        <a href="http://www.faqs.org/rfcs/rfc1869.html">RFC 1869</a> (SMTP service extensions)
-       <a href="http://www.faqs.org/rfcs/rfc1854.html">RFC 1854</a> (SMTP Pipelining)
        <a href="http://www.faqs.org/rfcs/rfc1870.html">RFC 1870</a> (Message Size Declaration)
        <a href="http://www.faqs.org/rfcs/rfc1985.html">RFC 1985</a> (ETRN command)
        <a href="http://www.faqs.org/rfcs/rfc2554.html">RFC 2554</a> (AUTH command)
        <a href="http://www.faqs.org/rfcs/rfc2821.html">RFC 2821</a> (SMTP protocol)
+       <a href="http://www.faqs.org/rfcs/rfc2920.html">RFC 2920</a> (SMTP Pipelining)
 
 <b>DIAGNOSTICS</b>
        Problems and transactions are logged to <b>syslogd</b>(8).
index c53e0033ce609499d94c222ad3926342038ef275..75e42c57aad8ef0dea89b4ff045ea726733d6e86 100644 (file)
@@ -59,9 +59,9 @@ RFC 1651 (SMTP service extensions)
 RFC 1652 (8bit-MIME transport)
 RFC 1870 (Message Size Declaration)
 RFC 2033 (LMTP protocol)
-RFC 2197 (Pipelining)
 RFC 2554 (AUTH command)
 RFC 2821 (SMTP protocol)
+RFC 2920 (SMTP Pipelining)
 .SH DIAGNOSTICS
 .ad
 .fi
index 233e7df3e510d9c7177d89a9e9c18f52cbaa0af1..c9370599941e2361dc758064c3ddc6d542595cf3 100644 (file)
@@ -50,7 +50,7 @@ entry for the pipe-based delivery transport.
 .fi
 The external command attributes are given in the \fBmaster.cf\fR
 file at the end of a service definition.  The syntax is as follows:
-.IP "\fBflags=BDFRhqu.>\fR (optional)"
+.IP "\fBflags=BDFORhqu.>\fR (optional)"
 Optional message processing flags. By default, a message is
 copied unchanged.
 .RS
@@ -66,6 +66,10 @@ envelope recipient address. Note: for this to work, the
 Prepend a "\fBFrom \fIsender time_stamp\fR" envelope header to
 the message content.
 This is expected by, for example, \fBUUCP\fR software.
+.IP \fBO\fR
+Prepend an "\fBX-Original-To: \fIrecipient\fR" message header
+with the original envelope recipient address. Note: for this to work,
+the \fItransport\fB_destination_recipient_limit\fR must be 1.
 .IP \fBR\fR
 Prepend a \fBReturn-Path:\fR message header with the envelope sender
 address.
index 018a6f6b780ad1c3295e95ea150d1b009864ce78..15bee3addf77abd047e22a359571583ba9fa412f 100644 (file)
@@ -53,9 +53,9 @@ RFC 1652 (8bit-MIME transport)
 RFC 1870 (Message Size Declaration)
 RFC 2045 (MIME: Format of Internet Message Bodies)
 RFC 2046 (MIME: Media Types)
-RFC 2197 (Pipelining)
 RFC 2554 (AUTH command)
 RFC 2821 (SMTP protocol)
+RFC 2920 (SMTP Pipelining)
 .SH DIAGNOSTICS
 .ad
 .fi
index 393e85b5c1fe5c56d3d199483f4412e2a7c53207..fe5ab654ad7c7d14cf2a1cd46cd5f832fadeb776 100644 (file)
@@ -44,11 +44,11 @@ RFC 821 (SMTP protocol)
 RFC 1123 (Host requirements)
 RFC 1652 (8bit-MIME transport)
 RFC 1869 (SMTP service extensions)
-RFC 1854 (SMTP Pipelining)
 RFC 1870 (Message Size Declaration)
 RFC 1985 (ETRN command)
 RFC 2554 (AUTH command)
 RFC 2821 (SMTP protocol)
+RFC 2920 (SMTP Pipelining)
 .SH DIAGNOSTICS
 .ad
 .fi
index dd92ec8f56c13395f8cc086c16c96474d84e0d9a..0e33b3d2b1a2641174fcc889b68f5dfe9588bf59 100644 (file)
@@ -127,6 +127,7 @@ char   *var_delay_rcpt;
   */
 static VSTRING *queue_id;
 static VSTRING *queue_name;
+static VSTRING *orig_rcpt;
 static VSTRING *recipient;
 static VSTRING *encoding;
 static VSTRING *sender;
@@ -147,9 +148,10 @@ static int bounce_append_proto(char *service_name, VSTREAM *client)
     if (mail_command_server(client,
                            ATTR_TYPE_NUM, MAIL_ATTR_FLAGS, &flags,
                            ATTR_TYPE_STR, MAIL_ATTR_QUEUEID, queue_id,
+                           ATTR_TYPE_STR, MAIL_ATTR_ORCPT, orig_rcpt,
                            ATTR_TYPE_STR, MAIL_ATTR_RECIP, recipient,
                            ATTR_TYPE_STR, MAIL_ATTR_WHY, why,
-                           ATTR_TYPE_END) != 4) {
+                           ATTR_TYPE_END) != 5) {
        msg_warn("malformed request");
        return (-1);
     }
@@ -298,9 +300,10 @@ static int bounce_one_proto(char *service_name, VSTREAM *client)
                            ATTR_TYPE_STR, MAIL_ATTR_QUEUEID, queue_id,
                            ATTR_TYPE_STR, MAIL_ATTR_ENCODING, encoding,
                            ATTR_TYPE_STR, MAIL_ATTR_SENDER, sender,
+                           ATTR_TYPE_STR, MAIL_ATTR_ORCPT, orig_rcpt,
                            ATTR_TYPE_STR, MAIL_ATTR_RECIP, recipient,
                            ATTR_TYPE_STR, MAIL_ATTR_WHY, why,
-                           ATTR_TYPE_END) != 7) {
+                           ATTR_TYPE_END) != 8) {
        msg_warn("malformed request");
        return (-1);
     }
@@ -403,6 +406,7 @@ static void post_jail_init(char *unused_name, char **unused_argv)
      */
     queue_id = vstring_alloc(10);
     queue_name = vstring_alloc(10);
+    orig_rcpt = vstring_alloc(10);
     recipient = vstring_alloc(10);
     encoding = vstring_alloc(10);
     sender = vstring_alloc(10);
index 94ca492bb94eecfb94aa68bccc0fb76432cc62b1..92fb6bb629755346555d3f087d32438d1025aee6 100644 (file)
@@ -43,6 +43,7 @@ typedef struct CLEANUP_STATE {
     char   *from;                      /* From: address */
     char   *resent_from;               /* Resent-From: address */
     char   *recip;                     /* envelope recipient address */
+    char   *orig_rcpt;                 /* original recipient address */
     char   *return_receipt;            /* return-receipt address */
     char   *errors_to;                 /* errors-to address */
     int     flags;                     /* processing options */
@@ -168,7 +169,7 @@ extern void cleanup_map11_tree(CLEANUP_STATE *, TOK822 *, MAPS *, int);
  /*
   * cleanup_map1n.c
   */
-ARGV   *cleanup_map1n_internal(CLEANUP_STATE *, char *, MAPS *, int);
+ARGV   *cleanup_map1n_internal(CLEANUP_STATE *, const char *, MAPS *, int);
 
  /*
   * cleanup_masquerade.c
@@ -180,7 +181,7 @@ extern void cleanup_masquerade_tree(TOK822 *, ARGV *);
  /*
   * Cleanup_recipient.c
   */
-extern void cleanup_out_recipient(CLEANUP_STATE *, char *);
+extern void cleanup_out_recipient(CLEANUP_STATE *, const char *, const char *);
 
 /* LICENSE
 /* .ad
index a4261c0fa359b664156600ea96de6e4db3b8fdc4..6464b4827ccec47366e9d13d34dc485be6b3cf29 100644 (file)
@@ -253,6 +253,7 @@ int     cleanup_flush(CLEANUP_STATE *state)
     if (state->errs != 0) {
        if (CAN_BOUNCE()) {
            if (bounce_append(BOUNCE_FLAG_CLEAN, state->queue_id,
+                             state->recip ? state->recip : "unknown",
                              state->recip ? state->recip : "unknown",
                              "cleanup", state->time,
                              "%s", state->reason ? state->reason :
index 3d0c2019e9abf272e71cb98b396b016ed6476c57..64b56e6ffcd77cc86e06da859e9539fec1f76c13 100644 (file)
@@ -180,6 +180,8 @@ static void cleanup_envelope_process(CLEANUP_STATE *state, int type, char *buf,
            state->errs |= CLEANUP_STAT_BAD;
            return;
        }
+       if (state->orig_rcpt == 0)
+           state->orig_rcpt = mystrdup(buf);
        cleanup_rewrite_internal(clean_addr, *buf ? buf : var_empty_addr);
        if (cleanup_rcpt_canon_maps)
            cleanup_map11_internal(state, clean_addr, cleanup_rcpt_canon_maps,
@@ -190,10 +192,12 @@ static void cleanup_envelope_process(CLEANUP_STATE *state, int type, char *buf,
        if (cleanup_masq_domains
            && (cleanup_masq_flags & CLEANUP_MASQ_FLAG_ENV_RCPT))
            cleanup_masquerade_internal(clean_addr, cleanup_masq_domains);
-       cleanup_out_recipient(state, STR(clean_addr));
+       cleanup_out_recipient(state, state->orig_rcpt, STR(clean_addr));
        if (state->recip == 0)
            state->recip = mystrdup(STR(clean_addr));
        vstring_free(clean_addr);
+       myfree(state->orig_rcpt);
+       state->orig_rcpt = 0;
     } else if (type == REC_TYPE_WARN) {
        if ((state->warn_time = atol(buf)) < 0) {
            state->errs |= CLEANUP_STAT_BAD;
@@ -227,6 +231,14 @@ static void cleanup_envelope_process(CLEANUP_STATE *state, int type, char *buf,
        }
        nvtable_update(state->attr, attr_name, attr_value);
     } else {
+       if (state->orig_rcpt != 0) {
+           msg_warn("%s: out-of-order original recipient <%.200s>",
+                    state->queue_id, buf);
+           myfree(state->orig_rcpt);
+           state->orig_rcpt = 0;
+       }
+       if (type == REC_TYPE_ORCP)
+           state->orig_rcpt = mystrdup(buf);
        cleanup_out(state, type, buf, len);
     }
 }
index a1c9d6b079ba197894d05e5e77669f3c2131bbf7..f964380f7de90a43336de950f419024b21a7bb41 100644 (file)
@@ -129,6 +129,8 @@ static void cleanup_extracted_process(CLEANUP_STATE *state, int type, char *buf,
 
     if (type == REC_TYPE_RCPT) {
        clean_addr = vstring_alloc(100);
+       if (state->orig_rcpt == 0)
+           state->orig_rcpt = mystrdup(buf);
        cleanup_rewrite_internal(clean_addr, *buf ? buf : var_empty_addr);
        if (cleanup_rcpt_canon_maps)
            cleanup_map11_internal(state, clean_addr, cleanup_rcpt_canon_maps,
@@ -139,11 +141,22 @@ static void cleanup_extracted_process(CLEANUP_STATE *state, int type, char *buf,
        if (cleanup_masq_domains
            && (cleanup_masq_flags & CLEANUP_MASQ_FLAG_ENV_RCPT))
            cleanup_masquerade_internal(clean_addr, cleanup_masq_domains);
-       cleanup_out_recipient(state, STR(clean_addr));
+       cleanup_out_recipient(state, state->orig_rcpt, STR(clean_addr));
        if (state->recip == 0)
            state->recip = mystrdup(STR(clean_addr));
        vstring_free(clean_addr);
+       myfree(state->orig_rcpt);
+       state->orig_rcpt = 0;
        return;
+    } else {
+       if (state->orig_rcpt != 0) {
+           msg_warn("%s: out-of-order original recipient <%.200s>",
+                    state->queue_id, buf);
+           myfree(state->orig_rcpt);
+           state->orig_rcpt = 0;
+       }
+       if (type == REC_TYPE_ORCP)
+           state->orig_rcpt = mystrdup(buf);
     }
     if (type != REC_TYPE_END) {
        cleanup_out(state, type, buf, len);
@@ -187,9 +200,10 @@ static void cleanup_extracted_process(CLEANUP_STATE *state, int type, char *buf,
                    && (cleanup_masq_flags & CLEANUP_MASQ_FLAG_ENV_RCPT)) {
                    vstring_strcpy(clean_addr, *cpp);
                    cleanup_masquerade_internal(clean_addr, cleanup_masq_domains);
-                   cleanup_out_recipient(state, STR(clean_addr));
+                   cleanup_out_recipient(state, STR(clean_addr),
+                                         STR(clean_addr));     /* XXX */
                } else
-                   cleanup_out_recipient(state, *cpp);
+                   cleanup_out_recipient(state, *cpp, *cpp);   /* XXX */
            }
            if (rcpt->argv[0])
                state->recip = mystrdup(rcpt->argv[0]);
index 4e6e6f290e99236c11fec81615d48a4876e03832..e83f4fb62855d18dee485ac64ac70bb83a94e129 100644 (file)
@@ -6,8 +6,11 @@
 /* SYNOPSIS
 /*     #include <cleanup.h>
 /*
-/*     ARGV    *cleanup_map1n_internal(addr)
-/*     char    *addr;
+/*     ARGV    *cleanup_map1n_internal(state, addr, maps, propagate)
+/*     CLEANUP_STATE *state;
+/*     const char *addr;
+/*     MAPS    *maps;
+/*     int     propagate;
 /* DESCRIPTION
 /*     This module implements one-to-many table mapping via table lookup.
 /*     Table lookups are done with quoted (externalized) address forms.
@@ -63,7 +66,7 @@
 
 /* cleanup_map1n_internal - one-to-many table lookups */
 
-ARGV   *cleanup_map1n_internal(CLEANUP_STATE *state, char *addr,
+ARGV   *cleanup_map1n_internal(CLEANUP_STATE *state, const char *addr,
                                       MAPS *maps, int propagate)
 {
     ARGV   *argv;
index bb283aa3cc6bb6bc166bee8df96ddefb9d637852..a45bba88b460525c08120a4e0ed1d180cf6e08f2 100644 (file)
@@ -6,9 +6,10 @@
 /* SYNOPSIS
 /*     #include "cleanup.h"
 /*
-/*     void    cleanup_out_recipient(state, recipient)
+/*     void    cleanup_out_recipient(state, orig_recipient, recipient)
 /*     CLEANUP_STATE *state;
-/*     char    *recipient;
+/*     const char *orig_recipient;
+/*     const char *recipient;
 /* DESCRIPTION
 /*     This module implements an envelope recipient output filter.
 /*
 /* System library. */
 
 #include <sys_defs.h>
+#include <string.h>
+
+#ifdef STRCASECMP_IN_STRINGS_H
+#include <strings.h>
+#endif
 
 /* Utility library. */
 
 
 /* cleanup_out_recipient - envelope recipient output filter */
 
-void    cleanup_out_recipient(CLEANUP_STATE *state, char *recip)
+void    cleanup_out_recipient(CLEANUP_STATE *state, const char *orcpt,
+                                     const char *recip)
 {
     ARGV   *argv;
     char  **cpp;
 
     if (cleanup_virtual_maps == 0) {
-       if (been_here_fixed(state->dups, recip) == 0)
-           cleanup_out_string(state, REC_TYPE_RCPT, recip), state->rcpt_count++;
+       if (been_here_fixed(state->dups, orcpt) == 0) {
+           if (strcasecmp(orcpt, recip) != 0)
+               cleanup_out_string(state, REC_TYPE_ORCP, orcpt);
+           cleanup_out_string(state, REC_TYPE_RCPT, recip);
+           state->rcpt_count++;
+       }
     } else {
        argv = cleanup_map1n_internal(state, recip, cleanup_virtual_maps,
                                  cleanup_ext_prop_mask & EXT_PROP_VIRTUAL);
-       for (cpp = argv->argv; *cpp; cpp++)
-           if (been_here_fixed(state->dups, *cpp) == 0)
-               cleanup_out_string(state, REC_TYPE_RCPT, *cpp), state->rcpt_count++;
+       if (been_here_fixed(state->dups, orcpt) == 0) {
+           for (cpp = argv->argv; *cpp; cpp++) {
+               cleanup_out_string(state, REC_TYPE_ORCP, orcpt);
+               cleanup_out_string(state, REC_TYPE_RCPT, *cpp);
+               state->rcpt_count++;
+           }
+       }
        argv_free(argv);
     }
 }
index 1e7bb8890a7a415c3d57d9f38179724038567051..522db49c238b0ef36685bb7668985b884c1e4045 100644 (file)
@@ -68,6 +68,7 @@ CLEANUP_STATE *cleanup_state_alloc(void)
     state->from = 0;
     state->resent_from = 0;
     state->recip = 0;
+    state->orig_rcpt = 0;
     state->return_receipt = 0;
     state->errors_to = 0;
     state->flags = 0;
@@ -110,6 +111,8 @@ void    cleanup_state_free(CLEANUP_STATE *state)
        myfree(state->resent_from);
     if (state->recip)
        myfree(state->recip);
+    if (state->orig_rcpt)
+       myfree(state->orig_rcpt);
     if (state->return_receipt)
        myfree(state->return_receipt);
     if (state->errors_to)
index 3b43f519b05a7148f2ee3efb1384f0a54a2910eb..7129f31293f8435cdc548052676a688fd69eeba7 100644 (file)
@@ -129,7 +129,7 @@ static int deliver_message(DELIVER_REQUEST *request)
        rcpt = request->rcpt_list.info + nrcpt;
        if (rcpt->offset >= 0) {
            status = bounce_append(BOUNCE_FLAG_KEEP, request->queue_id,
-                                  rcpt->address, "error",
+                                  rcpt->orig_addr, rcpt->address, "error",
                                   request->arrival_time,
                                   "%s", request->nexthop);
            if (status == 0)
index 14b74f84b96ae4dac4b079868878bf953daa0795..13d5fc20fc57df57ed92f4225a750c7ae0721a12 100644 (file)
@@ -6,17 +6,21 @@
 /* SYNOPSIS
 /*     #include <bounce.h>
 /*
-/*     int     bounce_append(flags, id, recipient, relay, entry, format, ...)
+/*     int     bounce_append(flags, id, orig_rcpt, recipient, relay,
+/*                             entry, format, ...)
 /*     int     flags;
 /*     const char *id;
+/*     const char *orig_rcpt;
 /*     const char *recipient;
 /*     const char *relay;
 /*     time_t  entry;
 /*     const char *format;
 /*
-/*     int     vbounce_append(flags, id, recipient, relay, entry, format, ap)
+/*     int     vbounce_append(flags, id, orig_rcpt, recipient, relay,
+/*                             entry, format, ap)
 /*     int     flags;
 /*     const char *id;
+/*     const char *orig_rcpt;
 /*     const char *recipient;
 /*     const char *relay;
 /*     time_t  entry;
 /*     time_t  entry;
 /*     const char *format;
 /*
-/*     int     vbounce_one(flags, queue, id, encoding, sender,
+/*     int     vbounce_one(flags, queue, id, encoding, sender, orig_rcpt,
 /*                             recipient, relay, entry, format, ap)
 /*     int     flags;
 /*     const char *queue;
 /*     const char *id;
 /*     const char *encoding;
 /*     const char *sender;
+/*     const char *orig_rcpt;
 /*     const char *recipient;
 /*     const char *relay;
 /*     time_t  entry;
 /*     the specified sender, including the bounce log that was
 /*     built with bounce_append().
 /*
-/*     bounce_one() bounces one recipient and immediately sends a 
-/*     notification to the sender. This procedure does not append 
-/*     the recipient and reason to the per-message bounce log, and 
-/*     should be used when a delivery agent changes the error 
+/*     bounce_one() bounces one recipient and immediately sends a
+/*     notification to the sender. This procedure does not append
+/*     the recipient and reason to the per-message bounce log, and
+/*     should be used when a delivery agent changes the error
 /*     return address in a manner that depends on the recipient
 /*     address.
 /*
 /*     This information is used for syslogging only.
 /* .IP entry
 /*     Message arrival time.
+/* .IP orig_rcpt
+/*     The original envelope recipient address.
 /* .IP recipient
 /*     Recipient address that the message could not be delivered to.
 /*     This information is used for syslogging only.
 
 /* bounce_append - append reason to per-message bounce log */
 
-int     bounce_append(int flags, const char *id, const char *recipient,
-                      const char *relay, time_t entry, const char *fmt,...)
+int     bounce_append(int flags, const char *id, const char *orig_rcpt,
+                             const char *recipient, const char *relay,
+                             time_t entry, const char *fmt,...)
 {
     va_list ap;
     int     status;
 
     va_start(ap, fmt);
-    status = vbounce_append(flags, id, recipient, relay, entry, fmt, ap);
+    status = vbounce_append(flags, id, orig_rcpt, recipient,
+                           relay, entry, fmt, ap);
     va_end(ap);
     return (status);
 }
 
 /* vbounce_append - append bounce reason to per-message log */
 
-int     vbounce_append(int flags, const char *id, const char *recipient,
-               const char *relay, time_t entry, const char *fmt, va_list ap)
+int     vbounce_append(int flags, const char *id, const char *orig_rcpt,
+                              const char *recipient, const char *relay,
+                              time_t entry, const char *fmt, va_list ap)
 {
     VSTRING *why;
     int     status;
@@ -184,16 +194,18 @@ int     vbounce_append(int flags, const char *id, const char *recipient,
                            ATTR_TYPE_NUM, MAIL_ATTR_NREQ, BOUNCE_CMD_APPEND,
                            ATTR_TYPE_NUM, MAIL_ATTR_FLAGS, flags,
                            ATTR_TYPE_STR, MAIL_ATTR_QUEUEID, id,
+                           ATTR_TYPE_STR, MAIL_ATTR_ORCPT, orig_rcpt,
                            ATTR_TYPE_STR, MAIL_ATTR_RECIP, recipient,
                            ATTR_TYPE_STR, MAIL_ATTR_WHY, vstring_str(why),
                            ATTR_TYPE_END) == 0) {
-       msg_info("%s: to=<%s>, relay=%s, delay=%d, status=%s (%s%s)",
-                id, recipient, relay, delay, var_soft_bounce ? "deferred" :
-                "bounced", var_soft_bounce ? "SOFT BOUNCE - " : "",
+       msg_info("%s: orig_to=<%s>, to=<%s>, relay=%s, delay=%d, status=%s (%s%s)",
+                id, orig_rcpt, recipient, relay, delay,
+                var_soft_bounce ? "deferred" : "bounced",
+                var_soft_bounce ? "SOFT BOUNCE - " : "",
                 vstring_str(why));
        status = (var_soft_bounce ? -1 : 0);
     } else if ((flags & BOUNCE_FLAG_CLEAN) == 0) {
-       status = defer_append(flags, id, recipient, "bounce", entry,
+       status = defer_append(flags, id, orig_rcpt, recipient, "bounce", entry,
                              "bounce failed");
     } else {
        status = -1;
@@ -235,14 +247,15 @@ int     bounce_flush(int flags, const char *queue, const char *id,
 
 int     bounce_one(int flags, const char *queue, const char *id,
                           const char *encoding, const char *sender,
-                          const char *recipient, const char *relay,
-                          time_t entry, const char *fmt,...)
+                          const char *orig_rcpt, const char *recipient,
+                          const char *relay, time_t entry,
+                          const char *fmt,...)
 {
     va_list ap;
     int     status;
 
     va_start(ap, fmt);
-    status = vbounce_one(flags, queue, id, encoding, sender,
+    status = vbounce_one(flags, queue, id, encoding, sender, orig_rcpt,
                         recipient, relay, entry, fmt, ap);
     va_end(ap);
     return (status);
@@ -252,8 +265,9 @@ int     bounce_one(int flags, const char *queue, const char *id,
 
 int     vbounce_one(int flags, const char *queue, const char *id,
                            const char *encoding, const char *sender,
-                           const char *recipient, const char *relay,
-                           time_t entry, const char *fmt, va_list ap)
+                           const char *orig_rcpt, const char *recipient,
+                           const char *relay, time_t entry,
+                           const char *fmt, va_list ap)
 {
     VSTRING *why;
     int     status;
@@ -264,7 +278,8 @@ int     vbounce_one(int flags, const char *queue, const char *id,
      * procedure.
      */
     if (var_soft_bounce)
-       return (vbounce_append(flags, id, recipient, relay, entry, fmt, ap));
+       return (vbounce_append(flags, id, orig_rcpt, recipient,
+                              relay, entry, fmt, ap));
 
     why = vstring_alloc(100);
     delay = time((time_t *) 0) - entry;
@@ -276,6 +291,7 @@ int     vbounce_one(int flags, const char *queue, const char *id,
                            ATTR_TYPE_STR, MAIL_ATTR_QUEUEID, id,
                            ATTR_TYPE_STR, MAIL_ATTR_ENCODING, encoding,
                            ATTR_TYPE_STR, MAIL_ATTR_SENDER, sender,
+                           ATTR_TYPE_STR, MAIL_ATTR_ORCPT, orig_rcpt,
                            ATTR_TYPE_STR, MAIL_ATTR_RECIP, recipient,
                            ATTR_TYPE_STR, MAIL_ATTR_WHY, vstring_str(why),
                            ATTR_TYPE_END) == 0) {
@@ -283,7 +299,7 @@ int     vbounce_one(int flags, const char *queue, const char *id,
                 id, recipient, relay, delay, vstring_str(why));
        status = 0;
     } else if ((flags & BOUNCE_FLAG_CLEAN) == 0) {
-       status = defer_append(flags, id, recipient, "bounce", entry,
+       status = defer_append(flags, id, orig_rcpt, recipient, "bounce", entry,
                              "bounce failed");
     } else {
        status = -1;
index 301ba72d16d70e3f35a8099d7dff971f96222747..caaccbfb704b86b3e987975604827b8f871cf85b 100644 (file)
  /*
   * Client interface.
   */
-extern int PRINTFLIKE(6, 7) bounce_append(int, const char *, const char *,
+extern int PRINTFLIKE(7, 8) bounce_append(int, const char *,
+                                                 const char *, const char *,
                                                  const char *, time_t,
                                                  const char *,...);
 extern int vbounce_append(int, const char *, const char *, const char *,
-                                 time_t, const char *, va_list);
+                              const char *, time_t, const char *, va_list);
 extern int bounce_flush(int, const char *, const char *, const char *, const char *);
-extern int PRINTFLIKE(9, 10) bounce_one(int, const char *, const char *,
+extern int PRINTFLIKE(10, 11) bounce_one(int, const char *, const char *,
                                                const char *, const char *,
                                                const char *, const char *,
-                                               time_t, const char *,...);
+                                               const char *, time_t,
+                                               const char *,...);
 extern int vbounce_one(int, const char *, const char *, const char *,
                               const char *, const char *, const char *,
-                              time_t, const char *, va_list);
+                              const char *, time_t, const char *, va_list);
 
  /*
   * Bounce/defer protocol commands.
index 862f3a6fdcb5ecca583b98ce9996b1c5d7556993..beb8b04a5be7d3a76e387e5c0a151163427c4e84 100644 (file)
@@ -6,17 +6,21 @@
 /* SYNOPSIS
 /*     #include <defer.h>
 /*
-/*     int     defer_append(flags, id, recipient, relay, entry, format, ...)
+/*     int     defer_append(flags, id, orig_rcpt, recipient, relay,
+/*                             entry, format, ...)
 /*     int     flags;
 /*     const char *id;
+/*     const char *orig_rcpt;
 /*     const char *recipient;
 /*     const char *relay;
 /*     time_t  entry;
 /*     const char *format;
 /*
-/*     int     vdefer_append(flags, id, recipient, relay, entry, format, ap)
+/*     int     vdefer_append(flags, id, orig_rcpt, recipient, relay,
+/*                             entry, format, ap)
 /*     int     flags;
 /*     const char *id;
+/*     const char *orig_rcpt;
 /*     const char *recipient;
 /*     const char *relay;
 /*     time_t  entry;
@@ -68,6 +72,8 @@
 /*     The message queue name of the original message file.
 /* .IP id
 /*     The queue id of the original message file.
+/* .IP orig_rcpt
+/*     The original envelope recipient address.
 /* .IP recipient
 /*     A recipient address that is being deferred. The domain part
 /*     of the address is marked dead (for a limited amount of time).
 
 /* defer_append - defer message delivery */
 
-int     defer_append(int flags, const char *id, const char *recipient,
-                      const char *relay, time_t entry, const char *fmt,...)
+int     defer_append(int flags, const char *id, const char *orig_rcpt,
+                            const char *recipient, const char *relay,
+                            time_t entry, const char *fmt,...)
 {
     va_list ap;
     int     status;
 
     va_start(ap, fmt);
-    status = vdefer_append(flags, id, recipient, relay, entry, fmt, ap);
+    status = vdefer_append(flags, id, orig_rcpt, recipient,
+                          relay, entry, fmt, ap);
     va_end(ap);
     return (status);
 }
 
 /* vdefer_append - defer delivery of queue file */
 
-int     vdefer_append(int flags, const char *id, const char *recipient,
-               const char *relay, time_t entry, const char *fmt, va_list ap)
+int     vdefer_append(int flags, const char *id, const char *orig_rcpt,
+                             const char *recipient, const char *relay,
+                             time_t entry, const char *fmt, va_list ap)
 {
     VSTRING *why = vstring_alloc(100);
     int     delay = time((time_t *) 0) - entry;
@@ -153,12 +162,13 @@ int     vdefer_append(int flags, const char *id, const char *recipient,
                            ATTR_TYPE_NUM, MAIL_ATTR_NREQ, BOUNCE_CMD_APPEND,
                            ATTR_TYPE_NUM, MAIL_ATTR_FLAGS, flags,
                            ATTR_TYPE_STR, MAIL_ATTR_QUEUEID, id,
+                           ATTR_TYPE_STR, MAIL_ATTR_ORCPT, orig_rcpt,
                            ATTR_TYPE_STR, MAIL_ATTR_RECIP, recipient,
                            ATTR_TYPE_STR, MAIL_ATTR_WHY, vstring_str(why),
                            ATTR_TYPE_END) != 0)
        msg_warn("%s: defer service failure", id);
-    msg_info("%s: to=<%s>, relay=%s, delay=%d, status=deferred (%s)",
-            id, recipient, relay, delay, vstring_str(why));
+    msg_info("%s: orig_to=<%s>, to=<%s>, relay=%s, delay=%d, status=deferred (%s)",
+            id, orig_rcpt, recipient, relay, delay, vstring_str(why));
     vstring_free(why);
 
     /*
index 18bbbddd903e2aa8ae5b6e4fa142c387e99951f5..acc7bfb9129cbf8da482cd80e8cb8a888cf7ded8 100644 (file)
  /*
   * External interface.
   */
-extern int PRINTFLIKE(6, 7) defer_append(int, const char *, const char *,
-                                   const char *, time_t, const char *,...);
+extern int PRINTFLIKE(7, 8) defer_append(int, const char *, const char *,
+                                        const char *, const char *, time_t,
+                                                const char *,...);
 extern int vdefer_append(int, const char *, const char *, const char *,
-                                time_t, const char *, va_list);
+                              const char *, time_t, const char *, va_list);
 extern int defer_flush(int, const char *, const char *, const char *, const char *);
 
 extern int defer_warn(int, const char *, const char *, const char *);
index d2492292f140306866b0e4e8b88f8728b8cf0160..91ecb467a35b8a4bdc2dc2a30e5c64211d21df3b 100644 (file)
@@ -6,10 +6,11 @@
 /* SYNOPSIS
 /*     #include <deliver_request.h>
 /*
-/*     int     deliver_pass(class, service, request, address, offset)
+/*     int     deliver_pass(class, service, request, orig_addr, address, offset)
 /*     const char *class;
 /*     const char *service;
 /*     DELIVER_REQUEST *request;
+/*     const char *orig_addr;
 /*     const char *address;
 /*     long    offset;
 /*
@@ -89,7 +90,8 @@ static int deliver_pass_initial_reply(VSTREAM *stream)
 /* deliver_pass_send_request - send delivery request to delivery process */
 
 static int deliver_pass_send_request(VSTREAM *stream, DELIVER_REQUEST *request,
-                          const char *nexthop, const char *addr, long offs)
+                                    const char *nexthop, const char *orcpt,
+                                            const char *addr, long offs)
 {
     int     stat;
 
@@ -106,6 +108,7 @@ static int deliver_pass_send_request(VSTREAM *stream, DELIVER_REQUEST *request,
               ATTR_TYPE_STR, MAIL_ATTR_RRCPT, request->return_receipt,
               ATTR_TYPE_LONG, MAIL_ATTR_TIME, request->arrival_time,
               ATTR_TYPE_LONG, MAIL_ATTR_OFFSET, offs,
+              ATTR_TYPE_STR, MAIL_ATTR_ORCPT, orcpt ? orcpt : "",
               ATTR_TYPE_STR, MAIL_ATTR_RECIP, addr,
               ATTR_TYPE_NUM, MAIL_ATTR_OFFSET, 0,
               ATTR_TYPE_END);
@@ -138,7 +141,8 @@ static int deliver_pass_final_reply(VSTREAM *stream, VSTRING *reason)
 /* deliver_pass - deliver one per-site queue entry */
 
 int     deliver_pass(const char *class, const char *service,
-                     DELIVER_REQUEST *request, const char *addr, long offs)
+                            DELIVER_REQUEST *request, const char *orig_addr,
+                            const char *addr, long offs)
 {
     VSTREAM *stream;
     VSTRING *reason;
@@ -175,7 +179,7 @@ int     deliver_pass(const char *class, const char *service,
      */
     if ((status = deliver_pass_initial_reply(stream)) == 0
        && (status = deliver_pass_send_request(stream, request, nexthop,
-                                              addr, offs)) == 0)
+                                              orig_addr, addr, offs)) == 0)
        status = deliver_pass_final_reply(stream, reason);
 
     /*
@@ -200,6 +204,7 @@ int     deliver_pass_all(const char *class, const char *service,
     list = &request->rcpt_list;
     for (rcpt = list->info; rcpt < list->info + list->len; rcpt++)
        status |= deliver_pass(class, service, request,
-                              rcpt->address, rcpt->offset);
+                              rcpt->orig_addr, rcpt->address,
+                              rcpt->offset);
     return (status);
 }
index 39e3e0f065e608fcac8f111d0f09aab0f98cc0b3..1854cda03d3c60d40a0964dd14f308808e2be5b7 100644 (file)
@@ -20,7 +20,7 @@
  /*
   * External interface.
   */
-extern int deliver_pass(const char *, const char *, DELIVER_REQUEST *, const char *, long);
+extern int deliver_pass(const char *, const char *, DELIVER_REQUEST *, const char *, const char *, long);
 extern int deliver_pass_all(const char *, const char *, DELIVER_REQUEST *);
 
 /* LICENSE
index 75dd3c61bcea64e91a1c9379846ecfb1f4cf4e28..b855d13a2e8161a704a125e94ddbc9de1445b32f 100644 (file)
@@ -171,6 +171,7 @@ static int deliver_request_get(VSTREAM *stream, DELIVER_REQUEST *request)
     static VSTRING *queue_id;
     static VSTRING *nexthop;
     static VSTRING *encoding;
+    static VSTRING *orig_addr;
     static VSTRING *address;
     static VSTRING *errors_to;
     static VSTRING *return_receipt;
@@ -186,6 +187,7 @@ static int deliver_request_get(VSTREAM *stream, DELIVER_REQUEST *request)
        queue_id = vstring_alloc(10);
        nexthop = vstring_alloc(10);
        encoding = vstring_alloc(10);
+       orig_addr = vstring_alloc(10);
        address = vstring_alloc(10);
        errors_to = vstring_alloc(10);
        return_receipt = vstring_alloc(10);
@@ -207,8 +209,10 @@ static int deliver_request_get(VSTREAM *stream, DELIVER_REQUEST *request)
                  ATTR_TYPE_STR, MAIL_ATTR_ERRTO, errors_to,
                  ATTR_TYPE_STR, MAIL_ATTR_RRCPT, return_receipt,
                  ATTR_TYPE_LONG, MAIL_ATTR_TIME, &request->arrival_time,
-                 ATTR_TYPE_END) != 11)
+                 ATTR_TYPE_END) != 11) {
+       msg_warn("%s: error receiving common attributes", myname);
        return (-1);
+    }
     if (mail_open_ok(vstring_str(queue_name),
                     vstring_str(queue_id), &st, &path) == 0)
        return (-1);
@@ -228,15 +232,22 @@ static int deliver_request_get(VSTREAM *stream, DELIVER_REQUEST *request)
     for (;;) {
        if (attr_scan(stream, ATTR_FLAG_MORE | ATTR_FLAG_STRICT,
                      ATTR_TYPE_LONG, MAIL_ATTR_OFFSET, &offset,
-                     ATTR_TYPE_END) != 1)
+                     ATTR_TYPE_END) != 1) {
+           msg_warn("%s: error receiving offset attribute", myname);
            return (-1);
+       }
        if (offset == 0)
            break;
        if (attr_scan(stream, ATTR_FLAG_MORE | ATTR_FLAG_STRICT,
+                     ATTR_TYPE_STR, MAIL_ATTR_ORCPT, orig_addr,
                      ATTR_TYPE_STR, MAIL_ATTR_RECIP, address,
-                     ATTR_TYPE_END) != 1)
+                     ATTR_TYPE_END) != 2) {
+           msg_warn("%s: error receiving recipient attributes", myname);
            return (-1);
-       recipient_list_add(&request->rcpt_list, offset, vstring_str(address));
+       }
+       recipient_list_add(&request->rcpt_list, offset,
+                      *vstring_str(orig_addr) ? vstring_str(orig_addr) : 0,
+                          vstring_str(address));
     }
 
     /*
index bf4f135b5581cbb107b3b89cb7786acae1000e19..c7435afa7343da6681d5a260d52aaa07b2e0cc23 100644 (file)
@@ -61,7 +61,7 @@ typedef struct VSTREAM _deliver_vstream_;
 extern DELIVER_REQUEST *deliver_request_read(_deliver_vstream_ *);
 extern int deliver_request_done(_deliver_vstream_ *, DELIVER_REQUEST *, int);
 
-extern int deliver_pass(const char *, const char *, DELIVER_REQUEST *, const char *, long);
+extern int deliver_pass(const char *, const char *, DELIVER_REQUEST *, const char *, const char *, long);
 
 /* LICENSE
 /* .ad
index c2d328981ca292a2b292e0aa30bdd3a0cb6c9fd2..596bd8c4bd64dd82ff4a5d2c206e3609934fd375 100644 (file)
@@ -6,8 +6,9 @@
 /* SYNOPSIS
 /*     #include <mail_copy.h>
 /*
-/*     int     mail_copy(sender, delivered, src, dst, flags, eol, why)
+/*     int     mail_copy(sender, envrcpt, delivered, src, dst, flags, eol, why)
 /*     const char *sender;
+/*     const char *envrcpt;
 /*     const char *delivered;
 /*     VSTREAM *src;
 /*     VSTREAM *dst;
@@ -48,6 +49,9 @@
 /* .IP MAIL_COPY_DELIVERED
 /*     Prepend a Delivered-To: header with the name of the
 /*     \fIdelivered\fR attribute.
+/* .IP MAIL_COPY_ORIG_RCPT
+/*     Prepend an X-Original-To: header with the original
+/*     envelope recipient address.
 /* .IP MAIL_COPY_RETURN_PATH
 /*     Prepend a Return-Path: header with the value of the
 /*     \fIsender\fR attribute.
 
 /* mail_copy - copy message with extreme prejudice */
 
-int     mail_copy(const char *sender, const char *delivered,
+int     mail_copy(const char *sender,
+                         const char *orig_rcpt,
+                         const char *delivered,
                          VSTREAM *src, VSTREAM *dst,
                          int flags, const char *eol, VSTRING *why)
 {
@@ -156,6 +162,13 @@ int     mail_copy(const char *sender, const char *delivered,
                            *sender ? vstring_str(buf) : "", eol);
        }
     }
+    if (flags & MAIL_COPY_ORIG_RCPT) {
+       if (orig_rcpt == 0)
+           msg_panic("%s: null orig_rcpt", myname);
+       quote_822_local(buf, orig_rcpt);
+       vstream_fprintf(dst, "X-Original-To: %s%s",
+                       lowercase(vstring_str(buf)), eol);
+    }
     if (flags & MAIL_COPY_DELIVERED) {
        if (delivered == 0)
            msg_panic("%s: null delivered", myname);
index efa1957c5c0bbd25b88a871c823a8cca3d88e394..e7d650ff8537828e3bf312ca1404aa2d30b05e27 100644 (file)
@@ -20,7 +20,8 @@
  /*
   * External interface.
   */
-extern int mail_copy(const char *, const char *, VSTREAM *, VSTREAM *,
+extern int mail_copy(const char *, const char *, const char *,
+                            VSTREAM *, VSTREAM *,
                             int, const char *, VSTRING *);
 
 #define MAIL_COPY_QUOTE                (1<<0)  /* prepend > to From_ */
@@ -30,9 +31,12 @@ extern int mail_copy(const char *, const char *, VSTREAM *, VSTREAM *,
 #define MAIL_COPY_RETURN_PATH  (1<<4)  /* prepend Return-Path: */
 #define MAIL_COPY_DOT          (1<<5)  /* escape dots - needed for bsmtp */
 #define MAIL_COPY_BLANK                (1<<6)  /* append blank line */
+#define MAIL_COPY_ORIG_RCPT    (1<<7)  /* prepend Delivered-To: */
 #define MAIL_COPY_MBOX         (MAIL_COPY_FROM | MAIL_COPY_QUOTE | \
                                    MAIL_COPY_TOFILE | MAIL_COPY_DELIVERED | \
-                                   MAIL_COPY_RETURN_PATH | MAIL_COPY_BLANK)
+                                   MAIL_COPY_RETURN_PATH | MAIL_COPY_BLANK | \
+                                       MAIL_COPY_ORIG_RCPT)
+
 #define MAIL_COPY_NONE         0       /* all turned off */
 
 #define MAIL_COPY_STAT_OK      0
index 89b005b0cc5307ad2c6179faa5a3933cb597445f..4168d7eadec0f0fd9597296890f75fd373f1ec6d 100644 (file)
@@ -84,6 +84,7 @@ extern char *mail_pathname(const char *, const char *);
 #define MAIL_ATTR_QUEUE                "queue_name"
 #define MAIL_ATTR_QUEUEID      "queue_id"
 #define MAIL_ATTR_SENDER       "sender"
+#define MAIL_ATTR_ORCPT                "original_recipient"
 #define MAIL_ATTR_RECIP                "recipient"
 #define MAIL_ATTR_WHY          "reason"
 #define MAIL_ATTR_VERPDL       "verp_delimiters"
index 476dbc4fbc4f3431519ce6055ebd2e13b60af204..e4b133be5b1c0c5cbc8a82a8eddf7a8b06e95ba6 100644 (file)
@@ -20,7 +20,7 @@
   * Patches change the patchlevel and the release date. Snapshots change the
   * release date only, unless they include the same bugfix as a patch release.
   */
-#define MAIL_RELEASE_DATE      "20021024"
+#define MAIL_RELEASE_DATE      "20021025"
 
 #define VAR_MAIL_VERSION       "mail_version"
 #define DEF_MAIL_VERSION       "1.1.11-" MAIL_RELEASE_DATE
index 7cee11d7fa5a9492dad3beeca2878c983ab78565..b8f07823b8b314ca9a28d67ee4c019064cec6cad 100644 (file)
@@ -51,6 +51,9 @@
 /* .IP "PIPE_CMD_SENDER (char *)"
 /*     The envelope sender address, which is passed on to the
 /*     \fImail_copy\fR() routine.
+/* .IP "PIPE_CMD_ORIG_RCPT (char *)"
+/*     The original recipient envelope address, which is passed on
+/*     to the \fImail_copy\fR() routine.
 /* .IP "PIPE_CMD_DELIVERED (char *)"
 /*     The recipient envelope address, which is passed on to the
 /*     \fImail_copy\fR() routine.
 struct pipe_args {
     int     flags;                     /* see mail_copy.h */
     char   *sender;                    /* envelope sender */
+    char   *orig_rcpt;                 /* original recipient */
     char   *delivered;                 /* envelope recipient */
     char   *eol;                       /* carriagecontrol */
     char  **argv;                      /* either an array */
@@ -171,6 +175,7 @@ static void get_pipe_args(struct pipe_args * args, va_list ap)
      */
     args->flags = 0;
     args->sender = 0;
+    args->orig_rcpt = 0;
     args->delivered = 0;
     args->eol = "\n";
     args->argv = 0;
@@ -194,6 +199,9 @@ static void get_pipe_args(struct pipe_args * args, va_list ap)
        case PIPE_CMD_SENDER:
            args->sender = va_arg(ap, char *);
            break;
+       case PIPE_CMD_ORIG_RCPT:
+           args->orig_rcpt = va_arg(ap, char *);
+           break;
        case PIPE_CMD_DELIVERED:
            args->delivered = va_arg(ap, char *);
            break;
@@ -453,7 +461,8 @@ int     pipe_command(VSTREAM *src, VSTRING *why,...)
         */
 #define DONT_CARE_WHY  ((VSTRING *) 0)
 
-       write_status = mail_copy(args.sender, args.delivered, src,
+       write_status = mail_copy(args.sender, args.orig_rcpt,
+                                args.delivered, src,
                                 cmd_in_stream, args.flags,
                                 args.eol, DONT_CARE_WHY);
 
index 1750ccc7bd30d5bff37035742a5798a673b8e163..9a36832cb8843119ea78d925fe1d8235c54d1e77 100644 (file)
@@ -38,6 +38,7 @@
 #define PIPE_CMD_SHELL         10      /* alternative shell */
 #define PIPE_CMD_EOL           11      /* record delimiter */
 #define PIPE_CMD_EXPORT                12      /* exportable environment */
+#define PIPE_CMD_ORIG_RCPT     13      /* mail_copy() original recipient */
 
  /*
   * Command completion status.
index 158338c5e687ee482280e0aad4f8ab56e9d7c806..1153b7c6a118df49f01e154976d4360ff584a5e7 100644 (file)
@@ -9,6 +9,7 @@
 /*     typedef struct {
 /* .in +4
 /*             long    offset;
+/*             char   *orig_addr;
 /*             char   *address;
 /* .in -4
 /*     } RECIPIENT;
 /*     void    recipient_list_init(list)
 /*     RECIPIENT_LIST *list;
 /*
-/*     void    recipient_list_add(list, offset, recipient)
+/*     void    recipient_list_add(list, offset, orig_rcpt, recipient)
 /*     RECIPIENT_LIST *list;
 /*     long    offset;
+/*     const char *orig_rcpt;
 /*     const char *recipient;
 /*
 /*     void    recipient_list_free(list)
@@ -90,13 +92,15 @@ void    recipient_list_init(RECIPIENT_LIST *list)
 
 /* recipient_list_add - add rcpt to list */
 
-void    recipient_list_add(RECIPIENT_LIST *list, long offset, const char *rcpt)
+void    recipient_list_add(RECIPIENT_LIST *list, long offset,
+                                  const char *orig_rcpt, const char *rcpt)
 {
     if (list->len >= list->avail) {
        list->avail *= 2;
        list->info = (RECIPIENT *)
            myrealloc((char *) list->info, list->avail * sizeof(RECIPIENT));
     }
+    list->info[list->len].orig_addr = orig_rcpt ? mystrdup(orig_rcpt) : 0;
     list->info[list->len].address = mystrdup(rcpt);
     list->info[list->len].offset = offset;
     list->len++;
@@ -108,7 +112,10 @@ void    recipient_list_free(RECIPIENT_LIST *list)
 {
     RECIPIENT *rcpt;
 
-    for (rcpt = list->info; rcpt < list->info + list->len; rcpt++)
+    for (rcpt = list->info; rcpt < list->info + list->len; rcpt++) {
+       if (rcpt->orig_addr)
+           myfree(rcpt->orig_addr);
        myfree(rcpt->address);
+    }
     myfree((char *) list->info);
 }
index e7e09d236f303a20275cfc906e46655c84877c78..0059b71cede94c01454b0edc198a093485e48c1c 100644 (file)
@@ -19,6 +19,7 @@
   */
 typedef struct RECIPIENT {
     long    offset;                    /* REC_TYPE_RCPT byte */
+    char   *orig_addr;                 /* null or original recipient */
     char   *address;                   /* complete address */
 } RECIPIENT;
 
@@ -29,7 +30,7 @@ typedef struct RECIPIENT_LIST {
 } RECIPIENT_LIST;
 
 extern void recipient_list_init(RECIPIENT_LIST *);
-extern void recipient_list_add(RECIPIENT_LIST *, long, const char *);
+extern void recipient_list_add(RECIPIENT_LIST *, long, const char *, const char *);
 extern void recipient_list_free(RECIPIENT_LIST *);
 
 /* LICENSE
index 3b0c11f89604cc279fd9b434099a6264e61c5915..25e60059d6802a4cfb416fbfb47ea1ad2f972167 100644 (file)
@@ -6,15 +6,17 @@
 /* SYNOPSIS
 /*     #include <sent.h>
 /*
-/*     int     sent(queue_id, recipient, relay, entry, format, ...)
+/*     int     sent(queue_id, orig_rcpt, recipient, relay, entry, format, ...)
 /*     const char *queue_id;
+/*     const char *orig_rcpt;
 /*     const char *recipient;
 /*     const char *relay;
 /*     time_t  entry;
 /*     const char *format;
 /*
-/*     int     vsent(queue_id, recipient, relay, entry, format, ap)
+/*     int     vsent(queue_id, orig_rcpt, recipient, relay, entry, format, ap)
 /*     const char *queue_id;
+/*     const char *orig_rcpt;
 /*     const char *recipient;
 /*     const char *relay;
 /*     time_t  entry;
@@ -28,6 +30,8 @@
 /*     Arguments:
 /* .IP queue_id
 /*     The message queue id.
+/* .IP orig_rcpt
+/*     The original envelope recipient address
 /* .IP recipient
 /*     The recipient address.
 /* .IP relay
 
 /* sent - log that a message was sent */
 
-int     sent(const char *queue_id, const char *recipient, const char *relay,
+int     sent(const char *queue_id, const char *orig_rcpt,
+                    const char *recipient, const char *relay,
                     time_t entry, const char *fmt,...)
 {
     va_list ap;
 
     va_start(ap, fmt);
-    vsent(queue_id, recipient, relay, entry, fmt, ap);
+    vsent(queue_id, orig_rcpt, recipient, relay, entry, fmt, ap);
     va_end(ap);
     return (0);
 }
 
 /* vsent - log that a message was sent */
 
-int     vsent(const char *queue_id, const char *recipient, const char *relay,
+int     vsent(const char *queue_id, const char *orig_rcpt,
+                     const char *recipient, const char *relay,
                      time_t entry, const char *fmt, va_list ap)
 {
 #define TEXT (vstring_str(text))
@@ -93,8 +99,8 @@ int     vsent(const char *queue_id, const char *recipient, const char *relay,
     int     delay = time((time_t *) 0) - entry;
 
     vstring_vsprintf(text, fmt, ap);
-    msg_info("%s: to=<%s>, relay=%s, delay=%d, status=sent%s%s%s",
-            queue_id, recipient, relay, delay,
+    msg_info("%s: orig_to=<%s>, to=<%s>, relay=%s, delay=%d, status=sent%s%s%s",
+            queue_id, orig_rcpt, recipient, relay, delay,
             *TEXT ? " (" : "", TEXT, *TEXT ? ")" : "");
     vstring_free(text);
     return (0);
index cc5178fd0fefeaf6d8bdc336db757eb764176df9..92c441427ce2616272435b52f1067cde4cae8072 100644 (file)
@@ -20,9 +20,9 @@
  /*
   * External interface.
   */
-extern int PRINTFLIKE(5, 6) sent(const char *, const char *, const char *,
-                                        time_t, const char *,...);
-extern int vsent(const char *, const char *, const char *,
+extern int PRINTFLIKE(6, 7) sent(const char *, const char *, const char *,
+                                   const char *, time_t, const char *,...);
+extern int vsent(const char *, const char *, const char *, const char *,
                         time_t, const char *, va_list);
 
 /* LICENSE
index aa9aaf350dce62e0bcf9a3f68a4c7f66e19d02fe..c17cc2123b3a03ac0eb52bf2c0661779264cfc24 100644 (file)
@@ -49,9 +49,9 @@
 /*     RFC 1652 (8bit-MIME transport)
 /*     RFC 1870 (Message Size Declaration)
 /*     RFC 2033 (LMTP protocol)
-/*     RFC 2197 (Pipelining)
 /*     RFC 2554 (AUTH command)
 /*     RFC 2821 (SMTP protocol)
+/*     RFC 2920 (SMTP Pipelining)
 /* DIAGNOSTICS
 /*     Problems and transactions are logged to \fBsyslogd\fR(8).
 /*     Corrupted message files are marked so that the queue manager can
index de41ac15fe3e0a56f94c07dbdee8e3907fd4b1b5..ee990474ba55775b0e5df0dbb46ec86c0ec79185 100644 (file)
@@ -575,16 +575,16 @@ static int lmtp_loop(LMTP_STATE *state, int send_state, int recv_state)
                        rcpt = request->rcpt_list.info + survivors[recv_dot];
                        if (resp->code / 100 == 2) {
                            if (rcpt->offset) {
-                               sent(request->queue_id, rcpt->address,
-                                    session->namaddr, request->arrival_time,
-                                    "%s", resp->str);
+                               sent(request->queue_id, rcpt->orig_addr,
+                                    rcpt->address, session->namaddr,
+                                    request->arrival_time, "%s", resp->str);
                                if (request->flags & DEL_REQ_FLAG_SUCCESS)
                                    deliver_completed(state->src, rcpt->offset);
                                rcpt->offset = 0;
                            }
                        } else {
                            lmtp_rcpt_fail(state, resp->code, rcpt,
-                                      "host %s said: %s (in reply to %s)",
+                                       "host %s said: %s (in reply to %s)",
                                           session->namaddr,
                                           translit(resp->str, "\n", " "),
                                           xfer_request[LMTP_STATE_DOT]);
index 713e4d89b698ad88fcc24f3c0fd98dc0abf69512..9a15d4d8e50ff5c8d9ef46e7dd2054aaf7027c62 100644 (file)
@@ -178,7 +178,7 @@ int     lmtp_site_fail(LMTP_STATE *state, int code, char *format,...)
        if (rcpt->offset == 0)
            continue;
        status = (soft_error ? defer_append : bounce_append)
-           (KEEP, request->queue_id, rcpt->address,
+           (KEEP, request->queue_id, rcpt->orig_addr, rcpt->address,
             session ? session->namaddr : "none",
             request->arrival_time, "%s", vstring_str(why));
        if (status == 0) {
@@ -225,7 +225,7 @@ int     lmtp_mesg_fail(LMTP_STATE *state, int code, char *format,...)
        if (rcpt->offset == 0)
            continue;
        status = (LMTP_SOFT(code) ? defer_append : bounce_append)
-           (KEEP, request->queue_id, rcpt->address,
+           (KEEP, request->queue_id, rcpt->orig_addr, rcpt->address,
             session->namaddr, request->arrival_time,
             "%s", vstring_str(why));
        if (status == 0) {
@@ -259,8 +259,8 @@ void    lmtp_rcpt_fail(LMTP_STATE *state, int code, RECIPIENT *rcpt,
      */
     va_start(ap, format);
     status = (LMTP_SOFT(code) ? vdefer_append : vbounce_append)
-       (KEEP, request->queue_id, rcpt->address, session->namaddr,
-        request->arrival_time, format, ap);
+       (KEEP, request->queue_id, rcpt->orig_addr, rcpt->address,
+        session->namaddr, request->arrival_time, format, ap);
     va_end(ap);
     if (status == 0) {
        deliver_completed(state->src, rcpt->offset);
@@ -305,7 +305,8 @@ int     lmtp_stream_except(LMTP_STATE *state, int code, char *description)
        if (rcpt->offset == 0)
            continue;
        state->status |= defer_append(KEEP, request->queue_id,
-                                     rcpt->address, session->namaddr,
+                                     rcpt->orig_addr, rcpt->address,
+                                     session->namaddr,
                                      request->arrival_time,
                                      "%s", vstring_str(why));
     }
index 8394a542ca04600222bc601f350757f634ca7b7f..e9d5db6bdc4d811d10d8174657042593aa2adce7 100644 (file)
@@ -534,6 +534,7 @@ static int local_deliver(DELIVER_REQUEST *rqst, char *service)
     for (msg_stat = 0, rcpt = rqst->rcpt_list.info; rcpt < rcpt_end; rcpt++) {
        state.dup_filter = been_here_init(var_dup_filter_limit, BH_FLAG_FOLD);
        forward_init();
+       state.msg_attr.orig_rcpt = rcpt->orig_addr;
        state.msg_attr.recipient = rcpt->address;
        rcpt_stat = deliver_recipient(state, usr_attr);
        rcpt_stat |= forward_finish(state.msg_attr, rcpt_stat);
index e5ab862f807ca9dbb682bae9850980c01a2a37e0..764affd77211080436fce0c9c1c7624fa01aa286 100644 (file)
@@ -70,6 +70,7 @@ typedef struct DELIVER_ATTR {
     long    offset;                    /* data offset */
     char   *encoding;                  /* MIME encoding */
     char   *sender;                    /* taken from envelope */
+    char   *orig_rcpt;                 /* from submission */
     char   *recipient;                 /* taken from resolver */
     char   *domain;                    /* recipient domain */
     char   *local;                     /* recipient full localpart */
@@ -120,15 +121,17 @@ typedef struct LOCAL_STATE {
  /*
   * Bundle up some often-user attributes.
   */
-#define BOUNCE_ATTR(attr)      attr.queue_id, attr.recipient, attr.relay, \
-                                       attr.arrival_time
-#define BOUNCE_ONE_ATTR(attr)  attr.queue_name, attr.queue_id, attr.encoding, \
-                                       attr.sender, attr.recipient, \
+#define BOUNCE_ATTR(attr)      attr.queue_id, attr.orig_rcpt, attr.recipient, \
                                        attr.relay, attr.arrival_time
-#define SENT_ATTR(attr)                attr.queue_id, attr.recipient, attr.relay, \
+#define BOUNCE_ONE_ATTR(attr)  attr.queue_name, attr.queue_id, attr.encoding, \
+                                       attr.sender, attr.orig_rcpt, \
+                                       attr.recipient, attr.relay, \
                                        attr.arrival_time
+#define SENT_ATTR(attr)                attr.queue_id, attr.orig_rcpt, attr.recipient, \
+                                       attr.relay, attr.arrival_time
 #define OPENED_ATTR(attr)      attr.queue_id, attr.sender
-#define COPY_ATTR(attr)                attr.sender, attr.delivered, attr.fp
+#define COPY_ATTR(attr)                attr.sender, attr.orig_rcpt, attr.delivered, \
+                                       attr.fp
 
 #define MSG_LOG_STATE(m, p) \
        msg_info("%s[%d]: local %s recip %s exten %s deliver %s exp_from %s", \
index 49ac57b2511e2bee91e392216446dac6fc3efddf..e867988fa9d2f3894aaf10a03ca7c70b645e4b23 100644 (file)
@@ -260,7 +260,8 @@ int     deliver_mailbox(LOCAL_STATE state, USER_ATTR usr_attr, int *statusp)
      */
     if (*var_mailbox_transport) {
        *statusp = deliver_pass(MAIL_CLASS_PRIVATE, var_mailbox_transport,
-                             state.request, state.msg_attr.recipient, -1L);
+                               state.request, state.msg_attr.orig_rcpt,
+                               state.msg_attr.recipient, -1L);
        return (YES);
     }
 
index 8904159a3a3a5f91f3e41ade48a4edcf1c5f5966..18774e44f19c66c7590cd0e7fdc5870596f2318c 100644 (file)
@@ -105,7 +105,8 @@ int     deliver_unknown(LOCAL_STATE state, USER_ATTR usr_attr)
      */
     if (*var_fallback_transport)
        return (deliver_pass(MAIL_CLASS_PRIVATE, var_fallback_transport,
-                            state.request, state.msg_attr.recipient, -1L));
+                            state.request, state.msg_attr.orig_rcpt,
+                            state.msg_attr.recipient, -1L));
 
     /*
      * Subject the luser_relay address to $name expansion, disable
index 13026b82c3c33c73112b27a18c25da1733fff03e..cf646935e72269dea04e1fb6bb70832542499a5b 100644 (file)
@@ -104,6 +104,7 @@ master.o: ../../include/clean_env.h
 master.o: ../../include/argv.h
 master.o: ../../include/safe.h
 master.o: ../../include/mail_params.h
+master.o: ../../include/mail_version.h
 master.o: ../../include/debug_process.h
 master.o: ../../include/mail_task.h
 master.o: ../../include/mail_conf.h
index 16505f6e45c908da6116481ef6081880b8f5c6cf..748501aed8a3517da9254bbc99e4358509f97a34 100644 (file)
@@ -214,6 +214,7 @@ extern QMGR_QUEUE *qmgr_queue_find(QMGR_TRANSPORT *, const char *);
   */
 struct QMGR_RCPT {
     long    offset;                    /* REC_TYPE_RCPT byte */
+    char   *orig_rcpt;                 /* null or original recipient */
     char   *address;                   /* complete address */
     QMGR_QUEUE *queue;                 /* resolved queue */
 };
@@ -225,7 +226,7 @@ struct QMGR_RCPT_LIST {
 };
 
 extern void qmgr_rcpt_list_init(QMGR_RCPT_LIST *);
-extern void qmgr_rcpt_list_add(QMGR_RCPT_LIST *, long, const char *);
+extern void qmgr_rcpt_list_add(QMGR_RCPT_LIST *, long, const char *, const char *);
 extern void qmgr_rcpt_list_free(QMGR_RCPT_LIST *);
 
  /*
@@ -359,7 +360,7 @@ extern void qmgr_peer_free(QMGR_PEER *);
   */
 extern void qmgr_defer_transport(QMGR_TRANSPORT *, const char *);
 extern void qmgr_defer_todo(QMGR_QUEUE *, const char *);
-extern void qmgr_defer_recipient(QMGR_MESSAGE *, const char *, const char *);
+extern void qmgr_defer_recipient(QMGR_MESSAGE *, const char *, const char *, const char *);
 
  /*
   * qmgr_bounce.c
index e8f01405f4d993c08e40086d9e1e4e49d4807b0c..0f9d50bee5f1087d72feb772392d62ed64201d47 100644 (file)
@@ -68,7 +68,7 @@ void    qmgr_bounce_recipient(QMGR_MESSAGE *message, QMGR_RCPT *recipient,
 
     va_start(ap, format);
     status = vbounce_append(BOUNCE_FLAG_KEEP, message->queue_id,
-                           recipient->address, "none",
+                           recipient->orig_rcpt, recipient->address, "none",
                            message->arrival_time, format, ap);
     va_end(ap);
 
index 72d30aac927e51395854f7982432a4d638fb7075..f0dd7c63b3aead644cff12169791b88a352740dd 100644 (file)
@@ -136,7 +136,8 @@ void    qmgr_defer_todo(QMGR_QUEUE *queue, const char *reason)
        message = entry->message;
        for (nrcpt = 0; nrcpt < entry->rcpt_list.len; nrcpt++) {
            recipient = entry->rcpt_list.info + nrcpt;
-           qmgr_defer_recipient(message, recipient->address, reason);
+           qmgr_defer_recipient(message, recipient->orig_rcpt,
+                                recipient->address, reason);
        }
        qmgr_entry_done(entry, QMGR_QUEUE_TODO);
     }
@@ -144,8 +145,8 @@ void    qmgr_defer_todo(QMGR_QUEUE *queue, const char *reason)
 
 /* qmgr_defer_recipient - defer delivery of specific recipient */
 
-void    qmgr_defer_recipient(QMGR_MESSAGE *message, const char *address,
-                                    const char *reason)
+void    qmgr_defer_recipient(QMGR_MESSAGE *message, const char *orig_addr,
+                                    const char *address, const char *reason)
 {
     char   *myname = "qmgr_defer_recipient";
 
@@ -159,6 +160,6 @@ void    qmgr_defer_recipient(QMGR_MESSAGE *message, const char *address,
      * Update the message structure and log the message disposition.
      */
     message->flags |= defer_append(BOUNCE_FLAG_KEEP, message->queue_id,
-                                  address, "none", message->arrival_time,
-                                  "%s", reason);
+                                  orig_addr, address, "none",
+                                  message->arrival_time, "%s", reason);
 }
index d8de110c95abe19fb18062b4f435bbe8bb5b5151..38be3d2b6c5968263c0a3ca85f6cc3d41d8db7b6 100644 (file)
@@ -177,6 +177,8 @@ static int qmgr_deliver_send_request(QMGR_ENTRY *entry, VSTREAM *stream)
     for (recipient = list.info; recipient < list.info + list.len; recipient++)
        attr_print(stream, ATTR_FLAG_MORE,
                   ATTR_TYPE_LONG, MAIL_ATTR_OFFSET, recipient->offset,
+                  ATTR_TYPE_STR, MAIL_ATTR_ORCPT,
+                  recipient->orig_rcpt ? recipient->orig_rcpt : "",
                   ATTR_TYPE_STR, MAIL_ATTR_RECIP, recipient->address,
                   ATTR_TYPE_END);
     attr_print(stream, ATTR_FLAG_NONE,
index 63c6326dd1e641905ef56ff548b23409e59567df..f1f5fdbf205ab99221204f9a11c3c5b40de55cd4 100644 (file)
@@ -288,6 +288,7 @@ static int qmgr_message_read(QMGR_MESSAGE *message)
     const char *error_text;
     char   *name;
     char   *value;
+    char   *orig_rcpt = 0;
 
     /*
      * Initialize. No early returns or we have a memory leak.
@@ -400,7 +401,8 @@ static int qmgr_message_read(QMGR_MESSAGE *message)
        } else if (rec_type == REC_TYPE_RCPT) {
            if (message->rcpt_list.len < recipient_limit) {
                message->rcpt_unread--;
-               qmgr_rcpt_list_add(&message->rcpt_list, curr_offset, start);
+               qmgr_rcpt_list_add(&message->rcpt_list, curr_offset,
+                                  orig_rcpt, start);
                if (message->rcpt_list.len >= recipient_limit) {
                    if ((message->rcpt_offset = vstream_ftell(message->fp)) < 0)
                        msg_fatal("vstream_ftell %s: %m",
@@ -455,8 +457,25 @@ static int qmgr_message_read(QMGR_MESSAGE *message)
                }
            }
        }
+       if (orig_rcpt != 0) {
+           msg_warn("%s: out-of-order original recipient <%.200s>",
+                    message->queue_id, start);
+           myfree(orig_rcpt);
+           orig_rcpt = 0;
+       }
+       if (rec_type == REC_TYPE_ORCP)
+           orig_rcpt = mystrdup(start);
     } while (rec_type > 0 && rec_type != REC_TYPE_END);
 
+    /*
+     * Grr.
+     */
+    if (orig_rcpt != 0) {
+       msg_warn("%s: out-of-order original recipient <%.200s>",
+                message->queue_id, start);
+       myfree(orig_rcpt);
+    }
+
     /*
      * Avoid clumsiness elsewhere in the program. When sending data across an
      * IPC channel, sending an empty string is more convenient than sending a
@@ -685,7 +704,8 @@ static void qmgr_message_resolve(QMGR_MESSAGE *message)
                                      "user has moved to %s", newloc);
                continue;
            } else if (dict_errno != 0) {
-               qmgr_defer_recipient(message, recipient->address,
+               qmgr_defer_recipient(message, recipient->orig_rcpt,
+                                    recipient->address,
                                     "relocated map lookup failure");
                continue;
            }
@@ -771,8 +791,9 @@ static void qmgr_message_resolve(QMGR_MESSAGE *message)
            if (strncasecmp(STR(reply.recipient), var_double_bounce_sender,
                            len) == 0
                && !var_double_bounce_sender[len]) {
-               sent(message->queue_id, recipient->address,
-                    "none", message->arrival_time, "discarded");
+               sent(message->queue_id, recipient->orig_rcpt,
+                    recipient->address, "none", message->arrival_time,
+                    "discarded");
                deliver_completed(message->fp, recipient->offset);
                msg_warn("%s: undeliverable postmaster notification discarded",
                         message->queue_id);
@@ -791,7 +812,8 @@ static void qmgr_message_resolve(QMGR_MESSAGE *message)
                if (strcmp(*cpp, STR(reply.transport)) == 0)
                    break;
            if (*cpp) {
-               qmgr_defer_recipient(message, recipient->address,
+               qmgr_defer_recipient(message, recipient->orig_rcpt,
+                                    recipient->address,
                                     "deferred transport");
                continue;
            }
@@ -821,7 +843,8 @@ static void qmgr_message_resolve(QMGR_MESSAGE *message)
         * This transport is dead. Defer delivery to this recipient.
         */
        if ((transport->flags & QMGR_TRANSPORT_STAT_DEAD) != 0) {
-           qmgr_defer_recipient(message, recipient->address, transport->reason);
+           qmgr_defer_recipient(message, recipient->orig_rcpt,
+                                recipient->address, transport->reason);
            continue;
        }
 
@@ -838,7 +861,8 @@ static void qmgr_message_resolve(QMGR_MESSAGE *message)
         * This queue is dead. Defer delivery to this recipient.
         */
        if (queue->window == 0) {
-           qmgr_defer_recipient(message, recipient->address, queue->reason);
+           qmgr_defer_recipient(message, recipient->orig_rcpt,
+                                recipient->address, queue->reason);
            continue;
        }
 
@@ -905,7 +929,8 @@ static void qmgr_message_assign(QMGR_MESSAGE *message)
             * Add the recipient to the current entry and increase all those
             * recipient counters accordingly.
             */
-           qmgr_rcpt_list_add(&entry->rcpt_list, recipient->offset, recipient->address);
+           qmgr_rcpt_list_add(&entry->rcpt_list, recipient->offset,
+                              recipient->orig_rcpt, recipient->address);
            job->rcpt_count++;
            message->rcpt_count++;
            qmgr_recipient_count++;
index 2bb292e016e29e519ec0f325bf11e006834058e2..94287fade4c8003719e7f65c3520d4d740c24f79 100644 (file)
@@ -9,9 +9,10 @@
 /*     void    qmgr_rcpt_list_init(list)
 /*     QMGR_RCPT_LIST *list;
 /*
-/*     void    qmgr_rcpt_list_add(list, offset, recipient)
+/*     void    qmgr_rcpt_list_add(list, offset, orig_rcpt, recipient)
 /*     QMGR_RCPT_LIST *list;
 /*     long    offset;
+/*     const char *orig_rcpt;
 /*     const char *recipient;
 /*
 /*     void    qmgr_rcpt_list_free(list)
@@ -71,13 +72,15 @@ void    qmgr_rcpt_list_init(QMGR_RCPT_LIST *list)
 
 /* qmgr_rcpt_list_add - add rcpt to list */
 
-void    qmgr_rcpt_list_add(QMGR_RCPT_LIST *list, long offset, const char *rcpt)
+void    qmgr_rcpt_list_add(QMGR_RCPT_LIST *list, long offset,
+                                  const char *orcpt, const char *rcpt)
 {
     if (list->len >= list->avail) {
        list->avail *= 2;
        list->info = (QMGR_RCPT *)
            myrealloc((char *) list->info, list->avail * sizeof(QMGR_RCPT));
     }
+    list->info[list->len].orig_rcpt = (orcpt ? mystrdup(orcpt) : 0);
     list->info[list->len].address = mystrdup(rcpt);
     list->info[list->len].offset = offset;
     list->info[list->len].queue = 0;
@@ -90,7 +93,10 @@ void    qmgr_rcpt_list_free(QMGR_RCPT_LIST *list)
 {
     QMGR_RCPT *rcpt;
 
-    for (rcpt = list->info; rcpt < list->info + list->len; rcpt++)
+    for (rcpt = list->info; rcpt < list->info + list->len; rcpt++) {
+       if (rcpt->orig_rcpt)
+           myfree(rcpt->orig_rcpt);
        myfree(rcpt->address);
+    }
     myfree((char *) list->info);
 }
index 0e865de294a40bcde1706f7626f1e60900fc8b97..e798de07cc2226b0b3168c9fce4646deead13ab3 100644 (file)
@@ -186,6 +186,12 @@ static int copy_segment(VSTREAM *qfile, VSTREAM *cleanup, PICKUP_INFO *info,
        if (type == REC_TYPE_FROM)
            if (info->sender == 0)
                info->sender = mystrdup(vstring_str(buf));
+       if (type == REC_TYPE_ORCP)
+           if (info->st.st_uid != var_owner_uid) {
+               msg_warn("uid=%ld: ignoring original recipient record: %.200s",
+                        (long) info->st.st_uid, vstring_str(buf));
+               continue;
+           }
        if (type == REC_TYPE_RCPT)
            if (info->rcpt == 0)
                info->rcpt = mystrdup(vstring_str(buf));
index c838969a43a4de7f48d9f0554e30f11dbd717b6c..6332ee4f40780f1f67e3c2f82ebd7c3deac6a402 100644 (file)
@@ -40,7 +40,7 @@
 /* .fi
 /*     The external command attributes are given in the \fBmaster.cf\fR
 /*     file at the end of a service definition.  The syntax is as follows:
-/* .IP "\fBflags=BDFRhqu.>\fR (optional)"
+/* .IP "\fBflags=BDFORhqu.>\fR (optional)"
 /*     Optional message processing flags. By default, a message is
 /*     copied unchanged.
 /* .RS
 /*     Prepend a "\fBFrom \fIsender time_stamp\fR" envelope header to
 /*     the message content.
 /*     This is expected by, for example, \fBUUCP\fR software.
+/* .IP \fBO\fR
+/*     Prepend an "\fBX-Original-To: \fIrecipient\fR" message header
+/*     with the original envelope recipient address. Note: for this to work,
+/*     the \fItransport\fB_destination_recipient_limit\fR must be 1.
 /* .IP \fBR\fR
 /*     Prepend a \fBReturn-Path:\fR message header with the envelope sender
 /*     address.
@@ -578,6 +582,9 @@ static void get_service_attr(PIPE_ATTR *attr, char **argv)
                case 'F':
                    attr->flags |= MAIL_COPY_FROM;
                    break;
+               case 'O':
+                   attr->flags |= MAIL_COPY_ORIG_RCPT;
+                   break;
                case 'R':
                    attr->flags |= MAIL_COPY_RETURN_PATH;
                    break;
@@ -699,7 +706,7 @@ static int eval_command_status(int command_status, char *service,
     case PIPE_STAT_OK:
        for (n = 0; n < request->rcpt_list.len; n++) {
            rcpt = request->rcpt_list.info + n;
-           sent(request->queue_id, rcpt->address, service,
+           sent(request->queue_id, rcpt->orig_addr, rcpt->address, service,
                 request->arrival_time, "%s", request->nexthop);
            if (request->flags & DEL_REQ_FLAG_SUCCESS)
                deliver_completed(src, rcpt->offset);
@@ -709,8 +716,9 @@ static int eval_command_status(int command_status, char *service,
        for (n = 0; n < request->rcpt_list.len; n++) {
            rcpt = request->rcpt_list.info + n;
            status = bounce_append(BOUNCE_FLAG_KEEP,
-                                  request->queue_id, rcpt->address,
-                                service, request->arrival_time, "%s", why);
+                                  request->queue_id, rcpt->orig_addr,
+                                  rcpt->address, service,
+                                  request->arrival_time, "%s", why);
            if (status == 0)
                deliver_completed(src, rcpt->offset);
            result |= status;
@@ -720,8 +728,9 @@ static int eval_command_status(int command_status, char *service,
        for (n = 0; n < request->rcpt_list.len; n++) {
            rcpt = request->rcpt_list.info + n;
            result |= defer_append(BOUNCE_FLAG_KEEP,
-                                  request->queue_id, rcpt->address,
-                                service, request->arrival_time, "%s", why);
+                                  request->queue_id, rcpt->orig_addr,
+                                  rcpt->address, service,
+                                  request->arrival_time, "%s", why);
        }
        break;
     case PIPE_STAT_CORRUPT:
@@ -801,6 +810,19 @@ static int deliver_message(DELIVER_REQUEST *request, char *service, char **argv)
        return (deliver_status);
     }
 
+    /*
+     * The O flag cannot be specified for multi-recipient deliveries.
+     */
+    if ((attr.flags & MAIL_COPY_ORIG_RCPT) && (rcpt_list->len > 1)) {
+       deliver_status = eval_command_status(PIPE_STAT_DEFER, service,
+                                            request, request->fp,
+                                            "mailer configuration error");
+       msg_warn("pipe flag `O' requires %s_destination_recipient_limit = 1",
+                service);
+       DELIVER_MSG_CLEANUP();
+       return (deliver_status);
+    }
+
     /*
      * Check that this agent accepts messages this large.
      */
@@ -851,6 +873,7 @@ static int deliver_message(DELIVER_REQUEST *request, char *service, char **argv)
                                  PIPE_CMD_TIME_LIMIT, conf.time_limit,
                                  PIPE_CMD_EOL, STR(attr.eol),
                                  PIPE_CMD_EXPORT, export_env->argv,
+                          PIPE_CMD_ORIG_RCPT, rcpt_list->info[0].orig_addr,
                             PIPE_CMD_DELIVERED, rcpt_list->info[0].address,
                                  PIPE_CMD_END);
     argv_free(export_env);
index 6f01c4f323b497a0c0c269ec900f250c151d0b73..a7685451e9bd16ca998673759e25aa25f49eafd5 100644 (file)
@@ -178,6 +178,7 @@ extern QMGR_QUEUE *qmgr_queue_find(QMGR_TRANSPORT *, const char *);
   */
 struct QMGR_RCPT {
     long    offset;                    /* REC_TYPE_RCPT byte */
+    char   *orig_rcpt;                 /* null or original recipient */
     char   *address;                   /* complete address */
     QMGR_QUEUE *queue;                 /* resolved queue */
 };
@@ -189,7 +190,7 @@ struct QMGR_RCPT_LIST {
 };
 
 extern void qmgr_rcpt_list_init(QMGR_RCPT_LIST *);
-extern void qmgr_rcpt_list_add(QMGR_RCPT_LIST *, long, const char *);
+extern void qmgr_rcpt_list_add(QMGR_RCPT_LIST *, long, const char *, const char *);
 extern void qmgr_rcpt_list_free(QMGR_RCPT_LIST *);
 
  /*
@@ -256,7 +257,7 @@ extern QMGR_MESSAGE *qmgr_message_realloc(QMGR_MESSAGE *);
   */
 extern void qmgr_defer_transport(QMGR_TRANSPORT *, const char *);
 extern void qmgr_defer_todo(QMGR_QUEUE *, const char *);
-extern void qmgr_defer_recipient(QMGR_MESSAGE *, const char *, const char *);
+extern void qmgr_defer_recipient(QMGR_MESSAGE *, const char *, const char *, const char *);
 
  /*
   * qmgr_bounce.c
index d6631c0add856c4486dfd145a00d67c9cfa9bdf6..23b92447b1f51189ae17c8d78d5f15e78604ed2d 100644 (file)
@@ -63,7 +63,7 @@ void    qmgr_bounce_recipient(QMGR_MESSAGE *message, QMGR_RCPT *recipient,
 
     va_start(ap, format);
     status = vbounce_append(BOUNCE_FLAG_KEEP, message->queue_id,
-                           recipient->address, "none",
+                           recipient->orig_rcpt, recipient->address, "none",
                            message->arrival_time, format, ap);
     va_end(ap);
 
index 8be8e7247bb82a1d11c6771803a5038185cec61f..8c0b5e7ce41132bff3ca15ff12763ac1d0ed872d 100644 (file)
@@ -131,7 +131,8 @@ void    qmgr_defer_todo(QMGR_QUEUE *queue, const char *reason)
        message = entry->message;
        for (nrcpt = 0; nrcpt < entry->rcpt_list.len; nrcpt++) {
            recipient = entry->rcpt_list.info + nrcpt;
-           qmgr_defer_recipient(message, recipient->address, reason);
+           qmgr_defer_recipient(message, recipient->orig_rcpt,
+                                recipient->address, reason);
        }
        qmgr_entry_done(entry, QMGR_QUEUE_TODO);
     }
@@ -139,8 +140,8 @@ void    qmgr_defer_todo(QMGR_QUEUE *queue, const char *reason)
 
 /* qmgr_defer_recipient - defer delivery of specific recipient */
 
-void    qmgr_defer_recipient(QMGR_MESSAGE *message, const char *address,
-                                    const char *reason)
+void    qmgr_defer_recipient(QMGR_MESSAGE *message, const char *orig_addr,
+                                    const char *address, const char *reason)
 {
     char   *myname = "qmgr_defer_recipient";
 
@@ -154,6 +155,6 @@ void    qmgr_defer_recipient(QMGR_MESSAGE *message, const char *address,
      * Update the message structure and log the message disposition.
      */
     message->flags |= defer_append(BOUNCE_FLAG_KEEP, message->queue_id,
-                                  address, "none", message->arrival_time,
-                                  "%s", reason);
+                                  orig_addr, address, "none",
+                                  message->arrival_time, "%s", reason);
 }
index 64b170c26a3a939e3b42d39e00e402dd775c048d..136b3dcb7f1f1aab068b1cae367405735e66c524 100644 (file)
@@ -172,6 +172,8 @@ static int qmgr_deliver_send_request(QMGR_ENTRY *entry, VSTREAM *stream)
     for (recipient = list.info; recipient < list.info + list.len; recipient++)
        attr_print(stream, ATTR_FLAG_MORE,
                   ATTR_TYPE_LONG, MAIL_ATTR_OFFSET, recipient->offset,
+                  ATTR_TYPE_STR, MAIL_ATTR_ORCPT,
+                  recipient->orig_rcpt ? recipient->orig_rcpt : "",
                   ATTR_TYPE_STR, MAIL_ATTR_RECIP, recipient->address,
                   ATTR_TYPE_END);
     attr_print(stream, ATTR_FLAG_NONE,
index 9eb702376fedaed2791c0debe42615f1074a6e7b..fd92d7d5234638f99985515408602861d3e68efe 100644 (file)
@@ -208,6 +208,7 @@ static int qmgr_message_read(QMGR_MESSAGE *message)
     const char *error_text;
     char   *name;
     char   *value;
+    char   *orig_rcpt = 0;
 
     /*
      * Initialize. No early returns or we have a memory leak.
@@ -276,7 +277,12 @@ static int qmgr_message_read(QMGR_MESSAGE *message)
        } else if (rec_type == REC_TYPE_RCPT) {
 #define FUDGE(x)       ((x) * (var_qmgr_fudge / 100.0))
            if (message->rcpt_list.len < FUDGE(var_qmgr_rcpt_limit)) {
-               qmgr_rcpt_list_add(&message->rcpt_list, curr_offset, start);
+               qmgr_rcpt_list_add(&message->rcpt_list, curr_offset,
+                                  orig_rcpt, start);
+               if (orig_rcpt) {
+                   myfree(orig_rcpt);
+                   orig_rcpt = 0;
+               }
                if (message->rcpt_list.len >= FUDGE(var_qmgr_rcpt_limit)) {
                    if ((message->rcpt_offset = vstream_ftell(message->fp)) < 0)
                        msg_fatal("vstream_ftell %s: %m",
@@ -335,8 +341,25 @@ static int qmgr_message_read(QMGR_MESSAGE *message)
                }
            }
        }
+       if (orig_rcpt != 0) {
+           msg_warn("%s: out-of-order original recipient <%.200s>",
+                    message->queue_id, start);
+           myfree(orig_rcpt);
+           orig_rcpt = 0;
+       }
+       if (rec_type == REC_TYPE_ORCP)
+           orig_rcpt = mystrdup(start);
     } while (rec_type > 0 && rec_type != REC_TYPE_END);
 
+    /*
+     * Grr.
+     */
+    if (orig_rcpt != 0) {
+       msg_warn("%s: out-of-order original recipient <%.200s>",
+                message->queue_id, start);
+       myfree(orig_rcpt);
+    }
+
     /*
      * If there is no size record, use the queue file size instead.
      */
@@ -565,7 +588,8 @@ static void qmgr_message_resolve(QMGR_MESSAGE *message)
                                      "user has moved to %s", newloc);
                continue;
            } else if (dict_errno != 0) {
-               qmgr_defer_recipient(message, recipient->address,
+               qmgr_defer_recipient(message, recipient->orig_rcpt,
+                                    recipient->address,
                                     "relocated map lookup failure");
                continue;
            }
@@ -651,8 +675,9 @@ static void qmgr_message_resolve(QMGR_MESSAGE *message)
            if (strncasecmp(STR(reply.recipient), var_double_bounce_sender,
                            len) == 0
                && !var_double_bounce_sender[len]) {
-               sent(message->queue_id, recipient->address,
-                    "none", message->arrival_time, "discarded");
+               sent(message->queue_id, recipient->orig_rcpt,
+                    recipient->address, "none", message->arrival_time,
+                    "discarded");
                deliver_completed(message->fp, recipient->offset);
                msg_warn("%s: undeliverable postmaster notification discarded",
                         message->queue_id);
@@ -671,7 +696,8 @@ static void qmgr_message_resolve(QMGR_MESSAGE *message)
                if (strcasecmp(*cpp, STR(reply.transport)) == 0)
                    break;
            if (*cpp) {
-               qmgr_defer_recipient(message, recipient->address,
+               qmgr_defer_recipient(message, recipient->orig_rcpt,
+                                    recipient->address,
                                     "deferred transport");
                continue;
            }
@@ -701,7 +727,8 @@ static void qmgr_message_resolve(QMGR_MESSAGE *message)
         * This transport is dead. Defer delivery to this recipient.
         */
        if ((transport->flags & QMGR_TRANSPORT_STAT_DEAD) != 0) {
-           qmgr_defer_recipient(message, recipient->address, transport->reason);
+           qmgr_defer_recipient(message, recipient->orig_rcpt,
+                                recipient->address, transport->reason);
            continue;
        }
 
@@ -718,7 +745,8 @@ static void qmgr_message_resolve(QMGR_MESSAGE *message)
         * This queue is dead. Defer delivery to this recipient.
         */
        if (queue->window == 0) {
-           qmgr_defer_recipient(message, recipient->address, queue->reason);
+           qmgr_defer_recipient(message, recipient->orig_rcpt,
+                                recipient->address, queue->reason);
            continue;
        }
 
@@ -757,7 +785,8 @@ static void qmgr_message_assign(QMGR_MESSAGE *message)
                             entry->rcpt_list.len)) {
                entry = qmgr_entry_create(queue, message);
            }
-           qmgr_rcpt_list_add(&entry->rcpt_list, recipient->offset, recipient->address);
+           qmgr_rcpt_list_add(&entry->rcpt_list, recipient->offset,
+                              recipient->orig_rcpt, recipient->address);
            qmgr_recipient_count++;
        }
     }
index 2bb292e016e29e519ec0f325bf11e006834058e2..94287fade4c8003719e7f65c3520d4d740c24f79 100644 (file)
@@ -9,9 +9,10 @@
 /*     void    qmgr_rcpt_list_init(list)
 /*     QMGR_RCPT_LIST *list;
 /*
-/*     void    qmgr_rcpt_list_add(list, offset, recipient)
+/*     void    qmgr_rcpt_list_add(list, offset, orig_rcpt, recipient)
 /*     QMGR_RCPT_LIST *list;
 /*     long    offset;
+/*     const char *orig_rcpt;
 /*     const char *recipient;
 /*
 /*     void    qmgr_rcpt_list_free(list)
@@ -71,13 +72,15 @@ void    qmgr_rcpt_list_init(QMGR_RCPT_LIST *list)
 
 /* qmgr_rcpt_list_add - add rcpt to list */
 
-void    qmgr_rcpt_list_add(QMGR_RCPT_LIST *list, long offset, const char *rcpt)
+void    qmgr_rcpt_list_add(QMGR_RCPT_LIST *list, long offset,
+                                  const char *orcpt, const char *rcpt)
 {
     if (list->len >= list->avail) {
        list->avail *= 2;
        list->info = (QMGR_RCPT *)
            myrealloc((char *) list->info, list->avail * sizeof(QMGR_RCPT));
     }
+    list->info[list->len].orig_rcpt = (orcpt ? mystrdup(orcpt) : 0);
     list->info[list->len].address = mystrdup(rcpt);
     list->info[list->len].offset = offset;
     list->info[list->len].queue = 0;
@@ -90,7 +93,10 @@ void    qmgr_rcpt_list_free(QMGR_RCPT_LIST *list)
 {
     QMGR_RCPT *rcpt;
 
-    for (rcpt = list->info; rcpt < list->info + list->len; rcpt++)
+    for (rcpt = list->info; rcpt < list->info + list->len; rcpt++) {
+       if (rcpt->orig_rcpt)
+           myfree(rcpt->orig_rcpt);
        myfree(rcpt->address);
+    }
     myfree((char *) list->info);
 }
index cc878e4fc384096bd62488ffa8486dffb1ad1642..6b76ae51c652daf7e59f143d5924d5a90c321e34 100644 (file)
@@ -95,6 +95,7 @@ qmqpd.o: ../../include/quote_822_local.h
 qmqpd.o: ../../include/quote_flags.h
 qmqpd.o: ../../include/match_parent_style.h
 qmqpd.o: ../../include/lex_822.h
+qmqpd.o: ../../include/verp_sender.h
 qmqpd.o: ../../include/mail_server.h
 qmqpd.o: qmqpd.h
 qmqpd_peer.o: qmqpd_peer.c
index a251e9774ca07b5aa7fe45f5edf8b3923ecc8442..86b825ebe0fb27c4b58fabea6410db2e4156ae43 100644 (file)
@@ -43,9 +43,9 @@
 /*     RFC 1870 (Message Size Declaration)
 /*     RFC 2045 (MIME: Format of Internet Message Bodies)
 /*     RFC 2046 (MIME: Media Types)
-/*     RFC 2197 (Pipelining)
 /*     RFC 2554 (AUTH command)
 /*     RFC 2821 (SMTP protocol)
+/*     RFC 2920 (SMTP Pipelining)
 /* DIAGNOSTICS
 /*     Problems and transactions are logged to \fBsyslogd\fR(8).
 /*     Corrupted message files are marked so that the queue manager can
index d13fe66cf6e6f8cb7d5bb454c69e0c3b2944ae97..4dad14c024672cc574a2852b8b880613daa989b7 100644 (file)
@@ -700,7 +700,8 @@ int     smtp_xfer(SMTP_STATE *state)
                            for (nrcpt = 0; nrcpt < recv_rcpt; nrcpt++) {
                                rcpt = request->rcpt_list.info + nrcpt;
                                if (rcpt->offset) {
-                                   sent(request->queue_id, rcpt->address,
+                                   sent(request->queue_id, rcpt->orig_addr,
+                                        rcpt->address,
                                         session->namaddr,
                                         request->arrival_time, "%s",
                                         resp->str);
index d9128f1f52bddc850ce61d6ac82a6c81eb68c28f..ef78e51f302e1781b85140e25d549535c32ee3b8 100644 (file)
@@ -167,7 +167,7 @@ int     smtp_site_fail(SMTP_STATE *state, int code, char *format,...)
        if (rcpt->offset == 0)
            continue;
        status = (soft_error ? defer_append : bounce_append)
-           (KEEP, request->queue_id, rcpt->address,
+           (KEEP, request->queue_id, rcpt->orig_addr, rcpt->address,
             session ? session->namaddr : "none",
             request->arrival_time, "%s", vstring_str(why));
        if (status == 0) {
@@ -214,7 +214,7 @@ int     smtp_mesg_fail(SMTP_STATE *state, int code, char *format,...)
        if (rcpt->offset == 0)
            continue;
        status = (SMTP_SOFT(code) ? defer_append : bounce_append)
-           (KEEP, request->queue_id, rcpt->address,
+           (KEEP, request->queue_id, rcpt->orig_addr, rcpt->address,
             session->namaddr, request->arrival_time,
             "%s", vstring_str(why));
        if (status == 0) {
@@ -248,8 +248,8 @@ void    smtp_rcpt_fail(SMTP_STATE *state, int code, RECIPIENT *rcpt,
      */
     va_start(ap, format);
     status = (SMTP_SOFT(code) ? vdefer_append : vbounce_append)
-       (KEEP, request->queue_id, rcpt->address, session->namaddr,
-        request->arrival_time, format, ap);
+       (KEEP, request->queue_id, rcpt->orig_addr, rcpt->address,
+        session->namaddr, request->arrival_time, format, ap);
     va_end(ap);
     if (status == 0) {
        deliver_completed(state->src, rcpt->offset);
@@ -294,7 +294,8 @@ int     smtp_stream_except(SMTP_STATE *state, int code, char *description)
        if (rcpt->offset == 0)
            continue;
        state->status |= defer_append(KEEP, request->queue_id,
-                                     rcpt->address, session->namaddr,
+                                     rcpt->orig_addr, rcpt->address,
+                                     session->namaddr,
                                      request->arrival_time,
                                      "%s", vstring_str(why));
     }
index b88803c9a9e1b3f452325ed25bd7f54934cdb0e3..7e9a1152c17c21d773fec0d2bd76278033742b4b 100644 (file)
 /*     RFC 1123 (Host requirements)
 /*     RFC 1652 (8bit-MIME transport)
 /*     RFC 1869 (SMTP service extensions)
-/*     RFC 1854 (SMTP Pipelining)
 /*     RFC 1870 (Message Size Declaration)
 /*     RFC 1985 (ETRN command)
 /*     RFC 2554 (AUTH command)
 /*     RFC 2821 (SMTP protocol)
+/*     RFC 2920 (SMTP Pipelining)
 /* DIAGNOSTICS
 /*     Problems and transactions are logged to \fBsyslogd\fR(8).
 /*
 /* .IP \fBdefault_rbl_reply\fR
 /*     Default template reply when a request is RBL blacklisted.
 /*     This template is used by the \fBreject_rbl_*\fR and
-/*     \fBreject_rhsbl_*\fR restrictions. See also: 
+/*     \fBreject_rhsbl_*\fR restrictions. See also:
 /*     \fBrbl_reply_maps\fR and \fBsmtpd_expansion_filter\fR.
 /* .IP \fBdefer_code\fR
 /*     Response code when a client request is rejected by the \fBdefer\fR
 /* .IP \fBmaps_rbl_reject_code\fR
 /*     Response code when a request is RBL blacklisted.
 /* .IP \fBrbl_reply_maps\fR
-/*     Table with template responses for RBL blacklisted requests, indexed by 
-/*     RBL domain name. These templates are used by the \fBreject_rbl_*\fR 
-/*     and \fBreject_rhsbl_*\fR restrictions. See also: 
+/*     Table with template responses for RBL blacklisted requests, indexed by
+/*     RBL domain name. These templates are used by the \fBreject_rbl_*\fR
+/*     and \fBreject_rhsbl_*\fR restrictions. See also:
 /*     \fBdefault_rbl_reply\fR and \fBsmtpd_expansion_filter\fR.
 /* .IP \fBreject_code\fR
 /*     Response code when the client matches a \fBreject\fR restriction.
index d20c9404c1a7e0cf39ab40aa2dd1f4f1d8521b5f..657f9a32a12d54a1b08f87d12b03828ece10190c 100644 (file)
@@ -92,13 +92,16 @@ static VSTREAM *safe_open_exist(const char *path, int flags,
 {
     struct stat local_statbuf;
     struct stat lstat_st;
+    int     saved_errno;
     VSTREAM *fp;
 
     /*
      * Open an existing file.
      */
     if ((fp = vstream_fopen(path, flags & ~(O_CREAT | O_EXCL), 0)) == 0) {
+       saved_errno = errno;
        vstring_sprintf(why, "cannot open file: %m");
+       errno = saved_errno;
        return (0);
     }
 
index 9635f7efba4eb8783bbe6061cb5ffcd67254299d..cd8c323196fb61c0d029f34546bfcb88101112c8 100644 (file)
 /*     While searching a lookup table, an address extension
 /*     (\fIuser+foo@domain.tld\fR) is ignored.
 /*
-/*     In a lookup table, specify a left-hand side of \fI@domain.tld\fR 
+/*     In a lookup table, specify a left-hand side of \fI@domain.tld\fR
 /*     to match any user in the specified domain that does not have a
 /*     specific \fIuser@domain.tld\fR entry.
 /*
 /*     While searching a lookup table, an address extension
 /*     (\fIuser+foo@domain.tld\fR) is ignored.
 /*
-/*     In a lookup table, specify a left-hand side of \fI@domain.tld\fR 
+/*     In a lookup table, specify a left-hand side of \fI@domain.tld\fR
 /*     to match any user in the specified domain that does not have a
 /*     specific \fIuser@domain.tld\fR entry.
 /* .IP "\fBvirtual_gid_maps\fR (regexp maps disallowed)"
 /*     While searching a lookup table, an address extension
 /*     (\fIuser+foo@domain.tld\fR) is ignored.
 /*
-/*     In a lookup table, specify a left-hand side of \fI@domain.tld\fR 
+/*     In a lookup table, specify a left-hand side of \fI@domain.tld\fR
 /*     to match any user in the specified domain that does not have a
 /*     specific \fIuser@domain.tld\fR entry.
 /* .SH "Locking controls"
@@ -317,6 +317,7 @@ static int local_deliver(DELIVER_REQUEST *rqst, char *service)
      * recipient. Update the per-message delivery status.
      */
     for (msg_stat = 0, rcpt = rqst->rcpt_list.info; rcpt < rcpt_end; rcpt++) {
+       state.msg_attr.orig_rcpt = rcpt->orig_addr;
        state.msg_attr.recipient = rcpt->address;
        rcpt_stat = deliver_recipient(state, usr_attr);
        if (rcpt_stat == 0)
index 1443bc8d04f20e806e10a2241d0bfa33b70f8ab9..844441d5a9859c9af48037a664ed9b54e27442de 100644 (file)
@@ -66,6 +66,7 @@ typedef struct DELIVER_ATTR {
     char   *queue_id;                  /* mail queue id */
     long    offset;                    /* data offset */
     char   *sender;                    /* taken from envelope */
+    char   *orig_rcpt;                 /* taken from sender */
     char   *recipient;                 /* taken from resolver */
     char   *user;                      /* recipient lookup handle */
     char   *delivered;                 /* for loop detection */
@@ -92,11 +93,12 @@ typedef struct LOCAL_STATE {
  /*
   * Bundle up some often-user attributes.
   */
-#define BOUNCE_ATTR(attr)      attr.queue_id, attr.recipient, attr.relay, \
-                                       attr.arrival_time
-#define SENT_ATTR(attr)                attr.queue_id, attr.recipient, attr.relay, \
-                                       attr.arrival_time
-#define COPY_ATTR(attr)                attr.sender, attr.delivered, attr.fp
+#define BOUNCE_ATTR(attr)      attr.queue_id, attr.orig_rcpt, attr.recipient, \
+                                       attr.relay, attr.arrival_time
+#define SENT_ATTR(attr)                attr.queue_id, attr.orig_rcpt, attr.recipient, \
+                                       attr.relay, attr.arrival_time
+#define COPY_ATTR(attr)                attr.sender, attr.orig_rcpt, attr.delivered, \
+                                       attr.fp
 
 #define MSG_LOG_STATE(m, p) \
        msg_info("%s[%d]: recip %s deliver %s", m, \