More abstraction of the gstring API
[exim.git] / src / src / deliver.c
index 029b7a59b6975cb7a42debb5856fe8bcf565dae8..084a048c938460383b005cb2670981d3c20c040d 100644 (file)
@@ -2,9 +2,10 @@
 *     Exim - an Internet mail transport agent    *
 *************************************************/
 
+/* Copyright (c) The Exim Maintainers 2020 - 2022 */
 /* Copyright (c) University of Cambridge 1995 - 2018 */
-/* Copyright (c) The Exim Maintainers 2020 - 2021 */
 /* See the file NOTICE for conditions of use and distribution. */
+/* SPDX-License-Identifier: GPL-2.0-or-later */
 
 /* The main code for delivering a message. */
 
@@ -341,13 +342,7 @@ if (Ustrstr(filename, US"/../"))
 for (int i = 2; i > 0; i--)
   {
   int fd = Uopen(filename,
-#ifdef O_CLOEXEC
-    O_CLOEXEC |
-#endif
-#ifdef O_NOFOLLOW
-    O_NOFOLLOW |
-#endif
-               O_WRONLY|O_APPEND|O_CREAT, mode);
+               EXIM_CLOEXEC | EXIM_NOFOLLOW | O_WRONLY|O_APPEND|O_CREAT, mode);
   if (fd >= 0)
     {
     /* Set the close-on-exec flag and change the owner to the exim uid/gid (this
@@ -953,9 +948,22 @@ router_name = transport_name = NULL;
 
 
 /*************************************************
-*        Generate local prt for logging          *
+*        Generate local part for logging         *
 *************************************************/
 
+static uschar *
+string_get_lpart_sub(const address_item * addr, uschar * s)
+{
+#ifdef SUPPORT_I18N
+if (testflag(addr, af_utf8_downcvt))
+  {
+  uschar * t = string_localpart_utf8_to_alabel(s, NULL);
+  return t ? t : s;    /* t is NULL on a failed conversion */
+  }
+#endif
+return s;
+}
+
 /* This function is a subroutine for use in string_log_address() below.
 
 Arguments:
@@ -970,32 +978,13 @@ string_get_localpart(address_item * addr, gstring * yield)
 {
 uschar * s;
 
-s = addr->prefix;
-if (testflag(addr, af_include_affixes) && s)
-  {
-#ifdef SUPPORT_I18N
-  if (testflag(addr, af_utf8_downcvt))
-    s = string_localpart_utf8_to_alabel(s, NULL);
-#endif
-  yield = string_cat(yield, s);
-  }
+if (testflag(addr, af_include_affixes) && (s = addr->prefix))
+  yield = string_cat(yield, string_get_lpart_sub(addr, s));
 
-s = addr->local_part;
-#ifdef SUPPORT_I18N
-if (testflag(addr, af_utf8_downcvt))
-  s = string_localpart_utf8_to_alabel(s, NULL);
-#endif
-yield = string_cat(yield, s);
+yield = string_cat(yield, string_get_lpart_sub(addr, addr->local_part));
 
-s = addr->suffix;
-if (testflag(addr, af_include_affixes) && s)
-  {
-#ifdef SUPPORT_I18N
-  if (testflag(addr, af_utf8_downcvt))
-    s = string_localpart_utf8_to_alabel(s, NULL);
-#endif
-  yield = string_cat(yield, s);
-  }
+if (testflag(addr, af_include_affixes) && (s = addr->suffix))
+  yield = string_cat(yield, string_get_lpart_sub(addr, s));
 
 return yield;
 }
@@ -1056,7 +1045,7 @@ splitting is done; in those cases use the original field. */
 else
   {
   uschar * cmp;
-  int off = g->ptr;    /* start of the "full address" */
+  int off = gstring_length(g); /* start of the "full address" */
 
   if (addr->local_part)
     {
@@ -1349,23 +1338,25 @@ if (LOGGING(deliver_time))
 if (addr->message)
   g = string_append(g, 2, US": ", addr->message);
 
-(void) string_from_gstring(g);
+ {
+  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->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", g->s);
+  log_write(addr->basic_errno <= ERRNO_RETRY_BASE ? L_retry_defer : 0, logflags,
+    "== %s", s);
+ }
 
 store_reset(reset_point);
 return;
@@ -1428,17 +1419,19 @@ if (addr->message)
 if (LOGGING(deliver_time))
   g = string_append(g, 2, US" DT=", string_timediff(&addr->delivery_time));
 
-(void) string_from_gstring(g);
-
 /* Do the logging. For the message log, "routing failed" for those cases,
 just to make it clearer. */
 
-if (driver_kind)
-  deliver_msglog("%s %s failed for %s\n", now, driver_kind, g->s);
-else
-  deliver_msglog("%s %s\n", now, g->s);
+ {
+  const uschar * s = string_from_gstring(g);
 
-log_write(0, LOG_MAIN, "** %s", g->s);
+  if (driver_kind)
+    deliver_msglog("%s %s failed for %s\n", now, driver_kind, s);
+  else
+    deliver_msglog("%s %s\n", now, s);
+
+  log_write(0, LOG_MAIN, "** %s", s);
+ }
 
 store_reset(reset_point);
 return;
@@ -4301,10 +4294,14 @@ So look out for the place it gets used.
     }
 
   /* Get the maximum it can handle in one envelope, with zero meaning
-  unlimited, which is forced for the MUA wrapper case. */
+  unlimited, which is forced for the MUA wrapper case and if the
+  value could vary depending on the messages.
+  For those, we only split (below) by (tpt,dest,erraddr,hdrs) and rely on the
+  transport splitting further by max_rcp.  So we potentially lose some
+  parallellism. */
 
-  address_count_max = tp->max_addresses;
-  if (address_count_max == 0 || mua_wrapper) address_count_max = 999999;
+  address_count_max = mua_wrapper || Ustrchr(tp->max_addresses, '$')
+    ? UNLIMITED_ADDRS : expand_max_rcpt(tp->max_addresses);
 
 
   /************************************************************************/
@@ -4710,17 +4707,13 @@ all pipes, so I do not see a reason to use non-blocking IO here
     {
     uschar * fname = spool_fname(US"input", message_subdir, message_id, US"-D");
 
-    if ((deliver_datafile = Uopen(fname,
-#ifdef O_CLOEXEC
-                                       O_CLOEXEC |
-#endif
-                                       O_RDWR | O_APPEND, 0)) < 0)
+    if (  (deliver_datafile = Uopen(fname, EXIM_CLOEXEC | O_RDWR | O_APPEND, 0))
+       < 0)
       log_write(0, LOG_MAIN|LOG_PANIC_DIE, "Failed to reopen %s for remote "
         "parallel delivery: %s", fname, strerror(errno));
     }
 
-    /* Set the close-on-exec flag */
-#ifndef O_CLOEXEC
+#ifndef O_CLOEXEC                      /* Set the close-on-exec flag */
     (void)fcntl(deliver_datafile, F_SETFD, fcntl(deliver_datafile, F_GETFD) |
       FD_CLOEXEC);
 #endif
@@ -5754,14 +5747,8 @@ Otherwise it might be needed again. */
   uschar * fname = spool_fname(US"input", message_subdir, id, US"-J");
   FILE * jread;
 
-  if (  (journal_fd = Uopen(fname, O_RDWR|O_APPEND
-#ifdef O_CLOEXEC
-                                   | O_CLOEXEC
-#endif
-#ifdef O_NOFOLLOW
-                                   | O_NOFOLLOW
-#endif
-       , SPOOL_MODE)) >= 0
+  if (  (journal_fd = Uopen(fname,
+             O_RDWR|O_APPEND | EXIM_CLOEXEC | EXIM_NOFOLLOW, SPOOL_MODE)) >= 0
      && lseek(journal_fd, 0, SEEK_SET) == 0
      && (jread = fdopen(journal_fd, "rb"))
      )
@@ -7159,10 +7146,7 @@ if (addr_local || addr_remote)
     uschar * fname = spool_fname(US"input", message_subdir, id, US"-J");
 
     if ((journal_fd = Uopen(fname,
-#ifdef O_CLOEXEC
-                       O_CLOEXEC |
-#endif
-                       O_WRONLY|O_APPEND|O_CREAT|O_EXCL, SPOOL_MODE)) < 0)
+             EXIM_CLOEXEC | O_WRONLY|O_APPEND|O_CREAT|O_EXCL, SPOOL_MODE)) < 0)
       {
       log_write(0, LOG_MAIN|LOG_PANIC, "Couldn't open journal file %s: %s",
        fname, strerror(errno));
@@ -7209,7 +7193,7 @@ local and remote LMTP deliveries. */
 
 if (!regex_IGNOREQUOTA)
   regex_IGNOREQUOTA =
-    regex_must_compile(US"\\n250[\\s\\-]IGNOREQUOTA(\\s|\\n|$)", FALSE, TRUE);
+    regex_must_compile(US"\\n250[\\s\\-]IGNOREQUOTA(\\s|\\n|$)", MCS_NOFLAGS, TRUE);
 
 /* Handle local deliveries */
 
@@ -8609,7 +8593,7 @@ if (cutthrough.cctx.sock >= 0 && cutthrough.callout_hold_only)
     if (pid == 0)      /* child: will fork again to totally disconnect */
       {
       smtp_proxy_tls(cutthrough.cctx.tls_ctx, big_buffer, big_buffer_size,
-                     pfd, 5*60);
+                     pfd, 5*60, cutthrough.host.name);
       /* does not return */
       }