Expand recipients_max
[exim.git] / src / src / moan.c
index 51f5da58a28ee723f1c141815251c9e6a4469705..a3c8e0aba4af20dc596e39f3ab71e02184b69d49 100644 (file)
@@ -2,8 +2,10 @@
 *     Exim - an Internet mail transport agent    *
 *************************************************/
 
+/* 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 */
 
 /* Functions for sending messages to sender or to mailmaster. */
 
@@ -63,7 +65,7 @@ if (!message_id)
     if (h->type == htype_id)
       {
       message_id = Ustrchr(h->text, ':') + 1;
-      while (isspace(*message_id)) message_id++;
+      Uskip_whitespace(&message_id);
       }
 
 for (h = header_list; h; h = h->next)
@@ -78,28 +80,48 @@ if (!h)
 /* We limit the total length of references.  Although there is no fixed
 limit, some systems do not like headers growing beyond recognition.
 Keep the first message ID for the thread root and the last few for
-the position inside the thread, up to a maximum of 12 altogether. */
+the position inside the thread, up to a maximum of 12 altogether.
+Also apply the max line length limit from RFC 2822 2.1.1
+
+XXX preferably we would get any limit from the outbound transport,
+passed in here for a limit value.
+*/
 
 if (h || message_id)
   {
-  fprintf(fp, "References:");
+  unsigned use = fprintf(fp, "References:");
+  if (message_id) use += Ustrlen(message_id) + 1;
   if (h)
     {
-    uschar * s, * id, * error;
+    const uschar * s;
+    uschar * id, * error;
     uschar * referenced_ids[12];
     int reference_count = 0;
 
     s = Ustrchr(h->text, ':') + 1;
     f.parse_allow_group = FALSE;
     while (*s && (s = parse_message_id(s, &id, &error)))
-      if (reference_count == nelem(referenced_ids))
-        {
-        memmove(referenced_ids + 1, referenced_ids + 2,
-           sizeof(referenced_ids) - 2*sizeof(uschar *));
-        referenced_ids[reference_count - 1] = id;
-        }
+      {
+      unsigned this = Ustrlen(id);
+      if (  reference_count == nelem(referenced_ids)
+        || use + this + reference_count > 998
+         )
+       {
+       if (reference_count > 1)
+         {
+         /* drop position 1 and shuffle down */
+         use -= Ustrlen(referenced_ids + 1);
+         memmove(referenced_ids + 1, referenced_ids + 2,
+            sizeof(referenced_ids) - 2*sizeof(*referenced_ids));
+
+         /* append new one */
+         referenced_ids[reference_count - 1] = id;
+         }
+       }
       else
        referenced_ids[reference_count++] = id;
+      use += this;
+      }
 
     for (int i = 0; i < reference_count; ++i)
       fprintf(fp, " %s", referenced_ids[i]);
@@ -136,8 +158,8 @@ Returns:         TRUE if message successfully sent
 */
 
 BOOL
-moan_send_message(uschar *recipient, int ident, error_block *eblock,
-  header_line *headers, FILE *message_file, uschar *firstline)
+moan_send_message(const uschar * recipient, int ident, error_block * eblock,
+  header_line * headers, FILE * message_file, uschar * firstline)
 {
 int written = 0;
 int fd;
@@ -384,7 +406,7 @@ if (bounce_return_message)
   if (bounce_return_body && message_file)
     {
     BOOL enddot = f.dot_ends && message_file == stdin;
-    uschar * buf = store_get(bounce_return_linesize_limit+2, TRUE);
+    uschar * buf = store_get(bounce_return_linesize_limit+2, GET_TAINTED);
 
     if (firstline) fprintf(fp, "%s", CS firstline);
 
@@ -539,7 +561,7 @@ switch(ident)
 
   case ERRMESS_TOOMANYRECIP:
   log_write(0, LOG_MAIN, "%s: too many recipients (max set to %d)", msg,
-    recipients_max);
+    recipients_max_expanded);
   break;
 
   case ERRMESS_LOCAL_SCAN:
@@ -609,7 +631,7 @@ if (addr)
   fprintf(f, "\nThe following address(es) have yet to be delivered:\n");
   for (; addr; addr = addr->next)
     {
-    uschar * parent = addr->parent ? addr->parent->address : NULL;
+    const uschar * parent = addr->parent ? addr->parent->address : NULL;
     fprintf(f, "  %s", addr->address);
     if (parent) fprintf(f, " <%s>", parent);
     if (addr->basic_errno > 0) fprintf(f, ": %s", strerror(addr->basic_errno));
@@ -692,7 +714,7 @@ fprintf(stderr, "%d previous message%s successfully processed.\n",
 
 fprintf(stderr, "The rest of the batch was abandoned.\n");
 
-exim_exit(yield, US"batch");
+exim_exit(yield);
 }
 
 
@@ -712,28 +734,28 @@ Returns:    additional recipient list or NULL
 */
 
 uschar *
-moan_check_errorcopy(uschar *recipient)
+moan_check_errorcopy(const uschar * recipient)
 {
-uschar *item, *localpart, *domain;
-const uschar *listptr = errors_copy;
+uschar * item;
+const uschar * localpart, * domain;
+const uschar * listptr = errors_copy;
 uschar *yield = NULL;
-uschar buffer[256];
 int sep = 0;
 int llen;
 
-if (errors_copy == NULL) return NULL;
+if (!errors_copy) return NULL;
 
 /* Set up pointer to the local part and domain, and compute the
 length of the local part. */
 
 localpart = recipient;
 domain = Ustrrchr(recipient, '@');
-if (domain == NULL) return NULL;  /* should not occur, but avoid crash */
+if (!domain) return NULL;      /* should not occur, but avoid crash */
 llen = domain++ - recipient;
 
 /* Scan through the configured items */
 
-while ((item = string_nextinlist(&listptr, &sep, buffer, sizeof(buffer))))
+while ((item = string_nextinlist(&listptr, &sep, NULL, 0)))
   {
   const uschar *newaddress = item;
   const uschar *pattern = string_dequote(&newaddress);