ratelimit fix: omit the limit parameter from the database lookup
[exim.git] / src / src / deliver.c
index ac23a33aa3a41a02410bde87008ac118e9efb8dd..d9bf21a4c3fd68fddbcc6107c081448f61e9b4e0 100644 (file)
@@ -1,4 +1,4 @@
-/* $Cambridge: exim/src/src/deliver.c,v 1.11 2005/04/06 14:40:24 ph10 Exp $ */
+/* $Cambridge: exim/src/src/deliver.c,v 1.15 2005/05/24 08:15:02 tom Exp $ */
 
 /*************************************************
 *     Exim - an Internet mail transport agent    *
@@ -878,6 +878,11 @@ if (result == OK)
   if ((log_extra_selector & LX_sender_on_delivery) != 0)
     s = string_append(s, &size, &ptr, 3, US" F=<", sender_address, US">");
 
+  #ifdef EXPERIMENTAL_SRS
+  if(addr->p.srs_sender)
+    s = string_append(s, &size, &ptr, 3, US" SRS=<", addr->p.srs_sender, US">");
+  #endif
+
   /* You might think that the return path must always be set for a successful
   delivery; indeed, I did for some time, until this statement crashed. The case
   when it is not set is for a delivery to /dev/null which is optimised by not
@@ -1537,8 +1542,14 @@ transport_instance *tp = addr->transport;
 /* Set up the return path from the errors or sender address. If the transport
 has its own return path setting, expand it and replace the existing value. */
 
-return_path = (addr->p.errors_address != NULL)?
-  addr->p.errors_address : sender_address;
+if(addr->p.errors_address != NULL)
+  return_path = addr->p.errors_address;
+#ifdef EXPERIMENTAL_SRS
+else if(addr->p.srs_sender != NULL)
+  return_path = addr->p.srs_sender;
+#endif
+else
+  return_path = sender_address;
 
 if (tp->return_path != NULL)
   {
@@ -3528,8 +3539,14 @@ for (delivery_count = 0; addr_remote != NULL; delivery_count++)
   /* Compute the return path, expanding a new one if required. The old one
   must be set first, as it might be referred to in the expansion. */
 
-  return_path = (addr->p.errors_address != NULL)?
-    addr->p.errors_address : sender_address;
+  if(addr->p.errors_address != NULL)
+    return_path = addr->p.errors_address;
+#ifdef EXPERIMENTAL_SRS
+  else if(addr->p.srs_sender != NULL)
+    return_path = addr->p.srs_sender;
+#endif
+  else
+    return_path = sender_address;
 
   if (tp->return_path != NULL)
     {
@@ -4180,7 +4197,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 +4233,6 @@ return yield;
 
 
 
-
 /*************************************************
 *         Print error for an address             *
 *************************************************/
@@ -4227,47 +4242,108 @@ 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')
     {
-    if (*s == '\\' && s[1] == 'n')
+    fprintf(f, "\n    ");
+    s += 2;
+    count = 0;
+    }
+  else
+    {
+    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    *
+*************************************************/
+
+/* This function was introduced when the test for duplicate addresses that are
+not pipes, files, or autoreplies was moved from the middle of routing to when
+routing was complete. That was to fix obscure cases when the routing history
+affects the subsequent routing of identical addresses. If that change has to be
+reversed, this function is no longer needed. For a while, the old code that was
+affected by this change is commented with !!!OLD-DE-DUP!!! so it can be found
+easily.
+
+This function is called after routing, to check that the final routed addresses
+are not duplicates. If we detect a duplicate, we remember what it is a
+duplicate of. Note that pipe, file, and autoreply de-duplication is handled
+during routing, so we must leave such "addresses" alone here, as otherwise they
+will incorrectly be discarded.
+
+Argument:     address of list anchor
+Returns:      nothing
+*/
+
+static void
+do_duplicate_check(address_item **anchor)
+{
+address_item *addr;
+while ((addr = *anchor) != NULL)
+  {
+  tree_node *tnode;
+  if (testflag(addr, af_pfr))
+    {
+    anchor = &(addr->next);
+    }
+  else if ((tnode = tree_search(tree_duplicates, addr->unique)) != NULL)
+    {
+    DEBUG(D_deliver|D_route)
+      debug_printf("%s is a duplicate address: discarded\n", addr->unique);
+    *anchor = addr->next;
+    addr->dupof = tnode->data.ptr;
+    addr->next = addr_duplicate;
+    addr_duplicate = addr;
+    }
+  else
+    {
+    tree_add_duplicate(addr->unique, addr);
+    anchor = &(addr->next);
     }
   }
 }
@@ -4942,6 +5018,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 */
 
 
@@ -5290,6 +5367,18 @@ while (addr_new != NULL)           /* Loop until all addresses dealt with */
       continue;
       }
 
+
+    /* !!!OLD-DE-DUP!!!  We used to test for duplicates at this point, in order
+    to save effort on routing duplicate addresses. However, facilities have
+    been added to Exim so that now two identical addresses that are children of
+    other addresses may be routed differently as a result of their previous
+    routing history. For example, different redirect routers may have given
+    them different redirect_router values, but there are other cases too.
+    Therefore, tests for duplicates now take place when routing is complete.
+    This is the old code, kept for a while for the record, and in case this
+    radical change has to be backed out for some reason. */
+
+    #ifdef NEVER
     /* If it's a duplicate, remember what it's a duplicate of */
 
     if ((tnode = tree_search(tree_duplicates, addr->unique)) != NULL)
@@ -5305,6 +5394,9 @@ while (addr_new != NULL)           /* Loop until all addresses dealt with */
     /* Record this address, so subsequent duplicates get picked up. */
 
     tree_add_duplicate(addr->unique, addr);
+    #endif
+
+
 
     /* Get the routing retry status, saving the two retry keys (with and
     without the local part) for subsequent use. Ignore retry records that
@@ -5617,6 +5709,21 @@ Ensure they are not set in transports. */
 local_user_gid = (gid_t)(-1);
 local_user_uid = (uid_t)(-1);
 
+
+/* !!!OLD-DE-DUP!!! The next two statement were introduced when checking for
+duplicates was moved from within routing to afterwards. If that change has to
+be backed out, they should be removed. */
+
+/* Check for any duplicate addresses. This check is delayed until after
+routing, because the flexibility of the routing configuration means that
+identical addresses with different parentage may end up being redirected to
+different addresses. Checking for duplicates too early (as we previously used
+to) makes this kind of thing not work. */
+
+do_duplicate_check(&addr_local);
+do_duplicate_check(&addr_remote);
+
+
 /* When acting as an MUA wrapper, we proceed only if all addresses route to a
 remote transport. The check that they all end up in one transaction happens in
 the do_remote_deliveries() function. */
@@ -6100,26 +6207,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 */
 
@@ -6621,21 +6717,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");