X-Git-Url: https://git.netwichtig.de/gitweb/?a=blobdiff_plain;f=src%2Fsrc%2Fdeliver.c;h=b5aa9b9a75d1a211622ca73b0a3b75dc6ad3f9f3;hb=dadff1d47e54962b0fdf98e8ce5cef42b6cb7fb5;hp=afbadca6a53e8e472015a08bda62c3be5ef96ea1;hpb=aeaf5db33f20a06399b8b15630cd2f5e9755e38a;p=user%2Fhenk%2Fcode%2Fexim.git diff --git a/src/src/deliver.c b/src/src/deliver.c index afbadca6a..b5aa9b9a7 100644 --- a/src/src/deliver.c +++ b/src/src/deliver.c @@ -2,13 +2,14 @@ * Exim - an Internet mail transport agent * *************************************************/ -/* Copyright (c) University of Cambridge 1995 - 2014 */ +/* Copyright (c) University of Cambridge 1995 - 2015 */ /* See the file NOTICE for conditions of use and distribution. */ /* The main code for delivering a message. */ #include "exim.h" +#include /* Data block for keeping track of subprocesses for parallel remote @@ -127,7 +128,7 @@ deliver_set_expansions(address_item *addr) { if (addr == NULL) { - uschar ***p = address_expansions; + const uschar ***p = address_expansions; while (*p != NULL) **p++ = NULL; return; } @@ -149,9 +150,9 @@ else } deliver_recipients = addr; -deliver_address_data = addr->p.address_data; -deliver_domain_data = addr->p.domain_data; -deliver_localpart_data = addr->p.localpart_data; +deliver_address_data = addr->prop.address_data; +deliver_domain_data = addr->prop.domain_data; +deliver_localpart_data = addr->prop.localpart_data; /* These may be unset for multiple addresses */ @@ -676,40 +677,78 @@ while (addr->parent != NULL) +/************************************************* +* Delivery logging support functions * +*************************************************/ + +/* The LOGGING() checks in d_log_interface() are complicated for backwards +compatibility. When outgoing interface logging was originally added, it was +conditional on just incoming_interface (which is off by default). The +outgoing_interface option is on by default to preserve this behaviour, but +you can enable incoming_interface and disable outgoing_interface to get I= +fields on incoming lines only. + +Arguments: + s The log line buffer + sizep Pointer to the buffer size + ptrp Pointer to current index into buffer + addr The address to be logged + +Returns: New value for s +*/ + +static uschar * +d_log_interface(uschar *s, int *sizep, int *ptrp) +{ +if (LOGGING(incoming_interface) && LOGGING(outgoing_interface) + && sending_ip_address != NULL) + { + s = string_append(s, sizep, ptrp, 2, US" I=[", sending_ip_address); + if (LOGGING(outgoing_port)) + s = string_append(s, sizep, ptrp, 2, US"]:", + string_sprintf("%d", sending_port)); + else + s = string_cat(s, sizep, ptrp, "]", 1); + } +return s; +} + + static uschar * -d_hostlog(uschar * s, int * sizep, int * ptrp, address_item * addr) +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; +s = string_append(s, sizep, ptrp, 5, US" H=", addr->host_used->name, + US" [", addr->host_used->address, US"]"); +if (LOGGING(outgoing_port)) + s = string_append(s, sizep, ptrp, 2, US":", string_sprintf("%d", + addr->host_used->port)); +return d_log_interface(s, sizep, ptrp); } + + #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) - ? +if (LOGGING(tls_cipher) && addr->cipher != NULL) + s = string_append(s, sizep, ptrp, 2, US" X=", addr->cipher); +if (LOGGING(tls_certificate_verified) && addr->cipher != NULL) + s = string_append(s, sizep, ptrp, 2, US" CV=", + testflag(addr, af_cert_verified) + ? #ifdef EXPERIMENTAL_DANE - testflag(addr, af_dane_verified) - ? "dane" - : + testflag(addr, af_dane_verified) + ? "dane" + : #endif - "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; + "yes" + : "no"); +if (LOGGING(tls_peerdn) && addr->peerdn != NULL) + s = string_append(s, sizep, ptrp, 3, US" DN=\"", + string_printing(addr->peerdn), US"\""); +return s; } #endif @@ -718,7 +757,7 @@ d_tlslog(uschar * s, int * sizep, int * ptrp, address_item * addr) #ifdef EXPERIMENTAL_EVENT uschar * -event_raise(uschar * action, uschar * event, uschar * ev_data) +event_raise(uschar * action, const uschar * event, uschar * ev_data) { uschar * s; if (action) @@ -752,11 +791,11 @@ return NULL; } static void -msg_event_raise(uschar * event, address_item * addr) +msg_event_raise(const uschar * event, const address_item * addr) { -uschar * save_domain = deliver_domain; +const uschar * save_domain = deliver_domain; uschar * save_local = deliver_localpart; -uschar * save_host = deliver_host; +const uschar * save_host = deliver_host; if (!addr->transport) return; @@ -808,7 +847,7 @@ pointer to a single host item in their host list, for use by the transport. */ s = reset_point = store_get(size); -log_address = string_log_address(addr, (log_write_selector & L_all_parents) != 0, TRUE); +log_address = string_log_address(addr, LOGGING(all_parents), TRUE); if (msg) s = string_append(s, &size, &ptr, 3, host_and_ident(TRUE), US" ", log_address); else @@ -817,16 +856,19 @@ else s = string_append(s, &size, &ptr, 2, US"> ", log_address); } -if (log_extra_selector & LX_incoming_interface && sending_ip_address) - s = string_append(s, &size, &ptr, 3, US" I=[", sending_ip_address, US"]"); - /* for the port: string_sprintf("%d", sending_port) */ - -if ((log_extra_selector & LX_sender_on_delivery) != 0 || msg) - s = string_append(s, &size, &ptr, 3, US" F=<", sender_address, US">"); +if (LOGGING(sender_on_delivery) || msg) + s = string_append(s, &size, &ptr, 3, US" F=<", +#ifdef EXPERIMENTAL_INTERNATIONAL + testflag(addr, af_utf8_downcvt) + ? string_address_utf8_to_alabel(sender_address, NULL) + : +#endif + sender_address, + US">"); #ifdef EXPERIMENTAL_SRS -if(addr->p.srs_sender) - s = string_append(s, &size, &ptr, 3, US" SRS=<", addr->p.srs_sender, US">"); +if(addr->prop.srs_sender) + s = string_append(s, &size, &ptr, 3, US" SRS=<", addr->prop.srs_sender, US">"); #endif /* You might think that the return path must always be set for a successful @@ -834,8 +876,7 @@ delivery; indeed, I did for some time, until this statement crashed. The case when it is not set is for a delivery to /dev/null which is optimised by not being run at all. */ -if (used_return_path != NULL && - (log_extra_selector & LX_return_path_on_delivery) != 0) +if (used_return_path != NULL && LOGGING(return_path_on_delivery)) s = string_append(s, &size, &ptr, 3, US" P=<", used_return_path, US">"); if (msg) @@ -847,7 +888,7 @@ if (addr->router != NULL) s = string_append(s, &size, &ptr, 2, US" T=", addr->transport->name); -if ((log_extra_selector & LX_delivery_size) != 0) +if (LOGGING(delivery_size)) s = string_append(s, &size, &ptr, 2, US" S=", string_sprintf("%d", transport_count)); @@ -857,6 +898,7 @@ if (addr->transport->info->local) { if (addr->host_list) s = string_append(s, &size, &ptr, 2, US" H=", addr->host_list->name); + s = d_log_interface(s, &size, &ptr); if (addr->shadow_message != NULL) s = string_cat(s, &size, &ptr, addr->shadow_message, Ustrlen(addr->shadow_message)); @@ -894,7 +936,7 @@ else if (addr->auth_id) { s = string_append(s, &size, &ptr, 2, US":", addr->auth_id); - if (log_extra_selector & LX_smtp_mailauth && addr->auth_sndr) + if (LOGGING(smtp_mailauth) && addr->auth_sndr) s = string_append(s, &size, &ptr, 2, US":", addr->auth_sndr); } } @@ -907,15 +949,15 @@ else /* confirmation message (SMTP (host_used) and LMTP (driver_name)) */ -if (log_extra_selector & LX_smtp_confirmation && - addr->message && +if (LOGGING(smtp_confirmation) && addr->message && (addr->host_used || Ustrcmp(addr->transport->driver_name, "lmtp") == 0)) { - int i; + unsigned i; + unsigned lim = big_buffer_size < 1024 ? big_buffer_size : 1024; uschar *p = big_buffer; uschar *ss = addr->message; *p++ = '\"'; - for (i = 0; i < 256 && ss[i] != 0; i++) /* limit logged amount */ + for (i = 0; i < lim && ss[i] != 0; i++) /* limit logged amount */ { if (ss[i] == '\"' || ss[i] == '\\') *p++ = '\\'; /* quote \ and " */ *p++ = ss[i]; @@ -927,11 +969,11 @@ if (log_extra_selector & LX_smtp_confirmation && /* Time on queue and actual time taken to deliver */ -if ((log_extra_selector & LX_queue_time) != 0) +if (LOGGING(queue_time)) s = string_append(s, &size, &ptr, 2, US" QT=", readconf_printtime( (int) ((long)time(NULL) - (long)received_time)) ); -if ((log_extra_selector & LX_deliver_time) != 0) +if (LOGGING(deliver_time)) s = string_append(s, &size, &ptr, 2, US" DT=", readconf_printtime(addr->more_errno)); @@ -1018,7 +1060,10 @@ malformed, it won't ever have gone near LDAP.) */ if (addr->message != NULL) { - addr->message = string_printing(addr->message); + const uschar * s = string_printing(addr->message); + if (s != addr->message) + addr->message = US s; + /* deconst cast ok as string_printing known to have alloc'n'copied */ if (((Ustrstr(addr->message, "failed to expand") != NULL) || (Ustrstr(addr->message, "expansion of ") != NULL)) && (Ustrstr(addr->message, "mysql") != NULL || Ustrstr(addr->message, "pgsql") != NULL || @@ -1075,11 +1120,12 @@ if (addr->return_file >= 0 && addr->return_filename != NULL) if (s != NULL) { uschar *p = big_buffer + Ustrlen(big_buffer); + const uschar * sp; while (p > big_buffer && isspace(p[-1])) p--; *p = 0; - s = string_printing(big_buffer); + sp = string_printing(big_buffer); log_write(0, LOG_MAIN, "<%s>: %s transport output: %s", - addr->address, tb->name, s); + addr->address, tb->name, sp); } (void)fclose(f); } @@ -1088,7 +1134,7 @@ if (addr->return_file >= 0 && addr->return_filename != NULL) /* Handle returning options, but only if there is an address to return the text to. */ - if (sender_address[0] != 0 || addr->p.errors_address != NULL) + if (sender_address[0] != 0 || addr->prop.errors_address != NULL) { if (tb->return_output) { @@ -1158,16 +1204,8 @@ if (result == OK) delivery_log(LOG_MAIN, addr, logchar, NULL); #ifdef SUPPORT_TLS - if (tls_out.ourcert) - { - tls_free_cert(tls_out.ourcert); - tls_out.ourcert = NULL; - } - if (tls_out.peercert) - { - tls_free_cert(tls_out.peercert); - tls_out.peercert = NULL; - } + tls_free_cert(&tls_out.ourcert); + tls_free_cert(&tls_out.peercert); tls_out.cipher = NULL; tls_out.peerdn = NULL; tls_out.ocsp = OCSP_NOT_REQ; @@ -1226,8 +1264,7 @@ else if (result == DEFER || result == PANIC) /* Create the address string for logging. Must not do this earlier, because an OK result may be changed to FAIL when a pipe returns text. */ - log_address = string_log_address(addr, - (log_write_selector & L_all_parents) != 0, result == OK); + log_address = string_log_address(addr, LOGGING(all_parents), result == OK); s = string_cat(s, &size, &ptr, log_address, Ustrlen(log_address)); @@ -1305,7 +1342,7 @@ else if (!testflag(addr, af_ignore_error) && (addr->special_action == SPECIAL_FREEZE || - (sender_address[0] == 0 && addr->p.errors_address == NULL) + (sender_address[0] == 0 && addr->prop.errors_address == NULL) )) { frozen_info = (addr->special_action == SPECIAL_FREEZE)? US"" : @@ -1338,18 +1375,16 @@ else /* Create the address string for logging. Must not do this earlier, because an OK result may be changed to FAIL when a pipe returns text. */ - log_address = string_log_address(addr, - (log_write_selector & L_all_parents) != 0, result == OK); + log_address = string_log_address(addr, LOGGING(all_parents), result == OK); s = string_cat(s, &size, &ptr, log_address, Ustrlen(log_address)); - if ((log_extra_selector & LX_sender_on_delivery) != 0) + if (LOGGING(sender_on_delivery)) s = string_append(s, &size, &ptr, 3, US" F=<", sender_address, US">"); /* Return path may not be set if no delivery actually happened */ - if (used_return_path != NULL && - (log_extra_selector & LX_return_path_on_delivery) != 0) + if (used_return_path != NULL && LOGGING(return_path_on_delivery)) s = string_append(s, &size, &ptr, 3, US" P=<", used_return_path, US">"); if (addr->router != NULL) @@ -1805,11 +1840,11 @@ transport_instance *tp = addr->transport; /* Set up the return path from the errors or sender address. If the transport has its own return path setting, expand it and replace the existing value. */ -if(addr->p.errors_address != NULL) - return_path = addr->p.errors_address; +if(addr->prop.errors_address != NULL) + return_path = addr->prop.errors_address; #ifdef EXPERIMENTAL_SRS -else if(addr->p.srs_sender != NULL) - return_path = addr->p.srs_sender; +else if(addr->prop.srs_sender != NULL) + return_path = addr->prop.srs_sender; #endif else return_path = sender_address; @@ -2421,9 +2456,9 @@ while (addr_local != NULL) (addr->flags & (af_pfr|af_file)) == (next->flags & (af_pfr|af_file)) && (!uses_lp || Ustrcmp(next->local_part, addr->local_part) == 0) && (!uses_dom || Ustrcmp(next->domain, addr->domain) == 0) && - same_strings(next->p.errors_address, addr->p.errors_address) && - same_headers(next->p.extra_headers, addr->p.extra_headers) && - same_strings(next->p.remove_headers, addr->p.remove_headers) && + same_strings(next->prop.errors_address, addr->prop.errors_address) && + same_headers(next->prop.extra_headers, addr->prop.extra_headers) && + same_strings(next->prop.remove_headers, addr->prop.remove_headers) && same_ugid(tp, addr, next) && ((addr->host_list == NULL && next->host_list == NULL) || (addr->host_list != NULL && next->host_list != NULL && @@ -2779,7 +2814,7 @@ sort_remote_deliveries(void) { int sep = 0; address_item **aptr = &addr_remote; -uschar *listptr = remote_sort_domains; +const uschar *listptr = remote_sort_domains; uschar *pattern; uschar patbuf[256]; @@ -2794,7 +2829,7 @@ while (*aptr != NULL && { address_item **next; deliver_domain = (*aptr)->domain; /* set $domain */ - if (match_isinlist(deliver_domain, &pattern, UCHAR_MAX+1, + if (match_isinlist(deliver_domain, (const uschar **)&pattern, UCHAR_MAX+1, &domainlist_anchor, NULL, MCL_DOMAIN, TRUE, NULL) == OK) { aptr = &((*aptr)->next); @@ -2804,7 +2839,7 @@ while (*aptr != NULL && next = &((*aptr)->next); while (*next != NULL && (deliver_domain = (*next)->domain, /* Set $domain */ - match_isinlist(deliver_domain, &pattern, UCHAR_MAX+1, + match_isinlist(deliver_domain, (const uschar **)&pattern, UCHAR_MAX+1, &domainlist_anchor, NULL, MCL_DOMAIN, TRUE, NULL)) != OK) next = &((*next)->next); @@ -3123,15 +3158,17 @@ while (!done) break; case '2': - addr->peercert = NULL; if (*ptr) (void) tls_import_cert(ptr, &addr->peercert); + else + addr->peercert = NULL; break; case '3': - addr->ourcert = NULL; if (*ptr) (void) tls_import_cert(ptr, &addr->ourcert); + else + addr->ourcert = NULL; break; # ifndef DISABLE_OCSP @@ -3227,7 +3264,7 @@ while (!done) case 'I': if (*ptr) sending_ip_address = string_copy(ptr); while (*ptr++) ; - if (*ptr) sending_port = atoi(ptr); + if (*ptr) sending_port = atoi(CS ptr); while (*ptr++) ; break; @@ -3945,13 +3982,13 @@ for (delivery_count = 0; addr_remote != NULL; delivery_count++) if ( (multi_domain || Ustrcmp(next->domain, addr->domain) == 0) && tp == next->transport && same_hosts(next->host_list, addr->host_list) - && same_strings(next->p.errors_address, addr->p.errors_address) - && same_headers(next->p.extra_headers, addr->p.extra_headers) + && same_strings(next->prop.errors_address, addr->prop.errors_address) + && same_headers(next->prop.extra_headers, addr->prop.extra_headers) && same_ugid(tp, next, addr) - && ( next->p.remove_headers == addr->p.remove_headers - || ( next->p.remove_headers != NULL - && addr->p.remove_headers != NULL - && Ustrcmp(next->p.remove_headers, addr->p.remove_headers) == 0 + && ( next->prop.remove_headers == addr->prop.remove_headers + || ( next->prop.remove_headers + && addr->prop.remove_headers + && Ustrcmp(next->prop.remove_headers, addr->prop.remove_headers) == 0 ) ) && ( !multi_domain || ( ( @@ -3995,11 +4032,11 @@ for (delivery_count = 0; addr_remote != NULL; delivery_count++) /* Compute the return path, expanding a new one if required. The old one must be set first, as it might be referred to in the expansion. */ - if(addr->p.errors_address != NULL) - return_path = addr->p.errors_address; + if(addr->prop.errors_address != NULL) + return_path = addr->prop.errors_address; #ifdef EXPERIMENTAL_SRS - else if(addr->p.srs_sender != NULL) - return_path = addr->p.srs_sender; + else if(addr->prop.srs_sender != NULL) + return_path = addr->prop.srs_sender; #endif else return_path = sender_address; @@ -4443,7 +4480,7 @@ for (delivery_count = 0; addr_remote != NULL; delivery_count++) } /* Local interface address/port */ - if (log_extra_selector & LX_incoming_interface && sending_ip_address) + if (LOGGING(incoming_interface) && sending_ip_address) { uschar * ptr = big_buffer; sprintf(CS ptr, "%.128s", sending_ip_address); @@ -4580,7 +4617,7 @@ if (percent_hack_domains != NULL) deliver_domain = addr->domain; /* set $domain */ - while ((rc = match_isinlist(deliver_domain, &percent_hack_domains, 0, + while ((rc = match_isinlist(deliver_domain, (const uschar **)&percent_hack_domains, 0, &domainlist_anchor, addr->domain_cache, MCL_DOMAIN, TRUE, NULL)) == OK && (t = Ustrrchr(local_part, '%')) != NULL) @@ -4803,15 +4840,12 @@ print_address_error(address_item *addr, FILE *f, uschar *t) int count = Ustrlen(t); uschar *s = testflag(addr, af_pass_message)? addr->message : NULL; -if (s == NULL) - { - if (addr->user_message != NULL) s = addr->user_message; else return; - } +if (!s && !(s = addr->user_message)) + return; fprintf(f, "\n %s", t); -while (*s != 0) - { +while (*s) if (*s == '\\' && s[1] == 'n') { fprintf(f, "\n "); @@ -4828,7 +4862,6 @@ while (*s != 0) count = 0; } } - } } @@ -4840,9 +4873,9 @@ while (*s != 0) a bounce or a warning message. It tries to format the message reasonably as required by RFC 3461 by adding a space after each newline -we assume that this function is only called if addr->host_used is set and if so -a useable addr->message is available containing some Exim description with ": \n" -ending, followed by the L/SMTP error message. +it uses the same logic as print_address_error() above. if af_pass_message is true +and addr->message is set it uses the remote host answer. if not addr->user_message +is used instead if available. Arguments: addr the address @@ -4854,21 +4887,23 @@ Returns: nothing static void print_dsn_diagnostic_code(const address_item *addr, FILE *f) { -uschar * s; +uschar *s = testflag(addr, af_pass_message) ? addr->message : NULL; -/* check host_used, af_pass_message flag and addr->message for safety reasons */ -if (!addr->host_used && testflag(addr, af_pass_message) && addr->message) - return; - -/* search first ": ". we assume to find the remote-MTA answer there */ -DEBUG(D_deliver) - debug_printf("DSN Diagnostic-Code: addr->dsn_message = %s\n", addr->message); -if (!(s = Ustrstr(addr->message, ": "))) - return; /* not found, bail out */ +/* af_pass_message and addr->message set ? print remote host answer */ +if (s) + { + DEBUG(D_deliver) + debug_printf("DSN Diagnostic-Code: addr->message = %s\n", addr->message); -fprintf(f, "Diagnostic-Code: smtp; "); + /* search first ": ". we assume to find the remote-MTA answer there */ + if (!(s = Ustrstr(addr->message, ": "))) + return; /* not found, bail out */ + s += 2; /* skip ": " */ + fprintf(f, "Diagnostic-Code: smtp; "); + } +/* no message available. do nothing */ +else return; -s += 2; /* skip ": " */ while (*s) if (*s == '\\' && s[1] == 'n') { @@ -5588,7 +5623,18 @@ if (process_recipients != RECIP_IGNORE) { recipient_item *r = recipients_list + i; address_item *new = deliver_make_addr(r->address, FALSE); - new->p.errors_address = r->errors_to; + new->prop.errors_address = r->errors_to; +#ifdef EXPERIMENTAL_INTERNATIONAL + if ((new->prop.utf8_msg = message_smtputf8)) + { + new->prop.utf8_downcvt = message_utf8_downconvert == 1; + new->prop.utf8_downcvt_maybe = message_utf8_downconvert == -1; + DEBUG(D_deliver) debug_printf("utf8, downconvert %s\n", + new->prop.utf8_downcvt ? "yes" + : new->prop.utf8_downcvt_maybe ? "ifneeded" + : "no"); + } +#endif if (r->pno >= 0) new->onetime_parent = recipients_list[r->pno].address; @@ -5597,7 +5643,8 @@ if (process_recipients != RECIP_IGNORE) to be passed on to other DSN enabled MTAs */ new->dsn_flags = r->dsn_flags & rf_dsnflags; new->dsn_orcpt = r->orcpt; - DEBUG(D_deliver) debug_printf("DSN: set orcpt: %s flags: %d\n", new->dsn_orcpt, new->dsn_flags); + DEBUG(D_deliver) debug_printf("DSN: set orcpt: %s flags: %d\n", + new->dsn_orcpt, new->dsn_flags); switch (process_recipients) { @@ -5672,7 +5719,7 @@ if (process_recipients != RECIP_IGNORE) if (process_recipients != RECIP_ACCEPT) { uschar * save_local = deliver_localpart; - uschar * save_domain = deliver_domain; + const uschar * save_domain = deliver_domain; deliver_localpart = expand_string( string_sprintf("${local_part:%s}", new->address)); @@ -5937,7 +5984,7 @@ while (addr_new != NULL) /* Loop until all addresses dealt with */ deliver_domain = addr->domain; /* set $domain */ if (!forced && hold_domains != NULL && - (rc = match_isinlist(addr->domain, &hold_domains, 0, + (rc = match_isinlist(addr->domain, (const uschar **)&hold_domains, 0, &domainlist_anchor, addr->domain_cache, MCL_DOMAIN, TRUE, NULL)) != FAIL) { @@ -6144,7 +6191,7 @@ while (addr_new != NULL) /* Loop until all addresses dealt with */ addr_route = addr->next; deliver_domain = addr->domain; /* set $domain */ - if ((rc = match_isinlist(addr->domain, &queue_domains, 0, + if ((rc = match_isinlist(addr->domain, (const uschar **)&queue_domains, 0, &domainlist_anchor, addr->domain_cache, MCL_DOMAIN, TRUE, NULL)) != OK) { @@ -6177,15 +6224,15 @@ while (addr_new != NULL) /* Loop until all addresses dealt with */ { int rc; address_item *addr = addr_route; - uschar *old_domain = addr->domain; + const uschar *old_domain = addr->domain; uschar *old_unique = addr->unique; addr_route = addr->next; addr->next = NULL; /* Just in case some router parameter refers to it. */ - return_path = (addr->p.errors_address != NULL)? - addr->p.errors_address : sender_address; + return_path = (addr->prop.errors_address != NULL)? + addr->prop.errors_address : sender_address; /* If a router defers an address, add a retry item. Whether or not to use the local part in the key is a property of the router. */ @@ -6255,8 +6302,8 @@ while (addr_new != NULL) /* Loop until all addresses dealt with */ if (addr_remote == addr && addr->router->same_domain_copy_routing && - addr->p.extra_headers == NULL && - addr->p.remove_headers == NULL && + addr->prop.extra_headers == NULL && + addr->prop.remove_headers == NULL && old_domain == addr->domain) { address_item **chain = &addr_route; @@ -6283,7 +6330,7 @@ while (addr_new != NULL) /* Loop until all addresses dealt with */ addr2->transport = addr->transport; addr2->host_list = addr->host_list; addr2->fallback_hosts = addr->fallback_hosts; - addr2->p.errors_address = addr->p.errors_address; + addr2->prop.errors_address = addr->prop.errors_address; copyflag(addr2, addr, af_hide_child | af_local_host_removed); DEBUG(D_deliver|D_route) @@ -6655,29 +6702,36 @@ else if (!dont_deliver) retry_update(&addr_defer, &addr_failed, &addr_succeed); addr_dsntmp = addr_succeed; addr_senddsn = NULL; -while(addr_dsntmp != NULL) +while(addr_dsntmp) { - DEBUG(D_deliver) - debug_printf("DSN: processing router : %s\n", addr_dsntmp->router->name); - - DEBUG(D_deliver) - debug_printf("DSN: processing successful delivery address: %s\n", addr_dsntmp->address); - /* af_ignore_error not honored here. it's not an error */ - - DEBUG(D_deliver) debug_printf("DSN: Sender_address: %s\n", sender_address); - DEBUG(D_deliver) debug_printf("DSN: orcpt: %s flags: %d\n", addr_dsntmp->dsn_orcpt, addr_dsntmp->dsn_flags); - DEBUG(D_deliver) debug_printf("DSN: envid: %s ret: %d\n", dsn_envid, dsn_ret); - DEBUG(D_deliver) debug_printf("DSN: Final recipient: %s\n", addr_dsntmp->address); - DEBUG(D_deliver) debug_printf("DSN: Remote SMTP server supports DSN: %d\n", addr_dsntmp->dsn_aware); + DEBUG(D_deliver) + { + debug_printf("DSN: processing router : %s\n" + "DSN: processing successful delivery address: %s\n" + "DSN: Sender_address: %s\n" + "DSN: orcpt: %s flags: %d\n" + "DSN: envid: %s ret: %d\n" + "DSN: Final recipient: %s\n" + "DSN: Remote SMTP server supports DSN: %d\n", + addr_dsntmp->router->name, + addr_dsntmp->address, + sender_address, + addr_dsntmp->dsn_orcpt, addr_dsntmp->dsn_flags, + dsn_envid, dsn_ret, + addr_dsntmp->address, + addr_dsntmp->dsn_aware + ); + } /* send report if next hop not DSN aware or a router flagged "last DSN hop" and a report was requested */ - if (((addr_dsntmp->dsn_aware != dsn_support_yes) || - ((addr_dsntmp->dsn_flags & rf_dsnlasthop) != 0)) - && - (((addr_dsntmp->dsn_flags & rf_dsnflags) != 0) && - ((addr_dsntmp->dsn_flags & rf_notify_success) != 0))) + if ( ( addr_dsntmp->dsn_aware != dsn_support_yes + || addr_dsntmp->dsn_flags & rf_dsnlasthop + ) + && addr_dsntmp->dsn_flags & rf_dsnflags + && addr_dsntmp->dsn_flags & rf_notify_success + ) { /* copy and relink address_item and send report with all of them at once later */ address_item *addr_next; @@ -6687,14 +6741,12 @@ while(addr_dsntmp != NULL) addr_senddsn->next = addr_next; } else - { - DEBUG(D_deliver) debug_printf("DSN: *** NOT SENDING DSN SUCCESS Message ***\n"); - } + DEBUG(D_deliver) debug_printf("DSN: not sending DSN success message\n"); addr_dsntmp = addr_dsntmp->next; } -if (addr_senddsn != NULL) +if (addr_senddsn) { pid_t pid; int fd; @@ -6710,8 +6762,7 @@ if (addr_senddsn != NULL) "create child process to send failure message: %s", getpid(), getppid(), strerror(errno)); - DEBUG(D_deliver) debug_printf("DSN: child_open_exim failed\n"); - + DEBUG(D_deliver) debug_printf("DSN: child_open_exim failed\n"); } else /* Creation of child succeeded */ { @@ -6720,7 +6771,8 @@ if (addr_senddsn != NULL) int topt = topt_add_return_path | topt_no_body; uschar * bound; - DEBUG(D_deliver) debug_printf("sending error message to: %s\n", sender_address); + DEBUG(D_deliver) + debug_printf("sending error message to: %s\n", sender_address); /* build unique id for MIME boundary */ bound = string_sprintf(TIME_T_FMT "-eximdsn-%d", time(NULL), rand()); @@ -6743,9 +6795,8 @@ if (addr_senddsn != NULL) " ----- The following addresses had successful delivery notifications -----\n", qualify_domain_sender, sender_address, bound, bound); - addr_dsntmp = addr_senddsn; - while(addr_dsntmp) - { + for (addr_dsntmp = addr_senddsn; addr_dsntmp; + addr_dsntmp = addr_dsntmp->next) fprintf(f, "<%s> (relayed %s)\n\n", addr_dsntmp->address, (addr_dsntmp->dsn_flags & rf_dsnlasthop) == 1 @@ -6754,15 +6805,14 @@ if (addr_senddsn != NULL) ? "to non-DSN-aware mailer" : "via non \"Remote SMTP\" router" ); - addr_dsntmp = addr_dsntmp->next; - } + fprintf(f, "--%s\n" "Content-type: message/delivery-status\n\n" "Reporting-MTA: dns; %s\n", bound, smtp_active_hostname); - if (dsn_envid != NULL) { - /* must be decoded from xtext: see RFC 3461:6.3a */ + if (dsn_envid) + { /* must be decoded from xtext: see RFC 3461:6.3a */ uschar *xdec_envid; if (auth_xtextdecode(dsn_envid, &xdec_envid) > 0) fprintf(f, "Original-Envelope-ID: %s\n", dsn_envid); @@ -6784,12 +6834,11 @@ if (addr_senddsn != NULL) addr_dsntmp->address); if (addr_dsntmp->host_used && addr_dsntmp->host_used->name) - fprintf(f, "Remote-MTA: dns; %s\nDiagnostic-Code: smtp; 250 Ok\n", + fprintf(f, "Remote-MTA: dns; %s\nDiagnostic-Code: smtp; 250 Ok\n\n", addr_dsntmp->host_used->name); else - fprintf(f,"Diagnostic-Code: X-Exim; relayed via non %s router\n", + fprintf(f, "Diagnostic-Code: X-Exim; relayed via non %s router\n\n", (addr_dsntmp->dsn_flags & rf_dsnlasthop) == 1 ? "DSN" : "SMTP"); - fputc('\n', f); } fprintf(f, "--%s\nContent-type: text/rfc822-headers\n\n", bound); @@ -6852,10 +6901,10 @@ while (addr_failed != NULL) If neither of these cases obtains, something has gone wrong. Log the incident, but then ignore the error. */ - if (sender_address[0] == 0 && addr_failed->p.errors_address == NULL) + if (sender_address[0] == 0 && addr_failed->prop.errors_address == NULL) { - if (!testflag(addr_failed, af_retry_timedout) && - !testflag(addr_failed, af_ignore_error)) + if ( !testflag(addr_failed, af_retry_timedout) + && !testflag(addr_failed, af_ignore_error)) { log_write(0, LOG_MAIN|LOG_PANIC, "internal error: bounce message " "failure is neither frozen nor ignored (it's been ignored)"); @@ -6868,19 +6917,19 @@ while (addr_failed != NULL) mark the recipient done. */ if ( testflag(addr_failed, af_ignore_error) - || ( ((addr_failed->dsn_flags & rf_dsnflags) != 0) - && ((addr_failed->dsn_flags & rf_notify_failure) != rf_notify_failure)) + || ( addr_failed->dsn_flags & rf_dsnflags + && (addr_failed->dsn_flags & rf_notify_failure) != rf_notify_failure) ) - { + { addr = addr_failed; addr_failed = addr->next; if (addr->return_filename != NULL) Uunlink(addr->return_filename); log_write(0, LOG_MAIN, "%s%s%s%s: error ignored", addr->address, - (addr->parent == NULL)? US"" : US" <", - (addr->parent == NULL)? US"" : addr->parent->address, - (addr->parent == NULL)? US"" : US">"); + !addr->parent ? US"" : US" <", + !addr->parent ? US"" : addr->parent->address, + !addr->parent ? US"" : US">"); address_done(addr, logtod); child_done(addr, logtod); @@ -6896,16 +6945,12 @@ while (addr_failed != NULL) else { - bounce_recipient = (addr_failed->p.errors_address == NULL)? - sender_address : addr_failed->p.errors_address; + bounce_recipient = addr_failed->prop.errors_address + ? addr_failed->prop.errors_address : sender_address; /* Make a subprocess to send a message */ - pid = child_open_exim(&fd); - - /* Creation of child failed */ - - if (pid < 0) + if ((pid = child_open_exim(&fd)) < 0) log_write(0, LOG_MAIN|LOG_PANIC_DIE, "Process %d (parent %d) failed to " "create child process to send failure message: %s", getpid(), getppid(), strerror(errno)); @@ -6936,20 +6981,16 @@ while (addr_failed != NULL) paddr = &addr_failed; for (addr = addr_failed; addr != NULL; addr = *paddr) - { - if (Ustrcmp(bounce_recipient, (addr->p.errors_address == NULL)? - sender_address : addr->p.errors_address) != 0) - { - paddr = &(addr->next); /* Not the same; skip */ - } - else /* The same - dechain */ - { + if (Ustrcmp(bounce_recipient, addr->prop.errors_address + ? addr->prop.errors_address : sender_address) == 0) + { /* The same - dechain */ *paddr = addr->next; *pmsgchain = addr; addr->next = NULL; pmsgchain = &(addr->next); } - } + else + paddr = &addr->next; /* Not the same; skip */ /* Include X-Failed-Recipients: for automatic interpretation, but do not let any one header line get too long. We do this by starting a @@ -6974,7 +7015,7 @@ while (addr_failed != NULL) /* Output the standard headers */ - if (errors_reply_to != NULL) + if (errors_reply_to) fprintf(f, "Reply-To: %s\n", errors_reply_to); fprintf(f, "Auto-Submitted: auto-replied\n"); moan_write_from(f); @@ -7142,10 +7183,18 @@ wording. */ } /* output machine readable part */ - fprintf(f, "--%s\n" - "Content-type: message/delivery-status\n\n" - "Reporting-MTA: dns; %s\n", - bound, smtp_active_hostname); +#ifdef EXPERIMENTAL_INTERNATIONAL + if (message_smtputf8) + fprintf(f, "--%s\n" + "Content-type: message/global-delivery-status\n\n" + "Reporting-MTA: dns; %s\n", + bound, smtp_active_hostname); + else +#endif + fprintf(f, "--%s\n" + "Content-type: message/delivery-status\n\n" + "Reporting-MTA: dns; %s\n", + bound, smtp_active_hostname); if (dsn_envid) { @@ -7170,6 +7219,7 @@ wording. */ addr->host_used->name); print_dsn_diagnostic_code(addr, f); } + fputc('\n', f); } /* Now copy the message, trying to give an intelligible comment if @@ -7190,7 +7240,7 @@ wording. */ bounce_return_size_limit is always honored. */ - fprintf(f, "\n--%s\n", bound); + fprintf(f, "--%s\n", bound); dsnlimitmsg = US"X-Exim-DSN-Information: Due to administrative limits only headers are returned"; dsnnotifyhdr = NULL; @@ -7219,10 +7269,16 @@ wording. */ } } - if (topt & topt_no_body) - fprintf(f,"Content-type: text/rfc822-headers\n\n"); +#ifdef EXPERIMENTAL_INTERNATIONAL + if (message_smtputf8) + fputs(topt & topt_no_body ? "Content-type: message/global-headers\n\n" + : "Content-type: message/global\n\n", + f); else - fprintf(f,"Content-type: message/rfc822\n\n"); +#endif + fputs(topt & topt_no_body ? "Content-type: text/rfc822-headers\n\n" + : "Content-type: message/rfc822\n\n", + f); fflush(f); transport_filter_argv = NULL; /* Just in case */ @@ -7322,11 +7378,9 @@ if (addr_defer == NULL) "msglog.OLD directory", spoolname); } else - { if (Uunlink(spoolname) < 0) log_write(0, LOG_MAIN|LOG_PANIC_DIE, "failed to unlink %s: %s", spoolname, strerror(errno)); - } } /* Remove the two message files. */ @@ -7342,7 +7396,7 @@ if (addr_defer == NULL) /* Log the end of this message, with queue time if requested. */ - if ((log_extra_selector & LX_queue_time_overall) != 0) + if (LOGGING(queue_time_overall)) log_write(0, LOG_MAIN, "Completed QT=%s", readconf_printtime( (int) ((long)time(NULL) - (long)received_time)) ); else @@ -7400,7 +7454,8 @@ else if (addr_defer != (address_item *)(+1)) if (deliver_domain != NULL) { - uschar *d = (testflag(addr, af_pfr))? addr->parent->domain : addr->domain; + const uschar *d = testflag(addr, af_pfr) + ? addr->parent->domain : addr->domain; /* The domain may be unset for an address that has never been routed because the system filter froze the message. */ @@ -7438,7 +7493,7 @@ else if (addr_defer != (address_item *)(+1)) DEBUG(D_deliver) debug_printf("one_time: adding %s in place of %s\n", otaddr->address, otaddr->parent->address); receive_add_recipient(otaddr->address, t); - recipients_list[recipients_count-1].errors_to = otaddr->p.errors_address; + recipients_list[recipients_count-1].errors_to = otaddr->prop.errors_address; tree_add_nonrecipient(otaddr->parent->address); update_spool = TRUE; } @@ -7450,7 +7505,7 @@ else if (addr_defer != (address_item *)(+1)) if (sender_address[0] != 0) { - if (addr->p.errors_address == NULL) + if (addr->prop.errors_address == NULL) { if (Ustrstr(recipients, sender_address) == NULL) recipients = string_sprintf("%s%s%s", recipients, @@ -7458,9 +7513,9 @@ else if (addr_defer != (address_item *)(+1)) } else { - if (Ustrstr(recipients, addr->p.errors_address) == NULL) + if (Ustrstr(recipients, addr->prop.errors_address) == NULL) recipients = string_sprintf("%s%s%s", recipients, - (recipients[0] == 0)? "" : ",", addr->p.errors_address); + (recipients[0] == 0)? "" : ",", addr->prop.errors_address); } } } @@ -7668,24 +7723,25 @@ else if (addr_defer != (address_item *)(+1)) } fputc('\n', f); - while (addr_dsndefer) + for ( ; addr_dsndefer; addr_dsndefer = addr_dsndefer->next) { if (addr_dsndefer->dsn_orcpt) - fprintf(f,"Original-Recipient: %s\n", addr_dsndefer->dsn_orcpt); + fprintf(f, "Original-Recipient: %s\n", addr_dsndefer->dsn_orcpt); - fprintf(f,"Action: delayed\n"); - fprintf(f,"Final-Recipient: rfc822;%s\n", addr_dsndefer->address); - fprintf(f,"Status: 4.0.0\n"); + fprintf(f, "Action: delayed\n" + "Final-Recipient: rfc822;%s\n" + "Status: 4.0.0\n", + addr_dsndefer->address); if (addr_dsndefer->host_used && addr_dsndefer->host_used->name) { - fprintf(f,"Remote-MTA: dns; %s\n", + fprintf(f, "Remote-MTA: dns; %s\n", addr_dsndefer->host_used->name); print_dsn_diagnostic_code(addr_dsndefer, f); } - addr_dsndefer = addr_dsndefer->next; + fputc('\n', f); } - fprintf(f, "\n--%s\n" + fprintf(f, "--%s\n" "Content-type: text/rfc822-headers\n\n", bound); @@ -7863,6 +7919,11 @@ if (!regex_PRDR) regex_PRDR = regex_must_compile(US"\\n250[\\s\\-]PRDR(\\s|\\n|$)", FALSE, TRUE); #endif +#ifdef EXPERIMENTAL_INTERNATIONAL +if (!regex_UTF8) regex_UTF8 = + regex_must_compile(US"\\n250[\\s\\-]SMTPUTF8(\\s|\\n|$)", FALSE, TRUE); +#endif + if (!regex_DSN) regex_DSN = regex_must_compile(US"\\n250[\\s\\-]DSN(\\s|\\n|$)", FALSE, TRUE); @@ -7871,6 +7932,41 @@ if (!regex_IGNOREQUOTA) regex_IGNOREQUOTA = } +uschar * +deliver_get_sender_address (uschar * id) +{ +int rc; +uschar * new_sender_address, + * save_sender_address; + +if (!spool_open_datafile(id)) + return NULL; + +/* Save and restore the global sender_address. I'm not sure if we should +not save/restore all the other global variables too, because +spool_read_header() may change all of them. But OTOH, when this +deliver_get_sender_address() gets called, the current message is done +already and nobody needs the globals anymore. (HS12, 2015-08-21) */ + +sprintf(CS spoolname, "%s-H", id); +save_sender_address = sender_address; + +rc = spool_read_header(spoolname, TRUE, TRUE); + +new_sender_address = sender_address; +sender_address = save_sender_address; + +if (rc != spool_read_OK) + return NULL; + +assert(new_sender_address); + +(void)close(deliver_datafile); +deliver_datafile = -1; + +return new_sender_address; +} + /* vi: aw ai sw=2 */ /* End of deliver.c */