This is the third of several patches to limit the number of address
verification requests in the Postfix mail queue.

This patch ensures that Postfix produces only one address verification
result when a virtual alias expands into multiple addresses.  Multiple
results would invalidate the verify(8) server's estimate of the
number of pending address verification requests. 

There are other reasons to avoid multiple results for one virtual
alias.  Multiple results aren't useful because only the last of
many results is remembered for the virtual alias. That last result
is not representative of the content of the virtual alias.

In other words this patch addresses inefficiency and inaccuracy,
and therefore it belongs in mainstream Postfix regardless of any
problem with the number of pending verification requests.

        Wietse

diff --exclude=man --exclude=html --exclude=README_FILES --exclude=INSTALL 
--exclude=.indent.pro --exclude=Makefile.in -r -cr 
/var/tmp/postfix-2.12-20140406-verify-2/src/cleanup/cleanup.h 
./src/cleanup/cleanup.h
*** /var/tmp/postfix-2.12-20140406-verify-2/src/cleanup/cleanup.h       Sat Nov 
23 19:39:32 2013
--- ./src/cleanup/cleanup.h     Sat Apr 26 17:44:56 2014
***************
*** 62,67 ****
--- 62,68 ----
      char   *return_receipt;           /* return-receipt address */
      char   *errors_to;                        /* errors-to address */
      int     flags;                    /* processing options, status flags */
+     int     tflags;                   /* User- or MTA-requested tracing */
      int     qmgr_opts;                        /* qmgr processing options */
      int     errs;                     /* any badness experienced */
      int     err_mask;                 /* allowed badness */
diff --exclude=man --exclude=html --exclude=README_FILES --exclude=INSTALL 
--exclude=.indent.pro --exclude=Makefile.in -r -cr 
/var/tmp/postfix-2.12-20140406-verify-2/src/cleanup/cleanup_envelope.c 
./src/cleanup/cleanup_envelope.c
*** /var/tmp/postfix-2.12-20140406-verify-2/src/cleanup/cleanup_envelope.c      
Fri Jun  5 21:24:50 2009
--- ./src/cleanup/cleanup_envelope.c    Sat Apr 26 17:46:26 2014
***************
*** 66,71 ****
--- 66,72 ----
  #include <mail_proto.h>
  #include <dsn_mask.h>
  #include <rec_attr_map.h>
+ #include <deliver_request.h>
  
  /* Application-specific. */
  
***************
*** 434,439 ****
--- 435,445 ----
        cleanup_out(state, type, buf, len);
        return;
      }
+     if (mapped_type == REC_TYPE_TFLAGS) {
+       if (state->tflags == 0) 
+           state->tflags = DEL_REQ_TRACE_FLAGS(atoi(mapped_buf));
+       return;
+     }
      if (type == REC_TYPE_WARN) {
        /* First instance wins. */
        if ((state->flags & CLEANUP_FLAG_WARN_SEEN) == 0) {
diff --exclude=man --exclude=html --exclude=README_FILES --exclude=INSTALL 
--exclude=.indent.pro --exclude=Makefile.in -r -cr 
/var/tmp/postfix-2.12-20140406-verify-2/src/cleanup/cleanup_out_recipient.c 
./src/cleanup/cleanup_out_recipient.c
*** /var/tmp/postfix-2.12-20140406-verify-2/src/cleanup/cleanup_out_recipient.c 
Sun May 20 12:29:53 2007
--- ./src/cleanup/cleanup_out_recipient.c       Sat Apr 26 19:59:55 2014
***************
*** 76,81 ****
--- 76,82 ----
  #include <recipient_list.h>
  #include <dsn.h>
  #include <trace.h>
+ #include <verify.h>
  #include <mail_queue.h>                       /* cleanup_trace_path */
  #include <mail_proto.h>
  #include <msg_stats.h>
***************
*** 104,109 ****
--- 105,124 ----
      }
  }
  
+ /* cleanup_verify_append - update verify daemon */
+ 
+ static void cleanup_verify_append(CLEANUP_STATE *state, RECIPIENT *rcpt,
+                                         DSN *dsn, int verify_status)
+ {
+     MSG_STATS stats;
+ 
+     if (verify_append(state->queue_id, CLEANUP_MSG_STATS(&stats, state),
+                     rcpt, "none", dsn, verify_status) != 0) {
+       msg_warn("%s: verify service update error", state->queue_id);
+       state->errs |= CLEANUP_STAT_WRITE;
+     }
+ }
+ 
  /* cleanup_out_recipient - envelope recipient output filter */
  
  void    cleanup_out_recipient(CLEANUP_STATE *state,
***************
*** 193,198 ****
--- 208,216 ----
       * recipient information, also ignore differences in DSN attributes. We
       * do, however, keep the DSN attributes of the recipient that survives
       * duplicate elimination.
+      * 
+      * Avoid multiple address verification results per request, because that
+      * would invalidate the verify(8) server's pending request estimate.
       */
      else {
        RECIPIENT rcpt;
***************
*** 200,205 ****
--- 218,231 ----
  
        argv = cleanup_map1n_internal(state, recip, cleanup_virt_alias_maps,
                                  cleanup_ext_prop_mask & EXT_PROP_VIRTUAL);
+       if (argv->argc > 1 && (state->tflags & DEL_REQ_FLAG_MTA_VRFY)) {
+           (void) DSN_SIMPLE(&dsn, "2.0.0", "aliased to multiple recipients");
+           dsn.action = "deliverable";
+           RECIPIENT_ASSIGN(&rcpt, 0, dsn_orcpt, dsn_notify, orcpt, recip);
+           cleanup_verify_append(state, &rcpt, &dsn, DEL_RCPT_STAT_OK);
+           argv_free(argv);
+           return;
+       }
        if ((dsn_notify & DSN_NOTIFY_SUCCESS)
            && (argv->argc > 1 || strcmp(recip, argv->argv[0]) != 0)) {
            (void) DSN_SIMPLE(&dsn, "2.0.0", "alias expanded");
diff --exclude=man --exclude=html --exclude=README_FILES --exclude=INSTALL 
--exclude=.indent.pro --exclude=Makefile.in -r -cr 
/var/tmp/postfix-2.12-20140406-verify-2/src/cleanup/cleanup_state.c 
./src/cleanup/cleanup_state.c
*** /var/tmp/postfix-2.12-20140406-verify-2/src/cleanup/cleanup_state.c Sat Nov 
23 19:37:19 2013
--- ./src/cleanup/cleanup_state.c       Sat Apr 26 17:45:10 2014
***************
*** 79,84 ****
--- 79,85 ----
      state->return_receipt = 0;
      state->errors_to = 0;
      state->flags = 0;
+     state->tflags = 0;
      state->qmgr_opts = 0;
      state->errs = 0;
      state->err_mask = 0;
diff --exclude=man --exclude=html --exclude=README_FILES --exclude=INSTALL 
--exclude=.indent.pro --exclude=Makefile.in -r -cr 
/var/tmp/postfix-2.12-20140406-verify-2/src/global/post_mail.c 
./src/global/post_mail.c
*** /var/tmp/postfix-2.12-20140406-verify-2/src/global/post_mail.c      Mon Feb 
12 15:34:48 2007
--- ./src/global/post_mail.c    Sat Apr 26 20:13:33 2014
***************
*** 51,56 ****
--- 51,61 ----
  /*
  /*    int     post_mail_fclose(stream)
  /*    VSTREAM *STREAM;
+ /*
+ /*    void    post_mail_fclose_async(stream, notify, context)
+ /*    VSTREAM *stream;
+ /*    void    (*notify)(int status, void *context);
+ /*    void    *context;
  /* DESCRIPTION
  /*    This module provides a convenient interface for the most
  /*    common case of sending one message to one recipient. It
***************
*** 88,93 ****
--- 93,103 ----
  /*
  /*    post_mail_fclose() completes the posting of a message.
  /*
+ /*    post_mail_fclose_async() completes the posting of a message
+ /*    and upon completion invokes the caller-specified notify
+ /*    routine, with the cleanup status and caller-specified context
+ /*    as arguments.
+ /*
  /*    Arguments:
  /* .IP sender
  /*    The sender envelope address. It is up to the application
***************
*** 179,184 ****
--- 189,204 ----
      VSTRING *queue_id;
  } POST_MAIL_STATE;
  
+  /*
+   * Call-back state for asynchronous close requests.
+   */
+ typedef struct {
+     int     status;
+     VSTREAM *stream;
+     POST_MAIL_FCLOSE_NOTIFY notify;
+     void   *context;
+ } POST_MAIL_FCLOSE_STATE;
+ 
  /* post_mail_init - initial negotiations */
  
  static void post_mail_init(VSTREAM *stream, const char *sender,
***************
*** 189,201 ****
      VSTRING *id = queue_id ? queue_id : vstring_alloc(100);
      struct timeval now;
      const char *date;
!     int cleanup_flags =
!       int_filt_flags(filter_class) | CLEANUP_FLAG_MASK_INTERNAL;
  
      GETTIMEOFDAY(&now);
      date = mail_date(now.tv_sec);
  
      /*
       * Negotiate with the cleanup service. Give up if we can't agree.
       */
      if (attr_scan(stream, ATTR_FLAG_STRICT,
--- 209,227 ----
      VSTRING *id = queue_id ? queue_id : vstring_alloc(100);
      struct timeval now;
      const char *date;
!     int     cleanup_flags =
!     int_filt_flags(filter_class) | CLEANUP_FLAG_MASK_INTERNAL;
  
      GETTIMEOFDAY(&now);
      date = mail_date(now.tv_sec);
  
      /*
+      * Don't flush buffers while sending the initial message records.
+      */
+     vstream_control(stream, VSTREAM_CTL_BUFSIZE, 2 * VSTREAM_BUFSIZE,
+                   VSTREAM_CTL_END);
+ 
+     /*
       * Negotiate with the cleanup service. Give up if we can't agree.
       */
      if (attr_scan(stream, ATTR_FLAG_STRICT,
***************
*** 358,364 ****
       */
      if (stream != 0) {
        event_enable_read(vstream_fileno(stream), post_mail_open_event,
!                          (void *) state);
        event_request_timer(post_mail_open_event, (void *) state,
                            var_daemon_timeout);
      } else {
--- 384,390 ----
       */
      if (stream != 0) {
        event_enable_read(vstream_fileno(stream), post_mail_open_event,
!                         (void *) state);
        event_request_timer(post_mail_open_event, (void *) state,
                            var_daemon_timeout);
      } else {
***************
*** 420,422 ****
--- 446,512 ----
      (void) vstream_fclose(cleanup);
      return (status);
  }
+ 
+ /* post_mail_fclose_event - event handler */
+ 
+ static void post_mail_fclose_event(int event, char *context)
+ {
+     POST_MAIL_FCLOSE_STATE *state = (POST_MAIL_FCLOSE_STATE *) context;
+     int     status = state->status;
+ 
+     if (status == 0) {
+       if (vstream_ferror(state->stream) != 0
+           || attr_scan(state->stream, ATTR_FLAG_MISSING,
+                        ATTR_TYPE_INT, MAIL_ATTR_STATUS, &status,
+                        ATTR_TYPE_END) != 1)
+           status = CLEANUP_STAT_WRITE;
+     }
+     (void) vstream_fclose(state->stream);
+     state->notify(status, state->context);
+     myfree((char *) state);
+ }
+ 
+ /* post_mail_fclose_async - finish posting of message */
+ 
+ void    post_mail_fclose_async(VSTREAM *stream,
+                                void (*notify) (int status, void *context),
+                                      void *context)
+ {
+     POST_MAIL_FCLOSE_STATE *state;
+     int     status = 0;
+ 
+ 
+     /*
+      * Send the message end marker only when there were no errors.
+      */
+     if (vstream_ferror(stream) != 0) {
+       status = CLEANUP_STAT_WRITE;
+     } else {
+       rec_fputs(stream, REC_TYPE_XTRA, "");
+       rec_fputs(stream, REC_TYPE_END, "");
+       if (vstream_fflush(stream))
+           status = CLEANUP_STAT_WRITE;
+     }
+ 
+     /*
+      * Bundle up the suspended state.
+      */
+     state = (POST_MAIL_FCLOSE_STATE *) mymalloc(sizeof(*state));
+     state->status = status;
+     state->stream = stream;
+     state->notify = notify;
+     state->context = context;
+ 
+     /*
+      * To keep interfaces as simple as possible we report all errors via the
+      * same interface as all successes.
+      */
+     if (status == 0) {
+       event_enable_read(vstream_fileno(stream), post_mail_fclose_event,
+                         (void *) state);
+       event_request_timer(post_mail_fclose_event, (void *) state,
+                           var_daemon_timeout);
+     } else {
+       event_request_timer(post_mail_fclose_event, (void *) state, 0);
+     }
+ }
diff --exclude=man --exclude=html --exclude=README_FILES --exclude=INSTALL 
--exclude=.indent.pro --exclude=Makefile.in -r -cr 
/var/tmp/postfix-2.12-20140406-verify-2/src/global/post_mail.h 
./src/global/post_mail.h
*** /var/tmp/postfix-2.12-20140406-verify-2/src/global/post_mail.h      Mon Jul 
10 17:16:00 2006
--- ./src/global/post_mail.h    Sat Apr 26 19:42:39 2014
***************
*** 34,39 ****
--- 34,41 ----
  extern int post_mail_fputs(VSTREAM *, const char *);
  extern int post_mail_buffer(VSTREAM *, const char *, int);
  extern int post_mail_fclose(VSTREAM *);
+ typedef void (*POST_MAIL_FCLOSE_NOTIFY)(int, void *);
+ extern void post_mail_fclose_async(VSTREAM *, POST_MAIL_FCLOSE_NOTIFY, void 
*);
  
  #define POST_MAIL_BUFFER(v, b) \
        post_mail_buffer((v), vstring_str(b), VSTRING_LEN(b))
diff --exclude=man --exclude=html --exclude=README_FILES --exclude=INSTALL 
--exclude=.indent.pro --exclude=Makefile.in -r -cr 
/var/tmp/postfix-2.12-20140406-verify-2/src/global/rec_attr_map.c 
./src/global/rec_attr_map.c
*** /var/tmp/postfix-2.12-20140406-verify-2/src/global/rec_attr_map.c   Mon Mar 
13 18:12:50 2006
--- ./src/global/rec_attr_map.c Sat Apr 26 17:36:16 2014
***************
*** 48,53 ****
--- 48,55 ----
        return (REC_TYPE_DSN_RET);
      } else if (strcmp(attr_name, MAIL_ATTR_CREATE_TIME) == 0) {
        return (REC_TYPE_CTIME);
+     } else if (strcmp(attr_name, MAIL_ATTR_TRACE_FLAGS) == 0) {
+       return (REC_TYPE_TFLAGS);
      } else {
        return (0);
      }
diff --exclude=man --exclude=html --exclude=README_FILES --exclude=INSTALL 
--exclude=.indent.pro --exclude=Makefile.in -r -cr 
/var/tmp/postfix-2.12-20140406-verify-2/src/global/rec_type.h 
./src/global/rec_type.h
*** /var/tmp/postfix-2.12-20140406-verify-2/src/global/rec_type.h       Fri Aug 
24 15:43:51 2012
--- ./src/global/rec_type.h     Sat Apr 26 17:39:05 2014
***************
*** 72,77 ****
--- 72,79 ----
  #define REC_TYPE_DSN_ORCPT    'o'     /* DSN orig rcpt address */
  #define REC_TYPE_DSN_NOTIFY   'n'     /* DSN notify flags */
  
+ #define REC_TYPE_TFLAGS               't'     /* User- or MTA-requested 
tracing */
+ 
  #define REC_TYPE_MILT_COUNT   'm'
  
  #define REC_TYPE_END  'E'             /* terminator, required */
diff --exclude=man --exclude=html --exclude=README_FILES --exclude=INSTALL 
--exclude=.indent.pro --exclude=Makefile.in -r -cr 
/var/tmp/postfix-2.12-20140406-verify-2/src/verify/verify.c 
./src/verify/verify.c
*** /var/tmp/postfix-2.12-20140406-verify-2/src/verify/verify.c Fri Apr 25 
19:48:07 2014
--- ./src/verify/verify.c       Sat Apr 26 19:46:47 2014
***************
*** 477,482 ****
--- 477,493 ----
      vstring_free(text);
  }
  
+ /* verify_post_mail_fclose_action - callback */
+ 
+ static void verify_post_mail_fclose_action(int status, void *context)
+ {
+     char   *addr = context;
+ 
+     if (status == 0)
+       verify_probe_queued(addr);
+     myfree(addr);
+ }
+ 
  /* verify_post_mail_action - callback */
  
  static void verify_post_mail_action(VSTREAM *stream, void *context)
***************
*** 487,497 ****
       * Probe messages need no body content, because they are never delivered,
       * deferred, or bounced.
       */
!     if (stream != 0) {
!       verify_probe_queued(addr);
        myfree(addr);
-       post_mail_fclose(stream);
-     }
  }
  
  /* verify_query_service - query address status */
--- 498,507 ----
       * Probe messages need no body content, because they are never delivered,
       * deferred, or bounced.
       */
!     if (stream != 0)
!       post_mail_fclose_async(stream, verify_post_mail_fclose_action, addr);
!     else
        myfree(addr);
  }
  
  /* verify_query_service - query address status */

Reply via email to