On Sat, 2005-02-26 at 15:55, Russell Stuart wrote:
> > The conditions trigger the bug are:
> >
> > 1. A new address is added with a redirect router with the unseen
> > directive.
> >
> > 2. There is a retry record pending for new address.
> >
> > 3. The new address is moved to the front of deliver.c's delivery
> > queue by another re-direct router.
> >
> > 4. A "control = queue_only" is in effect (perhaps - not sure about
> > this one).
> >
> > 5. The original address can be successfully delivered to.
> >
> > If all these conditions are met, then each time a queue running
> > comes along, it will create a duplicate email to original
> > address. This will happen until the retry record expires.
>
>
> Here is a patch that fixes the problem:
>
Well, it did fix the original problem, but it also introduced a new
one. Hopefully the patch below does the job properly. No doubt
others will review this code - if you find a problem let me know as
I have deployed it!
BTW, the trigger for the bug is simpler than what I described above.
The trigger is:
1. A message with several recipients that can be batched through
a local transport (any local transport).
2. The first message on the deliver.c queue has a retry item
outstanding.
In that case, every queue runner that comes along will do a
delivery to remaining recipients on that local transport,
regardless of whether a delivery has been done to that
recipient or not. This will continue until the retry item
expires.
Debian users can find a version of exim with the bug fixed here:
http://www.lubemobile.com.au/ras/debian/sarge/exim4
diff -Nur exim4-4.44.keep/src/deliver.c exim4-4.44/src/deliver.c
--- exim4-4.44.keep/src/deliver.c 2005-02-27 08:35:12.000000000 +1000
+++ exim4-4.44/src/deliver.c 2005-02-27 09:54:29.000000000 +1000
@@ -2081,6 +2081,21 @@
(addr->host_list != NULL && next->host_list != NULL &&
Ustrcmp(addr->host_list->name, next->host_list->name) == 0));
+ /* Ensure it hasn't been delivered */
+ if (ok)
+ {
+ (void)string_format(big_buffer, big_buffer_size, "%s/%s",
+ next->unique + (testflag(next, af_homonym)? 3:0),
+ next->transport->name);
+ if (tree_search(tree_nonrecipients, big_buffer) != 0)
+ {
+ ok = 0;
+ DEBUG(D_deliver|D_transport)
+ debug_printf("Can't batch %s as it has been delivered\n",
+ big_buffer);
+ }
+ }
+
/* If the transport has a batch_id setting, batch_id will be non-NULL
from the expansion outside the loop. Expand for this address and compare.
Expansion failure makes this address ineligible for batching. */