-/* $Cambridge: exim/src/src/deliver.c,v 1.13 2005/04/07 15:40:50 ph10 Exp $ */
+/* $Cambridge: exim/src/src/deliver.c,v 1.14 2005/04/28 13:06:32 ph10 Exp $ */
/*************************************************
* Exim - an Internet mail transport agent *
printed = US"an undisclosed address";
yield = FALSE;
}
-
else if (!testflag(addr, af_pfr) || addr->parent == NULL)
printed = addr->address;
-
/*************************************************
* Print error for an address *
*************************************************/
introducing newlines. All lines are indented by 4; the initial printing
position must be set before calling.
+This function used always to print the error. Nowadays we want to restrict it
+to cases such as SMTP errors from a remote host, and errors from :fail: and
+filter "fail". We no longer pass other information willy-nilly in bounce and
+warning messages. Text in user_message is always output; text in message only
+if the af_pass_message flag is set.
+
Arguments:
- addr points to the address
+ addr the address
f the FILE to print on
+ s some leading text
Returns: nothing
*/
static void
-print_address_error(address_item *addr, FILE *f)
+print_address_error(address_item *addr, FILE *f, uschar *t)
{
+int count = Ustrlen(t);
uschar *s = (addr->user_message != NULL)? addr->user_message : addr->message;
-if (addr->basic_errno > 0)
- {
- fprintf(f, "%s%s", strerror(addr->basic_errno),
- (s == NULL)? "" : ":\n ");
- }
-if (s == NULL)
+
+if (addr->user_message != NULL)
+ s = addr->user_message;
+else
{
- if (addr->basic_errno <= 0) fprintf(f, "unknown error");
+ if (!testflag(addr, af_pass_message) || addr->message == NULL) return;
+ s = addr->message;
}
-else
+
+fprintf(f, "\n %s", t);
+
+while (*s != 0)
{
- int count = 0;
- while (*s != 0)
+ if (*s == '\\' && s[1] == 'n')
+ {
+ fprintf(f, "\n ");
+ s += 2;
+ count = 0;
+ }
+ else
{
- if (*s == '\\' && s[1] == 'n')
+ fputc(*s, f);
+ count++;
+ if (*s++ == ':' && isspace(*s) && count > 45)
{
- fprintf(f, "\n ");
- s += 2;
+ fprintf(f, "\n "); /* sic (because space follows) */
count = 0;
}
- else
- {
- fputc(*s, f);
- count++;
- if (*s++ == ':' && isspace(*s) && count > 45)
- {
- fprintf(f, "\n "); /* sic (because space follows) */
- count = 0;
- }
- }
}
}
}
+
+
+
/*************************************************
* Check list of addresses for duplication *
*************************************************/
case RECIP_FAIL_FILTER:
new->message =
(filter_message == NULL)? US"delivery cancelled" : filter_message;
+ setflag(new, af_pass_message);
goto RECIP_QUEUE_FAILED; /* below */
/* 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
- post_process_one() for the existence of data in the message file.) */
+ post_process_one() for the existence of data in the message file.) A TRUE
+ return from print_address_information() means that the address is not
+ hidden. */
paddr = &msgchain;
for (addr = msgchain; addr != NULL; addr = *paddr)
{
if (print_address_information(addr, f, US" ", US"\n ", US""))
- {
- /* A TRUE return from print_address_information() means that the
- address is not hidden. If there is a return file, it has already
- been checked to ensure it is not empty. Omit the bland "return
- message generated" error, but otherwise include error information. */
-
- if (addr->return_file < 0 ||
- addr->message == NULL ||
- Ustrcmp(addr->message, "return message generated") != 0)
- {
- fprintf(f, "\n ");
- print_address_error(addr, f);
- }
- }
+ print_address_error(addr, f, US"");
/* End the final line for the address */
(addr_defer->next == NULL)? "is": "are");
}
- /* List the addresses. For any that are hidden, don't give the delay
- reason, because it might expose that which is hidden. Also, do not give
- "retry time not reached" because that isn't helpful. */
+ /* List the addresses, with error information if allowed */
fprintf(f, "\n");
while (addr_defer != NULL)
{
address_item *addr = addr_defer;
addr_defer = addr->next;
- if (print_address_information(addr, f, US" ", US"\n ", US"") &&
- addr->basic_errno > ERRNO_RETRY_BASE)
- {
- fprintf(f, "\n Delay reason: ");
- print_address_error(addr, f);
- }
+ if (print_address_information(addr, f, US" ", US"\n ", US""))
+ print_address_error(addr, f, US"Delay reason: ");
fprintf(f, "\n");
}
fprintf(f, "\n");
-/* $Cambridge: exim/src/src/transports/smtp.c,v 1.10 2005/04/07 10:54:54 ph10 Exp $ */
+/* $Cambridge: exim/src/src/transports/smtp.c,v 1.11 2005/04/28 13:06:32 ph10 Exp $ */
/*************************************************
* Exim - an Internet mail transport agent *
status means that an address is not currently being processed.
Arguments:
- addrlist points to a chain of addresses
- errno_value to put in each address's errno field
- msg to put in each address's message field
- rc to put in each address's transport_return field
+ addrlist points to a chain of addresses
+ errno_value to put in each address's errno field
+ msg to put in each address's message field
+ rc to put in each address's transport_return field
+ pass_message if TRUE, set the "pass message" flag in the address
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
*/
static
-void set_errno(address_item *addrlist, int errno_value, uschar *msg, int rc)
+void set_errno(address_item *addrlist, int errno_value, uschar *msg, int rc,
+ BOOL pass_message)
{
address_item *addr;
int orvalue = 0;
if (addr->transport_return < PENDING) continue;
addr->basic_errno = errno_value;
addr->more_errno |= orvalue;
- if (msg != NULL) addr->message = msg;
+ if (msg != NULL)
+ {
+ addr->message = msg;
+ if (pass_message) setflag(addr, af_pass_message);
+ }
addr->transport_return = rc;
}
}
chosen.
Arguments:
- host the current host, to get its name for messages
- errno_value pointer to the errno value
- more_errno from the top address for use with ERRNO_FILTER_FAIL
- buffer the SMTP response buffer
- yield where to put a one-digit SMTP response code
- message where to put an errror message
-
-Returns: TRUE if an SMTP "QUIT" command should be sent, else FALSE
+ host the current host, to get its name for messages
+ errno_value pointer to the errno value
+ more_errno from the top address for use with ERRNO_FILTER_FAIL
+ buffer the SMTP response buffer
+ yield where to put a one-digit SMTP response code
+ message where to put an errror message
+ pass_message set TRUE if message is an SMTP response
+
+Returns: TRUE if an SMTP "QUIT" command should be sent, else FALSE
*/
static BOOL check_response(host_item *host, int *errno_value, int more_errno,
- uschar *buffer, int *yield, uschar **message)
+ uschar *buffer, int *yield, uschar **message, BOOL *pass_message)
{
uschar *pl = US"";
if (buffer[0] != 0)
{
uschar *s = string_printing(buffer);
- *message = US string_sprintf("SMTP error from remote mailer after %s%s: "
+ *message = US string_sprintf("SMTP error from remote mail server after %s%s: "
"host %s [%s]: %s", pl, smtp_command, host->name, host->address, s);
+ *pass_message = TRUE;
*yield = buffer[0];
return TRUE;
}
uschar *message = string_sprintf("SMTP timeout while connected to %s [%s] "
"after RCPT TO:<%s>", host->name, host->address,
transport_rcpt_address(addr, include_affixes));
- set_errno(addrlist, save_errno, message, DEFER);
+ set_errno(addrlist, save_errno, message, DEFER, FALSE);
retry_add_item(addr, addr->address_retry_key, 0);
host->update_waiting = FALSE;
return -1;
else
{
addr->message =
- string_sprintf("SMTP error from remote mailer after RCPT TO:<%s>: "
+ string_sprintf("SMTP error from remote mail server after RCPT TO:<%s>: "
"host %s [%s]: %s", transport_rcpt_address(addr, include_affixes),
host->name, host->address, string_printing(buffer));
+ setflag(addr, af_pass_message);
deliver_msglog("%s %s\n", tod_stamp(tod_log), addr->message);
/* The response was 5xx */
{
int code;
uschar *msg;
+ BOOL pass_message;
if (pending_DATA > 0 || (yield & 1) != 0) return -3;
- (void)check_response(host, &errno, 0, buffer, &code, &msg);
+ (void)check_response(host, &errno, 0, buffer, &code, &msg, &pass_message);
DEBUG(D_transport) debug_printf("%s\nerror for DATA ignored: pipelining "
"is in use and there were no good recipients\n", msg);
}
BOOL completed_address = FALSE;
BOOL esmtp = TRUE;
BOOL pending_MAIL;
+BOOL pass_message = FALSE;
smtp_inblock inblock;
smtp_outblock outblock;
int max_rcpt = tblock->max_addresses;
{
uschar *message = string_sprintf("failed to expand helo_data: %s",
expand_string_message);
- set_errno(addrlist, 0, message, DEFER);
+ set_errno(addrlist, 0, message, DEFER, FALSE);
return ERROR;
}
{
uschar *message = string_sprintf("failed to expand "
"authenticated_sender: %s", expand_string_message);
- set_errno(addrlist, 0, message, DEFER);
+ set_errno(addrlist, 0, message, DEFER, FALSE);
return ERROR;
}
}
if (inblock.sock < 0)
{
set_errno(addrlist, (errno == ETIMEDOUT)? ERRNO_CONNECTTIMEOUT : errno,
- NULL, DEFER);
+ NULL, DEFER, FALSE);
return DEFER;
}
case ERROR:
yield = ERROR;
- set_errno(addrlist, 0, string_copy(buffer), DEFER);
+ set_errno(addrlist, 0, string_copy(buffer), DEFER, FALSE);
goto SEND_QUIT;
}
{
yield = DEFER;
set_errno(addrlist, ERRNO_AUTHFAIL,
- string_sprintf("authentication required but %s", fail_reason), DEFER);
+ string_sprintf("authentication required but %s", fail_reason), DEFER,
+ FALSE);
goto SEND_QUIT;
}
}
if (!rc)
{
- set_errno(addrlist->next, addrlist->basic_errno, addrlist->message, DEFER);
+ set_errno(addrlist->next, addrlist->basic_errno, addrlist->message, DEFER,
+ FALSE);
yield = ERROR;
goto SEND_QUIT;
}
}
if (badaddr != NULL)
{
- set_errno(addrlist, 0, badaddr->message, FAIL);
+ set_errno(addrlist, 0, badaddr->message, FAIL,
+ testflag(badaddr, af_pass_message));
ok = FALSE;
}
}
save_errno = errno;
message = NULL;
send_quit = check_response(host, &save_errno, addrlist->more_errno,
- buffer, &code, &message);
+ buffer, &code, &message, &pass_message);
goto FAILED;
SEND_FAILED:
{
if (code == '5')
{
- set_errno(addrlist, save_errno, message, FAIL);
+ set_errno(addrlist, save_errno, message, FAIL, pass_message);
}
else
{
- set_errno(addrlist, save_errno, message, DEFER);
+ set_errno(addrlist, save_errno, message, DEFER, pass_message);
yield = DEFER;
}
}
{
yield = (save_errno == ERRNO_CHHEADER_FAIL ||
save_errno == ERRNO_FILTER_FAIL)? ERROR : DEFER;
- set_errno(addrlist, save_errno, message, DEFER);
+ set_errno(addrlist, save_errno, message, DEFER, pass_message);
}
/* Otherwise we have a message-specific error response from the remote
{
if (mua_wrapper) code = '5'; /* Force hard failure in wrapper mode */
- set_errno(addrlist, save_errno, message, (code == '5')? FAIL : DEFER);
+ set_errno(addrlist, save_errno, message, (code == '5')? FAIL : DEFER,
+ pass_message);
/* If there's an errno, the message contains just the identity of
the host. */
))
{
uschar *msg;
+ BOOL pass_message;
if (send_rset)
{
ob->command_timeout)))
{
int code;
- send_quit = check_response(host, &errno, 0, buffer, &code, &msg);
+ send_quit = check_response(host, &errno, 0, buffer, &code, &msg,
+ &pass_message);
if (!send_quit)
{
DEBUG(D_transport) debug_printf("%s\n", msg);
/* If RSET failed and there are addresses left, they get deferred. */
- else set_errno(first_addr, errno, msg, DEFER);
+ else set_errno(first_addr, errno, msg, DEFER, FALSE);
}
}
if (dont_deliver)
{
host_item *host2;
- set_errno(addrlist, 0, NULL, OK);
+ set_errno(addrlist, 0, NULL, OK, FALSE);
for (addr = addrlist; addr != NULL; addr = addr->next)
{
addr->host_used = host;