X-Git-Url: https://git.exim.org/exim.git/blobdiff_plain/09c17790eec23907b93df1ec7cee746b28dfc836..93a6fce2ebf117f490d7ee11f066f75280d32386:/src/src/deliver.c diff --git a/src/src/deliver.c b/src/src/deliver.c index 27a4344c5..ec13ca40b 100644 --- a/src/src/deliver.c +++ b/src/src/deliver.c @@ -63,10 +63,8 @@ static address_item *addr_new = NULL; static address_item *addr_remote = NULL; static address_item *addr_route = NULL; static address_item *addr_succeed = NULL; -#ifdef EXPERIMENTAL_DSN static address_item *addr_dsntmp = NULL; static address_item *addr_senddsn = NULL; -#endif static FILE *message_log = NULL; static BOOL update_spool; @@ -129,7 +127,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; } @@ -720,7 +718,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) @@ -754,11 +752,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; @@ -819,6 +817,10 @@ 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">"); @@ -1016,7 +1018,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 || @@ -1073,11 +1078,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); } @@ -2777,7 +2783,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]; @@ -2792,7 +2798,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); @@ -2802,7 +2808,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); @@ -3166,14 +3172,12 @@ while (!done) break; #endif -#ifdef EXPERIMENTAL_DSN case 'D': if (addr == NULL) goto ADDR_MISMATCH; memcpy(&(addr->dsn_aware), ptr, sizeof(addr->dsn_aware)); ptr += sizeof(addr->dsn_aware); DEBUG(D_deliver) debug_printf("DSN read: addr->dsn_aware = %d\n", addr->dsn_aware); break; -#endif case 'A': if (addr == NULL) @@ -3223,6 +3227,14 @@ while (!done) addr = addr->next; break; + /* Local interface address/port */ + case 'I': + if (*ptr) sending_ip_address = string_copy(ptr); + while (*ptr++) ; + if (*ptr) sending_port = atoi(CS ptr); + while (*ptr++) ; + break; + /* Z marks the logical end of the data. It is followed by '0' if continue_transport was NULL at the end of transporting, otherwise '1'. We need to know when it becomes NULL during a delivery down a passed SMTP @@ -3844,9 +3856,20 @@ for (delivery_count = 0; addr_remote != NULL; delivery_count++) } /* Get the flag which specifies whether the transport can handle different - domains that nevertheless resolve to the same set of hosts. */ - - multi_domain = tp->multi_domain; + domains that nevertheless resolve to the same set of hosts. If it needs + expanding, get variables set: $address_data, $domain_data, $localpart_data, + $host, $host_address, $host_port. */ + if (tp->expand_multi_domain) + deliver_set_expansions(addr); + + if (exp_bool(addr, US"transport", tp->name, D_transport, + US"multi_domain", tp->multi_domain, tp->expand_multi_domain, + &multi_domain) != OK) + { + deliver_set_expansions(NULL); + remote_post_process(addr, LOG_MAIN|LOG_PANIC, addr->message, fallback); + continue; + } /* Get the maximum it can handle in one envelope, with zero meaning unlimited, which is forced for the MUA wrapper case. */ @@ -3915,26 +3938,35 @@ for (delivery_count = 0; addr_remote != NULL; delivery_count++) entirely different domains. The host list pointers can be NULL in the case where the hosts are defined in the transport. There is also a configured maximum limit of addresses that can be handled at once (see comments above - for how it is computed). */ + for how it is computed). + If the transport does not handle multiple domains, enforce that also, + and if it might need a per-address check for this, re-evaluate it. + */ while ((next = *anchor) != NULL && address_count < address_count_max) { - 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_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))) + BOOL md; + 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_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 + ) ) + && ( !multi_domain + || ( ( + !tp->expand_multi_domain || (deliver_set_expansions(next), 1), + exp_bool(addr, + US"transport", next->transport->name, D_transport, + US"multi_domain", next->transport->multi_domain, + next->transport->expand_multi_domain, &md) == OK + ) + && md + ) ) ) { *anchor = next->next; next->next = NULL; @@ -3944,6 +3976,7 @@ for (delivery_count = 0; addr_remote != NULL; delivery_count++) address_count++; } else anchor = &(next->next); + deliver_set_expansions(NULL); } /* If we are acting as an MUA wrapper, all addresses must go in a single @@ -4349,11 +4382,9 @@ for (delivery_count = 0; addr_remote != NULL; delivery_count++) rmt_dlv_checked_write(fd, 'P', '0', NULL, 0); #endif -#ifdef EXPERIMENTAL_DSN memcpy(big_buffer, &addr->dsn_aware, sizeof(addr->dsn_aware)); rmt_dlv_checked_write(fd, 'D', '0', big_buffer, sizeof(addr->dsn_aware)); DEBUG(D_deliver) debug_printf("DSN write: addr->dsn_aware = %d\n", addr->dsn_aware); -#endif /* Retry information: for most success cases this will be null. */ @@ -4415,6 +4446,18 @@ for (delivery_count = 0; addr_remote != NULL; delivery_count++) rmt_dlv_checked_write(fd, 'A', '0', big_buffer, ptr - big_buffer); } + /* Local interface address/port */ + if (log_extra_selector & LX_incoming_interface && sending_ip_address) + { + uschar * ptr = big_buffer; + sprintf(CS ptr, "%.128s", sending_ip_address); + while(*ptr++); + sprintf(CS ptr, "%d", sending_port); + while(*ptr++); + + rmt_dlv_checked_write(fd, 'I', '0', big_buffer, ptr - big_buffer); + } + /* Add termination flag, close the pipe, and that's it. The character after 'Z' indicates whether continue_transport is now NULL or not. A change from non-NULL to NULL indicates a problem with a continuing @@ -4541,7 +4584,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) @@ -4793,8 +4836,54 @@ while (*s != 0) } +/*********************************************************** +* Print Diagnostic-Code for an address * +************************************************************/ + +/* This function is called to print the error information out of an address for +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. + +Arguments: + addr the address + f the FILE to print on + +Returns: nothing +*/ + +static void +print_dsn_diagnostic_code(const address_item *addr, FILE *f) +{ +uschar * s; + +/* 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 */ + +fprintf(f, "Diagnostic-Code: smtp; "); +s += 2; /* skip ": " */ +while (*s) + if (*s == '\\' && s[1] == 'n') + { + fputs("\n ", f); /* as defined in RFC 3461 */ + s += 2; + } + else + fputc(*s++, f); +fputc('\n', f); +} /************************************************* @@ -5508,13 +5597,11 @@ if (process_recipients != RECIP_IGNORE) if (r->pno >= 0) new->onetime_parent = recipients_list[r->pno].address; -#ifdef EXPERIMENTAL_DSN /* If DSN support is enabled, set the dsn flags and the original receipt 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); -#endif switch (process_recipients) { @@ -5589,7 +5676,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)); @@ -5854,7 +5941,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) { @@ -6061,7 +6148,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) { @@ -6094,7 +6181,7 @@ 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; @@ -6459,31 +6546,7 @@ if (addr_remote != NULL) /* Precompile some regex that are used to recognize parameters in response to an EHLO command, if they aren't already compiled. */ - if (regex_PIPELINING == NULL) regex_PIPELINING = - regex_must_compile(US"\\n250[\\s\\-]PIPELINING(\\s|\\n|$)", FALSE, TRUE); - - if (regex_SIZE == NULL) regex_SIZE = - regex_must_compile(US"\\n250[\\s\\-]SIZE(\\s|\\n|$)", FALSE, TRUE); - - if (regex_AUTH == NULL) regex_AUTH = - regex_must_compile(US"\\n250[\\s\\-]AUTH\\s+([\\-\\w\\s]+)(?:\\n|$)", - FALSE, TRUE); - -#ifdef SUPPORT_TLS - if (regex_STARTTLS == NULL) regex_STARTTLS = - regex_must_compile(US"\\n250[\\s\\-]STARTTLS(\\s|\\n|$)", FALSE, TRUE); -#endif - -#ifndef DISABLE_PRDR - if (regex_PRDR == NULL) regex_PRDR = - regex_must_compile(US"\\n250[\\s\\-]PRDR(\\s|\\n|$)", FALSE, TRUE); -#endif - -#ifdef EXPERIMENTAL_DSN - /* Set the regex to check for DSN support on remote MTA */ - if (regex_DSN == NULL) regex_DSN = - regex_must_compile(US"\\n250[\\s\\-]DSN(\\s|\\n|$)", FALSE, TRUE); -#endif + deliver_init(); /* 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 @@ -6592,7 +6655,6 @@ prevents actual delivery. */ else if (!dont_deliver) retry_update(&addr_defer, &addr_failed, &addr_succeed); -#ifdef EXPERIMENTAL_DSN /* Send DSN for successful messages */ addr_dsntmp = addr_succeed; addr_senddsn = NULL; @@ -6660,14 +6722,13 @@ if (addr_senddsn != NULL) FILE *f = fdopen(fd, "wb"); /* header only as required by RFC. only failure DSN needs to honor RET=FULL */ int topt = topt_add_return_path | topt_no_body; - uschar boundaryStr[64]; + uschar * bound; DEBUG(D_deliver) debug_printf("sending error message to: %s\n", sender_address); /* build unique id for MIME boundary */ - snprintf(boundaryStr, sizeof(boundaryStr)-1, TIME_T_FMT "-eximdsn-%d", - time(NULL), rand()); - DEBUG(D_deliver) debug_printf("DSN: MIME boundary: %s\n", boundaryStr); + bound = string_sprintf(TIME_T_FMT "-eximdsn-%d", time(NULL), rand()); + DEBUG(D_deliver) debug_printf("DSN: MIME boundary: %s\n", bound); if (errors_reply_to) fprintf(f, "Reply-To: %s\n", errors_reply_to); @@ -6684,7 +6745,7 @@ if (addr_senddsn != NULL) "This message was created automatically by mail delivery software.\n" " ----- The following addresses had successful delivery notifications -----\n", - qualify_domain_sender, sender_address, boundaryStr, boundaryStr); + qualify_domain_sender, sender_address, bound, bound); addr_dsntmp = addr_senddsn; while(addr_dsntmp) @@ -6702,7 +6763,7 @@ if (addr_senddsn != NULL) fprintf(f, "--%s\n" "Content-type: message/delivery-status\n\n" "Reporting-MTA: dns; %s\n", - boundaryStr, smtp_active_hostname); + bound, smtp_active_hostname); if (dsn_envid != NULL) { /* must be decoded from xtext: see RFC 3461:6.3a */ @@ -6735,7 +6796,7 @@ if (addr_senddsn != NULL) fputc('\n', f); } - fprintf(f, "--%s\nContent-type: text/rfc822-headers\n\n", boundaryStr); + fprintf(f, "--%s\nContent-type: text/rfc822-headers\n\n", bound); fflush(f); transport_filter_argv = NULL; /* Just in case */ @@ -6745,15 +6806,13 @@ if (addr_senddsn != NULL) transport_write_message(NULL, fileno(f), topt, 0, NULL, NULL, NULL, NULL, NULL, 0); fflush(f); - fprintf(f,"\n"); - fprintf(f,"--%s--\n", boundaryStr); + fprintf(f,"\n--%s--\n", bound); fflush(f); fclose(f); rc = child_close(pid, 0); /* Waits for child to close, no timeout */ } } -#endif /*EXPERIMENTAL_DSN*/ /* If any addresses failed, we must send a message to somebody, unless af_ignore_error is set, in which case no action is taken. It is possible for @@ -6812,11 +6871,9 @@ while (addr_failed != NULL) it from the list, throw away any saved message file, log it, and mark the recipient done. */ - if (testflag(addr_failed, af_ignore_error) -#ifdef EXPERIMENTAL_DSN - || (((addr_failed->dsn_flags & rf_dsnflags) != 0) - && ((addr_failed->dsn_flags & rf_notify_failure) != rf_notify_failure)) -#endif + 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 = addr_failed; @@ -6870,12 +6927,10 @@ while (addr_failed != NULL) BOOL to_sender = strcmpic(sender_address, bounce_recipient) == 0; int max = (bounce_return_size_limit/DELIVER_IN_BUFFER_SIZE + 1) * DELIVER_IN_BUFFER_SIZE; -#ifdef EXPERIMENTAL_DSN - uschar boundaryStr[64]; + uschar * bound; uschar *dsnlimitmsg; uschar *dsnnotifyhdr; int topt; -#endif DEBUG(D_deliver) debug_printf("sending error message to: %s\n", bounce_recipient); @@ -6929,16 +6984,13 @@ while (addr_failed != NULL) moan_write_from(f); fprintf(f, "To: %s\n", bounce_recipient); -#ifdef EXPERIMENTAL_DSN /* generate boundary string and output MIME-Headers */ - snprintf(boundaryStr, sizeof(boundaryStr)-1, TIME_T_FMT "-eximdsn-%d", - time(NULL), rand()); + bound = string_sprintf(TIME_T_FMT "-eximdsn-%d", time(NULL), rand()); fprintf(f, "Content-Type: multipart/report;" " report-type=delivery-status; boundary=%s\n" "MIME-Version: 1.0\n", - boundaryStr); -#endif + bound); /* Open a template file if one is provided. Log failure to open, but carry on - default texts will be used. */ @@ -6963,12 +7015,10 @@ while (addr_failed != NULL) fprintf(f, "Subject: Mail delivery failed%s\n\n", to_sender? ": returning message to sender" : ""); -#ifdef EXPERIMENTAL_DSN /* output human readable part as text/plain section */ fprintf(f, "--%s\n" "Content-type: text/plain; charset=us-ascii\n\n", - boundaryStr); -#endif + bound); if ((emf_text = next_emf(emf, US"intro"))) fprintf(f, "%s", CS emf_text); @@ -7095,12 +7145,11 @@ wording. */ fputc('\n', f); } -#ifdef EXPERIMENTAL_DSN /* output machine readable part */ fprintf(f, "--%s\n" "Content-type: message/delivery-status\n\n" "Reporting-MTA: dns; %s\n", - boundaryStr, smtp_active_hostname); + bound, smtp_active_hostname); if (dsn_envid) { @@ -7120,10 +7169,12 @@ wording. */ "Status: 5.0.0\n", addr->address); if (addr->host_used && addr->host_used->name) - fprintf(f, "Remote-MTA: dns; %s\nDiagnostic-Code: smtp; %d\n", - addr->host_used->name, addr->basic_errno); + { + fprintf(f, "Remote-MTA: dns; %s\n", + addr->host_used->name); + print_dsn_diagnostic_code(addr, f); + } } -#endif /* Now copy the message, trying to give an intelligible comment if it is too long for it all to be copied. The limit isn't strictly @@ -7132,65 +7183,6 @@ wording. */ emf_text = next_emf(emf, US"copy"); -#ifndef EXPERIMENTAL_DSN - if (bounce_return_message) - { - int topt = topt_add_return_path; - if (!bounce_return_body) topt |= topt_no_body; - - if (emf_text) - fprintf(f, "%s", CS emf_text); - else - { - if (bounce_return_body) fprintf(f, -"------ This is a copy of the message, including all the headers. ------\n"); - else fprintf(f, -"------ This is a copy of the message's headers. ------\n"); - } - - /* While reading the "truncated" message, set return_size_limit to - the actual max testing value, rounded. We need to read the message - whether we are going to use it or not. */ - - { - int temp = bounce_return_size_limit; - bounce_return_size_limit = (max/1000)*1000; - emf_text = next_emf(emf, US"truncated"); - bounce_return_size_limit = temp; - } - - if (bounce_return_body && bounce_return_size_limit > 0) - { - struct stat statbuf; - if (fstat(deliver_datafile, &statbuf) == 0 && statbuf.st_size > max) - { - if (emf_text) - fprintf(f, "%s", CS emf_text); - else - fprintf(f, -"------ The body of the message is " OFF_T_FMT " characters long; only the first\n" -"------ %d or so are included here.\n", statbuf.st_size, max); - } - } - - fputc('\n', f); - fflush(f); - - transport_filter_argv = NULL; /* Just in case */ - return_path = sender_address; /* In case not previously set */ - transport_write_message(NULL, fileno(f), topt, - bounce_return_size_limit, NULL, NULL, NULL, NULL, NULL, 0); - } - - /* Write final text and close the template file if one is open */ - - if (emf) - { - if ((emf_text = next_emf(emf, US"final"))) - fprintf(f, "%s", CS emf_text); - (void)fclose(emf); - } -#else /* add message body we ignore the intro text from template and add the text for bounce_return_size_limit at the end. @@ -7202,7 +7194,7 @@ wording. */ bounce_return_size_limit is always honored. */ - fprintf(f, "\n--%s\n", boundaryStr); + fprintf(f, "\n--%s\n", bound); dsnlimitmsg = US"X-Exim-DSN-Information: Due to administrative limits only headers are returned"; dsnnotifyhdr = NULL; @@ -7247,8 +7239,7 @@ wording. */ if (emf) (void)fclose(emf); - fprintf(f, "\n--%s--\n", boundaryStr); -#endif /*EXPERIMENTAL_DSN*/ + fprintf(f, "\n--%s--\n", bound); /* Close the file, which should send an EOF to the child process that is receiving the message. Wait for it to finish. */ @@ -7413,7 +7404,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. */ @@ -7483,15 +7475,18 @@ else if (addr_defer != (address_item *)(+1)) is not sent. Another attempt will be made at the next delivery attempt (if it also defers). */ - if (!queue_2stage && delivery_attempted && -#ifdef EXPERIMENTAL_DSN - (((addr_defer->dsn_flags & rf_dsnflags) == 0) || - (addr_defer->dsn_flags & rf_notify_delay) == rf_notify_delay) && -#endif - delay_warning[1] > 0 && sender_address[0] != 0 && - (delay_warning_condition == NULL || - expand_check_condition(delay_warning_condition, - US"delay_warning", US"option"))) + if ( !queue_2stage + && delivery_attempted + && ( ((addr_defer->dsn_flags & rf_dsnflags) == 0) + || (addr_defer->dsn_flags & rf_notify_delay) == rf_notify_delay + ) + && delay_warning[1] > 0 + && sender_address[0] != 0 + && ( delay_warning_condition == NULL + || expand_check_condition(delay_warning_condition, + US"delay_warning", US"option") + ) + ) { int count; int show_time; @@ -7552,9 +7547,7 @@ else if (addr_defer != (address_item *)(+1)) uschar *wmf_text; FILE *wmf = NULL; FILE *f = fdopen(fd, "wb"); -#ifdef EXPERIMENTAL_DSN - uschar boundaryStr[64]; -#endif + uschar * bound; if (warn_message_file) { @@ -7575,16 +7568,13 @@ else if (addr_defer != (address_item *)(+1)) moan_write_from(f); fprintf(f, "To: %s\n", recipients); -#ifdef EXPERIMENTAL_DSN /* generated boundary string and output MIME-Headers */ - snprintf(boundaryStr, sizeof(boundaryStr)-1, - TIME_T_FMT "-eximdsn-%d", time(NULL), rand()); + bound = string_sprintf(TIME_T_FMT "-eximdsn-%d", time(NULL), rand()); fprintf(f, "Content-Type: multipart/report;" " report-type=delivery-status; boundary=%s\n" "MIME-Version: 1.0\n", - boundaryStr); -#endif + bound); if ((wmf_text = next_emf(wmf, US"header"))) fprintf(f, "%s\n", wmf_text); @@ -7592,12 +7582,10 @@ else if (addr_defer != (address_item *)(+1)) fprintf(f, "Subject: Warning: message %s delayed %s\n\n", message_id, warnmsg_delay); -#ifdef EXPERIMENTAL_DSN /* output human readable part as text/plain section */ fprintf(f, "--%s\n" "Content-type: text/plain; charset=us-ascii\n\n", - boundaryStr); -#endif + bound); if ((wmf_text = next_emf(wmf, US"intro"))) fprintf(f, "%s", CS wmf_text); @@ -7636,10 +7624,8 @@ else if (addr_defer != (address_item *)(+1)) /* List the addresses, with error information if allowed */ -#ifdef EXPERIMENTAL_DSN /* store addr_defer for machine readable part */ address_item *addr_dsndefer = addr_defer; -#endif fputc('\n', f); while (addr_defer) { @@ -7668,12 +7654,11 @@ else if (addr_defer != (address_item *)(+1)) "and when that happens, the message will be returned to you.\n"); } -#ifdef EXPERIMENTAL_DSN /* output machine readable part */ fprintf(f, "\n--%s\n" "Content-type: message/delivery-status\n\n" "Reporting-MTA: dns; %s\n", - boundaryStr, + bound, smtp_active_hostname); @@ -7697,14 +7682,17 @@ else if (addr_defer != (address_item *)(+1)) fprintf(f,"Final-Recipient: rfc822;%s\n", addr_dsndefer->address); fprintf(f,"Status: 4.0.0\n"); if (addr_dsndefer->host_used && addr_dsndefer->host_used->name) - fprintf(f,"Remote-MTA: dns; %s\nDiagnostic-Code: smtp; %d\n", - addr_dsndefer->host_used->name, addr_dsndefer->basic_errno); + { + fprintf(f,"Remote-MTA: dns; %s\n", + addr_dsndefer->host_used->name); + print_dsn_diagnostic_code(addr_dsndefer, f); + } addr_dsndefer = addr_dsndefer->next; } fprintf(f, "\n--%s\n" "Content-type: text/rfc822-headers\n\n", - boundaryStr); + bound); fflush(f); /* header only as required by RFC. only failure DSN needs to honor RET=FULL */ @@ -7715,10 +7703,9 @@ else if (addr_defer != (address_item *)(+1)) transport_write_message(NULL, fileno(f), topt, 0, NULL, NULL, NULL, NULL, NULL, 0); fflush(f); - fprintf(f,"\n--%s--\n", boundaryStr); + fprintf(f,"\n--%s--\n", bound); fflush(f); -#endif /*EXPERIMENTAL_DSN*/ /* Close and wait for child process to complete, without a timeout. If there's an error, don't update the count. */ @@ -7856,6 +7843,39 @@ acl_where = ACL_WHERE_UNKNOWN; return final_yield; } + + +void +deliver_init(void) +{ +if (!regex_PIPELINING) regex_PIPELINING = + regex_must_compile(US"\\n250[\\s\\-]PIPELINING(\\s|\\n|$)", FALSE, TRUE); + +if (!regex_SIZE) regex_SIZE = + regex_must_compile(US"\\n250[\\s\\-]SIZE(\\s|\\n|$)", FALSE, TRUE); + +if (!regex_AUTH) regex_AUTH = + regex_must_compile(US"\\n250[\\s\\-]AUTH\\s+([\\-\\w\\s]+)(?:\\n|$)", + FALSE, TRUE); + +#ifdef SUPPORT_TLS +if (!regex_STARTTLS) regex_STARTTLS = + regex_must_compile(US"\\n250[\\s\\-]STARTTLS(\\s|\\n|$)", FALSE, TRUE); +#endif + +#ifndef DISABLE_PRDR +if (!regex_PRDR) regex_PRDR = + regex_must_compile(US"\\n250[\\s\\-]PRDR(\\s|\\n|$)", FALSE, TRUE); +#endif + +if (!regex_DSN) regex_DSN = + regex_must_compile(US"\\n250[\\s\\-]DSN(\\s|\\n|$)", FALSE, TRUE); + +if (!regex_IGNOREQUOTA) regex_IGNOREQUOTA = + regex_must_compile(US"\\n250[\\s\\-]IGNOREQUOTA(\\s|\\n|$)", FALSE, TRUE); +} + + /* vi: aw ai sw=2 */ /* End of deliver.c */