X-Git-Url: https://git.exim.org/exim.git/blobdiff_plain/e027f545443fd6a5ec74c48c27dcd8b6634d5bba..7b4c8c1fb37f58921e29b6c0753e621c5c854626:/src/src/transports/smtp.c diff --git a/src/src/transports/smtp.c b/src/src/transports/smtp.c index 00274656c..4403fe113 100644 --- a/src/src/transports/smtp.c +++ b/src/src/transports/smtp.c @@ -12,6 +12,8 @@ #define PENDING_DEFER (PENDING + DEFER) #define PENDING_OK (PENDING + OK) +#define DELIVER_BUFFER_SIZE 4096 + /* Options specific to the smtp transport. This transport also supports LMTP over TCP/IP. The options must be in alphabetic order (note that "_" comes @@ -264,7 +266,8 @@ smtp_transport_options_block smtp_transport_option_defaults = { NULL, /* dkim_private_key */ NULL, /* dkim_selector */ NULL, /* dkim_sign_headers */ - NULL} /* dkim_strict */ + NULL, /* dkim_strict */ + FALSE} /* dot_stuffed */ #endif }; @@ -1221,7 +1224,8 @@ switch (dns_lookup(dnsa, buffer, T_TLSA, &fullname)) case DNS_AGAIN: return DEFER; /* just defer this TLS'd conn */ - case DNS_NOMATCH: + case DNS_NODATA: /* no TLSA RR for this lookup */ + case DNS_NOMATCH: /* no records at all for this lookup */ return dane_required ? FAIL : FAIL_FORCED; default: @@ -1399,6 +1403,8 @@ if (tctx->pending_BDAT) if (flags & tc_reap_prev && prev_cmd_count > 0) { + DEBUG(D_transport) debug_printf("look for %d responses" + " for previous pipelined cmds\n", prev_cmd_count); switch(sync_responses(tctx->first_addr, tctx->tblock->rcpt_include_affixes, tctx->sync_addr, tctx->host, prev_cmd_count, @@ -1406,8 +1412,7 @@ if (flags & tc_reap_prev && prev_cmd_count > 0) tctx->pending_MAIL, 0, tctx->inblock, ob->command_timeout, - buffer, 4096)) -/*XXX buffer size! */ + buffer, DELIVER_BUFFER_SIZE)) { case 1: /* 2xx (only) => OK */ case 3: tctx->good_RCPT = TRUE; /* 2xx & 5xx => OK & progress made */ @@ -1422,12 +1427,13 @@ if (flags & tc_reap_prev && prev_cmd_count > 0) pipelining_active = FALSE; } -/* Reap response for the cmd we just emitted, or an outstanding BDAT */ +/* Reap response for an outstanding BDAT */ -if (flags & tc_reap_one || tctx->pending_BDAT) +if (tctx->pending_BDAT) { -/*XXX buffer size! */ - if (!smtp_read_response(tctx->inblock, buffer, 4096, '2', + DEBUG(D_transport) debug_printf("look for one response for BDAT\n"); + + if (!smtp_read_response(tctx->inblock, buffer, DELIVER_BUFFER_SIZE, '2', ob->command_timeout)) { if (errno == 0 && buffer[0] == '4') @@ -1521,7 +1527,7 @@ BOOL completed_address = FALSE; BOOL esmtp = TRUE; BOOL pending_MAIL; BOOL pass_message = FALSE; -uschar peer_offered = 0; /*XXX should this be handed on cf. tls_offered, smtp_use_dsn ? */ +uschar peer_offered = 0; #ifndef DISABLE_PRDR BOOL prdr_active; #endif @@ -1548,7 +1554,7 @@ uschar *helo_data = NULL; uschar *message = NULL; uschar new_message_id[MESSAGE_ID_LENGTH + 1]; uschar *p; -uschar buffer[4096]; +uschar buffer[DELIVER_BUFFER_SIZE]; uschar inbuffer[4096]; uschar outbuffer[4096]; @@ -1756,7 +1762,7 @@ goto SEND_QUIT; #ifdef SUPPORT_TLS if (smtps) { - tls_offered = TRUE; + smtp_peer_options |= PEER_OFFERED_TLS; suppress_tls = FALSE; ob->tls_tempfail_tryclear = FALSE; smtp_command = US"SSL-on-connect"; @@ -1805,7 +1811,10 @@ goto SEND_QUIT; if (!good_response) goto RESPONSE_FAILED; } + peer_offered = smtp_peer_options = 0; + if (esmtp || lmtp) + { peer_offered = ehlo_response(buffer, Ustrlen(buffer), PEER_OFFERED_TLS /* others checked later */ ); @@ -1813,14 +1822,15 @@ goto SEND_QUIT; /* Set tls_offered if the response to EHLO specifies support for STARTTLS. */ #ifdef SUPPORT_TLS - tls_offered = !!(peer_offered & PEER_OFFERED_TLS); + smtp_peer_options |= peer_offered & PEER_OFFERED_TLS; #endif + } } /* For continuing deliveries down the same channel, the socket is the standard input, and we don't need to redo EHLO here (but may need to do so for TLS - see below). Set up the pointer to where subsequent commands will be left, for -error messages. Note that smtp_use_size and smtp_use_pipelining will have been +error messages. Note that smtp_peer_options will have been set from the command line if they were set in the process that passed the connection on. */ @@ -1845,7 +1855,7 @@ the client not be required to use TLS. If the response is bad, copy the buffer for error analysis. */ #ifdef SUPPORT_TLS -if ( tls_offered +if ( smtp_peer_options & PEER_OFFERED_TLS && !suppress_tls && verify_check_given_host(&ob->hosts_avoid_tls, host) != OK) { @@ -1907,6 +1917,7 @@ if ( tls_offered /* TLS session is set up */ + smtp_peer_options_wrap = smtp_peer_options; for (addr = addrlist; addr; addr = addr->next) if (addr->transport_return == PENDING_DEFER) { @@ -1976,6 +1987,7 @@ if (tls_out.active >= 0) helo_response = string_copy(buffer); #endif if (!good_response) goto RESPONSE_FAILED; + smtp_peer_options = 0; } /* If the host is required to use a secure channel, ensure that we @@ -1990,8 +2002,8 @@ else if ( smtps { save_errno = ERRNO_TLSREQUIRED; message = string_sprintf("a TLS session is required, but %s", - tls_offered ? "an attempt to start TLS failed" - : "the server did not offer TLS support"); + smtp_peer_options & PEER_OFFERED_TLS + ? "an attempt to start TLS failed" : "the server did not offer TLS support"); goto TLS_FAILED; } #endif /*SUPPORT_TLS*/ @@ -2008,6 +2020,7 @@ if (continue_hostname == NULL ) { if (esmtp || lmtp) + { peer_offered = ehlo_response(buffer, Ustrlen(buffer), 0 /* no TLS */ | (lmtp && ob->lmtp_ignore_quota ? PEER_OFFERED_IGNQ : 0) @@ -2015,7 +2028,7 @@ if (continue_hostname == NULL | PEER_OFFERED_PRDR #ifdef SUPPORT_I18N | (addrlist->prop.utf8_msg ? PEER_OFFERED_UTF8 : 0) - /*XXX if we hand peercaps on to continued-conn processes, + /*XXX if we hand peercaps on to continued-conn processes, must not depend on this addr */ #endif | PEER_OFFERED_DSN @@ -2023,61 +2036,64 @@ if (continue_hostname == NULL | (ob->size_addition >= 0 ? PEER_OFFERED_SIZE : 0) ); - /* Set for IGNOREQUOTA if the response to LHLO specifies support and the - lmtp_ignore_quota option was set. */ + /* Set for IGNOREQUOTA if the response to LHLO specifies support and the + lmtp_ignore_quota option was set. */ - igquotstr = peer_offered & PEER_OFFERED_IGNQ ? US" IGNOREQUOTA" : US""; + igquotstr = peer_offered & PEER_OFFERED_IGNQ ? US" IGNOREQUOTA" : US""; - /* If the response to EHLO specified support for the SIZE parameter, note - this, provided size_addition is non-negative. */ + /* If the response to EHLO specified support for the SIZE parameter, note + this, provided size_addition is non-negative. */ - smtp_use_size = !!(peer_offered & PEER_OFFERED_SIZE); + smtp_peer_options |= peer_offered & PEER_OFFERED_SIZE; - /* Note whether the server supports PIPELINING. If hosts_avoid_esmtp matched - the current host, esmtp will be false, so PIPELINING can never be used. If - the current host matches hosts_avoid_pipelining, don't do it. */ + /* Note whether the server supports PIPELINING. If hosts_avoid_esmtp matched + the current host, esmtp will be false, so PIPELINING can never be used. If + the current host matches hosts_avoid_pipelining, don't do it. */ - smtp_use_pipelining = peer_offered & PEER_OFFERED_PIPE - && verify_check_given_host(&ob->hosts_avoid_pipelining, host) != OK; + if ( peer_offered & PEER_OFFERED_PIPE + && verify_check_given_host(&ob->hosts_avoid_pipelining, host) != OK) + smtp_peer_options |= PEER_OFFERED_PIPE; - DEBUG(D_transport) debug_printf("%susing PIPELINING\n", - smtp_use_pipelining ? "" : "not "); + DEBUG(D_transport) debug_printf("%susing PIPELINING\n", + smtp_peer_options & PEER_OFFERED_PIPE ? "" : "not "); - if ( peer_offered & PEER_OFFERED_CHUNKING - && verify_check_given_host(&ob->hosts_try_chunking, host) != OK) - peer_offered &= ~PEER_OFFERED_CHUNKING; + if ( peer_offered & PEER_OFFERED_CHUNKING + && verify_check_given_host(&ob->hosts_try_chunking, host) != OK) + peer_offered &= ~PEER_OFFERED_CHUNKING; - if (peer_offered & PEER_OFFERED_CHUNKING) - {DEBUG(D_transport) debug_printf("CHUNKING usable\n");} + if (peer_offered & PEER_OFFERED_CHUNKING) + {DEBUG(D_transport) debug_printf("CHUNKING usable\n");} #ifndef DISABLE_PRDR - if ( peer_offered & PEER_OFFERED_PRDR - && verify_check_given_host(&ob->hosts_try_prdr, host) != OK) - peer_offered &= ~PEER_OFFERED_PRDR; + if ( peer_offered & PEER_OFFERED_PRDR + && verify_check_given_host(&ob->hosts_try_prdr, host) != OK) + peer_offered &= ~PEER_OFFERED_PRDR; - if (peer_offered & PEER_OFFERED_PRDR) - {DEBUG(D_transport) debug_printf("PRDR usable\n");} + if (peer_offered & PEER_OFFERED_PRDR) + {DEBUG(D_transport) debug_printf("PRDR usable\n");} #endif - /* Note if the server supports DSN */ - smtp_use_dsn = !!(peer_offered & PEER_OFFERED_DSN); - DEBUG(D_transport) debug_printf("%susing DSN\n", smtp_use_dsn ? "" : "not "); + /* Note if the server supports DSN */ + smtp_peer_options |= peer_offered & PEER_OFFERED_DSN; + DEBUG(D_transport) debug_printf("%susing DSN\n", + peer_offered & PEER_OFFERED_DSN ? "" : "not "); - /* Note if the response to EHLO specifies support for the AUTH extension. - If it has, check that this host is one we want to authenticate to, and do - the business. The host name and address must be available when the - authenticator's client driver is running. */ + /* Note if the response to EHLO specifies support for the AUTH extension. + If it has, check that this host is one we want to authenticate to, and do + the business. The host name and address must be available when the + authenticator's client driver is running. */ - switch (yield = smtp_auth(buffer, sizeof(buffer), addrlist, host, - ob, esmtp, &inblock, &outblock)) - { - default: goto SEND_QUIT; - case OK: break; - case FAIL_SEND: goto SEND_FAILED; - case FAIL: goto RESPONSE_FAILED; + switch (yield = smtp_auth(buffer, sizeof(buffer), addrlist, host, + ob, esmtp, &inblock, &outblock)) + { + default: goto SEND_QUIT; + case OK: break; + case FAIL_SEND: goto SEND_FAILED; + case FAIL: goto RESPONSE_FAILED; + } } } -pipelining_active = smtp_use_pipelining; +pipelining_active = !!(smtp_peer_options & PEER_OFFERED_PIPE); /* The setting up of the SMTP call is now complete. Any subsequent errors are message-specific. */ @@ -2123,6 +2139,16 @@ if (tblock->filter_command != NULL) yield = ERROR; goto SEND_QUIT; } + + if ( transport_filter_argv + && *transport_filter_argv + && **transport_filter_argv + && peer_offered & PEER_OFFERED_CHUNKING + ) + { + peer_offered &= ~PEER_OFFERED_CHUNKING; + DEBUG(D_transport) debug_printf("CHUNKING not usable due to transport filter\n"); + } } @@ -2152,7 +2178,7 @@ included in the count.) */ p = buffer; *p = 0; -if (smtp_use_size) +if (peer_offered & PEER_OFFERED_SIZE) { sprintf(CS p, " SIZE=%d", message_size+message_linecount+ob->size_addition); while (*p) p++; @@ -2196,7 +2222,7 @@ for (dsn_all_lasthop = TRUE, addr = first_addr; /* Add any DSN flags to the mail command */ -if (smtp_use_dsn && !dsn_all_lasthop) +if (peer_offered & PEER_OFFERED_DSN && !dsn_all_lasthop) { if (dsn_ret == dsn_ret_hdrs) { Ustrcpy(p, " RET=HDRS"); p += 9; } @@ -2254,7 +2280,7 @@ pending_MAIL = TRUE; /* The block starts with MAIL */ } #endif - rc = smtp_write_command(&outblock, smtp_use_pipelining, + rc = smtp_write_command(&outblock, pipelining_active, "MAIL FROM:<%s>%s\r\n", s, buffer); } @@ -2296,26 +2322,26 @@ that max_rcpt will be large, so all addresses will be done at once. */ for (addr = first_addr; addr && address_count < max_rcpt; addr = addr->next) + if (addr->transport_return == PENDING_DEFER) { int count; BOOL no_flush; uschar * rcpt_addr; - addr->dsn_aware = smtp_use_dsn ? dsn_support_yes : dsn_support_no; - - if (addr->transport_return != PENDING_DEFER) continue; + addr->dsn_aware = peer_offered & PEER_OFFERED_DSN + ? dsn_support_yes : dsn_support_no; address_count++; - no_flush = smtp_use_pipelining && (!mua_wrapper || addr->next); + no_flush = pipelining_active && (!mua_wrapper || addr->next); /* Add any DSN flags to the rcpt command and add to the sent string */ p = buffer; *p = 0; - if (smtp_use_dsn && !(addr->dsn_flags & rf_dsnlasthop)) + if (peer_offered & PEER_OFFERED_DSN && !(addr->dsn_flags & rf_dsnlasthop)) { - if ((addr->dsn_flags & rf_dsnflags) != 0) + if (addr->dsn_flags & rf_dsnflags) { int i; BOOL first = TRUE; @@ -2414,7 +2440,7 @@ If using CHUNKING, do not send a BDAT until we know how big a chunk we want to send is. */ if ( !(peer_offered & PEER_OFFERED_CHUNKING) - && (ok || (smtp_use_pipelining && !mua_wrapper))) + && (ok || (pipelining_active && !mua_wrapper))) { int count = smtp_write_command(&outblock, FALSE, "DATA\r\n"); @@ -2462,7 +2488,7 @@ else | (tblock->headers_only ? topt_no_body : 0) | (tblock->return_path_add ? topt_add_return_path : 0) | (tblock->delivery_date_add ? topt_add_delivery_date : 0) - | (tblock->envelope_to_add ? topt_add_envelope_to : 0), + | (tblock->envelope_to_add ? topt_add_envelope_to : 0) }; /* If using CHUNKING we need a callback from the generic transport @@ -2694,6 +2720,7 @@ else #ifndef DISABLE_PRDR if (prdr_active) addr->flags |= af_prdr_used; #endif + if (peer_offered & PEER_OFFERED_CHUNKING) addr->flags |= af_chunking_used; flag = '-'; #ifndef DISABLE_PRDR @@ -3020,6 +3047,7 @@ if (completed_address && ok && send_quit) if (tls_out.active >= 0) { tls_close(FALSE, TRUE); + smtp_peer_options = smtp_peer_options_wrap; if (smtps) ok = FALSE; else @@ -3037,9 +3065,7 @@ propagate it from the initial */ if (ok && transport_pass_socket(tblock->name, host->name, host->address, new_message_id, inblock.sock)) - { send_quit = FALSE; - } } /* If RSET failed and there are addresses left, they get deferred. */ @@ -3176,10 +3202,10 @@ prepare_addresses(address_item *addrlist, host_item *host) { address_item *first_addr = NULL; address_item *addr; -for (addr = addrlist; addr != NULL; addr = addr->next) +for (addr = addrlist; addr; addr = addr->next) if (addr->transport_return == DEFER) { - if (first_addr == NULL) first_addr = addr; + if (!first_addr) first_addr = addr; addr->transport_return = PENDING_DEFER; addr->basic_errno = 0; addr->more_errno = (host->mx >= 0)? 'M' : 'A'; @@ -3227,7 +3253,6 @@ int hosts_total = 0; int total_hosts_tried = 0; address_item *addr; BOOL expired = TRUE; -BOOL continuing = continue_hostname != NULL; uschar *expanded_hosts = NULL; uschar *pistring; uschar *tid = string_sprintf("%s transport", tblock->name); @@ -3239,9 +3264,15 @@ host_item *host = NULL; DEBUG(D_transport) { debug_printf("%s transport entered\n", tblock->name); - for (addr = addrlist; addr != NULL; addr = addr->next) + for (addr = addrlist; addr; addr = addr->next) debug_printf(" %s\n", addr->address); - if (continuing) debug_printf("already connected to %s [%s]\n", + if (hostlist) + { + debug_printf("hostlist:\n"); + for (host = hostlist; host; host = host->next) + debug_printf(" %s:%d\n", host->name, host->port); + } + if (continue_hostname) debug_printf("already connected to %s [%s]\n", continue_hostname, continue_host_address); } @@ -3257,9 +3288,9 @@ same one in order to be passed to a single transport - or if the transport has a host list with hosts_override set, use the host list supplied with the transport. It is an error for this not to exist. */ -if (hostlist == NULL || (ob->hosts_override && ob->hosts != NULL)) +if (!hostlist || (ob->hosts_override && ob->hosts)) { - if (ob->hosts == NULL) + if (!ob->hosts) { addrlist->message = string_sprintf("%s transport called with no hosts set", tblock->name); @@ -3278,7 +3309,7 @@ if (hostlist == NULL || (ob->hosts_override && ob->hosts != NULL)) as the hosts string will never be used again, it doesn't matter that we replace all the : characters with zeros. */ - if (ob->hostlist == NULL) + if (!ob->hostlist) { uschar *s = ob->hosts; @@ -3288,7 +3319,7 @@ if (hostlist == NULL || (ob->hosts_override && ob->hosts != NULL)) { addrlist->message = string_sprintf("failed to expand list of hosts " "\"%s\" in %s transport: %s", s, tblock->name, expand_string_message); - addrlist->transport_return = search_find_defer? DEFER : PANIC; + addrlist->transport_return = search_find_defer ? DEFER : PANIC; return FALSE; /* Only top address has status */ } DEBUG(D_transport) debug_printf("expanded list of hosts \"%s\" to " @@ -3301,7 +3332,7 @@ if (hostlist == NULL || (ob->hosts_override && ob->hosts != NULL)) host_build_hostlist(&hostlist, s, ob->hosts_randomize); /* Check that the expansion yielded something useful. */ - if (hostlist == NULL) + if (!hostlist) { addrlist->message = string_sprintf("%s transport has empty hosts setting", tblock->name); @@ -3327,17 +3358,17 @@ must sort it into a random order if it did not come from MX records and has not already been randomized (but don't bother if continuing down an existing connection). */ -else if (ob->hosts_randomize && hostlist->mx == MX_NONE && !continuing) +else if (ob->hosts_randomize && hostlist->mx == MX_NONE && !continue_hostname) { host_item *newlist = NULL; - while (hostlist != NULL) + while (hostlist) { host_item *h = hostlist; hostlist = hostlist->next; h->sort_key = random_number(100); - if (newlist == NULL) + if (!newlist) { h->next = NULL; newlist = h; @@ -3350,7 +3381,7 @@ else if (ob->hosts_randomize && hostlist->mx == MX_NONE && !continuing) else { host_item *hh = newlist; - while (hh->next != NULL) + while (hh->next) { if (h->sort_key < hh->next->sort_key) break; hh = hh->next; @@ -3412,23 +3443,22 @@ the current message. To cope with this, we have to go round the loop a second time. After that, set the status and error data for any addresses that haven't had it set already. */ -for (cutoff_retry = 0; expired && - cutoff_retry < ((ob->delay_after_cutoff)? 1 : 2); +for (cutoff_retry = 0; + expired && cutoff_retry < (ob->delay_after_cutoff ? 1 : 2); cutoff_retry++) { host_item *nexthost = NULL; int unexpired_hosts_tried = 0; for (host = hostlist; - host != NULL && - unexpired_hosts_tried < ob->hosts_max_try && - total_hosts_tried < ob->hosts_max_try_hardlimit; + host + && unexpired_hosts_tried < ob->hosts_max_try + && total_hosts_tried < ob->hosts_max_try_hardlimit; host = nexthost) { int rc; int host_af; uschar *rs; - BOOL serialized = FALSE; BOOL host_is_expired = FALSE; BOOL message_defer = FALSE; BOOL some_deferred = FALSE; @@ -3458,7 +3488,7 @@ for (cutoff_retry = 0; expired && Note that we mustn't skip unusable hosts if the address is not unset; they may be needed as expired hosts on the 2nd time round the cutoff loop. */ - if (host->address == NULL) + if (!host->address) { int new_port, flags; host_item *hh; @@ -3517,7 +3547,7 @@ for (cutoff_retry = 0; expired && "HOST_FIND_AGAIN" : "HOST_FIND_FAILED", host->name); host->status = hstatus_unusable; - for (addr = addrlist; addr != NULL; addr = addr->next) + for (addr = addrlist; addr; addr = addr->next) { if (addr->transport_return != DEFER) continue; addr->basic_errno = ERRNO_UNKNOWNHOST; @@ -3533,7 +3563,7 @@ for (cutoff_retry = 0; expired && if (rc == HOST_FOUND_LOCAL && !ob->allow_localhost) { - for (addr = addrlist; addr != NULL; addr = addr->next) + for (addr = addrlist; addr; addr = addr->next) { addr->basic_errno = 0; addr->message = string_sprintf("%s transport found host %s to be " @@ -3549,8 +3579,10 @@ for (cutoff_retry = 0; expired && result of the lookup. Set expired FALSE, to save the outer loop executing twice. */ - if (continuing && (Ustrcmp(continue_hostname, host->name) != 0 || - Ustrcmp(continue_host_address, host->address) != 0)) + if ( continue_hostname + && ( Ustrcmp(continue_hostname, host->name) != 0 + || Ustrcmp(continue_host_address, host->address) != 0 + ) ) { expired = FALSE; continue; /* With next host */ @@ -3574,11 +3606,9 @@ for (cutoff_retry = 0; expired && &domainlist_anchor, NULL, MCL_DOMAIN, TRUE, NULL) == OK)) { expired = FALSE; - for (addr = addrlist; addr != NULL; addr = addr->next) - { - if (addr->transport_return != DEFER) continue; - addr->message = US"domain matches queue_smtp_domains, or -odqs set"; - } + for (addr = addrlist; addr; addr = addr->next) + if (addr->transport_return == DEFER) + addr->message = US"domain matches queue_smtp_domains, or -odqs set"; continue; /* With next host */ } @@ -3601,8 +3631,8 @@ for (cutoff_retry = 0; expired && the standard SMTP port. A host may have its own port setting that overrides the default. */ - pistring = string_sprintf(":%d", (host->port == PORT_NONE)? - port : host->port); + pistring = string_sprintf(":%d", host->port == PORT_NONE + ? port : host->port); if (Ustrcmp(pistring, ":25") == 0) pistring = US""; /* Select IPv4 or IPv6, and choose an outgoing interface. If the interface @@ -3611,7 +3641,7 @@ for (cutoff_retry = 0; expired && because connections to the same host from a different interface should be treated separately. */ - host_af = (Ustrchr(host->address, ':') == NULL)? AF_INET : AF_INET6; + host_af = Ustrchr(host->address, ':') == NULL ? AF_INET : AF_INET6; if ((rs = ob->interface) && *rs) { if (!smtp_get_interface(rs, host_af, addrlist, &interface, tid)) @@ -3652,24 +3682,24 @@ for (cutoff_retry = 0; expired && switch (host->status) { case hstatus_unusable: - expired = FALSE; - setflag(addrlist, af_retry_skipped); - /* Fall through */ + expired = FALSE; + setflag(addrlist, af_retry_skipped); + /* Fall through */ case hstatus_unusable_expired: - switch (host->why) - { - case hwhy_retry: hosts_retry++; break; - case hwhy_failed: hosts_fail++; break; - case hwhy_deferred: hosts_defer++; break; - } - - /* If there was a retry message key, implying that previously there - was a message-specific defer, we don't want to update the list of - messages waiting for these hosts. */ - - if (retry_message_key != NULL) update_waiting = FALSE; - continue; /* With the next host or IP address */ + switch (host->why) + { + case hwhy_retry: hosts_retry++; break; + case hwhy_failed: hosts_fail++; break; + case hwhy_deferred: hosts_defer++; break; + } + + /* If there was a retry message key, implying that previously there + was a message-specific defer, we don't want to update the list of + messages waiting for these hosts. */ + + if (retry_message_key) update_waiting = FALSE; + continue; /* With the next host or IP address */ } } @@ -3678,12 +3708,11 @@ for (cutoff_retry = 0; expired && else { - if (host->address == NULL || - host->status != hstatus_unusable_expired || - host->last_try > received_time) + if ( !host->address + || host->status != hstatus_unusable_expired + || host->last_try > received_time) continue; - DEBUG(D_transport) - debug_printf("trying expired host %s [%s]%s\n", + DEBUG(D_transport) debug_printf("trying expired host %s [%s]%s\n", host->name, host->address, pistring); host_is_expired = TRUE; } @@ -3700,8 +3729,8 @@ for (cutoff_retry = 0; expired && and remember this for later deletion. Do not do any of this if we are sending the message down a pre-existing connection. */ - if (!continuing && - verify_check_given_host(&ob->serialize_hosts, host) == OK) + if ( !continue_hostname + && verify_check_given_host(&ob->serialize_hosts, host) == OK) { serialize_key = string_sprintf("host-serialize-%s", host->name); if (!enq_start(serialize_key, 1)) @@ -3712,7 +3741,6 @@ for (cutoff_retry = 0; expired && hosts_serial++; continue; } - serialized = TRUE; } /* OK, we have an IP address that is not waiting for its retry time to @@ -3726,11 +3754,11 @@ for (cutoff_retry = 0; expired && DEBUG(D_transport) debug_printf("delivering %s to %s [%s] (%s%s)\n", message_id, host->name, host->address, addrlist->address, - (addrlist->next == NULL)? "" : ", ..."); + addrlist->next ? ", ..." : ""); set_process_info("delivering %s to %s [%s] (%s%s)", message_id, host->name, host->address, addrlist->address, - (addrlist->next == NULL)? "" : ", ..."); + addrlist->next ? ", ..." : ""); /* This is not for real; don't do the delivery. If there are any remaining hosts, list them. */ @@ -3739,7 +3767,7 @@ for (cutoff_retry = 0; expired && { host_item *host2; set_errno_nohost(addrlist, 0, NULL, OK, FALSE); - for (addr = addrlist; addr != NULL; addr = addr->next) + for (addr = addrlist; addr; addr = addr->next) { addr->host_used = host; addr->special_action = '*'; @@ -3749,9 +3777,9 @@ for (cutoff_retry = 0; expired && { debug_printf("*** delivery by %s transport bypassed by -N option\n" "*** host and remaining hosts:\n", tblock->name); - for (host2 = host; host2 != NULL; host2 = host2->next) + for (host2 = host; host2; host2 = host2->next) debug_printf(" %s [%s]\n", host2->name, - (host2->address == NULL)? US"unset" : host2->address); + host2->address ? host2->address : US"unset"); } rc = OK; } @@ -3821,8 +3849,8 @@ for (cutoff_retry = 0; expired && failures, where the log has already been written. If all hosts defer a general message is written at the end. */ - if (rc == DEFER && first_addr->basic_errno != ERRNO_AUTHFAIL && - first_addr->basic_errno != ERRNO_TLSFAILURE) + if (rc == DEFER && first_addr->basic_errno != ERRNO_AUTHFAIL + && first_addr->basic_errno != ERRNO_TLSFAILURE) write_logs(first_addr, host); #ifndef DISABLE_EVENT @@ -3863,16 +3891,18 @@ for (cutoff_retry = 0; expired && /* Delivery attempt finished */ - rs = (rc == OK)? US"OK" : (rc == DEFER)? US"DEFER" : (rc == ERROR)? - US"ERROR" : US"?"; + rs = rc == OK ? US"OK" + : rc == DEFER ? US"DEFER" + : rc == ERROR ? US"ERROR" + : US"?"; set_process_info("delivering %s: just tried %s [%s] for %s%s: result %s", message_id, host->name, host->address, addrlist->address, - (addrlist->next == NULL)? "" : " (& others)", rs); + addrlist->next ? " (& others)" : "", rs); /* Release serialization if set up */ - if (serialized) enq_end(serialize_key); + if (serialize_key) enq_end(serialize_key); /* If the result is DEFER, or if a host retry record is known to exist, we need to add an item to the retry chain for updating the retry database @@ -3882,10 +3912,10 @@ for (cutoff_retry = 0; expired && the unusable tree at the outer level, so even if different address blocks contain the same address, it still won't get tried again.) */ - if (rc == DEFER || retry_host_key != NULL) + if (rc == DEFER || retry_host_key) { - int delete_flag = (rc != DEFER)? rf_delete : 0; - if (retry_host_key == NULL) + int delete_flag = rc != DEFER ? rf_delete : 0; + if (!retry_host_key) { BOOL incl_ip; if (exp_bool(addrlist, US"transport", tblock->name, D_transport, @@ -3893,9 +3923,9 @@ for (cutoff_retry = 0; expired && ob->expand_retry_include_ip_address, &incl_ip) != OK) incl_ip = TRUE; /* error; use most-specific retry record */ - retry_host_key = incl_ip ? - string_sprintf("T:%S:%s%s", host->name, host->address, pistring) : - string_sprintf("T:%S%s", host->name, pistring); + retry_host_key = incl_ip + ? string_sprintf("T:%S:%s%s", host->name, host->address, pistring) + : string_sprintf("T:%S%s", host->name, pistring); } /* If a delivery of another message over an existing SMTP connection @@ -3908,7 +3938,7 @@ for (cutoff_retry = 0; expired && host is genuinely down, another non-continued message delivery will notice it soon enough. */ - if (delete_flag != 0 || !continuing) + if (delete_flag != 0 || !continue_hostname) retry_add_item(first_addr, retry_host_key, rf_host | delete_flag); /* We may have tried an expired host, if its retry time has come; ensure @@ -3916,8 +3946,8 @@ for (cutoff_retry = 0; expired && if (rc == DEFER) { - host->status = (host_is_expired)? - hstatus_unusable_expired : hstatus_unusable; + host->status = host_is_expired + ? hstatus_unusable_expired : hstatus_unusable; host->why = hwhy_deferred; } } @@ -3930,10 +3960,10 @@ for (cutoff_retry = 0; expired && reasonable. Also, stop the message from being remembered as waiting for specific hosts. */ - if (message_defer || retry_message_key != NULL) + if (message_defer || retry_message_key) { - int delete_flag = message_defer? 0 : rf_delete; - if (retry_message_key == NULL) + int delete_flag = message_defer ? 0 : rf_delete; + if (!retry_message_key) { BOOL incl_ip; if (exp_bool(addrlist, US"transport", tblock->name, D_transport, @@ -3941,10 +3971,10 @@ for (cutoff_retry = 0; expired && ob->expand_retry_include_ip_address, &incl_ip) != OK) incl_ip = TRUE; /* error; use most-specific retry record */ - retry_message_key = incl_ip ? - string_sprintf("T:%S:%s%s:%s", host->name, host->address, pistring, - message_id) : - string_sprintf("T:%S%s:%s", host->name, pistring, message_id); + retry_message_key = incl_ip + ? string_sprintf("T:%S:%s%s:%s", host->name, host->address, pistring, + message_id) + : string_sprintf("T:%S%s:%s", host->name, pistring, message_id); } retry_add_item(addrlist, retry_message_key, rf_message | rf_host | delete_flag); @@ -3978,7 +4008,7 @@ for (cutoff_retry = 0; expired && case when we were trying to deliver down an existing channel and failed. Don't try any other hosts in this case. */ - if (continuing) break; + if (continue_hostname) break; /* If the whole delivery, or some individual addresses, were deferred and there are more hosts that could be tried, do not count this host towards @@ -3988,16 +4018,16 @@ for (cutoff_retry = 0; expired && important because if we don't try all hosts, the address will never time out. NOTE: this does not apply to hosts_max_try_hardlimit. */ - if ((rc == DEFER || some_deferred) && nexthost != NULL) + if ((rc == DEFER || some_deferred) && nexthost) { BOOL timedout; retry_config *retry = retry_find_config(host->name, NULL, 0, 0); - if (retry != NULL && retry->rules != NULL) + if (retry && retry->rules) { retry_rule *last_rule; for (last_rule = retry->rules; - last_rule->next != NULL; + last_rule->next; last_rule = last_rule->next); timedout = time(NULL) - received_time > last_rule->timeout; } @@ -4031,7 +4061,7 @@ specific failures. Force the delivery status for all addresses to FAIL. */ if (mua_wrapper) { - for (addr = addrlist; addr != NULL; addr = addr->next) + for (addr = addrlist; addr; addr = addr->next) addr->transport_return = FAIL; goto END_TRANSPORT; }