Update version number and copyright year.
[exim.git] / src / src / deliver.c
index e40ed6828ebb187b8f65f1bc2087d8ae35143e9e..fb853aa5d8f05e164166124e365108832af80095 100644 (file)
@@ -1,10 +1,10 @@
-/* $Cambridge: exim/src/src/deliver.c,v 1.32 2006/06/27 15:38:07 ph10 Exp $ */
+/* $Cambridge: exim/src/src/deliver.c,v 1.40 2007/01/08 10:50:18 ph10 Exp $ */
 
 /*************************************************
 *     Exim - an Internet mail transport agent    *
 *************************************************/
 
-/* Copyright (c) University of Cambridge 1995 - 2006 */
+/* Copyright (c) University of Cambridge 1995 - 2007 */
 /* See the file NOTICE for conditions of use and distribution. */
 
 /* The main code for delivering a message. */
@@ -1433,10 +1433,10 @@ int rc = OK;
 int size_limit;
 
 deliver_set_expansions(addr);
-size_limit = expand_string_integer(tp->message_size_limit);
+size_limit = expand_string_integer(tp->message_size_limit, TRUE);
 deliver_set_expansions(NULL);
 
-if (size_limit < 0)
+if (expand_string_message != NULL)
   {
   rc = DEFER;
   if (size_limit == -1)
@@ -2328,8 +2328,13 @@ while (addr_local != NULL)
                 retry_record->more_errno);
 
             DEBUG(D_deliver|D_retry)
+              {
               debug_printf("retry time not reached for %s: "
                 "checking ultimate address timeout\n", addr2->address);
+              debug_printf("  now=%d first_failed=%d next_try=%d expired=%d\n",
+                (int)now, (int)retry_record->first_failed,
+                (int)retry_record->next_try, retry_record->expired);
+              }
 
             if (retry != NULL && retry->rules != NULL)
               {
@@ -2338,9 +2343,8 @@ while (addr_local != NULL)
                    last_rule->next != NULL;
                    last_rule = last_rule->next);
               DEBUG(D_deliver|D_retry)
-                debug_printf("now=%d received_time=%d diff=%d timeout=%d\n",
-                  (int)now, received_time, (int)now - received_time,
-                  last_rule->timeout);
+                debug_printf("  received_time=%d diff=%d timeout=%d\n",
+                  received_time, (int)now - received_time, last_rule->timeout);
               if (now - received_time > last_rule->timeout) ok = TRUE;
               }
             else
@@ -4372,16 +4376,13 @@ while (*s != 0)
 /* 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.
+affects the subsequent routing of identical addresses. This function is called
+after routing, to check that the final routed addresses are not duplicates.
 
-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.
+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
@@ -4940,6 +4941,9 @@ else if (system_filter != NULL && process_recipients != RECIP_FAIL_TIMEOUT)
 
     while (p != NULL)
       {
+      if (parent->child_count == SHRT_MAX)
+        log_write(0, LOG_MAIN|LOG_PANIC_DIE, "system filter generated more "
+          "than %d delivery addresses", SHRT_MAX);
       parent->child_count++;
       p->parent = parent;
 
@@ -5450,40 +5454,11 @@ 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)
-      {
-      DEBUG(D_deliver|D_route)
-        debug_printf("%s is a duplicate address: discarded\n", addr->unique);
-      addr->dupof = tnode->data.ptr;
-      addr->next = addr_duplicate;
-      addr_duplicate = addr;
-      continue;
-      }
-
-    /* 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
-    are too old. */
+    without the local part) for subsequent use. If there is no retry record for
+    the standard address routing retry key, we look for the same key with the
+    sender attached, because this form is used by the smtp transport after a
+    4xx response to RCPT when address_retry_include_sender is true. */
 
     addr->domain_retry_key = string_sprintf("R:%s", addr->domain);
     addr->address_retry_key = string_sprintf("R:%s@%s", addr->local_part,
@@ -5496,12 +5471,22 @@ while (addr_new != NULL)           /* Loop until all addresses dealt with */
       domain_retry_record = dbfn_read(dbm_file, addr->domain_retry_key);
       if (domain_retry_record != NULL &&
           now - domain_retry_record->time_stamp > retry_data_expire)
-        domain_retry_record = NULL;
+        domain_retry_record = NULL;    /* Ignore if too old */
 
       address_retry_record = dbfn_read(dbm_file, addr->address_retry_key);
       if (address_retry_record != NULL &&
           now - address_retry_record->time_stamp > retry_data_expire)
-        address_retry_record = NULL;
+        address_retry_record = NULL;   /* Ignore if too old */
+
+      if (address_retry_record == NULL)
+        {
+        uschar * altkey = string_sprintf("%s:<%s>", addr->address_retry_key,
+          sender_address);
+        address_retry_record = dbfn_read(dbm_file, altkey);
+        if (address_retry_record != NULL &&
+            now - address_retry_record->time_stamp > retry_data_expire)
+          address_retry_record = NULL;   /* Ignore if too old */
+        }
       }
 
     DEBUG(D_deliver|D_retry)
@@ -5533,19 +5518,29 @@ while (addr_new != NULL)           /* Loop until all addresses dealt with */
       (void)post_process_one(addr, DEFER, LOG_MAIN, DTYPE_ROUTER, 0);
       }
 
-    /* If queue_running, defer routing unless no retry data or we've
-    passed the next retry time, or this message is forced. However,
-    if the retry time has expired, allow the routing attempt.
-    If it fails again, the address will be failed. This ensures that
+    /* If we are in a queue run, defer routing unless there is no retry data or
+    we've passed the next retry time, or this message is forced. In other
+    words, ignore retry data when not in a queue run.
+
+    However, if the domain retry time has expired, always allow the routing
+    attempt. If it fails again, the address will be failed. This ensures that
     each address is routed at least once, even after long-term routing
     failures.
 
     If there is an address retry, check that too; just wait for the next
     retry time. This helps with the case when the temporary error on the
     address was really message-specific rather than address specific, since
-    it allows other messages through. */
+    it allows other messages through.
+
+    We also wait for the next retry time if this is a message sent down an
+    existing SMTP connection (even though that will be forced). Otherwise there
+    will be far too many attempts for an address that gets a 4xx error. In
+    fact, after such an error, we should not get here because, the host should
+    not be remembered as one this message needs. However, there was a bug that
+    used to cause this to  happen, so it is best to be on the safe side. */
 
-    else if (!deliver_force && queue_running &&
+    else if (((queue_running && !deliver_force) || continue_hostname != NULL)
+            &&
             ((domain_retry_record != NULL &&
               now < domain_retry_record->next_try &&
               !domain_retry_record->expired)
@@ -5792,11 +5787,6 @@ 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
@@ -5806,7 +5796,6 @@ 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. */