Add new errors mail_4xx, data_4xx, lost_connection, tls_required.
[exim.git] / src / src / retry.c
index 2a5516003078797f3a64840d829c815af032b336..ca61e5c0c0df1c2e74dabea665d52510341784bf 100644 (file)
@@ -1,4 +1,4 @@
-/* $Cambridge: exim/src/src/retry.c,v 1.6 2006/02/08 14:28:51 ph10 Exp $ */
+/* $Cambridge: exim/src/src/retry.c,v 1.9 2006/03/09 15:10:16 ph10 Exp $ */
 
 /*************************************************
 *     Exim - an Internet mail transport agent    *
@@ -414,20 +414,31 @@ for (yield = retries; yield != NULL; yield = yield->next)
         continue;
       }
 
-    /* Handle 4xx responses to RCPT. The code that was received is in the 2nd
-    least significant byte of more_errno (with 400 subtracted). The required
-    value is coded in the 2nd least significant byte of the yield->more_errno
-    field as follows:
+    /* The TLSREQUIRED error also covers TLSFAILURE. These are subtly different
+    errors, but not worth separating at this level. */
+
+    else if (yield->basic_errno == ERRNO_TLSREQUIRED)
+      {
+      if (basic_errno != ERRNO_TLSREQUIRED && basic_errno != ERRNO_TLSFAILURE)
+        continue;
+      }
+
+    /* Handle 4xx responses to MAIL, RCPT, or DATA. The code that was received
+    is in the 2nd least significant byte of more_errno (with 400 subtracted).
+    The required value is coded in the 2nd least significant byte of the
+    yield->more_errno field as follows:
 
       255     => any 4xx code
       >= 100  => the decade must match the value less 100
       < 100   => the exact value must match
     */
 
-    else if (yield->basic_errno == ERRNO_RCPT4XX)
+    else if (yield->basic_errno == ERRNO_MAIL4XX ||
+             yield->basic_errno == ERRNO_RCPT4XX ||
+             yield->basic_errno == ERRNO_DATA4XX)
       {
       int wanted;
-      if (basic_errno != ERRNO_RCPT4XX) continue;
+      if (basic_errno != yield->basic_errno) continue;
       wanted = (yield->more_errno >> 8) & 255;
       if (wanted != 255)
         {
@@ -684,6 +695,16 @@ for (i = 0; i < 3; i++)
         /* Compute how long this destination has been failing */
 
         failing_interval = now - retry_record->first_failed;
+        DEBUG(D_retry) debug_printf("failing_interval=%d message_age=%d\n",
+          failing_interval, message_age);
+
+        /* If the message has been on the queue longer than the recorded time
+        of failure, use the message's age instead. This can happen when some
+        messages can be delivered and others cannot; a successful delivery will
+        reset the first_failed time, and this can lead to a failing message
+        being retried too often. */
+
+        if (message_age > failing_interval) failing_interval = message_age;
 
         /* Search for the current retry rule. The cutoff time of the
         last rule is handled differently to the others. The rule continues
@@ -738,7 +759,14 @@ for (i = 0; i < 3; i++)
 
         This implements "timeout this rule if EITHER the host (or routing or
         directing) has been failing for more than the maximum time, OR if the
-        message has been on the queue for more than the maximum time." */
+        message has been on the queue for more than the maximum time."
+
+        February 2006: It is possible that this code is no longer needed
+        following the change to the retry calculation to use the message age if
+        it is larger than the time since first failure. It may be that the
+        expired flag is always set when the other conditions are met. However,
+        this is a small bit of code, and it does no harm to leave it in place,
+        just in case. */
 
         if (received_time <= retry_record->first_failed &&
             addr == endaddr && !retry_record->expired && rule != NULL)
@@ -781,7 +809,8 @@ for (i = 0; i < 3; i++)
               {
               next_try = now + rule->p1;
               if (next_gap > rule->p1)
-                next_try += random_number(next_gap - rule->p1);
+                next_try += random_number(next_gap - rule->p1)/2 +
+                  (next_gap - rule->p1)/2;
               }
             }
           }