Routers: make retry_use_local_part default true when any non-domain condition is...
[exim.git] / src / src / deliver.c
index f79522d8e8a948c82f81529b5111b6f949694b63..a82a04f42a27d7cb2b011786cf575bdb363969df 100644 (file)
@@ -66,7 +66,6 @@ static address_item *addr_new = NULL;
 static address_item *addr_remote = NULL;
 static address_item *addr_route = NULL;
 static address_item *addr_succeed = NULL;
-static address_item *addr_dsntmp = NULL;
 static address_item *addr_senddsn = NULL;
 
 static FILE *message_log = NULL;
@@ -108,21 +107,21 @@ Returns:      the amount of bytes read
 static ssize_t
 readn(int fd, void * buffer, size_t len)
 {
-  void * next = buffer;
-  void * end = buffer + len;
+uschar * next = buffer;
+uschar * end = next + len;
 
-  while (next < end)
-    {
-    ssize_t got = read(fd, next, end - next);
+while (next < end)
+  {
+  ssize_t got = read(fd, next, end - next);
 
-    /* I'm not sure if there are signals that can interrupt us,
-    for now I assume the worst */
-    if (got == -1 && errno == EINTR) continue;
-    if (got <= 0) return next - buffer;
-    next += got;
-    }
+  /* I'm not sure if there are signals that can interrupt us,
+  for now I assume the worst */
+  if (got == -1 && errno == EINTR) continue;
+  if (got <= 0) return next - US buffer;
+  next += got;
+  }
 
-  return len;
+return len;
 }
 
 
@@ -145,7 +144,7 @@ Returns:      a pointer to an initialized address_item
 address_item *
 deliver_make_addr(uschar *address, BOOL copy)
 {
-address_item *addr = store_get(sizeof(address_item));
+address_item *addr = store_get(sizeof(address_item), FALSE);
 *addr = address_defaults;
 if (copy) address = string_copy(address);
 addr->address = address;
@@ -199,6 +198,7 @@ deliver_recipients = addr;
 deliver_address_data = addr->prop.address_data;
 deliver_domain_data = addr->prop.domain_data;
 deliver_localpart_data = addr->prop.localpart_data;
+router_var = addr->prop.variables;
 
 /* These may be unset for multiple addresses */
 
@@ -801,7 +801,7 @@ return g;
 
 
 
-#ifdef SUPPORT_TLS
+#ifndef DISABLE_TLS
 static gstring *
 d_tlslog(gstring * g, address_item * addr)
 {
@@ -1023,7 +1023,8 @@ splitting is done; in those cases use the original field. */
 
 else
   {
-  uschar * cmp = g->s + g->ptr;
+  uschar * cmp;
+  int off = g->ptr;    /* start of the "full address" */
 
   if (addr->local_part)
     {
@@ -1045,6 +1046,7 @@ else
   of all, do a caseless comparison; if this succeeds, do a caseful comparison
   on the local parts. */
 
+  cmp = g->s + off;            /* only now, as rebuffer likely done */
   string_from_gstring(g);      /* ensure nul-terminated */
   if (  strcmpic(cmp, topaddr->address) == 0
      && Ustrncmp(cmp, topaddr->address, Ustrchr(cmp, '@') - cmp) == 0
@@ -1137,7 +1139,7 @@ void
 delivery_log(int flags, address_item * addr, int logchar, uschar * msg)
 {
 gstring * g; /* Used for a temporary, expanding buffer, for building log lines  */
-void * reset_point;     /* released afterwards.  */
+rmark reset_point;
 
 /* Log the delivery on the main log. We use an extensible string to build up
 the log line, and reset the store afterwards. Remote deliveries should always
@@ -1149,7 +1151,8 @@ pointer to a single host item in their host list, for use by the transport. */
   lookup_dnssec_authenticated = NULL;
 #endif
 
-g = reset_point = string_get(256);
+reset_point = store_mark();
+g = string_get_tainted(256, TRUE);     /* addrs will be tainted, so avoid copy */
 
 if (msg)
   g = string_append(g, 2, host_and_ident(TRUE), US" ");
@@ -1231,7 +1234,7 @@ else
 #endif
     }
 
-#ifdef SUPPORT_TLS
+#ifndef DISABLE_TLS
   g = d_tlslog(g, addr);
 #endif
 
@@ -1250,7 +1253,7 @@ else
     {
     if (testflag(addr, af_pipelining))
       g = string_catn(g, US" L", 2);
-#ifdef EXPERIMENTAL_PIPE_CONNECT
+#ifdef SUPPORT_PIPE_CONNECT
     if (testflag(addr, af_early_pipe))
       g = string_catn(g, US"*", 1);
 #endif
@@ -1317,14 +1320,12 @@ static void
 deferral_log(address_item * addr, uschar * now,
   int logflags, uschar * driver_name, uschar * driver_kind)
 {
-gstring * g;
-void * reset_point;
+rmark reset_point = store_mark();
+gstring * g = string_get(256);
 
 /* Build up the line that is used for both the message log and the main
 log. */
 
-g = reset_point = string_get(256);
-
 /* Create the address string for logging. Must not do this earlier, because
 an OK result may be changed to FAIL when a pipe returns text. */
 
@@ -1396,8 +1397,8 @@ return;
 static void
 failure_log(address_item * addr, uschar * driver_kind, uschar * now)
 {
-void * reset_point;
-gstring * g = reset_point = string_get(256);
+rmark reset_point = store_mark();
+gstring * g = string_get(256);
 
 #ifndef DISABLE_EVENT
 /* Message failures for which we will send a DSN get their event raised
@@ -1435,7 +1436,7 @@ if (addr->transport)
 if (addr->host_used)
   g = d_hostlog(g, addr);
 
-#ifdef SUPPORT_TLS
+#ifndef DISABLE_TLS
 g = d_tlslog(g, addr);
 #endif
 
@@ -1635,7 +1636,7 @@ if (result == OK)
     }
 
   /* Certificates for logging (via events) */
-#ifdef SUPPORT_TLS
+#ifndef DISABLE_TLS
   tls_out.ourcert = addr->ourcert;
   addr->ourcert = NULL;
   tls_out.peercert = addr->peercert;
@@ -1651,7 +1652,7 @@ if (result == OK)
 
   delivery_log(LOG_MAIN, addr, logchar, NULL);
 
-#ifdef SUPPORT_TLS
+#ifndef DISABLE_TLS
   tls_free_cert(&tls_out.ourcert);
   tls_free_cert(&tls_out.peercert);
   tls_out.cipher = NULL;
@@ -1790,7 +1791,7 @@ if (format)
   gstring * g;
 
   va_start(ap, format);
-  g = string_vformat(NULL, TRUE, CS format, ap);
+  g = string_vformat(NULL, SVFMT_EXTEND|SVFMT_REBUFFER, CS format, ap);
   va_end(ap);
   addr->message = string_from_gstring(g);
   }
@@ -2052,10 +2053,10 @@ Returns:    TRUE if previously delivered by the transport
 static BOOL
 previously_transported(address_item *addr, BOOL testing)
 {
-(void)string_format(big_buffer, big_buffer_size, "%s/%s",
+uschar * s = string_sprintf("%s/%s",
   addr->unique + (testflag(addr, af_homonym)? 3:0), addr->transport->name);
 
-if (tree_search(tree_nonrecipients, big_buffer) != 0)
+if (tree_search(tree_nonrecipients, s) != 0)
   {
   DEBUG(D_deliver|D_route|D_transport)
     debug_printf("%s was previously delivered (%s transport): discarded\n",
@@ -2755,7 +2756,7 @@ while (addr_local)
     f.disable_logging = FALSE;  /* Jic */
     addr->message = addr->router
       ? string_sprintf("No transport set by %s router", addr->router->name)
-      : string_sprintf("No transport set by system filter");
+      : US"No transport set by system filter";
     post_process_one(addr, DEFER, logflags, EXIM_DTYPE_TRANSPORT, 0);
     continue;
     }
@@ -3066,7 +3067,7 @@ while (addr_local)
     else for (addr2 = addr; addr2; addr2 = addr2->next)
       if (addr2->transport_return == OK)
        {
-       addr3 = store_get(sizeof(address_item));
+       addr3 = store_get(sizeof(address_item), FALSE);
        *addr3 = *addr2;
        addr3->next = NULL;
        addr3->shadow_message = US &addr2->shadow_message;
@@ -3464,7 +3465,7 @@ while (!done)
 
       if (!r || !(*ptr & rf_delete))
        {
-       r = store_get(sizeof(retry_item));
+       r = store_get(sizeof(retry_item), FALSE);
        r->next = addr->retries;
        addr->retries = r;
        r->flags = *ptr++;
@@ -3505,7 +3506,7 @@ while (!done)
     it in with the other info, in order to keep each message short enough to
     guarantee it won't be split in the pipe. */
 
-#ifdef SUPPORT_TLS
+#ifndef DISABLE_TLS
     case 'X':
       if (!addr) goto ADDR_MISMATCH;          /* Below, in 'A' handler */
       switch (*subid)
@@ -3543,7 +3544,7 @@ while (!done)
        }
       while (*ptr++);
       break;
-#endif /*SUPPORT_TLS*/
+#endif /*DISABLE_TLS*/
 
     case 'C':  /* client authenticator information */
       switch (*subid)
@@ -3564,7 +3565,7 @@ while (!done)
     case 'L':
       switch (*subid)
        {
-#ifdef EXPERIMENTAL_PIPE_CONNECT
+#ifdef SUPPORT_PIPE_CONNECT
        case 2: setflag(addr, af_early_pipe);   /*FALLTHROUGH*/
 #endif
        case 1: setflag(addr, af_pipelining); break;
@@ -3647,7 +3648,7 @@ while (!done)
 
          if (*ptr)
            {
-           h = store_get(sizeof(host_item));
+           h = store_get(sizeof(host_item), FALSE);
            h->name = string_copy(ptr);
            while (*ptr++);
            h->address = string_copy(ptr);
@@ -4231,7 +4232,7 @@ set up, do so. */
 
 if (!parlist)
   {
-  parlist = store_get(remote_max_parallel * sizeof(pardata));
+  parlist = store_get(remote_max_parallel * sizeof(pardata), FALSE);
   for (poffset = 0; poffset < remote_max_parallel; poffset++)
     parlist[poffset].pid = 0;
   }
@@ -4793,7 +4794,6 @@ all pipes, so I do not see a reason to use non-blocking IO here
     for(; addr; addr = addr->next)
       {
       uschar *ptr;
-      retry_item *r;
 
       /* The certificate verification status goes into the flags */
       if (tls_out.certificate_verified) setflag(addr, af_cert_verified);
@@ -4805,7 +4805,7 @@ all pipes, so I do not see a reason to use non-blocking IO here
 # endif
 
       /* Use an X item only if there's something to send */
-#ifdef SUPPORT_TLS
+#ifndef DISABLE_TLS
       if (addr->cipher)
         {
         ptr = big_buffer + sprintf(CS big_buffer, "%.128s", addr->cipher) + 1;
@@ -4848,7 +4848,7 @@ all pipes, so I do not see a reason to use non-blocking IO here
         rmt_dlv_checked_write(fd, 'X', '4', big_buffer, ptr - big_buffer);
        }
 # endif
-#endif /*SUPPORT_TLS*/
+#endif /*DISABLE_TLS*/
 
       if (client_authenticator)
         {
@@ -4872,7 +4872,7 @@ all pipes, so I do not see a reason to use non-blocking IO here
 #endif
 
       if (testflag(addr, af_pipelining))
-#ifdef EXPERIMENTAL_PIPE_CONNECT
+#ifdef SUPPORT_PIPE_CONNECT
        if (testflag(addr, af_early_pipe))
          rmt_dlv_checked_write(fd, 'L', '2', NULL, 0);
        else
@@ -4893,7 +4893,7 @@ all pipes, so I do not see a reason to use non-blocking IO here
 
       /* Retry information: for most success cases this will be null. */
 
-      for (r = addr->retries; r; r = r->next)
+      for (retry_item * r = addr->retries; r; r = r->next)
         {
         sprintf(CS big_buffer, "%c%.500s", r->flags, r->key);
         ptr = big_buffer + Ustrlen(big_buffer+2) + 3;
@@ -5012,7 +5012,7 @@ all pipes, so I do not see a reason to use non-blocking IO here
 
   if (cutthrough.cctx.sock >= 0 && cutthrough.callout_hold_only)
     {
-#ifdef SUPPORT_TLS
+#ifndef DISABLE_TLS
     if (cutthrough.is_tls)
       tls_close(cutthrough.cctx.tls_ctx, TLS_NO_SHUTDOWN);
 #endif
@@ -5117,7 +5117,7 @@ where they are locally interpreted. [The new draft "821" is more explicit on
 this, Jan 1999.] We know the syntax is valid, so this can be done by simply
 removing quoting backslashes and any unquoted doublequotes. */
 
-t = addr->cc_local_part = store_get(len+1);
+t = addr->cc_local_part = store_get(len+1, is_tainted(address));
 while(len-- > 0)
   {
   int c = *address++;
@@ -5160,7 +5160,7 @@ if (percent_hack_domains)
 
   if (new_address)
     {
-    address_item *new_parent = store_get(sizeof(address_item));
+    address_item *new_parent = store_get(sizeof(address_item), FALSE);
     *new_parent = *addr;
     addr->parent = new_parent;
     new_parent->child_count = 1;
@@ -5486,6 +5486,25 @@ while ((addr = *anchor))
 
 
 
+/************************************************/
+
+static void
+print_dsn_addr_action(FILE * f, address_item * addr,
+  uschar * action, uschar * status)
+{
+address_item * pa;
+
+if (addr->dsn_orcpt)
+  fprintf(f,"Original-Recipient: %s\n", addr->dsn_orcpt);
+
+for (pa = addr; pa->parent; ) pa = pa->parent;
+fprintf(f, "Action: %s\n"
+    "Final-Recipient: rfc822;%s\n"
+    "Status: %s\n",
+  action, pa->address, status);
+}
+
+
 /*************************************************
 *              Deliver one message               *
 *************************************************/
@@ -6009,8 +6028,8 @@ else if (system_filter && process_recipients != RECIP_FAIL_TIMEOUT)
 
   if (addr_new)
     {
-    int uid = (system_filter_uid_set)? system_filter_uid : geteuid();
-    int gid = (system_filter_gid_set)? system_filter_gid : getegid();
+    int uid = system_filter_uid_set ? system_filter_uid : geteuid();
+    int gid = system_filter_gid_set ? system_filter_gid : getegid();
 
     /* The text "system-filter" is tested in transport_set_up_command() and in
     set_up_shell_command() in the pipe transport, to enable them to permit
@@ -6084,6 +6103,9 @@ else if (system_filter && process_recipients != RECIP_FAIL_TIMEOUT)
           if (!tmp)
             p->message = string_sprintf("failed to expand \"%s\" as a "
               "system filter transport name", tpname);
+         if (is_tainted(tmp))
+            p->message = string_sprintf("attempt to used tainted value '%s' for"
+             "transport '%s' as a system filter", tmp, tpname);
           tpname = tmp;
           }
         else
@@ -6171,7 +6193,7 @@ if (process_recipients != RECIP_IGNORE)
          to be passed on to other DSN enabled MTAs */
       new->dsn_flags = r->dsn_flags & rf_dsnflags;
       new->dsn_orcpt = r->orcpt;
-      DEBUG(D_deliver) debug_printf("DSN: set orcpt: %s  flags: %d\n",
+      DEBUG(D_deliver) debug_printf("DSN: set orcpt: %s  flags: 0x%x\n",
        new->dsn_orcpt ? new->dsn_orcpt : US"", new->dsn_flags);
 
       switch (process_recipients)
@@ -6244,7 +6266,7 @@ if (process_recipients != RECIP_IGNORE)
         }
 
 #ifndef DISABLE_EVENT
-      if (process_recipients != RECIP_ACCEPT)
+      if (process_recipients != RECIP_ACCEPT && event_action)
        {
        uschar * save_local =  deliver_localpart;
        const uschar * save_domain = deliver_domain;
@@ -6392,10 +6414,8 @@ while (addr_new)           /* Loop until all addresses dealt with */
       keep piling '>' characters on the front. */
 
       if (addr->address[0] == '>')
-        {
         while (tree_search(tree_duplicates, addr->unique))
           addr->unique = string_sprintf(">%s", addr->unique);
-        }
 
       else if ((tnode = tree_search(tree_duplicates, addr->unique)))
         {
@@ -6713,7 +6733,7 @@ while (addr_new)           /* Loop until all addresses dealt with */
       (void)post_process_one(addr, DEFER, LOG_MAIN, EXIM_DTYPE_ROUTER, 0);
 
       /* For remote-retry errors (here and just above) that we've not yet
-      hit the rery time, use the error recorded in the retry database
+      hit the retry time, use the error recorded in the retry database
       as info in the warning message.  This lets us send a message even
       when we're not failing on a fresh attempt.  We assume that this
       info is not sensitive. */
@@ -6803,8 +6823,8 @@ while (addr_new)           /* Loop until all addresses dealt with */
          &addr_succeed, v_none)) == DEFER)
       retry_add_item(addr,
         addr->router->retry_use_local_part
-        ? string_sprintf("R:%s@%s", addr->local_part, addr->domain)
-       : string_sprintf("R:%s", addr->domain),
+         ? string_sprintf("R:%s@%s", addr->local_part, addr->domain)
+         : string_sprintf("R:%s", addr->domain),
        0);
 
     /* Otherwise, if there is an existing retry record in the database, add
@@ -7269,38 +7289,38 @@ else if (!f.dont_deliver)
 /* Send DSN for successful messages if requested */
 addr_senddsn = NULL;
 
-for (addr_dsntmp = addr_succeed; addr_dsntmp; addr_dsntmp = addr_dsntmp->next)
+for (address_item * a = addr_succeed; a; a = a->next)
   {
   /* af_ignore_error not honored here. it's not an error */
   DEBUG(D_deliver) debug_printf("DSN: processing router : %s\n"
       "DSN: processing successful delivery address: %s\n"
       "DSN: Sender_address: %s\n"
-      "DSN: orcpt: %s  flags: %d\n"
+      "DSN: orcpt: %s  flags: 0x%x\n"
       "DSN: envid: %s  ret: %d\n"
       "DSN: Final recipient: %s\n"
       "DSN: Remote SMTP server supports DSN: %d\n",
-      addr_dsntmp->router ? addr_dsntmp->router->name : US"(unknown)",
-      addr_dsntmp->address,
+      a->router ? a->router->name : US"(unknown)",
+      a->address,
       sender_address,
-      addr_dsntmp->dsn_orcpt ? addr_dsntmp->dsn_orcpt : US"NULL",
-      addr_dsntmp->dsn_flags,
+      a->dsn_orcpt ? a->dsn_orcpt : US"NULL",
+      a->dsn_flags,
       dsn_envid ? dsn_envid : US"NULL", dsn_ret,
-      addr_dsntmp->address,
-      addr_dsntmp->dsn_aware
+      a->address,
+      a->dsn_aware
       );
 
   /* send report if next hop not DSN aware or a router flagged "last DSN hop"
      and a report was requested */
-  if (  (  addr_dsntmp->dsn_aware != dsn_support_yes
-       || addr_dsntmp->dsn_flags & rf_dsnlasthop
+  if (  (  a->dsn_aware != dsn_support_yes
+       || a->dsn_flags & rf_dsnlasthop
         )
-     && addr_dsntmp->dsn_flags & rf_notify_success
+     && a->dsn_flags & rf_notify_success
      )
     {
     /* copy and relink address_item and send report with all of them at once later */
     address_item * addr_next = addr_senddsn;
-    addr_senddsn = store_get(sizeof(address_item));
-    *addr_senddsn = *addr_dsntmp;
+    addr_senddsn = store_get(sizeof(address_item), FALSE);
+    *addr_senddsn = *a;
     addr_senddsn->next = addr_next;
     }
   else
@@ -7342,8 +7362,8 @@ if (addr_senddsn)
     if (errors_reply_to)
       fprintf(f, "Reply-To: %s\n", errors_reply_to);
 
+    moan_write_from(f);
     fprintf(f, "Auto-Submitted: auto-generated\n"
-       "From: Mail Delivery System <Mailer-Daemon@%s>\n"
        "To: %s\n"
        "Subject: Delivery Status Notification\n"
        "Content-Type: multipart/report; report-type=delivery-status; boundary=%s\n"
@@ -7354,14 +7374,13 @@ if (addr_senddsn)
 
        "This message was created automatically by mail delivery software.\n"
        " ----- The following addresses had successful delivery notifications -----\n",
-      qualify_domain_sender, sender_address, bound, bound);
+      sender_address, bound, bound);
 
-    for (addr_dsntmp = addr_senddsn; addr_dsntmp;
-        addr_dsntmp = addr_dsntmp->next)
+    for (address_item * a = addr_senddsn; a; a = a->next)
       fprintf(f, "<%s> (relayed %s)\n\n",
-       addr_dsntmp->address,
-       addr_dsntmp->dsn_flags & rf_dsnlasthop ? "via non DSN router"
-       : addr_dsntmp->dsn_aware == dsn_support_no ? "to non-DSN-aware mailer"
+       a->address,
+       a->dsn_flags & rf_dsnlasthop ? "via non DSN router"
+       : a->dsn_aware == dsn_support_no ? "to non-DSN-aware mailer"
        : "via non \"Remote SMTP\" router"
        );
 
@@ -7380,24 +7399,18 @@ if (addr_senddsn)
       }
     fputc('\n', f);
 
-    for (addr_dsntmp = addr_senddsn;
-        addr_dsntmp;
-        addr_dsntmp = addr_dsntmp->next)
+    for (address_item * a = addr_senddsn; a; a = a->next)
       {
-      if (addr_dsntmp->dsn_orcpt)
-        fprintf(f,"Original-Recipient: %s\n", addr_dsntmp->dsn_orcpt);
+      host_item * hu;
 
-      fprintf(f, "Action: delivered\n"
-         "Final-Recipient: rfc822;%s\n"
-         "Status: 2.0.0\n",
-       addr_dsntmp->address);
+      print_dsn_addr_action(f, a, US"delivered", US"2.0.0");
 
-      if (addr_dsntmp->host_used && addr_dsntmp->host_used->name)
+      if ((hu = a->host_used) && hu->name)
         fprintf(f, "Remote-MTA: dns; %s\nDiagnostic-Code: smtp; 250 Ok\n\n",
-         addr_dsntmp->host_used->name);
+         hu->name);
       else
        fprintf(f, "Diagnostic-Code: X-Exim; relayed via non %s router\n\n",
-         addr_dsntmp->dsn_flags & rf_dsnlasthop ? "DSN" : "SMTP");
+         a->dsn_flags & rf_dsnlasthop ? "DSN" : "SMTP");
       }
 
     fprintf(f, "--%s\nContent-type: text/rfc822-headers\n\n", bound);
@@ -7480,7 +7493,8 @@ while (addr_failed)
   mark the recipient done. */
 
   if (  addr_failed->prop.ignore_error
-     || addr_failed->dsn_flags & (rf_dsnflags & ~rf_notify_failure)
+     ||    addr_failed->dsn_flags & rf_dsnflags
+       && !(addr_failed->dsn_flags & rf_notify_failure)
      )
     {
     addr = addr_failed;
@@ -7490,11 +7504,13 @@ while (addr_failed)
 #ifndef DISABLE_EVENT
     msg_event_raise(US"msg:fail:delivery", addr);
 #endif
-    log_write(0, LOG_MAIN, "%s%s%s%s: error ignored",
+    log_write(0, LOG_MAIN, "%s%s%s%s: error ignored%s",
       addr->address,
       !addr->parent ? US"" : US" <",
       !addr->parent ? US"" : addr->parent->address,
-      !addr->parent ? US"" : US">");
+      !addr->parent ? US"" : US">",
+      addr->prop.ignore_error
+      ? US"" : US": RFC 3461 DSN, failure notify not requested");
 
     address_done(addr, logtod);
     child_done(addr, logtod);
@@ -7775,10 +7791,9 @@ wording. */
       for (addr = handled_addr; addr; addr = addr->next)
         {
        host_item * hu;
-        fprintf(fp, "Action: failed\n"
-           "Final-Recipient: rfc822;%s\n"
-           "Status: 5.0.0\n",
-           addr->address);
+
+       print_dsn_addr_action(fp, addr, US"failed", US"5.0.0");
+
         if ((hu = addr->host_used) && hu->name)
          {
          fprintf(fp, "Remote-MTA: dns; %s\n", hu->name);
@@ -8268,13 +8283,9 @@ else if (addr_defer != (address_item *)(+1))
 
         /* List the addresses, with error information if allowed */
 
-        /* store addr_defer for machine readable part */
-        address_item *addr_dsndefer = addr_defer;
         fputc('\n', f);
-        while (addr_defer)
+       for (address_item * addr = addr_defer; addr; addr = addr->next)
           {
-          address_item *addr = addr_defer;
-          addr_defer = addr->next;
           if (print_address_information(addr, f, US"  ", US"\n    ", US""))
             print_address_error(addr, f, US"Delay reason: ");
           fputc('\n', f);
@@ -8317,20 +8328,16 @@ else if (addr_defer != (address_item *)(+1))
           }
         fputc('\n', f);
 
-        for ( ; addr_dsndefer; addr_dsndefer = addr_dsndefer->next)
+       for (address_item * addr = addr_defer; addr; addr = addr->next)
           {
-          if (addr_dsndefer->dsn_orcpt)
-            fprintf(f, "Original-Recipient: %s\n", addr_dsndefer->dsn_orcpt);
-
-          fprintf(f, "Action: delayed\n"
-             "Final-Recipient: rfc822;%s\n"
-             "Status: 4.0.0\n",
-           addr_dsndefer->address);
-          if (addr_dsndefer->host_used && addr_dsndefer->host_used->name)
+         host_item * hu;
+
+         print_dsn_addr_action(f, addr, US"delayed", US"4.0.0");
+
+          if ((hu = addr->host_used) && hu->name)
             {
-            fprintf(f, "Remote-MTA: dns; %s\n",
-                   addr_dsndefer->host_used->name);
-            print_dsn_diagnostic_code(addr_dsndefer, f);
+            fprintf(f, "Remote-MTA: dns; %s\n", hu->name);
+            print_dsn_diagnostic_code(addr, f);
             }
          fputc('\n', f);
           }
@@ -8513,7 +8520,7 @@ if (!regex_SIZE) regex_SIZE =
 if (!regex_AUTH) regex_AUTH =
   regex_must_compile(AUTHS_REGEX, FALSE, TRUE);
 
-#ifdef SUPPORT_TLS
+#ifndef DISABLE_TLS
 if (!regex_STARTTLS) regex_STARTTLS =
   regex_must_compile(US"\\n250[\\s\\-]STARTTLS(\\s|\\n|$)", FALSE, TRUE);
 #endif
@@ -8537,7 +8544,7 @@ if (!regex_DSN) regex_DSN  =
 if (!regex_IGNOREQUOTA) regex_IGNOREQUOTA =
   regex_must_compile(US"\\n250[\\s\\-]IGNOREQUOTA(\\s|\\n|$)", FALSE, TRUE);
 
-#ifdef EXPERIMENTAL_PIPE_CONNECT
+#ifdef SUPPORT_PIPE_CONNECT
 if (!regex_EARLY_PIPE) regex_EARLY_PIPE =
   regex_must_compile(US"\\n250[\\s\\-]" EARLY_PIPE_FEATURE_NAME "(\\s|\\n|$)", FALSE, TRUE);
 #endif
@@ -8603,7 +8610,7 @@ if (cutthrough.cctx.sock >= 0 && cutthrough.callout_hold_only)
   smtp_peer_options = cutthrough.peer_options;
   continue_sequence = 0;
 
-#ifdef SUPPORT_TLS
+#ifndef DISABLE_TLS
   if (cutthrough.is_tls)
     {
     int pfd[2], pid;
@@ -8646,7 +8653,7 @@ else
   }
 return;                /* compiler quietening; control does not reach here. */
 
-#ifdef SUPPORT_TLS
+#ifndef DISABLE_TLS
 fail:
   log_write(0,
     LOG_MAIN | (exec_type == CEE_EXEC_EXIT ? LOG_PANIC : LOG_PANIC_DIE),