-/* $Cambridge: exim/src/src/receive.c,v 1.5 2004/11/25 13:54:31 ph10 Exp $ */
+/* $Cambridge: exim/src/src/receive.c,v 1.18 2005/05/23 15:28:38 fanf2 Exp $ */
/*************************************************
* Exim - an Internet mail transport agent *
*************************************************/
-/* Copyright (c) University of Cambridge 1995 - 2004 */
+/* Copyright (c) University of Cambridge 1995 - 2005 */
/* See the file NOTICE for conditions of use and distribution. */
/* Code for receiving a message and setting up spool files. */
-
#include "exim.h"
-
+#ifdef EXPERIMENTAL_DOMAINKEYS
+#define RECEIVE_GETC dk_receive_getc
+#define RECEIVE_UNGETC dk_receive_ungetc
+#else
+#define RECEIVE_GETC receive_getc
+#define RECEIVE_UNGETC receive_ungetc
+#endif
/*************************************************
* Local static variables *
* Read space info for a partition *
*************************************************/
-/* This function is called by receive_check_fs() below, and also by string
-expansion for variables such as $spool_space. The field names for the statvfs
+/* This function is called by receive_check_fs() below, and also by string
+expansion for variables such as $spool_space. The field names for the statvfs
structure are macros, because not all OS have F_FAVAIL and it seems tidier to
have macros for F_BAVAIL and F_FILES as well. Some kinds of file system do not
have inodes, and they return -1 for the number available.
Later: It turns out that some file systems that do not have the concept of
inodes return 0 rather than -1. Such systems should also return 0 for the total
-number of inodes, so we require that to be greater than zero before returning
+number of inodes, so we require that to be greater than zero before returning
an inode count.
Arguments:
isspool TRUE for spool partition, FALSE for log partition
inodeptr address of int to receive inode count; -1 if there isn't one
-
+
Returns: available on-root space, in kilobytes
- -1 for log partition if there isn't one
-
-All values are -1 if the STATFS functions are not available.
+ -1 for log partition if there isn't one
+
+All values are -1 if the STATFS functions are not available.
*/
-int
+int
receive_statvfs(BOOL isspool, int *inodeptr)
{
#ifdef HAVE_STATFS
if (isspool)
{
- path = spool_directory;
- name = US"spool";
- }
-
+ path = spool_directory;
+ name = US"spool";
+ }
+
/* Need to cut down the log file path to the directory, and to ignore any
appearance of "syslog" in it. */
{
int sep = ':'; /* Not variable - outside scripts use */
uschar *p = log_file_path;
- name = US"log";
+ name = US"log";
/* An empty log_file_path means "use the default". This is the same as an
empty item in a list. */
if (path == NULL) /* No log files */
{
- *inodeptr = -1;
- return -1;
- }
+ *inodeptr = -1;
+ return -1;
+ }
- /* An empty string means use the default, which is in the spool directory.
- But don't just use the spool directory, as it is possible that the log
+ /* An empty string means use the default, which is in the spool directory.
+ But don't just use the spool directory, as it is possible that the log
subdirectory has been symbolically linked elsewhere. */
- if (path[0] == 0)
+ if (path[0] == 0)
{
sprintf(CS buffer, CS"%s/log", CS spool_directory);
path = buffer;
- }
- else
+ }
+ else
{
- uschar *cp;
+ uschar *cp;
if ((cp = Ustrrchr(path, '/')) != NULL) *cp = 0;
- }
+ }
}
-
+
/* We now have the patch; do the business */
memset(&statbuf, 0, sizeof(statbuf));
smtp_closedown(US"spool or log directory problem");
exim_exit(EXIT_FAILURE);
}
-
+
*inodeptr = (statbuf.F_FILES > 0)? statbuf.F_FAVAIL : -1;
/* Disks are getting huge. Take care with computing the size in kilobytes. */
-
+
return (int)(((double)statbuf.F_BAVAIL * (double)statbuf.F_FRSIZE)/1024.0);
/* Unable to find partition sizes in this environment. */
if (check_spool_space > 0 || msg_size > 0 || check_spool_inodes > 0)
{
- space = receive_statvfs(TRUE, &inodes);
-
+ space = receive_statvfs(TRUE, &inodes);
+
DEBUG(D_receive)
debug_printf("spool directory space = %dK inodes = %d "
"check_space = %dK inodes = %d msg_size = %d\n",
space, inodes, check_spool_space, check_spool_inodes, msg_size);
-
- if ((space >= 0 && space < check_spool_space) ||
+
+ if ((space >= 0 && space < check_spool_space) ||
(inodes >= 0 && inodes < check_spool_inodes))
- {
+ {
log_write(0, LOG_MAIN, "spool directory space check failed: space=%d "
"inodes=%d", space, inodes);
return FALSE;
if (check_log_space > 0 || check_log_inodes > 0)
{
- space = receive_statvfs(FALSE, &inodes);
-
+ space = receive_statvfs(FALSE, &inodes);
+
DEBUG(D_receive)
debug_printf("log directory space = %dK inodes = %d "
"check_space = %dK inodes = %d\n",
space, inodes, check_log_space, check_log_inodes);
-
- if ((space >= 0 && space < check_log_space) ||
+
+ if ((space >= 0 && space < check_log_space) ||
(inodes >= 0 && inodes < check_log_inodes))
- {
+ {
log_write(0, LOG_MAIN, "log directory space check failed: space=%d "
"inodes=%d", space, inodes);
return FALSE;
}
- }
-
+ }
+
return TRUE;
}
msg = US"SMTP incoming data timeout";
log_write(L_lost_incoming_connection,
LOG_MAIN, "SMTP data timeout (message abandoned) on connection "
- "from %s",
- (sender_fullhost != NULL)? sender_fullhost : US"local process");
+ "from %s F=<%s>",
+ (sender_fullhost != NULL)? sender_fullhost : US"local process",
+ sender_address);
}
else
{
recipients_list[recipients_count].address = recipient;
recipients_list[recipients_count].pno = pno;
+#ifdef EXPERIMENTAL_BRIGHTMAIL
+recipients_list[recipients_count].bmi_optin = bmi_current_optin;
+/* reset optin string pointer for next recipient */
+bmi_current_optin = NULL;
+#endif
recipients_list[recipients_count++].errors_to = NULL;
}
{
if ((--recipients_count - count) > 0)
memmove(recipients_list + count, recipients_list + count + 1,
- (recipients_count - count)*sizeof(recipient_item));
+ (recipients_count - count)*sizeof(recipient_item));
return TRUE;
}
}
{
register int last_ch = '\n';
- for (; (ch = (receive_getc)()) != EOF; last_ch = ch)
+ for (; (ch = (RECEIVE_GETC)()) != EOF; last_ch = ch)
{
if (ch == 0) body_zerocount++;
if (last_ch == '\r' && ch != '\n')
ch_state = 1;
-while ((ch = (receive_getc)()) != EOF)
+while ((ch = (RECEIVE_GETC)()) != EOF)
{
if (ch == 0) body_zerocount++;
switch (ch_state)
int ch_state = 0;
register int ch;
-while ((ch = (receive_getc)()) != EOF)
+while ((ch = (RECEIVE_GETC)()) != EOF)
{
if (ch == 0) body_zerocount++;
switch (ch_state)
DEBUG(D_receive|D_acl) debug_printf(" (after Received:)");
break;
+ case htype_add_rfc:
+ /* add header before any header which is NOT Received: or Resent- */
+ last_received = header_list;
+ while ( (last_received->next != NULL) &&
+ ( (header_testname(last_received->next, US"Received", 8, FALSE)) ||
+ (header_testname_incomplete(last_received->next, US"Resent-", 7, FALSE)) ) )
+ last_received = last_received->next;
+ /* last_received now points to the last Received: or Resent-* header
+ in an uninterrupted chain of those header types (seen from the beginning
+ of all headers. Our current header must follow it. */
+ h->next = last_received->next;
+ last_received->next = h;
+ DEBUG(D_receive|D_acl) debug_printf(" (before any non-Received: or Resent-*: header)");
+ break;
+
default:
h->next = NULL;
header_last->next = h;
+#ifdef WITH_CONTENT_SCAN
+
+/*************************************************
+* Run the MIME ACL on a message *
+*************************************************/
+
+/* This code is in a subroutine so that it can be used for both SMTP
+and non-SMTP messages. It is called with a non-NULL ACL pointer.
+
+Arguments:
+ acl The ACL to run (acl_smtp_mime or acl_not_smtp_mime)
+ smtp_yield_ptr Set FALSE to kill messages after dropped connection
+ smtp_reply_ptr Where SMTP reply is being built
+ blackholed_by_ptr Where "blackholed by" message is being built
+
+Returns: TRUE to carry on; FALSE to abandon the message
+*/
+
+static BOOL
+run_mime_acl(uschar *acl, BOOL *smtp_yield_ptr, uschar **smtp_reply_ptr,
+ uschar **blackholed_by_ptr)
+{
+FILE *mbox_file;
+uschar rfc822_file_path[2048];
+unsigned long mbox_size;
+header_line *my_headerlist;
+uschar *user_msg, *log_msg;
+int mime_part_count_buffer = -1;
+int rc;
+
+memset(CS rfc822_file_path,0,2048);
+
+/* check if it is a MIME message */
+my_headerlist = header_list;
+while (my_headerlist != NULL) {
+ /* skip deleted headers */
+ if (my_headerlist->type == '*') {
+ my_headerlist = my_headerlist->next;
+ continue;
+ };
+ if (strncmpic(my_headerlist->text, US"Content-Type:", 13) == 0) {
+ DEBUG(D_receive) debug_printf("Found Content-Type: header - executing acl_smtp_mime.\n");
+ goto DO_MIME_ACL;
+ };
+ my_headerlist = my_headerlist->next;
+};
+
+DEBUG(D_receive) debug_printf("No Content-Type: header - presumably not a MIME message.\n");
+return TRUE;
+
+DO_MIME_ACL:
+/* make sure the eml mbox file is spooled up */
+mbox_file = spool_mbox(&mbox_size);
+if (mbox_file == NULL) {
+ /* error while spooling */
+ log_write(0, LOG_MAIN|LOG_PANIC,
+ "acl_smtp_mime: error while creating mbox spool file, message temporarily rejected.");
+ Uunlink(spool_name);
+ unspool_mbox();
+ smtp_respond(451, TRUE, US"temporary local problem");
+ message_id[0] = 0; /* Indicate no message accepted */
+ *smtp_reply_ptr = US""; /* Indicate reply already sent */
+ return FALSE; /* Indicate skip to end of receive function */
+};
+
+mime_is_rfc822 = 0;
+
+MIME_ACL_CHECK:
+mime_part_count = -1;
+rc = mime_acl_check(acl, mbox_file, NULL, &user_msg, &log_msg);
+fclose(mbox_file);
+
+if (Ustrlen(rfc822_file_path) > 0) {
+ mime_part_count = mime_part_count_buffer;
+
+ if (unlink(CS rfc822_file_path) == -1) {
+ log_write(0, LOG_PANIC,
+ "acl_smtp_mime: can't unlink RFC822 spool file, skipping.");
+ goto END_MIME_ACL;
+ };
+};
+
+/* check if we must check any message/rfc822 attachments */
+if (rc == OK) {
+ uschar temp_path[1024];
+ int n;
+ struct dirent *entry;
+ DIR *tempdir;
+
+ snprintf(CS temp_path, 1024, "%s/scan/%s", spool_directory, message_id);
+
+ tempdir = opendir(CS temp_path);
+ n = 0;
+ do {
+ entry = readdir(tempdir);
+ if (entry == NULL) break;
+ if (strncmpic(US entry->d_name,US"__rfc822_",9) == 0) {
+ snprintf(CS rfc822_file_path, 2048,"%s/scan/%s/%s", spool_directory, message_id, entry->d_name);
+ debug_printf("RFC822 attachment detected: running MIME ACL for '%s'\n", rfc822_file_path);
+ break;
+ };
+ } while (1);
+ closedir(tempdir);
+
+ if (entry != NULL) {
+ mbox_file = Ufopen(rfc822_file_path,"r");
+ if (mbox_file == NULL) {
+ log_write(0, LOG_PANIC,
+ "acl_smtp_mime: can't open RFC822 spool file, skipping.");
+ unlink(CS rfc822_file_path);
+ goto END_MIME_ACL;
+ };
+ /* set RFC822 expansion variable */
+ mime_is_rfc822 = 1;
+ mime_part_count_buffer = mime_part_count;
+ goto MIME_ACL_CHECK;
+ };
+};
+
+END_MIME_ACL:
+add_acl_headers(US"MIME");
+if (rc == DISCARD)
+ {
+ recipients_count = 0;
+ *blackholed_by_ptr = US"MIME ACL";
+ }
+else if (rc != OK)
+ {
+ Uunlink(spool_name);
+ unspool_mbox();
+ if (smtp_handle_acl_fail(ACL_WHERE_MIME, rc, user_msg, log_msg) != 0)
+ *smtp_yield_ptr = FALSE; /* No more messsages after dropped connection */
+ *smtp_reply_ptr = US""; /* Indicate reply already sent */
+ message_id[0] = 0; /* Indicate no message accepted */
+ return FALSE; /* Cause skip to end of receive function */
+ };
+
+return TRUE;
+}
+
+#endif /* WITH_CONTENT_SCAN */
+
/*************************************************
* Receive message *
BOOL resents_exist = FALSE;
uschar *resent_prefix = US"";
uschar *blackholed_by = NULL;
+uschar *blackhole_log_msg = US"";
flock_t lock_data;
error_block *bad_addresses = NULL;
if (thismessage_size_limit <= 0) thismessage_size_limit = INT_MAX;
-/* While reading the message, body_linecount and body_zerocount is computed.
-The full message_ linecount is set up only when the headers are read back in
-from the spool for delivery. */
+/* While reading the message, the following counts are computed. */
+
+message_linecount = body_linecount = body_zerocount = 0;
-body_linecount = body_zerocount = 0;
+#ifdef EXPERIMENTAL_DOMAINKEYS
+/* Call into DK to set up the context. Check if DK is to be run are carried out
+ inside dk_exim_verify_init(). */
+dk_exim_verify_init();
+#endif
/* Remember the time of reception. Exim uses time+pid for uniqueness of message
ids, and fractions of a second are required. See the comments that precede the
for (;;)
{
- int ch = (receive_getc)();
+ int ch = (RECEIVE_GETC)();
/* If we hit EOF on a SMTP connection, it's an error, since incoming
SMTP must have a correct "." terminator. */
if (ch == '\n')
{
if (first_line_ended_crlf == TRUE_UNSET) first_line_ended_crlf = FALSE;
- else if (first_line_ended_crlf) receive_ungetc(' ');
+ else if (first_line_ended_crlf) RECEIVE_UNGETC(' ');
goto EOL;
}
if (ptr == 0 && ch == '.' && (smtp_input || dot_ends))
{
- ch = (receive_getc)();
+ ch = (RECEIVE_GETC)();
if (ch == '\r')
{
- ch = (receive_getc)();
+ ch = (RECEIVE_GETC)();
if (ch != '\n')
{
- receive_ungetc(ch);
+ RECEIVE_UNGETC(ch);
ch = '\r'; /* Revert to CR */
}
}
if (ch == '\r')
{
- ch = (receive_getc)();
+ ch = (RECEIVE_GETC)();
if (ch == '\n')
{
if (first_line_ended_crlf == TRUE_UNSET) first_line_ended_crlf = TRUE;
/* Otherwise, put back the character after CR, and turn the bare CR
into LF SP. */
- ch = (receive_ungetc)(ch);
+ ch = (RECEIVE_UNGETC)(ch);
next->text[ptr++] = '\n';
message_size++;
ch = ' ';
/* End of header line reached */
EOL:
- receive_linecount++; /* For BSMTP errors */
+
+ /* Keep track of lines for BSMTP errors and overall message_linecount. */
+
+ receive_linecount++;
+ message_linecount++;
/* Now put in the terminating newline. There is always space for
at least two more characters. */
if (ch != EOF)
{
- int nextch = (receive_getc)();
+ int nextch = (RECEIVE_GETC)();
if (nextch == ' ' || nextch == '\t')
{
next->text[ptr++] = nextch;
message_size++;
continue; /* Iterate the loop */
}
- else if (nextch != EOF) (receive_ungetc)(nextch); /* For next time */
+ else if (nextch != EOF) (RECEIVE_UNGETC)(nextch); /* For next time */
else ch = EOF; /* Cause main loop to exit at end */
}
if (sender_address[0] == 0)
{
+ uschar *fromstart, *fromend;
+
+ fromstart = string_sprintf("%sFrom: %s%s", resent_prefix,
+ originator_name, (originator_name[0] == 0)? "" : " <");
+ fromend = (originator_name[0] == 0)? US"" : US">";
+
if (sender_local || local_error_message)
{
- header_add(htype_from, "%sFrom: %s%s%s@%s%s\n", resent_prefix,
- originator_name,
- (originator_name[0] == 0)? "" : " <",
- local_part_quote(originator_login),
- qualify_domain_sender,
- (originator_name[0] == 0)? "" : ">");
+ header_add(htype_from, "%s%s@%s%s\n", fromstart,
+ local_part_quote(originator_login), qualify_domain_sender,
+ fromend);
}
else if (submission_mode && authenticated_id != NULL)
{
if (submission_domain == NULL)
{
- header_add(htype_from, "%sFrom: %s@%s\n", resent_prefix,
- local_part_quote(authenticated_id), qualify_domain_sender);
+ header_add(htype_from, "%s%s@%s%s\n", fromstart,
+ local_part_quote(authenticated_id), qualify_domain_sender,
+ fromend);
}
else if (submission_domain[0] == 0) /* empty => whole address set */
{
- header_add(htype_from, "%sFrom: %s\n", resent_prefix,
- authenticated_id);
+ header_add(htype_from, "%s%s%s\n", fromstart, authenticated_id,
+ fromend);
}
else
{
- header_add(htype_from, "%sFrom: %s@%s\n", resent_prefix,
- local_part_quote(authenticated_id), submission_domain);
+ header_add(htype_from, "%s%s@%s%s\n", fromstart,
+ local_part_quote(authenticated_id), submission_domain,
+ fromend);
}
from_header = header_last; /* To get it checked for Sender: */
}
else
{
- if (!smtp_input || sender_local)
- header_add(htype_from, "%sFrom: %s%s%s%s\n",
- resent_prefix, originator_name,
- (originator_name[0] == 0)? "" : " <",
- (sender_address_unrewritten == NULL)?
- sender_address : sender_address_unrewritten,
- (originator_name[0] == 0)? "" : ">");
- else
- header_add(htype_from, "%sFrom: %s\n", resent_prefix, sender_address);
+ header_add(htype_from, "%sFrom: %s%s%s%s\n", resent_prefix,
+ originator_name,
+ (originator_name[0] == 0)? "" : " <",
+ (sender_address_unrewritten == NULL)?
+ sender_address : sender_address_unrewritten,
+ (originator_name[0] == 0)? "" : ">");
from_header = header_last; /* To get it checked for Sender: */
}
if (make_sender)
{
- if (submission_mode)
+ if (submission_mode && originator_name[0] == 0)
header_add(htype_sender, "%sSender: %s\n", resent_prefix,
generated_sender_address);
else
header_add(htype_sender, "%sSender: %s <%s>\n",
resent_prefix, originator_name, generated_sender_address);
}
+
+ /* Ensure that a non-null envelope sender address corresponds to the
+ submission mode sender address. */
+
+ if (submission_mode && sender_address[0] != 0)
+ {
+ if (sender_address_unrewritten == NULL)
+ sender_address_unrewritten = sender_address;
+ sender_address = generated_sender_address;
+ log_write(L_address_rewrite, LOG_MAIN,
+ "\"%s\" from env-from rewritten as \"%s\" by submission mode",
+ sender_address_unrewritten, generated_sender_address);
+ }
}
else message_ended = read_message_data(data_file);
receive_linecount += body_linecount; /* For BSMTP errors mainly */
+ message_linecount += body_linecount;
/* Handle premature termination of SMTP */
if (smtp_input && !smtp_batched_input)
{
+
+#ifdef EXPERIMENTAL_DOMAINKEYS
+ dk_exim_verify_finish();
+#endif
+
+#ifdef WITH_CONTENT_SCAN
+ if (acl_smtp_mime != NULL &&
+ !run_mime_acl(acl_smtp_mime, &smtp_yield, &smtp_reply, &blackholed_by))
+ goto TIDYUP;
+#endif /* WITH_CONTENT_SCAN */
+
+ /* Check the recipients count again, as the MIME ACL might have changed
+ them. */
+
if (acl_smtp_data != NULL && recipients_count > 0)
{
uschar *user_msg, *log_msg;
{
recipients_count = 0;
blackholed_by = US"DATA ACL";
+ if (log_msg != NULL)
+ blackhole_log_msg = string_sprintf(": %s", log_msg);
}
else if (rc != OK)
{
Uunlink(spool_name);
+#ifdef WITH_CONTENT_SCAN
+ unspool_mbox();
+#endif
if (smtp_handle_acl_fail(ACL_WHERE_DATA, rc, user_msg, log_msg) != 0)
smtp_yield = FALSE; /* No more messsages after dropped connection */
smtp_reply = US""; /* Indicate reply already sent */
/* Handle non-SMTP and batch SMTP (i.e. non-interactive) messages. Note that
we cannot take different actions for permanent and temporary rejections. */
- else if (acl_not_smtp != NULL)
+ else
{
- uschar *user_msg, *log_msg;
- rc = acl_check(ACL_WHERE_NOTSMTP, NULL, acl_not_smtp, &user_msg, &log_msg);
- if (rc == DISCARD)
- {
- recipients_count = 0;
- blackholed_by = US"non-SMTP ACL";
- }
- else if (rc != OK)
+
+#ifdef WITH_CONTENT_SCAN
+ if (acl_not_smtp_mime != NULL &&
+ !run_mime_acl(acl_not_smtp_mime, &smtp_yield, &smtp_reply,
+ &blackholed_by))
+ goto TIDYUP;
+#endif /* WITH_CONTENT_SCAN */
+
+ if (acl_not_smtp != NULL)
{
- Uunlink(spool_name);
- log_write(0, LOG_MAIN|LOG_REJECT, "F=<%s> rejected by non-SMTP ACL: %s",
- sender_address, log_msg);
- if (user_msg == NULL) user_msg = US"local configuration problem";
- if (smtp_batched_input)
+ uschar *user_msg, *log_msg;
+ rc = acl_check(ACL_WHERE_NOTSMTP, NULL, acl_not_smtp, &user_msg, &log_msg);
+ if (rc == DISCARD)
{
- moan_smtp_batch(NULL, "%d %s", 550, user_msg);
- /* Does not return */
+ recipients_count = 0;
+ blackholed_by = US"non-SMTP ACL";
+ if (log_msg != NULL)
+ blackhole_log_msg = string_sprintf(": %s", log_msg);
}
- else
+ else if (rc != OK)
{
- fseek(data_file, (long int)SPOOL_DATA_START_OFFSET, SEEK_SET);
- give_local_error(ERRMESS_LOCAL_ACL, user_msg,
- US"message rejected by non-SMTP ACL: ", error_rc, data_file,
- header_list);
- /* Does not return */
+ Uunlink(spool_name);
+#ifdef WITH_CONTENT_SCAN
+ unspool_mbox();
+#endif
+ log_write(0, LOG_MAIN|LOG_REJECT, "F=<%s> rejected by non-SMTP ACL: %s",
+ sender_address, log_msg);
+ if (user_msg == NULL) user_msg = US"local configuration problem";
+ if (smtp_batched_input)
+ {
+ moan_smtp_batch(NULL, "%d %s", 550, user_msg);
+ /* Does not return */
+ }
+ else
+ {
+ fseek(data_file, (long int)SPOOL_DATA_START_OFFSET, SEEK_SET);
+ give_local_error(ERRMESS_LOCAL_ACL, user_msg,
+ US"message rejected by non-SMTP ACL: ", error_rc, data_file,
+ header_list);
+ /* Does not return */
+ }
}
+ add_acl_headers(US"non-SMTP");
}
- add_acl_headers(US"non-SMTP");
}
+ /* The applicable ACLs have been run */
+
if (deliver_freeze) frozen_by = US"ACL"; /* for later logging */
if (queue_only_policy) queued_by = US"ACL";
enable_dollar_recipients = FALSE;
}
+#ifdef WITH_CONTENT_SCAN
+unspool_mbox();
+#endif
+
/* The final check on the message is to run the scan_local() function. The
version supplied with Exim always accepts, but this is a hook for sysadmins to
supply their own checking code. The local_scan() function is run even when all
deliver_firsttime = TRUE;
+#ifdef EXPERIMENTAL_BRIGHTMAIL
+if (bmi_run == 1) {
+ /* rewind data file */
+ lseek(data_fd, (long int)SPOOL_DATA_START_OFFSET, SEEK_SET);
+ bmi_verdicts = bmi_process_message(header_list, data_fd);
+};
+#endif
+
/* Update the timstamp in our Received: header to account for any time taken by
an ACL or by local_scan(). The new time is the time that all reception
processing is complete. */
{
if (smtp_reply == NULL)
{
- smtp_printf("250 OK id=%s\r\n", message_id);
+ if (fake_response != OK)
+ smtp_respond(fake_response == DEFER ? 450 : 550,
+ TRUE, fake_response_text);
+ else
+ smtp_printf("250 OK id=%s\r\n", message_id);
if (host_checking)
fprintf(stdout,
"\n**** SMTP testing: that is not a real message id!\n\n");
}
- else if (smtp_reply[0] != 0) smtp_printf("%.1024s\r\n", smtp_reply);
+ else if (smtp_reply[0] != 0)
+ {
+ if (fake_response != OK && (smtp_reply[0] == '2'))
+ smtp_respond(fake_response == DEFER ? 450 : 550,
+ TRUE, fake_response_text);
+ else
+ smtp_printf("%.1024s\r\n", smtp_reply);
+ }
}
/* For batched SMTP, generate an error message on failure, and do
uschar *detail = (local_scan_data != NULL)?
string_printing(local_scan_data) :
string_sprintf("(%s discarded recipients)", blackholed_by);
- log_write(0, LOG_MAIN, "=> blackhole %s", detail);
+ log_write(0, LOG_MAIN, "=> blackhole %s%s", detail, blackhole_log_msg);
log_write(0, LOG_MAIN, "Completed");
message_id[0] = 0;
}