build: use pkg-config for i18n
[exim.git] / src / src / receive.c
index ae70450681baf3b33e5e6906eb3b0366537834fb..ae4e1ff7ef50cba54ea50f5f2946eb0154982b4a 100644 (file)
@@ -17,7 +17,7 @@ extern int dcc_ok;
 #endif
 
 #ifdef SUPPORT_DMARC
 #endif
 
 #ifdef SUPPORT_DMARC
-# include "dmarc.h"
+# include "miscmods/dmarc.h"
 #endif
 
 /*************************************************
 #endif
 
 /*************************************************
@@ -290,12 +290,11 @@ Returns:       FALSE if there isn't enough space, or if the information cannot
 BOOL
 receive_check_fs(int msg_size)
 {
 BOOL
 receive_check_fs(int msg_size)
 {
-int_eximarith_t space;
 int inodes;
 
 if (check_spool_space > 0 || msg_size > 0 || check_spool_inodes > 0)
   {
 int inodes;
 
 if (check_spool_space > 0 || msg_size > 0 || check_spool_inodes > 0)
   {
-  space = receive_statvfs(TRUE, &inodes);
+  int_eximarith_t space = receive_statvfs(TRUE, &inodes);
 
   DEBUG(D_receive)
     debug_printf("spool directory space = " PR_EXIM_ARITH "K inodes = %d "
 
   DEBUG(D_receive)
     debug_printf("spool directory space = " PR_EXIM_ARITH "K inodes = %d "
@@ -313,7 +312,7 @@ if (check_spool_space > 0 || msg_size > 0 || check_spool_inodes > 0)
 
 if (check_log_space > 0 || check_log_inodes > 0)
   {
 
 if (check_log_space > 0 || check_log_inodes > 0)
   {
-  space = receive_statvfs(FALSE, &inodes);
+  int_eximarith_t space = receive_statvfs(FALSE, &inodes);
 
   DEBUG(D_receive)
     debug_printf("log directory space = " PR_EXIM_ARITH "K inodes = %d "
 
   DEBUG(D_receive)
     debug_printf("log directory space = " PR_EXIM_ARITH "K inodes = %d "
@@ -1204,6 +1203,8 @@ static void
 give_local_error(int errcode, uschar *text1, uschar *text2, int error_rc,
   FILE *f, header_line *hptr)
 {
 give_local_error(int errcode, uschar *text1, uschar *text2, int error_rc,
   FILE *f, header_line *hptr)
 {
+DEBUG(D_all) debug_printf("%s%s\n", text2, text1);
+
 if (error_handling == ERRORS_SENDER)
   {
   error_block eblock;
 if (error_handling == ERRORS_SENDER)
   {
   error_block eblock;
@@ -1394,7 +1395,7 @@ if (f.tcp_in_fastopen && !f.tcp_in_fastopen_logged)
 if (sender_ident)
   g = string_append(g, 2, US" U=", sender_ident);
 if (LOGGING(connection_id))
 if (sender_ident)
   g = string_append(g, 2, US" U=", sender_ident);
 if (LOGGING(connection_id))
-  g = string_fmt_append(g, " Ci=%lu", connection_id);
+  g = string_fmt_append(g, " Ci=%s", connection_id);
 if (received_protocol)
   g = string_append(g, 2, US" P=", received_protocol);
 if (LOGGING(pipelining) && f.smtp_in_pipelining_advertised)
 if (received_protocol)
   g = string_append(g, 2, US" P=", received_protocol);
 if (LOGGING(pipelining) && f.smtp_in_pipelining_advertised)
@@ -1572,6 +1573,7 @@ uschar * timestamp = expand_string(US"${tod_full}");
 header_line * received_header= header_list;
 
 if (recipients_count == 1) received_for = recipients_list[0].address;
 header_line * received_header= header_list;
 
 if (recipients_count == 1) received_for = recipients_list[0].address;
+GET_OPTION("received_header_text");
 received = expand_string(received_header_text);
 received_for = NULL;
 
 received = expand_string(received_header_text);
 received_for = NULL;
 
@@ -1746,7 +1748,7 @@ uschar *user_msg, *log_msg;
 /* Working header pointers */
 
 rmark reset_point;
 /* Working header pointers */
 
 rmark reset_point;
-header_line *next;
+header_line * next;
 
 /* Flags for noting the existence of certain headers (only one left) */
 
 
 /* Flags for noting the existence of certain headers (only one left) */
 
@@ -1754,15 +1756,16 @@ BOOL date_header_exists = FALSE;
 
 /* Pointers to receive the addresses of headers whose contents we need. */
 
 
 /* Pointers to receive the addresses of headers whose contents we need. */
 
-header_line *from_header = NULL;
-header_line *subject_header = NULL;
-header_line *msgid_header = NULL;
-header_line *received_header;
+header_line * from_header = NULL;
+#ifdef SUPPORT_DMARC
+header_line * dmarc_from_header = NULL;
+#endif
+header_line * subject_header = NULL, * msgid_header = NULL, * received_header;
 BOOL msgid_header_newly_created = FALSE;
 
 /* Variables for use when building the Received: header. */
 
 BOOL msgid_header_newly_created = FALSE;
 
 /* Variables for use when building the Received: header. */
 
-uschar *timestamp;
+uschar * timestamp;
 int tslen;
 
 /* Time of creation of message_id */
 int tslen;
 
 /* Time of creation of message_id */
@@ -1825,16 +1828,8 @@ mime_is_rfc822         = 0;
 mime_part_count        = -1;
 #endif
 
 mime_part_count        = -1;
 #endif
 
-#ifndef DISABLE_DKIM
-/* Call into DKIM to set up the context.  In CHUNKING mode
-we clear the dot-stuffing flag */
-if (smtp_input && !smtp_batched_input && !f.dkim_disable_verify)
-  dkim_exim_verify_init(chunking_state <= CHUNKING_OFFERED);
-#endif
-
-#ifdef SUPPORT_DMARC
-if (sender_host_address) dmarc_init(); /* initialize libopendmarc */
-#endif
+if (misc_mod_msg_init() != OK)
+  goto TIDYUP;
 
 /* In SMTP sessions we may receive several messages in one connection. Before
 each subsequent one, we wait for the clock to tick at the level of message-id
 
 /* In SMTP sessions we may receive several messages in one connection. Before
 each subsequent one, we wait for the clock to tick at the level of message-id
@@ -2199,8 +2194,9 @@ OVERSIZE:
     {
     if (!f.sender_address_forced)
       {
     {
     if (!f.sender_address_forced)
       {
-      uschar *uucp_sender = expand_string(uucp_from_sender);
-      if (!uucp_sender)
+      uschar * uucp_sender;
+      GET_OPTION("uucp_from_sender");
+      if (!(uucp_sender = expand_string(uucp_from_sender)))
         log_write(0, LOG_MAIN|LOG_PANIC,
           "expansion of \"%s\" failed after matching "
           "\"From \" line: %s", uucp_from_sender, expand_string_message);
         log_write(0, LOG_MAIN|LOG_PANIC,
           "expansion of \"%s\" failed after matching "
           "\"From \" line: %s", uucp_from_sender, expand_string_message);
@@ -2248,8 +2244,7 @@ OVERSIZE:
 
     if (isspace(*p)) break;
     while (mac_isgraph(*p) && *p != ':') p++;
 
     if (isspace(*p)) break;
     while (mac_isgraph(*p) && *p != ':') p++;
-    while (isspace(*p)) p++;
-    if (*p != ':')
+    if (Uskip_whitespace(&p) != ':')
       {
       body_zerocount = had_zero;
       break;
       {
       body_zerocount = had_zero;
       break;
@@ -2444,19 +2439,23 @@ for (header_line * h = header_list->next; h; h = h->next)
 
     case htype_from:
       h->type = htype_from;
 
     case htype_from:
       h->type = htype_from;
+#ifdef SUPPORT_DMARC
+      if (!is_resent) dmarc_from_header = h;
+#endif
       if (!resents_exist || is_resent)
        {
        from_header = h;
        if (!smtp_input)
          {
          int len;
       if (!resents_exist || is_resent)
        {
        from_header = h;
        if (!smtp_input)
          {
          int len;
-         uschar *s = Ustrchr(h->text, ':') + 1;
-         while (isspace(*s)) s++;
+         uschar * s = Ustrchr(h->text, ':') + 1;
+
+         Uskip_whitespace(&s);
          len = h->slen - (s - h->text) - 1;
          if (Ustrlen(originator_login) == len &&
              strncmpic(s, originator_login, len) == 0)
            {
          len = h->slen - (s - h->text) - 1;
          if (Ustrlen(originator_login) == len &&
              strncmpic(s, originator_login, len) == 0)
            {
-           uschar *name = is_resent? US"Resent-From" : US"From";
+           uschar * name = is_resent ? US"Resent-From" : US"From";
            header_add(htype_from, "%s: %s <%s@%s>\n", name, originator_name,
              originator_login, qualify_domain_sender);
            from_header = header_last;
            header_add(htype_from, "%s: %s <%s@%s>\n", name, originator_name,
              originator_login, qualify_domain_sender);
            from_header = header_last;
@@ -2511,15 +2510,13 @@ for (header_line * h = header_list->next; h; h = h->next)
 
       if (filter_test != FTEST_NONE)
        {
 
       if (filter_test != FTEST_NONE)
        {
-       uschar *start = h->text + 12;
-       uschar *end = start + Ustrlen(start);
-       while (isspace(*start)) start++;
+       uschar * start = h->text + 12;
+       uschar * end = start + Ustrlen(start);
+
+       Uskip_whitespace(&start);
        while (end > start && isspace(end[-1])) end--;
        if (*start == '<' && end[-1] == '>')
        while (end > start && isspace(end[-1])) end--;
        if (*start == '<' && end[-1] == '>')
-         {
-         start++;
-         end--;
-         }
+         { start++; end--; }
        return_path = string_copyn(start, end - start);
        printf("Return-path taken from \"Return-path:\" header line\n");
        }
        return_path = string_copyn(start, end - start);
        printf("Return-path taken from \"Return-path:\" header line\n");
        }
@@ -2622,12 +2619,12 @@ if (extract_recip)
     if ((h->type == htype_to || h->type == htype_cc || h->type == htype_bcc) &&
         (!contains_resent_headers || strncmpic(h->text, US"resent-", 7) == 0))
       {
     if ((h->type == htype_to || h->type == htype_cc || h->type == htype_bcc) &&
         (!contains_resent_headers || strncmpic(h->text, US"resent-", 7) == 0))
       {
-      uschar *s = Ustrchr(h->text, ':') + 1;
-      while (isspace(*s)) s++;
+      uschar * s = Ustrchr(h->text, ':') + 1;
+      Uskip_whitespace(&s);
 
       f.parse_allow_group = TRUE;          /* Allow address group syntax */
 
 
       f.parse_allow_group = TRUE;          /* Allow address group syntax */
 
-      while (*s != 0)
+      while (*s)
         {
         uschar *ss = parse_find_address_end(s, FALSE);
         uschar *recipient, *errmess, *pp;
         {
         uschar *ss = parse_find_address_end(s, FALSE);
         uschar *recipient, *errmess, *pp;
@@ -2635,7 +2632,7 @@ if (extract_recip)
 
         /* Check on maximum */
 
 
         /* Check on maximum */
 
-        if (recipients_max > 0 && ++rcount > recipients_max)
+        if (recipients_max_expanded > 0 && ++rcount > recipients_max_expanded)
           give_local_error(ERRMESS_TOOMANYRECIP, US"too many recipients",
             US"message rejected: ", error_rc, stdin, NULL);
           /* Does not return */
           give_local_error(ERRMESS_TOOMANYRECIP, US"too many recipients",
             US"message rejected: ", error_rc, stdin, NULL);
           /* Does not return */
@@ -2703,7 +2700,7 @@ if (extract_recip)
         /* Move on past this address */
 
         s = ss + (*ss ? 1 : 0);
         /* Move on past this address */
 
         s = ss + (*ss ? 1 : 0);
-        while (isspace(*s)) s++;
+        Uskip_whitespace(&s);
         }    /* Next address */
 
       f.parse_allow_group = FALSE;      /* Reset group syntax flags */
         }    /* Next address */
 
       f.parse_allow_group = FALSE;      /* Reset group syntax flags */
@@ -2819,6 +2816,7 @@ if (  !msgid_header
 
   /* Permit only letters, digits, dots, and hyphens in the domain */
 
 
   /* Permit only letters, digits, dots, and hyphens in the domain */
 
+  GET_OPTION("message_id_header_domain");
   if (message_id_domain)
     {
     uschar *new_id_domain = expand_string(message_id_domain);
   if (message_id_domain)
     {
     uschar *new_id_domain = expand_string(message_id_domain);
@@ -2840,6 +2838,7 @@ if (  !msgid_header
   /* Permit all characters except controls and RFC 2822 specials in the
   additional text part. */
 
   /* Permit all characters except controls and RFC 2822 specials in the
   additional text part. */
 
+  GET_OPTION("message_id_header_text");
   if (message_id_text)
     {
     uschar *new_id_text = expand_string(message_id_text);
   if (message_id_text)
     {
     uschar *new_id_text = expand_string(message_id_text);
@@ -3069,7 +3068,7 @@ if (  from_header
 it has already been rewritten as part of verification for SMTP input. */
 
 DEBUG(D_rewrite)
 it has already been rewritten as part of verification for SMTP input. */
 
 DEBUG(D_rewrite)
-  { debug_printf("global rewrite rules\n"); acl_level++; }
+  { debug_printf("rewrite rules on sender address\n"); acl_level++; }
 if (global_rewrite_rules && !sender_address_unrewritten && *sender_address)
   {
   /* deconst ok as src was not const */
 if (global_rewrite_rules && !sender_address_unrewritten && *sender_address)
   {
   /* deconst ok as src was not const */
@@ -3096,7 +3095,7 @@ documented as happening *after* recipient addresses are taken from the headers
 by the -t command line option. An added Sender: gets rewritten here. */
 
 DEBUG(D_rewrite)
 by the -t command line option. An added Sender: gets rewritten here. */
 
 DEBUG(D_rewrite)
-  { debug_printf("rewrite headers\n"); acl_level++; }
+  { debug_printf("qualify and rewrite headers\n"); acl_level++; }
 for (header_line * h = header_list->next, * newh; h; h = h->next)
   if ((newh = rewrite_header(h, NULL, NULL, global_rewrite_rules,
                              rewrite_existflags, TRUE)))
 for (header_line * h = header_list->next, * newh; h; h = h->next)
   if ((newh = rewrite_header(h, NULL, NULL, global_rewrite_rules,
                              rewrite_existflags, TRUE)))
@@ -3135,9 +3134,11 @@ new Received:) has not yet been set. */
 DEBUG(D_receive)
   {
   debug_printf(">>Headers after rewriting and local additions:\n");
 DEBUG(D_receive)
   {
   debug_printf(">>Headers after rewriting and local additions:\n");
+  acl_level++;
   for (header_line * h = header_list->next; h; h = h->next)
   for (header_line * h = header_list->next; h; h = h->next)
-    debug_printf("%c %s", h->type, h->text);
+    debug_printf_indent("%c %s", h->type, h->text);
   debug_printf("\n");
   debug_printf("\n");
+  acl_level--;
   }
 
 /* The headers are now complete in store. If we are running in filter
   }
 
 /* The headers are now complete in store. If we are running in filter
@@ -3509,172 +3510,140 @@ else
 #ifndef DISABLE_DKIM
     if (!f.dkim_disable_verify)
       {
 #ifndef DISABLE_DKIM
     if (!f.dkim_disable_verify)
       {
-      /* Finish verification */
-      dkim_exim_verify_finish();
+      misc_module_info * mi = misc_mod_findonly(US"dkim");
+      if (mi)
+       {
+       typedef void (*vfin_fn_t)(void);
+       typedef int  (*vacl_fn_t)(uschar **, uschar**);
+       typedef void (*vlog_fn_t)(void);
 
 
-      /* Check if we must run the DKIM ACL */
-      if (acl_smtp_dkim && dkim_verify_signers && *dkim_verify_signers)
-        {
-        uschar * dkim_verify_signers_expanded =
-          expand_string(dkim_verify_signers);
-       gstring * results = NULL;
-       int signer_sep = 0;
-       const uschar * ptr;
-       uschar * item;
-       gstring * seen_items = NULL;
-       int old_pool = store_pool;
-
-       store_pool = POOL_PERM;   /* Allow created variables to live to data ACL */
-
-        if (!(ptr = dkim_verify_signers_expanded))
-          log_write(0, LOG_MAIN|LOG_PANIC,
-            "expansion of dkim_verify_signers option failed: %s",
-            expand_string_message);
-
-       /* Default to OK when no items are present */
-       rc = OK;
-       while ((item = string_nextinlist(&ptr, &signer_sep, NULL, 0)))
-         {
-         /* Prevent running ACL for an empty item */
-         if (!item || !*item) continue;
+       /* Finish off the body hashes, calculate sigs and do compares */
 
 
-         /* Only run ACL once for each domain or identity,
-         no matter how often it appears in the expanded list. */
-         if (seen_items)
-           {
-           uschar * seen_item;
-           const uschar * seen_items_list = string_from_gstring(seen_items);
-           int seen_sep = ':';
-           BOOL seen_this_item = FALSE;
-
-           while ((seen_item = string_nextinlist(&seen_items_list, &seen_sep,
-                                                 NULL, 0)))
-             if (Ustrcmp(seen_item,item) == 0)
-               {
-               seen_this_item = TRUE;
-               break;
-               }
-
-           if (seen_this_item)
-             {
-             DEBUG(D_receive)
-               debug_printf("acl_smtp_dkim: skipping signer %s, "
-                 "already seen\n", item);
-             continue;
-             }
+       (((vfin_fn_t *) mi->functions)[DKIM_VERIFY_FINISH]) ();
 
 
-           seen_items = string_catn(seen_items, US":", 1);
-           }
-         seen_items = string_cat(seen_items, item);
+       /* Check if we must run the DKIM ACL */
+
+       GET_OPTION("acl_smtp_dkim");
+       if (acl_smtp_dkim)
+         {
+         rc = (((vacl_fn_t *) mi->functions)[DKIM_ACL_ENTRY])
+                                                   (&user_msg, &log_msg);
+         add_acl_headers(ACL_WHERE_DKIM, US"DKIM");
 
 
-         rc = dkim_exim_acl_run(item, &results, &user_msg, &log_msg);
          if (rc != OK)
            {
          if (rc != OK)
            {
-           DEBUG(D_receive)
-             debug_printf("acl_smtp_dkim: acl_check returned %d on %s, "
-               "skipping remaining items\n", rc, item);
            cancel_cutthrough_connection(TRUE, US"dkim acl not ok");
            cancel_cutthrough_connection(TRUE, US"dkim acl not ok");
-           break;
+
+           if (rc != DISCARD)
+             {
+             Uunlink(spool_name);
+             if (smtp_handle_acl_fail(ACL_WHERE_DKIM, rc, user_msg, log_msg) != 0)
+               smtp_yield = FALSE;     /* No more msgs after dropped conn */
+             smtp_reply = US"";        /* Indicate reply already sent */
+             goto NOT_ACCEPTED;        /* Skip to end of function */
+             }
+           recipients_count = 0;
+           blackholed_by = US"DKIM ACL";
+           if (log_msg)
+             blackhole_log_msg = string_sprintf(": %s", log_msg);
            }
          }
            }
          }
-       dkim_verify_status = string_from_gstring(results);
-       store_pool = old_pool;
-       add_acl_headers(ACL_WHERE_DKIM, US"DKIM");
-       if (rc == DISCARD)
-         {
-         recipients_count = 0;
-         blackholed_by = US"DKIM ACL";
-         if (log_msg)
-           blackhole_log_msg = string_sprintf(": %s", log_msg);
-         }
-       else if (rc != OK)
-         {
-         Uunlink(spool_name);
-         if (smtp_handle_acl_fail(ACL_WHERE_DKIM, rc, user_msg, log_msg) != 0)
-           smtp_yield = FALSE;    /* No more messages after dropped connection */
-         smtp_reply = US"";       /* Indicate reply already sent */
-         goto NOT_ACCEPTED;                    /* Skip to end of function */
-         }
-        }
-      else
-       dkim_exim_verify_log_all();
+       else    /* No ACL; just log */
+         (((vlog_fn_t *) mi->functions)[DKIM_VERIFY_LOG_ALL]) ();
+       }
       }
 #endif /* DISABLE_DKIM */
 
 #ifdef WITH_CONTENT_SCAN
       }
 #endif /* DISABLE_DKIM */
 
 #ifdef WITH_CONTENT_SCAN
-    if (  recipients_count > 0
-       && acl_smtp_mime
-       && !run_mime_acl(acl_smtp_mime, &smtp_yield, &smtp_reply, &blackholed_by)
-       )
-      goto TIDYUP;
+    if (recipients_count > 0)
+      {
+      GET_OPTION("acl_smtp_mime");
+      if (acl_smtp_mime
+        && !run_mime_acl(acl_smtp_mime, &smtp_yield, &smtp_reply, &blackholed_by)
+        )
+       goto TIDYUP;
+      }
 #endif /* WITH_CONTENT_SCAN */
 
 #ifdef SUPPORT_DMARC
 #endif /* WITH_CONTENT_SCAN */
 
 #ifdef SUPPORT_DMARC
-    dmarc_store_data(from_header);
+    {
+    misc_module_info * mi = misc_mod_findonly(US"dmarc");
+    if (mi)
+      {
+      typedef int (*fn_t)(header_line *);
+      (((fn_t *) mi->functions)[DMARC_STORE_DATA]) (dmarc_from_header);
+      }
+    }
 #endif
 
 #ifndef DISABLE_PRDR
 #endif
 
 #ifndef DISABLE_PRDR
-    if (prdr_requested && recipients_count > 1 && acl_smtp_data_prdr)
+    if (prdr_requested && recipients_count > 1)
       {
       {
-      int all_pass = OK;
-      int all_fail = FAIL;
+      GET_OPTION("acl_smtp_data_prdr");
+      if (acl_smtp_data_prdr)
+       {
+       int all_pass = OK;
+       int all_fail = FAIL;
 
 
-      smtp_printf("353 PRDR content analysis beginning\r\n", SP_MORE);
-      /* Loop through recipients, responses must be in same order received */
-      for (unsigned int c = 0; recipients_count > c; c++)
-        {
-       const uschar * addr = recipients_list[c].address;
-       uschar * msg= US"PRDR R=<%s> %s";
-       uschar * code;
-        DEBUG(D_receive)
-          debug_printf("PRDR processing recipient %s (%d of %d)\n",
-                       addr, c+1, recipients_count);
-        rc = acl_check(ACL_WHERE_PRDR, addr,
-                       acl_smtp_data_prdr, &user_msg, &log_msg);
-
-        /* If any recipient rejected content, indicate it in final message */
-        all_pass |= rc;
-        /* If all recipients rejected, indicate in final message */
-        all_fail &= rc;
-
-        switch (rc)
-          {
-          case OK: case DISCARD: code = US"250"; break;
-          case DEFER:            code = US"450"; break;
-          default:               code = US"550"; break;
-          }
-       if (user_msg != NULL)
-         smtp_user_msg(code, user_msg);
-       else
+       smtp_printf("353 PRDR content analysis beginning\r\n", SP_MORE);
+       /* Loop through recipients, responses must be in same order received */
+       for (unsigned int c = 0; recipients_count > c; c++)
          {
          {
+         const uschar * addr = recipients_list[c].address;
+         uschar * msg= US"PRDR R=<%s> %s";
+         uschar * code;
+         DEBUG(D_receive)
+           debug_printf("PRDR processing recipient %s (%d of %d)\n",
+                        addr, c+1, recipients_count);
+         rc = acl_check(ACL_WHERE_PRDR, addr,
+                        acl_smtp_data_prdr, &user_msg, &log_msg);
+
+         /* If any recipient rejected content, indicate it in final message */
+         all_pass |= rc;
+         /* If all recipients rejected, indicate in final message */
+         all_fail &= rc;
+
          switch (rc)
          switch (rc)
-            {
-            case OK: case DISCARD:
-              msg = string_sprintf(CS msg, addr, "acceptance");        break;
-            case DEFER:
-              msg = string_sprintf(CS msg, addr, "temporary refusal"); break;
-            default:
-              msg = string_sprintf(CS msg, addr, "refusal");           break;
-            }
-          smtp_user_msg(code, msg);
-         }
-       if (log_msg)       log_write(0, LOG_MAIN, "PRDR %s %s", addr, log_msg);
-       else if (user_msg) log_write(0, LOG_MAIN, "PRDR %s %s", addr, user_msg);
-       else               log_write(0, LOG_MAIN, "%s", CS msg);
+           {
+           case OK: case DISCARD: code = US"250"; break;
+           case DEFER:            code = US"450"; break;
+           default:               code = US"550"; break;
+           }
+         if (user_msg != NULL)
+           smtp_user_msg(code, user_msg);
+         else
+           {
+           switch (rc)
+             {
+             case OK: case DISCARD:
+               msg = string_sprintf(CS msg, addr, "acceptance");        break;
+             case DEFER:
+               msg = string_sprintf(CS msg, addr, "temporary refusal"); break;
+             default:
+               msg = string_sprintf(CS msg, addr, "refusal");           break;
+             }
+           smtp_user_msg(code, msg);
+           }
+         if (log_msg)       log_write(0, LOG_MAIN, "PRDR %s %s", addr, log_msg);
+         else if (user_msg) log_write(0, LOG_MAIN, "PRDR %s %s", addr, user_msg);
+         else               log_write(0, LOG_MAIN, "%s", CS msg);
 
 
-       if (rc != OK) { receive_remove_recipient(addr); c--; }
-        }
-      /* Set up final message, used if data acl gives OK */
-      smtp_reply = string_sprintf("%s id=%s message %s",
-                      all_fail == FAIL ? US"550" : US"250",
-                      message_id,
-                       all_fail == FAIL
-                        ? US"rejected for all recipients"
-                        : all_pass == OK
-                          ? US"accepted"
-                          : US"accepted for some recipients");
-      if (recipients_count == 0)
-       goto NOT_ACCEPTED;
+         if (rc != OK) { receive_remove_recipient(addr); c--; }
+         }
+       /* Set up final message, used if data acl gives OK */
+       smtp_reply = string_sprintf("%s id=%s message %s",
+                        all_fail == FAIL ? US"550" : US"250",
+                        message_id,
+                        all_fail == FAIL
+                          ? US"rejected for all recipients"
+                          : all_pass == OK
+                            ? US"accepted"
+                            : US"accepted for some recipients");
+       if (recipients_count == 0)
+         goto NOT_ACCEPTED;
+       }
+      else
+       prdr_requested = FALSE;
       }
     else
       prdr_requested = FALSE;
       }
     else
       prdr_requested = FALSE;
@@ -3683,6 +3652,7 @@ else
     /* Check the recipients count again, as the MIME ACL might have changed
     them. */
 
     /* Check the recipients count again, as the MIME ACL might have changed
     them. */
 
+    GET_OPTION("acl_smtp_data");
     if (acl_smtp_data && recipients_count > 0)
       {
       rc = acl_check(ACL_WHERE_DATA, NULL, acl_smtp_data, &user_msg, &log_msg);
     if (acl_smtp_data && recipients_count > 0)
       {
       rc = acl_check(ACL_WHERE_DATA, NULL, acl_smtp_data, &user_msg, &log_msg);
@@ -3720,6 +3690,7 @@ else
     {
 
 #ifdef WITH_CONTENT_SCAN
     {
 
 #ifdef WITH_CONTENT_SCAN
+    GET_OPTION("acl_not_smtp_mime");
     if (  acl_not_smtp_mime
        && !run_mime_acl(acl_not_smtp_mime, &smtp_yield, &smtp_reply,
           &blackholed_by)
     if (  acl_not_smtp_mime
        && !run_mime_acl(acl_not_smtp_mime, &smtp_yield, &smtp_reply,
           &blackholed_by)
@@ -3727,9 +3698,10 @@ else
       goto TIDYUP;
 #endif /* WITH_CONTENT_SCAN */
 
       goto TIDYUP;
 #endif /* WITH_CONTENT_SCAN */
 
+    GET_OPTION("acl_not_smtp");
     if (acl_not_smtp)
       {
     if (acl_not_smtp)
       {
-      uschar *user_msg, *log_msg;
+      uschar * user_msg, * log_msg;
       f.authentication_local = TRUE;
       rc = acl_check(ACL_WHERE_NOTSMTP, NULL, acl_not_smtp, &user_msg, &log_msg);
       if (rc == DISCARD)
       f.authentication_local = TRUE;
       rc = acl_check(ACL_WHERE_NOTSMTP, NULL, acl_not_smtp, &user_msg, &log_msg);
       if (rc == DISCARD)
@@ -4052,7 +4024,15 @@ else
 
 receive_messagecount++;
 
 
 receive_messagecount++;
 
-if (fflush(spool_data_file))
+if (  fflush(spool_data_file)
+#if _POSIX_C_SOURCE >= 199309L || _XOPEN_SOURCE >= 500
+# ifdef ENABLE_DISABLE_FSYNC
+   || !disable_fsync && fdatasync(data_fd)
+# else
+   || fdatasync(data_fd)
+# endif
+#endif
+   )
   {
   errmsg = string_sprintf("Spool write error: %s", strerror(errno));
   log_write(0, LOG_MAIN, "%s\n", errmsg);
   {
   errmsg = string_sprintf("Spool write error: %s", strerror(errno));
   log_write(0, LOG_MAIN, "%s\n", errmsg);
@@ -4149,12 +4129,22 @@ if (LOGGING(8bitmime))
   g = string_fmt_append(g, " M8S=%d", body_8bitmime);
 
 #ifndef DISABLE_DKIM
   g = string_fmt_append(g, " M8S=%d", body_8bitmime);
 
 #ifndef DISABLE_DKIM
-if (LOGGING(dkim) && dkim_verify_overall)
-  g = string_append(g, 2, US" DKIM=", dkim_verify_overall);
+if (LOGGING(dkim))
+  {
+  misc_module_info * mi = misc_mod_findonly(US"dkim");
+  typedef gstring * (*fn_t)(gstring *);
+  if (mi)
+    g = (((fn_t *) mi->functions)[DKIM_VDOM_FIRSTPASS]) (g);
+
 # ifdef EXPERIMENTAL_ARC
 # ifdef EXPERIMENTAL_ARC
-if (LOGGING(dkim) && arc_state && Ustrcmp(arc_state, "pass") == 0)
-  g = string_catn(g, US" ARC", 4);
+   {
+    mi = misc_mod_findonly(US"arc");
+    typedef BOOL (*fn_t)(void);
+    if (mi && (((fn_t *) mi->functions)[ARC_STATE_IS_PASS]) ())
+      g = string_catn(g, US" ARC", 4);
+   }
 # endif
 # endif
+  }
 #endif
 
 if (LOGGING(receive_time))
 #endif
 
 if (LOGGING(receive_time))
@@ -4596,3 +4586,5 @@ return yield;  /* TRUE if more messages (SMTP only) */
 }
 
 /* End of receive.c */
 }
 
 /* End of receive.c */
+/* vi: se aw ai sw=2
+*/