build: use pkg-config for i18n
[exim.git] / src / src / filtertest.c
index 092febaa486352ff5eafba01468e40db05a5abcb..35d939ee0b3795b8b9bc317f39272de996fe528c 100644 (file)
@@ -1,11 +1,11 @@
-/* $Cambridge: exim/src/src/filtertest.c,v 1.7 2005/08/30 10:07:58 ph10 Exp $ */
-
 /*************************************************
 *     Exim - an Internet mail transport agent    *
 *************************************************/
 
 /*************************************************
 *     Exim - an Internet mail transport agent    *
 *************************************************/
 
-/* Copyright (c) University of Cambridge 1995 - 2005 */
+/* Copyright (c) The Exim Maintainers 2021 - 2024 */
+/* Copyright (c) University of Cambridge 1995 - 2009 */
 /* See the file NOTICE for conditions of use and distribution. */
 /* See the file NOTICE for conditions of use and distribution. */
+/* SPDX-License-Identifier: GPL-2.0-or-later */
 
 
 /* Code for the filter test function. */
 
 
 /* Code for the filter test function. */
 we can set up the message_body variables at the same time (in normal use, the
 message_body variables are not set up unless needed). The reading code is
 written out here rather than having options in read_message_data, in order to
 we can set up the message_body variables at the same time (in normal use, the
 message_body variables are not set up unless needed). The reading code is
 written out here rather than having options in read_message_data, in order to
-keep that function as efficient as possible. Handling message_body_end is
-somewhat more tedious. Pile it all into a circular buffer and sort out at the
-end.
+keep that function as efficient as possible. (Later: this function is now
+global because it is also used by the -bem testing option.) Handling
+message_body_end is somewhat more tedious. Pile it all into a circular buffer
+and sort out at the end.
 
 Arguments:
   dot_ended   TRUE if message already terminated by '.'
 
 Arguments:
   dot_ended   TRUE if message already terminated by '.'
@@ -32,7 +33,7 @@ Arguments:
 Returns:      nothing
 */
 
 Returns:      nothing
 */
 
-static void
+void
 read_message_body(BOOL dot_ended)
 {
 register int ch;
 read_message_body(BOOL dot_ended)
 {
 register int ch;
@@ -46,11 +47,11 @@ body_len = 0;
 body_linecount = 0;
 header_size = message_size;
 
 body_linecount = 0;
 header_size = message_size;
 
-if (!dot_ended && !feof(stdin))
+if (!dot_ended && !stdin_feof())
   {
   {
-  if (!dot_ends)
+  if (!f.dot_ends)
     {
     {
-    while ((ch = getc(stdin)) != EOF)
+    while ((ch = stdin_getc(GETC_BUFFER_UNLIMITED)) != EOF)
       {
       if (ch == 0) body_zerocount++;
       if (ch == '\n') body_linecount++;
       {
       if (ch == 0) body_zerocount++;
       if (ch == '\n') body_linecount++;
@@ -63,7 +64,7 @@ if (!dot_ended && !feof(stdin))
   else
     {
     int ch_state = 1;
   else
     {
     int ch_state = 1;
-    while ((ch = getc(stdin)) != EOF)
+    while ((ch = stdin_getc(GETC_BUFFER_UNLIMITED)) != EOF)
       {
       if (ch == 0) body_zerocount++;
       switch (ch_state)
       {
       if (ch == 0) body_zerocount++;
       switch (ch_state)
@@ -96,7 +97,7 @@ if (!dot_ended && !feof(stdin))
       if (s > message_body_end + message_body_visible) s = message_body_end;
       message_size++;
       }
       if (s > message_body_end + message_body_visible) s = message_body_end;
       message_size++;
       }
-    READ_END: ch = ch;  /* Some compilers don't like null statements */
+    READ_END: ;
     }
   if (s == message_body_end || s[-1] != '\n') body_linecount++;
   }
     }
   if (s == message_body_end || s[-1] != '\n') body_linecount++;
   }
@@ -113,7 +114,7 @@ if (body_len >= message_body_visible)
   int above = message_body_visible - below;
   if (above > 0)
     {
   int above = message_body_visible - below;
   if (above > 0)
     {
-    uschar *temp = store_get(below);
+    uschar * temp = store_get(below, GET_UNTAINTED);
     memcpy(temp, message_body_end, below);
     memmove(message_body_end, s+1, above);
     memcpy(message_body_end + above, temp, below);
     memcpy(temp, message_body_end, below);
     memmove(message_body_end, s+1, above);
     memcpy(message_body_end + above, temp, below);
@@ -142,6 +143,30 @@ while (body_end_len > 0)
 
 
 
 
 
 
+static int
+exim_filter_interpret(const uschar * filebuf, int options,
+  address_item ** addrp, uschar ** error)
+{
+#ifdef DISABLE_EXIM_FILTER
+  printf("exim: Exim-filtering not available\n");
+  return FF_ERROR;
+#else
+
+const misc_module_info * mi;
+uschar * errstr = NULL;
+typedef int (*fn_t)(const uschar *, int, address_item **, uschar **);
+if (!(mi = misc_mod_find(US"exim_filter", &errstr)))
+  {
+  printf("exim: Exim-filtering not available: %s\n", errstr ? errstr : US"?");
+  return FF_ERROR;
+  }
+return(((fn_t *) mi->functions)[EXIM_INTERPRET])
+                             (filebuf, options, addrp, error);
+#endif
+}
+
+
+
 /*************************************************
 *            Test a mail filter                  *
 *************************************************/
 /*************************************************
 *            Test a mail filter                  *
 *************************************************/
@@ -162,7 +187,7 @@ Returns:      TRUE if no errors
 */
 
 BOOL
 */
 
 BOOL
-filter_runtest(int fd, uschar *filename, BOOL is_system, BOOL dot_ended)
+filter_runtest(int fd, const uschar * filename, BOOL is_system, BOOL dot_ended)
 {
 int rc, filter_type;
 BOOL yield;
 {
 int rc, filter_type;
 BOOL yield;
@@ -179,7 +204,7 @@ if (fstat(fd, &statbuf) != 0)
   return FALSE;
   }
 
   return FALSE;
   }
 
-filebuf = store_get(statbuf.st_size + 1);
+filebuf = store_get(statbuf.st_size + 1, filename);
 rc = read(fd, filebuf, statbuf.st_size);
 (void)close(fd);
 
 rc = read(fd, filebuf, statbuf.st_size);
 (void)close(fd);
 
@@ -200,8 +225,8 @@ filter_type = rda_is_filter(filebuf);
 if (is_system && filter_type == FILTER_FORWARD) filter_type = FILTER_EXIM;
 
 printf("Testing %s file \"%s\"\n\n",
 if (is_system && filter_type == FILTER_FORWARD) filter_type = FILTER_EXIM;
 
 printf("Testing %s file \"%s\"\n\n",
-  (filter_type == FILTER_EXIM)? "Exim filter" :
-  (filter_type == FILTER_SIEVE)? "Sieve filter" :
+  filter_type == FILTER_EXIM ? "Exim filter" :
+  filter_type == FILTER_SIEVE ? "Sieve filter" :
   "forward file",
   filename);
 
   "forward file",
   filename);
 
@@ -232,13 +257,13 @@ if (filter_type == FILTER_FORWARD)
     return FALSE;
     }
 
     return FALSE;
     }
 
-  if (generated == NULL)
+  if (!generated)
     printf("exim: no addresses generated from forward file\n");
 
   else
     {
     printf("exim: forward file generated:\n");
     printf("exim: no addresses generated from forward file\n");
 
   else
     {
     printf("exim: forward file generated:\n");
-    while (generated != NULL)
+    while (generated)
       {
       printf("  %s\n", generated->address);
       generated = generated->next;
       {
       printf("  %s\n", generated->address);
       generated = generated->next;
@@ -251,7 +276,7 @@ if (filter_type == FILTER_FORWARD)
 /* For a filter, set up the message_body variables and the message size if this
 is the first time this function has been called. */
 
 /* For a filter, set up the message_body variables and the message size if this
 is the first time this function has been called. */
 
-if (message_body == NULL) read_message_body(dot_ended);
+if (!message_body) read_message_body(dot_ended);
 
 /* Now pass the filter file to the function that interprets it. Because
 filter_test is not FILTER_NONE, the interpreter will output comments about what
 
 /* Now pass the filter file to the function that interprets it. Because
 filter_test is not FILTER_NONE, the interpreter will output comments about what
@@ -260,21 +285,30 @@ testing a system filter that is going to be followed by a user filter test. */
 
 if (is_system)
   {
 
 if (is_system)
   {
-  system_filtering = TRUE;
-  enable_dollar_recipients = TRUE; /* Permit $recipients in system filter */
-  yield = filter_interpret
-    (filebuf,
-    RDO_DEFER|RDO_FAIL|RDO_FILTER|RDO_FREEZE|RDO_REWRITE, &generated, &error);
-  enable_dollar_recipients = FALSE;
-  system_filtering = FALSE;
+  f.system_filtering = TRUE;
+  f.enable_dollar_recipients = TRUE; /* Permit $recipients in system filter */
+  yield = exim_filter_interpret(filebuf,
+      RDO_DEFER|RDO_FAIL|RDO_FILTER|RDO_FREEZE|RDO_REWRITE, &generated, &error);
+  f.enable_dollar_recipients = FALSE;
+  f.system_filtering = FALSE;
   }
   }
-else
+else if (filter_type == FILTER_SIEVE)
   {
   {
-  yield = (filter_type == FILTER_SIEVE)?
-    sieve_interpret(filebuf, RDO_REWRITE, NULL, NULL, NULL, &generated, &error)
-    :
-    filter_interpret(filebuf, RDO_REWRITE, &generated, &error);
+  const misc_module_info * mi;
+  uschar * errstr = NULL;
+  typedef int (*fn_t)(const uschar *, int, const sieve_block *,
+                      address_item **, uschar **);
+  if (!(mi = misc_mod_find(US"sieve_filter", &errstr)))
+    {
+    printf("exim: Sieve filtering not available: %s\n", errstr ? errstr : US"?");
+    yield = FF_ERROR;
+    }
+  else
+    yield = (((fn_t *) mi->functions)[SIEVE_INTERPRET])
+                             (filebuf, RDO_REWRITE, NULL, &generated, &error);
   }
   }
+else
+  yield = exim_filter_interpret(filebuf, RDO_REWRITE, &generated, &error);
 
 return yield != FF_ERROR;
 }
 
 return yield != FF_ERROR;
 }