(void *)offsetof(smtp_transport_options_block, serialize_hosts) },
{ "size_addition", opt_int,
(void *)offsetof(smtp_transport_options_block, size_addition) }
-#ifndef DISABLE_SOCKS
+#ifdef SUPPORT_SOCKS
,{ "socks_proxy", opt_stringptr,
(void *)offsetof(smtp_transport_options_block, socks_proxy) }
#endif
FALSE, /* lmtp_ignore_quota */
NULL, /* expand_retry_include_ip_address */
TRUE /* retry_include_ip_address */
-#ifndef DISABLE_SOCKS
+#ifdef SUPPORT_SOCKS
,NULL /* socks_proxy */
#endif
#ifdef SUPPORT_TLS
return FALSE;
}
-#ifdef EXPERIMENTAL_INTERNATIONAL
+#ifdef SUPPORT_I18N
/* Handle lack of advertised SMTPUTF8, for international message */
if (*errno_value == ERRNO_UTF8_FWD)
{
-#ifdef EXPERIMENTAL_EVENT
+#ifndef DISABLE_EVENT
/*************************************************
* Post-defer action *
*************************************************/
addr->basic_errno = ERRNO_RCPT4XX;
addr->more_errno |= ((buffer[1] - '0')*10 + buffer[2] - '0') << 8;
-#ifdef EXPERIMENTAL_EVENT
+#ifndef DISABLE_EVENT
event_defer_errno = addr->more_errno;
msg_event_raise(US"msg:rcpt:host:defer", addr);
#endif
if (host->next)
log_write(0, LOG_MAIN, "H=%s [%s]: %s", host->name, host->address, addr->message);
-#ifdef EXPERIMENTAL_EVENT
+#ifndef DISABLE_EVENT
else
msg_event_raise(US"msg:rcpt:defer", addr);
#endif
+uschar
+ehlo_response(uschar * buf, size_t bsize, uschar checks)
+{
+#ifdef SUPPORT_TLS
+if (checks & PEER_OFFERED_TLS)
+ if (pcre_exec(regex_STARTTLS, NULL, CS buf, bsize, 0, PCRE_EOPT, NULL, 0) < 0)
+ checks &= ~PEER_OFFERED_TLS;
+#endif
+
+ if ( checks & PEER_OFFERED_IGNQ
+ && pcre_exec(regex_IGNOREQUOTA, NULL, CS buf, bsize, 0,
+ PCRE_EOPT, NULL, 0) < 0)
+ checks &= ~PEER_OFFERED_IGNQ;
+
+#ifndef DISABLE_PRDR
+ if ( checks & PEER_OFFERED_PRDR
+ && pcre_exec(regex_PRDR, NULL, CS buf, bsize, 0, PCRE_EOPT, NULL, 0) < 0)
+ checks &= ~PEER_OFFERED_PRDR;
+#endif
+
+#ifdef SUPPORT_I18N
+ if ( checks & PEER_OFFERED_UTF8
+ && pcre_exec(regex_UTF8, NULL, CS buf, bsize, 0, PCRE_EOPT, NULL, 0) < 0)
+ checks &= ~PEER_OFFERED_UTF8;
+#endif
+
+ if ( checks & PEER_OFFERED_DSN
+ && pcre_exec(regex_DSN, NULL, CS buf, bsize, 0, PCRE_EOPT, NULL, 0) < 0)
+ checks &= ~PEER_OFFERED_DSN;
+
+ if ( checks & PEER_OFFERED_PIPE
+ && pcre_exec(regex_PIPELINING, NULL, CS buf, bsize, 0,
+ PCRE_EOPT, NULL, 0) < 0)
+ checks &= ~PEER_OFFERED_PIPE;
+
+ if ( checks & PEER_OFFERED_SIZE
+ && pcre_exec(regex_SIZE, NULL, CS buf, bsize, 0, PCRE_EOPT, NULL, 0) < 0)
+ checks &= ~PEER_OFFERED_SIZE;
+
+return checks;
+}
+
+
/*************************************************
* Deliver address list to given host *
*************************************************/
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 ? */
#ifndef DISABLE_PRDR
-BOOL prdr_offered = FALSE;
BOOL prdr_active;
#endif
-#ifdef EXPERIMENTAL_INTERNATIONAL
+#ifdef SUPPORT_I18N
BOOL utf8_needed = FALSE;
-BOOL utf8_offered = FALSE;
#endif
BOOL dsn_all_lasthop = TRUE;
#if defined(SUPPORT_TLS) && defined(EXPERIMENTAL_DANE)
delayed till here so that $sending_interface and $sending_port are set. */
helo_data = expand_string(ob->helo_data);
-#ifdef EXPERIMENTAL_INTERNATIONAL
+#ifdef SUPPORT_I18N
if (helo_data)
{
uschar * errstr = NULL;
#endif
if (!good_response) goto RESPONSE_FAILED;
-#ifdef EXPERIMENTAL_EVENT
+#ifndef DISABLE_EVENT
{
uschar * s;
lookup_dnssec_authenticated = host->dnssec==DS_YES ? US"yes"
if (!good_response) goto RESPONSE_FAILED;
}
- /* Set IGNOREQUOTA if the response to LHLO specifies support and the
- lmtp_ignore_quota option was set. */
-
- igquotstr = (lmtp && ob->lmtp_ignore_quota &&
- pcre_exec(regex_IGNOREQUOTA, NULL, CS buffer, Ustrlen(CS buffer), 0,
- PCRE_EOPT, NULL, 0) >= 0)? US" IGNOREQUOTA" : US"";
+ if (esmtp || lmtp)
+ peer_offered = ehlo_response(buffer, Ustrlen(buffer),
+ PEER_OFFERED_TLS
+ | 0 /* IGNQ checked later */
+ | 0 /* PRDR checked later */
+ | 0 /* UTF8 checked later */
+ | 0 /* DSN checked later */
+ | 0 /* PIPE checked later */
+ | 0 /* SIZE checked later */
+ );
/* Set tls_offered if the response to EHLO specifies support for STARTTLS. */
#ifdef SUPPORT_TLS
- tls_offered = esmtp &&
- pcre_exec(regex_STARTTLS, NULL, CS buffer, Ustrlen(buffer), 0,
- PCRE_EOPT, NULL, 0) >= 0;
-#endif
-
-#ifndef DISABLE_PRDR
- prdr_offered = esmtp
- && pcre_exec(regex_PRDR, NULL, CS buffer, Ustrlen(buffer), 0,
- PCRE_EOPT, NULL, 0) >= 0
- && verify_check_given_host(&ob->hosts_try_prdr, host) == OK;
-
- if (prdr_offered)
- {DEBUG(D_transport) debug_printf("PRDR usable\n");}
-#endif
-
-#ifdef EXPERIMENTAL_INTERNATIONAL
- if (addrlist->prop.utf8_msg)
- {
- utf8_needed = !addrlist->prop.utf8_downcvt
- && !addrlist->prop.utf8_downcvt_maybe;
- DEBUG(D_transport) if (!utf8_needed) debug_printf("utf8: %s downconvert\n",
- addrlist->prop.utf8_downcvt ? "mandatory" : "optional");
-
- utf8_offered = esmtp
- && pcre_exec(regex_UTF8, NULL, CS buffer, Ustrlen(buffer), 0,
- PCRE_EOPT, NULL, 0) >= 0;
- }
+ tls_offered = !!(peer_offered & PEER_OFFERED_TLS);
#endif
}
#endif
)
{
+ if (esmtp || lmtp)
+ peer_offered = ehlo_response(buffer, Ustrlen(buffer),
+ 0 /* no TLS */
+ | (lmtp && ob->lmtp_ignore_quota ? PEER_OFFERED_IGNQ : 0)
+ | PEER_OFFERED_PRDR
+#ifdef SUPPORT_I18N
+ | (addrlist->prop.utf8_msg ? PEER_OFFERED_UTF8 : 0)
+ /*XXX if we hand peercaps on to continued-conn processes,
+ must not depend on this addr */
+#endif
+ | PEER_OFFERED_DSN
+ | PEER_OFFERED_PIPE
+ | (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. */
- igquotstr = (lmtp && ob->lmtp_ignore_quota &&
- pcre_exec(regex_IGNOREQUOTA, NULL, CS buffer, Ustrlen(CS buffer), 0,
- PCRE_EOPT, NULL, 0) >= 0)? 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. */
- smtp_use_size = esmtp && ob->size_addition >= 0 &&
- pcre_exec(regex_SIZE, NULL, CS buffer, Ustrlen(CS buffer), 0,
- PCRE_EOPT, NULL, 0) >= 0;
+ smtp_use_size = !!(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. */
- smtp_use_pipelining = esmtp
- && verify_check_given_host(&ob->hosts_avoid_pipelining, host) != OK
- && pcre_exec(regex_PIPELINING, NULL, CS buffer, Ustrlen(CS buffer), 0,
- PCRE_EOPT, NULL, 0) >= 0;
+ smtp_use_pipelining = peer_offered & PEER_OFFERED_PIPE
+ && verify_check_given_host(&ob->hosts_avoid_pipelining, host) != OK;
DEBUG(D_transport) debug_printf("%susing PIPELINING\n",
- smtp_use_pipelining? "" : "not ");
+ smtp_use_pipelining ? "" : "not ");
#ifndef DISABLE_PRDR
- prdr_offered = esmtp
- && pcre_exec(regex_PRDR, NULL, CS buffer, Ustrlen(CS buffer), 0,
- PCRE_EOPT, NULL, 0) >= 0
- && verify_check_given_host(&ob->hosts_try_prdr, host) == OK;
+ if ( peer_offered & PEER_OFFERED_PRDR
+ && verify_check_given_host(&ob->hosts_try_prdr, host) != OK)
+ peer_offered &= ~PEER_OFFERED_PRDR;
- if (prdr_offered)
+ if (peer_offered & PEER_OFFERED_PRDR)
{DEBUG(D_transport) debug_printf("PRDR usable\n");}
#endif
-#ifdef EXPERIMENTAL_INTERNATIONAL
- if (addrlist->prop.utf8_msg)
- utf8_offered = esmtp
- && pcre_exec(regex_UTF8, NULL, CS buffer, Ustrlen(buffer), 0,
- PCRE_EOPT, NULL, 0) >= 0;
-#endif
-
/* Note if the server supports DSN */
- smtp_use_dsn = esmtp
- && pcre_exec(regex_DSN, NULL, CS buffer, Ustrlen(CS buffer), 0,
- PCRE_EOPT, NULL, 0) >= 0;
- DEBUG(D_transport) debug_printf("use_dsn=%d\n", smtp_use_dsn);
+ smtp_use_dsn = !!(peer_offered & PEER_OFFERED_DSN);
+ DEBUG(D_transport) debug_printf("%susing DSN\n", smtp_use_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
setting_up = FALSE;
-#ifdef EXPERIMENTAL_INTERNATIONAL
+#ifdef SUPPORT_I18N
+if (addrlist->prop.utf8_msg)
+ {
+ utf8_needed = !addrlist->prop.utf8_downcvt
+ && !addrlist->prop.utf8_downcvt_maybe;
+ DEBUG(D_transport) if (!utf8_needed) debug_printf("utf8: %s downconvert\n",
+ addrlist->prop.utf8_downcvt ? "mandatory" : "optional");
+ }
+
/* If this is an international message we need the host to speak SMTPUTF8 */
-if (utf8_needed && !utf8_offered)
+if (utf8_needed && !(peer_offered & PEER_OFFERED_UTF8))
{
errno = ERRNO_UTF8_FWD;
goto RESPONSE_FAILED;
#ifndef DISABLE_PRDR
prdr_active = FALSE;
-if (prdr_offered)
- {
+if (peer_offered & PEER_OFFERED_PRDR)
for (addr = first_addr; addr; addr = addr->next)
if (addr->transport_return == PENDING_DEFER)
{
}
break;
}
- }
#endif
-#ifdef EXPERIMENTAL_INTERNATIONAL
-if (addrlist->prop.utf8_msg && !addrlist->prop.utf8_downcvt && utf8_offered)
+#ifdef SUPPORT_I18N
+if ( addrlist->prop.utf8_msg
+ && !addrlist->prop.utf8_downcvt
+ && peer_offered & PEER_OFFERED_UTF8
+ )
sprintf(CS p, " SMTPUTF8"), p += 9;
#endif
{
uschar * s = return_path;
-#ifdef EXPERIMENTAL_INTERNATIONAL
+#ifdef SUPPORT_I18N
uschar * errstr = NULL;
/* If we must downconvert, do the from-address here. Remember we had to
for the to-addresses (done below), and also (ugly) for re-doing when building
the delivery log line. */
- if (addrlist->prop.utf8_msg && (addrlist->prop.utf8_downcvt || !utf8_offered))
+ if ( addrlist->prop.utf8_msg
+ && (addrlist->prop.utf8_downcvt || !(peer_offered & PEER_OFFERED_UTF8))
+ )
{
if (s = string_address_utf8_to_alabel(return_path, &errstr), errstr)
{
rcpt_addr = transport_rcpt_address(addr, tblock->rcpt_include_affixes);
-#ifdef EXPERIMENTAL_INTERNATIONAL
+#ifdef SUPPORT_I18N
{
uschar * dummy_errstr;
if ( testflag(addrlist, af_utf8_downcvt)
/* Set up confirmation if needed - applies only to SMTP */
if (
-#ifndef EXPERIMENTAL_EVENT
+#ifdef DISABLE_EVENT
LOGGING(smtp_confirmation) &&
#endif
!lmtp
switch(save_errno)
{
-#ifdef EXPERIMENTAL_INTERNATIONAL
+#ifdef SUPPORT_I18N
case ERRNO_UTF8_FWD:
code = '5';
/*FALLTHROUGH*/
(void)close(inblock.sock);
-#ifdef EXPERIMENTAL_EVENT
+#ifndef DISABLE_EVENT
(void) event_raise(tblock->event_action, US"tcp:close", NULL);
#endif
first_addr->basic_errno != ERRNO_TLSFAILURE)
write_logs(first_addr, host);
-#ifdef EXPERIMENTAL_EVENT
+#ifndef DISABLE_EVENT
if (rc == DEFER)
deferred_event_raise(first_addr, host);
#endif
&message_defer, TRUE);
if (rc == DEFER && first_addr->basic_errno != ERRNO_AUTHFAIL)
write_logs(first_addr, host);
-# ifdef EXPERIMENTAL_EVENT
+# ifndef DISABLE_EVENT
if (rc == DEFER)
deferred_event_raise(first_addr, host);
# endif
else if (expired)
{
setflag(addr, af_pass_message); /* This is not a security risk */
- addr->message = (ob->delay_after_cutoff)?
- US"retry time not reached for any host after a long failure period" :
- US"all hosts have been failing for a long time and were last tried "
+ addr->message = ob->delay_after_cutoff
+ ? US"retry time not reached for any host after a long failure period"
+ : US"all hosts have been failing for a long time and were last tried "
"after this message arrived";
/* If we are already using fallback hosts, or there are no fallback hosts
}
else
{
+ const uschar * s;
if (hosts_retry == hosts_total)
- addr->message = US"retry time not reached for any host";
+ s = US"retry time not reached for any host%s";
else if (hosts_fail == hosts_total)
- addr->message = US"all host address lookups failed permanently";
+ s = US"all host address lookups%s failed permanently";
else if (hosts_defer == hosts_total)
- addr->message = US"all host address lookups failed temporarily";
+ s = US"all host address lookups%s failed temporarily";
else if (hosts_serial == hosts_total)
- addr->message = US"connection limit reached for all hosts";
+ s = US"connection limit reached for all hosts%s";
else if (hosts_fail+hosts_defer == hosts_total)
- addr->message = US"all host address lookups failed";
- else addr->message = US"some host address lookups failed and retry time "
- "not reached for other hosts or connection limit reached";
+ s = US"all host address lookups%s failed";
+ else
+ s = US"some host address lookups failed and retry time "
+ "not reached for other hosts or connection limit reached%s";
+
+ addr->message = string_sprintf(s,
+ addr->domain ? string_sprintf(" for '%s'", addr->domain) : US"");
}
}
}