Remove details of errors in bounce and delay warning messages, unless
authorPhilip Hazel <ph10@hermes.cam.ac.uk>
Thu, 28 Apr 2005 13:06:32 +0000 (13:06 +0000)
committerPhilip Hazel <ph10@hermes.cam.ac.uk>
Thu, 28 Apr 2005 13:06:32 +0000 (13:06 +0000)
explicitly specified (e.g. :fail:) or a message from a remote host.

doc/doc-txt/ChangeLog
src/README.UPDATING
src/src/deliver.c
src/src/routers/queryprogram.c
src/src/routers/redirect.c
src/src/structs.h
src/src/transports/smtp.c

index d8272ab92b07481f2b3e6f5139859bf7e1d70e4b..cbb8e9cbbc45707587f1dd2baa3d9320fe4822f6 100644 (file)
@@ -1,4 +1,4 @@
-$Cambridge: exim/doc/doc-txt/ChangeLog,v 1.127 2005/04/27 13:29:32 ph10 Exp $
+$Cambridge: exim/doc/doc-txt/ChangeLog,v 1.128 2005/04/28 13:06:32 ph10 Exp $
 
 Change log file for Exim from version 4.21
 -------------------------------------------
@@ -249,6 +249,20 @@ PH/41 $message_linecount is a new variable that contains the total number of
       lines in the message. Compare $body_linecount, which is the count for the
       body only.
 
+PH/42 Exim no longer gives details of delivery errors for specific addresses in
+      bounce and delay warning messages, except in certain special cases, which
+      are as follows:
+
+      (a) An SMTP error message from a remote host;
+      (b) A message specified in a :fail: redirection;
+      (c) A message specified in a "fail" command in a system filter;
+      (d) A message specified in a FAIL return from the queryprogram router;
+      (e) A message specified by the cannot_route_message router option.
+
+      In these cases only, Exim does include the error details in bounce and
+      warning messages. There are also a few cases where bland messages such
+      as "unrouteable address" or "local delivery error" are given.
+
 
 A note about Exim versions 4.44 and 4.50
 ----------------------------------------
index c91c5768069d185e6dee6e173167f67c1a5e5776..efc123c15f4387a0187e4e1a75f5ff27e0c310f0 100644 (file)
@@ -1,4 +1,4 @@
-$Cambridge: exim/src/README.UPDATING,v 1.6 2005/04/06 16:26:42 ph10 Exp $
+$Cambridge: exim/src/README.UPDATING,v 1.7 2005/04/28 13:06:32 ph10 Exp $
 
 This document contains detailed information about incompatibilities that might
 be encountered when upgrading from one release of Exim to another. The
@@ -50,6 +50,10 @@ uses prefixes or suffixes on addresses that could be used for callouts, and you
 want the affixes to be retained, you must make sure that rcpt_include_affixes
 is set on the transport.
 
+3. Bounce and delay warning messages no longer contain details of delivery
+errors, except for explicit messages (e.g. generated by :fail:) and SMTP
+responses from remote hosts.
+
 
 Version 4.50
 ------------
index 78eb65bc6b2969fcfa5bb56d38f874075c23627c..a7b367d800433951688d66a815905437a1d2552e 100644 (file)
@@ -1,4 +1,4 @@
-/* $Cambridge: exim/src/src/deliver.c,v 1.13 2005/04/07 15:40:50 ph10 Exp $ */
+/* $Cambridge: exim/src/src/deliver.c,v 1.14 2005/04/28 13:06:32 ph10 Exp $ */
 
 /*************************************************
 *     Exim - an Internet mail transport agent    *
@@ -4180,7 +4180,6 @@ if (addr->parent != NULL && testflag(addr, af_hide_child))
   printed = US"an undisclosed address";
   yield = FALSE;
   }
-
 else if (!testflag(addr, af_pfr) || addr->parent == NULL)
   printed = addr->address;
 
@@ -4217,7 +4216,6 @@ return yield;
 
 
 
-
 /*************************************************
 *         Print error for an address             *
 *************************************************/
@@ -4227,53 +4225,62 @@ a bounce or a warning message. It tries to format the message reasonably by
 introducing newlines. All lines are indented by 4; the initial printing
 position must be set before calling.
 
+This function used always to print the error. Nowadays we want to restrict it
+to cases such as SMTP errors from a remote host, and errors from :fail: and
+filter "fail". We no longer pass other information willy-nilly in bounce and
+warning messages. Text in user_message is always output; text in message only
+if the af_pass_message flag is set.
+
 Arguments:
-  addr         points to the address
+  addr         the address
   f            the FILE to print on
+  s            some leading text
 
 Returns:       nothing
 */
 
 static void
-print_address_error(address_item *addr, FILE *f)
+print_address_error(address_item *addr, FILE *f, uschar *t)
 {
+int count = Ustrlen(t);
 uschar *s = (addr->user_message != NULL)? addr->user_message : addr->message;
-if (addr->basic_errno > 0)
-  {
-  fprintf(f, "%s%s", strerror(addr->basic_errno),
-    (s == NULL)? "" : ":\n    ");
-  }
-if (s == NULL)
+
+if (addr->user_message != NULL)
+  s = addr->user_message;
+else
   {
-  if (addr->basic_errno <= 0) fprintf(f, "unknown error");
+  if (!testflag(addr, af_pass_message) || addr->message == NULL) return;
+  s = addr->message;
   }
-else
+
+fprintf(f, "\n    %s", t);
+
+while (*s != 0)
   {
-  int count = 0;
-  while (*s != 0)
+  if (*s == '\\' && s[1] == 'n')
+    {
+    fprintf(f, "\n    ");
+    s += 2;
+    count = 0;
+    }
+  else
     {
-    if (*s == '\\' && s[1] == 'n')
+    fputc(*s, f);
+    count++;
+    if (*s++ == ':' && isspace(*s) && count > 45)
       {
-      fprintf(f, "\n    ");
-      s += 2;
+      fprintf(f, "\n   ");  /* sic (because space follows) */
       count = 0;
       }
-    else
-      {
-      fputc(*s, f);
-      count++;
-      if (*s++ == ':' && isspace(*s) && count > 45)
-        {
-        fprintf(f, "\n   ");  /* sic (because space follows) */
-        count = 0;
-        }
-      }
     }
   }
 }
 
 
 
+
+
+
 /*************************************************
 *     Check list of addresses for duplication    *
 *************************************************/
@@ -4994,6 +5001,7 @@ if (process_recipients != RECIP_IGNORE)
         case RECIP_FAIL_FILTER:
         new->message =
           (filter_message == NULL)? US"delivery cancelled" : filter_message;
+        setflag(new, af_pass_message);
         goto RECIP_QUEUE_FAILED;   /* below */
 
 
@@ -6182,26 +6190,15 @@ wording. */
 
       /* Process the addresses, leaving them on the msgchain if they have a
       file name for a return message. (There has already been a check in
-      post_process_one() for the existence of data in the message file.) */
+      post_process_one() for the existence of data in the message file.) A TRUE
+      return from print_address_information() means that the address is not
+      hidden. */
 
       paddr = &msgchain;
       for (addr = msgchain; addr != NULL; addr = *paddr)
         {
         if (print_address_information(addr, f, US"  ", US"\n    ", US""))
-          {
-          /* A TRUE return from print_address_information() means that the
-          address is not hidden. If there is a return file, it has already
-          been checked to ensure it is not empty. Omit the bland "return
-          message generated" error, but otherwise include error information. */
-
-          if (addr->return_file < 0 ||
-              addr->message == NULL ||
-              Ustrcmp(addr->message, "return message generated") != 0)
-            {
-            fprintf(f, "\n    ");
-            print_address_error(addr, f);
-            }
-          }
+          print_address_error(addr, f, US"");
 
         /* End the final line for the address */
 
@@ -6703,21 +6700,15 @@ else if (addr_defer != (address_item *)(+1))
             (addr_defer->next == NULL)? "is": "are");
           }
 
-        /* List the addresses. For any that are hidden, don't give the delay
-        reason, because it might expose that which is hidden. Also, do not give
-        "retry time not reached" because that isn't helpful. */
+        /* List the addresses, with error information if allowed */
 
         fprintf(f, "\n");
         while (addr_defer != NULL)
           {
           address_item *addr = addr_defer;
           addr_defer = addr->next;
-          if (print_address_information(addr, f, US"  ", US"\n    ", US"") &&
-              addr->basic_errno > ERRNO_RETRY_BASE)
-            {
-            fprintf(f, "\n    Delay reason: ");
-            print_address_error(addr, f);
-            }
+          if (print_address_information(addr, f, US"  ", US"\n    ", US""))
+            print_address_error(addr, f, US"Delay reason: ");
           fprintf(f, "\n");
           }
         fprintf(f, "\n");
index 5d7a51fdf9dca14c1150a621f5ebc6ef926beb8f..5282a1fa6bdce12cedf75d20808fc487fa6c649e 100644 (file)
@@ -1,4 +1,4 @@
-/* $Cambridge: exim/src/src/routers/queryprogram.c,v 1.3 2005/04/06 14:40:24 ph10 Exp $ */
+/* $Cambridge: exim/src/src/routers/queryprogram.c,v 1.4 2005/04/28 13:06:32 ph10 Exp $ */
 
 /*************************************************
 *     Exim - an Internet mail transport agent    *
@@ -416,7 +416,11 @@ if (strcmpic(rword, US"accept") != 0)
   if (strcmpic(rword, US"decline") == 0) return DECLINE;
   if (strcmpic(rword, US"pass") == 0) return PASS;
   addr->message = string_copy(rdata);                /* data is a message */
-  if (strcmpic(rword, US"fail") == 0) return FAIL;
+  if (strcmpic(rword, US"fail") == 0)
+    {
+    setflag(addr, af_pass_message);
+    return FAIL;
+    }
   if (strcmpic(rword, US"freeze") == 0) addr->special_action = SPECIAL_FREEZE;
   else if (strcmpic(rword, US"defer") != 0)
     {
index 0153a4d499e704c2f041484408e97effa4b64d97..8e8fc876c5af80642aca54bf5c712c6174e55c44 100644 (file)
@@ -1,4 +1,4 @@
-/* $Cambridge: exim/src/src/routers/redirect.c,v 1.9 2005/04/06 14:40:24 ph10 Exp $ */
+/* $Cambridge: exim/src/src/routers/redirect.c,v 1.10 2005/04/28 13:06:32 ph10 Exp $ */
 
 /*************************************************
 *     Exim - an Internet mail transport agent    *
@@ -655,8 +655,13 @@ switch (frc)
   if ((xrc = sort_errors_and_headers(rblock, addr, verify, &addr_prop)) != OK)
     return xrc;
   add_generated(rblock, addr_new, addr, generated, &addr_prop, &ugid, pw);
-  if (addr->message == NULL) addr->message = US"forced rejection";
-    else addr->user_message = addr->message;
+  if (addr->message == NULL)
+    addr->message = US"forced rejection";
+  else
+    {
+    addr->user_message = addr->message;
+    setflag(addr, af_pass_message);
+    }
   return FAIL;
 
   /* As in the case of a system filter, a freeze does not happen after a manual
index 791e11c698eb563fe689539335b8adef76ff5d23..645dfc25cf25b91f2fb888238a5e5253baeb1ae2 100644 (file)
@@ -1,4 +1,4 @@
-/* $Cambridge: exim/src/src/structs.h,v 1.4 2005/02/17 11:58:26 ph10 Exp $ */
+/* $Cambridge: exim/src/src/structs.h,v 1.5 2005/04/28 13:06:32 ph10 Exp $ */
 
 /*************************************************
 *     Exim - an Internet mail transport agent    *
@@ -498,6 +498,7 @@ typedef struct address_item_propagated {
 #define af_verify_callout      0x00400000 /* for cached sender verify: callout was specified */
 #define af_include_affixes     0x00800000 /* delivered with affixes in RCPT */
 #define af_cert_verified       0x01000000 /* delivered with verified TLS cert */
+#define af_pass_message        0x02000000 /* pass message in bounces */
 
 /* These flags must be propagated when a child is created */
 
index f53d742e4cc89ca80e21abf7f8a05c1afa72f230..69b1c1965bed1544d4b78b631077245f90e6f7f6 100644 (file)
@@ -1,4 +1,4 @@
-/* $Cambridge: exim/src/src/transports/smtp.c,v 1.10 2005/04/07 10:54:54 ph10 Exp $ */
+/* $Cambridge: exim/src/src/transports/smtp.c,v 1.11 2005/04/28 13:06:32 ph10 Exp $ */
 
 /*************************************************
 *     Exim - an Internet mail transport agent    *
@@ -313,10 +313,11 @@ host_build_hostlist(&(ob->fallback_hostlist), ob->fallback_hosts, FALSE);
 status means that an address is not currently being processed.
 
 Arguments:
-  addrlist     points to a chain of addresses
-  errno_value  to put in each address's errno field
-  msg          to put in each address's message field
-  rc           to put in each address's transport_return field
+  addrlist       points to a chain of addresses
+  errno_value    to put in each address's errno field
+  msg            to put in each address's message field
+  rc             to put in each address's transport_return field
+  pass_message   if TRUE, set the "pass message" flag in the address
 
 If errno_value has the special value ERRNO_CONNECTTIMEOUT, ETIMEDOUT is put in
 the errno field, and RTEF_CTOUT is ORed into the more_errno field, to indicate
@@ -326,7 +327,8 @@ Returns:       nothing
 */
 
 static
-void set_errno(address_item *addrlist, int errno_value, uschar *msg, int rc)
+void set_errno(address_item *addrlist, int errno_value, uschar *msg, int rc,
+  BOOL pass_message)
 {
 address_item *addr;
 int orvalue = 0;
@@ -340,7 +342,11 @@ for (addr = addrlist; addr != NULL; addr = addr->next)
   if (addr->transport_return < PENDING) continue;
   addr->basic_errno = errno_value;
   addr->more_errno |= orvalue;
-  if (msg != NULL) addr->message = msg;
+  if (msg != NULL)
+    {
+    addr->message = msg;
+    if (pass_message) setflag(addr, af_pass_message);
+    }
   addr->transport_return = rc;
   }
 }
@@ -358,18 +364,19 @@ the yield variable. If no response was actually read, a suitable digit is
 chosen.
 
 Arguments:
-  host         the current host, to get its name for messages
-  errno_value  pointer to the errno value
-  more_errno   from the top address for use with ERRNO_FILTER_FAIL
-  buffer       the SMTP response buffer
-  yield        where to put a one-digit SMTP response code
-  message      where to put an errror message
-
-Returns:       TRUE if an SMTP "QUIT" command should be sent, else FALSE
+  host           the current host, to get its name for messages
+  errno_value    pointer to the errno value
+  more_errno     from the top address for use with ERRNO_FILTER_FAIL
+  buffer         the SMTP response buffer
+  yield          where to put a one-digit SMTP response code
+  message        where to put an errror message
+  pass_message   set TRUE if message is an SMTP response
+
+Returns:         TRUE if an SMTP "QUIT" command should be sent, else FALSE
 */
 
 static BOOL check_response(host_item *host, int *errno_value, int more_errno,
-  uschar *buffer, int *yield, uschar **message)
+  uschar *buffer, int *yield, uschar **message, BOOL *pass_message)
 {
 uschar *pl = US"";
 
@@ -444,8 +451,9 @@ if (*errno_value == ERRNO_WRITEINCOMPLETE)
 if (buffer[0] != 0)
   {
   uschar *s = string_printing(buffer);
-  *message = US string_sprintf("SMTP error from remote mailer after %s%s: "
+  *message = US string_sprintf("SMTP error from remote mail server after %s%s: "
     "host %s [%s]: %s", pl, smtp_command, host->name, host->address, s);
+  *pass_message = TRUE;
   *yield = buffer[0];
   return TRUE;
   }
@@ -623,7 +631,7 @@ while (count-- > 0)
     uschar *message = string_sprintf("SMTP timeout while connected to %s [%s] "
       "after RCPT TO:<%s>", host->name, host->address,
       transport_rcpt_address(addr, include_affixes));
-    set_errno(addrlist, save_errno, message, DEFER);
+    set_errno(addrlist, save_errno, message, DEFER, FALSE);
     retry_add_item(addr, addr->address_retry_key, 0);
     host->update_waiting = FALSE;
     return -1;
@@ -646,9 +654,10 @@ while (count-- > 0)
   else
     {
     addr->message =
-      string_sprintf("SMTP error from remote mailer after RCPT TO:<%s>: "
+      string_sprintf("SMTP error from remote mail server after RCPT TO:<%s>: "
         "host %s [%s]: %s", transport_rcpt_address(addr, include_affixes),
         host->name, host->address, string_printing(buffer));
+    setflag(addr, af_pass_message);
     deliver_msglog("%s %s\n", tod_stamp(tod_log), addr->message);
 
     /* The response was 5xx */
@@ -699,8 +708,9 @@ if (pending_DATA != 0 &&
   {
   int code;
   uschar *msg;
+  BOOL pass_message;
   if (pending_DATA > 0 || (yield & 1) != 0) return -3;
-  (void)check_response(host, &errno, 0, buffer, &code, &msg);
+  (void)check_response(host, &errno, 0, buffer, &code, &msg, &pass_message);
   DEBUG(D_transport) debug_printf("%s\nerror for DATA ignored: pipelining "
     "is in use and there were no good recipients\n", msg);
   }
@@ -782,6 +792,7 @@ BOOL setting_up = TRUE;
 BOOL completed_address = FALSE;
 BOOL esmtp = TRUE;
 BOOL pending_MAIL;
+BOOL pass_message = FALSE;
 smtp_inblock inblock;
 smtp_outblock outblock;
 int max_rcpt = tblock->max_addresses;
@@ -822,7 +833,7 @@ if (helo_data == NULL)
   {
   uschar *message = string_sprintf("failed to expand helo_data: %s",
     expand_string_message);
-  set_errno(addrlist, 0, message, DEFER);
+  set_errno(addrlist, 0, message, DEFER, FALSE);
   return ERROR;
   }
 
@@ -842,7 +853,7 @@ if (ob->authenticated_sender != NULL)
       {
       uschar *message = string_sprintf("failed to expand "
         "authenticated_sender: %s", expand_string_message);
-      set_errno(addrlist, 0, message, DEFER);
+      set_errno(addrlist, 0, message, DEFER, FALSE);
       return ERROR;
       }
     }
@@ -861,7 +872,7 @@ if (continue_hostname == NULL)
   if (inblock.sock < 0)
     {
     set_errno(addrlist, (errno == ETIMEDOUT)? ERRNO_CONNECTTIMEOUT : errno,
-      NULL, DEFER);
+      NULL, DEFER, FALSE);
     return DEFER;
     }
 
@@ -1186,7 +1197,7 @@ if (continue_hostname == NULL
 
             case ERROR:
             yield = ERROR;
-            set_errno(addrlist, 0, string_copy(buffer), DEFER);
+            set_errno(addrlist, 0, string_copy(buffer), DEFER, FALSE);
             goto SEND_QUIT;
             }
 
@@ -1202,7 +1213,8 @@ if (continue_hostname == NULL
     {
     yield = DEFER;
     set_errno(addrlist, ERRNO_AUTHFAIL,
-      string_sprintf("authentication required but %s", fail_reason), DEFER);
+      string_sprintf("authentication required but %s", fail_reason), DEFER,
+      FALSE);
     goto SEND_QUIT;
     }
   }
@@ -1228,7 +1240,8 @@ if (tblock->filter_command != NULL)
 
   if (!rc)
     {
-    set_errno(addrlist->next, addrlist->basic_errno, addrlist->message, DEFER);
+    set_errno(addrlist->next, addrlist->basic_errno, addrlist->message, DEFER,
+      FALSE);
     yield = ERROR;
     goto SEND_QUIT;
     }
@@ -1368,7 +1381,8 @@ if (mua_wrapper)
     }
   if (badaddr != NULL)
     {
-    set_errno(addrlist, 0, badaddr->message, FAIL);
+    set_errno(addrlist, 0, badaddr->message, FAIL,
+      testflag(badaddr, af_pass_message));
     ok = FALSE;
     }
   }
@@ -1597,7 +1611,7 @@ if (!ok)
   save_errno = errno;
   message = NULL;
   send_quit = check_response(host, &save_errno, addrlist->more_errno,
-    buffer, &code, &message);
+    buffer, &code, &message, &pass_message);
   goto FAILED;
 
   SEND_FAILED:
@@ -1632,11 +1646,11 @@ if (!ok)
     {
     if (code == '5')
       {
-      set_errno(addrlist, save_errno, message, FAIL);
+      set_errno(addrlist, save_errno, message, FAIL, pass_message);
       }
     else
       {
-      set_errno(addrlist, save_errno, message, DEFER);
+      set_errno(addrlist, save_errno, message, DEFER, pass_message);
       yield = DEFER;
       }
     }
@@ -1662,7 +1676,7 @@ if (!ok)
     {
     yield = (save_errno == ERRNO_CHHEADER_FAIL ||
              save_errno == ERRNO_FILTER_FAIL)? ERROR : DEFER;
-    set_errno(addrlist, save_errno, message, DEFER);
+    set_errno(addrlist, save_errno, message, DEFER, pass_message);
     }
 
   /* Otherwise we have a message-specific error response from the remote
@@ -1683,7 +1697,8 @@ if (!ok)
     {
     if (mua_wrapper) code = '5';  /* Force hard failure in wrapper mode */
 
-    set_errno(addrlist, save_errno, message, (code == '5')? FAIL : DEFER);
+    set_errno(addrlist, save_errno, message, (code == '5')? FAIL : DEFER,
+      pass_message);
 
     /* If there's an errno, the message contains just the identity of
     the host. */
@@ -1747,6 +1762,7 @@ if (completed_address && ok && send_quit)
         ))
     {
     uschar *msg;
+    BOOL pass_message;
 
     if (send_rset)
       {
@@ -1760,7 +1776,8 @@ if (completed_address && ok && send_quit)
                   ob->command_timeout)))
         {
         int code;
-        send_quit = check_response(host, &errno, 0, buffer, &code, &msg);
+        send_quit = check_response(host, &errno, 0, buffer, &code, &msg,
+          &pass_message);
         if (!send_quit)
           {
           DEBUG(D_transport) debug_printf("%s\n", msg);
@@ -1806,7 +1823,7 @@ if (completed_address && ok && send_quit)
 
     /* If RSET failed and there are addresses left, they get deferred. */
 
-    else set_errno(first_addr, errno, msg, DEFER);
+    else set_errno(first_addr, errno, msg, DEFER, FALSE);
     }
   }
 
@@ -2449,7 +2466,7 @@ for (cutoff_retry = 0; expired &&
     if (dont_deliver)
       {
       host_item *host2;
-      set_errno(addrlist, 0, NULL, OK);
+      set_errno(addrlist, 0, NULL, OK, FALSE);
       for (addr = addrlist; addr != NULL; addr = addr->next)
         {
         addr->host_used = host;