Compiler quietening
[exim.git] / src / src / deliver.c
index a598e2535693f2d23e50eea7893d9785aeb46e20..2c0524e357984c2abfeff67b1d96956befebefd5 100644 (file)
@@ -718,27 +718,27 @@ d_tlslog(uschar * s, int * sizep, int * ptrp, address_item * addr)
 
 
 
-#ifdef EXPERIMENTAL_TPDA
-int
-tpda_raise_event(uschar * action, uschar * event, uschar * ev_data)
+#ifdef EXPERIMENTAL_EVENT
+uschar *
+event_raise(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",
+    debug_printf("Event(%s): event_action=|%s| delivery_IP=%s\n",
       event,
       action, deliver_host_address);
 
-  tpda_event = event;
-  tpda_data =  ev_data;
+  event_name = event;
+  event_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",
+      "failed to expand event_action %s in %s: %s\n",
       event, transport_name, expand_string_message);
 
-  tpda_event = tpda_data = NULL;
+  event_name = event_data = NULL;
 
   /* If the expansion returns anything but an empty string, flag for
   the caller to modify his normal processing
@@ -746,18 +746,19 @@ if (action)
   if (s && *s)
     {
     DEBUG(D_deliver)
-      debug_printf("TPDA(%s): event_action returned \"%s\"\n", event, s);
-    return DEFER;
+      debug_printf("Event(%s): event_action returned \"%s\"\n", event, s);
+    return s;
     }
   }
-return OK;
+return NULL;
 }
 
 static void
-tpda_msg_event(uschar * event, address_item * addr)
+msg_event_raise(uschar * event, address_item * addr)
 {
 uschar * save_domain = deliver_domain;
 uschar * save_local =  deliver_localpart;
+uschar * save_host =   deliver_host;
 
 if (!addr->transport)
   return;
@@ -766,16 +767,18 @@ router_name =    addr->router ? addr->router->name : NULL;
 transport_name = addr->transport->name;
 deliver_domain = addr->domain;
 deliver_localpart = addr->local_part;
+deliver_host =   addr->host_used ? addr->host_used->name : NULL;
 
-(void) tpda_raise_event(addr->transport->tpda_event_action, event,
+(void) event_raise(addr->transport->event_action, event,
          addr->host_used || Ustrcmp(addr->transport->driver_name, "lmtp") == 0
          ? addr->message : NULL);
 
+deliver_host =      save_host;
 deliver_localpart = save_local;
 deliver_domain =    save_domain;
 router_name = transport_name = NULL;
 }
-#endif /*EXPERIMENTAL_TPDA*/
+#endif /*EXPERIMENTAL_EVENT*/
 
 
 
@@ -795,13 +798,12 @@ int ptr = 0;            /* expanding buffer, for */
 uschar *s;              /* building log lines;   */
 void *reset_point;      /* released afterwards.  */
 
-
 /* 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
 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
+#ifdef EXPERIMENTAL_EVENT
   /* presume no successful remote delivery */
   lookup_dnssec_authenticated = NULL;
 #endif
@@ -868,9 +870,10 @@ else
     if (continue_sequence > 1)
       s = string_cat(s, &size, &ptr, US"*", 1);
 
-#ifdef EXPERIMENTAL_TPDA
+#ifdef EXPERIMENTAL_EVENT
     deliver_host_address = addr->host_used->address;
     deliver_host_port =    addr->host_used->port;
+    deliver_host =         addr->host_used->name;
 
     /* DNS lookup status */
     lookup_dnssec_authenticated = addr->host_used->dnssec==DS_YES ? US"yes"
@@ -936,9 +939,8 @@ store we used to build the line after writing it. */
 s[ptr] = 0;
 log_write(0, flags, "%s", s);
 
-#ifdef EXPERIMENTAL_TPDA
-/*XXX cutthrough calls this also for non-delivery...*/
-tpda_msg_event(US"msg:delivery", addr);
+#ifdef EXPERIMENTAL_EVENT
+if (!msg) msg_event_raise(US"msg:delivery", addr);
 #endif
 
 store_reset(reset_point);
@@ -979,7 +981,6 @@ int ptr = 0;            /* expanding buffer, for */
 uschar *s;              /* building log lines;   */
 void *reset_point;      /* released afterwards.  */
 
-
 DEBUG(D_deliver) debug_printf("post-process %s (%d)\n", addr->address, result);
 
 /* Set up driver kind and name for logging. Disable logging if the router or
@@ -1137,7 +1138,7 @@ if (result == OK)
     child_done(addr, now);
     }
 
-  /* Certificates for logging (via TPDA) */
+  /* Certificates for logging (via events) */
 #ifdef SUPPORT_TLS
   tls_out.ourcert = addr->ourcert;
   addr->ourcert = NULL;
@@ -1255,6 +1256,11 @@ else if (result == DEFER || result == PANIC)
       s = string_append(s, &size, &ptr, 2, US": ",
         US strerror(addr->basic_errno));
 
+    if (addr->host_used)
+      s = string_append(s, &size, &ptr, 5,
+                       US" H=", addr->host_used->name,
+                       US" [",  addr->host_used->address, US"]");
+
     if (addr->message != NULL)
       s = string_append(s, &size, &ptr, 2, US": ", addr->message);
 
@@ -1375,8 +1381,8 @@ else
 
   log_write(0, LOG_MAIN, "** %s", s);
 
-#ifdef EXPERIMENTAL_TPDA
-  tpda_msg_event(US"msg:fail:delivery", addr);
+#ifdef EXPERIMENTAL_EVENT
+  msg_event_raise(US"msg:fail:delivery", addr);
 #endif
 
   store_reset(reset_point);
@@ -2883,6 +2889,8 @@ uschar *ptr = endptr;
 uschar *msg = p->msg;
 BOOL done = p->done;
 BOOL unfinished = TRUE;
+/* minimum size to read is header size including id, subid and length */
+int required = PIPE_HEADER_SIZE;
 
 /* Loop through all items, reading from the pipe when necessary. The pipe
 is set up to be non-blocking, but there are two different Unix mechanisms in
@@ -2905,12 +2913,15 @@ while (!done)
   {
   retry_item *r, **rp;
   int remaining = endptr - ptr;
+  uschar header[PIPE_HEADER_SIZE + 1];
+  uschar id, subid;
+  uschar *endc;
 
   /* Read (first time) or top up the chars in the buffer if necessary.
   There will be only one read if we get all the available data (i.e. don't
   fill the buffer completely). */
 
-  if (remaining < 2500 && unfinished)
+  if (remaining < required && unfinished)
     {
     int len;
     int available = big_buffer_size - remaining;
@@ -2943,17 +2954,63 @@ while (!done)
     won't read any more, as "unfinished" will get set FALSE. */
 
     endptr += len;
+    remaining += len;
     unfinished = len == available;
     }
 
   /* If we are at the end of the available data, exit the loop. */
-
   if (ptr >= endptr) break;
 
+  /* copy and read header */
+  memcpy(header, ptr, PIPE_HEADER_SIZE);
+  header[PIPE_HEADER_SIZE] = '\0'; 
+  id = header[0];
+  subid = header[1];
+  required = Ustrtol(header + 2, &endc, 10) + PIPE_HEADER_SIZE;     /* header + data */
+  if (*endc)
+    {
+    msg = string_sprintf("failed to read pipe from transport process "
+      "%d for transport %s: error reading size from header", pid, addr->transport->driver_name);
+    done = TRUE;
+    break;
+    }
+
+  DEBUG(D_deliver)
+    debug_printf("header read  id:%c,subid:%c,size:%s,required:%d,remaining:%d,unfinished:%d\n", 
+                    id, subid, header+2, required, remaining, unfinished);
+
+  /* is there room for the dataset we want to read ? */
+  if (required > big_buffer_size - PIPE_HEADER_SIZE)
+    {
+    msg = string_sprintf("failed to read pipe from transport process "
+      "%d for transport %s: big_buffer too small! required size=%d buffer size=%d", pid, addr->transport->driver_name,
+      required, big_buffer_size - PIPE_HEADER_SIZE);
+    done = TRUE;
+    break;
+    }
+
+  /* we wrote all datasets with atomic write() calls 
+     remaining < required only happens if big_buffer was too small
+     to get all available data from pipe. unfinished has to be true 
+     as well. */
+  if (remaining < required)
+    {
+    if (unfinished)
+      continue;
+    msg = string_sprintf("failed to read pipe from transport process "
+      "%d for transport %s: required size=%d > remaining size=%d and unfinished=false", 
+      pid, addr->transport->driver_name, required, remaining);
+    done = TRUE;
+    break;
+    }
+
+  /* step behind the header */
+  ptr += PIPE_HEADER_SIZE;
   /* Handle each possible type of item, assuming the complete item is
   available in store. */
 
-  switch (*ptr++)
+  switch (id)
     {
     /* Host items exist only if any hosts were marked unusable. Match
     up by checking the IP address. */
@@ -3050,7 +3107,7 @@ while (!done)
 #ifdef SUPPORT_TLS
     case 'X':
     if (addr == NULL) goto ADDR_MISMATCH;          /* Below, in 'A' handler */
-    switch (*ptr++)
+    switch (subid)
       {
       case '1':
       addr->cipher = NULL;
@@ -3088,7 +3145,7 @@ while (!done)
 #endif /*SUPPORT_TLS*/
 
     case 'C':  /* client authenticator information */
-    switch (*ptr++)
+    switch (subid)
       {
       case '1':
        addr->authenticator = (*ptr)? string_copy(ptr) : NULL;
@@ -3111,7 +3168,7 @@ while (!done)
 
 #ifdef EXPERIMENTAL_DSN
     case 'D':
-    if (addr == NULL) break;
+    if (addr == NULL) goto ADDR_MISMATCH;
     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);
@@ -3179,7 +3236,7 @@ while (!done)
       continue_hostname = NULL;
       }
     done = TRUE;
-    DEBUG(D_deliver) debug_printf("Z%c item read\n", *ptr);
+    DEBUG(D_deliver) debug_printf("Z0%c item read\n", *ptr);
     break;
 
     /* Anything else is a disaster. */
@@ -3632,9 +3689,40 @@ while (parcount > max)
 
 
 static void
-rmt_dlv_checked_write(int fd, void * buf, int size)
+rmt_dlv_checked_write(int fd, char id, char subid, void * buf, int size)
+{
+uschar writebuffer[PIPE_HEADER_SIZE + BIG_BUFFER_SIZE];
+int     header_length;
+
+/* we assume that size can't get larger then BIG_BUFFER_SIZE which currently is set to 16k */
+/* complain to log if someone tries with buffer sizes we can't handle*/
+
+if (size > 99999)
 {
-int ret = write(fd, buf, size);
+  log_write(0, LOG_MAIN|LOG_PANIC_DIE, 
+    "Failed writing transport result to pipe: can't handle buffers > 99999 bytes. truncating!\n");
+  size = 99999;
+}
+
+/* to keep the write() atomic we build header in writebuffer and copy buf behind */
+/* two write() calls would increase the complexity of reading from pipe */
+
+/* convert size to human readable string prepended by id and subid */
+header_length = snprintf(CS writebuffer, PIPE_HEADER_SIZE+1, "%c%c%05d", id, subid, size);
+if (header_length != PIPE_HEADER_SIZE)
+{
+  log_write(0, LOG_MAIN|LOG_PANIC_DIE, "header snprintf failed\n");
+  writebuffer[0] = '\0';
+}
+
+DEBUG(D_deliver) debug_printf("header write id:%c,subid:%c,size:%d,final:%s\n", 
+                                 id, subid, size, writebuffer);
+
+if (buf && size > 0)
+  memcpy(writebuffer + PIPE_HEADER_SIZE, buf, size);
+
+size += PIPE_HEADER_SIZE;
+int ret = write(fd, writebuffer, size);
 if(ret != size)
   log_write(0, LOG_MAIN|LOG_PANIC_DIE, "Failed writing transport result to pipe: %s\n",
     ret == -1 ? strerror(errno) : "short write");
@@ -4160,8 +4248,8 @@ for (delivery_count = 0; addr_remote != NULL; delivery_count++)
     for (h = addr->host_list; h != NULL; h = h->next)
       {
       if (h->address == NULL || h->status < hstatus_unusable) continue;
-      sprintf(CS big_buffer, "H%c%c%s", h->status, h->why, h->address);
-      rmt_dlv_checked_write(fd, big_buffer, Ustrlen(big_buffer+3) + 4);
+      sprintf(CS big_buffer, "%c%c%s", h->status, h->why, h->address);
+      rmt_dlv_checked_write(fd, 'H', '0', big_buffer, Ustrlen(big_buffer+2) + 3);
       }
 
     /* The number of bytes written. This is the same for each address. Even
@@ -4169,9 +4257,8 @@ for (delivery_count = 0; addr_remote != NULL; delivery_count++)
     size of each one is the same, and it's that value we have got because
     transport_count gets reset before calling transport_write_message(). */
 
-    big_buffer[0] = 'S';
-    memcpy(big_buffer+1, &transport_count, sizeof(transport_count));
-    rmt_dlv_checked_write(fd, big_buffer, sizeof(transport_count) + 1);
+    memcpy(big_buffer, &transport_count, sizeof(transport_count));
+    rmt_dlv_checked_write(fd, 'S', '0', big_buffer, sizeof(transport_count));
 
     /* Information about what happened to each address. Four item types are
     used: an optional 'X' item first, for TLS information, then an optional "C"
@@ -4194,7 +4281,7 @@ for (delivery_count = 0; addr_remote != NULL; delivery_count++)
       if (addr->cipher)
         {
         ptr = big_buffer;
-        sprintf(CS ptr, "X1%.128s", addr->cipher);
+        sprintf(CS ptr, "%.128s", addr->cipher);
         while(*ptr++);
         if (!addr->peerdn)
          *ptr++ = 0;
@@ -4204,35 +4291,33 @@ for (delivery_count = 0; addr_remote != NULL; delivery_count++)
           while(*ptr++);
           }
 
-        rmt_dlv_checked_write(fd, big_buffer, ptr - big_buffer);
+        rmt_dlv_checked_write(fd, 'X', '1', big_buffer, ptr - big_buffer);
         }
       if (addr->peercert)
        {
         ptr = big_buffer;
-       *ptr++ = 'X'; *ptr++ = '2';
        if (!tls_export_cert(ptr, big_buffer_size-2, addr->peercert))
          while(*ptr++);
        else
          *ptr++ = 0;
-        rmt_dlv_checked_write(fd, big_buffer, ptr - big_buffer);
+        rmt_dlv_checked_write(fd, 'X', '2', big_buffer, ptr - big_buffer);
        }
       if (addr->ourcert)
        {
         ptr = big_buffer;
-       *ptr++ = 'X'; *ptr++ = '3';
        if (!tls_export_cert(ptr, big_buffer_size-2, addr->ourcert))
          while(*ptr++);
        else
          *ptr++ = 0;
-        rmt_dlv_checked_write(fd, big_buffer, ptr - big_buffer);
+        rmt_dlv_checked_write(fd, 'X', '3', big_buffer, ptr - big_buffer);
        }
 # ifndef DISABLE_OCSP
       if (addr->ocsp > OCSP_NOT_REQ)
        {
        ptr = big_buffer;
-       sprintf(CS ptr, "X4%c", addr->ocsp + '0');
+       sprintf(CS ptr, "%c", addr->ocsp + '0');
        while(*ptr++);
-        rmt_dlv_checked_write(fd, big_buffer, ptr - big_buffer);
+        rmt_dlv_checked_write(fd, 'X', '4', big_buffer, ptr - big_buffer);
        }
 # endif
 #endif /*SUPPORT_TLS*/
@@ -4240,34 +4325,33 @@ for (delivery_count = 0; addr_remote != NULL; delivery_count++)
       if (client_authenticator)
         {
         ptr = big_buffer;
-       sprintf(CS big_buffer, "C1%.64s", client_authenticator);
+       sprintf(CS big_buffer, "%.64s", client_authenticator);
         while(*ptr++);
-        rmt_dlv_checked_write(fd, big_buffer, ptr - big_buffer);
+        rmt_dlv_checked_write(fd, 'C', '1', big_buffer, ptr - big_buffer);
        }
       if (client_authenticated_id)
         {
         ptr = big_buffer;
-       sprintf(CS big_buffer, "C2%.64s", client_authenticated_id);
+       sprintf(CS big_buffer, "%.64s", client_authenticated_id);
         while(*ptr++);
-        rmt_dlv_checked_write(fd, big_buffer, ptr - big_buffer);
+        rmt_dlv_checked_write(fd, 'C', '2', big_buffer, ptr - big_buffer);
        }
       if (client_authenticated_sender)
         {
         ptr = big_buffer;
-       sprintf(CS big_buffer, "C3%.64s", client_authenticated_sender);
+       sprintf(CS big_buffer, "%.64s", client_authenticated_sender);
         while(*ptr++);
-        rmt_dlv_checked_write(fd, big_buffer, ptr - big_buffer);
+        rmt_dlv_checked_write(fd, 'C', '3', big_buffer, ptr - big_buffer);
        }
 
 #ifndef DISABLE_PRDR
       if (addr->flags & af_prdr_used)
-       rmt_dlv_checked_write(fd, "P", 1);
+       rmt_dlv_checked_write(fd, 'P', '0', NULL, 0);
 #endif
 
 #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);
+      memcpy(big_buffer, &addr->dsn_aware, sizeof(addr->dsn_aware));
+      rmt_dlv_checked_write(fd, 'D', '0', big_buffer, sizeof(addr->dsn_aware));
       DEBUG(D_deliver) debug_printf("DSN write: addr->dsn_aware = %d\n", addr->dsn_aware);
 #endif
 
@@ -4276,7 +4360,7 @@ for (delivery_count = 0; addr_remote != NULL; delivery_count++)
       for (r = addr->retries; r != NULL; r = r->next)
         {
         uschar *ptr;
-        sprintf(CS big_buffer, "R%c%.500s", r->flags, r->key);
+        sprintf(CS big_buffer, "%c%.500s", r->flags, r->key);
         ptr = big_buffer + Ustrlen(big_buffer+2) + 3;
         memcpy(ptr, &(r->basic_errno), sizeof(r->basic_errno));
         ptr += sizeof(r->basic_errno);
@@ -4287,13 +4371,13 @@ for (delivery_count = 0; addr_remote != NULL; delivery_count++)
           sprintf(CS ptr, "%.512s", r->message);
           while(*ptr++);
           }
-        rmt_dlv_checked_write(fd, big_buffer, ptr - big_buffer);
+        rmt_dlv_checked_write(fd, 'R', '0', big_buffer, ptr - big_buffer);
         }
 
       /* The rest of the information goes in an 'A' item. */
 
-      ptr = big_buffer + 3;
-      sprintf(CS big_buffer, "A%c%c", addr->transport_return,
+      ptr = big_buffer + 2;
+      sprintf(CS big_buffer, "%c%c", addr->transport_return,
         addr->special_action);
       memcpy(ptr, &(addr->basic_errno), sizeof(addr->basic_errno));
       ptr += sizeof(addr->basic_errno);
@@ -4328,7 +4412,7 @@ for (delivery_count = 0; addr_remote != NULL; delivery_count++)
               : addr->host_used->dnssec==DS_NO ? '1' : '0';
 
         }
-      rmt_dlv_checked_write(fd, big_buffer, ptr - big_buffer);
+      rmt_dlv_checked_write(fd, 'A', '0', big_buffer, ptr - big_buffer);
       }
 
     /* Add termination flag, close the pipe, and that's it. The character
@@ -4336,9 +4420,8 @@ for (delivery_count = 0; addr_remote != NULL; delivery_count++)
     A change from non-NULL to NULL indicates a problem with a continuing
     connection. */
 
-    big_buffer[0] = 'Z';
-    big_buffer[1] = (continue_transport == NULL)? '0' : '1';
-    rmt_dlv_checked_write(fd, big_buffer, 2);
+    big_buffer[0] = (continue_transport == NULL)? '0' : '1';
+    rmt_dlv_checked_write(fd, 'Z', '0', big_buffer, 1);
     (void)close(fd);
     exit(EXIT_SUCCESS);
     }
@@ -4640,6 +4723,10 @@ if (ancestor != addr)
       string_printing(original));
   }
 
+if (addr->host_used)
+  fprintf(f, "\n    host %s [%s]",
+         addr->host_used->name, addr->host_used->address);
+
 fprintf(f, "%s", CS se);
 return yield;
 }
@@ -5498,7 +5585,7 @@ if (process_recipients != RECIP_IGNORE)
         break;
         }
 
-#ifdef EXPERIMENTAL_TPDA
+#ifdef EXPERIMENTAL_EVENT
       if (process_recipients != RECIP_ACCEPT)
        {
        uschar * save_local =  deliver_localpart;
@@ -5509,7 +5596,7 @@ if (process_recipients != RECIP_IGNORE)
        deliver_domain =    expand_string(
                      string_sprintf("${domain:%s}", new->address));
 
-       (void) tpda_raise_event(delivery_event_action,
+       (void) event_raise(event_action,
                      US"msg:fail:internal", new->message);
 
        deliver_localpart = save_local;
@@ -6472,6 +6559,7 @@ if (mua_wrapper)
     {
     uschar *s = (addr_failed->user_message != NULL)?
       addr_failed->user_message : addr_failed->message;
+    host_item * host;
 
     fprintf(stderr, "Delivery failed: ");
     if (addr_failed->basic_errno > 0)
@@ -6479,6 +6567,8 @@ if (mua_wrapper)
       fprintf(stderr, "%s", strerror(addr_failed->basic_errno));
       if (s != NULL) fprintf(stderr, ": ");
       }
+    if ((host = addr_failed->host_used))
+      fprintf(stderr, "H=%s [%s]: ", host->name, host->address);
     if (s == NULL)
       {
       if (addr_failed->basic_errno <= 0) fprintf(stderr, "unknown error");
@@ -6570,14 +6660,13 @@ if (addr_senddsn != NULL)
     FILE *f = fdopen(fd, "wb");
     /* header only as required by RFC. only failure DSN needs to honor RET=FULL */
     int topt = topt_add_return_path | topt_no_body;
-    uschar boundaryStr[64];
+    uschar * bound;
      
     DEBUG(D_deliver) debug_printf("sending error message to: %s\n", sender_address);
   
     /* build unique id for MIME boundary */
-    snprintf(boundaryStr, sizeof(boundaryStr)-1, TIME_T_FMT "-eximdsn-%d",
-      time(NULL), rand());
-    DEBUG(D_deliver) debug_printf("DSN: MIME boundary: %s\n", boundaryStr);
+    bound = string_sprintf(TIME_T_FMT "-eximdsn-%d", time(NULL), rand());
+    DEBUG(D_deliver) debug_printf("DSN: MIME boundary: %s\n", bound);
   
     if (errors_reply_to)
       fprintf(f, "Reply-To: %s\n", errors_reply_to);
@@ -6594,7 +6683,7 @@ if (addr_senddsn != NULL)
    
        "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);
+      qualify_domain_sender, sender_address, bound, bound);
 
     addr_dsntmp = addr_senddsn;
     while(addr_dsntmp)
@@ -6612,7 +6701,7 @@ if (addr_senddsn != NULL)
     fprintf(f, "--%s\n"
        "Content-type: message/delivery-status\n\n"
        "Reporting-MTA: dns; %s\n",
-      boundaryStr, smtp_active_hostname);
+      bound, smtp_active_hostname);
 
     if (dsn_envid != NULL) {
       /* must be decoded from xtext: see RFC 3461:6.3a */
@@ -6645,7 +6734,7 @@ if (addr_senddsn != NULL)
       fputc('\n', f);
       }
 
-    fprintf(f, "--%s\nContent-type: text/rfc822-headers\n\n", boundaryStr);
+    fprintf(f, "--%s\nContent-type: text/rfc822-headers\n\n", bound);
            
     fflush(f);
     transport_filter_argv = NULL;   /* Just in case */
@@ -6656,7 +6745,7 @@ if (addr_senddsn != NULL)
     fflush(f);
 
     fprintf(f,"\n");       
-    fprintf(f,"--%s--\n", boundaryStr);
+    fprintf(f,"--%s--\n", bound);
 
     fflush(f);
     fclose(f);
@@ -6781,7 +6870,7 @@ while (addr_failed != NULL)
       int max = (bounce_return_size_limit/DELIVER_IN_BUFFER_SIZE + 1) *
         DELIVER_IN_BUFFER_SIZE;
 #ifdef EXPERIMENTAL_DSN
-      uschar boundaryStr[64];
+      uschar * bound;
       uschar *dsnlimitmsg;
       uschar *dsnnotifyhdr;
       int topt;
@@ -6841,13 +6930,12 @@ while (addr_failed != NULL)
 
 #ifdef EXPERIMENTAL_DSN
       /* generate boundary string and output MIME-Headers */
-      snprintf(boundaryStr, sizeof(boundaryStr)-1, TIME_T_FMT "-eximdsn-%d",
-       time(NULL), rand());
+      bound = string_sprintf(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);
+       bound);
 #endif
 
       /* Open a template file if one is provided. Log failure to open, but
@@ -6877,7 +6965,7 @@ while (addr_failed != NULL)
       /* output human readable part as text/plain section */
       fprintf(f, "--%s\n"
          "Content-type: text/plain; charset=us-ascii\n\n",
-       boundaryStr);
+       bound);
 #endif
 
       if ((emf_text = next_emf(emf, US"intro")))
@@ -7010,7 +7098,7 @@ wording. */
       fprintf(f, "--%s\n"
          "Content-type: message/delivery-status\n\n"
          "Reporting-MTA: dns; %s\n",
-       boundaryStr, smtp_active_hostname);
+       bound, smtp_active_hostname);
 
       if (dsn_envid)
        {
@@ -7112,7 +7200,7 @@ wording. */
          bounce_return_size_limit is always honored.
       */
   
-      fprintf(f, "\n--%s\n", boundaryStr);
+      fprintf(f, "\n--%s\n", bound);
 
       dsnlimitmsg = US"X-Exim-DSN-Information: Due to administrative limits only headers are returned";
       dsnnotifyhdr = NULL;
@@ -7157,7 +7245,7 @@ wording. */
       if (emf)
         (void)fclose(emf);
  
-      fprintf(f, "\n--%s--\n", boundaryStr);
+      fprintf(f, "\n--%s--\n", bound);
 #endif /*EXPERIMENTAL_DSN*/
 
       /* Close the file, which should send an EOF to the child process
@@ -7274,8 +7362,8 @@ if (addr_defer == NULL)
   /* Unset deliver_freeze so that we won't try to move the spool files further down */
   deliver_freeze = FALSE;
 
-#ifdef EXPERIMENTAL_TPDA
-  (void) tpda_raise_event(delivery_event_action, US"msg:complete", NULL);
+#ifdef EXPERIMENTAL_EVENT
+  (void) event_raise(event_action, US"msg:complete", NULL);
 #endif
 }
 
@@ -7463,7 +7551,7 @@ else if (addr_defer != (address_item *)(+1))
         FILE *wmf = NULL;
         FILE *f = fdopen(fd, "wb");
 #ifdef EXPERIMENTAL_DSN
-       uschar boundaryStr[64];
+       uschar * bound;
 #endif
 
         if (warn_message_file)
@@ -7487,13 +7575,12 @@ else if (addr_defer != (address_item *)(+1))
 
 #ifdef EXPERIMENTAL_DSN
         /* generated boundary string and output MIME-Headers */
-        snprintf(boundaryStr, sizeof(boundaryStr)-1,
-         TIME_T_FMT "-eximdsn-%d", time(NULL), rand());
+        bound = string_sprintf(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);
+         bound);
 #endif
 
         if ((wmf_text = next_emf(wmf, US"header")))
@@ -7506,7 +7593,7 @@ else if (addr_defer != (address_item *)(+1))
         /* output human readable part as text/plain section */
         fprintf(f, "--%s\n"
            "Content-type: text/plain; charset=us-ascii\n\n",
-         boundaryStr);
+         bound);
 #endif
 
         if ((wmf_text = next_emf(wmf, US"intro")))
@@ -7583,7 +7670,7 @@ else if (addr_defer != (address_item *)(+1))
         fprintf(f, "\n--%s\n"
            "Content-type: message/delivery-status\n\n"
            "Reporting-MTA: dns; %s\n",
-         boundaryStr,
+         bound,
          smtp_active_hostname);
  
 
@@ -7614,7 +7701,7 @@ else if (addr_defer != (address_item *)(+1))
 
         fprintf(f, "\n--%s\n"
            "Content-type: text/rfc822-headers\n\n",
-         boundaryStr);
+         bound);
 
         fflush(f);
         /* header only as required by RFC. only failure DSN needs to honor RET=FULL */
@@ -7625,7 +7712,7 @@ 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--%s--\n", boundaryStr);
+        fprintf(f,"\n--%s--\n", bound);
 
         fflush(f);
 #endif /*EXPERIMENTAL_DSN*/