-/* $Cambridge: exim/src/src/deliver.c,v 1.34 2006/06/30 15:36:08 ph10 Exp $ */
+/* $Cambridge: exim/src/src/deliver.c,v 1.46 2008/12/18 13:13:54 michael 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. */
{
BOOL return_output = FALSE;
struct stat statbuf;
- fsync(addr->return_file);
+ (void)EXIMfsync(addr->return_file);
/* If there is no output, do nothing. */
s = string_append(s, &size, &ptr, 2, US" CV=",
testflag(addr, af_cert_verified)? "yes":"no");
if ((log_extra_selector & LX_tls_peerdn) != 0 && addr->peerdn != NULL)
- s = string_append(s, &size, &ptr, 3, US" DN=\"", addr->peerdn, US"\"");
+ s = string_append(s, &size, &ptr, 3, US" DN=\"",
+ string_printing(addr->peerdn), US"\"");
#endif
if ((log_extra_selector & LX_smtp_confirmation) != 0 &&
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)
/* Ensure the journal file is pushed out to disk. */
- if (fsync(journal_fd) < 0)
+ if (EXIMfsync(journal_fd) < 0)
log_write(0, LOG_MAIN|LOG_PANIC, "failed to fsync journal: %s",
strerror(errno));
}
!contains_header(US"Reply-To", warn_message))
fprintf(f, "Reply-To: %s\n", errors_reply_to);
fprintf(f, "Auto-Submitted: auto-replied\n");
- if (!contains_header(US"From", warn_message))
- fprintf(f, "From: Mail Delivery System <Mailer-Daemon@%s>\n",
- qualify_domain_sender);
+ if (!contains_header(US"From", warn_message)) moan_write_from(f);
fprintf(f, "%s", CS warn_message);
/* Close and wait for child process to complete, without a timeout. */
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)
{
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
RDO_REWRITE,
NULL, /* No :include: restriction (not used in filter) */
NULL, /* No sieve vacation directory (not sieve!) */
+ NULL, /* No sieve enotify mailto owner (not sieve!) */
NULL, /* No sieve user address (not sieve!) */
NULL, /* No sieve subaddress (not sieve!) */
&ugid, /* uid/gid data */
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;
}
/* 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,
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)
(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)
string_sprintf("R:%s", addr->domain), 0);
/* Otherwise, if there is an existing retry record in the database, add
- retry items to delete both forms. Since the domain might have been
- rewritten (expanded to fully qualified) as a result of routing, ensure
- that the rewritten form is also deleted. */
+ retry items to delete both forms. We must also allow for the possibility
+ of a routing retry that includes the sender address. Since the domain might
+ have been rewritten (expanded to fully qualified) as a result of routing,
+ ensure that the rewritten form is also deleted. */
else if (testflag(addr, af_dr_retry_exists))
{
+ uschar *altkey = string_sprintf("%s:<%s>", addr->address_retry_key,
+ sender_address);
+ retry_add_item(addr, altkey, rf_delete);
retry_add_item(addr, addr->address_retry_key, rf_delete);
retry_add_item(addr, addr->domain_retry_key, rf_delete);
if (Ustrcmp(addr->domain, old_domain) != 0)
if (errors_reply_to != NULL)
fprintf(f, "Reply-To: %s\n", errors_reply_to);
fprintf(f, "Auto-Submitted: auto-replied\n");
- fprintf(f, "From: Mail Delivery System <Mailer-Daemon@%s>\n",
- qualify_domain_sender);
+ moan_write_from(f);
fprintf(f, "To: %s\n", bounce_recipient);
/* Open a template file if one is provided. Log failure to open, but
readconf_printtime(time(NULL) - received_time));
else
log_write(0, LOG_MAIN, "Completed");
+
+ /* Unset deliver_freeze so that we won't try to move the spool files further down */
+ deliver_freeze = FALSE;
}
/* If there are deferred addresses, we are keeping this message because it is
if (errors_reply_to != NULL)
fprintf(f, "Reply-To: %s\n", errors_reply_to);
fprintf(f, "Auto-Submitted: auto-replied\n");
- fprintf(f, "From: Mail Delivery System <Mailer-Daemon@%s>\n",
- qualify_domain_sender);
+ moan_write_from(f);
fprintf(f, "To: %s\n", recipients);
wmf_text = next_emf(wmf, US"header");