]> git.ipfire.org Git - thirdparty/postfix.git/commitdiff
postfix-2.0.16-20031219
authorWietse Venema <wietse@porcupine.org>
Fri, 19 Dec 2003 05:00:00 +0000 (00:00 -0500)
committerViktor Dukhovni <viktor@dukhovni.org>
Tue, 5 Feb 2013 06:29:21 +0000 (06:29 +0000)
16 files changed:
postfix/conf/sample-auth.cf
postfix/src/global/mail_params.h
postfix/src/global/mail_version.h
postfix/src/global/recipient_list.c
postfix/src/global/recipient_list.h
postfix/src/smtp/Makefile.in
postfix/src/smtp/smtp.c
postfix/src/smtp/smtp.h
postfix/src/smtp/smtp_addr.c
postfix/src/smtp/smtp_addr.h
postfix/src/smtp/smtp_connect.c
postfix/src/smtp/smtp_misc.c [new file with mode: 0644]
postfix/src/smtp/smtp_proto.c
postfix/src/smtp/smtp_state.c
postfix/src/smtp/smtp_trouble.c
postfix/src/util/sys_defs.h

index e44ec0abc4aa06acf63f539ad5a4d023696e1470..83e22aeaf57b80ee6ffc5e8718a9383bac53d268 100644 (file)
@@ -72,11 +72,11 @@ smtpd_sasl_security_options = noanonymous
 # The smtpd_sasl_local_domain parameter specifies the name of the
 # local authentication realm.
 # 
-# By default, the local authentication realm name is the name of the
-# machine.
+# By default, the local authentication realm name is the null string.
 # 
 #smtpd_sasl_local_domain = $mydomain
-smtpd_sasl_local_domain = $myhostname
+#smtpd_sasl_local_domain = $myhostname
+smtpd_sasl_local_domain =
 
 # The smtpd_sasl_exceptions_networks parameter controls what SMTP
 # clients Postfix will not offer AUTH support.
index 8c0f6f1f68d395c99b3cbfbab3256880483181ab..dc503c7cd486b99811a36f052faa08aa32b3453d 100644 (file)
@@ -180,6 +180,15 @@ extern bool var_disable_dns;
 #define DEF_SMTP_HOST_LOOKUP   SMTP_HOST_LOOKUP_DNS
 extern int var_smtp_dns_lookup;
 
+#define SMTP_BACKUP_SESSION    "session"
+#define SMTP_BACKUP_MESSAGE    "message"
+#define SMTP_BACKUP_RECIPIENT  "recipient"
+
+#define VAR_SMTP_BACKUP_MASK   "smtp_backup_on_soft_error"
+#define DEF_SMTP_BACKUP_MASK   SMTP_BACKUP_SESSION \
+                               " " SMTP_BACKUP_MESSAGE \
+                               " " SMTP_BACKUP_RECIPIENT
+
  /*
   * Location of the mail queue directory tree.
   */
index d83a0dda2892e34f87af02670e99e4e4da0b1394..386f333bcd4fd60f6aca264ac2eb8beff2b3ff4d 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      "20031217"
+#define MAIL_RELEASE_DATE      "20031219"
 
 #define VAR_MAIL_VERSION       "mail_version"
 #define DEF_MAIL_VERSION       "2.0.16-" MAIL_RELEASE_DATE
index 92d37f59711829fb62816606851beb7b0e9de670..84e1e1061613ac266db004c2fecf848fdb397537 100644 (file)
@@ -11,6 +11,7 @@
 /*             long    offset;
 /*             char   *orig_addr;
 /*             char   *address;
+/*             int     status;
 /* .in -4
 /*     } RECIPIENT;
 /*
 /*     const char *orig_rcpt;
 /*     const char *recipient;
 /*
+/*     void    recipient_list_truncate(list)
+/*     RECIPIENT_LIST *list;
+/*
 /*     void    recipient_list_free(list)
 /*     RECIPIENT_LIST *list;
 /* DESCRIPTION
 /*     This module maintains lists of recipient structures. Each
 /*     recipient is characterized by a destination address and
 /*     by the queue file offset of its delivery status record.
+/*     The per-recipient status is initialized to zero, and exists
+/*     solely for the convenience of the application. It is not used
+/*     by the recipient_list module itself.
 /*
 /*     recipient_list_init() creates an empty recipient structure list.
 /*     The list argument is initialized such that it can be given to
@@ -44,6 +51,9 @@
 /*     recipient_list_add() adds a recipient to the specified list.
 /*     The recipient address is copied with mystrdup().
 /*
+/*     recipient_list_truncate() truncates the specified list to
+/*     the specified length.
+/*
 /*     recipient_list_free() releases memory for the specified list
 /*     of recipient structures.
 /*
@@ -72,6 +82,7 @@
 /* System library. */
 
 #include <sys_defs.h>
+#include <msg.h>
 
 /* Utility library. */
 
@@ -106,18 +117,30 @@ void    recipient_list_add(RECIPIENT_LIST *list, long offset,
     list->info[list->len].orig_addr = mystrdup(orig_rcpt);
     list->info[list->len].address = mystrdup(rcpt);
     list->info[list->len].offset = offset;
+    list->info[list->len].status = 0;
     list->len++;
 }
 
-/* recipient_list_free - release memory for in-core recipient structure */
+/* recipient_list_truncate - release memory for unused recipient structures */
 
-void    recipient_list_free(RECIPIENT_LIST *list)
+void    recipient_list_truncate(RECIPIENT_LIST *list, int new_len)
 {
     RECIPIENT *rcpt;
 
-    for (rcpt = list->info; rcpt < list->info + list->len; rcpt++) {
+    if (new_len < 0 || new_len > list->len)
+       msg_panic("recipient_list_truncate: bad length %d", new_len);
+
+    for (rcpt = list->info + new_len; rcpt < list->info + list->len; rcpt++) {
        myfree(rcpt->orig_addr);
        myfree(rcpt->address);
     }
+    list->len = new_len;
+}
+
+/* recipient_list_free - release memory for in-core recipient structure */
+
+void    recipient_list_free(RECIPIENT_LIST *list)
+{
+    recipient_list_truncate(list, 0);
     myfree((char *) list->info);
 }
index 0059b71cede94c01454b0edc198a093485e48c1c..b85752b1851f3f49e9e8290ee52108af8783e323 100644 (file)
@@ -21,6 +21,7 @@ typedef struct RECIPIENT {
     long    offset;                    /* REC_TYPE_RCPT byte */
     char   *orig_addr;                 /* null or original recipient */
     char   *address;                   /* complete address */
+    int     status;                    /* Application specific. */
 } RECIPIENT;
 
 typedef struct RECIPIENT_LIST {
@@ -31,6 +32,7 @@ typedef struct RECIPIENT_LIST {
 
 extern void recipient_list_init(RECIPIENT_LIST *);
 extern void recipient_list_add(RECIPIENT_LIST *, long, const char *, const char *);
+extern void recipient_list_truncate(RECIPIENT_LIST *, int);
 extern void recipient_list_free(RECIPIENT_LIST *);
 
 /* LICENSE
index 2ae10116b49fc084adc200d79974ce2afad05e6f..529e8e3372b4ba741f0725148b515d9b880c9db2 100644 (file)
@@ -1,9 +1,9 @@
 SHELL  = /bin/sh
 SRCS   = smtp.c smtp_connect.c smtp_proto.c smtp_chat.c smtp_session.c \
-       smtp_addr.c smtp_trouble.c smtp_state.c \
+       smtp_addr.c smtp_trouble.c smtp_state.c smtp_misc.c \
        smtp_sasl_proto.c smtp_sasl_glue.c
 OBJS   = smtp.o smtp_connect.o smtp_proto.o smtp_chat.o smtp_session.o \
-       smtp_addr.o smtp_trouble.o smtp_state.o \
+       smtp_addr.o smtp_trouble.o smtp_state.o smtp_misc.o \
        smtp_sasl_proto.o smtp_sasl_glue.o
 HDRS   = smtp.h smtp_sasl.h
 TESTSRC        = 
@@ -89,16 +89,12 @@ smtp_addr.o: ../../include/stringops.h
 smtp_addr.o: ../../include/myrand.h
 smtp_addr.o: ../../include/mail_params.h
 smtp_addr.o: ../../include/own_inet_addr.h
-smtp_addr.o: ../../include/deliver_pass.h
-smtp_addr.o: ../../include/deliver_request.h
-smtp_addr.o: ../../include/vstream.h
-smtp_addr.o: ../../include/recipient_list.h
-smtp_addr.o: ../../include/mail_proto.h
-smtp_addr.o: ../../include/iostuff.h
-smtp_addr.o: ../../include/attr.h
 smtp_addr.o: ../../include/dns.h
 smtp_addr.o: smtp.h
+smtp_addr.o: ../../include/vstream.h
 smtp_addr.o: ../../include/argv.h
+smtp_addr.o: ../../include/deliver_request.h
+smtp_addr.o: ../../include/recipient_list.h
 smtp_addr.o: smtp_addr.h
 smtp_chat.o: smtp_chat.c
 smtp_chat.o: ../../include/sys_defs.h
@@ -137,14 +133,29 @@ smtp_connect.o: ../../include/sane_connect.h
 smtp_connect.o: ../../include/mail_params.h
 smtp_connect.o: ../../include/own_inet_addr.h
 smtp_connect.o: ../../include/debug_peer.h
+smtp_connect.o: ../../include/deliver_pass.h
+smtp_connect.o: ../../include/deliver_request.h
+smtp_connect.o: ../../include/recipient_list.h
+smtp_connect.o: ../../include/mail_proto.h
+smtp_connect.o: ../../include/attr.h
 smtp_connect.o: ../../include/mail_error.h
 smtp_connect.o: ../../include/name_mask.h
 smtp_connect.o: ../../include/dns.h
 smtp_connect.o: smtp.h
 smtp_connect.o: ../../include/argv.h
-smtp_connect.o: ../../include/deliver_request.h
-smtp_connect.o: ../../include/recipient_list.h
 smtp_connect.o: smtp_addr.h
+smtp_misc.o: smtp_misc.c
+smtp_misc.o: ../../include/sys_defs.h
+smtp_misc.o: ../../include/msg.h
+smtp_misc.o: ../../include/deliver_request.h
+smtp_misc.o: ../../include/vstring.h
+smtp_misc.o: ../../include/vbuf.h
+smtp_misc.o: ../../include/vstream.h
+smtp_misc.o: ../../include/recipient_list.h
+smtp_misc.o: ../../include/deliver_completed.h
+smtp_misc.o: ../../include/sent.h
+smtp_misc.o: smtp.h
+smtp_misc.o: ../../include/argv.h
 smtp_proto.o: smtp_proto.c
 smtp_proto.o: ../../include/sys_defs.h
 smtp_proto.o: ../../include/msg.h
@@ -162,10 +173,8 @@ smtp_proto.o: ../../include/smtp_stream.h
 smtp_proto.o: ../../include/mail_queue.h
 smtp_proto.o: ../../include/recipient_list.h
 smtp_proto.o: ../../include/deliver_request.h
-smtp_proto.o: ../../include/deliver_completed.h
 smtp_proto.o: ../../include/defer.h
 smtp_proto.o: ../../include/bounce.h
-smtp_proto.o: ../../include/sent.h
 smtp_proto.o: ../../include/record.h
 smtp_proto.o: ../../include/rec_type.h
 smtp_proto.o: ../../include/off_cvt.h
index d39fb17e2c930cdff2ea70bea363dfbeac1bb5f1..364121031afdea9c9299807983c0afebe13609f4 100644 (file)
@@ -310,14 +310,18 @@ int     var_smtp_pix_delay;
 int     var_smtp_line_limit;
 char   *var_smtp_helo_name;
 char   *var_smtp_host_lookup;
+char   *var_smtp_backup_mask;
 bool    var_smtp_quote_821_env;
 bool    var_smtp_defer_mxaddr;
 bool    var_smtp_send_xforward;
 
  /*
-  * Global variables.
+  * Global variables. smtp_errno is set by the address lookup routines and by
+  * the connection management routines.
   */
+int     smtp_errno;
 int     smtp_host_lookup_mask;
+int     smtp_backup_mask;
 
 /* deliver_message - deliver message with extreme prejudice */
 
@@ -392,15 +396,21 @@ static void smtp_service(VSTREAM *client_stream, char *unused_service, char **ar
     }
 }
 
-/* pre_init - pre-jail initialization */
+/* post_init - post-jail initialization */
 
-static void pre_init(char *unused_name, char **unused_argv)
+static void post_init(char *unused_name, char **unused_argv)
 {
     static NAME_MASK lookup_masks[] = {
        SMTP_HOST_LOOKUP_DNS, SMTP_MASK_DNS,
        SMTP_HOST_LOOKUP_NATIVE, SMTP_MASK_NATIVE,
        0,
     };
+    static NAME_MASK backup_masks[] = {
+       SMTP_BACKUP_SESSION, SMTP_BACKUP_SESSION_FAILURE,
+       SMTP_BACKUP_MESSAGE, SMTP_BACKUP_MESSAGE_FAILURE,
+       SMTP_BACKUP_RECIPIENT, SMTP_BACKUP_RECIPIENT_FAILURE,
+       0,
+    };
 
     /*
      * Turn on per-peer debugging.
@@ -420,6 +430,23 @@ static void pre_init(char *unused_name, char **unused_argv)
                 str_name_mask(VAR_SMTP_HOST_LOOKUP, lookup_masks,
                               smtp_host_lookup_mask));
 
+    /*
+     * When to choose a backup host after a temporary failure.
+     */
+    smtp_backup_mask = name_mask(VAR_SMTP_BACKUP_MASK, backup_masks,
+                                var_smtp_backup_mask);
+    if (msg_verbose)
+       msg_info("when to try backup host: %s",
+                str_name_mask(VAR_SMTP_BACKUP_MASK, backup_masks,
+                              smtp_backup_mask));
+
+}
+
+/* pre_init - pre-jail initialization */
+
+static void pre_init(char *unused_name, char **unused_argv)
+{
+
     /*
      * SASL initialization.
      */
@@ -468,6 +495,7 @@ int     main(int argc, char **argv)
        VAR_SMTP_BIND_ADDR, DEF_SMTP_BIND_ADDR, &var_smtp_bind_addr, 0, 0,
        VAR_SMTP_HELO_NAME, DEF_SMTP_HELO_NAME, &var_smtp_helo_name, 1, 0,
        VAR_SMTP_HOST_LOOKUP, DEF_SMTP_HOST_LOOKUP, &var_smtp_host_lookup, 1, 0,
+       VAR_SMTP_BACKUP_MASK, DEF_SMTP_BACKUP_MASK, &var_smtp_backup_mask, 0, 0,
        0,
     };
     static CONFIG_TIME_TABLE time_table[] = {
@@ -510,6 +538,7 @@ int     main(int argc, char **argv)
                       MAIL_SERVER_STR_TABLE, str_table,
                       MAIL_SERVER_BOOL_TABLE, bool_table,
                       MAIL_SERVER_PRE_INIT, pre_init,
+                      MAIL_SERVER_POST_INIT, post_init,
                       MAIL_SERVER_PRE_ACCEPT, pre_accept,
                       MAIL_SERVER_EXIT, pre_exit,
                       0);
index f713f8b4cf5eb1118cbae639cb9078c7da644df2..04337966a74ba759501ed213c62061e045d0414b 100644 (file)
@@ -56,29 +56,53 @@ typedef struct SMTP_STATE {
     int     space_left;                        /* output length control */
     struct MIME_STATE *mime_state;     /* mime state machine */
     int     final_server;              /* final mail server */
-    int     backup_server;             /* relayhost or fallback relay */
 } SMTP_STATE;
 
-#define SMTP_FEATURE_ESMTP     (1<<0)
-#define SMTP_FEATURE_8BITMIME  (1<<1)
-#define SMTP_FEATURE_PIPELINING        (1<<2)
-#define SMTP_FEATURE_SIZE      (1<<3)
-#define SMTP_FEATURE_STARTTLS  (1<<4)
-#define SMTP_FEATURE_AUTH      (1<<5)
-#define SMTP_FEATURE_MAYBEPIX  (1<<6)  /* PIX smtp fixup mode */
-#define SMTP_FEATURE_XFORWARD_NAME (1<<7)
-#define SMTP_FEATURE_XFORWARD_ADDR (1<<8)
-#define SMTP_FEATURE_XFORWARD_PROTO (1<<9)
-#define SMTP_FEATURE_XFORWARD_HELO (1<<10)
+ /*
+  * Server features.
+  */
+#define SMTP_FEATURE_ESMTP             (1<<0)
+#define SMTP_FEATURE_8BITMIME          (1<<1)
+#define SMTP_FEATURE_PIPELINING                (1<<2)
+#define SMTP_FEATURE_SIZE              (1<<3)
+#define SMTP_FEATURE_STARTTLS          (1<<4)
+#define SMTP_FEATURE_AUTH              (1<<5)
+#define SMTP_FEATURE_MAYBEPIX          (1<<6)  /* PIX smtp fixup mode */
+#define SMTP_FEATURE_XFORWARD_NAME     (1<<7)
+#define SMTP_FEATURE_XFORWARD_ADDR     (1<<8)
+#define SMTP_FEATURE_XFORWARD_PROTO    (1<<9)
+#define SMTP_FEATURE_XFORWARD_HELO     (1<<10)
+
+ /*
+  * Application-specific per-recipient status.
+  */
+#define SMTP_RCPT_KEEP 1               /* send to backup host */
+#define SMTP_RCPT_DROP 2               /* remove from list */
 
  /*
   * smtp.c
   */
+extern int smtp_errno;                 /* XXX can we get rid of this? */
+#define SMTP_NONE      0               /* no error */
+#define SMTP_FAIL      1               /* permanent error */
+#define SMTP_RETRY     2               /* temporary error */
+#define SMTP_LOOP      3               /* MX loop */
+
 extern int smtp_host_lookup_mask;      /* host lookup methods to use */
 
 #define SMTP_MASK_DNS          (1<<0)
 #define SMTP_MASK_NATIVE       (1<<1)
 
+ /*
+  * What soft errors qualify for going to a backup host.
+  */
+extern int smtp_backup_mask;           /* when to try backup host */
+
+#define SMTP_BACKUP_SESSION_FAILURE    (1<<0)
+#define SMTP_BACKUP_MESSAGE_FAILURE    (1<<1)
+#define SMTP_BACKUP_RECIPIENT_FAILURE  (1<<2)
+
  /*
   * smtp_session.c
   */
@@ -119,6 +143,12 @@ extern SMTP_RESP *smtp_chat_resp(SMTP_STATE *);
 extern void smtp_chat_reset(SMTP_STATE *);
 extern void smtp_chat_notify(SMTP_STATE *);
 
+ /*
+  * smtp_misc.c.
+  */
+extern void smtp_rcpt_done(SMTP_STATE *, const char *, RECIPIENT *);
+extern int smtp_weed_request(RECIPIENT_LIST *);
+
  /*
   * smtp_trouble.c
   */
@@ -140,14 +170,6 @@ extern VSTRING *smtp_unalias_addr(VSTRING *, const char *);
 extern SMTP_STATE *smtp_state_alloc(void);
 extern void smtp_state_free(SMTP_STATE *);
 
- /*
-  * Status codes. Errors must have negative codes so that they do not
-  * interfere with useful counts of work done.
-  */
-#define SMTP_OK                        0       /* so far, so good */
-#define SMTP_RETRY             (-1)    /* transient error */
-#define SMTP_FAIL              (-2)    /* hard error */
-
 /* LICENSE
 /* .ad
 /* .fi
index 0bf04b827097e0eb682c63be5d982137cca6ee93..da701da673f838ed52808533d3257fc0bc31a8c8 100644 (file)
@@ -6,13 +6,13 @@
 /* SYNOPSIS
 /*     #include "smtp_addr.h"
 /*
-/*     DNS_RR *smtp_domain_addr(state, name)
-/*     SMTP_STATE *state;
+/*     DNS_RR *smtp_domain_addr(name, why)
 /*     char    *name;
+/*     VSTRING *why;
 /*
-/*     DNS_RR *smtp_host_addr(state, name)
-/*     SMTP_STATE *state;
+/*     DNS_RR *smtp_host_addr(name, why)
 /*     char    *name;
+/*     VSTRING *why;
 /* DESCRIPTION
 /*     This module implements Internet address lookups. By default,
 /*     lookups are done via the Internet domain name service (DNS).
 /*     exchanger hosts listed for the named domain. Addresses are
 /*     returned in most-preferred first order. The result is truncated
 /*     so that it contains only hosts that are more preferred than the
-/*     local mail server itself. When the "best MX is local" feature
-/*     is enabled, the local system is allowed to be the best mail
-/*     exchanger, and mail is delivered accordingly. Otherwise,
-/*     mailer loops are treated as an error.
+/*     local mail server itself.
 /*
 /*     When no mail exchanger is listed in the DNS for \fIname\fR, the
 /*     request is passed to smtp_host_addr().
 /*     when DNS lookups are explicitly disabled.
 /*
 /*     All routines either return a DNS_RR pointer, or return a null
-/*     pointer and report any problems via the smtp_trouble(3) module.
+/*     pointer and set the \fIsmtp_errno\fR global variable accordingly:
+/* .IP SMTP_RETRY
+/*     The request failed due to a soft error, and should be retried later.
+/* .IP SMTP_FAIL
+/*     The request attempt failed due to a hard error.
+/* .IP SMTP_LOOP
+/*     The local machine is the best mail exchanger.
+/* .PP
+/*     In addition, a textual description of the problem is made available
+/*     via the \fIwhy\fR argument.
 /* LICENSE
 /* .ad
 /* .fi
@@ -109,7 +115,6 @@ static int h_errno = TRY_AGAIN;
 
 #include <mail_params.h>
 #include <own_inet_addr.h>
-#include <deliver_pass.h>
 
 /* DNS library. */
 
@@ -120,9 +125,6 @@ static int h_errno = TRY_AGAIN;
 #include "smtp.h"
 #include "smtp_addr.h"
 
-#define ERROR_CLASS_RETRY      450
-#define ERROR_CLASS_FAIL       550
-
 /* smtp_print_addr - print address list */
 
 static void smtp_print_addr(char *what, DNS_RR *addr_list)
@@ -146,8 +148,7 @@ static void smtp_print_addr(char *what, DNS_RR *addr_list)
 
 /* smtp_addr_one - address lookup for one host name */
 
-static DNS_RR *smtp_addr_one(DNS_RR *addr_list, char *host, unsigned pref,
-                                    VSTRING *why, int *error_class)
+static DNS_RR *smtp_addr_one(DNS_RR *addr_list, char *host, unsigned pref, VSTRING *why)
 {
     char   *myname = "smtp_addr_one";
     struct in_addr inaddr;
@@ -180,13 +181,13 @@ static DNS_RR *smtp_addr_one(DNS_RR *addr_list, char *host, unsigned pref,
            addr_list = dns_rr_append(addr_list, addr);
            return (addr_list);
        default:
-           *error_class = ERROR_CLASS_RETRY;
+           smtp_errno = SMTP_RETRY;
            return (addr_list);
        case DNS_FAIL:
-           *error_class = ERROR_CLASS_FAIL;
+           smtp_errno = SMTP_FAIL;
            return (addr_list);
        case DNS_NOTFOUND:
-           *error_class = ERROR_CLASS_FAIL;
+           smtp_errno = SMTP_FAIL;
            /* maybe gethostbyname() will succeed */
            break;
        }
@@ -199,13 +200,12 @@ static DNS_RR *smtp_addr_one(DNS_RR *addr_list, char *host, unsigned pref,
        memset((char *) &fixed, 0, sizeof(fixed));
        if ((hp = gethostbyname(host)) == 0) {
            vstring_sprintf(why, "%s: %s", host, HSTRERROR(h_errno));
-           *error_class = (h_errno == TRY_AGAIN ?
-                           ERROR_CLASS_RETRY : ERROR_CLASS_FAIL);
+           smtp_errno = (h_errno == TRY_AGAIN ? SMTP_RETRY : SMTP_FAIL);
        } else if (hp->h_addrtype != AF_INET) {
            vstring_sprintf(why, "%s: host not found", host);
            msg_warn("%s: unknown address family %d for %s",
                     myname, hp->h_addrtype, host);
-           *error_class = ERROR_CLASS_FAIL;
+           smtp_errno = SMTP_FAIL;
        } else {
            while (hp->h_addr_list[0]) {
                addr_list = dns_rr_append(addr_list,
@@ -226,7 +226,7 @@ static DNS_RR *smtp_addr_one(DNS_RR *addr_list, char *host, unsigned pref,
 
 /* smtp_addr_list - address lookup for a list of mail exchangers */
 
-static DNS_RR *smtp_addr_list(DNS_RR *mx_names, VSTRING *why, int *error_class)
+static DNS_RR *smtp_addr_list(DNS_RR *mx_names, VSTRING *why)
 {
     DNS_RR *addr_list = 0;
     DNS_RR *rr;
@@ -236,7 +236,7 @@ static DNS_RR *smtp_addr_list(DNS_RR *mx_names, VSTRING *why, int *error_class)
      * with DNS lookups (except if we're backup MX, and all the better MX
      * hosts can't be found).
      * 
-     * XXX 2821: update error_class (0->FAIL upon unrecoverable lookup error,
+     * XXX 2821: update smtp_errno (0->FAIL upon unrecoverable lookup error,
      * any->RETRY upon temporary lookup error) so that we can correctly
      * handle the case of no resolvable MX host. Currently this is always
      * treated as a soft error. RFC 2821 wants a more precise response.
@@ -244,8 +244,7 @@ static DNS_RR *smtp_addr_list(DNS_RR *mx_names, VSTRING *why, int *error_class)
     for (rr = mx_names; rr; rr = rr->next) {
        if (rr->type != T_MX)
            msg_panic("smtp_addr_list: bad resource type: %d", rr->type);
-       addr_list = smtp_addr_one(addr_list, (char *) rr->data, rr->pref,
-                                 why, error_class);
+       addr_list = smtp_addr_one(addr_list, (char *) rr->data, rr->pref, why);
     }
     return (addr_list);
 }
@@ -328,16 +327,13 @@ static int smtp_compare_pref(DNS_RR *a, DNS_RR *b)
 
 /* smtp_domain_addr - mail exchanger address lookup */
 
-DNS_RR *smtp_domain_addr(SMTP_STATE *state, char *name)
+DNS_RR *smtp_domain_addr(char *name, VSTRING *why)
 {
-    DELIVER_REQUEST *request = state->request;
     DNS_RR *mx_names;
     DNS_RR *addr_list = 0;
     DNS_RR *self = 0;
     unsigned best_pref;
     unsigned best_found;
-    int     error_class;
-    VSTRING *why = vstring_alloc(1);
 
     /*
      * Preferences from DNS use 0..32767, fall-backs use 32768+.
@@ -391,40 +387,26 @@ DNS_RR *smtp_domain_addr(SMTP_STATE *state, char *name)
      * that an IP address is listed only under one hostname. However, looking
      * at hostnames provides a partial solution for MX hosts behind a NAT
      * gateway.
-     * 
-     * Defer host lookup errors if a) there are more mail servers or b) we are
-     * looking up a relayhost or fallback relay.
      */
-#define DEFER_HOST_LOOKUP_ERROR(s) \
-       ((s)->final_server == 0 || (s)->backup_server)
-
     switch (dns_lookup(name, T_MX, 0, &mx_names, (VSTRING *) 0, why)) {
     default:
+       smtp_errno = SMTP_RETRY;
        if (var_ign_mx_lookup_err)
-           addr_list = smtp_host_addr(state, name);
-       else
-           smtp_site_fail(state, ERROR_CLASS_RETRY,
-                          "%s: %s", request->queue_id, vstring_str(why));
+           addr_list = smtp_host_addr(name, why);
        break;
     case DNS_FAIL:
+       smtp_errno = SMTP_FAIL;
        if (var_ign_mx_lookup_err)
-           addr_list = smtp_host_addr(state, name);
-       else {
-           smtp_site_fail(state, DEFER_HOST_LOOKUP_ERROR(state) ?
-                          ERROR_CLASS_RETRY : ERROR_CLASS_FAIL,
-                          "%s: %s", request->queue_id, vstring_str(why));
-       }
+           addr_list = smtp_host_addr(name, why);
        break;
     case DNS_OK:
        mx_names = dns_rr_sort(mx_names, smtp_compare_pref);
        best_pref = (mx_names ? mx_names->pref : IMPOSSIBLE_PREFERENCE);
-       addr_list = smtp_addr_list(mx_names, why, &error_class);
+       addr_list = smtp_addr_list(mx_names, why);
        dns_rr_free(mx_names);
        if (addr_list == 0) {
-           if (var_smtp_defer_mxaddr || DEFER_HOST_LOOKUP_ERROR(state))
-               error_class = ERROR_CLASS_RETRY;
-           smtp_site_fail(state, error_class,
-                          "%s: %s", request->queue_id, vstring_str(why));
+           if (var_smtp_defer_mxaddr)
+               smtp_errno = SMTP_RETRY;
            msg_warn("no MX host for %s has a valid A record", name);
            break;
        }
@@ -435,23 +417,14 @@ DNS_RR *smtp_domain_addr(SMTP_STATE *state, char *name)
            addr_list = smtp_truncate_self(addr_list, self->pref);
            if (addr_list == 0) {
                if (best_pref != best_found) {
-                   smtp_site_fail(state, ERROR_CLASS_RETRY,
-                                  "%s: unable to find primary relay for %s",
-                                  request->queue_id, name);
-               } else if (*var_bestmx_transp != 0) {   /* we're best MX */
-                   state->status =
-                       deliver_pass_all(MAIL_CLASS_PRIVATE, var_bestmx_transp,
-                                        request);
-                   state->final_server = 1;
+                   vstring_sprintf(why, "unable to find primary relay for %s",
+                                   name);
+                   smtp_errno = SMTP_RETRY;
                } else {
-                   msg_warn("%s is best MX host for %s but no local, virtual "
-                        "or remote delivery is configured for that domain",
-                            var_myhostname, request->nexthop);
-                   smtp_site_fail(state, ERROR_CLASS_FAIL,
-                                  "%s: mail for %s loops back to myself",
-                                  request->queue_id, name);
+                   vstring_sprintf(why, "mail for %s loops back to myself",
+                                   name);
+                   smtp_errno = SMTP_LOOP;
                }
-               break;
            }
        }
        if (addr_list && addr_list->next && var_smtp_rand_addr) {
@@ -460,43 +433,31 @@ DNS_RR *smtp_domain_addr(SMTP_STATE *state, char *name)
        }
        break;
     case DNS_NOTFOUND:
-       addr_list = smtp_host_addr(state, name);
+       addr_list = smtp_host_addr(name, why);
        break;
     }
 
     /*
      * Clean up.
      */
-    vstring_free(why);
     return (addr_list);
 }
 
 /* smtp_host_addr - direct host lookup */
 
-DNS_RR *smtp_host_addr(SMTP_STATE *state, char *host)
+DNS_RR *smtp_host_addr(char *host, VSTRING *why)
 {
-    DELIVER_REQUEST *request = state->request;
     DNS_RR *addr_list;
-    int     error_class;
-    VSTRING *why = vstring_alloc(1);
 
     /*
      * If the host is specified by numerical address, just convert the
      * address to internal form. Otherwise, the host is specified by name.
      */
 #define PREF0  0
-    addr_list = smtp_addr_one((DNS_RR *) 0, host, PREF0, why, &error_class);
-    if (addr_list == 0) {
-       if (DEFER_HOST_LOOKUP_ERROR(state))
-           error_class = ERROR_CLASS_RETRY;
-       smtp_site_fail(state, error_class,
-                      "%s: %s", request->queue_id, vstring_str(why));
-    } else {
-       if (addr_list->next && var_smtp_rand_addr)
-           addr_list = dns_rr_shuffle(addr_list);
-       if (msg_verbose)
-           smtp_print_addr(host, addr_list);
-    }
-    vstring_free(why);
+    addr_list = smtp_addr_one((DNS_RR *) 0, host, PREF0, why);
+    if (addr_list && addr_list->next && var_smtp_rand_addr)
+       addr_list = dns_rr_shuffle(addr_list);
+    if (msg_verbose)
+       smtp_print_addr(host, addr_list);
     return (addr_list);
 }
index d9f72833f730b4b4f6b1bb0e225e06159a01799d..d0dabba49bd390f769a22de1b2e7d7c689525c75 100644 (file)
@@ -16,8 +16,8 @@
  /*
   * Internal interfaces.
   */
-extern DNS_RR *smtp_host_addr(SMTP_STATE *state, char *);
-extern DNS_RR *smtp_domain_addr(SMTP_STATE *state, char *);
+extern DNS_RR *smtp_host_addr(char *, VSTRING *);
+extern DNS_RR *smtp_domain_addr(char *, VSTRING *);
 
 /* LICENSE
 /* .ad
index 547f88e4c882505852c7d0019c28967d978107fa..9ed095c838ac869c5d8aa75be9c1107d021c7ae9 100644 (file)
@@ -82,6 +82,7 @@
 #include <mail_params.h>
 #include <own_inet_addr.h>
 #include <debug_peer.h>
+#include <deliver_pass.h>
 #include <mail_error.h>
 
 /* DNS library. */
@@ -95,8 +96,8 @@
 
 /* smtp_connect_addr - connect to explicit address */
 
-static SMTP_SESSION *smtp_connect_addr(SMTP_STATE *state, DNS_RR *addr,
-                                              unsigned port)
+static SMTP_SESSION *smtp_connect_addr(DNS_RR *addr, unsigned port,
+                                              VSTRING *why)
 {
     char   *myname = "smtp_connect_addr";
     struct sockaddr_in sin;
@@ -111,8 +112,11 @@ static SMTP_SESSION *smtp_connect_addr(SMTP_STATE *state, DNS_RR *addr,
     /*
      * Sanity checks.
      */
-    if (addr->data_len > sizeof(sin.sin_addr))
-       msg_panic("%s: unexpected address length %d", myname, addr->data_len);
+    if (addr->data_len > sizeof(sin.sin_addr)) {
+       msg_warn("%s: skip address with length %d", myname, addr->data_len);
+       smtp_errno = SMTP_RETRY;
+       return (0);
+    }
 
     /*
      * Initialize.
@@ -174,8 +178,9 @@ static SMTP_SESSION *smtp_connect_addr(SMTP_STATE *state, DNS_RR *addr,
        conn_stat = sane_connect(sock, (struct sockaddr *) & sin, sizeof(sin));
     }
     if (conn_stat < 0) {
-       smtp_site_fail(state, 450, "connect to %s[%s] port %u: %m",
-                      addr->name, inet_ntoa(sin.sin_addr), ntohs(port));
+       vstring_sprintf(why, "connect to %s[%s]: %m",
+                       addr->name, inet_ntoa(sin.sin_addr));
+       smtp_errno = SMTP_RETRY;
        close(sock);
        return (0);
     }
@@ -184,8 +189,9 @@ static SMTP_SESSION *smtp_connect_addr(SMTP_STATE *state, DNS_RR *addr,
      * Skip this host if it takes no action within some time limit.
      */
     if (read_wait(sock, var_smtp_helo_tmout) < 0) {
-       smtp_site_fail(state, 450, "connect to %s[%s] port %u: read timeout",
-                      addr->name, inet_ntoa(sin.sin_addr), ntohs(port));
+       vstring_sprintf(why, "connect to %s[%s]: read timeout",
+                       addr->name, inet_ntoa(sin.sin_addr));
+       smtp_errno = SMTP_RETRY;
        close(sock);
        return (0);
     }
@@ -195,14 +201,35 @@ static SMTP_SESSION *smtp_connect_addr(SMTP_STATE *state, DNS_RR *addr,
      */
     stream = vstream_fdopen(sock, O_RDWR);
     if ((ch = VSTREAM_GETC(stream)) == VSTREAM_EOF) {
-       smtp_site_fail(state, 450, "connect to %s[%s] port %u: "
-                      "server dropped connection without sending the initial SMTP greeting",
-                      addr->name, inet_ntoa(sin.sin_addr), ntohs(port));
+       vstring_sprintf(why, "connect to %s[%s]: server dropped connection without sending the initial SMTP greeting",
+                       addr->name, inet_ntoa(sin.sin_addr));
+       smtp_errno = SMTP_RETRY;
        vstream_fclose(stream);
        return (0);
     }
     vstream_ungetc(stream, ch);
 
+    /*
+     * Skip this host if it sends a 4xx greeting.
+     */
+    if (ch == '4' && var_smtp_skip_4xx_greeting) {
+       vstring_sprintf(why, "connect to %s[%s]: server refused mail service",
+                       addr->name, inet_ntoa(sin.sin_addr));
+       smtp_errno = SMTP_RETRY;
+       vstream_fclose(stream);
+       return (0);
+    }
+
+    /*
+     * Skip this host if it sends a 5xx greeting.
+     */
+    if (ch == '5' && var_smtp_skip_5xx_greeting) {
+       vstring_sprintf(why, "connect to %s[%s]: server refused mail service",
+                       addr->name, inet_ntoa(sin.sin_addr));
+       smtp_errno = SMTP_RETRY;
+       vstream_fclose(stream);
+       return (0);
+    }
     return (smtp_session_alloc(stream, addr->name, inet_ntoa(sin.sin_addr)));
 }
 
@@ -246,6 +273,7 @@ static char *smtp_parse_destination(char *destination, char *def_service,
 int     smtp_connect(SMTP_STATE *state)
 {
     DELIVER_REQUEST *request = state->request;
+    VSTRING *why = vstring_alloc(10);
     char   *dest_buf;
     char   *host;
     unsigned port;
@@ -272,22 +300,21 @@ int     smtp_connect(SMTP_STATE *state)
        argv_split_append(sites, var_fallback_relay, ", \t\r\n");
 
     /*
-     * Don't give up after any soft error until we have tried all servers.
+     * Don't give up after a qualifying soft error until we have tried all
+     * qualifying mail servers.
      * 
      * Don't give up after a hard host lookup error until we have tried the
      * fallback relay servers.
      * 
-     * Don't bounce mail after host lookup problems with a relayhost or with
-     * fallback relays.
+     * Don't bounce mail after a host lookup problem with a relayhost or with a
+     * fallback relay.
      * 
      * All this means that error handling and error reporting depends on whether
-     * there are more mail servers (state->final_server), or whether we're
-     * looking up a relayhost or fallback relay (state->backup_server).
+     * the error qualifies for trying more mail servers, or whether we're
+     * looking up a relayhost or fallback relay.
      */
     for (cpp = sites->argv; (dest = *cpp) != 0; cpp++) {
        state->final_server = (cpp[1] == 0);
-       state->backup_server =
-           (cpp > sites->argv || strcmp(request->nexthop, var_relayhost) == 0);
 
        /*
         * Parse the destination. Default is to use the SMTP port. Look up
@@ -295,37 +322,36 @@ int     smtp_connect(SMTP_STATE *state)
         * specified, or when DNS lookups are disabled.
         */
        dest_buf = smtp_parse_destination(dest, def_service, &host, &port);
+
+       /*
+        * Resolve an SMTP server. Skip mail exchanger lookups when a quoted
+        * host is specified, or when DNS lookups are disabled.
+        */
        if (msg_verbose)
-           msg_info("connecting to \"%s\" port \"%d\"", host, ntohs(port));
+           msg_info("connecting to %s port %d", host, ntohs(port));
        if (var_disable_dns || *dest == '[') {
-           addr_list = smtp_host_addr(state, host);
+           addr_list = smtp_host_addr(host, why);
        } else {
-           addr_list = smtp_domain_addr(state, host);
+           addr_list = smtp_domain_addr(host, why);
        }
        myfree(dest_buf);
 
        /*
-        * No address list. The mail has / has not been delivered. What to do
-        * next (skip remaining hosts / try to deliver) is recorded in the
-        * state->final_server attribute.
+        * Don't try the fall-back relay if mail loops to myself.
         */
-       if (addr_list == 0) {
-           if (state->backup_server)
-               msg_warn("%s or %s configuration problem",
-                        VAR_RELAYHOST, VAR_FALLBACK_RELAY);
-       }
+       if (addr_list == 0 && smtp_errno == SMTP_LOOP)
+           break;
 
        /*
         * Connect to an SMTP server. XXX Limit the number of addresses that
         * we're willing to try for a non-fallback destination.
         * 
-        * After a soft error, log deferrals and update delivery status values
-        * only when there are no further attempts.
+        * After a soft error, weed out the recipient list and if there are any
+        * left, try again.
         */
        for (addr = addr_list; addr; addr = addr->next) {
-           if ((state->session = smtp_connect_addr(state, addr, port)) != 0) {
+           if ((state->session = smtp_connect_addr(addr, port, why)) != 0) {
                state->final_server = (cpp[1] == 0 && addr->next == 0);
-               state->status = 0;
                state->session->best = (addr->pref == addr_list->pref);
                debug_peer_check(state->session->host, state->session->addr);
                if (smtp_helo(state) == 0)
@@ -337,23 +363,71 @@ int     smtp_connect(SMTP_STATE *state)
                /* XXX smtp_xfer() may abort in the middle of DATA. */
                smtp_session_free(state->session);
                debug_peer_restore();
-               if (state->status == 0 || state->final_server)
+               if (smtp_weed_request(&request->rcpt_list) == 0)
                    break;
+           } else {
+               msg_info("%s (port %d)", vstring_str(why), ntohs(port));
            }
        }
        dns_rr_free(addr_list);
+    }
+
+    /*
+     * We still need to deliver, bounce or defer some recipients.
+     * 
+     * Pay attention to what could be configuration problems, and pretend that
+     * these are recoverable rather than bouncing the mail.
+     */
+    if (request->rcpt_list.len > 0) {
+       if (smtp_errno != SMTP_RETRY) {
+
+           /*
+            * The fall-back destination did not resolve as expected, or it
+            * is refusing to talk to us.
+            */
+           if (sites->argc > 1 && cpp > sites->argv) {
+               msg_warn("%s configuration problem", VAR_FALLBACK_RELAY);
+               smtp_errno = SMTP_RETRY;
+           }
+
+           /*
+            * The next-hop relayhost did not resolve as expected, or it is
+            * refusing to talk to us.
+            */
+           else if (strcmp(sites->argv[0], var_relayhost) == 0) {
+               msg_warn("%s configuration problem", VAR_RELAYHOST);
+               smtp_errno = SMTP_RETRY;
+           }
+
+           /*
+            * Mail for the next-hop destination loops back to myself.
+            */
+           else if (smtp_errno == SMTP_LOOP && *var_bestmx_transp) {
+               state->status = deliver_pass_all(MAIL_CLASS_PRIVATE,
+                                                var_bestmx_transp,
+                                                request);
+               smtp_errno = SMTP_NONE;
+           }
+       }
 
        /*
-        * In case someone has raised the "final server" flag before we have
-        * tried all fallback servers.
+        * We still need to bounce or defer some recipients. Do it now or
+        * else they would silently disappear due to lack of error
+        * indication.
         */
-       if (state->final_server)
-           break;
+       if (smtp_errno != SMTP_NONE) {
+           if (!state->final_server)
+               msg_panic("smtp_connect: we have left-over recipients but "
+                         "we did not try to connect to the final server");
+           smtp_site_fail(state, smtp_errno == SMTP_RETRY ? 450 : 550,
+                          "%s", vstring_str(why));
+       }
     }
 
     /*
      * Cleanup.
      */
     argv_free(sites);
+    vstring_free(why);
     return (state->status);
 }
diff --git a/postfix/src/smtp/smtp_misc.c b/postfix/src/smtp/smtp_misc.c
new file mode 100644 (file)
index 0000000..f9b2a3d
--- /dev/null
@@ -0,0 +1,81 @@
+/* System  library. */
+
+#include <sys_defs.h>
+#include <stdlib.h>                    /* smtp_weed_request  */
+
+/* Utility  library. */
+
+#include <msg.h>
+
+/* Global library. */
+
+#include <deliver_request.h>           /* smtp_rcpt_done */
+#include <deliver_completed.h>         /* smtp_rcpt_done */
+#include <sent.h>                      /* smtp_rcpt_done */
+
+/* Application-specific. */
+
+#include <smtp.h>
+
+/* smtp_rcpt_done - mark recipient as done or else */
+
+void    smtp_rcpt_done(SMTP_STATE *state, const char *reply, RECIPIENT *rcpt)
+{
+    DELIVER_REQUEST *request = state->request;
+    SMTP_SESSION *session = state->session;
+    int     status;
+
+    /*
+     * Report success and delete the recipient from the delivery request.
+     * Defer if the success can't be reported.
+     */
+    status = sent(DEL_REQ_TRACE_FLAGS(request->flags),
+                 request->queue_id, rcpt->orig_addr,
+                 rcpt->address, rcpt->offset,
+                 session->namaddr,
+                 request->arrival_time,
+                 "%s", reply);
+    if (status == 0)
+       if (request->flags & DEL_REQ_FLAG_SUCCESS)
+           deliver_completed(state->src, rcpt->offset);
+    rcpt->status = SMTP_RCPT_DROP;
+    state->status |= status;
+}
+
+/* smtp_weed_request_callback - qsort callback */
+
+static int smtp_weed_request_callback(const void *a, const void *b)
+{
+    return (((RECIPIENT *) a)->status - ((RECIPIENT *) b)->status);
+}
+
+/* smtp_weed_request - purge completed recipients from request */
+
+int     smtp_weed_request(RECIPIENT_LIST *rcpt_list)
+{
+    RECIPIENT *rcpt;
+    int     nrcpt;
+
+    /*
+     * Status codes one can expect to find: SMTP_RCPT_KEEP (try recipient
+     * another time), SMTP_RCPT_DROP (remove recipient from request) and zero
+     * (error: after delivery attempt, recipient status should be either KEEP
+     * or DROP).
+     */
+    if (rcpt_list->len > 1)
+       qsort((void *) rcpt_list->info, rcpt_list->len,
+             sizeof(rcpt_list->info), smtp_weed_request_callback);
+
+    for (nrcpt = 0; nrcpt < rcpt_list->len; nrcpt++) {
+       rcpt = rcpt_list->info + nrcpt;
+       if (rcpt->status == SMTP_RCPT_KEEP)
+           rcpt->status = 0;
+       if (rcpt->status == SMTP_RCPT_DROP)
+           break;
+       else
+           msg_panic("smtp_weed_request: bad status: %d for <%s>",
+                     rcpt->status, rcpt->address);
+    }
+    recipient_list_truncate(rcpt_list, nrcpt);
+    return (nrcpt);
+}
index 849c31f79b5f8408abde62de3e256a2092a76b85..438cffe767faad902353489fae2455e943c70665 100644 (file)
 #include <mail_queue.h>
 #include <recipient_list.h>
 #include <deliver_request.h>
-#include <deliver_completed.h>
 #include <defer.h>
 #include <bounce.h>
-#include <sent.h>
 #include <record.h>
 #include <rec_type.h>
 #include <off_cvt.h>
@@ -197,13 +195,10 @@ int     smtp_helo(SMTP_STATE *state)
     /*
      * Read and parse the server's SMTP greeting banner.
      */
-    if ((resp = smtp_chat_resp(state))->code / 100 != 2) {
-       if (var_smtp_skip_5xx_greeting && resp->code / 100 == '5')
-           resp->code -= 100;
+    if ((resp = smtp_chat_resp(state))->code / 100 != 2)
        return (smtp_site_fail(state, resp->code,
                               "host %s refused to talk to me: %s",
                         session->namaddr, translit(resp->str, "\n", " ")));
-    }
 
     /*
      * XXX Some PIX firewall versions require flush before ".<CR><LF>" so it
@@ -436,6 +431,16 @@ int     smtp_xfer(SMTP_STATE *state)
 #define SENDING_MAIL \
        (recv_state <= SMTP_STATE_DOT)
 
+    /*
+     * Sanity check. Recipients should be unmarked at this point.
+     */
+    if (request->rcpt_list.len <= 0)
+       msg_panic("smtp_xfer: bad recipient count: %d",
+                 request->rcpt_list.len);
+    if (request->rcpt_list.info->status != 0)
+       msg_panic("smtp_xfer: bad recipient status: %d",
+                 request->rcpt_list.info->status);
+
     /*
      * See if we should even try to send this message at all. This code sits
      * here rather than in the EHLO processing code, because of future SMTP
@@ -763,24 +768,14 @@ int     smtp_xfer(SMTP_STATE *state)
                        if (resp->code / 100 == 2) {
                            ++nrcpt;
                            /* If trace-only, mark the recipient done. */
-                           if (DEL_REQ_TRACE_ONLY(request->flags)
-                               && sent(DEL_REQ_TRACE_FLAGS(request->flags),
-                                       request->queue_id, rcpt->orig_addr,
-                                       rcpt->address, rcpt->offset,
-                                   session->namaddr, request->arrival_time,
-                                       "%s",
-                                    translit(resp->str, "\n", " ")) == 0) {
-                               if (request->flags & DEL_REQ_FLAG_SUCCESS)
-                                   deliver_completed(state->src, rcpt->offset);
-                               rcpt->offset = 0;       /* in case deferred */
-                           }
+                           if (DEL_REQ_TRACE_ONLY(request->flags))
+                               smtp_rcpt_done(state, resp->str, rcpt);
                        } else {
                            smtp_rcpt_fail(state, resp->code, rcpt,
                                        "host %s said: %s (in reply to %s)",
                                           session->namaddr,
                                           translit(resp->str, "\n", " "),
                                           xfer_request[SMTP_STATE_RCPT]);
-                           rcpt->offset = 0;   /* in case deferred */
                        }
                    }
                    /* If trace-only, send RSET instead of DATA. */
@@ -827,18 +822,8 @@ int     smtp_xfer(SMTP_STATE *state)
                        } else {
                            for (nrcpt = 0; nrcpt < recv_rcpt; nrcpt++) {
                                rcpt = request->rcpt_list.info + nrcpt;
-                               if (rcpt->offset) {
-                                   if (sent(DEL_REQ_TRACE_FLAGS(request->flags),
-                                        request->queue_id, rcpt->orig_addr,
-                                            rcpt->address, rcpt->offset,
-                                            session->namaddr,
-                                            request->arrival_time,
-                                            "%s", resp->str) == 0) {
-                                       if (request->flags & DEL_REQ_FLAG_SUCCESS)
-                                           deliver_completed(state->src, rcpt->offset);
-                                       rcpt->offset = 0;
-                                   }
-                               }
+                               if (rcpt->status == 0)
+                                   smtp_rcpt_done(state, resp->str, rcpt);
                            }
                        }
                    }
index ac63d27f61cccbe356dbfb0ef64c38cec529c20b..726feb5cef89c25fb85f19f40bd8d2b2cd08280c 100644 (file)
@@ -73,7 +73,6 @@ SMTP_STATE *smtp_state_alloc(void)
     state->space_left = 0;
     state->mime_state = 0;
     state->final_server = 0;
-    state->backup_server = 0;
     return (state);
 }
 
index 53a1b1ec2a521bd9d18a7420c8939c799d7dfe45..6281955971d71d7b15c95c0dd440fa1a125ae84a 100644 (file)
@@ -33,7 +33,9 @@
 /*     the problem, delivery of a single message is deferred, delivery
 /*     of all messages to the same domain is deferred, or one or more
 /*     recipients are given up as non-deliverable and a bounce log is
-/*     updated.
+/*     updated. In any case, the recipient status is updated to either
+/*     SMTP_RCPT_KEEP (try again with a backup host) or SMTP_RCPT_DROP
+/*     (delete recipient from delivery request).
 /*
 /*     In addition, when an unexpected response code is seen such
 /*     as 3xx where only 4xx or 5xx are expected, or any error code
 /*     what appear to be configuration errors - very likely, they
 /*     would suffer the same problem and just cause more trouble.
 /*
-/*     In case of a soft error, action depends on whether there are
-/*     more mail servers (log an informational record only and try
-/*     the other servers) or whether this is the final server (log
-/*     recipient delivery status records).
-/*
-/*     In the case of a hard error that affects all recipients,
-/*     recipient delivery status records are logged, and the
-/*     final server flag is raised so that any remaining mail
-/*     servers are skipped.
+/*     In case of a soft error, action depends on whether the error
+/*     qualifies for trying the request with other mail servers (log
+/*     an informational record only and try the a backup server) or
+/*     whether this is the final server (log recipient delivery status
+/*     records and delete the recipient from the request).
 /*
 /*     smtp_site_fail() handles the case where the program fails to
 /*     complete the initial SMTP handshake: the server is not reachable,
@@ -60,9 +58,8 @@
 /*     argument gives a textual description.
 /*     The policy is: soft error, non-final server: log an informational
 /*     record why the host is being skipped; soft error, final server:
-/*     defer delivery of all remaining recipients; hard error: bounce all
-/*     remaining recipients and set the "final server" flag so that any
-/*     remaining mail servers will be skipped.
+/*     defer delivery of all remaining recipients and mark the destination
+/*     a problematic; hard error: bounce all remaining recipients.
 /*     The result is non-zero.
 /*
 /*     smtp_mesg_fail() handles the case where the smtp server
@@ -70,8 +67,7 @@
 /*     The policy is: soft error, non-final server: log an informational
 /*     record why the host is being skipped; soft error, final server:
 /*     defer delivery of all remaining recipients; hard error: bounce all
-/*     remaining recipients and set the "final server" flag so that any
-/*     remaining mail servers will be skipped.
+/*     remaining recipients.
 /*     The result is non-zero.
 /*
 /*     smtp_rcpt_fail() handles the case where a recipient is not
@@ -80,7 +76,7 @@
 /*     The policy is: soft error, non-final server: log an informational
 /*     record why the recipient is being skipped; soft error, final server:
 /*     defer delivery of this recipient; hard error: bounce this
-/*     recipient. This routine does not change the "final server" flag.
+/*     recipient.
 /*
 /*     smtp_stream_except() handles the exceptions generated by
 /*     the smtp_stream(3) module (i.e. timeouts and I/O errors).
@@ -159,7 +155,7 @@ static void smtp_check_code(SMTP_STATE *state, int code)
        state->error_mask |= MAIL_ERROR_PROTOCOL;
 }
 
-/* smtp_site_fail - skip site, defer all recipients, or bounce all recipients */
+/* smtp_site_fail - skip site, defer or bounce all recipients */
 
 int     smtp_site_fail(SMTP_STATE *state, int code, char *format,...)
 {
@@ -180,38 +176,44 @@ int     smtp_site_fail(SMTP_STATE *state, int code, char *format,...)
     va_end(ap);
 
     /*
-     * Don't defer the recipients just yet when there are still more mail
-     * servers. Just log something informative to show why we're skipping
-     * this host.
+     * Don't defer the recipients just yet when this error qualifies them for
+     * delivery to a backup server. Just log something informative to show
+     * why we're skipping this host.
      */
-    if (soft_error && state->final_server == 0) {
+    if (soft_error && state->final_server == 0
+       && (smtp_backup_mask & SMTP_BACKUP_SESSION_FAILURE)) {
        msg_info("%s: %s", request->queue_id, vstring_str(why));
-       state->status |= -1;
+       for (nrcpt = 0; nrcpt < request->rcpt_list.len; nrcpt++) {
+           rcpt = request->rcpt_list.info + nrcpt;
+           if (rcpt->status != 0)
+               continue;
+           rcpt->status = SMTP_RCPT_KEEP;
+       }
     }
 
     /*
-     * Defer or bounce all the remaining recipients and raise the final mail
-     * server flag.
+     * Defer or bounce all the remaining recipients, and delete them from the
+     * delivery request. If a bounce fails, defer instead and do not qualify
+     * the recipient for delivery to a backup server.
      */
     else {
        for (nrcpt = 0; nrcpt < request->rcpt_list.len; nrcpt++) {
            rcpt = request->rcpt_list.info + nrcpt;
-           if (rcpt->offset == 0)
+           if (rcpt->status != 0)
                continue;
            status = (soft_error ? defer_append : bounce_append)
                (DEL_REQ_TRACE_FLAGS(request->flags), request->queue_id,
                 rcpt->orig_addr, rcpt->address, rcpt->offset,
                 session ? session->namaddr : "none",
                 request->arrival_time, "%s", vstring_str(why));
-           if (status == 0) {
+           if (status == 0)
                deliver_completed(state->src, rcpt->offset);
-               rcpt->offset = 0;
-           }
+           rcpt->status = SMTP_RCPT_DROP;
            state->status |= status;
        }
+       /* XXX This assumes no fall-back relay. */
        if (soft_error && request->hop_status == 0)
            request->hop_status = mystrdup(vstring_str(why));
-       state->final_server = 1;
     }
     smtp_check_code(state, code);
 
@@ -243,36 +245,41 @@ int     smtp_mesg_fail(SMTP_STATE *state, int code, char *format,...)
     va_end(ap);
 
     /*
-     * Don't defer the recipients just yet when there are still more mail
-     * servers. Just log something informative to show why we're skipping
-     * this host.
+     * Don't defer the recipients just yet when this error qualifies them for
+     * delivery to a backup server. Just log something informative to show
+     * why we're skipping this host.
      */
-    if (soft_error && state->final_server == 0) {
+    if (soft_error && state->final_server == 0
+       && (smtp_backup_mask & SMTP_BACKUP_MESSAGE_FAILURE)) {
        msg_info("%s: %s", request->queue_id, vstring_str(why));
-       state->status |= -1;
+       for (nrcpt = 0; nrcpt < request->rcpt_list.len; nrcpt++) {
+           rcpt = request->rcpt_list.info + nrcpt;
+           if (rcpt->status != 0)
+               continue;
+           rcpt->status = SMTP_RCPT_KEEP;
+       }
     }
 
     /*
-     * Defer or bounce all the remaining recipients and raise the final mail
-     * server flag.
+     * Defer or bounce all the remaining recipients, and delete them from the
+     * delivery request. If a bounce fails, defer instead and do not qualify
+     * the recipient for delivery to a backup server.
      */
     else {
        for (nrcpt = 0; nrcpt < request->rcpt_list.len; nrcpt++) {
            rcpt = request->rcpt_list.info + nrcpt;
-           if (rcpt->offset == 0)
+           if (rcpt->status != 0)
                continue;
            status = (soft_error ? defer_append : bounce_append)
                (DEL_REQ_TRACE_FLAGS(request->flags), request->queue_id,
                 rcpt->orig_addr, rcpt->address, rcpt->offset,
                 session->namaddr, request->arrival_time,
                 "%s", vstring_str(why));
-           if (status == 0) {
+           if (status == 0)
                deliver_completed(state->src, rcpt->offset);
-               rcpt->offset = 0;
-           }
+           rcpt->status = SMTP_RCPT_DROP;
            state->status |= status;
        }
-       state->final_server = 1;
     }
     smtp_check_code(state, code);
 
@@ -295,31 +302,29 @@ void    smtp_rcpt_fail(SMTP_STATE *state, int code, RECIPIENT *rcpt,
     va_list ap;
 
     /*
-     * Don't defer this recipient record just yet when there are still more
-     * mail servers. Just log something informative to show why we're
-     * skipping this recipient now.
+     * Don't defer this recipient record just yet when this error qualifies
+     * for trying other mail servers. Just log something informative to show
+     * why we're skipping this recipient now.
      */
-    if (soft_error && state->final_server == 0) {
-       VSTRING *buf = vstring_alloc(10);
+    if (soft_error && state->final_server == 0
+       && (smtp_backup_mask & SMTP_BACKUP_RECIPIENT_FAILURE)) {
+       VSTRING *buf = vstring_alloc(100);
 
        va_start(ap, format);
        vstring_vsprintf(buf, format, ap);
        va_end(ap);
        msg_info("%s: %s", request->queue_id, vstring_str(buf));
+       rcpt->status = SMTP_RCPT_KEEP;
        vstring_free(buf);
-       status = -1;
     }
 
     /*
-     * Defer or bounce this specific recipient.
-     * 
-     * If this is a hard error, we must not raise the final mail server flag. We
-     * may still make another SMTP connection to deliver deferred recipients.
+     * Defer or bounce this recipient, and delete from the delivery request.
+     * If the bounce fails, defer instead and do not qualify the recipient
+     * for delivery to a backup server.
      * 
-     * If this is a soft error, we got here because the final mail server flag
-     * was already set.
-     * 
-     * So don't touch that final mail server flag!
+     * Note: we may still make an SMTP connection to deliver other recipients
+     * that did qualify for delivery to a backup server.
      */
     else {
        va_start(ap, format);
@@ -328,13 +333,12 @@ void    smtp_rcpt_fail(SMTP_STATE *state, int code, RECIPIENT *rcpt,
             rcpt->orig_addr, rcpt->address, rcpt->offset,
             session->namaddr, request->arrival_time, format, ap);
        va_end(ap);
-       if (status == 0) {
+       if (status == 0)
            deliver_completed(state->src, rcpt->offset);
-           rcpt->offset = 0;
-       }
+       rcpt->status = SMTP_RCPT_DROP;
+       state->status |= status;
     }
     smtp_check_code(state, code);
-    state->status |= status;
 }
 
 /* smtp_stream_except - defer domain after I/O problem */
@@ -364,21 +368,29 @@ int     smtp_stream_except(SMTP_STATE *state, int code, char *description)
     }
 
     /*
-     * Don't defer the recipients just yet when there are still more mail
-     * servers. Just log why we're abandoning this host.
+     * Don't defer the recipients just yet when this error qualifies them for
+     * delivery to a backup server. Just log something informative to show
+     * why we're skipping this host.
      */
-    if (state->final_server == 0) {
+    if (state->final_server == 0
+       && (smtp_backup_mask & SMTP_BACKUP_SESSION_FAILURE)) {
        msg_info("%s: %s", request->queue_id, vstring_str(why));
-       state->status |= -1;
+       for (nrcpt = 0; nrcpt < request->rcpt_list.len; nrcpt++) {
+           rcpt = request->rcpt_list.info + nrcpt;
+           if (rcpt->status != 0)
+               continue;
+           rcpt->status = SMTP_RCPT_KEEP;
+       }
     }
 
     /*
-     * Final server. Defer all the remaining recipients.
+     * Defer all the remaining recipients and drop them from the delivery
+     * request.
      */
     else {
        for (nrcpt = 0; nrcpt < request->rcpt_list.len; nrcpt++) {
            rcpt = request->rcpt_list.info + nrcpt;
-           if (rcpt->offset == 0)
+           if (rcpt->status != 0)
                continue;
            state->status |= defer_append(DEL_REQ_TRACE_FLAGS(request->flags),
                                          request->queue_id,
@@ -386,6 +398,7 @@ int     smtp_stream_except(SMTP_STATE *state, int code, char *description)
                                          rcpt->offset, session->namaddr,
                                          request->arrival_time,
                                          "%s", vstring_str(why));
+           rcpt->status = SMTP_RCPT_DROP;
        }
     }
 
index b9913e715c391f6b7687f040b50ea22c9fac72b7..649c1dd554f2b886c07a82b6b25273db5fd9f31f 100644 (file)
@@ -875,6 +875,7 @@ extern int h_errno;
 #define STATVFS_IN_SYS_STATVFS_H
 #define UNIX_DOMAIN_CONNECT_BLOCKS_FOR_ACCEPT
 #define MISSING_SETENV
+#define STRCASECMP_IN_STRINGS_H
 /* SCO5 misses just S_ISSOCK, the others are there
  * Use C_ISSOCK definition from cpio.h.
  */