JSON: add jsons extract variant, to strip quotes from string results
[exim.git] / src / src / expand.c
index ea10f990db4aea7c6e343290d8ec281fbcbde157..79304c8b1ab5ae8ec90a2ad856e79b76a7503d30 100644 (file)
@@ -2170,7 +2170,7 @@ BOOL testfor = TRUE;
 BOOL tempcond, combined_cond;
 BOOL *subcondptr;
 BOOL sub2_honour_dollar = TRUE;
-int i, rc, cond_type, roffset;
+int rc, cond_type, roffset;
 int_eximarith_t num[2];
 struct stat statbuf;
 uschar name[256];
@@ -2737,7 +2737,7 @@ switch(cond_type)
 
       if (sublen == 24)
         {
-        uschar *coded = b64encode(digest, 16);
+        uschar *coded = b64encode(CUS digest, 16);
         DEBUG(D_auth) debug_printf("crypteq: using MD5+B64 hashing\n"
           "  subject=%s\n  crypted=%s\n", coded, sub[1]+5);
         tempcond = (Ustrcmp(coded, sub[1]+5) == 0);
@@ -2774,7 +2774,7 @@ switch(cond_type)
 
       if (sublen == 28)
         {
-        uschar *coded = b64encode(digest, 20);
+        uschar *coded = b64encode(CUS digest, 20);
         DEBUG(D_auth) debug_printf("crypteq: using SHA1+B64 hashing\n"
           "  subject=%s\n  crypted=%s\n", coded, sub[1]+6);
         tempcond = (Ustrcmp(coded, sub[1]+6) == 0);
@@ -3893,7 +3893,8 @@ return NULL;
 /* Pull off the leading array or object element, returning
 a copy in an allocated string.  Update the list pointer.
 
-The element may itself be an abject or array.
+The element may itself be an object or array.
+Return NULL when the list is empty.
 */
 
 uschar *
@@ -3915,6 +3916,7 @@ for (item = s;
     case '}': object_depth--; break;
     }
 *list = *s ? s+1 : s;
+if (item == s) return NULL;
 item = string_copyn(item, s - item);
 DEBUG(D_expand) debug_printf_indent("  json ele: '%s'\n", item);
 return US item;
@@ -5344,7 +5346,6 @@ while (*s != 0)
     case EITEM_NHASH:
     case EITEM_SUBSTR:
       {
-      int i;
       int len;
       uschar *ret;
       int val[2] = { 0, -1 };
@@ -5634,7 +5635,13 @@ while (*s != 0)
       uschar *sub[3];
       int save_expand_nmax =
         save_expand_strings(save_expand_nstring, save_expand_nlength);
-      enum {extract_basic, extract_json} fmt = extract_basic;
+
+      /* On reflection the original behaviour of extract-json for a string
+      result, leaving it quoted, was a mistake.  But it was already published,
+      hence the addition of jsons.  In a future major version, make json
+      work like josons, and withdraw jsons. */
+
+      enum {extract_basic, extract_json, extract_jsons} fmt = extract_basic;
 
       while (isspace(*s)) s++;
 
@@ -5642,7 +5649,10 @@ while (*s != 0)
 
       if (*s != '{')                                   /*}*/
        if (Ustrncmp(s, "json", 4) == 0)
-         {fmt = extract_json; s += 4;}
+         if (*(s += 4) == 's')
+           {fmt = extract_jsons; s++;}
+         else
+           fmt = extract_json;
 
       /* While skipping we cannot rely on the data for expansions being
       available (eg. $item) hence cannot decide on numeric vs. keyed.
@@ -5723,7 +5733,7 @@ while (*s != 0)
            if (*p == 0)
              {
              field_number *= x;
-             if (fmt != extract_json) j = 3;               /* Need 3 args */
+             if (fmt == extract_basic) j = 3;               /* Need 3 args */
              field_number_set = TRUE;
              }
             }
@@ -5750,6 +5760,7 @@ while (*s != 0)
          break;
 
        case extract_json:
+       case extract_jsons:
          {
          uschar * s, * item;
          const uschar * list;
@@ -5777,10 +5788,11 @@ while (*s != 0)
              }
            while (field_number > 0 && (item = json_nextinlist(&list)))
              field_number--;
-           s = item;
-           lookup_value = s;
-           while (*s) s++;
-           while (--s >= lookup_value && isspace(*s)) *s = '\0';
+           if ((lookup_value = s = item))
+             {
+             while (*s) s++;
+             while (--s >= lookup_value && isspace(*s)) *s = '\0';
+             }
            }
          else
            {
@@ -5815,6 +5827,17 @@ while (*s != 0)
              }
            }
          }
+
+         if (  fmt == extract_jsons
+            && lookup_value
+            && !(lookup_value = dewrap(lookup_value, US"\"\"")))
+           {
+           expand_string_message =
+             string_sprintf("%s wrapping string result for extract jsons",
+               expand_string_message);
+           goto EXPAND_FAILED_CURLY;
+           }
+         break;        /* json/s */
        }
 
       /* If no string follows, $value gets substituted; otherwise there can
@@ -6844,7 +6867,7 @@ while (*s != 0)
             }
           }
 
-        enc = b64encode(sub, out - sub);
+        enc = b64encode(CUS sub, out - sub);
         yield = string_cat(yield, enc);
         continue;
         }
@@ -7508,9 +7531,9 @@ while (*s != 0)
 #ifdef SUPPORT_TLS
        uschar * s = vp && *(void **)vp->value
          ? tls_cert_der_b64(*(void **)vp->value)
-         : b64encode(sub, Ustrlen(sub));
+         : b64encode(CUS sub, Ustrlen(sub));
 #else
-       uschar * s = b64encode(sub, Ustrlen(sub));
+       uschar * s = b64encode(CUS sub, Ustrlen(sub));
 #endif
        yield = string_cat(yield, s);
        continue;