This patch implements the "can expand <string>" test for filters.

--- src/globals.h.orig	Wed Jun 14 07:57:42 2000
+++ src/globals.h	Sun Jul 16 02:43:27 2000
@@ -194,6 +194,8 @@
 extern int    filter_sn[FILTER_VARIABLE_COUNT]; /* variables set by system filter */
 extern char  *filter_test;            /* Run as a filter tester on this file */
 extern char  *filter_thisaddress;     /* For address looping */
+extern char  *filter_expansion;       /* Valid if string expansion succeeds */
+extern char  *filter_expansion_error; /* Valid if string expansion fails */
 extern int    finduser_retries;       /* Retry count for getpwnam() */
 extern BOOL   forbid_domain_literals; /* As it says */
 extern BOOL   freeze_tell_mailmaster; /* Message on each freeze */
--- src/globals.c.orig	Wed Jun 14 07:57:42 2000
+++ src/globals.c	Sun Jul 16 02:49:30 2000
@@ -291,6 +291,8 @@
 int    filter_sn[FILTER_VARIABLE_COUNT];
 char  *filter_test            = NULL;
 char  *filter_thisaddress     = NULL;
+char  *filter_expansion       = NULL;
+char  *filter_expansion_error = NULL;
 int    finduser_retries       = 0;
 BOOL   forbid_domain_literals = FALSE;
 BOOL   freeze_tell_mailmaster = FALSE;
--- src/expand.c.orig	Wed Jun 14 07:57:42 2000
+++ src/expand.c	Sun Jul 16 02:44:26 2000
@@ -84,6 +84,8 @@
   { "domain",              vtype_stringptr,   &deliver_domain },
   { "domain_data",         vtype_stringptr,   &domain_data },
   { "errmsg_recipient",    vtype_stringptr,   &errmsg_recipient },
+  { "expansion",           vtype_stringptr,   &filter_expansion },
+  { "expansion_error",     vtype_stringptr,   &filter_expansion_error },
   { "home",                vtype_stringptr,   &deliver_home },
   { "host",                vtype_stringptr,   &deliver_host },
   { "host_address",        vtype_stringptr,   &deliver_host_address },
--- src/filter.c.orig	Wed Jun 14 07:57:42 2000
+++ src/filter.c	Sun Jul 16 03:07:05 2000
@@ -128,14 +128,15 @@
        cond_ends, cond_ENDS, cond_is, cond_IS, cond_matches,
        cond_MATCHES, cond_contains, cond_CONTAINS, cond_delivered,
        cond_above, cond_below, cond_errormsg, cond_firsttime,
-       cond_manualthaw, cond_foranyaddress };
+       cond_manualthaw, cond_foranyaddress, cond_canexpand };
 
 static char *cond_names[] = {
   "and", "or", "personal",
   "begins", "BEGINS", "ends", "ENDS",
   "is", "IS", "matches", "MATCHES", "contains",
   "CONTAINS", "delivered", "above", "below", "error_message",
-  "first_delivery", "manually_thawed", "foranyaddress" };
+  "first_delivery", "manually_thawed", "foranyaddress",
+  "can expand" };
 
 static char *cond_not_names[] = {
   "", "", "not personal",
@@ -144,7 +145,8 @@
   "is not", "IS not", "does not match",
   "does not MATCH", "does not contain", "does not CONTAIN",
   "not delivered", "not above", "not below", "not error_message",
-  "not first_delivery", "not manually_thawed", "not foranyaddress" };
+  "not first_delivery", "not manually_thawed", "not foranyaddress",
+  "cannot expand" };
 
 /* Tables of binary condition words and their corresponding types. Not easy
 to amalgamate with the above because of the different variants. */
@@ -553,6 +555,32 @@
       ptr = nextsigchar(ptr+1, TRUE);
       }
 
+    /* Canexpand is just followed by the string we want to check for
+    expandability. The condition name itself is two words which makes
+    things slightly unusual. */
+
+    else if (strcmp(buffer, "can") == 0 ||
+	     strcmp(buffer, "cannot") == 0)
+      {
+      if (buffer[3] == 'n') /* first letter of "not" or '\0' */
+	c->testfor = !c->testfor;
+
+      ptr = nextitem(ptr, buffer, sizeof(buffer), TRUE);
+      if (*error_pointer != NULL) break;
+      if (strcmp(buffer, "expand") != 0)
+	{
+	*error_pointer = string_sprintf("expected \"expand\" "
+	  "in line %d of filter file", line_number);
+	break;
+	}
+
+      ptr = nextitem(ptr, buffer, sizeof(buffer), TRUE);
+      if (*error_pointer != NULL) break;
+
+      c->type = cond_canexpand;
+      c->left = string_copy(buffer);
+      }
+
     /* If it's not a word we recognize, then it must be the lefthand
     operand of one of the comparison words. */
 
@@ -808,6 +836,10 @@
   print_condition(c->right, FALSE);
   debug_printf(")");
   break;
+
+  case cond_canexpand:
+  debug_printf("%s %s", name, c->left);
+  break;
   }
 }
 
@@ -1579,6 +1611,23 @@
     }
   break;
 
+  /* The canexpand condition tests if a string expansion succeeds. */
+
+  case cond_canexpand:
+  p = (char *)(c->left);
+  pp = expand_string(p);
+  if (pp == NULL)
+    {
+    yield = FALSE;
+    filter_expansion_error = expand_string_message;
+    }
+  else
+    {
+    yield = TRUE;
+    filter_expansion = pp;
+    }
+  break;
+
   /* All other conditions have left and right values that need expanding;
   on error, it doesn't matter what value is returned. */
 
@@ -2138,6 +2187,8 @@
     case if_command:
       {
       char *save_address = filter_thisaddress;
+      char *save_expansion = filter_expansion;
+      char *save_expanderr = filter_expansion_error;
       BOOL ok = TRUE;
       condition_value =
         test_condition((condition_block *)(commands->args[0]), delivered, TRUE);
@@ -2150,6 +2201,8 @@
         output_indent -= 2;
         }
       filter_thisaddress = save_address;
+      filter_expansion = save_expansion;
+      filter_expansion_error = save_expanderr;
       if (!ok) return FALSE;
       }
     break;
