pass advertised facility to continued-transport process
[exim.git] / src / src / verify.c
index f64057fd1fb6b657bf7440f3193d2fb38f508e2a..d890f5fc60a96d54a4c1c948aec6c06754d75f2e 100644 (file)
@@ -155,10 +155,6 @@ do_callout(address_item *addr, host_item *host_list, transport_feedback *tf,
   int callout, int callout_overall, int callout_connect, int options,
   uschar *se_mailfrom, uschar *pm_mailfrom)
 {
-BOOL is_recipient = (options & vopt_is_recipient) != 0;
-BOOL callout_no_cache = (options & vopt_callout_no_cache) != 0;
-BOOL callout_random = (options & vopt_callout_random) != 0;
-
 int yield = OK;
 int old_domain_cache_result = ccache_accept;
 BOOL done = FALSE;
@@ -166,8 +162,8 @@ uschar *address_key;
 uschar *from_address;
 uschar *random_local_part = NULL;
 const uschar *save_deliver_domain = deliver_domain;
-uschar **failure_ptr = is_recipient?
-  &recipient_verify_failure : &sender_verify_failure;
+uschar **failure_ptr = options & vopt_is_recipient
+  &recipient_verify_failure : &sender_verify_failure;
 open_db dbblock;
 open_db *dbm_file = NULL;
 dbdata_callout_cache new_domain_record;
@@ -189,12 +185,13 @@ because that may influence the result of the callout. */
 address_key = addr->address;
 from_address = US"";
 
-if (is_recipient)
+if (options & vopt_is_recipient)
   {
   if (options & vopt_callout_recipsender)
     {
     address_key = string_sprintf("%s/<%s>", addr->address, sender_address);
     from_address = sender_address;
+    if (cutthrough.delivery) options |= vopt_callout_no_cache;
     }
   else if (options & vopt_callout_recippmaster)
     {
@@ -217,7 +214,7 @@ else
 /* Open the callout cache database, it it exists, for reading only at this
 stage, unless caching has been disabled. */
 
-if (callout_no_cache)
+if (options & vopt_callout_no_cache)
   {
   HDEBUG(D_verify) debug_printf("callout cache: disabled by no_cache\n");
   }
@@ -273,26 +270,26 @@ if (dbm_file != NULL)
     the data in the new record. If a random check is required but hasn't been
     done, skip the remaining cache processing. */
 
-    if (callout_random) switch(cache_record->random_result)
+    if (options & vopt_callout_random) switch(cache_record->random_result)
       {
       case ccache_accept:
-      HDEBUG(D_verify)
-        debug_printf("callout cache: domain accepts random addresses\n");
-      goto END_CALLOUT;     /* Default yield is OK */
+       HDEBUG(D_verify)
+         debug_printf("callout cache: domain accepts random addresses\n");
+       goto END_CALLOUT;     /* Default yield is OK */
 
       case ccache_reject:
-      HDEBUG(D_verify)
-        debug_printf("callout cache: domain rejects random addresses\n");
-      callout_random = FALSE;
-      new_domain_record.random_result = ccache_reject;
-      new_domain_record.random_stamp = cache_record->random_stamp;
-      break;
+       HDEBUG(D_verify)
+         debug_printf("callout cache: domain rejects random addresses\n");
+       options &= ~vopt_callout_random;
+       new_domain_record.random_result = ccache_reject;
+       new_domain_record.random_stamp = cache_record->random_stamp;
+       break;
 
       default:
-      HDEBUG(D_verify)
-        debug_printf("callout cache: need to check random address handling "
-          "(not cached or cache expired)\n");
-      goto END_CACHE;
+       HDEBUG(D_verify)
+         debug_printf("callout cache: need to check random address handling "
+           "(not cached or cache expired)\n");
+       goto END_CACHE;
       }
 
     /* If a postmaster check is requested, but there was a previous failure,
@@ -389,7 +386,7 @@ else
   with a random local part, ensure that such a local part is available. If not,
   log the fact, but carry on without randomming. */
 
-  if (callout_random && callout_random_local_part != NULL)
+  if (options & vopt_callout_random && callout_random_local_part != NULL)
     if (!(random_local_part = expand_string(callout_random_local_part)))
       log_write(0, LOG_MAIN|LOG_PANIC, "failed to expand "
         "callout_random_local_part: %s", expand_string_message);
@@ -640,12 +637,14 @@ can do it there for the non-rcpt-verify case.  For this we keep an addresscount.
 
       if (host->dnssec == DS_YES)
        {
-       if(  (  dane_required
-            || verify_check_given_host(&ob->hosts_try_dane, host) == OK
-            )
-         && (rc = tlsa_lookup(host, &tlsa_dnsa, dane_required, &dane)) != OK
+       if(  dane_required
+         || verify_check_given_host(&ob->hosts_try_dane, host) == OK
          )
-         return rc;
+         {
+         if ((rc = tlsa_lookup(host, &tlsa_dnsa, dane_required)) != OK)
+           return rc;
+         dane = TRUE;
+         }
        }
       else if (dane_required)
        {
@@ -760,7 +759,7 @@ can do it there for the non-rcpt-verify case.  For this we keep an addresscount.
       ? string_sprintf(" SIZE=%d", message_size + ob->size_addition) : US"";
 
 #ifdef SUPPORT_TLS
-    tls_offered = !!(peer_offered & PEER_OFFERED_TLS);
+    smtp_peer_options |= peer_offered & PEER_OFFERED_TLS;
 #endif
 
     /* If TLS is available on this connection attempt to
@@ -792,8 +791,10 @@ can do it there for the non-rcpt-verify case.  For this we keep an addresscount.
       if (!smtps && !smtp_read_response(&inblock, buffer2, sizeof(buffer2), '2',
                        ob->command_timeout))
         {
-        if (errno != 0 || buffer2[0] == 0 ||
-               (buffer2[0] == '4' && !ob->tls_tempfail_tryclear))
+        if (  errno != 0
+          || buffer2[0] == 0
+          || buffer2[0] == '4' && !ob->tls_tempfail_tryclear
+          )
          {
          Ustrncpy(responsebuffer, buffer2, sizeof(responsebuffer));
          done= FALSE;
@@ -827,24 +828,10 @@ can do it there for the non-rcpt-verify case.  For this we keep an addresscount.
            (void) event_raise(addr->transport->event_action,
                                    US"tcp:close", NULL);
 # endif
-# ifdef EXPERIMENTAL_DANE
-           if (dane)
-             {
-             if (!dane_required)
-               {
-               log_write(0, LOG_MAIN, "DANE attempt failed;"
-                 " trying CA-root TLS to %s [%s] (not in hosts_require_dane)",
-                 host->name, host->address);
-               dane = FALSE;
-               goto tls_negotiate;
-               }
-             }
-           else
-# endif
-             if (  ob->tls_tempfail_tryclear
-                && !smtps
-                && verify_check_given_host(&ob->hosts_require_tls, host) != OK
-                )
+           if (  ob->tls_tempfail_tryclear
+              && !smtps
+              && verify_check_given_host(&ob->hosts_require_tls, host) != OK
+              )
              {
              log_write(0, LOG_MAIN, "TLS session failure:"
                " delivering unencrypted to %s [%s] (not in hosts_require_tls)",
@@ -902,13 +889,16 @@ can do it there for the non-rcpt-verify case.  For this we keep an addresscount.
     /* Need proper integration with the proper transport mechanism. */
     if (cutthrough.delivery)
       {
+#ifndef DISABLE_DKIM
+      uschar * s;
+#endif
       if (addr->transport->filter_command)
         {
         cutthrough.delivery = FALSE;
         HDEBUG(D_acl|D_v) debug_printf("Cutthrough cancelled by presence of transport filter\n");
         }
 #ifndef DISABLE_DKIM
-      if (ob->dkim_domain)
+      else if ((s = ob->dkim.dkim_domain) && (s = expand_string(s)) && *s)
         {
         cutthrough.delivery = FALSE;
         HDEBUG(D_acl|D_v) debug_printf("Cutthrough cancelled by presence of DKIM signing\n");
@@ -1255,10 +1245,9 @@ can do it there for the non-rcpt-verify case.  For this we keep an addresscount.
             big_buffer, host->name, host->address,
             string_printing(responsebuffer));
 
-        addr->user_message = is_recipient?
-          string_sprintf("Callout verification failed:\n%s", responsebuffer)
-          :
-          string_sprintf("Called:   %s\nSent:     %s\nResponse: %s",
+        addr->user_message = options & vopt_is_recipient
+         ? string_sprintf("Callout verification failed:\n%s", responsebuffer)
+          : string_sprintf("Called:   %s\nSent:     %s\nResponse: %s",
             host->address, big_buffer, responsebuffer);
 
         /* Hard rejection ends the process */
@@ -1280,13 +1269,16 @@ can do it there for the non-rcpt-verify case.  For this we keep an addresscount.
        && rcpt_count == 1
        && done
        && yield == OK
-       && (options & (vopt_callout_recipsender|vopt_callout_recippmaster)) == vopt_callout_recipsender
+       &&    (options & (vopt_callout_recipsender|vopt_callout_recippmaster|vopt_success_on_redirect))
+          == vopt_callout_recipsender
        && !random_local_part
        && !pm_mailfrom
        && cutthrough.fd < 0
        && !lmtp
        )
       {
+      HDEBUG(D_acl|D_v) debug_printf("holding verify callout open for cutthrough delivery\n");
+
       cutthrough.fd = outblock.sock;   /* We assume no buffer in use in the outblock */
       cutthrough.nrcpt = 1;
       cutthrough.interface = interface;
@@ -1332,7 +1324,8 @@ there was an error before or with MAIL FROM:, and errno was not zero,
 implying some kind of I/O error. We don't want to write the cache in that case.
 Otherwise the value is ccache_accept, ccache_reject, or ccache_reject_mfnull. */
 
-if (!callout_no_cache && new_domain_record.result != ccache_unknown)
+if (  !(options & vopt_callout_no_cache)
+   && new_domain_record.result != ccache_unknown)
   {
   if ((dbm_file = dbfn_open(US"callout", O_RDWR|O_CREAT, &dbblock, FALSE))
        == NULL)
@@ -1343,8 +1336,9 @@ if (!callout_no_cache && new_domain_record.result != ccache_unknown)
     {
     (void)dbfn_write(dbm_file, addr->domain, &new_domain_record,
       (int)sizeof(dbdata_callout_cache));
-    HDEBUG(D_verify) debug_printf("wrote callout cache domain record:\n"
+    HDEBUG(D_verify) debug_printf("wrote callout cache domain record for %s:\n"
       "  result=%d postmaster=%d random=%d\n",
+      addr->domain,
       new_domain_record.result,
       new_domain_record.postmaster_result,
       new_domain_record.random_result);
@@ -1356,7 +1350,8 @@ is disabled. */
 
 if (done)
   {
-  if (!callout_no_cache && new_address_record.result != ccache_unknown)
+  if (  !(options & vopt_callout_no_cache)
+     && new_address_record.result != ccache_unknown)
     {
     if (dbm_file == NULL)
       dbm_file = dbfn_open(US"callout", O_RDWR|O_CREAT, &dbblock, FALSE);
@@ -1368,8 +1363,9 @@ if (done)
       {
       (void)dbfn_write(dbm_file, address_key, &new_address_record,
         (int)sizeof(dbdata_callout_cache_address));
-      HDEBUG(D_verify) debug_printf("wrote %s callout cache address record\n",
-        (new_address_record.result == ccache_accept)? "positive" : "negative");
+      HDEBUG(D_verify) debug_printf("wrote %s callout cache address record for %s\n",
+        new_address_record.result == ccache_accept ? "positive" : "negative",
+       address_key);
       }
     }
   }    /* done */
@@ -1381,7 +1377,7 @@ it alone if supplying details. Otherwise, give a generic response. */
 else   /* !done */
   {
   uschar *dullmsg = string_sprintf("Could not complete %s verify callout",
-    is_recipient? "recipient" : "sender");
+    options & vopt_is_recipient ? "recipient" : "sender");
   yield = DEFER;
 
   if (host_list->next != NULL || addr->message == NULL) addr->message = dullmsg;
@@ -1391,12 +1387,11 @@ else   /* !done */
       "The mail server(s) for the domain may be temporarily unreachable, or\n"
       "they may be permanently unreachable from this server. In the latter case,\n%s",
       dullmsg, addr->address,
-      is_recipient?
-        "the address will never be accepted."
-        :
-        "you need to change the address or create an MX record for its domain\n"
-        "if it is supposed to be generally accessible from the Internet.\n"
-        "Talk to your mail administrator for details.");
+      options & vopt_is_recipient
+       ?  "the address will never be accepted."
+        : "you need to change the address or create an MX record for its domain\n"
+         "if it is supposed to be generally accessible from the Internet.\n"
+         "Talk to your mail administrator for details.");
 
   /* Force a specific error code */
 
@@ -1564,9 +1559,9 @@ return cutthrough_response('3', NULL) == '3';
 }
 
 
-/* fd and use_crlf args only to match write_chunk() */
+/* fd and tctx args only to match write_chunk() */
 static BOOL
-cutthrough_write_chunk(int fd, uschar * s, int len, BOOL use_crlf)
+cutthrough_write_chunk(int fd, transport_ctx * tctx, uschar * s, int len)
 {
 uschar * s2;
 while(s && (s2 = Ustrchr(s, '\n')))
@@ -1585,6 +1580,8 @@ return TRUE;
 BOOL
 cutthrough_headers_send(void)
 {
+transport_ctx tctx;
+
 if(cutthrough.fd < 0)
   return FALSE;
 
@@ -1593,12 +1590,13 @@ if(cutthrough.fd < 0)
 */
 HDEBUG(D_acl) debug_printf("----------- start cutthrough headers send -----------\n");
 
-if (!transport_headers_send(&cutthrough.addr, cutthrough.fd,
-       cutthrough.addr.transport->add_headers,
-       cutthrough.addr.transport->remove_headers,
-       &cutthrough_write_chunk, TRUE,
-       cutthrough.addr.transport->rewrite_rules,
-       cutthrough.addr.transport->rewrite_existflags))
+tctx.tblock = cutthrough.addr.transport;
+tctx.addr = &cutthrough.addr;
+tctx.check_string = US".";
+tctx.escape_string = US"..";
+tctx.options = topt_use_crlf;
+
+if (!transport_headers_send(cutthrough.fd, &tctx, &cutthrough_write_chunk))
   return FALSE;
 
 HDEBUG(D_acl) debug_printf("----------- done cutthrough headers send ------------\n");
@@ -1818,21 +1816,20 @@ verify_address(address_item *vaddr, FILE *f, int options, int callout,
 {
 BOOL allok = TRUE;
 BOOL full_info = (f == NULL)? FALSE : (debug_selector != 0);
-BOOL is_recipient = (options & vopt_is_recipient) != 0;
 BOOL expn         = (options & vopt_expn) != 0;
 BOOL success_on_redirect = (options & vopt_success_on_redirect) != 0;
 int i;
 int yield = OK;
 int verify_type = expn? v_expn :
      address_test_mode? v_none :
-          is_recipient? v_recipient : v_sender;
+          options & vopt_is_recipient? v_recipient : v_sender;
 address_item *addr_list;
 address_item *addr_new = NULL;
 address_item *addr_remote = NULL;
 address_item *addr_local = NULL;
 address_item *addr_succeed = NULL;
-uschar **failure_ptr = is_recipient?
-  &recipient_verify_failure : &sender_verify_failure;
+uschar **failure_ptr = options & vopt_is_recipient
+  &recipient_verify_failure : &sender_verify_failure;
 uschar *ko_prefix, *cr;
 uschar *address = vaddr->address;
 uschar *save_sender;
@@ -1865,7 +1862,7 @@ if (parse_find_at(address) == NULL)
     *failure_ptr = US"qualify";
     return FAIL;
     }
-  address = rewrite_address_qualify(address, is_recipient);
+  address = rewrite_address_qualify(address, options & vopt_is_recipient);
   }
 
 DEBUG(D_verify)
@@ -1880,7 +1877,7 @@ may have been set by domains and local part tests during an ACL. */
 if (global_rewrite_rules != NULL)
   {
   uschar *old = address;
-  address = rewrite_address(address, is_recipient, FALSE,
+  address = rewrite_address(address, options & vopt_is_recipient, FALSE,
     global_rewrite_rules, rewrite_existflags);
   if (address != old)
     {
@@ -1904,7 +1901,7 @@ if (address[0] == 0) return OK;
 
 /* Flip the legacy TLS-related variables over to the outbound set in case
 they're used in the context of a transport used by verification. Reset them
-at exit from this routine. */
+at exit from this routine (so no returns allowed from here on). */
 
 tls_modify_variables(&tls_out);
 
@@ -1913,6 +1910,10 @@ while verifying a sender address (a nice bit of self-reference there). */
 
 save_sender = sender_address;
 
+/* Observability variable for router/transport use */
+
+verify_mode = options & vopt_is_recipient ? US"R" : US"S";
+
 /* Update the address structure with the possibly qualified and rewritten
 address. Set it up as the starting address on the chain of new addresses. */
 
@@ -1928,7 +1929,7 @@ If an address generates more than one child, the loop is used only when
 full_info is set, and this can only be set locally. Remote enquiries just get
 information about the top level address, not anything that it generated. */
 
-while (addr_new != NULL)
+while (addr_new)
   {
   int rc;
   address_item *addr = addr_new;
@@ -1977,18 +1978,18 @@ while (addr_new != NULL)
 
   /* Just in case some router parameter refers to it. */
 
-  return_path = (addr->prop.errors_address != NULL)?
-    addr->prop.errors_address : sender_address;
+  return_path = addr->prop.errors_address
+    addr->prop.errors_address : sender_address;
 
   /* Split the address into domain and local part, handling the %-hack if
   necessary, and then route it. While routing a sender address, set
   $sender_address to <> because that is what it will be if we were trying to
   send a bounce to the sender. */
 
-  if (routed != NULL) *routed = FALSE;
+  if (routed) *routed = FALSE;
   if ((rc = deliver_split_address(addr)) == OK)
     {
-    if (!is_recipient) sender_address = null_sender;
+    if (!(options & vopt_is_recipient)) sender_address = null_sender;
     rc = route_address(addr, &addr_local, &addr_remote, &addr_new,
       &addr_succeed, verify_type);
     sender_address = save_sender;     /* Put back the real sender */
@@ -2002,11 +2003,11 @@ while (addr_new != NULL)
 
   if (rc == OK)
     {
-    if (routed != NULL) *routed = TRUE;
+    if (routed) *routed = TRUE;
     if (callout > 0)
       {
-      host_item *host_list = addr->host_list;
       transport_instance * tp;
+      host_item * host_list = addr->host_list;
 
       /* Make up some data for use in the case where there is no remote
       transport. */
@@ -2036,7 +2037,7 @@ while (addr_new != NULL)
         transport is configured to override the router's hosts, we must build a
         host list of the transport's hosts, and find the IP addresses */
 
-        if (tf.hosts != NULL && (host_list == NULL || tf.hosts_override))
+        if (tf.hosts && (!host_list || tf.hosts_override))
           {
           uschar *s;
           const uschar *save_deliver_domain = deliver_domain;
@@ -2050,7 +2051,7 @@ while (addr_new != NULL)
           deliver_domain = save_deliver_domain;
           deliver_localpart = save_deliver_localpart;
 
-          if (s == NULL)
+          if (!s)
             {
             log_write(0, LOG_MAIN|LOG_PANIC, "failed to expand list of hosts "
               "\"%s\" in %s transport for callout: %s", tf.hosts,
@@ -2072,7 +2073,7 @@ while (addr_new != NULL)
             if (tf.qualify_single) flags |= HOST_FIND_QUALIFY_SINGLE;
             if (tf.search_parents) flags |= HOST_FIND_SEARCH_PARENTS;
 
-            for (host = host_list; host != NULL; host = nexthost)
+            for (host = host_list; host; host = nexthost)
               {
               nexthost = host->next;
               if (tf.gethostbyname ||
@@ -2099,7 +2100,7 @@ while (addr_new != NULL)
       /* Can only do a callout if we have at least one host! If the callout
       fails, it will have set ${sender,recipient}_verify_failure. */
 
-      if (host_list != NULL)
+      if (host_list)
         {
         HDEBUG(D_verify) debug_printf("Attempting full verification using callout\n");
         if (host_checking && !host_checking_callout)
@@ -2113,10 +2114,8 @@ while (addr_new != NULL)
 #ifdef SUPPORT_TLS
          deliver_set_expansions(addr);
 #endif
-         verify_mode = is_recipient ? US"R" : US"S";
           rc = do_callout(addr, host_list, &tf, callout, callout_overall,
             callout_connect, options, se_mailfrom, pm_mailfrom);
-         verify_mode = NULL;
           }
         }
       else
@@ -2142,24 +2141,24 @@ while (addr_new != NULL)
   if (rc == FAIL)
     {
     allok = FALSE;
-    if (f != NULL)
+    if (f)
       {
       address_item *p = addr->parent;
 
       respond_printf(f, "%s%s %s", ko_prefix,
-        full_info? addr->address : address,
-        address_test_mode? "is undeliverable" : "failed to verify");
+        full_info ? addr->address : address,
+        address_test_mode ? "is undeliverable" : "failed to verify");
       if (!expn && admin_user)
         {
         if (addr->basic_errno > 0)
           respond_printf(f, ": %s", strerror(addr->basic_errno));
-        if (addr->message != NULL)
+        if (addr->message)
           respond_printf(f, ": %s", addr->message);
         }
 
       /* Show parents iff doing full info */
 
-      if (full_info) while (p != NULL)
+      if (full_info) while (p)
         {
         respond_printf(f, "%s\n    <-- %s", cr, p->address);
         p = p->parent;
@@ -2169,11 +2168,11 @@ while (addr_new != NULL)
     cancel_cutthrough_connection("routing hard fail");
 
     if (!full_info)
-    {
+      {
       yield = copy_error(vaddr, addr, FAIL);
       goto out;
-    }
-    else yield = FAIL;
+      }
+    yield = FAIL;
     }
 
   /* Soft failure */
@@ -2181,7 +2180,7 @@ while (addr_new != NULL)
   else if (rc == DEFER)
     {
     allok = FALSE;
-    if (f != NULL)
+    if (f)
       {
       address_item *p = addr->parent;
       respond_printf(f, "%s%s cannot be resolved at this time", ko_prefix,
@@ -2190,7 +2189,7 @@ while (addr_new != NULL)
         {
         if (addr->basic_errno > 0)
           respond_printf(f, ": %s", strerror(addr->basic_errno));
-        if (addr->message != NULL)
+        if (addr->message)
           respond_printf(f, ": %s", addr->message);
         else if (addr->basic_errno <= 0)
           respond_printf(f, ": unknown error");
@@ -2198,7 +2197,7 @@ while (addr_new != NULL)
 
       /* Show parents iff doing full info */
 
-      if (full_info) while (p != NULL)
+      if (full_info) while (p)
         {
         respond_printf(f, "%s\n    <-- %s", cr, p->address);
         p = p->parent;
@@ -2212,7 +2211,7 @@ while (addr_new != NULL)
       yield = copy_error(vaddr, addr, DEFER);
       goto out;
       }
-    else if (yield == OK) yield = DEFER;
+    if (yield == OK) yield = DEFER;
     }
 
   /* If we are handling EXPN, we do not want to continue to route beyond
@@ -2221,20 +2220,20 @@ while (addr_new != NULL)
   else if (expn)
     {
     uschar *ok_prefix = US"250-";
-    if (addr_new == NULL)
-      {
-      if (addr_local == NULL && addr_remote == NULL)
+
+    if (!addr_new)
+      if (!addr_local && !addr_remote)
         respond_printf(f, "250 mail to <%s> is discarded\r\n", address);
       else
         respond_printf(f, "250 <%s>\r\n", address);
-      }
-    else while (addr_new != NULL)
+
+    else do
       {
       address_item *addr2 = addr_new;
       addr_new = addr2->next;
-      if (addr_new == NULL) ok_prefix = US"250 ";
+      if (!addr_new) ok_prefix = US"250 ";
       respond_printf(f, "%s<%s>\r\n", ok_prefix, addr2->address);
-      }
+      } while (addr_new);
     yield = OK;
     goto out;
     }
@@ -2256,21 +2255,30 @@ while (addr_new != NULL)
     just a single new address as a special case, and continues on to verify the
     generated address. */
 
-    if (!full_info &&                    /* Stop if short info wanted AND */
-         (((addr_new == NULL ||          /* No new address OR */
-           addr_new->next != NULL ||     /* More than one new address OR */
-           testflag(addr_new, af_pfr)))  /* New address is pfr */
-         ||                              /* OR */
-         (addr_new != NULL &&            /* At least one new address AND */
-          success_on_redirect)))         /* success_on_redirect is set */
+    if (  !full_info                   /* Stop if short info wanted AND */
+       && (  (  !addr_new              /* No new address OR */
+             || addr_new->next         /* More than one new address OR */
+            || testflag(addr_new, af_pfr)      /* New address is pfr */
+            )
+          ||                           /* OR */
+             (  addr_new               /* At least one new address AND */
+             && success_on_redirect    /* success_on_redirect is set */
+         )  )
+       )
       {
-      if (f != NULL) fprintf(f, "%s %s\n", address,
-        address_test_mode? "is deliverable" : "verified");
+      if (f) fprintf(f, "%s %s\n",
+        address, address_test_mode ? "is deliverable" : "verified");
 
       /* If we have carried on to verify a child address, we want the value
       of $address_data to be that of the child */
 
       vaddr->prop.address_data = addr->prop.address_data;
+
+      /* If stopped because more than one new address, cannot cutthrough */
+
+      if (addr_new && addr_new->next)
+       cancel_cutthrough_connection("multiple addresses from routing");
+
       yield = OK;
       goto out;
       }
@@ -2286,7 +2294,7 @@ If there are no local and no remote addresses, and there were no pipes, files,
 or autoreplies, and there were no errors or deferments, the message is to be
 discarded, usually because of the use of :blackhole: in an alias file. */
 
-if (allok && addr_local == NULL && addr_remote == NULL)
+if (allok && !addr_local && !addr_remote)
   {
   fprintf(f, "mail to %s is discarded\n", address);
   goto out;
@@ -2367,6 +2375,7 @@ for (addr_list = addr_local, i = 0; i < 2; addr_list = addr_remote, i++)
 the -bv or -bt case). */
 
 out:
+verify_mode = NULL;
 tls_modify_variables(&tls_in);
 
 return yield;