* Exim - an Internet mail transport agent *
*************************************************/
-/* Copyright (c) University of Cambridge 1995 - 2009 */
+/* Copyright (c) University of Cambridge 1995 - 2014 */
/* See the file NOTICE for conditions of use and distribution. */
/* The main code for delivering a message. */
+static uschar *
+d_hostlog(uschar * s, int * sizep, int * ptrp, address_item * addr)
+{
+ s = string_append(s, sizep, ptrp, 5, US" H=", addr->host_used->name,
+ US" [", addr->host_used->address, US"]");
+ if ((log_extra_selector & LX_outgoing_port) != 0)
+ s = string_append(s, sizep, ptrp, 2, US":", string_sprintf("%d",
+ addr->host_used->port));
+ return s;
+}
+
+#ifdef SUPPORT_TLS
+static uschar *
+d_tlslog(uschar * s, int * sizep, int * ptrp, address_item * addr)
+{
+ if ((log_extra_selector & LX_tls_cipher) != 0 && addr->cipher != NULL)
+ s = string_append(s, sizep, ptrp, 2, US" X=", addr->cipher);
+ if ((log_extra_selector & LX_tls_certificate_verified) != 0 &&
+ addr->cipher != NULL)
+ s = string_append(s, sizep, ptrp, 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, sizep, ptrp, 3, US" DN=\"",
+ string_printing(addr->peerdn), US"\"");
+ return s;
+}
+#endif
+
/* If msg is NULL this is a delivery log and logchar is used. Otherwise
-this is a nonstandard call; no two-characher delivery flag is written
+this is a nonstandard call; no two-character delivery flag is written
but sender-host and sender are prefixed and "msg" is inserted in the log line.
Arguments:
have a pointer to the host item that succeeded; local deliveries can have a
pointer to a single host item in their host list, for use by the transport. */
+#ifdef EXPERIMENTAL_TPDA
+ tpda_delivery_ip = NULL; /* presume no successful remote delivery */
+ tpda_delivery_port = 0;
+ tpda_delivery_fqdn = NULL;
+ tpda_delivery_local_part = NULL;
+ tpda_delivery_domain = NULL;
+ tpda_delivery_confirmation = NULL;
+#endif
+
s = reset_point = store_get(size);
log_address = string_log_address(addr, (log_write_selector & L_all_parents) != 0, TRUE);
if (addr->transport->info->local)
{
if (addr->host_list != NULL)
+ {
s = string_append(s, &size, &ptr, 2, US" H=", addr->host_list->name);
+ #ifdef EXPERIMENTAL_TPDA
+ tpda_delivery_fqdn = addr->host_list->name;
+ #endif
+ }
if (addr->shadow_message != NULL)
s = string_cat(s, &size, &ptr, addr->shadow_message,
Ustrlen(addr->shadow_message));
{
if (addr->host_used != NULL)
{
- s = string_append(s, &size, &ptr, 5, US" H=", addr->host_used->name,
- US" [", addr->host_used->address, US"]");
- if ((log_extra_selector & LX_outgoing_port) != 0)
- s = string_append(s, &size, &ptr, 2, US":", string_sprintf("%d",
- addr->host_used->port));
+ s = d_hostlog(s, &size, &ptr, addr);
if (continue_sequence > 1)
s = string_cat(s, &size, &ptr, US"*", 1);
+
+ #ifdef EXPERIMENTAL_TPDA
+ tpda_delivery_ip = addr->host_used->address;
+ tpda_delivery_port = addr->host_used->port;
+ tpda_delivery_fqdn = addr->host_used->name;
+ tpda_delivery_local_part = addr->local_part;
+ tpda_delivery_domain = addr->domain;
+ tpda_delivery_confirmation = addr->message;
+ #endif
}
#ifdef SUPPORT_TLS
- if ((log_extra_selector & LX_tls_cipher) != 0 && addr->cipher != NULL)
- s = string_append(s, &size, &ptr, 2, US" X=", addr->cipher);
- if ((log_extra_selector & LX_tls_certificate_verified) != 0 &&
- addr->cipher != NULL)
- 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=\"",
- string_printing(addr->peerdn), US"\"");
+ s = d_tlslog(s, &size, &ptr, addr);
#endif
if (addr->authenticator)
}
}
- if ((log_extra_selector & LX_smtp_confirmation) != 0 &&
- addr->message != NULL)
- {
- int i;
- uschar *p = big_buffer;
- uschar *ss = addr->message;
- *p++ = '\"';
- for (i = 0; i < 100 && ss[i] != 0; i++)
- {
- if (ss[i] == '\"' || ss[i] == '\\') *p++ = '\\';
- *p++ = ss[i];
- }
- *p++ = '\"';
- *p = 0;
- s = string_append(s, &size, &ptr, 2, US" C=", big_buffer);
- }
+ #ifdef EXPERIMENTAL_PRDR
+ if (addr->flags & af_prdr_used)
+ s = string_append(s, &size, &ptr, 1, US" PRDR");
+ #endif
+ }
+
+/* confirmation message (SMTP (host_used) and LMTP (driver_name)) */
+
+if ((log_extra_selector & LX_smtp_confirmation) != 0 &&
+ addr->message != NULL &&
+ ((addr->host_used != NULL) || (Ustrcmp(addr->transport->driver_name, "lmtp") == 0)))
+ {
+ int i;
+ uschar *p = big_buffer;
+ uschar *ss = addr->message;
+ *p++ = '\"';
+ for (i = 0; i < 100 && ss[i] != 0; i++)
+ {
+ if (ss[i] == '\"' || ss[i] == '\\') *p++ = '\\';
+ *p++ = ss[i];
+ }
+ *p++ = '\"';
+ *p = 0;
+ s = string_append(s, &size, &ptr, 2, US" C=", big_buffer);
}
/* Time on queue and actual time taken to deliver */
s[ptr] = 0;
log_write(0, flags, "%s", s);
+
+#ifdef EXPERIMENTAL_TPDA
+if (addr->transport->tpda_delivery_action)
+ {
+ DEBUG(D_deliver)
+ debug_printf(" TPDA(Delivery): tpda_deliver_action=|%s| tpda_delivery_IP=%s\n",
+ addr->transport->tpda_delivery_action, tpda_delivery_ip);
+
+ router_name = addr->router->name;
+ transport_name = addr->transport->name;
+ if (!expand_string(addr->transport->tpda_delivery_action) && *expand_string_message)
+ log_write(0, LOG_MAIN|LOG_PANIC, "failed to expand tpda_deliver_action in %s: %s\n",
+ transport_name, expand_string_message);
+ router_name = NULL;
+ transport_name = NULL;
+ }
+#endif
store_reset(reset_point);
return;
}
if (((Ustrstr(addr->message, "failed to expand") != NULL) || (Ustrstr(addr->message, "expansion of ") != NULL)) &&
(Ustrstr(addr->message, "mysql") != NULL ||
Ustrstr(addr->message, "pgsql") != NULL ||
+#ifdef EXPERIMENTAL_REDIS
+ Ustrstr(addr->message, "redis") != NULL ||
+#endif
Ustrstr(addr->message, "sqlite") != NULL ||
Ustrstr(addr->message, "ldap:") != NULL ||
Ustrstr(addr->message, "ldapdn:") != NULL ||
if (used_return_path != NULL &&
(log_extra_selector & LX_return_path_on_delivery) != 0)
- {
s = string_append(s, &size, &ptr, 3, US" P=<", used_return_path, US">");
- }
if (addr->router != NULL)
s = string_append(s, &size, &ptr, 2, US" R=", addr->router->name);
s = string_append(s, &size, &ptr, 2, US" T=", addr->transport->name);
if (addr->host_used != NULL)
- s = string_append(s, &size, &ptr, 5, US" H=", addr->host_used->name,
- US" [", addr->host_used->address, US"]");
+ s = d_hostlog(s, &size, &ptr, addr);
+
+ #ifdef SUPPORT_TLS
+ s = d_tlslog(s, &size, &ptr, addr);
+ #endif
if (addr->basic_errno > 0)
s = string_append(s, &size, &ptr, 2, US": ",
set_process_info("delivering %s to %s using %s", message_id,
addr->local_part, addr->transport->name);
+ /* Setting this global in the subprocess means we need never clear it */
+ transport_name = addr->transport->name;
+
/* If a transport filter has been specified, set up its argument list.
Any errors will get put into the address, and FALSE yielded. */
to do, which is for the ultimate address timeout. */
if (!ok)
- {
- retry_config *retry =
- retry_find_config(retry_key+2, addr2->domain,
- retry_record->basic_errno,
- 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)
- {
- retry_rule *last_rule;
- for (last_rule = retry->rules;
- last_rule->next != NULL;
- last_rule = last_rule->next);
- DEBUG(D_deliver|D_retry)
- 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
- {
- DEBUG(D_deliver|D_retry)
- debug_printf("no retry rule found: assume timed out\n");
- ok = TRUE; /* No rule => timed out */
- }
-
- DEBUG(D_deliver|D_retry)
- {
- if (ok) debug_printf("on queue longer than maximum retry for "
- "address - allowing delivery\n");
- }
- }
+ ok = retry_ultimate_address_timeout(retry_key, addr2->domain,
+ retry_record, now);
}
}
else DEBUG(D_retry) debug_printf("no retry record exists\n");
while (*ptr++);
break;
+#ifdef EXPERIMENTAL_PRDR
+ case 'P':
+ addr->flags |= af_prdr_used; break;
+#endif
+
case 'A':
if (addr == NULL)
{
int fd = pfd[pipe_write];
host_item *h;
- /* There are weird circumstances in which logging is disabled */
+ /* Setting this global in the subprocess means we need never clear it */
+ transport_name = tp->name;
+ /* There are weird circumstances in which logging is disabled */
disable_logging = tp->disable_logging;
/* Show pids on debug output if parallelism possible */
rmt_dlv_checked_write(fd, big_buffer, ptr - big_buffer);
}
+ #ifdef EXPERIMENTAL_PRDR
+ if (addr->flags & af_prdr_used) rmt_dlv_checked_write(fd, "P", 1);
+ #endif
+
/* Retry information: for most success cases this will be null. */
for (r = addr->retries; r != NULL; r = r->next)
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. */
+ used to cause this to happen, so it is best to be on the safe side.
+
+ Even if we haven't reached the retry time in the hints, there is one more
+ check to do, which is for the ultimate address timeout. We only do this
+ check if there is an address retry record and there is not a domain retry
+ record; this implies that previous attempts to handle the address had the
+ retry_use_local_parts option turned on. We use this as an approximation
+ for the destination being like a local delivery, for example delivery over
+ LMTP to an IMAP message store. In this situation users are liable to bump
+ into their quota and thereby have intermittently successful deliveries,
+ which keep the retry record fresh, which can lead to us perpetually
+ deferring messages. */
else if (((queue_running && !deliver_force) || continue_hostname != NULL)
&&
||
(address_retry_record != NULL &&
now < address_retry_record->next_try))
- )
+ &&
+ (domain_retry_record != NULL ||
+ address_retry_record == NULL ||
+ !retry_ultimate_address_timeout(addr->address_retry_key,
+ addr->domain, address_retry_record, now)))
{
addr->message = US"retry time not reached";
addr->basic_errno = ERRNO_RRETRY;
regex_must_compile(US"\\n250[\\s\\-]STARTTLS(\\s|\\n|$)", FALSE, TRUE);
#endif
+ #ifdef EXPERIMENTAL_PRDR
+ if (regex_PRDR == NULL) regex_PRDR =
+ regex_must_compile(US"\\n250[\\s\\-]PRDR(\\s|\\n|$)", FALSE, TRUE);
+ #endif
+
/* Now sort the addresses if required, and do the deliveries. The yield of
do_remote_deliveries is FALSE when mua_wrapper is set and all addresses
cannot be delivered in one transaction. */
return final_yield;
}
+/* vi: aw ai sw=2
+*/
/* End of deliver.c */