git://git.exim.org
/
exim.git
/ blobdiff
commit
grep
author
committer
pickaxe
?
search:
re
summary
|
shortlog
|
log
|
commit
|
commitdiff
|
tree
raw
|
inline
| side by side
Events: move from Experimental to mainline
[exim.git]
/
src
/
src
/
transports
/
smtp.c
diff --git
a/src/src/transports/smtp.c
b/src/src/transports/smtp.c
index 48bab9599e90638eea213a8b4c5ac4aecd511918..135069d0f189e487f2cfb304dd155f59c4f9244a 100644
(file)
--- a/
src/src/transports/smtp.c
+++ b/
src/src/transports/smtp.c
@@
-2,7
+2,7
@@
* Exim - an Internet mail transport agent *
*************************************************/
* Exim - an Internet mail transport agent *
*************************************************/
-/* Copyright (c) University of Cambridge 1995 - 201
4
*/
+/* Copyright (c) University of Cambridge 1995 - 201
5
*/
/* See the file NOTICE for conditions of use and distribution. */
#include "../exim.h"
/* See the file NOTICE for conditions of use and distribution. */
#include "../exim.h"
@@
-159,7
+159,7
@@
optionlist smtp_transport_options[] = {
(void *)offsetof(smtp_transport_options_block, serialize_hosts) },
{ "size_addition", opt_int,
(void *)offsetof(smtp_transport_options_block, size_addition) }
(void *)offsetof(smtp_transport_options_block, serialize_hosts) },
{ "size_addition", opt_int,
(void *)offsetof(smtp_transport_options_block, size_addition) }
-#ifdef
EXPERIMENTAL
_SOCKS
+#ifdef
SUPPORT
_SOCKS
,{ "socks_proxy", opt_stringptr,
(void *)offsetof(smtp_transport_options_block, socks_proxy) }
#endif
,{ "socks_proxy", opt_stringptr,
(void *)offsetof(smtp_transport_options_block, socks_proxy) }
#endif
@@
-249,7
+249,7
@@
smtp_transport_options_block smtp_transport_option_defaults = {
FALSE, /* lmtp_ignore_quota */
NULL, /* expand_retry_include_ip_address */
TRUE /* retry_include_ip_address */
FALSE, /* lmtp_ignore_quota */
NULL, /* expand_retry_include_ip_address */
TRUE /* retry_include_ip_address */
-#ifdef
EXPERIMENTAL
_SOCKS
+#ifdef
SUPPORT
_SOCKS
,NULL /* socks_proxy */
#endif
#ifdef SUPPORT_TLS
,NULL /* socks_proxy */
#endif
#ifdef SUPPORT_TLS
@@
-440,6
+440,8
@@
Arguments:
rc to put in each address's transport_return field
pass_message if TRUE, set the "pass message" flag in the address
host if set, mark addrs as having used this host
rc to put in each address's transport_return field
pass_message if TRUE, set the "pass message" flag in the address
host if set, mark addrs as having used this host
+ smtp_greeting from peer
+ helo_response from peer
If errno_value has the special value ERRNO_CONNECTTIMEOUT, ETIMEDOUT is put in
the errno field, and RTEF_CTOUT is ORed into the more_errno field, to indicate
If errno_value has the special value ERRNO_CONNECTTIMEOUT, ETIMEDOUT is put in
the errno field, and RTEF_CTOUT is ORed into the more_errno field, to indicate
@@
-450,7
+452,11
@@
Returns: nothing
static void
set_errno(address_item *addrlist, int errno_value, uschar *msg, int rc,
static void
set_errno(address_item *addrlist, int errno_value, uschar *msg, int rc,
- BOOL pass_message, host_item * host)
+ BOOL pass_message, host_item * host
+#ifdef EXPERIMENTAL_DSN_INFO
+ , const uschar * smtp_greeting, const uschar * helo_response
+#endif
+ )
{
address_item *addr;
int orvalue = 0;
{
address_item *addr;
int orvalue = 0;
@@
-459,7
+465,7
@@
if (errno_value == ERRNO_CONNECTTIMEOUT)
errno_value = ETIMEDOUT;
orvalue = RTEF_CTOUT;
}
errno_value = ETIMEDOUT;
orvalue = RTEF_CTOUT;
}
-for (addr = addrlist; addr
!= NULL
; addr = addr->next)
+for (addr = addrlist; addr; addr = addr->next)
if (addr->transport_return >= PENDING)
{
addr->basic_errno = errno_value;
if (addr->transport_return >= PENDING)
{
addr->basic_errno = errno_value;
@@
-471,10
+477,31
@@
for (addr = addrlist; addr != NULL; addr = addr->next)
}
addr->transport_return = rc;
if (host)
}
addr->transport_return = rc;
if (host)
+ {
addr->host_used = host;
addr->host_used = host;
+#ifdef EXPERIMENTAL_DSN_INFO
+ if (smtp_greeting)
+ {uschar * s = Ustrchr(smtp_greeting, '\n'); if (s) *s = '\0';}
+ addr->smtp_greeting = smtp_greeting;
+
+ if (helo_response)
+ {uschar * s = Ustrchr(helo_response, '\n'); if (s) *s = '\0';}
+ addr->helo_response = helo_response;
+#endif
+ }
}
}
}
}
+static void
+set_errno_nohost(address_item *addrlist, int errno_value, uschar *msg, int rc,
+ BOOL pass_message)
+{
+set_errno(addrlist, errno_value, msg, rc, pass_message, NULL
+#ifdef EXPERIMENTAL_DSN_INFO
+ , NULL, NULL
+#endif
+ );
+}
/*************************************************
/*************************************************
@@
-569,7
+596,7
@@
if (*errno_value == ERRNO_WRITEINCOMPLETE)
return FALSE;
}
return FALSE;
}
-#ifdef
EXPERIMENTAL_INTERNATIONAL
+#ifdef
SUPPORT_I18N
/* Handle lack of advertised SMTPUTF8, for international message */
if (*errno_value == ERRNO_UTF8_FWD)
{
/* Handle lack of advertised SMTPUTF8, for international message */
if (*errno_value == ERRNO_UTF8_FWD)
{
@@
-628,6
+655,9
@@
write_logs(address_item *addr, host_item *host)
{
uschar * message = string_sprintf("H=%s [%s]", host->name, host->address);
{
uschar * message = string_sprintf("H=%s [%s]", host->name, host->address);
+if (LOGGING(outgoing_port))
+ message = string_sprintf("%s:%d", message,
+ host->port == PORT_NONE ? 25 : host->port);
if (addr->message)
{
message = string_sprintf("%s: %s", message, addr->message);
if (addr->message)
{
message = string_sprintf("%s: %s", message, addr->message);
@@
-638,9
+668,6
@@
if (addr->message)
}
else
{
}
else
{
- if (log_extra_selector & LX_outgoing_port)
- message = string_sprintf("%s:%d", message,
- host->port == PORT_NONE ? 25 : host->port);
log_write(0, LOG_MAIN, "%s %s", message, strerror(addr->basic_errno));
deliver_msglog("%s %s %s\n", tod_stamp(tod_log), message,
strerror(addr->basic_errno));
log_write(0, LOG_MAIN, "%s %s", message, strerror(addr->basic_errno));
deliver_msglog("%s %s %s\n", tod_stamp(tod_log), message,
strerror(addr->basic_errno));
@@
-656,7
+683,7
@@
msglog_line(host_item * host, uschar * message)
-#if
def EXPERIMENTAL
_EVENT
+#if
ndef DISABLE
_EVENT
/*************************************************
* Post-defer action *
*************************************************/
/*************************************************
* Post-defer action *
*************************************************/
@@
-847,7
+874,7
@@
while (count-- > 0)
{
uschar *message = string_sprintf("SMTP timeout after RCPT TO:<%s>",
transport_rcpt_address(addr, include_affixes));
{
uschar *message = string_sprintf("SMTP timeout after RCPT TO:<%s>",
transport_rcpt_address(addr, include_affixes));
- set_errno
(addrlist, ETIMEDOUT, message, DEFER, FALSE, NULL
);
+ set_errno
_nohost(addrlist, ETIMEDOUT, message, DEFER, FALSE
);
retry_add_item(addr, addr->address_retry_key, 0);
update_waiting = FALSE;
return -1;
retry_add_item(addr, addr->address_retry_key, 0);
update_waiting = FALSE;
return -1;
@@
-892,12
+919,22
@@
while (count-- > 0)
addr->basic_errno = ERRNO_RCPT4XX;
addr->more_errno |= ((buffer[1] - '0')*10 + buffer[2] - '0') << 8;
addr->basic_errno = ERRNO_RCPT4XX;
addr->more_errno |= ((buffer[1] - '0')*10 + buffer[2] - '0') << 8;
+#ifndef DISABLE_EVENT
+ event_defer_errno = addr->more_errno;
+ msg_event_raise(US"msg:rcpt:host:defer", addr);
+#endif
+
/* Log temporary errors if there are more hosts to be tried.
If not, log this last one in the == line. */
if (host->next)
log_write(0, LOG_MAIN, "H=%s [%s]: %s", host->name, host->address, addr->message);
/* Log temporary errors if there are more hosts to be tried.
If not, log this last one in the == line. */
if (host->next)
log_write(0, LOG_MAIN, "H=%s [%s]: %s", host->name, host->address, addr->message);
+#ifndef DISABLE_EVENT
+ else
+ msg_event_raise(US"msg:rcpt:defer", addr);
+#endif
+
/* Do not put this message on the list of those waiting for specific
hosts, as otherwise it is likely to be tried too often. */
/* Do not put this message on the list of those waiting for specific
hosts, as otherwise it is likely to be tried too often. */
@@
-1096,8
+1133,8
@@
if (is_esmtp && regex_match_and_setup(regex_AUTH, buffer, 0, -1))
/* Internal problem, message in buffer. */
case ERROR:
/* Internal problem, message in buffer. */
case ERROR:
- set_errno(addrlist, ERRNO_AUTHPROB, string_copy(buffer),
- DEFER, FALSE
, NULL
);
+ set_errno
_nohost
(addrlist, ERRNO_AUTHPROB, string_copy(buffer),
+ DEFER, FALSE);
return ERROR;
}
return ERROR;
}
@@
-1111,9
+1148,9
@@
if (is_esmtp && regex_match_and_setup(regex_AUTH, buffer, 0, -1))
if (require_auth == OK && !smtp_authenticated)
{
if (require_auth == OK && !smtp_authenticated)
{
- set_errno(addrlist, ERRNO_AUTHFAIL,
+ set_errno
_nohost
(addrlist, ERRNO_AUTHFAIL,
string_sprintf("authentication required but %s", fail_reason), DEFER,
string_sprintf("authentication required but %s", fail_reason), DEFER,
- FALSE
, NULL
);
+ FALSE);
return DEFER;
}
return DEFER;
}
@@
-1152,7
+1189,7
@@
if (ob->authenticated_sender != NULL)
{
uschar *message = string_sprintf("failed to expand "
"authenticated_sender: %s", expand_string_message);
{
uschar *message = string_sprintf("failed to expand "
"authenticated_sender: %s", expand_string_message);
- set_errno
(addrlist, ERRNO_EXPANDFAIL, message, DEFER, FALSE, NULL
);
+ set_errno
_nohost(addrlist, ERRNO_EXPANDFAIL, message, DEFER, FALSE
);
return TRUE;
}
}
return TRUE;
}
}
@@
-1274,14
+1311,19
@@
we will veto this new message. */
static BOOL
smtp_are_same_identities(uschar * message_id, smtp_compare_t * s_compare)
{
static BOOL
smtp_are_same_identities(uschar * message_id, smtp_compare_t * s_compare)
{
-uschar * save_sender_address = sender_address;
-uschar * current_local_identity =
+
+uschar * message_local_identity,
+ * current_local_identity,
+ * new_sender_address;
+
+current_local_identity =
smtp_local_identity(s_compare->current_sender_address, s_compare->tblock);
smtp_local_identity(s_compare->current_sender_address, s_compare->tblock);
-uschar * new_sender_address = deliver_get_sender_address(message_id);
-uschar * message_local_identity =
- smtp_local_identity(new_sender_address, s_compare->tblock);
-sender_address = save_sender_address;
+if (!(new_sender_address = deliver_get_sender_address(message_id)))
+ return 0;
+
+message_local_identity =
+ smtp_local_identity(new_sender_address, s_compare->tblock);
return Ustrcmp(current_local_identity, message_local_identity) == 0;
}
return Ustrcmp(current_local_identity, message_local_identity) == 0;
}
@@
-1361,7
+1403,7
@@
BOOL pass_message = FALSE;
BOOL prdr_offered = FALSE;
BOOL prdr_active;
#endif
BOOL prdr_offered = FALSE;
BOOL prdr_active;
#endif
-#ifdef
EXPERIMENTAL_INTERNATIONAL
+#ifdef
SUPPORT_I18N
BOOL utf8_needed = FALSE;
BOOL utf8_offered = FALSE;
#endif
BOOL utf8_needed = FALSE;
BOOL utf8_offered = FALSE;
#endif
@@
-1376,6
+1418,10
@@
smtp_outblock outblock;
int max_rcpt = tblock->max_addresses;
uschar *igquotstr = US"";
int max_rcpt = tblock->max_addresses;
uschar *igquotstr = US"";
+#ifdef EXPERIMENTAL_DSN_INFO
+uschar *smtp_greeting = NULL;
+uschar *helo_response = NULL;
+#endif
uschar *helo_data = NULL;
uschar *message = NULL;
uschar *helo_data = NULL;
uschar *message = NULL;
@@
-1427,8
+1473,8
@@
tls_modify_variables(&tls_out);
#ifndef SUPPORT_TLS
if (smtps)
{
#ifndef SUPPORT_TLS
if (smtps)
{
- set_errno(addrlist, ERRNO_TLSFAILURE, US"TLS support not available",
- DEFER, FALSE
, NULL
);
+ set_errno
_nohost
(addrlist, ERRNO_TLSFAILURE, US"TLS support not available",
+ DEFER, FALSE);
return ERROR;
}
#endif
return ERROR;
}
#endif
@@
-1445,8
+1491,8
@@
if (continue_hostname == NULL)
if (inblock.sock < 0)
{
if (inblock.sock < 0)
{
- set_errno(addrlist, (errno == ETIMEDOUT)? ERRNO_CONNECTTIMEOUT : errno,
- NULL, DEFER, FALSE
, NULL
);
+ set_errno
_nohost
(addrlist, (errno == ETIMEDOUT)? ERRNO_CONNECTTIMEOUT : errno,
+ NULL, DEFER, FALSE);
return DEFER;
}
return DEFER;
}
@@
-1464,18
+1510,18
@@
if (continue_hostname == NULL)
&& dane_required /* do not error on only dane-requested */
)
{
&& dane_required /* do not error on only dane-requested */
)
{
- set_errno(addrlist, ERRNO_DNSDEFER,
+ set_errno
_nohost
(addrlist, ERRNO_DNSDEFER,
string_sprintf("DANE error: tlsa lookup %s",
rc == DEFER ? "DEFER" : "FAIL"),
string_sprintf("DANE error: tlsa lookup %s",
rc == DEFER ? "DEFER" : "FAIL"),
- rc, FALSE
, NULL
);
+ rc, FALSE);
return rc;
}
}
else if (dane_required)
{
return rc;
}
}
else if (dane_required)
{
- set_errno(addrlist, ERRNO_DNSDEFER,
+ set_errno
_nohost
(addrlist, ERRNO_DNSDEFER,
string_sprintf("DANE error: %s lookup not DNSSEC", host->name),
string_sprintf("DANE error: %s lookup not DNSSEC", host->name),
- FAIL, FALSE
, NULL
);
+ FAIL, FALSE);
return FAIL;
}
return FAIL;
}
@@
-1489,14
+1535,14
@@
if (continue_hostname == NULL)
delayed till here so that $sending_interface and $sending_port are set. */
helo_data = expand_string(ob->helo_data);
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;
if ((helo_data = string_domain_utf8_to_alabel(helo_data, &errstr)), errstr)
{
errstr = string_sprintf("failed to expand helo_data: %s", errstr);
if (helo_data)
{
uschar * errstr = NULL;
if ((helo_data = string_domain_utf8_to_alabel(helo_data, &errstr)), errstr)
{
errstr = string_sprintf("failed to expand helo_data: %s", errstr);
- set_errno
(addrlist, ERRNO_EXPANDFAIL, errstr, DEFER, FALSE, NULL
);
+ set_errno
_nohost(addrlist, ERRNO_EXPANDFAIL, errstr, DEFER, FALSE
);
yield = DEFER;
goto SEND_QUIT;
}
yield = DEFER;
goto SEND_QUIT;
}
@@
-1509,10
+1555,14
@@
if (continue_hostname == NULL)
if (!smtps)
{
if (!smtps)
{
- if (!smtp_read_response(&inblock, buffer, sizeof(buffer), '2',
- ob->command_timeout)) goto RESPONSE_FAILED;
+ BOOL good_response = smtp_read_response(&inblock, buffer, sizeof(buffer),
+ '2', ob->command_timeout);
+#ifdef EXPERIMENTAL_DSN_INFO
+ smtp_greeting = string_copy(buffer);
+#endif
+ if (!good_response) goto RESPONSE_FAILED;
-#if
def EXPERIMENTAL
_EVENT
+#if
ndef DISABLE
_EVENT
{
uschar * s;
lookup_dnssec_authenticated = host->dnssec==DS_YES ? US"yes"
{
uschar * s;
lookup_dnssec_authenticated = host->dnssec==DS_YES ? US"yes"
@@
-1520,9
+1570,9
@@
if (continue_hostname == NULL)
s = event_raise(tblock->event_action, US"smtp:connect", buffer);
if (s)
{
s = event_raise(tblock->event_action, US"smtp:connect", buffer);
if (s)
{
- set_errno(addrlist, ERRNO_EXPANDFAIL,
+ set_errno
_nohost
(addrlist, ERRNO_EXPANDFAIL,
string_sprintf("deferred by smtp:connect event expansion: %s", s),
string_sprintf("deferred by smtp:connect event expansion: %s", s),
- DEFER, FALSE
, NULL
);
+ DEFER, FALSE);
yield = DEFER;
goto SEND_QUIT;
}
yield = DEFER;
goto SEND_QUIT;
}
@@
-1536,7
+1586,7
@@
if (continue_hostname == NULL)
{
uschar *message = string_sprintf("failed to expand helo_data: %s",
expand_string_message);
{
uschar *message = string_sprintf("failed to expand helo_data: %s",
expand_string_message);
- set_errno
(addrlist, ERRNO_EXPANDFAIL, message, DEFER, FALSE, NULL
);
+ set_errno
_nohost(addrlist, ERRNO_EXPANDFAIL, message, DEFER, FALSE
);
yield = DEFER;
goto SEND_QUIT;
}
yield = DEFER;
goto SEND_QUIT;
}
@@
-1601,9
+1651,18
@@
goto SEND_QUIT;
if (!smtp_read_response(&inblock, buffer, sizeof(buffer), '2',
ob->command_timeout))
{
if (!smtp_read_response(&inblock, buffer, sizeof(buffer), '2',
ob->command_timeout))
{
- if (errno != 0 || buffer[0] == 0 || lmtp) goto RESPONSE_FAILED;
+ if (errno != 0 || buffer[0] == 0 || lmtp)
+ {
+#ifdef EXPERIMENTAL_DSN_INFO
+ helo_response = string_copy(buffer);
+#endif
+ goto RESPONSE_FAILED;
+ }
esmtp = FALSE;
}
esmtp = FALSE;
}
+#ifdef EXPERIMENTAL_DSN_INFO
+ helo_response = string_copy(buffer);
+#endif
}
else
{
}
else
{
@@
-1613,10
+1672,16
@@
goto SEND_QUIT;
if (!esmtp)
{
if (!esmtp)
{
+ BOOL good_response;
+
if (smtp_write_command(&outblock, FALSE, "HELO %s\r\n", helo_data) < 0)
goto SEND_FAILED;
if (smtp_write_command(&outblock, FALSE, "HELO %s\r\n", helo_data) < 0)
goto SEND_FAILED;
- if (!smtp_read_response(&inblock, buffer, sizeof(buffer), '2',
- ob->command_timeout)) goto RESPONSE_FAILED;
+ good_response = smtp_read_response(&inblock, buffer, sizeof(buffer),
+ '2', ob->command_timeout);
+#ifdef EXPERIMENTAL_DSN_INFO
+ helo_response = string_copy(buffer);
+#endif
+ if (!good_response) goto RESPONSE_FAILED;
}
/* Set IGNOREQUOTA if the response to LHLO specifies support and the
}
/* Set IGNOREQUOTA if the response to LHLO specifies support and the
@@
-1644,7
+1709,7
@@
goto SEND_QUIT;
{DEBUG(D_transport) debug_printf("PRDR usable\n");}
#endif
{DEBUG(D_transport) debug_printf("PRDR usable\n");}
#endif
-#ifdef
EXPERIMENTAL_INTERNATIONAL
+#ifdef
SUPPORT_I18N
if (addrlist->prop.utf8_msg)
{
utf8_needed = !addrlist->prop.utf8_downcvt
if (addrlist->prop.utf8_msg)
{
utf8_needed = !addrlist->prop.utf8_downcvt
@@
-1666,6
+1731,11
@@
error messages. Note that smtp_use_size and smtp_use_pipelining will have been
set from the command line if they were set in the process that passed the
connection on. */
set from the command line if they were set in the process that passed the
connection on. */
+/*XXX continue case needs to propagate DSN_INFO, prob. in deliver.c
+as the contine goes via transport_pass_socket() and doublefork and exec.
+It does not wait. Unclear how we keep separate host's responses
+separate - we could match up by host ip+port as a bodge. */
+
else
{
inblock.sock = outblock.sock = fileno(stdin);
else
{
inblock.sock = outblock.sock = fileno(stdin);
@@
-1744,7
+1814,7
@@
if ( tls_offered
/* TLS session is set up */
/* TLS session is set up */
- for (addr = addrlist; addr
!= NULL
; addr = addr->next)
+ for (addr = addrlist; addr; addr = addr->next)
if (addr->transport_return == PENDING_DEFER)
{
addr->cipher = tls_out.cipher;
if (addr->transport_return == PENDING_DEFER)
{
addr->cipher = tls_out.cipher;
@@
-1769,6
+1839,8
@@
start of the Exim process (in exim.c). */
if (tls_out.active >= 0)
{
char *greeting_cmd;
if (tls_out.active >= 0)
{
char *greeting_cmd;
+ BOOL good_response;
+
if (helo_data == NULL)
{
helo_data = expand_string(ob->helo_data);
if (helo_data == NULL)
{
helo_data = expand_string(ob->helo_data);
@@
-1776,7
+1848,7
@@
if (tls_out.active >= 0)
{
uschar *message = string_sprintf("failed to expand helo_data: %s",
expand_string_message);
{
uschar *message = string_sprintf("failed to expand helo_data: %s",
expand_string_message);
- set_errno
(addrlist, ERRNO_EXPANDFAIL, message, DEFER, FALSE, NULL
);
+ set_errno
_nohost(addrlist, ERRNO_EXPANDFAIL, message, DEFER, FALSE
);
yield = DEFER;
goto SEND_QUIT;
}
yield = DEFER;
goto SEND_QUIT;
}
@@
-1785,8
+1857,12
@@
if (tls_out.active >= 0)
/* For SMTPS we need to wait for the initial OK response. */
if (smtps)
{
/* For SMTPS we need to wait for the initial OK response. */
if (smtps)
{
- if (!smtp_read_response(&inblock, buffer, sizeof(buffer), '2',
- ob->command_timeout)) goto RESPONSE_FAILED;
+ good_response = smtp_read_response(&inblock, buffer, sizeof(buffer),
+ '2', ob->command_timeout);
+#ifdef EXPERIMENTAL_DSN_INFO
+ smtp_greeting = string_copy(buffer);
+#endif
+ if (!good_response) goto RESPONSE_FAILED;
}
if (esmtp)
}
if (esmtp)
@@
-1801,9
+1877,12
@@
if (tls_out.active >= 0)
if (smtp_write_command(&outblock, FALSE, "%s %s\r\n",
lmtp? "LHLO" : greeting_cmd, helo_data) < 0)
goto SEND_FAILED;
if (smtp_write_command(&outblock, FALSE, "%s %s\r\n",
lmtp? "LHLO" : greeting_cmd, helo_data) < 0)
goto SEND_FAILED;
- if (!smtp_read_response(&inblock, buffer, sizeof(buffer), '2',
- ob->command_timeout))
- goto RESPONSE_FAILED;
+ good_response = smtp_read_response(&inblock, buffer, sizeof(buffer),
+ '2', ob->command_timeout);
+#ifdef EXPERIMENTAL_DSN_INFO
+ helo_response = string_copy(buffer);
+#endif
+ if (!good_response) goto RESPONSE_FAILED;
}
/* If the host is required to use a secure channel, ensure that we
}
/* If the host is required to use a secure channel, ensure that we
@@
-1871,7
+1950,7
@@
if (continue_hostname == NULL
{DEBUG(D_transport) debug_printf("PRDR usable\n");}
#endif
{DEBUG(D_transport) debug_printf("PRDR usable\n");}
#endif
-#ifdef
EXPERIMENTAL_INTERNATIONAL
+#ifdef
SUPPORT_I18N
if (addrlist->prop.utf8_msg)
utf8_offered = esmtp
&& pcre_exec(regex_UTF8, NULL, CS buffer, Ustrlen(buffer), 0,
if (addrlist->prop.utf8_msg)
utf8_offered = esmtp
&& pcre_exec(regex_UTF8, NULL, CS buffer, Ustrlen(buffer), 0,
@@
-1904,7
+1983,7
@@
message-specific. */
setting_up = FALSE;
setting_up = FALSE;
-#ifdef
EXPERIMENTAL_INTERNATIONAL
+#ifdef
SUPPORT_I18N
/* If this is an international message we need the host to speak SMTPUTF8 */
if (utf8_needed && !utf8_offered)
{
/* If this is an international message we need the host to speak SMTPUTF8 */
if (utf8_needed && !utf8_offered)
{
@@
-1930,8
+2009,8
@@
if (tblock->filter_command != NULL)
if (!rc)
{
if (!rc)
{
- set_errno(addrlist->next, addrlist->basic_errno, addrlist->message, DEFER,
- FALSE
, NULL
);
+ set_errno
_nohost
(addrlist->next, addrlist->basic_errno, addrlist->message, DEFER,
+ FALSE);
yield = ERROR;
goto SEND_QUIT;
}
yield = ERROR;
goto SEND_QUIT;
}
@@
-1989,7
+2068,7
@@
if (prdr_offered)
}
#endif
}
#endif
-#ifdef
EXPERIMENTAL_INTERNATIONAL
+#ifdef
SUPPORT_I18N
if (addrlist->prop.utf8_msg && !addrlist->prop.utf8_downcvt && utf8_offered)
sprintf(CS p, " SMTPUTF8"), p += 9;
#endif
if (addrlist->prop.utf8_msg && !addrlist->prop.utf8_downcvt && utf8_offered)
sprintf(CS p, " SMTPUTF8"), p += 9;
#endif
@@
-2049,7
+2128,7
@@
pending_MAIL = TRUE; /* The block starts with MAIL */
{
uschar * s = return_path;
{
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
uschar * errstr = NULL;
/* If we must downconvert, do the from-address here. Remember we had to
@@
-2060,7
+2139,7
@@
pending_MAIL = TRUE; /* The block starts with MAIL */
{
if (s = string_address_utf8_to_alabel(return_path, &errstr), errstr)
{
{
if (s = string_address_utf8_to_alabel(return_path, &errstr), errstr)
{
- set_errno
(addrlist, ERRNO_EXPANDFAIL, errstr, DEFER, FALSE, NULL
);
+ set_errno
_nohost(addrlist, ERRNO_EXPANDFAIL, errstr, DEFER, FALSE
);
yield = ERROR;
goto SEND_QUIT;
}
yield = ERROR;
goto SEND_QUIT;
}
@@
-2160,7
+2239,7
@@
for (addr = first_addr;
rcpt_addr = transport_rcpt_address(addr, tblock->rcpt_include_affixes);
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)
{
uschar * dummy_errstr;
if ( testflag(addrlist, af_utf8_downcvt)
@@
-2212,8
+2291,8
@@
if (mua_wrapper)
if (badaddr->transport_return != PENDING_OK)
{
/*XXX could we find a better errno than 0 here? */
if (badaddr->transport_return != PENDING_OK)
{
/*XXX could we find a better errno than 0 here? */
- set_errno(addrlist, 0, badaddr->message, FAIL,
- testflag(badaddr, af_pass_message)
, NULL
);
+ set_errno
_nohost
(addrlist, 0, badaddr->message, FAIL,
+ testflag(badaddr, af_pass_message));
ok = FALSE;
break;
}
ok = FALSE;
break;
}
@@
-2379,8
+2458,8
@@
if (!ok) ok = TRUE; else
/* Set up confirmation if needed - applies only to SMTP */
if (
/* Set up confirmation if needed - applies only to SMTP */
if (
-#if
ndef EXPERIMENTAL
_EVENT
-
(log_extra_selector & LX_smtp_confirmation) != 0
&&
+#if
def DISABLE
_EVENT
+
LOGGING(smtp_confirmation)
&&
#endif
!lmtp
)
#endif
!lmtp
)
@@
-2435,7
+2514,7
@@
if (!ok) ok = TRUE; else
continue;
}
completed_address = TRUE; /* NOW we can set this flag */
continue;
}
completed_address = TRUE; /* NOW we can set this flag */
- if (
(log_extra_selector & LX_smtp_confirmation) != 0
)
+ if (
LOGGING(smtp_confirmation)
)
{
const uschar *s = string_printing(buffer);
/* deconst cast ok here as string_printing was checked to have alloc'n'copied */
{
const uschar *s = string_printing(buffer);
/* deconst cast ok here as string_printing was checked to have alloc'n'copied */
@@
-2470,7
+2549,7
@@
if (!ok) ok = TRUE; else
else
sprintf(CS buffer, "%.500s\n", addr->unique);
else
sprintf(CS buffer, "%.500s\n", addr->unique);
- DEBUG(D_deliver) debug_printf("journalling %s", buffer);
+ DEBUG(D_deliver) debug_printf("journalling %s
\n
", buffer);
len = Ustrlen(CS buffer);
if (write(journal_fd, buffer, len) != len)
log_write(0, LOG_MAIN|LOG_PANIC, "failed to write journal for "
len = Ustrlen(CS buffer);
if (write(journal_fd, buffer, len) != len)
log_write(0, LOG_MAIN|LOG_PANIC, "failed to write journal for "
@@
-2507,7
+2586,7
@@
if (!ok) ok = TRUE; else
else
sprintf(CS buffer, "%.500s\n", addr->unique);
else
sprintf(CS buffer, "%.500s\n", addr->unique);
- DEBUG(D_deliver) debug_printf("journalling(PRDR) %s", buffer);
+ DEBUG(D_deliver) debug_printf("journalling(PRDR) %s
\n
", buffer);
len = Ustrlen(CS buffer);
if (write(journal_fd, buffer, len) != len)
log_write(0, LOG_MAIN|LOG_PANIC, "failed to write journal for "
len = Ustrlen(CS buffer);
if (write(journal_fd, buffer, len) != len)
log_write(0, LOG_MAIN|LOG_PANIC, "failed to write journal for "
@@
-2537,22
+2616,27
@@
the problem is not related to this specific message. */
if (!ok)
{
if (!ok)
{
- int code;
+ int code, set_rc;
+ uschar * set_message;
RESPONSE_FAILED:
RESPONSE_FAILED:
- save_errno = errno;
- message = NULL;
- send_quit = check_response(host, &save_errno, addrlist->more_errno,
- buffer, &code, &message, &pass_message);
- goto FAILED;
+ {
+ save_errno = errno;
+ message = NULL;
+ send_quit = check_response(host, &save_errno, addrlist->more_errno,
+ buffer, &code, &message, &pass_message);
+ goto FAILED;
+ }
SEND_FAILED:
SEND_FAILED:
- save_errno = errno;
- code = '4';
- message = US string_sprintf("send() to %s [%s] failed: %s",
- host->name, host->address, strerror(save_errno));
- send_quit = FALSE;
- goto FAILED;
+ {
+ save_errno = errno;
+ code = '4';
+ message = US string_sprintf("send() to %s [%s] failed: %s",
+ host->name, host->address, strerror(save_errno));
+ send_quit = FALSE;
+ goto FAILED;
+ }
/* This label is jumped to directly when a TLS negotiation has failed,
or was not done for a host for which it is required. Values will be set
/* This label is jumped to directly when a TLS negotiation has failed,
or was not done for a host for which it is required. Values will be set
@@
-2573,16
+2657,14
@@
if (!ok)
FAILED:
ok = FALSE; /* For when reached by GOTO */
FAILED:
ok = FALSE; /* For when reached by GOTO */
+ set_message = message;
if (setting_up)
{
if (code == '5')
if (setting_up)
{
if (code == '5')
- set_
errno(addrlist, save_errno, message, FAIL, pass_message, host)
;
+ set_
rc = FAIL
;
else
else
- {
- set_errno(addrlist, save_errno, message, DEFER, pass_message, host);
- yield = DEFER;
- }
+ yield = set_rc = DEFER;
}
/* We want to handle timeouts after MAIL or "." and loss of connection after
}
/* We want to handle timeouts after MAIL or "." and loss of connection after
@@
-2597,7
+2679,7
@@
if (!ok)
switch(save_errno)
{
switch(save_errno)
{
-#ifdef
EXPERIMENTAL_INTERNATIONAL
+#ifdef
SUPPORT_I18N
case ERRNO_UTF8_FWD:
code = '5';
/*FALLTHROUGH*/
case ERRNO_UTF8_FWD:
code = '5';
/*FALLTHROUGH*/
@@
-2641,14
+2723,15
@@
if (!ok)
if (message_error)
{
if (mua_wrapper) code = '5'; /* Force hard failure in wrapper mode */
if (message_error)
{
if (mua_wrapper) code = '5'; /* Force hard failure in wrapper mode */
- set_errno(addrlist, save_errno, message, (code == '5')? FAIL : DEFER,
- pass_message, host);
/* If there's an errno, the message contains just the identity of
the host. */
/* If there's an errno, the message contains just the identity of
the host. */
- if (code != '5') /* Anything other than 5 is treated as temporary */
+ if (code == '5')
+ set_rc = FAIL;
+ else /* Anything other than 5 is treated as temporary */
{
{
+ set_rc = DEFER;
if (save_errno > 0)
message = US string_sprintf("%s: %s", message, strerror(save_errno));
if (host->next != NULL) log_write(0, LOG_MAIN, "%s", message);
if (save_errno > 0)
message = US string_sprintf("%s: %s", message, strerror(save_errno));
if (host->next != NULL) log_write(0, LOG_MAIN, "%s", message);
@@
-2665,11
+2748,17
@@
if (!ok)
else
{
else
{
+ set_rc = DEFER;
yield = (save_errno == ERRNO_CHHEADER_FAIL ||
save_errno == ERRNO_FILTER_FAIL)? ERROR : DEFER;
yield = (save_errno == ERRNO_CHHEADER_FAIL ||
save_errno == ERRNO_FILTER_FAIL)? ERROR : DEFER;
- set_errno(addrlist, save_errno, message, DEFER, pass_message, host);
}
}
}
}
+
+ set_errno(addrlist, save_errno, set_message, set_rc, pass_message, host
+#ifdef EXPERIMENTAL_DSN_INFO
+ , smtp_greeting, helo_response
+#endif
+ );
}
}
@@
-2782,6
+2871,9
@@
if (completed_address && ok && send_quit)
/* If the socket is successfully passed, we musn't send QUIT (or
indeed anything!) from here. */
/* If the socket is successfully passed, we musn't send QUIT (or
indeed anything!) from here. */
+/*XXX DSN_INFO: assume likely to do new HELO; but for greet we'll want to
+propagate it from the initial
+*/
if (ok && transport_pass_socket(tblock->name, host->name, host->address,
new_message_id, inblock.sock))
{
if (ok && transport_pass_socket(tblock->name, host->name, host->address,
new_message_id, inblock.sock))
{
@@
-2791,7
+2883,11
@@
if (completed_address && ok && send_quit)
/* If RSET failed and there are addresses left, they get deferred. */
/* If RSET failed and there are addresses left, they get deferred. */
- else set_errno(first_addr, errno, msg, DEFER, FALSE, host);
+ else set_errno(first_addr, errno, msg, DEFER, FALSE, host
+#ifdef EXPERIMENTAL_DSN_INFO
+ , smtp_greeting, helo_response
+#endif
+ );
}
}
}
}
@@
-2834,7
+2930,7
@@
case continue_more won't get set. */
(void)close(inblock.sock);
(void)close(inblock.sock);
-#if
def EXPERIMENTAL
_EVENT
+#if
ndef DISABLE
_EVENT
(void) event_raise(tblock->event_action, US"tcp:close", NULL);
#endif
(void) event_raise(tblock->event_action, US"tcp:close", NULL);
#endif
@@
-2932,6
+3028,10
@@
for (addr = addrlist; addr != NULL; addr = addr->next)
addr->peercert = NULL;
addr->peerdn = NULL;
addr->ocsp = OCSP_NOT_REQ;
addr->peercert = NULL;
addr->peerdn = NULL;
addr->ocsp = OCSP_NOT_REQ;
+#endif
+#ifdef EXPERIMENTAL_DSN_INFO
+ addr->smtp_greeting = NULL;
+ addr->helo_response = NULL;
#endif
}
return first_addr;
#endif
}
return first_addr;
@@
-3169,7
+3269,6
@@
for (cutoff_retry = 0; expired &&
BOOL serialized = FALSE;
BOOL host_is_expired = FALSE;
BOOL message_defer = FALSE;
BOOL serialized = FALSE;
BOOL host_is_expired = FALSE;
BOOL message_defer = FALSE;
- BOOL ifchanges = FALSE;
BOOL some_deferred = FALSE;
address_item *first_addr = NULL;
uschar *interface = NULL;
BOOL some_deferred = FALSE;
address_item *first_addr = NULL;
uschar *interface = NULL;
@@
-3345,15
+3444,18
@@
for (cutoff_retry = 0; expired &&
if (Ustrcmp(pistring, ":25") == 0) pistring = US"";
/* Select IPv4 or IPv6, and choose an outgoing interface. If the interface
if (Ustrcmp(pistring, ":25") == 0) pistring = US"";
/* Select IPv4 or IPv6, and choose an outgoing interface. If the interface
- string changes upon expansion, we must add it to the key that is used for
- retries, because connections to the same host from a different interface
- should be treated separately. */
+ string is set, even if constant (as different transports can have different
+ constant settings), we must add it to the key that is used for retries,
+ 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 (!smtp_get_interface(ob->interface, host_af, addrlist, &ifchanges,
- &interface, tid))
- return FALSE;
- if (ifchanges) pistring = string_sprintf("%s/%s", pistring, interface);
+ if ((rs = ob->interface) && *rs)
+ {
+ if (!smtp_get_interface(rs, host_af, addrlist, &interface, tid))
+ return FALSE;
+ pistring = string_sprintf("%s/%s", pistring, interface);
+ }
/* The first time round the outer loop, check the status of the host by
inspecting the retry data. The second time round, we are interested only
/* The first time round the outer loop, check the status of the host by
inspecting the retry data. The second time round, we are interested only
@@
-3440,7
+3542,7
@@
for (cutoff_retry = 0; expired &&
verify_check_given_host(&ob->serialize_hosts, host) == OK)
{
serialize_key = string_sprintf("host-serialize-%s", host->name);
verify_check_given_host(&ob->serialize_hosts, host) == OK)
{
serialize_key = string_sprintf("host-serialize-%s", host->name);
- if (!enq_start(serialize_key))
+ if (!enq_start(serialize_key
, 1
))
{
DEBUG(D_transport)
debug_printf("skipping host %s because another Exim process "
{
DEBUG(D_transport)
debug_printf("skipping host %s because another Exim process "
@@
-3474,7
+3576,7
@@
for (cutoff_retry = 0; expired &&
if (dont_deliver)
{
host_item *host2;
if (dont_deliver)
{
host_item *host2;
- set_errno
(addrlist, 0, NULL, OK, FALSE, NULL
);
+ set_errno
_nohost(addrlist, 0, NULL, OK, FALSE
);
for (addr = addrlist; addr != NULL; addr = addr->next)
{
addr->host_used = host;
for (addr = addrlist; addr != NULL; addr = addr->next)
{
addr->host_used = host;
@@
-3526,15
+3628,14
@@
for (cutoff_retry = 0; expired &&
host_item *h;
DEBUG(D_transport)
debug_printf("hosts_max_try limit reached with this host\n");
host_item *h;
DEBUG(D_transport)
debug_printf("hosts_max_try limit reached with this host\n");
- for (h = host; h != NULL; h = h->next)
- if (h->mx != host->mx) break;
- if (h != NULL)
- {
- nexthost = h;
- unexpired_hosts_tried--;
- DEBUG(D_transport) debug_printf("however, a higher MX host exists "
- "and will be tried\n");
- }
+ for (h = host; h; h = h->next) if (h->mx != host->mx)
+ {
+ nexthost = h;
+ unexpired_hosts_tried--;
+ DEBUG(D_transport) debug_printf("however, a higher MX host exists "
+ "and will be tried\n");
+ break;
+ }
}
/* Attempt the delivery. */
}
/* Attempt the delivery. */
@@
-3562,7
+3663,7
@@
for (cutoff_retry = 0; expired &&
first_addr->basic_errno != ERRNO_TLSFAILURE)
write_logs(first_addr, host);
first_addr->basic_errno != ERRNO_TLSFAILURE)
write_logs(first_addr, host);
-#if
def EXPERIMENTAL
_EVENT
+#if
ndef DISABLE
_EVENT
if (rc == DEFER)
deferred_event_raise(first_addr, host);
#endif
if (rc == DEFER)
deferred_event_raise(first_addr, host);
#endif
@@
-3590,7
+3691,7
@@
for (cutoff_retry = 0; expired &&
&message_defer, TRUE);
if (rc == DEFER && first_addr->basic_errno != ERRNO_AUTHFAIL)
write_logs(first_addr, host);
&message_defer, TRUE);
if (rc == DEFER && first_addr->basic_errno != ERRNO_AUTHFAIL)
write_logs(first_addr, host);
-# if
def EXPERIMENTAL
_EVENT
+# if
ndef DISABLE
_EVENT
if (rc == DEFER)
deferred_event_raise(first_addr, host);
# endif
if (rc == DEFER)
deferred_event_raise(first_addr, host);
# endif