X-Git-Url: https://git.exim.org/exim.git/blobdiff_plain/cf39cf5741111de26125a55c311223b5b6b6a36b..d7d7b7b91dd75cec636fc144da7e27eed860f971:/src/src/transports/smtp.c diff --git a/src/src/transports/smtp.c b/src/src/transports/smtp.c index 5c7311071..bb8c6e018 100644 --- a/src/src/transports/smtp.c +++ b/src/src/transports/smtp.c @@ -1,10 +1,10 @@ -/* $Cambridge: exim/src/src/transports/smtp.c,v 1.14 2005/08/02 09:24:45 ph10 Exp $ */ +/* $Cambridge: exim/src/src/transports/smtp.c,v 1.20 2006/02/07 11:19:03 ph10 Exp $ */ /************************************************* * Exim - an Internet mail transport agent * *************************************************/ -/* Copyright (c) University of Cambridge 1995 - 2005 */ +/* Copyright (c) University of Cambridge 1995 - 2006 */ /* See the file NOTICE for conditions of use and distribution. */ #include "../exim.h" @@ -93,6 +93,8 @@ optionlist smtp_transport_options[] = { (void *)offsetof(smtp_transport_options_block, interface) }, { "keepalive", opt_bool, (void *)offsetof(smtp_transport_options_block, keepalive) }, + { "lmtp_ignore_quota", opt_bool, + (void *)offsetof(smtp_transport_options_block, lmtp_ignore_quota) }, { "max_rcpt", opt_int | opt_public, (void *)offsetof(transport_instance, max_addresses) }, { "multi_domain", opt_bool | opt_public, @@ -163,6 +165,7 @@ smtp_transport_options_block smtp_transport_option_defaults = { FALSE, /* hosts_override */ FALSE, /* hosts_randomize */ TRUE, /* keepalive */ + FALSE, /* lmtp_ignore_quota */ TRUE /* retry_include_ip_address */ #ifdef SUPPORT_TLS ,NULL, /* tls_certificate */ @@ -326,8 +329,8 @@ this particular type of timeout. 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) { address_item *addr; @@ -459,11 +462,12 @@ if (buffer[0] != 0) } /* No data was read. If there is no errno, this must be the EOF (i.e. -connection closed) case, which causes deferral. Otherwise, put the host's -identity in the message, leaving the errno value to be interpreted as well. In -all cases, we have to assume the connection is now dead. */ +connection closed) case, which causes deferral. An explicit connection reset +error has the same effect. Otherwise, put the host's identity in the message, +leaving the errno value to be interpreted as well. In all cases, we have to +assume the connection is now dead. */ -if (*errno_value == 0) +if (*errno_value == 0 || *errno_value == ECONNRESET) { *errno_value = ERRNO_SMTPCLOSED; *message = US string_sprintf("Remote host %s [%s] closed connection " @@ -502,14 +506,14 @@ if (addr->message != NULL) } else { - log_write(0, LOG_MAIN, "%s [%s]: %s", - host->name, - host->address, - strerror(addr->basic_errno)); - deliver_msglog("%s %s [%s]: %s\n", - tod_stamp(tod_log), - host->name, - host->address, + uschar *msg = + ((log_extra_selector & LX_outgoing_port) != 0)? + string_sprintf("%s [%s]:%d", host->name, host->address, + (host->port == PORT_NONE)? 25 : host->port) + : + string_sprintf("%s [%s]", host->name, host->address); + log_write(0, LOG_MAIN, "%s %s", msg, strerror(addr->basic_errno)); + deliver_msglog("%s %s %s\n", tod_stamp(tod_log), msg, strerror(addr->basic_errno)); } } @@ -746,7 +750,7 @@ Arguments: failed by one of them. host host to deliver to host_af AF_INET or AF_INET6 - port TCP/IP port to use, in host byte order + port default TCP/IP port to use, in host byte order interface interface to bind to, or NULL tblock transport instance block copy_host TRUE if host set in addr->host_used must be copied, because @@ -796,6 +800,7 @@ BOOL pass_message = FALSE; smtp_inblock inblock; smtp_outblock outblock; int max_rcpt = tblock->max_addresses; +uschar *igquotstr = US""; uschar *local_authenticated_sender = authenticated_sender; uschar *helo_data; uschar *message = NULL; @@ -947,6 +952,13 @@ goto SEND_QUIT; ob->command_timeout)) 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""; + /* Set tls_offered if the response to EHLO specifies support for STARTTLS. */ #ifdef SUPPORT_TLS @@ -1081,6 +1093,13 @@ if (continue_hostname == NULL int require_auth; uschar *fail_reason = US"server did not advertise AUTH support"; + /* 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""; + /* If the response to EHLO specified support for the SIZE parameter, note this, provided size_addition is non-negative. */ @@ -1343,8 +1362,8 @@ for (addr = first_addr; yield as OK, because this error can often mean that there is a problem with just one address, so we don't want to delay the host. */ - count = smtp_write_command(&outblock, no_flush, "RCPT TO:<%s>\r\n", - transport_rcpt_address(addr, tblock->rcpt_include_affixes)); + count = smtp_write_command(&outblock, no_flush, "RCPT TO:<%s>%s\r\n", + transport_rcpt_address(addr, tblock->rcpt_include_affixes), igquotstr); if (count < 0) goto SEND_FAILED; if (count > 0) { @@ -1559,11 +1578,10 @@ if (!ok) ok = TRUE; else } /* SMTP, or success return from LMTP for this address. Pass back the - actual port used. */ + actual host that was used. */ addr->transport_return = OK; addr->more_errno = delivery_time; - thost->port = port; addr->host_used = thost; addr->special_action = flag; addr->message = conf; @@ -2112,12 +2130,9 @@ else if (ob->hosts_randomize && hostlist->mx == MX_NONE && !continuing) } -/* Sort out the port. Set up a string for adding to the retry key if the port -number is not the standard SMTP port. */ +/* Sort out the default port. */ if (!smtp_get_port(ob->port, addrlist, &port, tid)) return FALSE; -pistring = string_sprintf(":%d", port); -if (Ustrcmp(pistring, ":25") == 0) pistring = US""; /* For each host-plus-IP-address on the list: @@ -2221,6 +2236,8 @@ for (cutoff_retry = 0; expired && if (host->address == NULL) { + int new_port; + host_item *hh; uschar *canonical_name; if (host->status >= hstatus_unusable) @@ -2232,12 +2249,19 @@ for (cutoff_retry = 0; expired && DEBUG(D_transport) debug_printf("getting address for %s\n", host->name); + /* The host name is permitted to have an attached port. Find it, and + strip it from the name. Just remember it for now. */ + + new_port = host_item_get_port(host); + + /* Count hosts looked up */ + hosts_looked_up++; /* Find by name if so configured, or if it's an IP address. We don't just copy the IP address, because we need the test-for-local to happen. */ - if (ob->gethostbyname || string_is_ip_address(host->name, NULL) > 0) + if (ob->gethostbyname || string_is_ip_address(host->name, NULL) != 0) rc = host_find_byname(host, NULL, &canonical_name, TRUE); else { @@ -2248,6 +2272,11 @@ for (cutoff_retry = 0; expired && &canonical_name, NULL); } + /* Update the host (and any additional blocks, resulting from + multihoming) with a host-specific port, if any. */ + + for (hh = host; hh != nexthost; hh = hh->next) hh->port = new_port; + /* Failure to find the host at this time (usually DNS temporary failure) is really a kind of routing failure rather than a transport failure. Therefore we add a retry item of the routing kind, not to stop us trying @@ -2341,6 +2370,14 @@ for (cutoff_retry = 0; expired && deliver_host = host->name; deliver_host_address = host->address; + /* Set up a string for adding to the retry key if the port number is not + 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); + 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