Rename substructure for ease of debugging
[exim.git] / src / src / deliver.c
index a0c48d652e7666b32b6c66f89df6ad93651d432a..e25de7eb82653cc9c106317166bf60d2d7733550 100644 (file)
@@ -127,7 +127,7 @@ deliver_set_expansions(address_item *addr)
 {
 if (addr == NULL)
   {
-  uschar ***p = address_expansions;
+  const uschar ***p = address_expansions;
   while (*p != NULL) **p++ = NULL;
   return;
   }
@@ -149,9 +149,9 @@ else
   }
 
 deliver_recipients = addr;
-deliver_address_data = addr->p.address_data;
-deliver_domain_data = addr->p.domain_data;
-deliver_localpart_data = addr->p.localpart_data;
+deliver_address_data = addr->prop.address_data;
+deliver_domain_data = addr->prop.domain_data;
+deliver_localpart_data = addr->prop.localpart_data;
 
 /* These may be unset for multiple addresses */
 
@@ -718,7 +718,7 @@ d_tlslog(uschar * s, int * sizep, int * ptrp, address_item * addr)
 
 #ifdef EXPERIMENTAL_EVENT
 uschar *
-event_raise(uschar * action, uschar * event, uschar * ev_data)
+event_raise(uschar * action, const uschar * event, uschar * ev_data)
 {
 uschar * s;
 if (action)
@@ -752,11 +752,11 @@ return NULL;
 }
 
 static void
-msg_event_raise(uschar * event, address_item * addr)
+msg_event_raise(const uschar * event, const address_item * addr)
 {
-uschar * save_domain = deliver_domain;
+const uschar * save_domain = deliver_domain;
 uschar * save_local =  deliver_localpart;
-uschar * save_host =   deliver_host;
+const uschar * save_host = deliver_host;
 
 if (!addr->transport)
   return;
@@ -817,12 +817,16 @@ else
   s = string_append(s, &size, &ptr, 2, US"> ", log_address);
   }
 
+if (log_extra_selector & LX_incoming_interface  &&  sending_ip_address)
+  s = string_append(s, &size, &ptr, 3, US" I=[", sending_ip_address, US"]");
+  /* for the port:  string_sprintf("%d", sending_port) */
+
 if ((log_extra_selector & LX_sender_on_delivery) != 0  ||  msg)
   s = string_append(s, &size, &ptr, 3, US" F=<", sender_address, US">");
 
 #ifdef EXPERIMENTAL_SRS
-if(addr->p.srs_sender)
-  s = string_append(s, &size, &ptr, 3, US" SRS=<", addr->p.srs_sender, US">");
+if(addr->prop.srs_sender)
+  s = string_append(s, &size, &ptr, 3, US" SRS=<", addr->prop.srs_sender, US">");
 #endif
 
 /* You might think that the return path must always be set for a successful
@@ -907,11 +911,12 @@ if (log_extra_selector & LX_smtp_confirmation &&
     addr->message &&
     (addr->host_used || Ustrcmp(addr->transport->driver_name, "lmtp") == 0))
   {
-  int i;
+  unsigned i;
+  unsigned lim = big_buffer_size < 1024 ? big_buffer_size : 1024;
   uschar *p = big_buffer;
   uschar *ss = addr->message;
   *p++ = '\"';
-  for (i = 0; i < 256 && ss[i] != 0; i++)      /* limit logged amount */
+  for (i = 0; i < lim && ss[i] != 0; i++)      /* limit logged amount */
     {
     if (ss[i] == '\"' || ss[i] == '\\') *p++ = '\\'; /* quote \ and " */
     *p++ = ss[i];
@@ -1014,7 +1019,10 @@ malformed, it won't ever have gone near LDAP.) */
 
 if (addr->message != NULL)
   {
-  addr->message = string_printing(addr->message);
+  const uschar * s = string_printing(addr->message);
+  if (s != addr->message)
+    addr->message = US s;
+    /* deconst cast ok as string_printing known to have alloc'n'copied */
   if (((Ustrstr(addr->message, "failed to expand") != NULL) || (Ustrstr(addr->message, "expansion of ") != NULL)) &&
       (Ustrstr(addr->message, "mysql") != NULL ||
        Ustrstr(addr->message, "pgsql") != NULL ||
@@ -1071,11 +1079,12 @@ if (addr->return_file >= 0 && addr->return_filename != NULL)
         if (s != NULL)
           {
           uschar *p = big_buffer + Ustrlen(big_buffer);
+         const uschar * sp;
           while (p > big_buffer && isspace(p[-1])) p--;
           *p = 0;
-          s = string_printing(big_buffer);
+          sp = string_printing(big_buffer);
           log_write(0, LOG_MAIN, "<%s>: %s transport output: %s",
-            addr->address, tb->name, s);
+            addr->address, tb->name, sp);
           }
         (void)fclose(f);
         }
@@ -1084,7 +1093,7 @@ if (addr->return_file >= 0 && addr->return_filename != NULL)
     /* Handle returning options, but only if there is an address to return
     the text to. */
 
-    if (sender_address[0] != 0 || addr->p.errors_address != NULL)
+    if (sender_address[0] != 0 || addr->prop.errors_address != NULL)
       {
       if (tb->return_output)
         {
@@ -1301,7 +1310,7 @@ else
 
   if (!testflag(addr, af_ignore_error) &&
       (addr->special_action == SPECIAL_FREEZE ||
-        (sender_address[0] == 0 && addr->p.errors_address == NULL)
+        (sender_address[0] == 0 && addr->prop.errors_address == NULL)
       ))
     {
     frozen_info = (addr->special_action == SPECIAL_FREEZE)? US"" :
@@ -1801,11 +1810,11 @@ transport_instance *tp = addr->transport;
 /* Set up the return path from the errors or sender address. If the transport
 has its own return path setting, expand it and replace the existing value. */
 
-if(addr->p.errors_address != NULL)
-  return_path = addr->p.errors_address;
+if(addr->prop.errors_address != NULL)
+  return_path = addr->prop.errors_address;
 #ifdef EXPERIMENTAL_SRS
-else if(addr->p.srs_sender != NULL)
-  return_path = addr->p.srs_sender;
+else if(addr->prop.srs_sender != NULL)
+  return_path = addr->prop.srs_sender;
 #endif
 else
   return_path = sender_address;
@@ -2417,9 +2426,9 @@ while (addr_local != NULL)
         (addr->flags & (af_pfr|af_file)) == (next->flags & (af_pfr|af_file)) &&
         (!uses_lp  || Ustrcmp(next->local_part, addr->local_part) == 0) &&
         (!uses_dom || Ustrcmp(next->domain, addr->domain) == 0) &&
-        same_strings(next->p.errors_address, addr->p.errors_address) &&
-        same_headers(next->p.extra_headers, addr->p.extra_headers) &&
-        same_strings(next->p.remove_headers, addr->p.remove_headers) &&
+        same_strings(next->prop.errors_address, addr->prop.errors_address) &&
+        same_headers(next->prop.extra_headers, addr->prop.extra_headers) &&
+        same_strings(next->prop.remove_headers, addr->prop.remove_headers) &&
         same_ugid(tp, addr, next) &&
         ((addr->host_list == NULL && next->host_list == NULL) ||
          (addr->host_list != NULL && next->host_list != NULL &&
@@ -2775,7 +2784,7 @@ sort_remote_deliveries(void)
 {
 int sep = 0;
 address_item **aptr = &addr_remote;
-uschar *listptr = remote_sort_domains;
+const uschar *listptr = remote_sort_domains;
 uschar *pattern;
 uschar patbuf[256];
 
@@ -2790,7 +2799,7 @@ while (*aptr != NULL &&
     {
     address_item **next;
     deliver_domain = (*aptr)->domain;   /* set $domain */
-    if (match_isinlist(deliver_domain, &pattern, UCHAR_MAX+1,
+    if (match_isinlist(deliver_domain, (const uschar **)&pattern, UCHAR_MAX+1,
           &domainlist_anchor, NULL, MCL_DOMAIN, TRUE, NULL) == OK)
       {
       aptr = &((*aptr)->next);
@@ -2800,7 +2809,7 @@ while (*aptr != NULL &&
     next = &((*aptr)->next);
     while (*next != NULL &&
            (deliver_domain = (*next)->domain,  /* Set $domain */
-            match_isinlist(deliver_domain, &pattern, UCHAR_MAX+1,
+            match_isinlist(deliver_domain, (const uschar **)&pattern, UCHAR_MAX+1,
               &domainlist_anchor, NULL, MCL_DOMAIN, TRUE, NULL)) != OK)
       next = &((*next)->next);
 
@@ -3219,6 +3228,14 @@ while (!done)
     addr = addr->next;
     break;
 
+    /* Local interface address/port */
+    case 'I':
+    if (*ptr) sending_ip_address = string_copy(ptr);
+    while (*ptr++) ;
+    if (*ptr) sending_port = atoi(CS ptr);
+    while (*ptr++) ;
+    break;
+
     /* Z marks the logical end of the data. It is followed by '0' if
     continue_transport was NULL at the end of transporting, otherwise '1'.
     We need to know when it becomes NULL during a delivery down a passed SMTP
@@ -3933,13 +3950,13 @@ for (delivery_count = 0; addr_remote != NULL; delivery_count++)
     if (  (multi_domain || Ustrcmp(next->domain, addr->domain) == 0)
        && tp == next->transport
        && same_hosts(next->host_list, addr->host_list)
-       && same_strings(next->p.errors_address, addr->p.errors_address)
-       && same_headers(next->p.extra_headers, addr->p.extra_headers)
+       && same_strings(next->prop.errors_address, addr->prop.errors_address)
+       && same_headers(next->prop.extra_headers, addr->prop.extra_headers)
        && same_ugid(tp, next, addr)
-       && (  next->p.remove_headers == addr->p.remove_headers
-         || (  next->p.remove_headers != NULL
-            && addr->p.remove_headers != NULL
-            && Ustrcmp(next->p.remove_headers, addr->p.remove_headers) == 0
+       && (  next->prop.remove_headers == addr->prop.remove_headers
+         || (  next->prop.remove_headers
+            && addr->prop.remove_headers
+            && Ustrcmp(next->prop.remove_headers, addr->prop.remove_headers) == 0
          )  )
        && (  !multi_domain
          || (  (
@@ -3983,11 +4000,11 @@ for (delivery_count = 0; addr_remote != NULL; delivery_count++)
   /* Compute the return path, expanding a new one if required. The old one
   must be set first, as it might be referred to in the expansion. */
 
-  if(addr->p.errors_address != NULL)
-    return_path = addr->p.errors_address;
+  if(addr->prop.errors_address != NULL)
+    return_path = addr->prop.errors_address;
 #ifdef EXPERIMENTAL_SRS
-  else if(addr->p.srs_sender != NULL)
-    return_path = addr->p.srs_sender;
+  else if(addr->prop.srs_sender != NULL)
+    return_path = addr->prop.srs_sender;
 #endif
   else
     return_path = sender_address;
@@ -4430,6 +4447,18 @@ for (delivery_count = 0; addr_remote != NULL; delivery_count++)
       rmt_dlv_checked_write(fd, 'A', '0', big_buffer, ptr - big_buffer);
       }
 
+    /* Local interface address/port */
+    if (log_extra_selector & LX_incoming_interface  &&  sending_ip_address)
+      {
+      uschar * ptr = big_buffer;
+      sprintf(CS ptr, "%.128s", sending_ip_address);
+      while(*ptr++);
+      sprintf(CS ptr, "%d", sending_port);
+      while(*ptr++);
+
+      rmt_dlv_checked_write(fd, 'I', '0', big_buffer, ptr - big_buffer);
+      }
+
     /* Add termination flag, close the pipe, and that's it. The character
     after 'Z' indicates whether continue_transport is now NULL or not.
     A change from non-NULL to NULL indicates a problem with a continuing
@@ -4556,7 +4585,7 @@ if (percent_hack_domains != NULL)
 
   deliver_domain = addr->domain;  /* set $domain */
 
-  while ((rc = match_isinlist(deliver_domain, &percent_hack_domains, 0,
+  while ((rc = match_isinlist(deliver_domain, (const uschar **)&percent_hack_domains, 0,
            &domainlist_anchor, addr->domain_cache, MCL_DOMAIN, TRUE, NULL))
              == OK &&
          (t = Ustrrchr(local_part, '%')) != NULL)
@@ -5564,7 +5593,11 @@ if (process_recipients != RECIP_IGNORE)
       {
       recipient_item *r = recipients_list + i;
       address_item *new = deliver_make_addr(r->address, FALSE);
-      new->p.errors_address = r->errors_to;
+      new->prop.errors_address = r->errors_to;
+#ifdef EXPERIMENTAL_INTERNATIONAL
+      new->prop.utf8 = message_smtputf8;
+      DEBUG(D_deliver) debug_printf("utf8: %c\n", message_smtputf8 ? 'T':'F');
+#endif
 
       if (r->pno >= 0)
         new->onetime_parent = recipients_list[r->pno].address;
@@ -5648,7 +5681,7 @@ if (process_recipients != RECIP_IGNORE)
       if (process_recipients != RECIP_ACCEPT)
        {
        uschar * save_local =  deliver_localpart;
-       uschar * save_domain = deliver_domain;
+       const uschar * save_domain = deliver_domain;
 
        deliver_localpart = expand_string(
                      string_sprintf("${local_part:%s}", new->address));
@@ -5913,7 +5946,7 @@ while (addr_new != NULL)           /* Loop until all addresses dealt with */
 
     deliver_domain = addr->domain;  /* set $domain */
     if (!forced && hold_domains != NULL &&
-         (rc = match_isinlist(addr->domain, &hold_domains, 0,
+         (rc = match_isinlist(addr->domain, (const uschar **)&hold_domains, 0,
            &domainlist_anchor, addr->domain_cache, MCL_DOMAIN, TRUE,
            NULL)) != FAIL)
       {
@@ -6120,7 +6153,7 @@ while (addr_new != NULL)           /* Loop until all addresses dealt with */
       addr_route = addr->next;
 
       deliver_domain = addr->domain;  /* set $domain */
-      if ((rc = match_isinlist(addr->domain, &queue_domains, 0,
+      if ((rc = match_isinlist(addr->domain, (const uschar **)&queue_domains, 0,
             &domainlist_anchor, addr->domain_cache, MCL_DOMAIN, TRUE, NULL))
               != OK)
         {
@@ -6153,15 +6186,15 @@ while (addr_new != NULL)           /* Loop until all addresses dealt with */
     {
     int rc;
     address_item *addr = addr_route;
-    uschar *old_domain = addr->domain;
+    const uschar *old_domain = addr->domain;
     uschar *old_unique = addr->unique;
     addr_route = addr->next;
     addr->next = NULL;
 
     /* Just in case some router parameter refers to it. */
 
-    return_path = (addr->p.errors_address != NULL)?
-      addr->p.errors_address : sender_address;
+    return_path = (addr->prop.errors_address != NULL)?
+      addr->prop.errors_address : sender_address;
 
     /* If a router defers an address, add a retry item. Whether or not to
     use the local part in the key is a property of the router. */
@@ -6231,8 +6264,8 @@ while (addr_new != NULL)           /* Loop until all addresses dealt with */
 
     if (addr_remote == addr &&
         addr->router->same_domain_copy_routing &&
-        addr->p.extra_headers == NULL &&
-        addr->p.remove_headers == NULL &&
+        addr->prop.extra_headers == NULL &&
+        addr->prop.remove_headers == NULL &&
         old_domain == addr->domain)
       {
       address_item **chain = &addr_route;
@@ -6259,7 +6292,7 @@ while (addr_new != NULL)           /* Loop until all addresses dealt with */
         addr2->transport = addr->transport;
         addr2->host_list = addr->host_list;
         addr2->fallback_hosts = addr->fallback_hosts;
-        addr2->p.errors_address = addr->p.errors_address;
+        addr2->prop.errors_address = addr->prop.errors_address;
         copyflag(addr2, addr, af_hide_child | af_local_host_removed);
 
         DEBUG(D_deliver|D_route)
@@ -6631,29 +6664,36 @@ else if (!dont_deliver) retry_update(&addr_defer, &addr_failed, &addr_succeed);
 addr_dsntmp = addr_succeed;
 addr_senddsn = NULL;
 
-while(addr_dsntmp != NULL)
+while(addr_dsntmp)
   {
-  DEBUG(D_deliver)
-    debug_printf("DSN: processing router : %s\n", addr_dsntmp->router->name);
-
-  DEBUG(D_deliver)
-    debug_printf("DSN: processing successful delivery address: %s\n", addr_dsntmp->address);
-
   /* af_ignore_error not honored here. it's not an error */
-
-  DEBUG(D_deliver) debug_printf("DSN: Sender_address: %s\n", sender_address);
-  DEBUG(D_deliver) debug_printf("DSN: orcpt: %s  flags: %d\n", addr_dsntmp->dsn_orcpt, addr_dsntmp->dsn_flags);
-  DEBUG(D_deliver) debug_printf("DSN: envid: %s  ret: %d\n", dsn_envid, dsn_ret);
-  DEBUG(D_deliver) debug_printf("DSN: Final recipient: %s\n", addr_dsntmp->address);
-  DEBUG(D_deliver) debug_printf("DSN: Remote SMTP server supports DSN: %d\n", addr_dsntmp->dsn_aware);
+  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: envid: %s  ret: %d\n"
+      "DSN: Final recipient: %s\n"
+      "DSN: Remote SMTP server supports DSN: %d\n",
+      addr_dsntmp->router->name,
+      addr_dsntmp->address,
+      sender_address,
+      addr_dsntmp->dsn_orcpt, addr_dsntmp->dsn_flags,
+      dsn_envid, dsn_ret,
+      addr_dsntmp->address,
+      addr_dsntmp->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) != 0))
-      &&
-      (((addr_dsntmp->dsn_flags & rf_dsnflags) != 0) &&
-        ((addr_dsntmp->dsn_flags & rf_notify_success) != 0)))
+  if (  (  addr_dsntmp->dsn_aware != dsn_support_yes
+       || addr_dsntmp->dsn_flags & rf_dsnlasthop
+        )
+     && addr_dsntmp->dsn_flags & rf_dsnflags
+     && addr_dsntmp->dsn_flags & rf_notify_success
+     )
     {
     /* copy and relink address_item and send report with all of them at once later */
     address_item *addr_next;
@@ -6663,14 +6703,12 @@ while(addr_dsntmp != NULL)
     addr_senddsn->next = addr_next;
     }
   else
-    {
-      DEBUG(D_deliver) debug_printf("DSN: *** NOT SENDING DSN SUCCESS Message ***\n"); 
-    }
+    DEBUG(D_deliver) debug_printf("DSN: not sending DSN success message\n"); 
 
   addr_dsntmp = addr_dsntmp->next;
   }
 
-if (addr_senddsn != NULL)
+if (addr_senddsn)
   {
   pid_t pid;
   int fd;
@@ -6686,8 +6724,7 @@ if (addr_senddsn != NULL)
       "create child process to send failure message: %s", getpid(),
       getppid(), strerror(errno));
 
-      DEBUG(D_deliver) debug_printf("DSN: child_open_exim failed\n");
-
+    DEBUG(D_deliver) debug_printf("DSN: child_open_exim failed\n");
     }    
   else  /* Creation of child succeeded */
     {
@@ -6696,7 +6733,8 @@ if (addr_senddsn != NULL)
     int topt = topt_add_return_path | topt_no_body;
     uschar * bound;
      
-    DEBUG(D_deliver) debug_printf("sending error message to: %s\n", sender_address);
+    DEBUG(D_deliver)
+      debug_printf("sending error message to: %s\n", sender_address);
   
     /* build unique id for MIME boundary */
     bound = string_sprintf(TIME_T_FMT "-eximdsn-%d", time(NULL), rand());
@@ -6719,9 +6757,8 @@ if (addr_senddsn != NULL)
        " ----- The following addresses had successful delivery notifications -----\n",
       qualify_domain_sender, sender_address, bound, bound);
 
-    addr_dsntmp = addr_senddsn;
-    while(addr_dsntmp)
-      {
+    for (addr_dsntmp = addr_senddsn; addr_dsntmp;
+        addr_dsntmp = addr_dsntmp->next)
       fprintf(f, "<%s> (relayed %s)\n\n",
        addr_dsntmp->address,
        (addr_dsntmp->dsn_flags & rf_dsnlasthop) == 1
@@ -6730,15 +6767,14 @@ if (addr_senddsn != NULL)
          ? "to non-DSN-aware mailer"
          : "via non \"Remote SMTP\" router"
        );
-      addr_dsntmp = addr_dsntmp->next;
-      }
+
     fprintf(f, "--%s\n"
        "Content-type: message/delivery-status\n\n"
        "Reporting-MTA: dns; %s\n",
       bound, smtp_active_hostname);
 
-    if (dsn_envid != NULL) {
-      /* must be decoded from xtext: see RFC 3461:6.3a */
+    if (dsn_envid)
+      {                        /* must be decoded from xtext: see RFC 3461:6.3a */
       uschar *xdec_envid;
       if (auth_xtextdecode(dsn_envid, &xdec_envid) > 0)
         fprintf(f, "Original-Envelope-ID: %s\n", dsn_envid);
@@ -6760,12 +6796,11 @@ if (addr_senddsn != NULL)
        addr_dsntmp->address);
 
       if (addr_dsntmp->host_used && addr_dsntmp->host_used->name)
-        fprintf(f, "Remote-MTA: dns; %s\nDiagnostic-Code: smtp; 250 Ok\n",
+        fprintf(f, "Remote-MTA: dns; %s\nDiagnostic-Code: smtp; 250 Ok\n\n",
          addr_dsntmp->host_used->name);
       else
-       fprintf(f,"Diagnostic-Code: X-Exim; relayed via non %s router\n",
+       fprintf(f, "Diagnostic-Code: X-Exim; relayed via non %s router\n\n",
          (addr_dsntmp->dsn_flags & rf_dsnlasthop) == 1 ? "DSN" : "SMTP");
-      fputc('\n', f);
       }
 
     fprintf(f, "--%s\nContent-type: text/rfc822-headers\n\n", bound);
@@ -6828,10 +6863,10 @@ while (addr_failed != NULL)
   If neither of these cases obtains, something has gone wrong. Log the
   incident, but then ignore the error. */
 
-  if (sender_address[0] == 0 && addr_failed->p.errors_address == NULL)
+  if (sender_address[0] == 0 && addr_failed->prop.errors_address == NULL)
     {
-    if (!testflag(addr_failed, af_retry_timedout) &&
-        !testflag(addr_failed, af_ignore_error))
+    if (  !testflag(addr_failed, af_retry_timedout)
+       && !testflag(addr_failed, af_ignore_error))
       {
       log_write(0, LOG_MAIN|LOG_PANIC, "internal error: bounce message "
         "failure is neither frozen nor ignored (it's been ignored)");
@@ -6844,19 +6879,19 @@ while (addr_failed != NULL)
   mark the recipient done. */
 
   if (  testflag(addr_failed, af_ignore_error)
-     || (  ((addr_failed->dsn_flags & rf_dsnflags) != 0)
-        && ((addr_failed->dsn_flags & rf_notify_failure) != rf_notify_failure))
+     || (  addr_failed->dsn_flags & rf_dsnflags
+        && (addr_failed->dsn_flags & rf_notify_failure) != rf_notify_failure)
      )
-  {
+    {
     addr = addr_failed;
     addr_failed = addr->next;
     if (addr->return_filename != NULL) Uunlink(addr->return_filename);
 
     log_write(0, LOG_MAIN, "%s%s%s%s: error ignored",
       addr->address,
-      (addr->parent == NULL)? US"" : US" <",
-      (addr->parent == NULL)? US"" : addr->parent->address,
-      (addr->parent == NULL)? US"" : US">");
+      !addr->parent ? US"" : US" <",
+      !addr->parent ? US"" : addr->parent->address,
+      !addr->parent ? US"" : US">");
 
     address_done(addr, logtod);
     child_done(addr, logtod);
@@ -6872,16 +6907,12 @@ while (addr_failed != NULL)
 
   else
     {
-    bounce_recipient = (addr_failed->p.errors_address == NULL)?
-      sender_address : addr_failed->p.errors_address;
+    bounce_recipient = addr_failed->prop.errors_address
+      ? addr_failed->prop.errors_address : sender_address;
 
     /* Make a subprocess to send a message */
 
-    pid = child_open_exim(&fd);
-
-    /* Creation of child failed */
-
-    if (pid < 0)
+    if ((pid = child_open_exim(&fd)) < 0)
       log_write(0, LOG_MAIN|LOG_PANIC_DIE, "Process %d (parent %d) failed to "
         "create child process to send failure message: %s", getpid(),
         getppid(), strerror(errno));
@@ -6912,20 +6943,16 @@ while (addr_failed != NULL)
 
       paddr = &addr_failed;
       for (addr = addr_failed; addr != NULL; addr = *paddr)
-        {
-        if (Ustrcmp(bounce_recipient, (addr->p.errors_address == NULL)?
-              sender_address : addr->p.errors_address) != 0)
-          {
-          paddr = &(addr->next);      /* Not the same; skip */
-          }
-        else                          /* The same - dechain */
-          {
+        if (Ustrcmp(bounce_recipient, addr->prop.errors_address
+             ? addr->prop.errors_address : sender_address) == 0)
+          {                          /* The same - dechain */
           *paddr = addr->next;
           *pmsgchain = addr;
           addr->next = NULL;
           pmsgchain = &(addr->next);
           }
-        }
+        else
+          paddr = &addr->next;        /* Not the same; skip */
 
       /* Include X-Failed-Recipients: for automatic interpretation, but do
       not let any one header line get too long. We do this by starting a
@@ -6950,7 +6977,7 @@ while (addr_failed != NULL)
 
       /* Output the standard headers */
 
-      if (errors_reply_to != NULL)
+      if (errors_reply_to)
         fprintf(f, "Reply-To: %s\n", errors_reply_to);
       fprintf(f, "Auto-Submitted: auto-replied\n");
       moan_write_from(f);
@@ -7118,10 +7145,18 @@ wording. */
         }
 
       /* output machine readable part */
-      fprintf(f, "--%s\n"
-         "Content-type: message/delivery-status\n\n"
-         "Reporting-MTA: dns; %s\n",
-       bound, smtp_active_hostname);
+#ifdef EXPERIMENTAL_INTERNATIONAL
+      if (message_smtputf8)
+       fprintf(f, "--%s\n"
+           "Content-type: message/global-delivery-status\n\n"
+           "Reporting-MTA: dns; %s\n",
+         bound, smtp_active_hostname);
+      else
+#endif
+       fprintf(f, "--%s\n"
+           "Content-type: message/delivery-status\n\n"
+           "Reporting-MTA: dns; %s\n",
+         bound, smtp_active_hostname);
 
       if (dsn_envid)
        {
@@ -7146,6 +7181,7 @@ wording. */
            addr->host_used->name);
           print_dsn_diagnostic_code(addr, f);
           }
+       fputc('\n', f);
         }
 
       /* Now copy the message, trying to give an intelligible comment if
@@ -7166,7 +7202,7 @@ wording. */
          bounce_return_size_limit is always honored.
       */
   
-      fprintf(f, "\n--%s\n", bound);
+      fprintf(f, "--%s\n", bound);
 
       dsnlimitmsg = US"X-Exim-DSN-Information: Due to administrative limits only headers are returned";
       dsnnotifyhdr = NULL;
@@ -7195,10 +7231,16 @@ wording. */
             }
           }
   
-      if (topt & topt_no_body)
-        fprintf(f,"Content-type: text/rfc822-headers\n\n");
+#ifdef EXPERIMENTAL_INTERNATIONAL
+      if (message_smtputf8)
+       fputs(topt & topt_no_body ? "Content-type: message/global-headers\n\n"
+                                 : "Content-type: message/global\n\n",
+             f);
       else
-        fprintf(f,"Content-type: message/rfc822\n\n");
+#endif
+       fputs(topt & topt_no_body ? "Content-type: text/rfc822-headers\n\n"
+                                 : "Content-type: message/rfc822\n\n",
+             f);
 
       fflush(f);
       transport_filter_argv = NULL;   /* Just in case */
@@ -7298,11 +7340,9 @@ if (addr_defer == NULL)
           "msglog.OLD directory", spoolname);
       }
     else
-      {
       if (Uunlink(spoolname) < 0)
         log_write(0, LOG_MAIN|LOG_PANIC_DIE, "failed to unlink %s: %s",
                  spoolname, strerror(errno));
-      }
     }
 
   /* Remove the two message files. */
@@ -7376,7 +7416,8 @@ else if (addr_defer != (address_item *)(+1))
 
     if (deliver_domain != NULL)
       {
-      uschar *d = (testflag(addr, af_pfr))? addr->parent->domain : addr->domain;
+      const uschar *d = testflag(addr, af_pfr)
+       ? addr->parent->domain : addr->domain;
 
       /* The domain may be unset for an address that has never been routed
       because the system filter froze the message. */
@@ -7414,7 +7455,7 @@ else if (addr_defer != (address_item *)(+1))
         DEBUG(D_deliver) debug_printf("one_time: adding %s in place of %s\n",
           otaddr->address, otaddr->parent->address);
         receive_add_recipient(otaddr->address, t);
-        recipients_list[recipients_count-1].errors_to = otaddr->p.errors_address;
+        recipients_list[recipients_count-1].errors_to = otaddr->prop.errors_address;
         tree_add_nonrecipient(otaddr->parent->address);
         update_spool = TRUE;
         }
@@ -7426,7 +7467,7 @@ else if (addr_defer != (address_item *)(+1))
 
     if (sender_address[0] != 0)
       {
-      if (addr->p.errors_address == NULL)
+      if (addr->prop.errors_address == NULL)
         {
         if (Ustrstr(recipients, sender_address) == NULL)
           recipients = string_sprintf("%s%s%s", recipients,
@@ -7434,9 +7475,9 @@ else if (addr_defer != (address_item *)(+1))
         }
       else
         {
-        if (Ustrstr(recipients, addr->p.errors_address) == NULL)
+        if (Ustrstr(recipients, addr->prop.errors_address) == NULL)
           recipients = string_sprintf("%s%s%s", recipients,
-            (recipients[0] == 0)? "" : ",", addr->p.errors_address);
+            (recipients[0] == 0)? "" : ",", addr->prop.errors_address);
         }
       }
     }
@@ -7644,24 +7685,25 @@ else if (addr_defer != (address_item *)(+1))
           }
         fputc('\n', f);
 
-        while (addr_dsndefer)
+        for ( ; addr_dsndefer; addr_dsndefer = addr_dsndefer->next)
           {
           if (addr_dsndefer->dsn_orcpt)
-            fprintf(f,"Original-Recipient: %s\n", addr_dsndefer->dsn_orcpt);
+            fprintf(f, "Original-Recipient: %s\n", addr_dsndefer->dsn_orcpt);
 
-          fprintf(f,"Action: delayed\n");
-          fprintf(f,"Final-Recipient: rfc822;%s\n", addr_dsndefer->address);
-          fprintf(f,"Status: 4.0.0\n");
+          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)
             {
-            fprintf(f,"Remote-MTA: dns; %s\n", 
+            fprintf(f, "Remote-MTA: dns; %s\n", 
                    addr_dsndefer->host_used->name);
             print_dsn_diagnostic_code(addr_dsndefer, f);
             }
-          addr_dsndefer = addr_dsndefer->next;
+         fputc('\n', f);
           }
 
-        fprintf(f, "\n--%s\n"
+        fprintf(f, "--%s\n"
            "Content-type: text/rfc822-headers\n\n",
          bound);
 
@@ -7839,6 +7881,11 @@ if (!regex_PRDR) regex_PRDR =
   regex_must_compile(US"\\n250[\\s\\-]PRDR(\\s|\\n|$)", FALSE, TRUE);
 #endif
 
+#ifdef SUPPORT_TLS
+if (!regex_UTF8) regex_UTF8 =
+  regex_must_compile(US"\\n250[\\s\\-]SMTPUTF8(\\s|\\n|$)", FALSE, TRUE);
+#endif
+
 if (!regex_DSN) regex_DSN  =
   regex_must_compile(US"\\n250[\\s\\-]DSN(\\s|\\n|$)", FALSE, TRUE);
 
@@ -7847,6 +7894,22 @@ if (!regex_IGNOREQUOTA) regex_IGNOREQUOTA =
 }
 
 
+uschar *
+deliver_get_sender_address (uschar * id)
+{
+if (!spool_open_datafile(id))
+  return NULL;
+
+sprintf(CS spoolname, "%s-H", id);
+if (spool_read_header(spoolname, TRUE, TRUE) != spool_read_OK)
+  return NULL;
+
+(void)close(deliver_datafile);
+deliver_datafile = -1;
+
+return sender_address;
+}
+
 /* vi: aw ai sw=2
 */
 /* End of deliver.c */