constification
[exim.git] / src / src / expand.c
index 4135574d6b7f90de130602a653494cd745fcdbc1..fd5884306400c1851d2ae9cd769749cef393d192 100644 (file)
@@ -30,10 +30,6 @@ typedef unsigned esi_flags;
 # endif
 #endif /*!STAND_ALONE*/
 
-#ifdef LOOKUP_LDAP
-# include "lookups/ldap.h"
-#endif
-
 #ifdef SUPPORT_CRYPTEQ
 # ifdef CRYPT_H
 #  include <crypt.h>
@@ -425,51 +421,6 @@ enum {
 };
 
 
-/* Types of table entry */
-
-enum vtypes {
-  vtype_int,            /* value is address of int */
-  vtype_filter_int,     /* ditto, but recognized only when filtering */
-  vtype_ino,            /* value is address of ino_t (not always an int) */
-  vtype_uid,            /* value is address of uid_t (not always an int) */
-  vtype_gid,            /* value is address of gid_t (not always an int) */
-  vtype_bool,           /* value is address of bool */
-  vtype_stringptr,      /* value is address of pointer to string */
-  vtype_msgbody,        /* as stringptr, but read when first required */
-  vtype_msgbody_end,    /* ditto, the end of the message */
-  vtype_msgheaders,     /* the message's headers, processed */
-  vtype_msgheaders_raw, /* the message's headers, unprocessed */
-  vtype_localpart,      /* extract local part from string */
-  vtype_domain,         /* extract domain from string */
-  vtype_string_func,   /* value is string returned by given function */
-  vtype_todbsdin,       /* value not used; generate BSD inbox tod */
-  vtype_tode,           /* value not used; generate tod in epoch format */
-  vtype_todel,          /* value not used; generate tod in epoch/usec format */
-  vtype_todf,           /* value not used; generate full tod */
-  vtype_todl,           /* value not used; generate log tod */
-  vtype_todlf,          /* value not used; generate log file datestamp tod */
-  vtype_todzone,        /* value not used; generate time zone only */
-  vtype_todzulu,        /* value not used; generate zulu tod */
-  vtype_reply,          /* value not used; get reply from headers */
-  vtype_pid,            /* value not used; result is pid */
-  vtype_host_lookup,    /* value not used; get host name */
-  vtype_load_avg,       /* value not used; result is int from os_getloadavg */
-  vtype_pspace,         /* partition space; value is T/F for spool/log */
-  vtype_pinodes,        /* partition inodes; value is T/F for spool/log */
-  vtype_cert           /* SSL certificate */
-#ifndef DISABLE_DKIM
-  ,vtype_dkim           /* Lookup of value in DKIM signature */
-#endif
-};
-
-/* Type for main variable table */
-
-typedef struct {
-  const char *name;
-  enum vtypes type;
-  void       *value;
-} var_entry;
-
 /* Type for entries pointing to address/length pairs. Not currently
 in use. */
 
@@ -503,10 +454,10 @@ static var_entry var_table[] = {
   { "address_file",        vtype_stringptr,   &address_file },
   { "address_pipe",        vtype_stringptr,   &address_pipe },
 #ifdef EXPERIMENTAL_ARC
-  { "arc_domains",         vtype_string_func, (void *) &fn_arc_domains },
-  { "arc_oldest_pass",     vtype_int,         &arc_oldest_pass },
-  { "arc_state",           vtype_stringptr,   &arc_state },
-  { "arc_state_reason",    vtype_stringptr,   &arc_state_reason },
+  { "arc_domains",         vtype_module,       US"arc" },
+  { "arc_oldest_pass",     vtype_module,       US"arc" },
+  { "arc_state",           vtype_module,       US"arc" },
+  { "arc_state_reason",    vtype_module,       US"arc" },
 #endif
   { "authenticated_fail_id",vtype_stringptr,  &authenticated_fail_id },
   { "authenticated_id",    vtype_stringptr,   &authenticated_id },
@@ -539,33 +490,36 @@ static var_entry var_table[] = {
   { "dcc_result",          vtype_stringptr,   &dcc_result },
 #endif
 #ifndef DISABLE_DKIM
-  { "dkim_algo",           vtype_dkim,        (void *)DKIM_ALGO },
-  { "dkim_bodylength",     vtype_dkim,        (void *)DKIM_BODYLENGTH },
-  { "dkim_canon_body",     vtype_dkim,        (void *)DKIM_CANON_BODY },
-  { "dkim_canon_headers",  vtype_dkim,        (void *)DKIM_CANON_HEADERS },
-  { "dkim_copiedheaders",  vtype_dkim,        (void *)DKIM_COPIEDHEADERS },
-  { "dkim_created",        vtype_dkim,        (void *)DKIM_CREATED },
-  { "dkim_cur_signer",     vtype_stringptr,   &dkim_cur_signer },
-  { "dkim_domain",         vtype_stringptr,   &dkim_signing_domain },
-  { "dkim_expires",        vtype_dkim,        (void *)DKIM_EXPIRES },
-  { "dkim_headernames",    vtype_dkim,        (void *)DKIM_HEADERNAMES },
-  { "dkim_identity",       vtype_dkim,        (void *)DKIM_IDENTITY },
-  { "dkim_key_granularity",vtype_dkim,        (void *)DKIM_KEY_GRANULARITY },
-  { "dkim_key_length",     vtype_int,         &dkim_key_length },
-  { "dkim_key_nosubdomains",vtype_dkim,       (void *)DKIM_NOSUBDOMAINS },
-  { "dkim_key_notes",      vtype_dkim,        (void *)DKIM_KEY_NOTES },
-  { "dkim_key_srvtype",    vtype_dkim,        (void *)DKIM_KEY_SRVTYPE },
-  { "dkim_key_testing",    vtype_dkim,        (void *)DKIM_KEY_TESTING },
-  { "dkim_selector",       vtype_stringptr,   &dkim_signing_selector },
-  { "dkim_signers",        vtype_stringptr,   &dkim_signers },
-  { "dkim_verify_reason",  vtype_stringptr,   &dkim_verify_reason },
-  { "dkim_verify_status",  vtype_stringptr,   &dkim_verify_status },
+  { "dkim_algo",           vtype_module,       US"dkim" },
+  { "dkim_bodylength",     vtype_module,       US"dkim" },
+  { "dkim_canon_body",     vtype_module,       US"dkim" },
+  { "dkim_canon_headers",  vtype_module,       US"dkim" },
+  { "dkim_copiedheaders",  vtype_module,       US"dkim" },
+  { "dkim_created",        vtype_module,       US"dkim" },
+  { "dkim_cur_signer",     vtype_module,       US"dkim" },
+  { "dkim_domain",         vtype_module,       US"dkim" },
+  { "dkim_expires",        vtype_module,       US"dkim" },
+  { "dkim_headernames",    vtype_module,       US"dkim" },
+  { "dkim_identity",       vtype_module,       US"dkim" },
+  { "dkim_key_granularity",vtype_module,       US"dkim" },
+  { "dkim_key_length",     vtype_module,       US"dkim" },
+  { "dkim_key_nosubdomains",vtype_module,      US"dkim" },
+  { "dkim_key_notes",      vtype_module,       US"dkim" },
+  { "dkim_key_srvtype",    vtype_module,       US"dkim" },
+  { "dkim_key_testing",    vtype_module,       US"dkim" },
+  { "dkim_selector",       vtype_module,       US"dkim" },
+  { "dkim_signers",        vtype_module,       US"dkim" },
+  { "dkim_verify_reason",  vtype_module,       US"dkim" },
+  { "dkim_verify_signers", vtype_module,       US"dkim" },
+  { "dkim_verify_status",  vtype_module,       US"dkim" },
 #endif
 #ifdef SUPPORT_DMARC
-  { "dmarc_domain_policy", vtype_stringptr,   &dmarc_domain_policy },
-  { "dmarc_status",        vtype_stringptr,   &dmarc_status },
-  { "dmarc_status_text",   vtype_stringptr,   &dmarc_status_text },
-  { "dmarc_used_domain",   vtype_stringptr,   &dmarc_used_domain },
+  { "dmarc_alignment_dkim",vtype_module,       US"dmarc" },
+  { "dmarc_alignment_spf", vtype_module,       US"dmarc" },
+  { "dmarc_domain_policy", vtype_module,       US"dmarc" },
+  { "dmarc_status",        vtype_module,       US"dmarc" },
+  { "dmarc_status_text",   vtype_module,       US"dmarc" },
+  { "dmarc_used_domain",   vtype_module,       US"dmarc" },
 #endif
   { "dnslist_domain",      vtype_stringptr,   &dnslist_domain },
   { "dnslist_matched",     vtype_stringptr,   &dnslist_matched },
@@ -758,12 +712,12 @@ static var_entry var_table[] = {
   { "spam_score_int",      vtype_stringptr,   &spam_score_int },
 #endif
 #ifdef SUPPORT_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 },
-  { "spf_result_guessed",  vtype_bool,        &spf_result_guessed },
-  { "spf_smtp_comment",    vtype_stringptr,   &spf_smtp_comment },
+  { "spf_guess",           vtype_module,       US"spf" },
+  { "spf_header_comment",  vtype_module,       US"spf" },
+  { "spf_received",        vtype_module,       US"spf" },
+  { "spf_result",          vtype_module,       US"spf" },
+  { "spf_result_guessed",  vtype_module,       US"spf" },
+  { "spf_smtp_comment",    vtype_module,       US"spf" },
 #endif
   { "spool_directory",     vtype_stringptr,   &spool_directory },
   { "spool_inodes",        vtype_pinodes,     (void *)TRUE },
@@ -1044,9 +998,10 @@ Returns:        TRUE if condition is met, FALSE if not
 */
 
 BOOL
-expand_check_condition(uschar *condition, uschar *m1, uschar *m2)
+expand_check_condition(const uschar * condition,
+  const uschar * m1, const uschar * m2)
 {
-uschar * ss = expand_string(condition);
+const uschar * ss = expand_cstring(condition);
 if (!ss)
   {
   if (!f.expand_string_forcedfail && !f.search_find_defer)
@@ -1284,19 +1239,19 @@ return NULL;
 
 
 static var_entry *
-find_var_ent(uschar * name)
+find_var_ent(uschar * name, var_entry * table, unsigned nent)
 {
 int first = 0;
-int last = nelem(var_table);
+int last = nent;
 
 while (last > first)
   {
   int middle = (first + last)/2;
-  int c = Ustrcmp(name, var_table[middle].name);
+  int c = Ustrcmp(name, table[middle].name);
 
   if (c > 0) { first = middle + 1; continue; }
   if (c < 0) { last = middle; continue; }
-  return &var_table[middle];
+  return &table[middle];
   }
 return NULL;
 }
@@ -1423,7 +1378,7 @@ expand_getcertele(uschar * field, uschar * certvar)
 {
 var_entry * vp;
 
-if (!(vp = find_var_ent(certvar)))
+if (!(vp = find_var_ent(certvar, var_table, nelem(var_table))))
   {
   expand_string_message =
     string_sprintf("no variable named \"%s\"", certvar);
@@ -1938,9 +1893,11 @@ static const uschar *
 find_variable(uschar * name, esi_flags flags, int * newsize)
 {
 var_entry * vp;
-uschar *s, *domain;
-uschar **ss;
+uschar * s, * domain;
+uschar ** ss;
 void * val;
+var_entry * table = var_table;
+unsigned table_count = nelem(var_table);
 
 /* Handle ACL variables, whose names are of the form acl_cxxx or acl_mxxx.
 Originally, xxx had to be a number in the range 0-9 (later 0-19), but from
@@ -1985,9 +1942,11 @@ else if (Ustrncmp(name, "regex", 5) == 0)
   }
 #endif
 
+sublist:
+
 /* For all other variables, search the table */
 
-if (!(vp = find_var_ent(name)))
+if (!(vp = find_var_ent(name, table, table_count)))
   return NULL;          /* Unknown variable name */
 
 /* Found an existing variable. If in skipping state, the value isn't needed,
@@ -2175,9 +2134,29 @@ switch (vp->type)
 
 #ifndef DISABLE_DKIM
   case vtype_dkim:
-    return dkim_exim_expand_query((int)(long)val);
+    {
+    misc_module_info * mi = misc_mod_findonly(US"dkim");
+    typedef uschar * (*fn_t)(int);
+    return mi
+      ? (((fn_t *) mi->functions)[DKIM_EXPAND_QUERY]) ((int)(long)val)
+      : US"";
+    }
 #endif
 
+  case vtype_module:
+    {
+    uschar * errstr;
+    misc_module_info * mi = misc_mod_find(val, &errstr);
+    if (mi)
+      {
+      table = mi->variables;
+      table_count = mi->variables_count;
+      goto sublist;
+      }
+    log_write(0, LOG_MAIN|LOG_PANIC,
+      "failed to find %s module for %s: %s", US val, name, errstr);
+    return US"";
+    }
   }
 
 return NULL;  /* Unknown variable. Silences static checkers. */
@@ -2190,7 +2169,8 @@ void
 modify_variable(uschar *name, void * value)
 {
 var_entry * vp;
-if ((vp = find_var_ent(name))) vp->value = value;
+if ((vp = find_var_ent(name, var_table, nelem(var_table))))
+  vp->value = value;
 return;          /* Unknown variable name, fail silently */
 }
 
@@ -2789,31 +2769,48 @@ switch(cond_type = identify_operator(&s, &opname))
     /* Various authentication tests - all optionally compiled */
 
     case ECOND_PAM:
-    #ifdef SUPPORT_PAM
-    rc = auth_call_pam(sub[0], &expand_string_message);
-    goto END_AUTH;
-    #else
-    goto COND_FAILED_NOT_COMPILED;
-    #endif  /* SUPPORT_PAM */
+#ifdef SUPPORT_PAM
+      {
+      const misc_module_info * mi = misc_mod_find(US"pam", NULL);
+      typedef int (*fn_t)(const uschar *, uschar **);
+      if (!mi)
+       goto COND_FAILED_NOT_COMPILED;
+      rc = (((fn_t *) mi->functions)[PAM_AUTH_CALL])
+                                         (sub[0], &expand_string_message);
+      goto END_AUTH;
+      }
+#else
+      goto COND_FAILED_NOT_COMPILED;
+#endif  /* SUPPORT_PAM */
 
     case ECOND_RADIUS:
-    #ifdef RADIUS_CONFIG_FILE
-    rc = auth_call_radius(sub[0], &expand_string_message);
-    goto END_AUTH;
-    #else
-    goto COND_FAILED_NOT_COMPILED;
-    #endif  /* RADIUS_CONFIG_FILE */
+#ifdef RADIUS_CONFIG_FILE
+      {
+      const misc_module_info * mi = misc_mod_find(US"radius", NULL);
+      typedef int (*fn_t)(const uschar *, uschar **);
+      if (!mi)
+       goto COND_FAILED_NOT_COMPILED;
+      rc = (((fn_t *) mi->functions)[RADIUS_AUTH_CALL])
+                                         (sub[0], &expand_string_message);
+      goto END_AUTH;
+      }
+#else
+      goto COND_FAILED_NOT_COMPILED;
+#endif  /* RADIUS_CONFIG_FILE */
 
     case ECOND_LDAPAUTH:
     #ifdef LOOKUP_LDAP
       {
-      /* Just to keep the interface the same */
-      BOOL do_cache;
-      int old_pool = store_pool;
-      store_pool = POOL_SEARCH;
-      rc = eldapauth_find((void *)(-1), NULL, sub[0], Ustrlen(sub[0]), NULL,
-        &expand_string_message, &do_cache);
-      store_pool = old_pool;
+      int expand_setup = -1;
+      const lookup_info * li = search_findtype(US"ldapauth", 8);
+      void * handle;
+
+      if (li && (handle = search_open(NULL, li, 0, NULL, NULL)))
+       rc = search_find(handle, NULL, sub[0],
+                       -1, NULL, 0, 0, &expand_setup, NULL)
+         ? OK : f.search_find_defer ? DEFER : FAIL;
+      else
+       { expand_string_message = search_error_message; rc = FAIL; }
       }
     goto END_AUTH;
     #else
@@ -4908,18 +4905,7 @@ while (*s)
       yield = authres_local(yield, sub_arg[0]);
       yield = authres_iprev(yield);
       yield = authres_smtpauth(yield);
-#ifdef SUPPORT_SPF
-      yield = authres_spf(yield);
-#endif
-#ifndef DISABLE_DKIM
-      yield = authres_dkim(yield);
-#endif
-#ifdef SUPPORT_DMARC
-      yield = authres_dmarc(yield);
-#endif
-#ifdef EXPERIMENTAL_ARC
-      yield = authres_arc(yield);
-#endif
+      yield = misc_mod_authres(yield);
       break;
       }
 
@@ -5020,9 +5006,9 @@ while (*s)
 
     case EITEM_LOOKUP:
       {
-      int stype, partial, affixlen, starflags;
-      int expand_setup = 0;
-      int nameptr = 0;
+      int expand_setup = 0, nameptr = 0;
+      int partial, affixlen, starflags;
+      const lookup_info * li;
       uschar * key, * filename;
       const uschar * affix, * opts;
       uschar * save_lookup_value = lookup_value;
@@ -5075,8 +5061,8 @@ while (*s)
       /* Now check for the individual search type and any partial or default
       options. Only those types that are actually in the binary are valid. */
 
-      if ((stype = search_findtype_partial(name, &partial, &affix, &affixlen,
-         &starflags, &opts)) < 0)
+      if (!(li = search_findtype_partial(name, &partial, &affix, &affixlen,
+         &starflags, &opts)))
         {
         expand_string_message = search_error_message;
         goto EXPAND_FAILED;
@@ -5085,7 +5071,7 @@ while (*s)
       /* Check that a key was provided for those lookup types that need it,
       and was not supplied for those that use the query style. */
 
-      if (!mac_islookup(stype, lookup_querystyle|lookup_absfilequery))
+      if (!mac_islookup(li, lookup_querystyle|lookup_absfilequery))
         {
         if (!key)
           {
@@ -5128,7 +5114,7 @@ while (*s)
       file types, the query (i.e. "key") starts with a file name. */
 
       if (!key)
-       key = search_args(stype, name, filename, &filename, opts);
+       key = search_args(li, name, filename, &filename, opts);
 
       /* If skipping, don't do the next bit - just lookup_value == NULL, as if
       the entry was not found. Note that there is no search_close() function.
@@ -5147,7 +5133,7 @@ while (*s)
         lookup_value = NULL;
       else
         {
-        void * handle = search_open(filename, stype, 0, NULL, NULL);
+        void * handle = search_open(filename, li, 0, NULL, NULL);
         if (!handle)
           {
           expand_string_message = search_error_message;
@@ -5187,8 +5173,7 @@ while (*s)
       restore_expand_strings(save_expand_nmax, save_expand_nstring,
         save_expand_nlength);
 
-      if (flags & ESI_SKIPPING) continue;
-      break;
+      if (flags & ESI_SKIPPING) continue; else break;
       }
 
     /* If Perl support is configured, handle calling embedded perl subroutines,
@@ -5208,6 +5193,8 @@ while (*s)
       {
       uschar * sub_arg[EXIM_PERL_MAX_ARGS + 2];
       gstring * new_yield;
+      const misc_module_info * mi;
+      uschar * errstr;
 
       if (expand_forbid & RDO_PERL)
         {
@@ -5215,6 +5202,13 @@ while (*s)
         goto EXPAND_FAILED;
         }
 
+      if (!(mi = misc_mod_find(US"perl", &errstr)))
+        {
+        expand_string_message =
+         string_sprintf("failed to locate perl module: %s", errstr);
+        goto EXPAND_FAILED;
+        }
+
       switch(read_subs(sub_arg, EXIM_PERL_MAX_ARGS + 1, 1, &s, flags, TRUE,
            name, &resetok, NULL))
         {
@@ -5229,6 +5223,8 @@ while (*s)
       if (!opt_perl_started)
         {
         uschar * initerror;
+       typedef uschar * (*fn_t)(uschar *);
+
         if (!opt_perl_startup)
           {
           expand_string_message = US"A setting of perl_startup is needed when "
@@ -5236,7 +5232,8 @@ while (*s)
           goto EXPAND_FAILED;
           }
         DEBUG(D_any) debug_printf("Starting Perl interpreter\n");
-        if ((initerror = init_perl(opt_perl_startup)))
+       initerror = (((fn_t *) mi->functions)[PERL_STARTUP]) (opt_perl_startup);
+        if (initerror)
           {
           expand_string_message =
             string_sprintf("error in perl_startup code: %s\n", initerror);
@@ -5248,8 +5245,12 @@ while (*s)
       /* Call the function */
 
       sub_arg[EXIM_PERL_MAX_ARGS + 1] = NULL;
-      new_yield = call_perl_cat(yield, &expand_string_message,
-        sub_arg[0], sub_arg + 1);
+       {
+       typedef gstring * (*fn_t)(gstring *, uschar **, uschar *, uschar **);
+       new_yield = (((fn_t *) mi->functions)[PERL_CAT])
+                                             (yield, &expand_string_message,
+                                               sub_arg[0], sub_arg + 1);
+       }
 
       /* NULL yield indicates failure; if the message pointer has been set to
       NULL, the yield was undef, indicating a forced failure. Otherwise the
@@ -5472,7 +5473,7 @@ while (*s)
       FILE * f;
       uschar * sub_arg[2];
 
-      if ((expand_forbid & RDO_READFILE) != 0)
+      if (expand_forbid & RDO_READFILE)
         {
         expand_string_message = US"file insertions are not permitted";
         goto EXPAND_FAILED;
@@ -5528,12 +5529,18 @@ while (*s)
 
       if (!(flags & ESI_SKIPPING))
         {
-       int stype = search_findtype(US"readsock", 8);
+       const lookup_info * li = search_findtype(US"readsock", 8);
        gstring * g = NULL;
        void * handle;
        int expand_setup = -1;
        uschar * s;
 
+       if (!li)
+         {
+         expand_string_message = search_error_message;
+         goto EXPAND_FAILED;
+         }
+
        /* If the reqstr is empty, flag that and set a dummy */
 
        if (!sub_arg[1][0])
@@ -5552,8 +5559,7 @@ while (*s)
 
          /* First option has no tag and is timeout */
          if ((item = string_nextinlist(&list, &sep, NULL, 0)))
-           g = string_append_listele(g, ',',
-                 string_sprintf("timeout=%s", item));
+           g = string_append_listele_fmt(g, ',', TRUE, "timeout=%s", item);
 
          /* The rest of the options from the expansion */
          while ((item = string_nextinlist(&list, &sep, NULL, 0)))
@@ -5564,14 +5570,13 @@ while (*s)
          options is the readsock expansion. */
 
          if (sub_arg[3] && *sub_arg[3])
-           g = string_append_listele(g, ',',
-                 string_sprintf("eol=%s",
-                   string_printing2(sub_arg[3], SP_TAB|SP_SPACE)));
+           g = string_append_listele_fmt(g, ',', TRUE, 
+                 "eol=%s", string_printing2(sub_arg[3], SP_TAB|SP_SPACE));
          }
 
        /* Gat a (possibly cached) handle for the connection */
 
-       if (!(handle = search_open(sub_arg[0], stype, 0, NULL, NULL)))
+       if (!(handle = search_open(sub_arg[0], li, 0, NULL, NULL)))
          {
          if (*expand_string_message) goto EXPAND_FAILED;
          expand_string_message = search_error_message;
@@ -5621,8 +5626,7 @@ while (*s)
        expand_string_message = US"missing '}' closing readsocket";
        goto EXPAND_FAILED_CURLY;
        }
-      if (flags & ESI_SKIPPING) continue;
-      break;
+      if (flags & ESI_SKIPPING) continue; else break;
 
       /* Come here on failure to create socket, connect socket, write to the
       socket, or timeout on reading. If another substring follows, expand and
@@ -5792,8 +5796,7 @@ while (*s)
         case 2: goto EXPAND_FAILED_CURLY;    /* returned value is 0 */
         }
 
-      if (flags & ESI_SKIPPING) continue;
-      break;
+      if (flags & ESI_SKIPPING) continue; else break;
       }
 
     /* Handle character translation for "tr" */
@@ -6347,8 +6350,7 @@ while (*s)
       restore_expand_strings(save_expand_nmax, save_expand_nstring,
         save_expand_nlength);
 
-      if (flags & ESI_SKIPPING) continue;
-      break;
+      if (flags & ESI_SKIPPING) continue; else break;
       }
 
     /* return the Nth item from a list */
@@ -6447,8 +6449,7 @@ while (*s)
       restore_expand_strings(save_expand_nmax, save_expand_nstring,
         save_expand_nlength);
 
-      if (flags & ESI_SKIPPING) continue;
-      break;
+      if (flags & ESI_SKIPPING) continue; else break;
       }
 
     case EITEM_LISTQUOTE:
@@ -6547,8 +6548,7 @@ while (*s)
 
       restore_expand_strings(save_expand_nmax, save_expand_nstring,
         save_expand_nlength);
-      if (flags & ESI_SKIPPING) continue;
-      break;
+      if (flags & ESI_SKIPPING) continue; else break;
       }
 #endif /*DISABLE_TLS*/
 
@@ -6760,8 +6760,7 @@ while (*s)
       /* Restore preserved $item */
 
       iterate_item = save_iterate_item;
-      if (flags & ESI_SKIPPING) continue;
-      break;
+      if (flags & ESI_SKIPPING) continue; else break;
       }
 
     case EITEM_SORT:
@@ -7062,8 +7061,7 @@ while (*s)
         case 1: goto EXPAND_FAILED;          /* when all is well, the */
         case 2: goto EXPAND_FAILED_CURLY;    /* returned value is 0 */
         }
-      if (flags & ESI_SKIPPING) continue;
-      break;
+      if (flags & ESI_SKIPPING) continue; else break;
       }
 
 #ifdef SUPPORT_SRS
@@ -7219,7 +7217,8 @@ NOT_ITEM: ;
              string_sprintf("missing '}' closing cert arg of %s", name);
            goto EXPAND_FAILED_CURLY;
            }
-         if ((vp = find_var_ent(sub)) && vp->type == vtype_cert)
+         if (  (vp = find_var_ent(sub, var_table, nelem(var_table)))
+            && vp->type == vtype_cert)
            {
            s = s1+1;
            break;
@@ -7794,19 +7793,19 @@ NOT_ITEM: ;
 
        else
          {
-         int n;
+         const lookup_info * li;
          uschar * opt = Ustrchr(arg, '_');
 
          if (opt) *opt++ = 0;
 
-         if ((n = search_findtype(arg, Ustrlen(arg))) < 0)
+         if (!(li = search_findtype(arg, Ustrlen(arg))))
            {
            expand_string_message = search_error_message;
            goto EXPAND_FAILED;
            }
 
-         if (lookup_list[n]->quote)
-           sub = (lookup_list[n]->quote)(sub, opt, (unsigned)n);
+         if (li->quote)
+           sub = (li->quote)(sub, opt, li->acq_num);
          else if (opt)
            sub = NULL;
 
@@ -8701,16 +8700,16 @@ Returns:     OK     value placed in rvalue
 
 int
 exp_bool(address_item * addr,
-  uschar * mtype, uschar * mname, unsigned dbg_opt,
+  const uschar * mtype, const uschar * mname, unsigned dbg_opt,
   uschar * oname, BOOL bvalue,
-  uschar * svalue, BOOL * rvalue)
+  const uschar * svalue, BOOL * rvalue)
 {
-uschar * expanded;
+const uschar * expanded;
 
 DEBUG(D_expand) debug_printf("try option %s\n", oname);
 if (!svalue) { *rvalue = bvalue; return OK; }
 
-if (!(expanded = expand_string(svalue)))
+if (!(expanded = expand_cstring(svalue)))
   {
   if (f.expand_string_forcedfail)
     {
@@ -8781,8 +8780,8 @@ int fd, off = 0, len;
 
 if ((fd = exim_open2(CS filename, O_RDONLY)) < 0)
   {
-  log_write(0, LOG_MAIN | LOG_PANIC, "unable to open file for reading: %s",
-            filename);
+  log_write(0, LOG_MAIN | LOG_PANIC, "unable to open file '%s' for reading: %s",
+            filename, strerror(errno));
   return NULL;
   }
 
@@ -8951,7 +8950,7 @@ if (opt_perl_startup != NULL)
   uschar *errstr;
   printf("Starting Perl interpreter\n");
   errstr = init_perl(opt_perl_startup);
-  if (errstr != NULL)
+  if (errstr)
     {
     printf("** error in perl_startup code: %s\n", errstr);
     return EXIT_FAILURE;