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

--- src/globals.h.orig	Thu Jun 13 09:32:04 2002
+++ src/globals.h	Fri Jun 21 14:01:50 2002
@@ -235,6 +235,8 @@
 extern int     filter_sn[FILTER_VARIABLE_COUNT]; /* variables set by system filter */
 extern uschar *filter_test;            /* Run as a filter tester on this file */
 extern uschar *filter_thisaddress;     /* For address looping */
+extern uschar *filter_expansion;       /* Valid if string expansion succeeds */
+extern uschar *filter_expansion_error; /* Valid if string expansion fails */
 extern int     finduser_retries;       /* Retry count for getpwnam() */
 extern uschar *freeze_tell;            /* Message on (some) freezings */
 
--- src/globals.c.orig	Thu Jun 13 09:32:04 2002
+++ src/globals.c	Fri Jun 21 14:02:32 2002
@@ -396,6 +396,8 @@
 int     filter_sn[FILTER_VARIABLE_COUNT];
 uschar *filter_test            = NULL;
 uschar *filter_thisaddress     = NULL;
+uschar *filter_expansion       = NULL;
+uschar *filter_expansion_error = NULL;
 int     finduser_retries       = 0;
 uschar *freeze_tell            = NULL;
 
--- src/expand.c.orig	Thu Jun 13 09:32:04 2002
+++ src/expand.c	Fri Jun 21 14:03:38 2002
@@ -169,6 +169,8 @@
   { "dnslist_value",       vtype_stringptr,   &dnslist_value },
   { "domain",              vtype_stringptr,   &deliver_domain },
   { "domain_data",         vtype_stringptr,   &deliver_domain_data },
+  { "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	Thu Jun 13 09:32:04 2002
+++ src/filter.c	Fri Jun 21 14:06:29 2002
@@ -123,14 +123,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",
@@ -139,7 +140,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. */
@@ -548,6 +550,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. */
 
@@ -804,6 +832,10 @@
   print_condition(c->right, FALSE);
   debug_printf(")");
   break;
+
+  case cond_canexpand:
+  debug_printf("%s %s", name, c->left);
+  break;
   }
 }
 
@@ -1591,6 +1623,23 @@
   parse_found_group = FALSE;
   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. */
 
@@ -2129,6 +2178,8 @@
     case if_command:
       {
       uschar *save_address = filter_thisaddress;
+      uschar *save_expansion = filter_expansion;
+      uschar *save_expanderr = filter_expansion_error;
       int ok = FF_DELIVERED;
       condition_value =
         test_condition((condition_block *)(commands->args[0]), TRUE);
@@ -2140,6 +2191,8 @@
         output_indent -= 2;
         }
       filter_thisaddress = save_address;
+      filter_expansion = save_expansion;
+      filter_expansion_error = save_expanderr;
       if (finish_obeyed || (ok != FF_DELIVERED && ok != FF_NOTDELIVERED))
         return ok;
       }

