X-Git-Url: https://git.exim.org/exim.git/blobdiff_plain/35b7b6ff525028eef69cf19d86f77deb1a84b7c9..a7538db17824b7fd70c12ef7561a67b85d6f247e:/src/src/deliver.c diff --git a/src/src/deliver.c b/src/src/deliver.c index c2f769da6..48d3fd7ec 100644 --- a/src/src/deliver.c +++ b/src/src/deliver.c @@ -141,11 +141,13 @@ the first address. */ if (addr->host_list == NULL) { deliver_host = deliver_host_address = US""; + deliver_host_port = 0; } else { deliver_host = addr->host_list->name; deliver_host_address = addr->host_list->address; + deliver_host_port = addr->host_list->port; } deliver_recipients = addr; @@ -705,6 +707,43 @@ d_tlslog(uschar * s, int * sizep, int * ptrp, address_item * addr) } #endif + +#ifdef EXPERIMENTAL_TPDA +int +tpda_raise_event(uschar * action, uschar * event, uschar * ev_data) +{ +uschar * s; +if (action) + { + DEBUG(D_deliver) + debug_printf("TPDA(%s): tpda_event_action=|%s| tpda_delivery_IP=%s\n", + event, + action, deliver_host_address); + + tpda_event = event; + tpda_data = ev_data; + + if (!(s = expand_string(action)) && *expand_string_message) + log_write(0, LOG_MAIN|LOG_PANIC, + "failed to expand tpda_event_action %s in %s: %s\n", + event, transport_name, expand_string_message); + + tpda_event = tpda_data = NULL; + + /* If the expansion returns anything but an empty string, flag for + the caller to modify his normal processing + */ + if (s && *s) + { + DEBUG(D_deliver) + debug_printf("TPDA(%s): event_action returned \"%s\"\n", s); + return DEFER; + } + } +return OK; +} +#endif + /* If msg is NULL this is a delivery log and logchar is used. Otherwise this is a nonstandard call; no two-character delivery flag is written but sender-host and sender are prefixed and "msg" is inserted in the log line. @@ -728,12 +767,7 @@ 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; + /* presume no successful remote delivery */ lookup_dnssec_authenticated = NULL; #endif @@ -782,13 +816,8 @@ if ((log_extra_selector & LX_delivery_size) != 0) if (addr->transport->info->local) { - if (addr->host_list != NULL) - { + if (addr->host_list) 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)); @@ -804,24 +833,20 @@ else 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; +#ifdef EXPERIMENTAL_TPDA + deliver_host_address = addr->host_used->address; + deliver_host_port = addr->host_used->port; /* DNS lookup status */ lookup_dnssec_authenticated = addr->host_used->dnssec==DS_YES ? US"yes" : addr->host_used->dnssec==DS_NO ? US"no" : NULL; - #endif +#endif } - #ifdef SUPPORT_TLS +#ifdef SUPPORT_TLS s = d_tlslog(s, &size, &ptr, addr); - #endif +#endif if (addr->authenticator) { @@ -834,10 +859,10 @@ else } } - #ifndef DISABLE_PRDR +#ifndef DISABLE_PRDR if (addr->flags & af_prdr_used) s = string_append(s, &size, &ptr, 1, US" PRDR"); - #endif +#endif } /* confirmation message (SMTP (host_used) and LMTP (driver_name)) */ @@ -863,16 +888,12 @@ if (log_extra_selector & LX_smtp_confirmation && /* Time on queue and actual time taken to deliver */ if ((log_extra_selector & LX_queue_time) != 0) - { s = string_append(s, &size, &ptr, 2, US" QT=", - readconf_printtime(time(NULL) - received_time)); - } + readconf_printtime( (int) ((long)time(NULL) - (long)received_time)) ); if ((log_extra_selector & LX_deliver_time) != 0) - { s = string_append(s, &size, &ptr, 2, US" DT=", readconf_printtime(addr->more_errno)); - } /* string_cat() always leaves room for the terminator. Release the store we used to build the line after writing it. */ @@ -881,19 +902,22 @@ 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; + uschar * save_domain = deliver_domain; + uschar * save_local = deliver_localpart; + + router_name = addr->router ? addr->router->name : NULL; + transport_name = addr->transport ? addr->transport->name : NULL; + deliver_domain = addr->domain; + deliver_localpart = addr->local_part; + + (void) tpda_raise_event(addr->transport->tpda_event_action, US"msg:delivery", + addr->host_used || Ustrcmp(addr->transport->driver_name, "lmtp") == 0 + ? addr->message : NULL); + + deliver_localpart = save_local; + deliver_domain = save_domain; + router_name = transport_name = NULL; } #endif store_reset(reset_point); @@ -1093,7 +1117,7 @@ if (result == OK) } /* Certificates for logging (via TPDA) */ - #ifdef SUPPORT_TLS +#ifdef SUPPORT_TLS tls_out.ourcert = addr->ourcert; addr->ourcert = NULL; tls_out.peercert = addr->peercert; @@ -1102,11 +1126,11 @@ if (result == OK) tls_out.cipher = addr->cipher; tls_out.peerdn = addr->peerdn; tls_out.ocsp = addr->ocsp; - #endif +#endif delivery_log(LOG_MAIN, addr, logchar, NULL); - #ifdef SUPPORT_TLS +#ifdef SUPPORT_TLS if (tls_out.ourcert) { tls_free_cert(tls_out.ourcert); @@ -1120,7 +1144,7 @@ if (result == OK) tls_out.cipher = NULL; tls_out.peerdn = NULL; tls_out.ocsp = OCSP_NOT_REQ; - #endif +#endif } @@ -1301,9 +1325,9 @@ else if (addr->host_used != NULL) s = d_hostlog(s, &size, &ptr, addr); - #ifdef SUPPORT_TLS +#ifdef SUPPORT_TLS s = d_tlslog(s, &size, &ptr, addr); - #endif +#endif if (addr->basic_errno > 0) s = string_append(s, &size, &ptr, 2, US": ", @@ -1892,19 +1916,19 @@ if ((pid = fork()) == 0) diagnosis that it's reasonable to make them something that has to be explicitly requested. */ - #ifdef RLIMIT_CORE +#ifdef RLIMIT_CORE struct rlimit rl; rl.rlim_cur = 0; rl.rlim_max = 0; if (setrlimit(RLIMIT_CORE, &rl) < 0) { - #ifdef SETRLIMIT_NOT_SUPPORTED +# ifdef SETRLIMIT_NOT_SUPPORTED if (errno != ENOSYS && errno != ENOTSUP) - #endif +# endif log_write(0, LOG_MAIN|LOG_PANIC, "setrlimit(RLIMIT_CORE) failed: %s", strerror(errno)); } - #endif +#endif /* Reset the random number generator, so different processes don't all have the same sequence. */ @@ -2991,7 +3015,7 @@ while (!done) it in with the other info, in order to keep each message short enough to guarantee it won't be split in the pipe. */ - #ifdef SUPPORT_TLS +#ifdef SUPPORT_TLS case 'X': if (addr == NULL) goto ADDR_MISMATCH; /* Below, in 'A' handler */ switch (*ptr++) @@ -3019,17 +3043,17 @@ while (!done) (void) tls_import_cert(ptr, &addr->ourcert); break; - #ifndef DISABLE_OCSP +# ifndef DISABLE_OCSP case '4': addr->ocsp = OCSP_NOT_REQ; if (*ptr) addr->ocsp = *ptr - '0'; break; - #endif +# endif } while (*ptr++); break; - #endif /*SUPPORT_TLS*/ +#endif /*SUPPORT_TLS*/ case 'C': /* client authenticator information */ switch (*ptr++) @@ -3053,14 +3077,14 @@ while (!done) break; #endif - #ifdef EXPERIMENTAL_DSN +#ifdef EXPERIMENTAL_DSN case 'D': if (addr == NULL) break; 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 +#endif case 'A': if (addr == NULL) @@ -3958,11 +3982,11 @@ for (delivery_count = 0; addr_remote != NULL; delivery_count++) that it can use either of them, though it prefers O_NONBLOCK, which distinguishes between EOF and no-more-data. */ - #ifdef O_NONBLOCK +#ifdef O_NONBLOCK (void)fcntl(pfd[pipe_read], F_SETFL, O_NONBLOCK); - #else +#else (void)fcntl(pfd[pipe_read], F_SETFL, O_NDELAY); - #endif +#endif /* If the maximum number of subprocesses already exist, wait for a process to finish. If we ran out of file descriptors, parmax will have been reduced @@ -4131,7 +4155,7 @@ for (delivery_count = 0; addr_remote != NULL; delivery_count++) if (tls_out.certificate_verified) setflag(addr, af_cert_verified); /* Use an X item only if there's something to send */ - #ifdef SUPPORT_TLS +#ifdef SUPPORT_TLS if (addr->cipher) { ptr = big_buffer; @@ -4167,7 +4191,7 @@ for (delivery_count = 0; addr_remote != NULL; delivery_count++) *ptr++ = 0; rmt_dlv_checked_write(fd, big_buffer, ptr - big_buffer); } - #ifndef DISABLE_OCSP +# ifndef DISABLE_OCSP if (addr->ocsp > OCSP_NOT_REQ) { ptr = big_buffer; @@ -4175,8 +4199,8 @@ for (delivery_count = 0; addr_remote != NULL; delivery_count++) while(*ptr++); rmt_dlv_checked_write(fd, big_buffer, ptr - big_buffer); } - # endif - #endif /*SUPPORT_TLS*/ +# endif +#endif /*SUPPORT_TLS*/ if (client_authenticator) { @@ -4200,17 +4224,17 @@ for (delivery_count = 0; addr_remote != NULL; delivery_count++) rmt_dlv_checked_write(fd, big_buffer, ptr - big_buffer); } - #ifndef DISABLE_PRDR +#ifndef DISABLE_PRDR if (addr->flags & af_prdr_used) rmt_dlv_checked_write(fd, "P", 1); - #endif +#endif - #ifdef EXPERIMENTAL_DSN +#ifdef EXPERIMENTAL_DSN big_buffer[0] = 'D'; memcpy(big_buffer+1, &addr->dsn_aware, sizeof(addr->dsn_aware)); rmt_dlv_checked_write(fd, big_buffer, sizeof(addr->dsn_aware) + 1); DEBUG(D_deliver) debug_printf("DSN write: addr->dsn_aware = %d\n", addr->dsn_aware); - #endif +#endif /* Retry information: for most success cases this will be null. */ @@ -4925,7 +4949,7 @@ attempted. */ if (deliver_freeze) { - #ifdef SUPPORT_MOVE_FROZEN_MESSAGES +#ifdef SUPPORT_MOVE_FROZEN_MESSAGES /* Moving to another directory removes the message from Exim's view. Other tools must be used to deal with it. Logging of this action happens in spool_move_message() and its subfunctions. */ @@ -4933,7 +4957,7 @@ if (deliver_freeze) if (move_frozen_messages && spool_move_message(id, message_subdir, US"", US"F")) return continue_closedown(); /* yields DELIVER_NOT_ATTEMPTED */ - #endif +#endif /* For all frozen messages (bounces or not), timeout_frozen_after sets the maximum time to keep messages that are frozen. Thaw if we reach it, with a @@ -5362,13 +5386,13 @@ if (process_recipients != RECIP_IGNORE) if (r->pno >= 0) new->onetime_parent = recipients_list[r->pno].address; - #ifdef EXPERIMENTAL_DSN +#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 +#endif switch (process_recipients) { @@ -6304,21 +6328,21 @@ if (addr_remote != NULL) regex_must_compile(US"\\n250[\\s\\-]AUTH\\s+([\\-\\w\\s]+)(?:\\n|$)", FALSE, TRUE); - #ifdef SUPPORT_TLS +#ifdef SUPPORT_TLS if (regex_STARTTLS == NULL) regex_STARTTLS = regex_must_compile(US"\\n250[\\s\\-]STARTTLS(\\s|\\n|$)", FALSE, TRUE); - #endif +#endif - #ifndef DISABLE_PRDR +#ifndef DISABLE_PRDR if (regex_PRDR == NULL) regex_PRDR = regex_must_compile(US"\\n250[\\s\\-]PRDR(\\s|\\n|$)", FALSE, TRUE); - #endif +#endif - #ifdef EXPERIMENTAL_DSN +#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 +#endif /* Now sort the addresses if required, and do the deliveries. The yield of do_remote_deliveries is FALSE when mua_wrapper is set and all addresses @@ -6497,74 +6521,77 @@ if (addr_senddsn != NULL) DEBUG(D_deliver) debug_printf("sending error message to: %s\n", sender_address); /* build unique id for MIME boundary */ - snprintf(boundaryStr, 63, "%l-eximdsn-%d", (long) time(NULL), rand()); + snprintf(boundaryStr, sizeof(boundaryStr)-1, TIME_T_FMT "-eximdsn-%d", + time(NULL), rand()); DEBUG(D_deliver) debug_printf("DSN: MIME boundary: %s\n", boundaryStr); - if (errors_reply_to != NULL) fprintf(f,"Reply-To: %s\n", errors_reply_to); + if (errors_reply_to) + fprintf(f, "Reply-To: %s\n", errors_reply_to); - fprintf(f,"Auto-Submitted: auto-generated\n"); - fprintf(f,"From: Mail Delivery System \n", qualify_domain_sender); - fprintf(f,"To: %s\n", sender_address); - fprintf(f,"Subject: Delivery Status Notification\n"); - fprintf(f,"Content-Type: multipart/report; report-type=delivery-status; boundary=%s\n", boundaryStr); - fprintf(f,"MIME-Version: 1.0\n\n"); - - fprintf(f,"--%s\n", boundaryStr); - fprintf(f,"Content-type: text/plain; charset=us-ascii\n\n"); + fprintf(f, "Auto-Submitted: auto-generated\n" + "From: Mail Delivery System \n" + "To: %s\n" + "Subject: Delivery Status Notification\n" + "Content-Type: multipart/report; report-type=delivery-status; boundary=%s\n" + "MIME-Version: 1.0\n\n" + + "--%s\n" + "Content-type: text/plain; charset=us-ascii\n\n" - fprintf(f,"This message was created automatically by mail delivery software.\n"); - fprintf(f," ----- The following addresses had successful delivery notifications -----\n"); + "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); addr_dsntmp = addr_senddsn; - while(addr_dsntmp != NULL) + while(addr_dsntmp) { - if ((addr_dsntmp->dsn_flags & rf_dsnlasthop) == 1) { - fprintf(f,"<%s> (relayed via non DSN router)\n\n", addr_dsntmp->address); - } - else if (addr_dsntmp->dsn_aware == dsn_support_no) { - fprintf(f,"<%s> (relayed to non-DSN-aware mailer)\n\n", addr_dsntmp->address); - } - else { - fprintf(f,"<%s> (relayed via non \"Remote SMTP\" router)\n\n", addr_dsntmp->address); - } + 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 = addr_dsntmp->next; } - fprintf(f,"--%s\n", boundaryStr); - fprintf(f,"Content-type: message/delivery-status\n\n"); - - fprintf(f,"Reporting-MTA: dns; %s\n", smtp_active_hostname); + fprintf(f, "--%s\n" + "Content-type: message/delivery-status\n\n" + "Reporting-MTA: dns; %s\n", + boundaryStr, smtp_active_hostname); + if (dsn_envid != NULL) { /* 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); + fprintf(f, "Original-Envelope-ID: %s\n", dsn_envid); else - fprintf(f,"X-Original-Envelope-ID: error decoding xtext formated ENVID\n"); + fprintf(f, "X-Original-Envelope-ID: error decoding xtext formated ENVID\n"); } - fprintf(f,"\n"); + fputc('\n', f); - addr_dsntmp = addr_senddsn; - while(addr_dsntmp != NULL) + for (addr_dsntmp = addr_senddsn; + addr_dsntmp; + addr_dsntmp = addr_dsntmp->next) { - if (addr_dsntmp->dsn_orcpt != NULL) { + if (addr_dsntmp->dsn_orcpt) fprintf(f,"Original-Recipient: %s\n", addr_dsntmp->dsn_orcpt); - } - fprintf(f,"Action: delivered\n"); - fprintf(f,"Final-Recipient: rfc822;%s\n", addr_dsntmp->address); - fprintf(f,"Status: 2.0.0\n"); - if ((addr_dsntmp->host_used != NULL) && (addr_dsntmp->host_used->name != NULL)) - fprintf(f,"Remote-MTA: dns; %s\nDiagnostic-Code: smtp; 250 Ok\n", addr_dsntmp->host_used->name); + + fprintf(f, "Action: delivered\n" + "Final-Recipient: rfc822;%s\n" + "Status: 2.0.0\n", + 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", + addr_dsntmp->host_used->name); else - if ((addr_dsntmp->dsn_flags & rf_dsnlasthop) == 1) - fprintf(f,"Diagnostic-Code: X-Exim; relayed via non DSN router\n"); - else - fprintf(f,"Diagnostic-Code: X-Exim; relayed via non SMTP router\n"); - fprintf(f,"\n"); - addr_dsntmp = addr_dsntmp->next; + fprintf(f,"Diagnostic-Code: X-Exim; relayed via non %s router\n", + (addr_dsntmp->dsn_flags & rf_dsnlasthop) == 1 ? "DSN" : "SMTP"); + fputc('\n', f); } - fprintf(f,"--%s\n", boundaryStr); - fprintf(f,"Content-type: text/rfc822-headers\n\n"); + fprintf(f, "--%s\nContent-type: text/rfc822-headers\n\n", boundaryStr); fflush(f); transport_filter_argv = NULL; /* Just in case */ @@ -6582,7 +6609,7 @@ if (addr_senddsn != NULL) rc = child_close(pid, 0); /* Waits for child to close, no timeout */ } } -#endif +#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 @@ -6699,6 +6726,12 @@ 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 *dsnlimitmsg; + uschar *dsnnotifyhdr; + int topt; +#endif DEBUG(D_deliver) debug_printf("sending error message to: %s\n", bounce_recipient); @@ -6754,69 +6787,68 @@ while (addr_failed != NULL) #ifdef EXPERIMENTAL_DSN /* generate boundary string and output MIME-Headers */ - uschar boundaryStr[64]; - snprintf(boundaryStr, 63, "%l-eximdsn-%d", (long) time(NULL), rand()); - fprintf(f,"Content-Type: multipart/report; report-type=delivery-status; boundary=%s\n", boundaryStr); - fprintf(f,"MIME-Version: 1.0\n"); + snprintf(boundaryStr, sizeof(boundaryStr)-1, 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 /* Open a template file if one is provided. Log failure to open, but carry on - default texts will be used. */ - if (bounce_message_file != NULL) - { - emf = Ufopen(bounce_message_file, "rb"); - if (emf == NULL) + if (bounce_message_file) + if (!(emf = Ufopen(bounce_message_file, "rb"))) log_write(0, LOG_MAIN|LOG_PANIC, "Failed to open %s for error " "message texts: %s", bounce_message_file, strerror(errno)); - } /* Quietly copy to configured additional addresses if required. */ - bcc = moan_check_errorcopy(bounce_recipient); - if (bcc != NULL) fprintf(f, "Bcc: %s\n", bcc); + if ((bcc = moan_check_errorcopy(bounce_recipient))) + fprintf(f, "Bcc: %s\n", bcc); /* The texts for the message can be read from a template file; if there isn't one, or if it is too short, built-in texts are used. The first emf text is a Subject: and any other headers. */ - emf_text = next_emf(emf, US"header"); - if (emf_text != NULL) fprintf(f, "%s\n", emf_text); else - { + if ((emf_text = next_emf(emf, US"header"))) + fprintf(f, "%s\n", emf_text); + else 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", boundaryStr); - fprintf(f,"Content-type: text/plain; charset=us-ascii\n\n"); + fprintf(f, "--%s\n" + "Content-type: text/plain; charset=us-ascii\n\n", + boundaryStr); #endif - emf_text = next_emf(emf, US"intro"); - if (emf_text != NULL) fprintf(f, "%s", CS emf_text); else + if ((emf_text = next_emf(emf, US"intro"))) + fprintf(f, "%s", CS emf_text); + else { fprintf(f, /* This message has been reworded several times. It seems to be confusing to somebody, however it is worded. I have retreated to the original, simple wording. */ "This message was created automatically by mail delivery software.\n"); - if (bounce_message_text != NULL) fprintf(f, "%s", CS bounce_message_text); + + if (bounce_message_text) + fprintf(f, "%s", CS bounce_message_text); if (to_sender) - { fprintf(f, "\nA message that you sent could not be delivered to one or more of its\n" "recipients. This is a permanent error. The following address(es) failed:\n"); - } else - { fprintf(f, "\nA message sent by\n\n <%s>\n\n" "could not be delivered to one or more of its recipients. The following\n" "address(es) failed:\n", sender_address); - } } - fprintf(f, "\n"); + fputc('\n', f); /* Process the addresses, leaving them on the msgchain if they have a file name for a return message. (There has already been a check in @@ -6853,7 +6885,7 @@ wording. */ } } - fprintf(f, "\n"); + fputc('\n', f); /* Get the next text, whether we need it or not, so as to be positioned for the one after. */ @@ -6867,11 +6899,13 @@ wording. */ fd, and the return_filename field in the *last* one will be set (to the name of the file). */ - if (msgchain != NULL) + if (msgchain) { address_item *nextaddr; - if (emf_text != NULL) fprintf(f, "%s", CS emf_text); else + if (emf_text) + fprintf(f, "%s", CS emf_text); + else fprintf(f, "The following text was generated during the delivery " "attempt%s:\n", (filecount > 1)? "s" : ""); @@ -6883,15 +6917,15 @@ wording. */ /* List all the addresses that relate to this file */ - fprintf(f, "\n"); - while(addr != NULL) /* Insurance */ + fputc('\n', f); + while(addr) /* Insurance */ { print_address_information(addr, f, US"------ ", US"\n ", US" ------\n"); - if (addr->return_filename != NULL) break; + if (addr->return_filename) break; addr = addr->next; } - fprintf(f, "\n"); + fputc('\n', f); /* Now copy the file */ @@ -6914,32 +6948,36 @@ wording. */ addr->next = handled_addr; handled_addr = topaddr; } - fprintf(f, "\n"); + fputc('\n', f); } #ifdef EXPERIMENTAL_DSN /* output machine readable part */ - fprintf(f,"--%s\n", boundaryStr); - fprintf(f,"Content-type: message/delivery-status\n\n"); - - fprintf(f,"Reporting-MTA: dns; %s\n", smtp_active_hostname); - if (dsn_envid != NULL) { + fprintf(f, "--%s\n" + "Content-type: message/delivery-status\n\n" + "Reporting-MTA: dns; %s\n", + boundaryStr, smtp_active_hostname); + + 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); + fprintf(f, "Original-Envelope-ID: %s\n", dsn_envid); else - fprintf(f,"X-Original-Envelope-ID: error decoding xtext formated ENVID\n"); + fprintf(f, "X-Original-Envelope-ID: error decoding xtext formated ENVID\n"); } - fprintf(f,"\n"); + fputc('\n', f); - for (addr = handled_addr; addr != NULL; addr = addr->next) + for (addr = handled_addr; addr; addr = addr->next) { - fprintf(f,"Action: failed\n"); - fprintf(f,"Final-Recipient: rfc822;%s\n", addr->address); - fprintf(f,"Status: 5.0.0\n"); - if ((addr->host_used != NULL) && (addr->host_used->name != NULL)) - fprintf(f,"Remote-MTA: dns; %s\nDiagnostic-Code: smtp; %d\n", addr->host_used->name, addr->basic_errno); + fprintf(f, "Action: failed\n" + "Final-Recipient: rfc822;%s\n" + "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); } #endif @@ -6956,7 +6994,9 @@ wording. */ int topt = topt_add_return_path; if (!bounce_return_body) topt |= topt_no_body; - if (emf_text != NULL) fprintf(f, "%s", CS emf_text); else + 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"); @@ -6979,18 +7019,17 @@ wording. */ { struct stat statbuf; if (fstat(deliver_datafile, &statbuf) == 0 && statbuf.st_size > max) - { - if (emf_text != NULL) fprintf(f, "%s", CS emf_text); else - { + 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); - } - } } - fprintf(f, "\n"); + 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, @@ -6999,10 +7038,10 @@ wording. */ /* Write final text and close the template file if one is open */ - if (emf != NULL) + if (emf) { - emf_text = next_emf(emf, US"final"); - if (emf_text != NULL) fprintf(f, "%s", CS emf_text); + if ((emf_text = next_emf(emf, US"final"))) + fprintf(f, "%s", CS emf_text); (void)fclose(emf); } #else @@ -7017,11 +7056,12 @@ wording. */ bounce_return_size_limit is always honored. */ - fprintf(f,"\n--%s\n", boundaryStr); + fprintf(f, "\n--%s\n", boundaryStr); + + dsnlimitmsg = US"X-Exim-DSN-Information: Due to administrative limits only headers are returned"; + dsnnotifyhdr = NULL; + topt = topt_add_return_path; - uschar *dsnlimitmsg = US"X-Exim-DSN-Information: Due to administrative limits only headers are returned"; - uschar *dsnnotifyhdr = NULL; - int topt = topt_add_return_path; /* RET=HDRS? top priority */ if (dsn_ret == dsn_ret_hdrs) topt |= topt_no_body; @@ -7058,12 +7098,11 @@ wording. */ fflush(f); /* we never add the final text. close the file */ - if (emf != NULL) + if (emf) (void)fclose(emf); - fprintf(f,"\n"); - fprintf(f,"--%s--\n", boundaryStr); -#endif + fprintf(f, "\n--%s--\n", boundaryStr); +#endif /*EXPERIMENTAL_DSN*/ /* Close the file, which should send an EOF to the child process that is receiving the message. Wait for it to finish. */ @@ -7172,7 +7211,7 @@ if (addr_defer == NULL) if ((log_extra_selector & LX_queue_time_overall) != 0) log_write(0, LOG_MAIN, "Completed QT=%s", - readconf_printtime(time(NULL) - received_time)); + readconf_printtime( (int) ((long)time(NULL) - (long)received_time)) ); else log_write(0, LOG_MAIN, "Completed"); @@ -7363,8 +7402,11 @@ 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 - if (warn_message_file != NULL) + if (warn_message_file) { wmf = Ufopen(warn_message_file, "rb"); if (wmf == NULL) @@ -7377,7 +7419,7 @@ else if (addr_defer != (address_item *)(+1)) string_sprintf("%d minutes", show_time/60): string_sprintf("%d hours", show_time/3600); - 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); @@ -7385,14 +7427,16 @@ else if (addr_defer != (address_item *)(+1)) #ifdef EXPERIMENTAL_DSN /* generated boundary string and output MIME-Headers */ - uschar boundaryStr[64]; - snprintf(boundaryStr, 63, "%l-eximdsn-%d", (long) time(NULL), rand()); - fprintf(f,"Content-Type: multipart/report; report-type=delivery-status; boundary=%s\n", boundaryStr); - fprintf(f,"MIME-Version: 1.0\n"); + snprintf(boundaryStr, sizeof(boundaryStr)-1, + 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 - wmf_text = next_emf(wmf, US"header"); - if (wmf_text != NULL) + if ((wmf_text = next_emf(wmf, US"header"))) fprintf(f, "%s\n", wmf_text); else fprintf(f, "Subject: Warning: message %s delayed %s\n\n", @@ -7400,12 +7444,14 @@ else if (addr_defer != (address_item *)(+1)) #ifdef EXPERIMENTAL_DSN /* output human readable part as text/plain section */ - fprintf(f,"--%s\n", boundaryStr); - fprintf(f,"Content-type: text/plain; charset=us-ascii\n\n"); + fprintf(f, "--%s\n" + "Content-type: text/plain; charset=us-ascii\n\n", + boundaryStr); #endif - wmf_text = next_emf(wmf, US"intro"); - if (wmf_text != NULL) fprintf(f, "%s", CS wmf_text); else + if ((wmf_text = next_emf(wmf, US"intro"))) + fprintf(f, "%s", CS wmf_text); + else { fprintf(f, "This message was created automatically by mail delivery software.\n"); @@ -7415,28 +7461,27 @@ else if (addr_defer != (address_item *)(+1)) "A message that you sent has not yet been delivered to one or more of its\n" "recipients after more than "); - else fprintf(f, + else + fprintf(f, "A message sent by\n\n <%s>\n\n" "has not yet been delivered to one or more of its recipients after more than \n", - sender_address); + sender_address); - fprintf(f, "%s on the queue on %s.\n\n", warnmsg_delay, - primary_hostname); - fprintf(f, "The message identifier is: %s\n", message_id); + fprintf(f, "%s on the queue on %s.\n\n" + "The message identifier is: %s\n", + warnmsg_delay, primary_hostname, message_id); for (h = header_list; h != NULL; h = h->next) - { if (strncmpic(h->text, US"Subject:", 8) == 0) fprintf(f, "The subject of the message is: %s", h->text + 9); else if (strncmpic(h->text, US"Date:", 5) == 0) fprintf(f, "The date of the message is: %s", h->text + 6); - } - fprintf(f, "\n"); + fputc('\n', f); fprintf(f, "The address%s to which the message has not yet been " "delivered %s:\n", - (addr_defer->next == NULL)? "" : "es", - (addr_defer->next == NULL)? "is": "are"); + !addr_defer->next ? "" : "es", + !addr_defer->next ? "is": "are"); } /* List the addresses, with error information if allowed */ @@ -7445,23 +7490,23 @@ else if (addr_defer != (address_item *)(+1)) /* store addr_defer for machine readable part */ address_item *addr_dsndefer = addr_defer; #endif - fprintf(f, "\n"); - while (addr_defer != NULL) + fputc('\n', f); + while (addr_defer) { address_item *addr = addr_defer; addr_defer = addr->next; if (print_address_information(addr, f, US" ", US"\n ", US"")) print_address_error(addr, f, US"Delay reason: "); - fprintf(f, "\n"); + fputc('\n', f); } - fprintf(f, "\n"); + fputc('\n', f); /* Final text */ - if (wmf != NULL) + if (wmf) { - wmf_text = next_emf(wmf, US"final"); - if (wmf_text != NULL) fprintf(f, "%s", CS wmf_text); + if ((wmf_text = next_emf(wmf, US"final"))) + fprintf(f, "%s", CS wmf_text); (void)fclose(wmf); } else @@ -7475,11 +7520,15 @@ else if (addr_defer != (address_item *)(+1)) #ifdef EXPERIMENTAL_DSN /* output machine readable part */ - fprintf(f,"\n--%s\n", boundaryStr); - fprintf(f,"Content-type: message/delivery-status\n\n"); + fprintf(f, "\n--%s\n" + "Content-type: message/delivery-status\n\n" + "Reporting-MTA: dns; %s\n", + boundaryStr, + smtp_active_hostname); - fprintf(f,"Reporting-MTA: dns; %s\n", smtp_active_hostname); - if (dsn_envid != NULL) { + + if (dsn_envid) + { /* must be decoded from xtext: see RFC 3461:6.3a */ uschar *xdec_envid; if (auth_xtextdecode(dsn_envid, &xdec_envid) > 0) @@ -7487,24 +7536,25 @@ else if (addr_defer != (address_item *)(+1)) else fprintf(f,"X-Original-Envelope-ID: error decoding xtext formated ENVID\n"); } - fprintf(f,"\n"); + fputc('\n', f); - while (addr_dsndefer != NULL) + while (addr_dsndefer) { - if (addr_dsndefer->dsn_orcpt != NULL) { + if (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"); - if ((addr_dsndefer->host_used != NULL) && (addr_dsndefer->host_used->name != NULL)) + 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); + addr_dsndefer->host_used->name, addr_dsndefer->basic_errno); addr_dsndefer = addr_dsndefer->next; } - fprintf(f,"\n--%s\n", boundaryStr); - fprintf(f,"Content-type: text/rfc822-headers\n\n"); + fprintf(f, "\n--%s\n" + "Content-type: text/rfc822-headers\n\n", + boundaryStr); fflush(f); /* header only as required by RFC. only failure DSN needs to honor RET=FULL */ @@ -7515,11 +7565,10 @@ 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"); - fprintf(f,"--%s--\n", boundaryStr); + fprintf(f,"\n--%s--\n", boundaryStr); fflush(f); -#endif +#endif /*EXPERIMENTAL_DSN*/ /* Close and wait for child process to complete, without a timeout. If there's an error, don't update the count. */ @@ -7632,10 +7681,10 @@ if (remove_journal) /* Move the message off the spool if reqested */ - #ifdef SUPPORT_MOVE_FROZEN_MESSAGES +#ifdef SUPPORT_MOVE_FROZEN_MESSAGES if (deliver_freeze && move_frozen_messages) (void)spool_move_message(id, message_subdir, US"", US"F"); - #endif +#endif } /* Closing the data file frees the lock; if the file has been unlinked it