]> git.ipfire.org Git - thirdparty/postfix.git/commitdiff
postfix-2.0.10-20030531
authorWietse Venema <wietse@porcupine.org>
Sat, 31 May 2003 05:00:00 +0000 (00:00 -0500)
committerViktor Dukhovni <viktor@dukhovni.org>
Tue, 5 Feb 2013 06:28:54 +0000 (06:28 +0000)
28 files changed:
postfix/HISTORY
postfix/html/qmgr.8.html
postfix/man/man8/qmgr.8
postfix/src/cleanup/Makefile.in
postfix/src/cleanup/cleanup.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_message.c
postfix/src/cleanup/cleanup_state.c
postfix/src/global/Makefile.in
postfix/src/global/cleanup_user.h
postfix/src/global/mail_version.h
postfix/src/global/qmgr_user.h [new file with mode: 0644]
postfix/src/global/rec_type.h
postfix/src/nqmgr/Makefile.in
postfix/src/nqmgr/qmgr.h
postfix/src/nqmgr/qmgr_message.c
postfix/src/qmgr/Makefile.in
postfix/src/qmgr/qmgr.c
postfix/src/qmgr/qmgr.h
postfix/src/qmgr/qmgr_entry.c
postfix/src/qmgr/qmgr_message.c
postfix/src/smtpd/smtpd.c
postfix/src/smtpd/smtpd.h
postfix/src/smtpd/smtpd_check.c
postfix/src/util/sys_defs.h

index 05995f9c7318242c3f52e12b405fa3435ac9b36a..88bf11709869d4e72f83e9c724acc4bd179e0a5a 100644 (file)
@@ -8104,7 +8104,7 @@ Apologies for any names omitted.
        descriptor is writable while write() transfers zero bytes.
        File:  global/pipe_command.c.
 
-2003052[3-6]
+2003052[3-9]
 
        Cleanup: rewrote the queue file record processing loops in
        cleanup and in [n]qmgr. This code had deteriorated a lot
@@ -8118,12 +8118,31 @@ Apologies for any names omitted.
        (a.k.a.  20010228). Files: cleanup/cleanup_extracted.c,
        showq/showq.c.
 
+       Performance: the queue manager no longer has to examine
+       every queue file record before it can start deliveries.
+       This helps to avoid thrashing with very large mailing lists.
+       Postfix queue files have an extra field in the size record
+       with queue manager processing hints.  This change is backward
+       and forward compatible.  Files:  cleanup/cleanup_envelope.c,
+       cleanup/cleanup_extracted.c, *qmgr/qmgr_message.c.
+
 20030528
 
        Compatibility: "sendmail -q<time>" without -bd option causes
        the command to exit instead of waiting for input on the
        standard input stream. File: sendmail/sendmail.c.
 
+20030530
+
+       Bugfix: client access denied with smtpd_delay_reject=no
+       broke "sendmail -bs". Fix by Victor Duchovni, Morgan Stanley.
+       File: smtpd/smtpd.c.
+
+20030531
+
+       Compatibility: allow <@site,@site:address> route addresses
+       in SMTP commands.  File: smtpd/smtpd.c.
+
 Open problems:
 
        Low: smtp-source may block when sending large test messages.
index 48c8b188fa43e2d25ac954ae34e2781df4b65556..bf1197c21662f5ada905f9e7e9b2dd7155122368 100644 (file)
@@ -220,42 +220,26 @@ QMGR(8)                                                   QMGR(8)
        In the text below, <i>transport</i> is the first field in a  <b>mas-</b>
        <b>ter.cf</b> entry.
 
-       <b>qmgr</b><i>_</i><b>fudge</b><i>_</i><b>factor</b> (valid range: 10..100)
-              The  percentage  of  delivery resources that a busy
-              mail system will use up for  delivery  of  a  large
-              mailing  list  message.  With 100%, delivery of one
-              message does not begin before the previous  message
-              has  been  delivered.  This results in good perfor-
-              mance for large mailing lists, but results in  poor
-              response  time for one-to-one mail.  With less than
-              100%, response time for one-to-one  mail  improves,
-              but  large  mailing  list delivery performance suf-
-              fers. In the worst case, recipients near the begin-
-              ning  of  a  large list receive a burst of messages
-              immediately, while recipients near the end of  that
-              list  receive  that  same burst of messages a whole
-              day later.
-
        <b>initial</b><i>_</i><b>destination</b><i>_</i><b>concurrency</b>
-              Initial per-destination concurrency level for  par-
+              Initial  per-destination concurrency level for par-
               allel delivery to the same destination.
 
        <b>default</b><i>_</i><b>destination</b><i>_</i><b>concurrency</b><i>_</i><b>limit</b>
-              Default  limit on the number of parallel deliveries
+              Default limit on the number of parallel  deliveries
               to the same destination.
 
        <i>transport_</i><b>destination</b><i>_</i><b>concurrency</b><i>_</i><b>limit</b>
-              Limit on the number of parallel deliveries  to  the
-              same  destination,  for delivery via the named mes-
+              Limit  on  the number of parallel deliveries to the
+              same destination, for delivery via the  named  mes-
               sage <i>transport</i>.
 
 <b>Recipient</b> <b>controls</b>
        <b>default</b><i>_</i><b>destination</b><i>_</i><b>recipient</b><i>_</i><b>limit</b>
-              Default limit on the number of recipients per  mes-
+              Default  limit on the number of recipients per mes-
               sage transfer.
 
        <i>transport_</i><b>destination</b><i>_</i><b>recipient</b><i>_</i><b>limit</b>
-              Limit  on  the  number  of  recipients  per message
+              Limit on  the  number  of  recipients  per  message
               transfer, for the named message <i>transport</i>.
 
 <b>SEE</b> <b>ALSO</b>
@@ -264,7 +248,7 @@ QMGR(8)                                                   QMGR(8)
        <a href="trivial-rewrite.8.html">trivial-rewrite(8)</a>, address routing
 
 <b>LICENSE</b>
-       The Secure Mailer license must be  distributed  with  this
+       The  Secure  Mailer  license must be distributed with this
        software.
 
 <b>AUTHOR(S)</b>
index 039112b61ccfc54a8f838d08a0dde14decfb4694..a42aba54779687cb0f79ac629b7ffb0e29a48cdc 100644 (file)
@@ -211,17 +211,6 @@ delivery transport.
 .fi
 In the text below, \fItransport\fR is the first field in a
 \fBmaster.cf\fR entry.
-.IP "\fBqmgr_fudge_factor\fR (valid range: 10..100)"
-The percentage of delivery resources that a busy mail system will
-use up for delivery of a large mailing list message.
-With 100%, delivery of one message does not begin before the previous
-message has been delivered. This results in good performance for large
-mailing lists, but results in poor response time for one-to-one mail.
-With less than 100%, response time for one-to-one mail improves,
-but large mailing list delivery performance suffers. In the worst
-case, recipients near the beginning of a large list receive a burst
-of messages immediately, while recipients near the end of that list
-receive that same burst of messages a whole day later.
 .IP \fBinitial_destination_concurrency\fR
 Initial per-destination concurrency level for parallel delivery
 to the same destination.
index 6ad1ee0ac02b0e0e93bca7980fc1c7b3dc4a580e..ef995fb26701e3712fea96997245509df1c4487f 100644 (file)
@@ -192,6 +192,7 @@ cleanup_envelope.o: ../../include/htable.h
 cleanup_envelope.o: ../../include/record.h
 cleanup_envelope.o: ../../include/rec_type.h
 cleanup_envelope.o: ../../include/cleanup_user.h
+cleanup_envelope.o: ../../include/qmgr_user.h
 cleanup_envelope.o: ../../include/tok822.h
 cleanup_envelope.o: ../../include/resolve_clnt.h
 cleanup_envelope.o: ../../include/mail_params.h
@@ -222,6 +223,7 @@ cleanup_extracted.o: ../../include/mymalloc.h
 cleanup_extracted.o: ../../include/nvtable.h
 cleanup_extracted.o: ../../include/htable.h
 cleanup_extracted.o: ../../include/cleanup_user.h
+cleanup_extracted.o: ../../include/qmgr_user.h
 cleanup_extracted.o: ../../include/record.h
 cleanup_extracted.o: ../../include/rec_type.h
 cleanup_extracted.o: ../../include/mail_params.h
index 1e988f22e9bf29601cdfc58ae15009ca0475266e..0d8afa8b457de7d0009eee7487b4a7bd5457e075 100644 (file)
 /*     These filters see physical lines one at a time, in chunks of
 /*     at most line_length_limit bytes.
 /* .IP \fBbody_checks_size_limit\fP
-/*     The amount of content per message body segment that is 
+/*     The amount of content per message body segment that is
 /*     subjected to \fB$body_checks\fR filtering.
 /* .IP \fBheader_checks\fR
 /* .IP "\fBmime_header_checks\fR (default: \fB$header_checks\fR)"
 /* .IP "\fBnested_header_checks\fR (default: \fB$header_checks\fR)"
 /*     Lookup tables with content filters for message header lines:
-/*     respectively, these are applied to the primary message headers 
-/*     (not including MIME headers), to the MIME headers anywhere in 
+/*     respectively, these are applied to the primary message headers
+/*     (not including MIME headers), to the MIME headers anywhere in
 /*     the message, and to the initial headers of attached messages.
 /*     These filters see logical headers one at a time, including headers
 /*     that span multiple lines.
 /* .ad
 /* .fi
 /* .IP \fBdisable_mime_input_processing\fR
-/*     While receiving, give no special treatment to \fBContent-Type:\fR 
-/*     message headers; all text after the initial message headers is 
+/*     While receiving, give no special treatment to \fBContent-Type:\fR
+/*     message headers; all text after the initial message headers is
 /*     considered to be part of the message body.
 /* .IP \fBmime_boundary_length_limit\fR
 /*     The amount of space that will be allocated for MIME multipart
 /*     boundary strings. The MIME processor is unable to distinguish
-/*     between boundary strings that do not differ in the first 
+/*     between boundary strings that do not differ in the first
 /*     \fB$mime_boundary_length_limit\fR characters.
 /* .IP \fBmime_nesting_limit\fR
 /*     The maximal nesting level of multipart mail that the MIME
 /*     Reject mail with 8-bit text in message headers. This blocks
 /*     mail from poorly written applications.
 /* .IP \fBstrict_8bitmime_body\fR
-/*     Reject mail with 8-bit text in content that claims to be 7-bit, 
-/*     or in content that has no explicit content encoding information. 
-/*     This blocks mail from poorly written mail software. Unfortunately, 
-/*     this also breaks majordomo approval requests when the included 
+/*     Reject mail with 8-bit text in content that claims to be 7-bit,
+/*     or in content that has no explicit content encoding information.
+/*     This blocks mail from poorly written mail software. Unfortunately,
+/*     this also breaks majordomo approval requests when the included
 /*     request contains valid 8-bit MIME mail, and it breaks bounces from
 /*     mailers that do not properly encapsulate 8-bit content (for example,
 /*     bounces from qmail or from old versions of Postfix).
index bfca5262480fd0ec11aece4b350112b22b19dab9..bb09e8fe12e1e3f4a2eac37cdc299d9a3bc3f851 100644 (file)
@@ -47,7 +47,8 @@ typedef struct CLEANUP_STATE {
     char   *orig_rcpt;                 /* original recipient address */
     char   *return_receipt;            /* return-receipt address */
     char   *errors_to;                 /* errors-to address */
-    int     flags;                     /* processing options */
+    int     flags;                     /* processing options, status flags */
+    int     qmgr_opts;                 /* qmgr processing options */
     int     errs;                      /* any badness experienced */
     int     err_mask;                  /* allowed badness */
     int     headers_seen;              /* which headers were seen */
@@ -56,10 +57,7 @@ typedef struct CLEANUP_STATE {
     BH_TABLE *dups;                    /* recipient dup filter */
     void    (*action) (struct CLEANUP_STATE *, int, const char *, int);
     off_t   data_offset;               /* start of message content */
-    off_t   xtra_offset;               /* start of extracted content */
-    int     warn_seen;                 /* REC_TYPE_WARN seen */
-    int     verp_seen;                 /* REC_TYPE_VERP seen */
-    int     end_seen;                  /* REC_TYPE_END seen */
+    off_t   xtra_offset;               /* start of extra segment */
     int     rcpt_count;                        /* recipient count */
     char   *reason;                    /* failure reason */
     NVTABLE *attr;                     /* queue file attribute list */
@@ -69,6 +67,13 @@ typedef struct CLEANUP_STATE {
     char   *redirect;                  /* from header/body patterns */
 } CLEANUP_STATE;
 
+ /*
+  * Status flags. Flags 0-15 are reserved for cleanup_user.h.
+  */
+#define CLEANUP_FLAG_INRCPT    (1<<16) /* Processing recipient records */
+#define CLEANUP_FLAG_WARN_SEEN (1<<17) /* REC_TYPE_WARN record seen */
+#define CLEANUP_FLAG_END_SEEN  (1<<18) /* REC_TYPE_END record seen */
+
  /*
   * Mappings.
   */
index c0f749cd377d2f1a1ceb8d10a189c98249988b0f..eb67ce24446c2bb85ad8c392705d449207b5f8bb 100644 (file)
@@ -188,7 +188,7 @@ int     cleanup_flush(CLEANUP_STATE *state)
     if (CLEANUP_OUT_OK(state)) {
        if (state->recip == 0)
            state->errs |= CLEANUP_STAT_RCPT;
-       if (state->end_seen == 0)
+       if ((state->flags & CLEANUP_FLAG_END_SEEN) == 0)
            state->errs |= CLEANUP_STAT_BAD;
     }
 
index 2e731a9481a83dbf1254e5e1da4621bea1c497b7..8026e6fa3598934f2dcfff4944150dac98159623 100644 (file)
@@ -63,6 +63,7 @@
 #include <record.h>
 #include <rec_type.h>
 #include <cleanup_user.h>
+#include <qmgr_user.h>
 #include <tok822.h>
 #include <mail_params.h>
 #include <ext_prop.h>
@@ -93,7 +94,8 @@ void    cleanup_envelope(CLEANUP_STATE *state, int type,
     cleanup_out_format(state, REC_TYPE_SIZE, REC_TYPE_SIZE_FORMAT,
                       (REC_TYPE_SIZE_CAST1) 0, /* content size */
                       (REC_TYPE_SIZE_CAST2) 0, /* content offset */
-                      (REC_TYPE_SIZE_CAST3) 0);        /* recipient count */
+                      (REC_TYPE_SIZE_CAST3) 0, /* recipient count */
+                      (REC_TYPE_SIZE_CAST4) 0);/* qmgr options */
 
     /*
      * Pass control to the actual envelope processing routine.
@@ -110,19 +112,19 @@ static void cleanup_envelope_process(CLEANUP_STATE *state, int type,
     char   *attr_name;
     char   *attr_value;
     const char *error_text;
-    int     extra_flags;
+    int     extra_opts;
 
     if (msg_verbose)
        msg_info("initial envelope %c %.*s", type, len, buf);
 
     if (type == REC_TYPE_FLGS) {
        /* Not part of queue file format. */
-       extra_flags = atol(buf);
-       if (extra_flags & ~CLEANUP_FLAG_MASK_EXTRA)
+       extra_opts = atol(buf);
+       if (extra_opts & ~CLEANUP_FLAG_MASK_EXTRA)
            msg_warn("%s: ignoring bad extra flags: 0x%x",
-                    state->queue_id, extra_flags);
+                    state->queue_id, extra_opts);
        else
-           state->flags |= extra_flags;
+           state->flags |= extra_opts;
        return;
     }
     if (strchr(REC_TYPE_ENVELOPE, type) == 0) {
@@ -133,13 +135,55 @@ static void cleanup_envelope_process(CLEANUP_STATE *state, int type,
     }
 
     /*
-     * The code for processing recipient records is first, because there can
-     * be lots of them. However, recipient records appear at the end of the
-     * initial or extracted envelope, so that the queue manager does not have
-     * to read the whole envelope before it can start deliveries.
+     * Although recipient records appear at the end of the initial or
+     * extracted envelope, the code for processing recipient records is first
+     * because there can be lots of them.
+     * 
+     * Recipient records may be mixed with other information (such as FILTER or
+     * REDIRECT actions from SMTPD). In that case the queue manager needs to
+     * examine all queue file records before it can start delivery. This is
+     * not a problem because SMTPD recipient lists are small.
+     * 
+     * However, if recipient records are not mixed with other records
+     * (typically, mailing list mail) then we can make an optimization: the
+     * queue manager does not need to examine every envelope record before it
+     * can start deliveries. This can help with very large mailing lists.
      */
-    if (type == REC_TYPE_RCPT) {
+
+    /*
+     * On the transition from non-recipient records to recipient records,
+     * emit some records and do some sanity checks.
+     * 
+     * XXX Moving the envelope sender (and the test for its presence) to the
+     * extracted segment can reduce qmqpd memory requirements because it no
+     * longer needs to read the entire message into main memory.
+     */
+    if ((state->flags & CLEANUP_FLAG_INRCPT) == 0
+       && strchr(REC_TYPE_ENV_RECIPIENT, type) != 0) {
+       if ((state->flags & CLEANUP_FLAG_WARN_SEEN) == 0
+           && var_delay_warn_time > 0) {
+           cleanup_out_format(state, REC_TYPE_WARN, REC_TYPE_WARN_FORMAT,
+                              (long) var_delay_warn_time);
+       }
+       if (state->sender == 0) {
+           msg_warn("%s: message rejected: missing sender envelope record",
+                    state->queue_id);
+           state->errs |= CLEANUP_STAT_BAD;
+           return;
+       }
+       if (state->time == 0) {
+           msg_warn("%s: message rejected: missing time envelope record",
+                    state->queue_id);
+           state->errs |= CLEANUP_STAT_BAD;
+           return;
+       }
        state->flags |= CLEANUP_FLAG_INRCPT;
+    }
+
+    /*
+     * Regular initial envelope record processing.
+     */
+    if (type == REC_TYPE_RCPT) {
        if (state->sender == 0) {               /* protect showq */
            msg_warn("%s: message rejected: envelope recipient precedes sender",
                     state->queue_id);
@@ -154,7 +198,6 @@ static void cleanup_envelope_process(CLEANUP_STATE *state, int type,
        return;
     }
     if (type == REC_TYPE_DONE) {
-       state->flags |= CLEANUP_FLAG_INRCPT;
        if (state->orig_rcpt != 0) {
            myfree(state->orig_rcpt);
            state->orig_rcpt = 0;
@@ -169,53 +212,12 @@ static void cleanup_envelope_process(CLEANUP_STATE *state, int type,
        state->orig_rcpt = 0;
     }
     if (type == REC_TYPE_ORCP) {
-       state->flags |= CLEANUP_FLAG_INRCPT;
        state->orig_rcpt = mystrdup(buf);
        return;
     }
-
-    /*
-     * These non-recipient records may appear before or after recipient
-     * records. In order to keep recipient records pure, We take away these
-     * non-recipient records from the input, and output them at the start of
-     * the extracted envelope segment.
-     */
-    if (type == REC_TYPE_FILT) {
-       /* Last instance wins. */
-       if (strchr(buf, ':') == 0) {
-           msg_warn("%s: ignoring invalid content filter: %.100s",
-                    state->queue_id, buf);
-           return;
-       }
-       if (state->filter)
-           myfree(state->filter);
-       state->filter = mystrdup(buf);
-       return;
-    }
-    if (type == REC_TYPE_RDR) {
-       /* Last instance wins. */
-       if (strchr(buf, '@') == 0) {
-           msg_warn("%s: ignoring invalid redirect address: %.100s",
-                    state->queue_id, buf);
-           return;
-       }
-       if (state->redirect)
-           myfree(state->redirect);
-       state->redirect = mystrdup(buf);
-       return;
-    }
-
-    /*
-     * The following records must not appear after recipient records. We
-     * force the warning record before the sender record so we know when
-     * (not) to emit a warning record. A warning or size record may already
-     * be present when mail is requeued with "postsuper -r".
-     */
-    if (type != REC_TYPE_MESG && (state->flags & CLEANUP_FLAG_INRCPT) != 0) {
-       msg_warn("%s: ignoring %s record after initial envelope recipients",
-                state->queue_id, rec_type_name(type));
-       return;
-    }
+    if (type != REC_TYPE_MESG && (state->flags & CLEANUP_FLAG_INRCPT))
+       /* Tell qmgr that recipients are mixed with other information. */
+       state->qmgr_opts |= QMGR_READ_FLAG_MIXED_RCPT_OTHER;
     if (type == REC_TYPE_SIZE)
        /* Use our own SIZE record instead. */
        return;
@@ -243,45 +245,18 @@ static void cleanup_envelope_process(CLEANUP_STATE *state, int type,
            state->errs |= CLEANUP_STAT_BAD;
            return;
        }
-       /* Kluge to force REC_TYPE_WARN before recipients. */
-       if (state->warn_seen == 0 && var_delay_warn_time > 0) {
-           cleanup_out_format(state, REC_TYPE_WARN, REC_TYPE_WARN_FORMAT,
-                              (long) var_delay_warn_time);
-           state->warn_seen = 1;
-       }
        cleanup_addr_sender(state, buf);
        return;
     }
     if (type == REC_TYPE_WARN) {
        /* First instance wins. */
-       if (state->warn_seen == 0) {
-           if (atoi(buf) < 0) {
-               msg_warn("%s: message rejected: bad warning time: %.100s",
-                        state->queue_id, buf);
-               state->errs |= CLEANUP_STAT_BAD;
-               return;
-           }
-           state->warn_seen = 1;
-           cleanup_out(state, type, buf, len);
-       }
-       return;
-    }
-    if (type == REC_TYPE_VERP) {
-       /* First instance wins. */
-       if (state->verp_seen == 0) {
-           if ((error_text = verp_delims_verify(buf)) != 0) {
-               msg_warn("%s: message rejected: %s: %.100s",
-                        state->queue_id, error_text, buf);
-               state->errs |= CLEANUP_STAT_BAD;
-               return;
-           }
-           state->verp_seen = 1;
+       if ((state->flags & CLEANUP_FLAG_WARN_SEEN) == 0) {
+           state->flags |= CLEANUP_FLAG_WARN_SEEN;
            cleanup_out(state, type, buf, len);
        }
        return;
     }
     if (type == REC_TYPE_ATTR) {
-       /* Pass through. Last instance wins. */
        char   *sbuf;
 
        if (state->attr->used >= var_qattr_count_limit) {
@@ -304,31 +279,9 @@ static void cleanup_envelope_process(CLEANUP_STATE *state, int type,
        return;
     }
     if (type != REC_TYPE_MESG) {
-       /* Any other allowed record type. Pass through. */
        cleanup_out(state, type, buf, len);
        return;
     }
-
-    /*
-     * On the transition from initial envelope segment to content segment, do
-     * some sanity checks.
-     * 
-     * XXX If senders can be specified in the extracted envelope segment (this
-     * could reduce qmqpd's memory requirements), then we need to move the
-     * VERP test there, too.
-     */
-    if (state->sender == 0 || state->time == 0) {
-       msg_warn("%s: message rejected: missing sender or time envelope record",
-                state->queue_id);
-       state->errs |= CLEANUP_STAT_BAD;
-       return;
-    }
-    if (state->verp_seen && (state->sender == 0 || *state->sender == 0)) {
-       msg_warn("%s: message rejected: VERP request with no or null sender",
-                state->queue_id);
-       state->errs |= CLEANUP_STAT_BAD;
-       return;
-    }
-    state->flags &= ~CLEANUP_FLAG_INRCPT;
     state->action = cleanup_message;
+    state->flags &= ~CLEANUP_FLAG_INRCPT;
 }
index d66eb65d3c15d7ba4d83670256e3c711e96f0867..e072e86b6c0927e506cc55175738e318961f16ce 100644 (file)
 /*     int     len;
 /* DESCRIPTION
 /*     This module processes message records with information extracted
-/*     from the initial message envelope or from the message content, or
-/*     with recipients that are stored after the message content. It
-/*     updates recipient records, and writes extracted information records
-/*     to the output.
+/*     from message content, or with recipients that are stored after the
+/*     message content. It updates recipient records, and writes extracted
+/*     information records to the output.
 /*
 /*     Arguments:
 /* .IP state
@@ -58,6 +57,7 @@
 /* Global library. */
 
 #include <cleanup_user.h>
+#include <qmgr_user.h>
 #include <record.h>
 #include <rec_type.h>
 #include <mail_params.h>
@@ -70,8 +70,7 @@
 
 #define STR(x) vstring_str(x)
 
-static void cleanup_extracted_non_rcpt(CLEANUP_STATE *, int, const char *, int);
-static void cleanup_extracted_rcpt(CLEANUP_STATE *, int, const char *, int);
+static void cleanup_extracted_process(CLEANUP_STATE *, int, const char *, int);
 
 /* cleanup_extracted - initialize extracted segment */
 
@@ -87,16 +86,21 @@ void    cleanup_extracted(CLEANUP_STATE *state, int type,
     /*
      * Pass control to the actual envelope processing routine.
      */
-    state->action = cleanup_extracted_non_rcpt;
-    cleanup_extracted_non_rcpt(state, type, buf, len);
+    state->action = cleanup_extracted_process;
+    cleanup_extracted_process(state, type, buf, len);
 }
 
-/* cleanup_extracted_non_rcpt - process non-recipient records */
+/* cleanup_extracted_process - process one extracted envelope record */
 
-void    cleanup_extracted_non_rcpt(CLEANUP_STATE *state, int type,
-                                          const char *buf, int len)
+void    cleanup_extracted_process(CLEANUP_STATE *state, int type,
+                                         const char *buf, int len)
 {
+    const char myname[] = "cleanup_extracted_process";
     const char *encoding;
+    const char generated_by_cleanup[] = {
+       REC_TYPE_FILT, REC_TYPE_RDR, REC_TYPE_ATTR,
+       REC_TYPE_RRTO, REC_TYPE_ERTO, 0,
+    };
 
     if (msg_verbose)
        msg_info("extracted envelope %c %.*s", type, len, buf);
@@ -110,99 +114,31 @@ void    cleanup_extracted_non_rcpt(CLEANUP_STATE *state, int type,
     }
 
     /*
-     * The following records are taken away from the initial envelope segment
-     * and may be overruled by information from header/body_checks; then they
-     * are emitted at the start of the extracted envelope segment.
-     * 
-     * If we encounter these records here, then the message was subjected to
-     * "postsuper -r" and we can ignore these records if we already have
-     * information from header/body_checks.
+     * At the end of the non-recipient records, emit optional information
+     * from header/body content.
      */
-    if (type == REC_TYPE_FILT) {
-       /* Our own header/body_checks information wins. */
-       if (state->filter == 0)
-           state->filter = mystrdup(buf);
-       return;
-    }
-    if (type == REC_TYPE_RDR) {
-       /* Our own header/body_checks information wins. */
-       if (state->redirect == 0)
-           state->redirect = mystrdup(buf);
-       return;
+    if ((state->flags & CLEANUP_FLAG_INRCPT) == 0
+       && strchr(REC_TYPE_EXT_RECIPIENT, type) != 0) {
+       if (state->filter != 0)
+           cleanup_out_string(state, REC_TYPE_FILT, state->filter);
+       if (state->redirect != 0)
+           cleanup_out_string(state, REC_TYPE_RDR, state->redirect);
+       if ((encoding = nvtable_find(state->attr, MAIL_ATTR_ENCODING)) != 0)
+           cleanup_out_format(state, REC_TYPE_ATTR, "%s=%s",
+                              MAIL_ATTR_ENCODING, encoding);
+       state->flags |= CLEANUP_FLAG_INRCPT;
     }
 
     /*
-     * Ignore records that the cleanup server extracts from message headers.
-     * These records may appear in "postsuper -r" email.
+     * Regular extracted envelope record processing.
      */
-    if (type == REC_TYPE_RRTO)
-       /* Use our own headers extracted return address. */
-       return;
-    if (type == REC_TYPE_ERTO)
-       /* Use our own headers extracted error address. */
-       return;
-    if (type == REC_TYPE_ATTR)
-       /* Use our own headers extracted content encoding. */
-       return;
-
-    if (type != REC_TYPE_END && type != REC_TYPE_FROM
-       && type != REC_TYPE_DONE && type != REC_TYPE_ORCP) {
-       /* Any other allowed non-recipient record. Pass through. */
-       cleanup_out(state, type, buf, len);
-       return;
-    }
-
-    /*
-     * At the end of the non-recipient record section, emit optional
-     * information from header/body_checks actions, from the start of the
-     * extracted envelope, or from the initial envelope.
-     */
-    if (state->filter != 0)
-       cleanup_out_string(state, REC_TYPE_FILT, state->filter);
-
-    if (state->redirect != 0)
-       cleanup_out_string(state, REC_TYPE_RDR, state->redirect);
-
-    if ((encoding = nvtable_find(state->attr, MAIL_ATTR_ENCODING)) != 0)
-       cleanup_out_format(state, REC_TYPE_ATTR, "%s=%s",
-                          MAIL_ATTR_ENCODING, encoding);
-
-    /*
-     * Terminate the non-recipient records with the Return-Receipt-To and
-     * Errors-To records. The queue manager relies on this information.
-     */
-    cleanup_out_string(state, REC_TYPE_RRTO, state->return_receipt ?
-                      state->return_receipt : "");
-
-    cleanup_out_string(state, REC_TYPE_ERTO, state->errors_to ?
-                      state->errors_to : state->sender);
-
-    /*
-     * Pass control to the routine that processes the recipient portion of
-     * the extracted segment.
-     */
-    state->action = cleanup_extracted_rcpt;
-    cleanup_extracted_rcpt(state, type, buf, len);
-}
-
-/* cleanup_extracted_rcpt - process recipients in extracted segment */
-
-static void cleanup_extracted_rcpt(CLEANUP_STATE *state, int type,
-                                          const char *buf, int len)
-{
-    char   *myname = "cleanup_extracted_rcpt";
-
-    if (msg_verbose)
-       msg_info("extracted envelope %c %.*s", type, len, buf);
-
-    if (strchr(REC_TYPE_EXTRACT, type) == 0) {
-       msg_warn("%s: message rejected: "
-                "unexpected record type %d in extracted envelope",
-                state->queue_id, type);
-       state->errs |= CLEANUP_STAT_BAD;
-       return;
-    }
     if (type == REC_TYPE_RCPT) {
+       if (state->sender == 0) {               /* protect showq */
+           msg_warn("%s: message rejected: envelope recipient precedes sender",
+                    state->queue_id);
+           state->errs |= CLEANUP_STAT_BAD;
+           return;
+       }
        if (state->orig_rcpt == 0)
            state->orig_rcpt = mystrdup(buf);
        cleanup_addr_recipient(state, buf);
@@ -219,7 +155,7 @@ static void cleanup_extracted_rcpt(CLEANUP_STATE *state, int type,
     }
     if (state->orig_rcpt != 0) {
        /* REC_TYPE_ORCP must be followed by REC_TYPE_RCPT or REC_TYPE DONE. */
-       msg_warn("%s: out-of-order original recipient record <%.200s>",
+       msg_warn("%s: ignoring out-of-order original recipient record <%.200s>",
                 state->queue_id, buf);
        myfree(state->orig_rcpt);
        state->orig_rcpt = 0;
@@ -228,11 +164,20 @@ static void cleanup_extracted_rcpt(CLEANUP_STATE *state, int type,
        state->orig_rcpt = mystrdup(buf);
        return;
     }
+    if (type != REC_TYPE_END && (state->flags & CLEANUP_FLAG_INRCPT))
+       /* Tell qmgr that recipients are mixed with other information. */
+       state->qmgr_opts |= QMGR_READ_FLAG_MIXED_RCPT_OTHER;
+    if (strchr(generated_by_cleanup, type) != 0) {
+       /* Use our own header/body info instead. */
+       return;
+    }
     if (type != REC_TYPE_END) {
-       msg_warn("%s: ignoring %s record after extracted envelope recipients",
-                state->queue_id, rec_type_name(type));
+       /* Pass on other non-recipient record. */
+       cleanup_out(state, type, buf, len);
        return;
     }
+    state->flags &= ~CLEANUP_FLAG_INRCPT;
+    state->flags |= CLEANUP_FLAG_END_SEEN;
 
     /*
      * On the way out, add the optional automatic BCC recipient.
@@ -245,7 +190,6 @@ static void cleanup_extracted_rcpt(CLEANUP_STATE *state, int type,
      * Terminate the extracted segment.
      */
     cleanup_out_string(state, REC_TYPE_END, "");
-    state->end_seen = 1;
 
     /*
      * vstream_fseek() would flush the buffer anyway, but the code just reads
@@ -272,5 +216,6 @@ static void cleanup_extracted_rcpt(CLEANUP_STATE *state, int type,
     cleanup_out_format(state, REC_TYPE_SIZE, REC_TYPE_SIZE_FORMAT,
            (REC_TYPE_SIZE_CAST1) (state->xtra_offset - state->data_offset),
                       (REC_TYPE_SIZE_CAST2) state->data_offset,
-                      (REC_TYPE_SIZE_CAST3) state->rcpt_count);
+                      (REC_TYPE_SIZE_CAST3) state->rcpt_count,
+                      (REC_TYPE_SIZE_CAST4) state->qmgr_opts);
 }
index 81cf66287be97592309e729b54181fbc5787c5a8..c078ea6636a82e1bdb9b5f9deab2558520e95c6f 100644 (file)
@@ -648,8 +648,8 @@ static void cleanup_message_headerbody(CLEANUP_STATE *state, int type,
      * This should never happen.
      */
     else {
-       msg_warn("%s: unexpected record type in message content: %d"
-                ": message rejected", myname, type);
+       msg_warn("%s: message rejected: "
+             "unexpected record type %d in message content", myname, type);
        state->errs |= CLEANUP_STAT_BAD;
     }
 }
@@ -683,7 +683,7 @@ void    cleanup_message(CLEANUP_STATE *state, int type, const char *buf, int len
     int     mime_options;
 
     /*
-     * Write the start-of-content segment marker. 
+     * Write the start-of-content segment marker.
      */
     cleanup_out_string(state, REC_TYPE_MESG, "");
     if ((state->data_offset = vstream_ftell(state->dst)) < 0)
index 845cde7ec323097c428ffc22fee73ca70421a1af..a22a32d6f0984b018747fa163cf1bb127af3e3db 100644 (file)
@@ -71,6 +71,7 @@ CLEANUP_STATE *cleanup_state_alloc(void)
     state->return_receipt = 0;
     state->errors_to = 0;
     state->flags = 0;
+    state->qmgr_opts = 0;
     state->errs = 0;
     state->err_mask = 0;
     state->headers_seen = 0;
@@ -80,9 +81,6 @@ CLEANUP_STATE *cleanup_state_alloc(void)
     state->action = cleanup_envelope;
     state->data_offset = -1;
     state->xtra_offset = -1;
-    state->warn_seen = 0;
-    state->verp_seen = 0;
-    state->end_seen = 0;
     state->rcpt_count = 0;
     state->reason = 0;
     state->attr = nvtable_create(10);
index fb9f9f638f564c15e6571e95c06d5c60aff2fccb..612a03e2ddd895b59f1bc425cf2142ecd2438122 100644 (file)
@@ -63,7 +63,7 @@ HDRS  = been_here.h bounce.h canon_addr.h cleanup_user.h clnt_stream.h \
        mbox_conf.h mbox_open.h abounce.h qmqp_proto.h verp_sender.h \
        match_parent_style.h quote_flags.h mime_state.h header_token.h \
        lex_822.h strip_addr.h virtual8_maps.h hold_message.h verify_clnt.h \
-       trace.h log_adhoc.h verify.h dict_proxy.h mail_dict.h
+       trace.h log_adhoc.h verify.h dict_proxy.h mail_dict.h qmgr_user.h
 TESTSRC        = rec2stream.c stream2rec.c recdump.c
 WARN   = -W -Wformat -Wimplicit -Wmissing-prototypes \
        -Wparentheses -Wstrict-prototypes -Wswitch -Wuninitialized \
index cb94eb6f777cb37e26cb7e8eee65743d33fa085d..b4fc4249e46528840bd86c0688dbea0a7ee431dc 100644 (file)
@@ -12,7 +12,7 @@
 /* .nf
 
  /*
-  * Options.
+  * Client processing options. Flags 16- are reserved for cleanup.h.
   */
 #define CLEANUP_FLAG_NONE      0       /* No special features */
 #define CLEANUP_FLAG_BOUNCE    (1<<0)  /* Bounce bad messages */
 #define CLEANUP_FLAG_DISCARD   (1<<3)  /* Discard message silently */
 #define CLEANUP_FLAG_BCC_OK    (1<<4)  /* Ok to add auto-BCC addresses */
 
- /*
-  * Status.
-  */
-#define CLEANUP_FLAG_INRCPT    (1<<16) /* Expecting recipient records only */
-
  /*
   * These are set on the fly while processing SMTP envelopes or message
   * content.
@@ -36,9 +31,7 @@
  /*
   * Diagnostics.
   */
-
 #define CLEANUP_STAT_OK                0       /* Success. */
-
 #define CLEANUP_STAT_BAD       (1<<0)  /* Internal protocol error */
 #define CLEANUP_STAT_WRITE     (1<<1)  /* Error writing message file */
 #define CLEANUP_STAT_SIZE      (1<<2)  /* Message file too big */
index 3aae7b741c510749c726ff45bd4e064a10eacf88..8154eeaf00afaf6030d5455b413b998cf1c223fa 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      "20030526"
+#define MAIL_RELEASE_DATE      "20030531"
 
 #define VAR_MAIL_VERSION       "mail_version"
 #define DEF_MAIL_VERSION       "2.0.10-" MAIL_RELEASE_DATE
diff --git a/postfix/src/global/qmgr_user.h b/postfix/src/global/qmgr_user.h
new file mode 100644 (file)
index 0000000..6397129
--- /dev/null
@@ -0,0 +1,36 @@
+#ifndef _QMGR_USER_H_INCLUDED_
+#define _QMGR_USER_H_INCLUDED_
+
+/*++
+/* NAME
+/*     qmgr_user 3h
+/* SUMMARY
+/*     qmgr user interface codes
+/* SYNOPSIS
+/*     #include <qmgr_user.h>
+/* DESCRIPTION
+/* .nf
+
+ /*
+  * Queue file read options. Flags 16- are reserved by qmgr.h.
+  */
+#define QMGR_READ_FLAG_NONE            0       /* No special features */
+#define QMGR_READ_FLAG_MIXED_RCPT_OTHER        (1<<0)  /* Mixed recipient/other */
+
+ /*
+  * Backwards compatibility.
+  */
+#define QMGR_READ_FLAG_DEFAULT (QMGR_READ_FLAG_MIXED_RCPT_OTHER)
+
+/* LICENSE
+/* .ad
+/* .fi
+/*     The Secure Mailer license must be distributed with this software.
+/* AUTHOR(S)
+/*     Wietse Venema
+/*     IBM T.J. Watson Research
+/*     P.O. Box 704
+/*     Yorktown Heights, NY 10598, USA
+/*--*/
+
+#endif
index 3f3d10d85469da3a891b0fb633940b3a32eda92e..70aef24c95b38c00881b46228ce8df288e2beaf0 100644 (file)
 
 #define REC_TYPE_END   'E'             /* terminator, required */
 
+ /*
+  * What I expect to see in a "pure recipient" sequence at the end of the
+  * initial or extracted envelope segments, respectively. When a queue file
+  * contains pure recipient sequences only, then the queue manager will not
+  * have to read all the queue file records before starting delivery. This
+  * is often the case with list mail, where such optimization is desirable.
+  */
+#define REC_TYPE_ENV_RECIPIENT "MDRO"
+#define REC_TYPE_EXT_RECIPIENT "EDRO"
+
  /*
   * The types of records that I expect to see while processing different
   * record groups. The first member in each set is the record type that
 
  /*
   * The record at the beginning of the envelope segment specifies the message
-  * content size, data offset, and recipient count. These are fixed-width
-  * fields so they can be updated in place.
+  * content size, data offset, recipient count, and processing flags. These
+  * are fixed-width fields so they can be updated in place. Flags are defined
+  * in cleanup_user.h
   */
-#define REC_TYPE_SIZE_FORMAT   "%15ld %15ld %15ld"     /* size/count format */
+#define REC_TYPE_SIZE_FORMAT   "%15ld %15ld %15ld %15ld"
 #define REC_TYPE_SIZE_CAST1    long
 #define REC_TYPE_SIZE_CAST2    long
 #define REC_TYPE_SIZE_CAST3    long
+#define REC_TYPE_SIZE_CAST4    long
 
  /*
   * The record at the beginning of the message content records specifies the
index c9a01a6f355ef32c3e3a8f3c96c6c26bca130def..c5f6254e7e1d24ee6136511944bb93ff7046a3ab 100644 (file)
@@ -199,6 +199,7 @@ qmgr_message.o: ../../include/verp_sender.h
 qmgr_message.o: ../../include/mail_proto.h
 qmgr_message.o: ../../include/iostuff.h
 qmgr_message.o: ../../include/attr.h
+qmgr_message.o: ../../include/qmgr_user.h
 qmgr_message.o: ../../include/rewrite_clnt.h
 qmgr_message.o: ../../include/resolve_clnt.h
 qmgr_message.o: qmgr.h
index 2f17e595e87ae950665f54979e0a67473260caad..e3fbd9ac0c90bd651a23c5e57d52e5361ff146eb 100644 (file)
@@ -254,6 +254,7 @@ struct QMGR_MESSAGE {
     int     flags;                     /* delivery problems */
     int     qflags;                    /* queuing flags */
     int     tflags;                    /* tracing flags */
+    int     rflags;                    /* queue file read flags */
     VSTREAM *fp;                       /* open queue file or null */
     int     refcount;                  /* queue entries */
     int     single_rcpt;               /* send one rcpt at a time */
@@ -283,6 +284,11 @@ struct QMGR_MESSAGE {
                                         * per transport) */
 };
 
+ /*
+  * Flags 0-15 are reserved for qmgr_user.h.
+  */
+#define QMGR_READ_FLAG_SEEN_ALL_NON_RCPT       (1<<16)
+
 #define QMGR_MESSAGE_LOCKED    ((QMGR_MESSAGE *) 1)
 
 extern int qmgr_message_count;
index 9ca0fcb00ee9c2ae42d07378c2e9dadd41686e56..d252cff69907cf3a5d56ac9aac5d0fd79d3eddd3 100644 (file)
 #include <opened.h>
 #include <verp_sender.h>
 #include <mail_proto.h>
+#include <qmgr_user.h>
 
 /* Client stubs. */
 
@@ -146,6 +147,7 @@ static QMGR_MESSAGE *qmgr_message_create(const char *queue_name,
     message->flags = 0;
     message->qflags = qflags;
     message->tflags = 0;
+    message->rflags = QMGR_READ_FLAG_DEFAULT;
     message->fp = 0;
     message->refcount = 0;
     message->single_rcpt = 0;
@@ -350,6 +352,14 @@ static int qmgr_message_read(QMGR_MESSAGE *message)
      * Fortunately, this poses no major problem on the scheduling algorithm,
      * as the only impact is that the already deferred messages are not
      * chosen by qmgr_job_candidate() as often as they could.
+     * 
+     * On the first open, we must examine all non-recipient records.
+     * 
+     * XXX We know how to skip over large numbers of recipient records in the
+     * initial envelope segment but we haven't yet implemented code to skip
+     * over large numbers of recipient records in the extracted envelope
+     * segment. This is not a problem as long as only "sendmail -t" produces
+     * extracted segment recipients.
      */
     for (;;) {
        if ((curr_offset = vstream_ftell(message->fp)) < 0)
@@ -366,8 +376,10 @@ static int qmgr_message_read(QMGR_MESSAGE *message)
        start = vstring_str(buf);
        if (msg_verbose > 1)
            msg_info("record %c %s", rec_type, start);
-       if (rec_type == REC_TYPE_END)
+       if (rec_type == REC_TYPE_END) {
+           message->rflags |= QMGR_READ_FLAG_SEEN_ALL_NON_RCPT;
            break;
+       }
        if (rec_type == REC_TYPE_RCPT) {
            /* See also below for code setting orig_rcpt. */
            if (message->rcpt_offset == 0) {
@@ -383,10 +395,11 @@ static int qmgr_message_read(QMGR_MESSAGE *message)
                        msg_fatal("vstream_ftell %s: %m",
                                  VSTREAM_PATH(message->fp));
                    /* We already examined all non-recipient records. */
-                   if (message->errors_to)
+                   if (message->rflags & QMGR_READ_FLAG_SEEN_ALL_NON_RCPT)
                        break;
                    /* Examine non-recipient records in extracted segment. */
-                   if (curr_offset < message->data_offset
+                   if ((message->rflags & QMGR_READ_FLAG_MIXED_RCPT_OTHER) == 0
+                       && curr_offset < message->data_offset
                        && vstream_fseek(message->fp, message->data_offset
                                         + message->data_size, SEEK_SET) < 0)
                        msg_fatal("seek file %s: %m", VSTREAM_PATH(message->fp));
@@ -407,7 +420,7 @@ static int qmgr_message_read(QMGR_MESSAGE *message)
        }
        if (orig_rcpt != 0) {
            /* REC_TYPE_ORCP must go before REC_TYPE_RCPT or REC_TYPE DONE. */
-           msg_warn("%s: out-of-order original recipient record <%.200s>",
+           msg_warn("%s: ignoring out-of-order original recipient <%.200s>",
                     message->queue_id, orig_rcpt);
            myfree(orig_rcpt);
            orig_rcpt = 0;
@@ -418,17 +431,24 @@ static int qmgr_message_read(QMGR_MESSAGE *message)
                orig_rcpt = mystrdup(start);
            continue;
        }
-       if (message->errors_to)
+       if (message->rflags & QMGR_READ_FLAG_SEEN_ALL_NON_RCPT)
            /* We already examined all non-recipient records. */
            continue;
        if (rec_type == REC_TYPE_SIZE) {
            if (message->data_offset == 0) {
-               if ((count = sscanf(start, "%ld %ld %d", &message->data_size,
-                     &message->data_offset, &message->rcpt_unread)) == 3) {
+               if ((count = sscanf(start, "%ld %ld %d %d",
+                                &message->data_size, &message->data_offset,
+                          &message->rcpt_unread, &message->rflags)) >= 3) {
                    /* Postfix >= 1.0 (a.k.a. 20010228). */
                    if (message->data_offset <= 0 || message->data_size <= 0) {
-                       msg_warn("invalid size record, file %s",
-                                VSTREAM_PATH(message->fp));
+                       msg_warn("%s: invalid size record: %.100s",
+                                message->queue_id, start);
+                       rec_type = REC_TYPE_ERROR;
+                       break;
+                   }
+                   if (message->rflags & (~0 << 16)) {
+                       msg_warn("%s: invalid flags in size record: %.100s",
+                                message->queue_id, start);
                        rec_type = REC_TYPE_ERROR;
                        break;
                    }
@@ -437,7 +457,8 @@ static int qmgr_message_read(QMGR_MESSAGE *message)
                    qmgr_message_oldstyle_scan(message);
                } else {
                    /* Can't happen. */
-                   msg_warn("%s: weird size record", message->queue_id);
+                   msg_warn("%s: message rejected: weird size record",
+                            message->queue_id);
                    rec_type = REC_TYPE_ERROR;
                    break;
                }
@@ -498,9 +519,6 @@ static int qmgr_message_read(QMGR_MESSAGE *message)
        if (rec_type == REC_TYPE_ERTO) {
            if (message->errors_to == 0)
                message->errors_to = mystrdup(start);
-           /* We already examined all non-recipient records. */
-           if (message->rcpt_offset)
-               break;
            continue;
        }
        if (rec_type == REC_TYPE_RRTO) {
@@ -517,8 +535,11 @@ static int qmgr_message_read(QMGR_MESSAGE *message)
        }
        if (rec_type == REC_TYPE_VERP) {
            if (message->verp_delims == 0) {
-               if (verp_delims_verify(start) != 0) {
-                   msg_warn("%s: bad VERP record content: \"%s\"",
+               if (message->sender == 0 || message->sender[0] == 0) {
+                   msg_warn("%s: ignoring VERP request for null sender",
+                            message->queue_id);
+               } else if (verp_delims_verify(start) != 0) {
+                   msg_warn("%s: ignoring bad VERP request: \"%.100s\"",
                             message->queue_id, start);
                } else {
                    message->single_rcpt = 1;
@@ -534,7 +555,7 @@ static int qmgr_message_read(QMGR_MESSAGE *message)
      */
     if (orig_rcpt != 0) {
        if (rec_type > 0)
-           msg_warn("%s: out-of-order original recipient <%.200s>",
+           msg_warn("%s: ignoring out-of-order original recipient <%.200s>",
                     message->queue_id, orig_rcpt);
        myfree(orig_rcpt);
     }
@@ -567,13 +588,17 @@ static int qmgr_message_read(QMGR_MESSAGE *message)
        message->rcpt_unread = 0;
     }
     if (rec_type <= 0) {
-       msg_warn("%s: missing end record", message->queue_id);
+       msg_warn("%s: message rejected: missing end record",
+                message->queue_id);
     } else if (message->arrival_time == 0) {
-       msg_warn("%s: missing arrival time record", message->queue_id);
+       msg_warn("%s: message rejected: missing arrival time record",
+                message->queue_id);
     } else if (message->sender == 0) {
-       msg_warn("%s: missing sender record", message->queue_id);
+       msg_warn("%s: message rejected: missing sender record",
+                message->queue_id);
     } else if (message->data_offset == 0) {
-       msg_warn("%s: missing size record", message->queue_id);
+       msg_warn("%s: message rejected: missing size record",
+                message->queue_id);
     } else {
        return (0);
     }
@@ -733,7 +758,6 @@ static void qmgr_message_resolve(QMGR_MESSAGE *message)
            }
            rewrite_clnt_internal(REWRITE_CANON, message->redirect_addr,
                                  reply.recipient);
-
            UPDATE(recipient->address, STR(reply.recipient));
            if (qmgr_resolve_one(message, recipient,
                                 recipient->address, &reply) < 0)
index f4a1419c8a29c3358bb04271c9591b4e4b2e4932..06ead63742123b3f913d2f7b9d12e355f49d332f 100644 (file)
@@ -186,6 +186,7 @@ qmgr_message.o: ../../include/verp_sender.h
 qmgr_message.o: ../../include/mail_proto.h
 qmgr_message.o: ../../include/iostuff.h
 qmgr_message.o: ../../include/attr.h
+qmgr_message.o: ../../include/qmgr_user.h
 qmgr_message.o: ../../include/rewrite_clnt.h
 qmgr_message.o: ../../include/resolve_clnt.h
 qmgr_message.o: qmgr.h
index 63a8e2dbaa9ead23c8aa545c84aaa51e7184774c..771882eea5e6fe857d4d0ff6f07e9ec0077c5f6b 100644 (file)
 /* .fi
 /*     In the text below, \fItransport\fR is the first field in a
 /*     \fBmaster.cf\fR entry.
-/* .IP "\fBqmgr_fudge_factor\fR (valid range: 10..100)"
-/*     The percentage of delivery resources that a busy mail system will
-/*     use up for delivery of a large mailing list message.
-/*     With 100%, delivery of one message does not begin before the previous
-/*     message has been delivered. This results in good performance for large
-/*     mailing lists, but results in poor response time for one-to-one mail.
-/*     With less than 100%, response time for one-to-one mail improves,
-/*     but large mailing list delivery performance suffers. In the worst
-/*     case, recipients near the beginning of a large list receive a burst
-/*     of messages immediately, while recipients near the end of that list
-/*     receive that same burst of messages a whole day later.
 /* .IP \fBinitial_destination_concurrency\fR
 /*     Initial per-destination concurrency level for parallel delivery
 /*     to the same destination.
@@ -277,7 +266,6 @@ int     var_dest_con_limit;
 int     var_dest_rcpt_limit;
 char   *var_defer_xports;
 bool    var_allow_min_user;
-int     var_qmgr_fudge;
 int     var_local_rcpt_lim;            /* XXX */
 int     var_local_con_lim;             /* XXX */
 int     var_proc_limit;
@@ -491,7 +479,6 @@ int     main(int argc, char **argv)
        VAR_INIT_DEST_CON, DEF_INIT_DEST_CON, &var_init_dest_concurrency, 1, 0,
        VAR_DEST_CON_LIMIT, DEF_DEST_CON_LIMIT, &var_dest_con_limit, 0, 0,
        VAR_DEST_RCPT_LIMIT, DEF_DEST_RCPT_LIMIT, &var_dest_rcpt_limit, 0, 0,
-       VAR_QMGR_FUDGE, DEF_QMGR_FUDGE, &var_qmgr_fudge, 10, 100,
        VAR_LOCAL_RCPT_LIMIT, DEF_LOCAL_RCPT_LIMIT, &var_local_rcpt_lim, 0, 0,
        VAR_LOCAL_CON_LIMIT, DEF_LOCAL_CON_LIMIT, &var_local_con_lim, 0, 0,
        VAR_PROC_LIMIT, DEF_PROC_LIMIT, &var_proc_limit, 1, 0,
index 67a1adfcedc94013a066959094ba8a2a6891f9e8..6386397143e958d40e7c280db63aa881b6ced7ec 100644 (file)
@@ -216,6 +216,7 @@ struct QMGR_MESSAGE {
     int     flags;                     /* delivery problems */
     int     qflags;                    /* queuing flags */
     int     tflags;                    /* tracing flags */
+    int     rflags;                    /* queue file read flags */
     VSTREAM *fp;                       /* open queue file or null */
     int     refcount;                  /* queue entries */
     int     single_rcpt;               /* send one rcpt at a time */
@@ -238,6 +239,11 @@ struct QMGR_MESSAGE {
     QMGR_RCPT_LIST rcpt_list;          /* complete addresses */
 };
 
+ /*
+  * Flags 0-15 are reserved for qmgr_user.h.
+  */
+#define QMGR_READ_FLAG_SEEN_ALL_NON_RCPT       (1<<16)
+
 #define QMGR_MESSAGE_LOCKED    ((QMGR_MESSAGE *) 1)
 
 extern int qmgr_message_count;
index 3d3f9f461e53f44b24d233d74c36d1de2dc47744..ef07b0b086ac5d441f0b1027bc6fc9c5514dcef5 100644 (file)
@@ -174,10 +174,9 @@ void    qmgr_entry_done(QMGR_ENTRY *entry, int which)
      * today, while people near the end of the list get that same burst of
      * postings a whole day later.
      */
-#define FUDGE(x)       ((x) * (var_qmgr_fudge / 100.0))
     message->refcount--;
     if (message->rcpt_offset > 0
-       && qmgr_recipient_count < FUDGE(var_qmgr_rcpt_limit))
+       && qmgr_recipient_count < var_qmgr_rcpt_limit)
        qmgr_message_realloc(message);
     if (message->refcount == 0)
        qmgr_active_done(message);
index 7ae2839a0498a2f6b5999b1fdd17e0f5944c1f6a..918ea599adef2e5ba45c69d3ad19fba87572df75 100644 (file)
 #include <opened.h>
 #include <verp_sender.h>
 #include <mail_proto.h>
+#include <qmgr_user.h>
 
 /* Client stubs. */
 
@@ -137,6 +138,7 @@ static QMGR_MESSAGE *qmgr_message_create(const char *queue_name,
     message->flags = 0;
     message->qflags = qflags;
     message->tflags = 0;
+    message->rflags = QMGR_READ_FLAG_DEFAULT;
     message->fp = 0;
     message->refcount = 0;
     message->single_rcpt = 0;
@@ -319,6 +321,14 @@ static int qmgr_message_read(QMGR_MESSAGE *message)
      * number of in-core recipients per message would asymptotically approach
      * (global recipient limit)/(active queue size limit), which gives equal
      * delay per recipient rather than equal delay per message.
+     * 
+     * On the first open, we must examine all non-recipient records.
+     * 
+     * XXX We know how to skip over large numbers of recipient records in the
+     * initial envelope segment but we haven't yet implemented code to skip
+     * over large numbers of recipient records in the extracted envelope
+     * segment. This is not a problem as long as only "sendmail -t" produces
+     * extracted segment recipients.
      */
     for (;;) {
        if ((curr_offset = vstream_ftell(message->fp)) < 0)
@@ -335,8 +345,10 @@ static int qmgr_message_read(QMGR_MESSAGE *message)
        start = vstring_str(buf);
        if (msg_verbose > 1)
            msg_info("record %c %s", rec_type, start);
-       if (rec_type == REC_TYPE_END)
+       if (rec_type == REC_TYPE_END) {
+           message->rflags |= QMGR_READ_FLAG_SEEN_ALL_NON_RCPT;
            break;
+       }
        if (rec_type == REC_TYPE_RCPT) {
            /* See also below for code setting orig_rcpt. */
            if (message->rcpt_offset == 0) {
@@ -351,10 +363,11 @@ static int qmgr_message_read(QMGR_MESSAGE *message)
                        msg_fatal("vstream_ftell %s: %m",
                                  VSTREAM_PATH(message->fp));
                    /* We already examined all non-recipient records. */
-                   if (message->errors_to)
+                   if (message->rflags & QMGR_READ_FLAG_SEEN_ALL_NON_RCPT)
                        break;
                    /* Examine non-recipient records in extracted segment. */
-                   if (curr_offset < message->data_offset
+                   if ((message->rflags & QMGR_READ_FLAG_MIXED_RCPT_OTHER) == 0
+                       && curr_offset < message->data_offset
                        && vstream_fseek(message->fp, message->data_offset
                                         + message->data_size, SEEK_SET) < 0)
                        msg_fatal("seek file %s: %m", VSTREAM_PATH(message->fp));
@@ -372,7 +385,7 @@ static int qmgr_message_read(QMGR_MESSAGE *message)
        }
        if (orig_rcpt != 0) {
            /* REC_TYPE_ORCP must go before REC_TYPE_RCPT or REC_TYPE DONE. */
-           msg_warn("%s: out-of-order original recipient record <%.200s>",
+           msg_warn("%s: ignoring out-of-order original recipient <%.200s>",
                     message->queue_id, orig_rcpt);
            myfree(orig_rcpt);
            orig_rcpt = 0;
@@ -383,17 +396,24 @@ static int qmgr_message_read(QMGR_MESSAGE *message)
                orig_rcpt = mystrdup(start);
            continue;
        }
-       if (message->errors_to)
+       if (message->rflags & QMGR_READ_FLAG_SEEN_ALL_NON_RCPT)
            /* We already examined all non-recipient records. */
            continue;
        if (rec_type == REC_TYPE_SIZE) {
            if (message->data_offset == 0) {
-               if ((count = sscanf(start, "%ld %ld %d", &message->data_size,
-                                   &message->data_offset, &nrcpt)) == 3) {
+               if ((count = sscanf(start, "%ld %ld %d %d",
+                                &message->data_size, &message->data_offset,
+                                   &nrcpt, &message->rflags)) >= 3) {
                    /* Postfix >= 1.0 (a.k.a. 20010228). */
                    if (message->data_offset <= 0 || message->data_size <= 0) {
-                       msg_warn("invalid size record, file %s",
-                                VSTREAM_PATH(message->fp));
+                       msg_warn("%s: invalid size record: %.100s",
+                                message->queue_id, start);
+                       rec_type = REC_TYPE_ERROR;
+                       break;
+                   }
+                   if (message->rflags & (~0 << 16)) {
+                       msg_warn("%s: invalid flags in size record: %.100s",
+                                message->queue_id, start);
                        rec_type = REC_TYPE_ERROR;
                        break;
                    }
@@ -402,7 +422,8 @@ static int qmgr_message_read(QMGR_MESSAGE *message)
                    qmgr_message_oldstyle_scan(message);
                } else {
                    /* Can't happen. */
-                   msg_warn("%s: weird size record", message->queue_id);
+                   msg_warn("%s: message rejected: weird size record",
+                            message->queue_id);
                    rec_type = REC_TYPE_ERROR;
                    break;
                }
@@ -463,9 +484,6 @@ static int qmgr_message_read(QMGR_MESSAGE *message)
        if (rec_type == REC_TYPE_ERTO) {
            if (message->errors_to == 0)
                message->errors_to = mystrdup(start);
-           /* We already examined all non-recipient records. */
-           if (message->rcpt_offset)
-               break;
            continue;
        }
        if (rec_type == REC_TYPE_RRTO) {
@@ -482,8 +500,11 @@ static int qmgr_message_read(QMGR_MESSAGE *message)
        }
        if (rec_type == REC_TYPE_VERP) {
            if (message->verp_delims == 0) {
-               if (verp_delims_verify(start) != 0) {
-                   msg_warn("%s: bad VERP record content: \"%s\"",
+               if (message->sender == 0 || message->sender[0] == 0) {
+                   msg_warn("%s: ignoring VERP request for null sender",
+                            message->queue_id);
+               } else if (verp_delims_verify(start) != 0) {
+                   msg_warn("%s: ignoring bad VERP request: \"%.100s\"",
                             message->queue_id, start);
                } else {
                    message->single_rcpt = 1;
@@ -499,7 +520,7 @@ static int qmgr_message_read(QMGR_MESSAGE *message)
      */
     if (orig_rcpt != 0) {
        if (rec_type > 0)
-           msg_warn("%s: out-of-order original recipient <%.200s>",
+           msg_warn("%s: ignoring out-of-order original recipient <%.200s>",
                     message->queue_id, orig_rcpt);
        myfree(orig_rcpt);
     }
@@ -526,13 +547,17 @@ static int qmgr_message_read(QMGR_MESSAGE *message)
      * including the queue file end marker.
      */
     if (rec_type <= 0) {
-       msg_warn("%s: missing end record", message->queue_id);
+       msg_warn("%s: message rejected: missing end record",
+                message->queue_id);
     } else if (message->arrival_time == 0) {
-       msg_warn("%s: missing arrival time record", message->queue_id);
+       msg_warn("%s: message rejected: missing arrival time record",
+                message->queue_id);
     } else if (message->sender == 0) {
-       msg_warn("%s: missing sender record", message->queue_id);
+       msg_warn("%s: message rejected: missing sender record",
+                message->queue_id);
     } else if (message->data_offset == 0) {
-       msg_warn("%s: missing size record", message->queue_id);
+       msg_warn("%s: message rejected: missing size record",
+                message->queue_id);
     } else {
        return (0);
     }
index 34441615d045cba3f3139abee6ad6c0bb9088daa..91a864aee41ca2f74dd83e2c7673b3f656824213 100644 (file)
@@ -639,7 +639,9 @@ static char *extract_addr(SMTPD_STATE *state, SMTPD_TOKEN *arg,
     int     naddr;
     int     non_addr;
     char   *err = 0;
-    char   *junk;
+    char   *junk = 0;
+    char   *text;
+    char   *colon;
 
     /*
      * Special case.
@@ -663,11 +665,19 @@ static char *extract_addr(SMTPD_STATE *state, SMTPD_TOKEN *arg,
        msg_info("%s: input: %s", myname, STR(arg->vstrval));
     if (STR(arg->vstrval)[0] == '<'
        && STR(arg->vstrval)[LEN(arg->vstrval) - 1] == '>') {
-       junk = mystrndup(STR(arg->vstrval) + 1, LEN(arg->vstrval) - 2);
-       tree = tok822_parse(junk);
-       myfree(junk);
+       junk = text = mystrndup(STR(arg->vstrval) + 1, LEN(arg->vstrval) - 2);
     } else
-       tree = tok822_parse(STR(arg->vstrval));
+       text = STR(arg->vstrval);
+
+    /*
+     * Truncate deprecated route address form.
+     */
+    if (*text == '@' && (colon = strchr(text, ':')) != 0)
+       text = colon + 1;
+    tree = tok822_parse(text);
+
+    if (junk)
+       myfree(junk);
 
     /*
      * Find trouble.
@@ -710,7 +720,7 @@ static char *extract_addr(SMTPD_STATE *state, SMTPD_TOKEN *arg,
      * Report trouble. Log a warning only if we are going to sleep+reject so
      * that attackers can't flood our logfiles.
      */
-    if (arg->strval[0] == 0 && !allow_empty_addr) {
+    if ((arg->strval[0] == 0 && !allow_empty_addr) || arg->strval[0] == '@') {
        msg_warn("Illegal address syntax from %s in %s command: %s",
                 state->namaddr, state->where, STR(arg->vstrval));
        err = "501 Bad address syntax";
@@ -904,14 +914,6 @@ static void mail_reset(SMTPD_STATE *state)
        smtpd_sasl_mail_reset(state);
 #endif
     state->discard = 0;
-    if (state->filter) {
-       myfree(state->filter);
-       state->filter = 0;
-    }
-    if (state->redirect) {
-       myfree(state->redirect);
-       state->redirect = 0;
-    }
 }
 
 /* rcpt_cmd - process RCPT TO command */
@@ -1104,32 +1106,24 @@ static int data_cmd(SMTPD_STATE *state, int argc, SMTPD_TOKEN *unused_argv)
     }
 
     /*
-     * Send the end-of-content marker, then do some post-message checks
-and send the end-of-file marker.
+     * Send the end-of-segment markers.
      */
-    if (state->err == CLEANUP_STAT_OK) {
-       rec_fputs(state->cleanup, REC_TYPE_XTRA, "");
-       err = smtpd_check_dot(state);
-       if (rec_fputs(state->cleanup, REC_TYPE_END, "") < 0
+    if (state->err == CLEANUP_STAT_OK)
+       if (rec_fputs(state->cleanup, REC_TYPE_XTRA, "") < 0
+           || rec_fputs(state->cleanup, REC_TYPE_END, "") < 0
            || vstream_fflush(state->cleanup))
            state->err = CLEANUP_STAT_WRITE;
-    }
 
     /*
      * Finish the queue file or finish the cleanup conversation.
      */
-    if (state->err == 0 && err == 0)
+    if (state->err == 0)
        state->err = mail_stream_finish(state->dest, why = vstring_alloc(10));
     else
        mail_stream_cleanup(state->dest);
     state->dest = 0;
     state->cleanup = 0;
 
-    if (err != 0) {
-       smtpd_chat_reply(state, "%s", err);
-       return (-1);
-    }
-
     /*
      * Handle any errors. One message may suffer from multiple errors, so
      * complain only about the most severe error. Forgive any previous client
@@ -1484,7 +1478,8 @@ static void smtpd_proto(SMTPD_STATE *state)
        break;
 
     case 0:
-       if (var_smtpd_delay_reject == 0
+       if (SMTPD_STAND_ALONE(state) == 0
+           && var_smtpd_delay_reject == 0
            && (state->access_denied = smtpd_check_client(state)) != 0) {
            smtpd_chat_reply(state, "%s", state->access_denied);
        } else {
index faaeefe89260e9c28edf481ea63fe5cd339050f5..334fe749a7acd9f1da030ef54d226234e4cf5d2c 100644 (file)
@@ -99,8 +99,6 @@ typedef struct SMTPD_STATE {
     int     session_discard;           /* per-session discard_action */
     char   *session_filter;            /* per-session filter action */
     char   *session_redirect;          /* per-session redirect action */
-    char   *filter;                    /* per-message filter action */
-    char   *redirect;                  /* per-message redirect action */
 } SMTPD_STATE;
 
 extern void smtpd_state_init(SMTPD_STATE *, VSTREAM *);
index 8773d06166ac5ec066633797798779981fd0d4e0..fc14ab1750958828938b37c7544ed04e83022e15 100644 (file)
@@ -1805,7 +1805,9 @@ static int check_table_result(SMTPD_STATE *state, const char *table,
                    || STREQ(reply_class, SMTPD_NAME_HELO))) {
                SAFE_STRDUP(state->session_filter, cmd_text);
            } else {
-               SAFE_STRDUP(state->filter, cmd_text);
+#ifndef TEST
+               rec_fprintf(state->dest->stream, REC_TYPE_FILT, "%s", cmd_text);
+#endif
            }
            return (SMTPD_CHECK_DUNNO);
        }
@@ -1859,9 +1861,9 @@ static int check_table_result(SMTPD_STATE *state, const char *table,
            state->session_discard = 1;
        } else {
 #ifndef TEST
-           state->discard = 1;
            rec_fprintf(state->dest->stream, REC_TYPE_FLGS, "%d",
                        CLEANUP_FLAG_DISCARD);
+           state->discard = 1;
 #endif
        }
        return (SMTPD_CHECK_OK);
@@ -1892,7 +1894,9 @@ static int check_table_result(SMTPD_STATE *state, const char *table,
                    || STREQ(reply_class, SMTPD_NAME_HELO))) {
                SAFE_STRDUP(state->session_redirect, cmd_text);
            } else {
-               SAFE_STRDUP(state->redirect, cmd_text);
+#ifndef TEST
+               rec_fprintf(state->dest->stream, REC_TYPE_RDR, "%s", cmd_text);
+#endif
            }
            return (SMTPD_CHECK_DUNNO);
        }
@@ -3126,19 +3130,22 @@ char   *smtpd_check_mail(SMTPD_STATE *state, char *sender)
     /*
      * Actions that were triggered during connect or HELO need to be repeated
      * with each MAIL FROM command.
-     * 
-     * XXX Left-hand side should always be zero. But this may not be the case
-     * during stand-alone testing when commands can execute out of protocol.
      */
     if (var_smtpd_delay_reject == 0) {
-       if( state->session_hold)
-       rec_fprintf(state->dest->stream, REC_TYPE_FLGS, "%d",
-                   CLEANUP_FLAG_HOLD);
-       if( state->session_discard)
-       rec_fprintf(state->dest->stream, REC_TYPE_FLGS, "%d",
-                   CLEANUP_FLAG_DISCARD);
-       SAFE_STRDUP(state->filter, state->session_filter);
-       SAFE_STRDUP(state->redirect, state->session_redirect);
+#ifndef TEST
+       if (state->session_hold)
+           rec_fprintf(state->dest->stream, REC_TYPE_FLGS, "%d",
+                       CLEANUP_FLAG_HOLD);
+       if (state->session_discard)
+           rec_fprintf(state->dest->stream, REC_TYPE_FLGS, "%d",
+                       CLEANUP_FLAG_DISCARD);
+       if (state->session_redirect)
+           rec_fprintf(state->dest->stream, REC_TYPE_RDR, "%s",
+                       state->session_redirect);
+       if (state->session_filter)
+           rec_fprintf(state->dest->stream, REC_TYPE_FILT, "%s",
+                       state->session_filter);
+#endif
     }
 
     /*
@@ -3550,19 +3557,6 @@ char   *smtpd_check_data(SMTPD_STATE *state)
     return (status == SMTPD_CHECK_REJECT ? STR(error_text) : 0);
 }
 
-/* smtpd_check_dot - do stuff after message transfer */
-
-char   *smtpd_check_dot(SMTPD_STATE *state)
-{
-    if (state->redirect)
-       rec_fprintf(state->dest->stream, REC_TYPE_RDR, "%s",
-                   state->redirect);
-    if (state->filter)
-       rec_fprintf(state->dest->stream, REC_TYPE_FILT, "%s",
-                   state->filter);
-    return (0);
-}
-
 #ifdef TEST
 
  /*
index c786073a2cb25895f6885c74f0c6ab6e4d73a79a..20b49f9c0366ec6d429b1c28709a4e8ba982a293 100644 (file)
@@ -185,6 +185,7 @@ extern int opterr;                  /* XXX use <getopt.h> */
 #define USE_STATFS
 #define STATFS_IN_SYS_MOUNT_H
 #define HAS_POSIX_REGEXP
+#define BROKEN_WRITE_SELECT_ON_NON_BLOCKING_PIPE
 #endif
 
  /*