summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/src/EDITME4
-rw-r--r--src/src/config.h.defaults1
-rw-r--r--src/src/deliver.c40
-rw-r--r--src/src/exim.c3
-rw-r--r--src/src/expand.c10
-rw-r--r--src/src/globals.c11
-rw-r--r--src/src/globals.h12
-rw-r--r--src/src/structs.h3
-rw-r--r--src/src/transport.c4
-rw-r--r--src/src/transports/smtp.c76
-rw-r--r--src/src/transports/smtp.h3
11 files changed, 166 insertions, 1 deletions
diff --git a/src/src/EDITME b/src/src/EDITME
index e29c1eb25..1db70f715 100644
--- a/src/src/EDITME
+++ b/src/src/EDITME
@@ -469,6 +469,10 @@ EXIM_MONITOR=eximon.bin
# Uncomment the following line to add Per-Recipient-Data-Response support.
# EXPERIMENTAL_PRDR=yes
+# Uncomment the following line to support Transport post-delivery actions,
+# eg. for logging to a database.
+# EXPERIMENTAL_TPDA=yes
+
###############################################################################
# THESE ARE THINGS YOU MIGHT WANT TO SPECIFY #
diff --git a/src/src/config.h.defaults b/src/src/config.h.defaults
index 1594f6858..bf7ac63fb 100644
--- a/src/src/config.h.defaults
+++ b/src/src/config.h.defaults
@@ -170,6 +170,7 @@ it's a default value. */
#define EXPERIMENTAL_PRDR
#define EXPERIMENTAL_SPF
#define EXPERIMENTAL_SRS
+#define EXPERIMENTAL_TPDA
/* For developers */
#define WANT_DEEPER_PRINTF_CHECKS
diff --git a/src/src/deliver.c b/src/src/deliver.c
index 23e63d553..bc6a69fbf 100644
--- a/src/src/deliver.c
+++ b/src/src/deliver.c
@@ -695,6 +695,15 @@ the log line, and reset the store afterwards. Remote deliveries should always
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);
@@ -741,7 +750,12 @@ if ((log_extra_selector & LX_delivery_size) != 0)
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));
@@ -760,6 +774,15 @@ else
addr->host_used->port));
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
@@ -827,6 +850,23 @@ store we used to build the line after writing it. */
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;
}
diff --git a/src/src/exim.c b/src/src/exim.c
index 8ab0456d8..c5053ba7c 100644
--- a/src/src/exim.c
+++ b/src/src/exim.c
@@ -825,6 +825,9 @@ fprintf(f, "Support for:");
#ifdef EXPERIMENTAL_PRDR
fprintf(f, " Experimental_PRDR");
#endif
+#ifdef EXPERIMENTAL_TPDA
+ fprintf(f, " Experimental_TPDA");
+#endif
fprintf(f, "\n");
fprintf(f, "Lookups (built-in):");
diff --git a/src/src/expand.c b/src/src/expand.c
index edef45dba..a22ee2af4 100644
--- a/src/src/expand.c
+++ b/src/src/expand.c
@@ -677,6 +677,16 @@ static var_entry var_table[] = {
{ "tod_logfile", vtype_todlf, NULL },
{ "tod_zone", vtype_todzone, NULL },
{ "tod_zulu", vtype_todzulu, NULL },
+#ifdef EXPERIMENTAL_TPDA
+ { "tpda_defer_errno", vtype_int, &tpda_defer_errno },
+ { "tpda_defer_errstr", vtype_stringptr, &tpda_defer_errstr },
+ { "tpda_delivery_confirmation", vtype_stringptr, &tpda_delivery_confirmation },
+ { "tpda_delivery_domain", vtype_stringptr, &tpda_delivery_domain },
+ { "tpda_delivery_fqdn", vtype_stringptr, &tpda_delivery_fqdn },
+ { "tpda_delivery_ip", vtype_stringptr, &tpda_delivery_ip },
+ { "tpda_delivery_local_part",vtype_stringptr,&tpda_delivery_local_part },
+ { "tpda_delivery_port", vtype_int, &tpda_delivery_port },
+#endif
{ "transport_name", vtype_stringptr, &transport_name },
{ "value", vtype_stringptr, &lookup_value },
{ "version_number", vtype_stringptr, &version_string },
diff --git a/src/src/globals.c b/src/src/globals.c
index 05bb0ae86..d4589cd18 100644
--- a/src/src/globals.c
+++ b/src/src/globals.c
@@ -1280,6 +1280,17 @@ int thismessage_size_limit = 0;
int timeout_frozen_after = 0;
BOOL timestamps_utc = FALSE;
+#ifdef EXPERIMENTAL_TPDA
+int tpda_defer_errno = 0;
+uschar *tpda_defer_errstr = NULL;
+uschar *tpda_delivery_ip = NULL;
+int tpda_delivery_port = 0;
+uschar *tpda_delivery_fqdn = NULL;
+uschar *tpda_delivery_local_part= NULL;
+uschar *tpda_delivery_domain = NULL;
+uschar *tpda_delivery_confirmation = NULL;
+#endif
+
transport_instance *transports = NULL;
transport_instance transport_defaults = {
diff --git a/src/src/globals.h b/src/src/globals.h
index 2cc16881b..104b5fa7a 100644
--- a/src/src/globals.h
+++ b/src/src/globals.h
@@ -834,6 +834,18 @@ extern int test_harness_load_avg; /* For use when testing */
extern int thismessage_size_limit; /* Limit for this message */
extern int timeout_frozen_after; /* Max time to keep frozen messages */
extern BOOL timestamps_utc; /* Use UTC for all times */
+
+#ifdef EXPERIMENTAL_TPDA
+extern int tpda_defer_errno; /* error number set when a remote delivery is deferred with a host error */
+extern uschar *tpda_defer_errstr; /* error string set when a remote delivery is deferred with a host error */
+extern uschar *tpda_delivery_ip; /* IP of host, which has accepted delivery */
+extern int tpda_delivery_port; /* port of host, which has accepted delivery */
+extern uschar *tpda_delivery_fqdn; /* FQDN of host, which has accepted delivery */
+extern uschar *tpda_delivery_local_part;/* local part of address being delivered */
+extern uschar *tpda_delivery_domain; /* domain part of address being delivered */
+extern uschar *tpda_delivery_confirmation; /* SMTP confirmation message */
+#endif
+
extern uschar *transport_name; /* Name of transport last started */
extern int transport_count; /* Count of bytes transported */
extern int transport_newlines; /* Accurate count of number of newline chars transported */
diff --git a/src/src/structs.h b/src/src/structs.h
index 53aa2106b..baf9a0f85 100644
--- a/src/src/structs.h
+++ b/src/src/structs.h
@@ -184,6 +184,9 @@ typedef struct transport_instance {
BOOL log_fail_output;
BOOL log_defer_output;
BOOL retry_use_local_part; /* Defaults true for local, false for remote */
+#ifdef EXPERIMENTAL_TPDA
+ uschar *tpda_delivery_action; /* String to expand on success */
+#endif
} transport_instance;
diff --git a/src/src/transport.c b/src/src/transport.c
index 7dd1afb85..d2540be62 100644
--- a/src/src/transport.c
+++ b/src/src/transport.c
@@ -94,6 +94,10 @@ optionlist optionlist_transports[] = {
(void *)offsetof(transport_instance, shadow_condition) },
{ "shadow_transport", opt_stringptr|opt_public,
(void *)offsetof(transport_instance, shadow) },
+#ifdef EXPERIMENTAL_TPDA
+ { "tpda_delivery_action",opt_stringptr | opt_public,
+ (void *)offsetof(transport_instance, tpda_delivery_action) },
+#endif
{ "transport_filter", opt_stringptr|opt_public,
(void *)offsetof(transport_instance, filter_command) },
{ "transport_filter_timeout", opt_time|opt_public,
diff --git a/src/src/transports/smtp.c b/src/src/transports/smtp.c
index b18720cc0..9918f3116 100644
--- a/src/src/transports/smtp.c
+++ b/src/src/transports/smtp.c
@@ -156,6 +156,10 @@ optionlist smtp_transport_options[] = {
{ "tls_verify_certificates", opt_stringptr,
(void *)offsetof(smtp_transport_options_block, tls_verify_certificates) }
#endif
+#ifdef EXPERIMENTAL_TPDA
+ ,{ "tpda_host_defer_action", opt_stringptr,
+ (void *)offsetof(smtp_transport_options_block, tpda_host_defer_action) },
+#endif
};
/* Size of the options list. An extern variable has to be used so that its
@@ -233,6 +237,9 @@ smtp_transport_options_block smtp_transport_option_defaults = {
NULL, /* dkim_sign_headers */
NULL /* dkim_strict */
#endif
+#ifdef EXPERIMENTAL_TPDA
+ ,NULL /* tpda_host_defer_action */
+#endif
};
@@ -577,6 +584,59 @@ else
+#ifdef EXPERIMENTAL_TPDA
+/*************************************************
+* Post-defer action *
+*************************************************/
+
+/* This expands an arbitrary per-transport string.
+ It might, for example, be used to write to the database log.
+
+Arguments:
+ ob transport options block
+ addr the address item containing error information
+ host the current host
+
+Returns: nothing
+*/
+
+static void
+tpda_deferred(smtp_transport_options_block *ob, address_item *addr, host_item *host)
+{
+uschar *action = ob->tpda_host_defer_action;
+if (!action)
+ return;
+
+tpda_delivery_ip = string_copy(host->address);
+tpda_delivery_port = (host->port == PORT_NONE)? 25 : host->port;
+tpda_delivery_fqdn = string_copy(host->name);
+tpda_delivery_local_part = string_copy(addr->local_part);
+tpda_delivery_domain = string_copy(addr->domain);
+tpda_defer_errno = addr->basic_errno;
+
+tpda_defer_errstr = addr->message
+ ? addr->basic_errno > 0
+ ? string_sprintf("%s: %s", addr->message, strerror(addr->basic_errno))
+ : string_copy(addr->message)
+ : addr->basic_errno > 0
+ ? string_copy(strerror(addr->basic_errno))
+ : NULL;
+
+DEBUG(D_transport)
+ debug_printf(" TPDA(host defer): tpda_host_defer_action=|%s| tpda_delivery_IP=%s\n",
+ action, tpda_delivery_ip);
+
+router_name = addr->router->name;
+transport_name = addr->transport->name;
+if (!expand_string(action) && *expand_string_message)
+ log_write(0, LOG_MAIN|LOG_PANIC, "failed to expand tpda_defer_action in %s: %s\n",
+ transport_name, expand_string_message);
+router_name = transport_name = NULL;
+}
+#endif
+
+
+
/*************************************************
* Synchronize SMTP responses *
*************************************************/
@@ -1912,7 +1972,12 @@ if (!ok) ok = TRUE; else
/* Set up confirmation if needed - applies only to SMTP */
- if ((log_extra_selector & LX_smtp_confirmation) != 0 && !lmtp)
+ if (
+ #ifndef EXPERIMENTAL_TPDA
+ (log_extra_selector & LX_smtp_confirmation) != 0 &&
+ #endif
+ !lmtp
+ )
{
uschar *s = string_printing(buffer);
conf = (s == buffer)? (uschar *)string_copy(s) : s;
@@ -3051,6 +3116,11 @@ for (cutoff_retry = 0; expired &&
first_addr->basic_errno != ERRNO_TLSFAILURE)
write_logs(first_addr, host);
+ #ifdef EXPERIMENTAL_TPDA
+ if (rc == DEFER)
+ tpda_deferred(ob, first_addr, host);
+ #endif
+
/* If STARTTLS was accepted, but there was a failure in setting up the
TLS session (usually a certificate screwup), and the host is not in
hosts_require_tls, and tls_tempfail_tryclear is true, try again, with
@@ -3073,6 +3143,10 @@ for (cutoff_retry = 0; expired &&
expanded_hosts != NULL, &message_defer, TRUE);
if (rc == DEFER && first_addr->basic_errno != ERRNO_AUTHFAIL)
write_logs(first_addr, host);
+ #ifdef EXPERIMENTAL_TPDA
+ if (rc == DEFER)
+ tpda_deferred(ob, first_addr, host);
+ #endif
}
#endif
}
diff --git a/src/src/transports/smtp.h b/src/src/transports/smtp.h
index 8e85294bc..0d8801647 100644
--- a/src/src/transports/smtp.h
+++ b/src/src/transports/smtp.h
@@ -73,6 +73,9 @@ typedef struct {
uschar *dkim_sign_headers;
uschar *dkim_strict;
#endif
+ #ifdef EXPERIMENTAL_TPDA
+ uschar *tpda_host_defer_action;
+ #endif
} smtp_transport_options_block;
/* Data for reading the private options. */