Merge branch 'master' into dane
[exim.git] / src / src / deliver.c
index 32cba9a91b49f543d76ccc3f0ce0e4ff71f19acf..d00af9c11a6e5cf1c2c1a3228df7ca946165cad1 100644 (file)
@@ -141,11 +141,13 @@ the first address. */
 if (addr->host_list == NULL)
   {
   deliver_host = deliver_host_address = US"";
+  deliver_host_port = 0;
   }
 else
   {
   deliver_host = addr->host_list->name;
   deliver_host_address = addr->host_list->address;
+  deliver_host_port = addr->host_list->port;
   }
 
 deliver_recipients = addr;
@@ -697,7 +699,15 @@ d_tlslog(uschar * s, int * sizep, int * ptrp, address_item * addr)
   if ((log_extra_selector & LX_tls_certificate_verified) != 0 &&
        addr->cipher != NULL)
     s = string_append(s, sizep, ptrp, 2, US" CV=",
-      testflag(addr, af_cert_verified)? "yes":"no");
+      testflag(addr, af_cert_verified)
+      ?
+#ifdef EXPERIMENTAL_DANE
+        testflag(addr, af_dane_verified)
+      ? "dane"
+      :
+#endif
+        "yes"
+      : "no");
   if ((log_extra_selector & LX_tls_peerdn) != 0 && addr->peerdn != NULL)
     s = string_append(s, sizep, ptrp, 3, US" DN=\"",
       string_printing(addr->peerdn), US"\"");
@@ -705,6 +715,43 @@ d_tlslog(uschar * s, int * sizep, int * ptrp, address_item * addr)
 }
 #endif
 
+
+#ifdef EXPERIMENTAL_TPDA
+int
+tpda_raise_event(uschar * action, uschar * event, uschar * ev_data)
+{
+uschar * s;
+if (action)
+  {
+  DEBUG(D_deliver)
+    debug_printf("TPDA(%s): tpda_event_action=|%s| tpda_delivery_IP=%s\n",
+      event,
+      action, deliver_host_address);
+
+  tpda_event = event;
+  tpda_data =  ev_data;
+
+  if (!(s = expand_string(action)) && *expand_string_message)
+    log_write(0, LOG_MAIN|LOG_PANIC,
+      "failed to expand tpda_event_action %s in %s: %s\n",
+      event, transport_name, expand_string_message);
+
+  tpda_event = tpda_data = NULL;
+
+  /* If the expansion returns anything but an empty string, flag for
+  the caller to modify his normal processing
+  */
+  if (s && *s)
+    {
+    DEBUG(D_deliver)
+      debug_printf("TPDA(%s): event_action returned \"%s\"\n", s);
+    return DEFER;
+    }
+  }
+return OK;
+}
+#endif
+
 /* If msg is NULL this is a delivery log and logchar is used. Otherwise
 this is a nonstandard call; no two-character delivery flag is written
 but sender-host and sender are prefixed and "msg" is inserted in the log line.
@@ -728,12 +775,7 @@ have a pointer to the host item that succeeded; local deliveries can have a
 pointer to a single host item in their host list, for use by the transport. */
 
 #ifdef EXPERIMENTAL_TPDA
-  tpda_delivery_ip = NULL;     /* presume no successful remote delivery */
-  tpda_delivery_port = 0;
-  tpda_delivery_fqdn = NULL;
-  tpda_delivery_local_part = NULL;
-  tpda_delivery_domain = NULL;
-  tpda_delivery_confirmation = NULL;
+  /* presume no successful remote delivery */
   lookup_dnssec_authenticated = NULL;
 #endif
 
@@ -782,13 +824,8 @@ if ((log_extra_selector & LX_delivery_size) != 0)
 
 if (addr->transport->info->local)
   {
-  if (addr->host_list != NULL)
-    {
+  if (addr->host_list)
     s = string_append(s, &size, &ptr, 2, US" H=", addr->host_list->name);
-    #ifdef EXPERIMENTAL_TPDA
-      tpda_delivery_fqdn = addr->host_list->name;
-    #endif
-    }
   if (addr->shadow_message != NULL)
     s = string_cat(s, &size, &ptr, addr->shadow_message,
       Ustrlen(addr->shadow_message));
@@ -804,24 +841,20 @@ else
     if (continue_sequence > 1)
       s = string_cat(s, &size, &ptr, US"*", 1);
 
-    #ifdef EXPERIMENTAL_TPDA
-    tpda_delivery_ip =           addr->host_used->address;
-    tpda_delivery_port =         addr->host_used->port;
-    tpda_delivery_fqdn =         addr->host_used->name;
-    tpda_delivery_local_part =   addr->local_part;
-    tpda_delivery_domain =       addr->domain;
-    tpda_delivery_confirmation = addr->message;
+#ifdef EXPERIMENTAL_TPDA
+    deliver_host_address = addr->host_used->address;
+    deliver_host_port =    addr->host_used->port;
 
     /* DNS lookup status */
     lookup_dnssec_authenticated = addr->host_used->dnssec==DS_YES ? US"yes"
                              : addr->host_used->dnssec==DS_NO ? US"no"
                              : NULL;
-    #endif
+#endif
     }
 
-  #ifdef SUPPORT_TLS
+#ifdef SUPPORT_TLS
   s = d_tlslog(s, &size, &ptr, addr);
-  #endif
+#endif
 
   if (addr->authenticator)
     {
@@ -834,10 +867,10 @@ else
       }
     }
 
-  #ifndef DISABLE_PRDR
+#ifndef DISABLE_PRDR
   if (addr->flags & af_prdr_used)
     s = string_append(s, &size, &ptr, 1, US" PRDR");
-  #endif
+#endif
   }
 
 /* confirmation message (SMTP (host_used) and LMTP (driver_name)) */
@@ -877,19 +910,22 @@ s[ptr] = 0;
 log_write(0, flags, "%s", s);
 
 #ifdef EXPERIMENTAL_TPDA
-if (addr->transport->tpda_delivery_action)
   {
-  DEBUG(D_deliver)
-    debug_printf("  TPDA(Delivery): tpda_deliver_action=|%s| tpda_delivery_IP=%s\n",
-      addr->transport->tpda_delivery_action, tpda_delivery_ip);
-
-  router_name =    addr->router->name;
-  transport_name = addr->transport->name;
-  if (!expand_string(addr->transport->tpda_delivery_action) && *expand_string_message)
-    log_write(0, LOG_MAIN|LOG_PANIC, "failed to expand tpda_deliver_action in %s: %s\n",
-      transport_name, expand_string_message);
-  router_name = NULL;
-  transport_name = NULL;
+  uschar * save_domain = deliver_domain;
+  uschar * save_local =  deliver_localpart;
+
+  router_name =    addr->router ? addr->router->name : NULL;
+  transport_name = addr->transport ? addr->transport->name : NULL;
+  deliver_domain = addr->domain;
+  deliver_localpart = addr->local_part;
+
+  (void) tpda_raise_event(addr->transport->tpda_event_action, US"msg:delivery",
+           addr->host_used || Ustrcmp(addr->transport->driver_name, "lmtp") == 0
+           ? addr->message : NULL);
+
+  deliver_localpart = save_local;
+  deliver_domain =    save_domain;
+  router_name = transport_name = NULL;
   }
 #endif
 store_reset(reset_point);
@@ -1089,7 +1125,7 @@ if (result == OK)
     }
 
   /* Certificates for logging (via TPDA) */
-  #ifdef SUPPORT_TLS
+#ifdef SUPPORT_TLS
   tls_out.ourcert = addr->ourcert;
   addr->ourcert = NULL;
   tls_out.peercert = addr->peercert;
@@ -1098,11 +1134,11 @@ if (result == OK)
   tls_out.cipher = addr->cipher;
   tls_out.peerdn = addr->peerdn;
   tls_out.ocsp = addr->ocsp;
-  #endif
+#endif
 
   delivery_log(LOG_MAIN, addr, logchar, NULL);
 
-  #ifdef SUPPORT_TLS
+#ifdef SUPPORT_TLS
   if (tls_out.ourcert)
     {
     tls_free_cert(tls_out.ourcert);
@@ -1116,7 +1152,7 @@ if (result == OK)
   tls_out.cipher = NULL;
   tls_out.peerdn = NULL;
   tls_out.ocsp = OCSP_NOT_REQ;
-  #endif
+#endif
   }
 
 
@@ -1297,9 +1333,9 @@ else
   if (addr->host_used != NULL)
     s = d_hostlog(s, &size, &ptr, addr);
 
-  #ifdef SUPPORT_TLS
+#ifdef SUPPORT_TLS
   s = d_tlslog(s, &size, &ptr, addr);
-  #endif
+#endif
 
   if (addr->basic_errno > 0)
     s = string_append(s, &size, &ptr, 2, US": ",
@@ -1888,19 +1924,19 @@ if ((pid = fork()) == 0)
   diagnosis that it's reasonable to make them something that has to be explicitly requested.
   */
 
-  #ifdef RLIMIT_CORE
+#ifdef RLIMIT_CORE
   struct rlimit rl;
   rl.rlim_cur = 0;
   rl.rlim_max = 0;
   if (setrlimit(RLIMIT_CORE, &rl) < 0)
     {
-    #ifdef SETRLIMIT_NOT_SUPPORTED
+ifdef SETRLIMIT_NOT_SUPPORTED
     if (errno != ENOSYS && errno != ENOTSUP)
-    #endif
+endif
       log_write(0, LOG_MAIN|LOG_PANIC, "setrlimit(RLIMIT_CORE) failed: %s",
         strerror(errno));
     }
-  #endif
+#endif
 
   /* Reset the random number generator, so different processes don't all
   have the same sequence. */
@@ -2987,7 +3023,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
+#ifdef SUPPORT_TLS
     case 'X':
     if (addr == NULL) goto ADDR_MISMATCH;          /* Below, in 'A' handler */
     switch (*ptr++)
@@ -3015,17 +3051,17 @@ while (!done)
        (void) tls_import_cert(ptr, &addr->ourcert);
       break;
 
-      #ifndef DISABLE_OCSP
+ifndef DISABLE_OCSP
       case '4':
       addr->ocsp = OCSP_NOT_REQ;
       if (*ptr)
        addr->ocsp = *ptr - '0';
       break;
-      #endif
+endif
       }
     while (*ptr++);
     break;
-    #endif     /*SUPPORT_TLS*/
+#endif /*SUPPORT_TLS*/
 
     case 'C':  /* client authenticator information */
     switch (*ptr++)
@@ -3049,14 +3085,14 @@ while (!done)
     break;
 #endif
 
-    #ifdef EXPERIMENTAL_DSN
+#ifdef EXPERIMENTAL_DSN
     case 'D':
     if (addr == NULL) break;
     memcpy(&(addr->dsn_aware), ptr, sizeof(addr->dsn_aware));
     ptr += sizeof(addr->dsn_aware);
     DEBUG(D_deliver) debug_printf("DSN read: addr->dsn_aware = %d\n", addr->dsn_aware);
     break;
-    #endif
+#endif
 
     case 'A':
     if (addr == NULL)
@@ -3954,11 +3990,11 @@ for (delivery_count = 0; addr_remote != NULL; delivery_count++)
     that it can use either of them, though it prefers O_NONBLOCK, which
     distinguishes between EOF and no-more-data. */
 
-    #ifdef O_NONBLOCK
+#ifdef O_NONBLOCK
     (void)fcntl(pfd[pipe_read], F_SETFL, O_NONBLOCK);
-    #else
+#else
     (void)fcntl(pfd[pipe_read], F_SETFL, O_NDELAY);
-    #endif
+#endif
 
     /* If the maximum number of subprocesses already exist, wait for a process
     to finish. If we ran out of file descriptors, parmax will have been reduced
@@ -4125,9 +4161,12 @@ for (delivery_count = 0; addr_remote != NULL; delivery_count++)
 
       /* The certificate verification status goes into the flags */
       if (tls_out.certificate_verified) setflag(addr, af_cert_verified);
+#ifdef EXPERIMENTAL_DANE
+      if (tls_out.dane_verified)        setflag(addr, af_dane_verified);
+#endif
 
       /* Use an X item only if there's something to send */
-      #ifdef SUPPORT_TLS
+#ifdef SUPPORT_TLS
       if (addr->cipher)
         {
         ptr = big_buffer;
@@ -4163,7 +4202,7 @@ for (delivery_count = 0; addr_remote != NULL; delivery_count++)
          *ptr++ = 0;
         rmt_dlv_checked_write(fd, big_buffer, ptr - big_buffer);
        }
-      #ifndef DISABLE_OCSP
+ifndef DISABLE_OCSP
       if (addr->ocsp > OCSP_NOT_REQ)
        {
        ptr = big_buffer;
@@ -4171,8 +4210,8 @@ for (delivery_count = 0; addr_remote != NULL; delivery_count++)
        while(*ptr++);
         rmt_dlv_checked_write(fd, big_buffer, ptr - big_buffer);
        }
-      # endif
-      #endif   /*SUPPORT_TLS*/
+# endif
+#endif /*SUPPORT_TLS*/
 
       if (client_authenticator)
         {
@@ -4196,17 +4235,17 @@ for (delivery_count = 0; addr_remote != NULL; delivery_count++)
         rmt_dlv_checked_write(fd, big_buffer, ptr - big_buffer);
        }
 
-      #ifndef DISABLE_PRDR
+#ifndef DISABLE_PRDR
       if (addr->flags & af_prdr_used)
        rmt_dlv_checked_write(fd, "P", 1);
-      #endif
+#endif
 
-      #ifdef EXPERIMENTAL_DSN
+#ifdef EXPERIMENTAL_DSN
       big_buffer[0] = 'D';
       memcpy(big_buffer+1, &addr->dsn_aware, sizeof(addr->dsn_aware));
       rmt_dlv_checked_write(fd, big_buffer, sizeof(addr->dsn_aware) + 1);
       DEBUG(D_deliver) debug_printf("DSN write: addr->dsn_aware = %d\n", addr->dsn_aware);
-      #endif
+#endif
 
       /* Retry information: for most success cases this will be null. */
 
@@ -4921,7 +4960,7 @@ attempted. */
 
 if (deliver_freeze)
   {
-  #ifdef SUPPORT_MOVE_FROZEN_MESSAGES
+#ifdef SUPPORT_MOVE_FROZEN_MESSAGES
   /* Moving to another directory removes the message from Exim's view. Other
   tools must be used to deal with it. Logging of this action happens in
   spool_move_message() and its subfunctions. */
@@ -4929,7 +4968,7 @@ if (deliver_freeze)
   if (move_frozen_messages &&
       spool_move_message(id, message_subdir, US"", US"F"))
     return continue_closedown();   /* yields DELIVER_NOT_ATTEMPTED */
-  #endif
+#endif
 
   /* For all frozen messages (bounces or not), timeout_frozen_after sets the
   maximum time to keep messages that are frozen. Thaw if we reach it, with a
@@ -5358,13 +5397,13 @@ if (process_recipients != RECIP_IGNORE)
       if (r->pno >= 0)
         new->onetime_parent = recipients_list[r->pno].address;
 
-      #ifdef EXPERIMENTAL_DSN
+#ifdef EXPERIMENTAL_DSN
       /* If DSN support is enabled, set the dsn flags and the original receipt 
          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", new->dsn_orcpt, new->dsn_flags);
-      #endif
+#endif
 
       switch (process_recipients)
         {
@@ -6300,21 +6339,21 @@ if (addr_remote != NULL)
     regex_must_compile(US"\\n250[\\s\\-]AUTH\\s+([\\-\\w\\s]+)(?:\\n|$)",
       FALSE, TRUE);
 
-  #ifdef SUPPORT_TLS
+#ifdef SUPPORT_TLS
   if (regex_STARTTLS == NULL) regex_STARTTLS =
     regex_must_compile(US"\\n250[\\s\\-]STARTTLS(\\s|\\n|$)", FALSE, TRUE);
-  #endif
+#endif
 
-  #ifndef DISABLE_PRDR
+#ifndef DISABLE_PRDR
   if (regex_PRDR == NULL) regex_PRDR =
     regex_must_compile(US"\\n250[\\s\\-]PRDR(\\s|\\n|$)", FALSE, TRUE);
-  #endif
+#endif
 
-  #ifdef EXPERIMENTAL_DSN
+#ifdef EXPERIMENTAL_DSN
   /* Set the regex to check for DSN support on remote MTA */
   if (regex_DSN == NULL) regex_DSN  =
     regex_must_compile(US"\\n250[\\s\\-]DSN(\\s|\\n|$)", FALSE, TRUE);
-  #endif
+#endif
 
   /* Now sort the addresses if required, and do the deliveries. The yield of
   do_remote_deliveries is FALSE when mua_wrapper is set and all addresses
@@ -6497,71 +6536,73 @@ if (addr_senddsn != NULL)
       time(NULL), rand());
     DEBUG(D_deliver) debug_printf("DSN: MIME boundary: %s\n", boundaryStr);
   
-    if (errors_reply_to != NULL) fprintf(f,"Reply-To: %s\n", errors_reply_to);
+    if (errors_reply_to)
+      fprintf(f, "Reply-To: %s\n", errors_reply_to);
  
-    fprintf(f,"Auto-Submitted: auto-generated\n");
-    fprintf(f,"From: Mail Delivery System <Mailer-Daemon@%s>\n", qualify_domain_sender);
-    fprintf(f,"To: %s\n", sender_address);
-    fprintf(f,"Subject: Delivery Status Notification\n");
-    fprintf(f,"Content-Type: multipart/report; report-type=delivery-status; boundary=%s\n", boundaryStr);
-    fprintf(f,"MIME-Version: 1.0\n\n");
-
-    fprintf(f,"--%s\n", boundaryStr);
-    fprintf(f,"Content-type: text/plain; charset=us-ascii\n\n");
+    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"
+       "MIME-Version: 1.0\n\n"
+
+       "--%s\n"
+       "Content-type: text/plain; charset=us-ascii\n\n"
    
-    fprintf(f,"This message was created automatically by mail delivery software.\n");
-    fprintf(f," ----- The following addresses had successful delivery notifications -----\n");
+       "This message was created automatically by mail delivery software.\n"
+       " ----- The following addresses had successful delivery notifications -----\n",
+      qualify_domain_sender, sender_address, boundaryStr, boundaryStr);
 
     addr_dsntmp = addr_senddsn;
-    while(addr_dsntmp != NULL)
+    while(addr_dsntmp)
       {
-      if ((addr_dsntmp->dsn_flags & rf_dsnlasthop) == 1) {
-        fprintf(f,"<%s> (relayed via non DSN router)\n\n", addr_dsntmp->address);
-        }
-      else if (addr_dsntmp->dsn_aware == dsn_support_no) {
-        fprintf(f,"<%s> (relayed to non-DSN-aware mailer)\n\n", addr_dsntmp->address);
-        } 
-      else {
-        fprintf(f,"<%s> (relayed via non \"Remote SMTP\" router)\n\n", addr_dsntmp->address);
-        }
+      fprintf(f, "<%s> (relayed %s)\n\n",
+       addr_dsntmp->address,
+       (addr_dsntmp->dsn_flags & rf_dsnlasthop) == 1
+         ? "via non DSN router"
+         : addr_dsntmp->dsn_aware == dsn_support_no
+         ? "to non-DSN-aware mailer"
+         : "via non \"Remote SMTP\" router"
+       );
       addr_dsntmp = addr_dsntmp->next;
       }
-    fprintf(f,"--%s\n", boundaryStr);
-    fprintf(f,"Content-type: message/delivery-status\n\n");
-           
-    fprintf(f,"Reporting-MTA: dns; %s\n", smtp_active_hostname);
+    fprintf(f, "--%s\n"
+       "Content-type: message/delivery-status\n\n"
+       "Reporting-MTA: dns; %s\n",
+      boundaryStr, smtp_active_hostname);
+
     if (dsn_envid != NULL) {
       /* 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);
+        fprintf(f, "Original-Envelope-ID: %s\n", dsn_envid);
       else
-        fprintf(f,"X-Original-Envelope-ID: error decoding xtext formated ENVID\n");
+        fprintf(f, "X-Original-Envelope-ID: error decoding xtext formated ENVID\n");
       }
-    fprintf(f,"\n");
+    fputc('\n', f);
 
-    addr_dsntmp = addr_senddsn;
-    while(addr_dsntmp != NULL)
+    for (addr_dsntmp = addr_senddsn;
+        addr_dsntmp;
+        addr_dsntmp = addr_dsntmp->next)
       {
-      if (addr_dsntmp->dsn_orcpt != NULL) {
+      if (addr_dsntmp->dsn_orcpt)
         fprintf(f,"Original-Recipient: %s\n", addr_dsntmp->dsn_orcpt);
-        }
-      fprintf(f,"Action: delivered\n");
-      fprintf(f,"Final-Recipient: rfc822;%s\n", addr_dsntmp->address);
-      fprintf(f,"Status: 2.0.0\n");
-      if ((addr_dsntmp->host_used != NULL) && (addr_dsntmp->host_used->name != NULL))
-        fprintf(f,"Remote-MTA: dns; %s\nDiagnostic-Code: smtp; 250 Ok\n", addr_dsntmp->host_used->name);
+
+      fprintf(f, "Action: delivered\n"
+         "Final-Recipient: rfc822;%s\n"
+         "Status: 2.0.0\n",
+       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",
+         addr_dsntmp->host_used->name);
       else
-        if ((addr_dsntmp->dsn_flags & rf_dsnlasthop) == 1)
-          fprintf(f,"Diagnostic-Code: X-Exim; relayed via non DSN router\n");
-        else
-          fprintf(f,"Diagnostic-Code: X-Exim; relayed via non SMTP router\n");
-      fprintf(f,"\n");
-      addr_dsntmp = addr_dsntmp->next;
+       fprintf(f,"Diagnostic-Code: X-Exim; relayed via non %s router\n",
+         (addr_dsntmp->dsn_flags & rf_dsnlasthop) == 1 ? "DSN" : "SMTP");
+      fputc('\n', f);
       }
 
-    fprintf(f,"--%s\n", boundaryStr);
-    fprintf(f,"Content-type: text/rfc822-headers\n\n");
+    fprintf(f, "--%s\nContent-type: text/rfc822-headers\n\n", boundaryStr);
            
     fflush(f);
     transport_filter_argv = NULL;   /* Just in case */
@@ -6579,7 +6620,7 @@ if (addr_senddsn != NULL)
     rc = child_close(pid, 0);     /* Waits for child to close, no timeout */
     }
   }
-#endif
+#endif /*EXPERIMENTAL_DSN*/
 
 /* If any addresses failed, we must send a message to somebody, unless
 af_ignore_error is set, in which case no action is taken. It is possible for
@@ -6696,6 +6737,12 @@ while (addr_failed != NULL)
       BOOL to_sender = strcmpic(sender_address, bounce_recipient) == 0;
       int max = (bounce_return_size_limit/DELIVER_IN_BUFFER_SIZE + 1) *
         DELIVER_IN_BUFFER_SIZE;
+#ifdef EXPERIMENTAL_DSN
+      uschar boundaryStr[64];
+      uschar *dsnlimitmsg;
+      uschar *dsnnotifyhdr;
+      int topt;
+#endif
 
       DEBUG(D_deliver)
         debug_printf("sending error message to: %s\n", bounce_recipient);
@@ -6751,69 +6798,68 @@ while (addr_failed != NULL)
 
 #ifdef EXPERIMENTAL_DSN
       /* generate boundary string and output MIME-Headers */
-      uschar boundaryStr[64];
-      snprintf(boundaryStr, 63, "%l-eximdsn-%d", (long) time(NULL), rand());
-      fprintf(f,"Content-Type: multipart/report; report-type=delivery-status; boundary=%s\n", boundaryStr);
-      fprintf(f,"MIME-Version: 1.0\n");
+      snprintf(boundaryStr, sizeof(boundaryStr)-1, TIME_T_FMT "-eximdsn-%d",
+       time(NULL), rand());
+
+      fprintf(f, "Content-Type: multipart/report;"
+           " report-type=delivery-status; boundary=%s\n"
+         "MIME-Version: 1.0\n",
+       boundaryStr);
 #endif
 
       /* Open a template file if one is provided. Log failure to open, but
       carry on - default texts will be used. */
 
-      if (bounce_message_file != NULL)
-        {
-        emf = Ufopen(bounce_message_file, "rb");
-        if (emf == NULL)
+      if (bounce_message_file)
+        if (!(emf = Ufopen(bounce_message_file, "rb")))
           log_write(0, LOG_MAIN|LOG_PANIC, "Failed to open %s for error "
             "message texts: %s", bounce_message_file, strerror(errno));
-        }
 
       /* Quietly copy to configured additional addresses if required. */
 
-      bcc = moan_check_errorcopy(bounce_recipient);
-      if (bcc != NULL) fprintf(f, "Bcc: %s\n", bcc);
+      if ((bcc = moan_check_errorcopy(bounce_recipient)))
+       fprintf(f, "Bcc: %s\n", bcc);
 
       /* The texts for the message can be read from a template file; if there
       isn't one, or if it is too short, built-in texts are used. The first
       emf text is a Subject: and any other headers. */
 
-      emf_text = next_emf(emf, US"header");
-      if (emf_text != NULL) fprintf(f, "%s\n", emf_text); else
-        {
+      if ((emf_text = next_emf(emf, US"header")))
+       fprintf(f, "%s\n", emf_text);
+      else
         fprintf(f, "Subject: Mail delivery failed%s\n\n",
           to_sender? ": returning message to sender" : "");
-        }
 
 #ifdef EXPERIMENTAL_DSN
       /* output human readable part as text/plain section */
-      fprintf(f,"--%s\n", boundaryStr);
-      fprintf(f,"Content-type: text/plain; charset=us-ascii\n\n");
+      fprintf(f, "--%s\n"
+         "Content-type: text/plain; charset=us-ascii\n\n",
+       boundaryStr);
 #endif
 
-      emf_text = next_emf(emf, US"intro");
-      if (emf_text != NULL) fprintf(f, "%s", CS emf_text); else
+      if ((emf_text = next_emf(emf, US"intro")))
+       fprintf(f, "%s", CS emf_text);
+      else
         {
         fprintf(f,
 /* This message has been reworded several times. It seems to be confusing to
 somebody, however it is worded. I have retreated to the original, simple
 wording. */
 "This message was created automatically by mail delivery software.\n");
-        if (bounce_message_text != NULL) fprintf(f, "%s", CS bounce_message_text);
+
+        if (bounce_message_text)
+         fprintf(f, "%s", CS bounce_message_text);
         if (to_sender)
-          {
           fprintf(f,
 "\nA message that you sent could not be delivered to one or more of its\n"
 "recipients. This is a permanent error. The following address(es) failed:\n");
-          }
         else
-          {
           fprintf(f,
 "\nA message sent by\n\n  <%s>\n\n"
 "could not be delivered to one or more of its recipients. The following\n"
 "address(es) failed:\n", sender_address);
-          }
         }
-      fprintf(f, "\n");
+      fputc('\n', f);
 
       /* Process the addresses, leaving them on the msgchain if they have a
       file name for a return message. (There has already been a check in
@@ -6850,7 +6896,7 @@ wording. */
           }
         }
 
-      fprintf(f, "\n");
+      fputc('\n', f);
 
       /* Get the next text, whether we need it or not, so as to be
       positioned for the one after. */
@@ -6864,11 +6910,13 @@ wording. */
       fd, and the return_filename field in the *last* one will be set (to the
       name of the file). */
 
-      if (msgchain != NULL)
+      if (msgchain)
         {
         address_item *nextaddr;
 
-        if (emf_text != NULL) fprintf(f, "%s", CS emf_text); else
+        if (emf_text)
+         fprintf(f, "%s", CS emf_text);
+       else
           fprintf(f,
             "The following text was generated during the delivery "
             "attempt%s:\n", (filecount > 1)? "s" : "");
@@ -6880,15 +6928,15 @@ wording. */
 
           /* List all the addresses that relate to this file */
 
-          fprintf(f, "\n");
-          while(addr != NULL)                   /* Insurance */
+         fputc('\n', f);
+          while(addr)                   /* Insurance */
             {
             print_address_information(addr, f, US"------ ",  US"\n       ",
               US" ------\n");
-            if (addr->return_filename != NULL) break;
+            if (addr->return_filename) break;
             addr = addr->next;
             }
-          fprintf(f, "\n");
+         fputc('\n', f);
 
           /* Now copy the file */
 
@@ -6911,32 +6959,36 @@ wording. */
           addr->next = handled_addr;
           handled_addr = topaddr;
           }
-        fprintf(f, "\n");
+       fputc('\n', f);
         }
 
 #ifdef EXPERIMENTAL_DSN
       /* output machine readable part */
-      fprintf(f,"--%s\n", boundaryStr);
-      fprintf(f,"Content-type: message/delivery-status\n\n");
-      fprintf(f,"Reporting-MTA: dns; %s\n", smtp_active_hostname);
-      if (dsn_envid != NULL) {
+      fprintf(f, "--%s\n"
+         "Content-type: message/delivery-status\n\n"
+         "Reporting-MTA: dns; %s\n",
+       boundaryStr, smtp_active_hostname);
+
+      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);
+          fprintf(f, "Original-Envelope-ID: %s\n", dsn_envid);
         else
-          fprintf(f,"X-Original-Envelope-ID: error decoding xtext formated ENVID\n");
+          fprintf(f, "X-Original-Envelope-ID: error decoding xtext formated ENVID\n");
         }
-      fprintf(f,"\n");
+      fputc('\n', f);
  
-      for (addr = handled_addr; addr != NULL; addr = addr->next)
+      for (addr = handled_addr; addr; addr = addr->next)
         {
-        fprintf(f,"Action: failed\n");
-        fprintf(f,"Final-Recipient: rfc822;%s\n", addr->address);
-        fprintf(f,"Status: 5.0.0\n");
-        if ((addr->host_used != NULL) && (addr->host_used->name != NULL))
-          fprintf(f,"Remote-MTA: dns; %s\nDiagnostic-Code: smtp; %d\n", addr->host_used->name, addr->basic_errno);
+        fprintf(f, "Action: failed\n"
+           "Final-Recipient: rfc822;%s\n"
+           "Status: 5.0.0\n",
+           addr->address);
+        if (addr->host_used && addr->host_used->name)
+          fprintf(f, "Remote-MTA: dns; %s\nDiagnostic-Code: smtp; %d\n",
+           addr->host_used->name, addr->basic_errno);
         }
 #endif
 
@@ -6953,7 +7005,9 @@ wording. */
         int topt = topt_add_return_path;
         if (!bounce_return_body) topt |= topt_no_body;
 
-        if (emf_text != NULL) fprintf(f, "%s", CS emf_text); else
+        if (emf_text)
+         fprintf(f, "%s", CS emf_text);
+       else
           {
           if (bounce_return_body) fprintf(f,
 "------ This is a copy of the message, including all the headers. ------\n");
@@ -6976,18 +7030,19 @@ wording. */
           {
           struct stat statbuf;
           if (fstat(deliver_datafile, &statbuf) == 0 && statbuf.st_size > max)
-            {
-            if (emf_text != NULL) fprintf(f, "%s", CS emf_text); else
-              {
+           {
+            if (emf_text)
+             fprintf(f, "%s", CS emf_text);
+           else
               fprintf(f,
 "------ The body of the message is " OFF_T_FMT " characters long; only the first\n"
 "------ %d or so are included here.\n", statbuf.st_size, max);
-              }
-            }
+           }
           }
 
-        fprintf(f, "\n");
+       fputc('\n', f);
         fflush(f);
+
         transport_filter_argv = NULL;   /* Just in case */
         return_path = sender_address;   /* In case not previously set */
         transport_write_message(NULL, fileno(f), topt,
@@ -6996,10 +7051,10 @@ wording. */
 
       /* Write final text and close the template file if one is open */
 
-      if (emf != NULL)
+      if (emf)
         {
-        emf_text = next_emf(emf, US"final");
-        if (emf_text != NULL) fprintf(f, "%s", CS emf_text);
+        if ((emf_text = next_emf(emf, US"final")))
+         fprintf(f, "%s", CS emf_text);
         (void)fclose(emf);
         }
 #else
@@ -7014,11 +7069,12 @@ wording. */
          bounce_return_size_limit is always honored.
       */
   
-      fprintf(f,"\n--%s\n", boundaryStr);
+      fprintf(f, "\n--%s\n", boundaryStr);
+
+      dsnlimitmsg = US"X-Exim-DSN-Information: Due to administrative limits only headers are returned";
+      dsnnotifyhdr = NULL;
+      topt = topt_add_return_path;
 
-      uschar *dsnlimitmsg = US"X-Exim-DSN-Information: Due to administrative limits only headers are returned";
-      uschar *dsnnotifyhdr = NULL;
-      int topt = topt_add_return_path;
       /* RET=HDRS? top priority */
       if (dsn_ret == dsn_ret_hdrs)
         topt |= topt_no_body;
@@ -7055,12 +7111,11 @@ wording. */
       fflush(f);
  
       /* we never add the final text. close the file */
-      if (emf != NULL)
+      if (emf)
         (void)fclose(emf);
  
-      fprintf(f,"\n");
-      fprintf(f,"--%s--\n", boundaryStr);
-#endif
+      fprintf(f, "\n--%s--\n", boundaryStr);
+#endif /*EXPERIMENTAL_DSN*/
 
       /* Close the file, which should send an EOF to the child process
       that is receiving the message. Wait for it to finish. */
@@ -7360,8 +7415,11 @@ else if (addr_defer != (address_item *)(+1))
         uschar *wmf_text;
         FILE *wmf = NULL;
         FILE *f = fdopen(fd, "wb");
+#ifdef EXPERIMENTAL_DSN
+       uschar boundaryStr[64];
+#endif
 
-        if (warn_message_file != NULL)
+        if (warn_message_file)
           {
           wmf = Ufopen(warn_message_file, "rb");
           if (wmf == NULL)
@@ -7374,7 +7432,7 @@ else if (addr_defer != (address_item *)(+1))
           string_sprintf("%d minutes", show_time/60):
           string_sprintf("%d hours", show_time/3600);
 
-        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);
@@ -7382,14 +7440,16 @@ else if (addr_defer != (address_item *)(+1))
 
 #ifdef EXPERIMENTAL_DSN
         /* generated boundary string and output MIME-Headers */
-        uschar boundaryStr[64];
-        snprintf(boundaryStr, 63, "%l-eximdsn-%d", (long) time(NULL), rand());
-        fprintf(f,"Content-Type: multipart/report; report-type=delivery-status; boundary=%s\n", boundaryStr);
-        fprintf(f,"MIME-Version: 1.0\n");
+        snprintf(boundaryStr, sizeof(boundaryStr)-1,
+         TIME_T_FMT "-eximdsn-%d", time(NULL), rand());
+
+        fprintf(f, "Content-Type: multipart/report;"
+           " report-type=delivery-status; boundary=%s\n"
+           "MIME-Version: 1.0\n",
+         boundaryStr);
 #endif
 
-        wmf_text = next_emf(wmf, US"header");
-        if (wmf_text != NULL)
+        if ((wmf_text = next_emf(wmf, US"header")))
           fprintf(f, "%s\n", wmf_text);
         else
           fprintf(f, "Subject: Warning: message %s delayed %s\n\n",
@@ -7397,12 +7457,14 @@ else if (addr_defer != (address_item *)(+1))
 
 #ifdef EXPERIMENTAL_DSN
         /* output human readable part as text/plain section */
-        fprintf(f,"--%s\n", boundaryStr);
-        fprintf(f,"Content-type: text/plain; charset=us-ascii\n\n");
+        fprintf(f, "--%s\n"
+           "Content-type: text/plain; charset=us-ascii\n\n",
+         boundaryStr);
 #endif
 
-        wmf_text = next_emf(wmf, US"intro");
-        if (wmf_text != NULL) fprintf(f, "%s", CS wmf_text); else
+        if ((wmf_text = next_emf(wmf, US"intro")))
+         fprintf(f, "%s", CS wmf_text);
+       else
           {
           fprintf(f,
 "This message was created automatically by mail delivery software.\n");
@@ -7412,28 +7474,27 @@ else if (addr_defer != (address_item *)(+1))
 "A message that you sent has not yet been delivered to one or more of its\n"
 "recipients after more than ");
 
-          else fprintf(f,
+          else
+           fprintf(f,
 "A message sent by\n\n  <%s>\n\n"
 "has not yet been delivered to one or more of its recipients after more than \n",
-          sender_address);
+             sender_address);
 
-          fprintf(f, "%s on the queue on %s.\n\n", warnmsg_delay,
-            primary_hostname);
-          fprintf(f, "The message identifier is:     %s\n", message_id);
+          fprintf(f, "%s on the queue on %s.\n\n"
+             "The message identifier is:     %s\n",
+           warnmsg_delay, primary_hostname, message_id);
 
           for (h = header_list; h != NULL; h = h->next)
-            {
             if (strncmpic(h->text, US"Subject:", 8) == 0)
               fprintf(f, "The subject of the message is: %s", h->text + 9);
             else if (strncmpic(h->text, US"Date:", 5) == 0)
               fprintf(f, "The date of the message is:    %s", h->text + 6);
-            }
-          fprintf(f, "\n");
+          fputc('\n', f);
 
           fprintf(f, "The address%s to which the message has not yet been "
             "delivered %s:\n",
-            (addr_defer->next == NULL)? "" : "es",
-            (addr_defer->next == NULL)? "is": "are");
+            !addr_defer->next ? "" : "es",
+            !addr_defer->next ? "is": "are");
           }
 
         /* List the addresses, with error information if allowed */
@@ -7442,23 +7503,23 @@ else if (addr_defer != (address_item *)(+1))
         /* store addr_defer for machine readable part */
         address_item *addr_dsndefer = addr_defer;
 #endif
-        fprintf(f, "\n");
-        while (addr_defer != NULL)
+        fputc('\n', f);
+        while (addr_defer)
           {
           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: ");
-          fprintf(f, "\n");
+          fputc('\n', f);
           }
-        fprintf(f, "\n");
+        fputc('\n', f);
 
         /* Final text */
 
-        if (wmf != NULL)
+        if (wmf)
           {
-          wmf_text = next_emf(wmf, US"final");
-          if (wmf_text != NULL) fprintf(f, "%s", CS wmf_text);
+          if ((wmf_text = next_emf(wmf, US"final")))
+           fprintf(f, "%s", CS wmf_text);
           (void)fclose(wmf);
           }
         else
@@ -7472,11 +7533,15 @@ else if (addr_defer != (address_item *)(+1))
 
 #ifdef EXPERIMENTAL_DSN
         /* output machine readable part */
-        fprintf(f,"\n--%s\n", boundaryStr);
-        fprintf(f,"Content-type: message/delivery-status\n\n");
+        fprintf(f, "\n--%s\n"
+           "Content-type: message/delivery-status\n\n"
+           "Reporting-MTA: dns; %s\n",
+         boundaryStr,
+         smtp_active_hostname);
  
-        fprintf(f,"Reporting-MTA: dns; %s\n", smtp_active_hostname);
-        if (dsn_envid != NULL) {
+
+        if (dsn_envid)
+         {
           /* must be decoded from xtext: see RFC 3461:6.3a */
           uschar *xdec_envid;
           if (auth_xtextdecode(dsn_envid, &xdec_envid) > 0)
@@ -7484,24 +7549,25 @@ else if (addr_defer != (address_item *)(+1))
           else
             fprintf(f,"X-Original-Envelope-ID: error decoding xtext formated ENVID\n");
           }
-        fprintf(f,"\n");
+        fputc('\n', f);
 
-        while (addr_dsndefer != NULL)
+        while (addr_dsndefer)
           {
-          if (addr_dsndefer->dsn_orcpt != NULL) {
+          if (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");
-          if ((addr_dsndefer->host_used != NULL) && (addr_dsndefer->host_used->name != NULL))
+          if (addr_dsndefer->host_used && addr_dsndefer->host_used->name)
             fprintf(f,"Remote-MTA: dns; %s\nDiagnostic-Code: smtp; %d\n", 
-                      addr_dsndefer->host_used->name, addr_dsndefer->basic_errno);
+                   addr_dsndefer->host_used->name, addr_dsndefer->basic_errno);
           addr_dsndefer = addr_dsndefer->next;
           }
 
-        fprintf(f,"\n--%s\n", boundaryStr);
-        fprintf(f,"Content-type: text/rfc822-headers\n\n");
+        fprintf(f, "\n--%s\n"
+           "Content-type: text/rfc822-headers\n\n",
+         boundaryStr);
 
         fflush(f);
         /* header only as required by RFC. only failure DSN needs to honor RET=FULL */
@@ -7512,11 +7578,10 @@ else if (addr_defer != (address_item *)(+1))
         transport_write_message(NULL, fileno(f), topt, 0, NULL, NULL, NULL, NULL, NULL, 0);
         fflush(f);
 
-        fprintf(f,"\n");
-        fprintf(f,"--%s--\n", boundaryStr);
+        fprintf(f,"\n--%s--\n", boundaryStr);
 
         fflush(f);
-#endif
+#endif /*EXPERIMENTAL_DSN*/
 
         /* Close and wait for child process to complete, without a timeout.
         If there's an error, don't update the count. */
@@ -7629,10 +7694,10 @@ if (remove_journal)
 
   /* Move the message off the spool if reqested */
 
-  #ifdef SUPPORT_MOVE_FROZEN_MESSAGES
+#ifdef SUPPORT_MOVE_FROZEN_MESSAGES
   if (deliver_freeze && move_frozen_messages)
     (void)spool_move_message(id, message_subdir, US"", US"F");
-  #endif
+#endif
   }
 
 /* Closing the data file frees the lock; if the file has been unlinked it