Make whitespace strings compare euqal to zero. fixes: bug #749
[exim.git] / src / src / expand.c
index beb72aa678470696e617dcc3fc874598c6ee3477..599dd9c0d70fdd5d509793efc64873f7be1b5735 100644 (file)
@@ -1,4 +1,4 @@
-/* $Cambridge: exim/src/src/expand.c,v 1.92 2008/01/17 13:03:35 tom Exp $ */
+/* $Cambridge: exim/src/src/expand.c,v 1.97 2008/12/12 14:51:47 nm4 Exp $ */
 
 /*************************************************
 *     Exim - an Internet mail transport agent    *
@@ -575,6 +575,7 @@ static var_entry var_table[] = {
   { "spam_score_int",      vtype_stringptr,   &spam_score_int },
 #endif
 #ifdef EXPERIMENTAL_SPF
+  { "spf_guess",           vtype_stringptr,   &spf_guess },
   { "spf_header_comment",  vtype_stringptr,   &spf_header_comment },
   { "spf_received",        vtype_stringptr,   &spf_received },
   { "spf_result",          vtype_stringptr,   &spf_result },
@@ -3135,6 +3136,12 @@ we reset the store before processing it; if the result is in fresh store, we
 use that without copying. This is helpful for expanding strings like
 $message_headers which can get very long.
 
+There's a problem if a ${dlfunc item has side-effects that cause allocation,
+since resetting the store at the end of the expansion will free store that was
+allocated by the plugin code as well as the slop after the expanded string. So
+we skip any resets if ${dlfunc has been used. This is an unfortunate
+consequence of string expansion becoming too powerful.
+
 Arguments:
   string         the string to be expanded
   ket_ends       true if expansion is to stop at }
@@ -3160,6 +3167,7 @@ uschar *yield = store_get(size);
 uschar *s = string;
 uschar *save_expand_nstring[EXPAND_MAXN+1];
 int save_expand_nlength[EXPAND_MAXN+1];
+BOOL resetok = TRUE;
 
 expand_string_forcedfail = FALSE;
 expand_string_message = US"";
@@ -3232,7 +3240,7 @@ while (*s != 0)
 
     if (ptr == 0 && yield != NULL)
       {
-      store_reset(yield);
+      if (resetok) store_reset(yield);
       yield = NULL;
       size = 0;
       }
@@ -3817,7 +3825,7 @@ while (*s != 0)
              Adjust "inow" accordingly. */
           if ( (iexpire < 7) && (inow >= 993) ) inow = 0;
 
-          if (iexpire > inow)
+          if (iexpire >= inow)
             {
             prvscheck_result = US"1";
             DEBUG(D_expand) debug_printf("prvscheck: success, $pvrs_result set to 1\n");
@@ -4651,7 +4659,7 @@ while (*s != 0)
             while (len > 0 && isspace(p[len-1])) len--;
             p[len] = 0;
 
-            if (*p == 0)
+            if (*p == 0 && !skipping)
               {
               expand_string_message = US"first argument of \"extract\" must "
                 "not be empty";
@@ -4962,8 +4970,10 @@ while (*s != 0)
       returns OK, we have a replacement string; if it returns DEFER then
       expansion has failed in a non-forced manner; if it returns FAIL then
       failure was forced; if it returns ERROR or any other value there's a
-      problem, so panic slightly. */
+      problem, so panic slightly. In any case, assume that the function has
+      side-effects on the store that must be preserved. */
 
+      resetok = FALSE;
       result = NULL;
       for (argc = 0; argv[argc] != NULL; argc++);
       status = func(&result, argc - 2, &argv[2]);
@@ -5701,7 +5711,7 @@ while (*s != 0)
     int newsize = 0;
     if (ptr == 0)
       {
-      store_reset(yield);
+      if (resetok) store_reset(yield);
       yield = NULL;
       size = 0;
       }
@@ -5756,7 +5766,7 @@ if (left != NULL) *left = s;
 In many cases the final string will be the first one that was got and so there
 will be optimal store usage. */
 
-store_reset(yield + ptr + 1);
+if (resetok) store_reset(yield + ptr + 1);
 DEBUG(D_expand)
   {
   debug_printf("expanding: %.*s\n   result: %s\n", (int)(s - string), string,
@@ -5864,6 +5874,23 @@ systems, so we set it zero ourselves. */
 
 errno = 0;
 expand_string_message = NULL;               /* Indicates no error */
+
+/* Before Exim 4.64, strings consisting entirely of whitespace compared
+equal to 0.  Unfortunately, people actually relied upon that, so preserve
+the behaviour explicitly.  Stripping leading whitespace is a harmless
+noop change since strtol skips it anyway (provided that there is a number
+to find at all). */
+if (isspace(*s))
+  {
+  while (isspace(*s)) ++s;
+  if (*s == '\0')
+    {
+      DEBUG(D_expand)
+       debug_printf("treating blank string as number 0\n");
+      return 0;
+    }
+  }
+
 value = strtol(CS s, CSS &endptr, 10);
 
 if (endptr == s)