]> git.netwichtig.de Git - user/henk/code/exim.git/blobdiff - src/src/deliver.c
Fix $recipients expansion when used within ${run...}. Bug 3013
[user/henk/code/exim.git] / src / src / deliver.c
index d0e6d1c2ecbd9660b30ddcd7666c4687c84c3b10..52270368ee3b7fc4eaacd991a303529772e2ce0f 100644 (file)
@@ -2,7 +2,7 @@
 *     Exim - an Internet mail transport agent    *
 *************************************************/
 
-/* Copyright (c) The Exim Maintainers 2020 - 2022 */
+/* Copyright (c) The Exim Maintainers 2020 - 2023 */
 /* Copyright (c) University of Cambridge 1995 - 2018 */
 /* See the file NOTICE for conditions of use and distribution. */
 /* SPDX-License-Identifier: GPL-2.0-or-later */
@@ -723,7 +723,7 @@ child_done(address_item * addr, const uschar * now)
 {
 while (addr->parent)
   {
-  address_item *aa;
+  address_item * aa;
 
   addr = addr->parent;
   if (--addr->child_count > 0) return;   /* Incomplete parent */
@@ -1278,7 +1278,7 @@ if (LOGGING(deliver_time))
 /* string_cat() always leaves room for the terminator. Release the
 store we used to build the line after writing it. */
 
-log_write(0, flags, "%s", string_from_gstring(g));
+log_write(0, flags, "%Y", g);
 
 #ifndef DISABLE_EVENT
 if (!msg) msg_event_raise(US"msg:delivery", addr);
@@ -1337,25 +1337,21 @@ if (LOGGING(deliver_time))
 if (addr->message)
   g = string_append(g, 2, US": ", addr->message);
 
- {
-  const uschar * s = string_from_gstring(g);
+/* Log the deferment in the message log, but don't clutter it
+up with retry-time defers after the first delivery attempt. */
 
-  /* Log the deferment in the message log, but don't clutter it
-  up with retry-time defers after the first delivery attempt. */
+if (f.deliver_firsttime || addr->basic_errno > ERRNO_RETRY_BASE)
+  deliver_msglog("%s %.*s\n", now, g->ptr, g->s);
 
-  if (f.deliver_firsttime || addr->basic_errno > ERRNO_RETRY_BASE)
-    deliver_msglog("%s %s\n", now, s);
+/* Write the main log and reset the store.
+For errors of the type "retry time not reached" (also remotes skipped
+on queue run), logging is controlled by L_retry_defer. Note that this kind
+of error number is negative, and all the retry ones are less than any
+others. */
 
-  /* Write the main log and reset the store.
-  For errors of the type "retry time not reached" (also remotes skipped
-  on queue run), logging is controlled by L_retry_defer. Note that this kind
-  of error number is negative, and all the retry ones are less than any
-  others. */
 
-
-  log_write(addr->basic_errno <= ERRNO_RETRY_BASE ? L_retry_defer : 0, logflags,
-    "== %s", s);
- }
+log_write(addr->basic_errno <= ERRNO_RETRY_BASE ? L_retry_defer : 0, logflags,
+  "== %Y", g);
 
 store_reset(reset_point);
 return;
@@ -1421,16 +1417,12 @@ if (LOGGING(deliver_time))
 /* Do the logging. For the message log, "routing failed" for those cases,
 just to make it clearer. */
 
- {
-  const uschar * s = string_from_gstring(g);
-
-  if (driver_kind)
-    deliver_msglog("%s %s failed for %s\n", now, driver_kind, s);
-  else
-    deliver_msglog("%s %s\n", now, s);
+if (driver_kind)
+  deliver_msglog("%s %s failed for %.*s\n", now, driver_kind, g->ptr, g->s);
+else
+  deliver_msglog("%s %.*s\n", now, g->ptr, g->s);
 
-  log_write(0, LOG_MAIN, "** %s", s);
- }
+log_write(0, LOG_MAIN, "** %Y", g);
 
 store_reset(reset_point);
 return;
@@ -2371,7 +2363,9 @@ if ((pid = exim_fork(US"delivery-local")) == 0)
      addr->local_part, tp->name);
 
     /* Setting these globals in the subprocess means we need never clear them */
-    transport_name = addr->transport->name;
+
+    transport_name = tp->name;
+    if (addr->router) router_name = addr->router->name;
     driver_srcfile = tp->srcfile;
     driver_srcline = tp->srcline;
 
@@ -2382,7 +2376,7 @@ if ((pid = exim_fork(US"delivery-local")) == 0)
       {
       ok = transport_set_up_command(&transport_filter_argv,
         tp->filter_command,
-        TRUE, PANIC, addr, FALSE, US"transport filter", NULL);
+        TSUC_EXPAND_ARGS, PANIC, addr, US"transport filter", NULL);
       transport_filter_timeout = tp->filter_timeout;
       }
     else transport_filter_argv = NULL;
@@ -3351,8 +3345,8 @@ while (!done)
 
   pipeheader[PIPE_HEADER_SIZE] = '\0';
   DEBUG(D_deliver)
-    debug_printf("got %ld bytes (pipeheader) from transport process %d\n",
-      (long) got, pid);
+    debug_printf("got %ld bytes (pipeheader) '%c' from transport process %d\n",
+      (long) got, *id, pid);
 
   {
   /* If we can't decode the pipeheader, the subprocess seems to have a
@@ -3467,7 +3461,7 @@ while (!done)
 
     /* Put the amount of data written into the parlist block */
 
-    case 'S':
+    case 'S':          /* Size */
       memcpy(&(p->transport_count), ptr, sizeof(transport_count));
       ptr += sizeof(transport_count);
       break;
@@ -3557,7 +3551,7 @@ while (!done)
       if (*subid > '1') setflag(addr, af_tcp_fastopen_data);
       break;
 
-    case 'D':
+    case 'D':          /* DSN */
       if (!addr) goto ADDR_MISMATCH;
       memcpy(&(addr->dsn_aware), ptr, sizeof(addr->dsn_aware));
       ptr += sizeof(addr->dsn_aware);
@@ -4663,7 +4657,9 @@ all pipes, so I do not see a reason to use non-blocking IO here
     host_item *h;
 
     /* Setting these globals in the subprocess means we need never clear them */
-    transport_name = addr->transport->name;
+
+    transport_name = tp->name;
+    if (addr->router) router_name = addr->router->name;
     driver_srcfile = tp->srcfile;
     driver_srcline = tp->srcline;
 
@@ -5370,6 +5366,11 @@ while (*s)
       fprintf(f, "\n   ");  /* sic (because space follows) */
       count = 0;
       }
+    else if (count > 254)      /* arbitrary limit */
+      {
+      fprintf(f, "[truncated]");
+      do s++; while (*s && !(*s == '\\' && s[1] == '\n'));
+      }
     }
 }
 
@@ -5561,69 +5562,14 @@ Limit to about 1024 chars total. */
 static void
 dsn_put_wrapped(FILE * fp, const uschar * header, const uschar * s)
 {
-const uschar * t;
-int llen = fprintf(fp, "%s", CS header), sleft = Ustrlen(s);
-int remain = 1022 - llen;
-
-if (*s && remain > 0)
-  {
-  for(;;)
-    {
-    unsigned ltail;    /* source chars to skip */
-
-    /* Chop at a newline, or end of string */
-
-    if ((t = Ustrchr(s, '\\')) && t[1] == 'n')
-      ltail = 2;
-    else if ((t = Ustrchr(s, '\n')))
-      ltail = 1;
-    else
-      {
-      t = s + sleft;
-      ltail = 0;
-      }
-
-    /* If that is too long, search backward for a space */
+gstring * g = string_cat(NULL, header);
 
-    if ((llen + t - s) > 78)
-      {
-      const uschar * u;
-      for (u = s + 78 - llen; u > s + 10; --u) if (*u == ' ') break;
-      if (u > s + 10)
-       {                               /* found a space to linebreak at */
-       llen = u - s;
-       remain -= fprintf(fp, "%.*s", (int)llen, s);
-       s += ++llen;                    /* skip the space also */
-       }
-      else if (llen < 78)
-       {                               /* just linebreak at 78 */
-       llen = 78 - llen;
-       remain -= fprintf(fp, "%.*s", llen, s);
-       s += llen;
-       }
-      else                             /* header rather long */
-       llen = 0;
-      }
-    else
-      {
-      llen = t - s;
-      remain -= fprintf(fp, "%.*s", llen, s);
-      s = t + ltail;
-      }
+g = string_cat(g, s);
+gstring_release_unused(g);
+fprintf(fp, "%s\n", wrap_header(string_from_gstring(g), 79, 1023, US" ", 1));
+}
 
-    sleft -= llen;
-    remain -= 2;
-    if (!*s || remain <= 0)
-      break;
-    fputs("\n ", fp);
-    llen = 1;          /* one for the leading space output above */
-    }
 
-  if (s[-1] != '\n') fputs("\n", fp);
-  }
-else
-  fputs("\n", fp);
-}
 
 
 /*************************************************
@@ -6004,7 +5950,7 @@ wording. */
 
     tctx.u.fd = fileno(fp);
     tctx.tblock = &tb;
-    tctx.options = topt;
+    tctx.options = topt | topt_truncate_headers;
     tb.add_headers = dsnnotifyhdr;
 
     /*XXX no checking for failure!  buggy! */
@@ -6035,7 +5981,7 @@ wording. */
 
   if (rc != 0)
     {
-    uschar *s = US"";
+    uschar * s = US"";
     if (now - received_time.tv_sec < retry_maximum_timeout && !addr_defer)
       {
       addr_defer = (address_item *)(+1);
@@ -6222,7 +6168,7 @@ fprintf(f, "--%s\n"
 fflush(f);
 /* header only as required by RFC. only failure DSN needs to honor RET=FULL */
 tctx.u.fd = fileno(f);
-tctx.options = topt_add_return_path | topt_no_body;
+tctx.options = topt_add_return_path | topt_truncate_headers | topt_no_body;
 transport_filter_argv = NULL;   /* Just in case */
 return_path = sender_address;   /* In case not previously set */
 
@@ -6383,7 +6329,7 @@ if (addr_senddsn)
     /* Write the original email out */
 
     tctx.u.fd = fd;
-    tctx.options = topt_add_return_path | topt_no_body;
+    tctx.options = topt_add_return_path | topt_truncate_headers | topt_no_body;
     /*XXX hmm, FALSE(fail) retval ignored.
     Could error for any number of reasons, and they are not handled. */
     transport_write_message(&tctx, 0);
@@ -6438,7 +6384,7 @@ Returns:      When the global variable mua_wrapper is FALSE:
 */
 
 int
-deliver_message(uschar *id, BOOL forced, BOOL give_up)
+deliver_message(uschar * id, BOOL forced, BOOL give_up)
 {
 int i, rc;
 int final_yield = DELIVER_ATTEMPTED_NORMAL;
@@ -6524,7 +6470,7 @@ opening the data file, message_subdir gets set. */
 if ((deliver_datafile = spool_open_datafile(id)) < 0)
   return continue_closedown();  /* yields DELIVER_NOT_ATTEMPTED */
 
-/* The value of message_size at this point has been set to the data length,
+/* tHe value of message_size at this point has been set to the data length,
 plus one for the blank line that notionally precedes the data. */
 
 /* Now read the contents of the header file, which will set up the headers in
@@ -6557,8 +6503,8 @@ give up; if the message has been around for sufficiently long, remove it. */
     if (rc != spool_read_hdrerror)
       {
       received_time.tv_sec = received_time.tv_usec = 0;
-      /*XXX subsec precision?*/
-      for (i = 0; i < 6; i++)
+      /*III subsec precision?*/
+      for (i = 0; i < MESSAGE_ID_TIME_LEN; i++)
        received_time.tv_sec = received_time.tv_sec * BASE_62 + tab62[id[i] - '0'];
       }