X-Git-Url: https://git.exim.org/exim.git/blobdiff_plain/8768d5483a5894400ae1f70cda1beb44ed9b087c..d12746bc15d83ab821be36975da0179672708bc1:/src/src/deliver.c diff --git a/src/src/deliver.c b/src/src/deliver.c index e3165051f..0b403bad2 100644 --- a/src/src/deliver.c +++ b/src/src/deliver.c @@ -761,10 +761,9 @@ d_log_interface(gstring * g) if (LOGGING(incoming_interface) && LOGGING(outgoing_interface) && sending_ip_address) { - g = string_append(g, 2, US" I=[", sending_ip_address); - g = LOGGING(outgoing_port) - ? string_append(g, 2, US"]:", string_sprintf("%d", sending_port)) - : string_catn(g, US"]", 1); + g = string_fmt_append(g, " I=[%s]", sending_ip_address); + if (LOGGING(outgoing_port)) + g = string_fmt_append(g, "%d", sending_port); } return g; } @@ -784,21 +783,21 @@ if (LOGGING(dnssec) && h->dnssec == DS_YES) g = string_append(g, 3, US" [", h->address, US"]"); if (LOGGING(outgoing_port)) - g = string_append(g, 2, US":", string_sprintf("%d", h->port)); + g = string_fmt_append(g, ":%d", h->port); #ifdef SUPPORT_SOCKS if (LOGGING(proxy) && proxy_local_address) { g = string_append(g, 3, US" PRX=[", proxy_local_address, US"]"); if (LOGGING(outgoing_port)) - g = string_append(g, 2, US":", string_sprintf("%d", proxy_local_port)); + g = string_fmt_append(g, ":%d", proxy_local_port); } #endif g = d_log_interface(g); if (testflag(addr, af_tcp_fastopen)) - g = string_catn(g, US" TFO", 4); + g = string_catn(g, US" TFO*", testflag(addr, af_tcp_fastopen_data) ? 5 : 4); return g; } @@ -851,7 +850,7 @@ if (action) if (!(s = expand_string(action)) && *expand_string_message) log_write(0, LOG_MAIN|LOG_PANIC, "failed to expand event_action %s in %s: %s\n", - event, transport_name, expand_string_message); + event, transport_name ? transport_name : US"main", expand_string_message); event_name = event_data = NULL; @@ -877,20 +876,33 @@ const uschar * save_host = deliver_host; const uschar * save_address = deliver_host_address; const int save_port = deliver_host_port; -if (!addr->transport) - return; - router_name = addr->router ? addr->router->name : NULL; -transport_name = addr->transport->name; deliver_domain = addr->domain; deliver_localpart = addr->local_part; deliver_host = addr->host_used ? addr->host_used->name : NULL; -(void) event_raise(addr->transport->event_action, event, - addr->host_used - || Ustrcmp(addr->transport->driver_name, "smtp") == 0 - || Ustrcmp(addr->transport->driver_name, "lmtp") == 0 - ? addr->message : NULL); +if (!addr->transport) + { + if (Ustrcmp(event, "msg:fail:delivery") == 0) + { + /* An address failed with no transport involved. This happens when + a filter was used which triggered a fail command (in such a case + a transport isn't needed). Convert it to an internal fail event. */ + + (void) event_raise(event_action, US"msg:fail:internal", addr->message); + } + } +else + { + transport_name = addr->transport->name; + + (void) event_raise(addr->transport->event_action, event, + addr->host_used + || Ustrcmp(addr->transport->driver_name, "smtp") == 0 + || Ustrcmp(addr->transport->driver_name, "lmtp") == 0 + || Ustrcmp(addr->transport->driver_name, "autoreply") == 0 + ? addr->message : NULL); + } deliver_host_port = save_port; deliver_host_address = save_address; @@ -1095,7 +1107,7 @@ static uschar buf[sizeof("0.000s")]; if (diff->tv_sec >= 5 || !LOGGING(millisec)) return readconf_printtime((int)diff->tv_sec); -sprintf(CS buf, "%d.%03ds", (int)diff->tv_sec, (int)diff->tv_usec/1000); +sprintf(CS buf, "%u.%03us", (uint)diff->tv_sec, (uint)diff->tv_usec/1000); return buf; } @@ -1183,8 +1195,7 @@ if (addr->router) g = string_append(g, 2, US" T=", addr->transport->name); if (LOGGING(delivery_size)) - g = string_append(g, 2, US" S=", - string_sprintf("%d", transport_count)); + g = string_fmt_append(g, " S=%d", transport_count); /* Local delivery */ @@ -1234,8 +1245,15 @@ else } } - if (LOGGING(pipelining) && testflag(addr, af_pipelining)) - g = string_catn(g, US" L", 2); + if (LOGGING(pipelining)) + { + if (testflag(addr, af_pipelining)) + g = string_catn(g, US" L", 2); +#ifdef EXPERIMENTAL_PIPE_CONNECT + if (testflag(addr, af_early_pipe)) + g = string_catn(g, US"*", 1); +#endif + } #ifndef DISABLE_PRDR if (testflag(addr, af_prdr_used)) @@ -1325,13 +1343,12 @@ if (driver_name) { if (driver_kind[1] == 't' && addr->router) g = string_append(g, 2, US" R=", addr->router->name); - g = string_cat(g, string_sprintf(" %c=%s", toupper(driver_kind[1]), driver_name)); + g = string_fmt_append(g, " %c=%s", toupper(driver_kind[1]), driver_name); } else if (driver_kind) g = string_append(g, 2, US" ", driver_kind); -/*XXX need an s+s+p sprintf */ -g = string_cat(g, string_sprintf(" defer (%d)", addr->basic_errno)); +g = string_fmt_append(g, " defer (%d)", addr->basic_errno); if (addr->basic_errno > 0) g = string_append(g, 2, US": ", @@ -1345,8 +1362,7 @@ if (addr->host_used) if (LOGGING(outgoing_port)) { int port = addr->host_used->port; - g = string_append(g, 2, - US":", port == PORT_NONE ? US"25" : string_sprintf("%d", port)); + g = string_fmt_append(g, ":%d", port == PORT_NONE ? 25 : port); } } @@ -1383,6 +1399,16 @@ failure_log(address_item * addr, uschar * driver_kind, uschar * now) void * reset_point; gstring * g = reset_point = string_get(256); +#ifndef DISABLE_EVENT +/* Message failures for which we will send a DSN get their event raised +later so avoid doing it here. */ + +if ( !addr->prop.ignore_error + && !(addr->dsn_flags & (rf_dsnflags & ~rf_notify_failure)) + ) + msg_event_raise(US"msg:fail:delivery", addr); +#endif + /* Build up the log line for the message and main logs */ /* Create the address string for logging. Must not do this earlier, because @@ -1431,10 +1457,6 @@ else log_write(0, LOG_MAIN, "** %s", g->s); -#ifndef DISABLE_EVENT -msg_event_raise(US"msg:fail:delivery", addr); -#endif - store_reset(reset_point); return; } @@ -1766,13 +1788,12 @@ addr->basic_errno = code; if (format) { va_list ap; - uschar buffer[512]; + gstring * g; + va_start(ap, format); - if (!string_vformat(buffer, sizeof(buffer), CS format, ap)) - log_write(0, LOG_MAIN|LOG_PANIC_DIE, - "common_error expansion was longer than " SIZE_T_FMT, sizeof(buffer)); + g = string_vformat(NULL, TRUE, CS format, ap); va_end(ap); - addr->message = string_copy(buffer); + addr->message = string_from_gstring(g); } for (addr2 = addr->next; addr2; addr2 = addr2->next) @@ -3296,8 +3317,8 @@ small items (less than PIPE_BUF, which seems to be at least 512 in any Unix and often bigger) so even if we are reading while the subprocess is still going, we should never have only a partial item in the buffer. -hs12: This assumption is not true anymore, since we got quit large items (certificate -information and such) +hs12: This assumption is not true anymore, since we get quite large items (certificate +information and such). Argument: poffset the offset of the parlist item @@ -3557,6 +3578,9 @@ while (!done) case 'L': switch (*subid) { +#ifdef EXPERIMENTAL_PIPE_CONNECT + case 2: setflag(addr, af_early_pipe); /*FALLTHROUGH*/ +#endif case 1: setflag(addr, af_pipelining); break; } break; @@ -3568,6 +3592,7 @@ while (!done) case 'T': setflag(addr, af_tcp_fastopen_conn); if (*subid > '0') setflag(addr, af_tcp_fastopen); + if (*subid > '1') setflag(addr, af_tcp_fastopen_data); break; case 'D': @@ -4666,12 +4691,10 @@ all pipes, so I do not see a reason to use non-blocking IO here search_tidyup(); - if ((pid = fork()) == 0) { int fd = pfd[pipe_write]; host_item *h; - DEBUG(D_deliver) debug_selector |= D_pid; // hs12 /* Setting this global in the subprocess means we need never clear it */ transport_name = tp->name; @@ -4867,6 +4890,11 @@ all pipes, so I do not see a reason to use non-blocking IO here #endif if (testflag(addr, af_pipelining)) +#ifdef EXPERIMENTAL_PIPE_CONNECT + if (testflag(addr, af_early_pipe)) + rmt_dlv_checked_write(fd, 'L', '2', NULL, 0); + else +#endif rmt_dlv_checked_write(fd, 'L', '1', NULL, 0); if (testflag(addr, af_chunking_used)) @@ -4874,7 +4902,9 @@ all pipes, so I do not see a reason to use non-blocking IO here if (testflag(addr, af_tcp_fastopen_conn)) rmt_dlv_checked_write(fd, 'T', - testflag(addr, af_tcp_fastopen) ? '1' : '0', NULL, 0); + testflag(addr, af_tcp_fastopen) ? testflag(addr, af_tcp_fastopen_data) + ? '2' : '1' : '0', + NULL, 0); memcpy(big_buffer, &addr->dsn_aware, sizeof(addr->dsn_aware)); rmt_dlv_checked_write(fd, 'D', '0', big_buffer, sizeof(addr->dsn_aware)); @@ -5569,7 +5599,8 @@ message size. This use of strcpy() is OK because the length id is checked when it is obtained from a command line (the -M or -q options), and otherwise it is known to be a valid message id. */ -Ustrcpy(message_id, id); +if (id != message_id) + Ustrcpy(message_id, id); f.deliver_force = forced; return_count = 0; message_size = 0; @@ -6171,19 +6202,19 @@ if (process_recipients != RECIP_IGNORE) /* RECIP_DEFER is set when a system filter freezes a message. */ case RECIP_DEFER: - new->next = addr_defer; - addr_defer = new; - break; + new->next = addr_defer; + addr_defer = new; + break; /* RECIP_FAIL_FILTER is set when a system filter has obeyed a "fail" command. */ case RECIP_FAIL_FILTER: - new->message = - filter_message ? filter_message : US"delivery cancelled"; - setflag(new, af_pass_message); - goto RECIP_QUEUE_FAILED; /* below */ + new->message = + filter_message ? filter_message : US"delivery cancelled"; + setflag(new, af_pass_message); + goto RECIP_QUEUE_FAILED; /* below */ /* RECIP_FAIL_TIMEOUT is set when a message is frozen, but is older @@ -6193,15 +6224,15 @@ if (process_recipients != RECIP_IGNORE) been logged. */ case RECIP_FAIL_TIMEOUT: - new->message = US"delivery cancelled; message timed out"; - goto RECIP_QUEUE_FAILED; /* below */ + new->message = US"delivery cancelled; message timed out"; + goto RECIP_QUEUE_FAILED; /* below */ /* RECIP_FAIL is set when -Mg has been used. */ case RECIP_FAIL: - new->message = US"delivery cancelled by administrator"; - /* Fall through */ + new->message = US"delivery cancelled by administrator"; + /* Fall through */ /* Common code for the failure cases above. If this is not a bounce message, put the address on the failed list so that it is used to @@ -6209,11 +6240,11 @@ if (process_recipients != RECIP_IGNORE) The incident has already been logged. */ RECIP_QUEUE_FAILED: - if (sender_address[0] != 0) - { - new->next = addr_failed; - addr_failed = new; - } + if (sender_address[0]) + { + new->next = addr_failed; + addr_failed = new; + } break; @@ -6222,17 +6253,17 @@ if (process_recipients != RECIP_IGNORE) is a bounce message, it will get frozen. */ case RECIP_FAIL_LOOP: - new->message = US"Too many \"Received\" headers - suspected mail loop"; - post_process_one(new, FAIL, LOG_MAIN, EXIM_DTYPE_ROUTER, 0); - break; + new->message = US"Too many \"Received\" headers - suspected mail loop"; + post_process_one(new, FAIL, LOG_MAIN, EXIM_DTYPE_ROUTER, 0); + break; /* Value should be RECIP_ACCEPT; take this as the safe default. */ default: - if (!addr_new) addr_new = new; else addr_last->next = new; - addr_last = new; - break; + if (!addr_new) addr_new = new; else addr_last->next = new; + addr_last = new; + break; } #ifndef DISABLE_EVENT @@ -6240,17 +6271,23 @@ if (process_recipients != RECIP_IGNORE) { uschar * save_local = deliver_localpart; const uschar * save_domain = deliver_domain; + uschar * addr = new->address, * errmsg = NULL; + int start, end, dom; - deliver_localpart = expand_string( - string_sprintf("${local_part:%s}", new->address)); - deliver_domain = expand_string( - string_sprintf("${domain:%s}", new->address)); + if (!parse_extract_address(addr, &errmsg, &start, &end, &dom, TRUE)) + log_write(0, LOG_MAIN|LOG_PANIC, + "failed to parse address '%.100s': %s\n", addr, errmsg); + else + { + deliver_localpart = + string_copyn(addr+start, dom ? (dom-1) - start : end - start); + deliver_domain = dom ? CUS string_copyn(addr+dom, end - dom) : CUS""; - (void) event_raise(event_action, - US"msg:fail:internal", new->message); + event_raise(event_action, US"msg:fail:internal", new->message); - deliver_localpart = save_local; - deliver_domain = save_domain; + deliver_localpart = save_local; + deliver_domain = save_domain; + } } #endif } @@ -7248,7 +7285,6 @@ for (addr_dsntmp = addr_succeed; addr_dsntmp; addr_dsntmp = addr_dsntmp->next) 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 ) { @@ -7282,7 +7318,7 @@ if (addr_senddsn) } else /* Creation of child succeeded */ { - FILE *f = fdopen(fd, "wb"); + FILE * f = fdopen(fd, "wb"); /* header only as required by RFC. only failure DSN needs to honor RET=FULL */ uschar * bound; transport_ctx tctx = {{0}}; @@ -7315,11 +7351,9 @@ if (addr_senddsn) addr_dsntmp = addr_dsntmp->next) fprintf(f, "<%s> (relayed %s)\n\n", addr_dsntmp->address, - (addr_dsntmp->dsn_flags & rf_dsnlasthop) == 1 - ? "via non DSN router" - : addr_dsntmp->dsn_aware == dsn_support_no - ? "to non-DSN-aware mailer" - : "via non \"Remote SMTP\" router" + addr_dsntmp->dsn_flags & rf_dsnlasthop ? "via non DSN router" + : addr_dsntmp->dsn_aware == dsn_support_no ? "to non-DSN-aware mailer" + : "via non \"Remote SMTP\" router" ); fprintf(f, "--%s\n" @@ -7354,7 +7388,7 @@ if (addr_senddsn) addr_dsntmp->host_used->name); else fprintf(f, "Diagnostic-Code: X-Exim; relayed via non %s router\n\n", - (addr_dsntmp->dsn_flags & rf_dsnlasthop) == 1 ? "DSN" : "SMTP"); + addr_dsntmp->dsn_flags & rf_dsnlasthop ? "DSN" : "SMTP"); } fprintf(f, "--%s\nContent-type: text/rfc822-headers\n\n", bound); @@ -7365,8 +7399,10 @@ if (addr_senddsn) /* Write the original email out */ - tctx.u.fd = fileno(f); + tctx.u.fd = fd; tctx.options = topt_add_return_path | topt_no_body; + /*XXX hmm, retval ignored. + Could error for any number of reasons, and they are not handled. */ transport_write_message(&tctx, 0); fflush(f); @@ -7435,14 +7471,16 @@ while (addr_failed) mark the recipient done. */ if ( addr_failed->prop.ignore_error - || ( addr_failed->dsn_flags & rf_dsnflags - && (addr_failed->dsn_flags & rf_notify_failure) != rf_notify_failure - ) ) + || addr_failed->dsn_flags & (rf_dsnflags & ~rf_notify_failure) + ) { addr = addr_failed; addr_failed = addr->next; if (addr->return_filename) Uunlink(addr->return_filename); +#ifndef DISABLE_EVENT + msg_event_raise(US"msg:fail:delivery", addr); +#endif log_write(0, LOG_MAIN, "%s%s%s%s: error ignored", addr->address, !addr->parent ? US"" : US" <", @@ -7832,6 +7870,7 @@ wording. */ tctx.options = topt; tb.add_headers = dsnnotifyhdr; + /*XXX no checking for failure! buggy! */ transport_write_message(&tctx, 0); } fflush(fp); @@ -8074,8 +8113,8 @@ else if (addr_defer != (address_item *)(+1)) if ( !f.queue_2stage && delivery_attempted - && ( ((addr_defer->dsn_flags & rf_dsnflags) == 0) - || (addr_defer->dsn_flags & rf_notify_delay) == rf_notify_delay + && ( !(addr_defer->dsn_flags & rf_dsnflags) + || addr_defer->dsn_flags & rf_notify_delay ) && delay_warning[1] > 0 && sender_address[0] != 0 @@ -8298,6 +8337,7 @@ else if (addr_defer != (address_item *)(+1)) return_path = sender_address; /* In case not previously set */ /* Write the original email out */ + /*XXX no checking for failure! buggy! */ transport_write_message(&tctx, 0); fflush(f); @@ -8461,8 +8501,7 @@ 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); + regex_must_compile(AUTHS_REGEX, FALSE, TRUE); #ifdef SUPPORT_TLS if (!regex_STARTTLS) regex_STARTTLS = @@ -8492,6 +8531,11 @@ if (!regex_DSN) regex_DSN = if (!regex_IGNOREQUOTA) regex_IGNOREQUOTA = regex_must_compile(US"\\n250[\\s\\-]IGNOREQUOTA(\\s|\\n|$)", FALSE, TRUE); + +#ifdef EXPERIMENTAL_PIPE_CONNECT +if (!regex_EARLY_PIPE) regex_EARLY_PIPE = + regex_must_compile(US"\\n250[\\s\\-]" EARLY_PIPE_FEATURE_NAME "(\\s|\\n|$)", FALSE, TRUE); +#endif } @@ -8597,6 +8641,7 @@ else } return; /* compiler quietening; control does not reach here. */ +#ifdef SUPPORT_TLS fail: log_write(0, LOG_MAIN | (exec_type == CEE_EXEC_EXIT ? LOG_PANIC : LOG_PANIC_DIE), @@ -8606,6 +8651,7 @@ fail: Note: this must be _exit(), not exit(). */ _exit(EX_EXECFAILED); +#endif } /* vi: aw ai sw=2