build: use pkg-config for i18n
[exim.git] / src / src / drtables.c
index 183edf321ba20ab3655d01306637209d646146a4..28846320c914c6ef03e277d978791d0f3f4cc2ee 100644 (file)
@@ -1,11 +1,11 @@
-/* $Cambridge: exim/src/src/drtables.c,v 1.11 2009/11/16 19:50:36 nm4 Exp $ */
-
 /*************************************************
 *     Exim - an Internet mail transport agent    *
 *************************************************/
 
 /*************************************************
 *     Exim - an Internet mail transport agent    *
 *************************************************/
 
-/* Copyright (c) University of Cambridge 1995 - 2009 */
+/* Copyright (c) The Exim Maintainers 2020 - 2024 */
+/* Copyright (c) University of Cambridge 1995 - 2018 */
 /* See the file NOTICE for conditions of use and distribution. */
 /* See the file NOTICE for conditions of use and distribution. */
+/* SPDX-License-Identifier: GPL-2.0-or-later */
 
 
 #include "exim.h"
 
 
 #include "exim.h"
@@ -18,608 +18,794 @@ various macros in config.h that ultimately come from Local/Makefile. They are
 all described in src/EDITME. */
 
 
 all described in src/EDITME. */
 
 
-lookup_info **lookup_list;
-int lookup_list_count = 0;
+//lookup_info **lookup_list;
+tree_node * lookups_tree = NULL;
+unsigned lookup_list_count = 0;
 
 
-static int lookup_list_init_done = 0;
+/* Lists of information about which drivers are included in the exim binary. */
 
 
-/* Table of information about all possible authentication mechamisms. All
-entries are always present if any mechanism is declared, but the functions are
-set to NULL for those that are not compiled into the binary. */
+auth_info * auths_available= NULL;
+router_info * routers_available = NULL;
+transport_info * transports_available = NULL;
 
 
-#ifdef AUTH_CRAM_MD5
-#include "auths/cram_md5.h"
-#endif
 
 
-#ifdef AUTH_CYRUS_SASL
-#include "auths/cyrus_sasl.h"
-#endif
 
 
-#ifdef AUTH_DOVECOT
-#include "auths/dovecot.h"
-#endif
+#ifndef MACRO_PREDEF
 
 
-#ifdef AUTH_PLAINTEXT
-#include "auths/plaintext.h"
+gstring *
+auth_show_supported(gstring * g)
+{
+uschar * b = US""               /* static-build authenticatornames */
+#if defined(AUTH_CRAM_MD5) && AUTH_CRAM_MD5!=2
+  " cram_md5"
 #endif
 #endif
-
-#ifdef AUTH_SPA
-#include "auths/spa.h"
+#if defined(AUTH_CYRUS_SASL) && AUTH_CYRUS_SASL!=2
+  " cyrus_sasl"
 #endif
 #endif
+#if defined(AUTH_DOVECOT) && AUTH_DOVECOT!=2
+  " dovecot"
+#endif
+#if defined(AUTH_EXTERNAL) && AUTH_EXTERNAL!=2
+  " external"
+#endif
+#if defined(AUTH_GSASL) && AUTH_GSASL!=2
+  " gsasl"
+#endif
+#if defined(AUTH_HEIMDAL_GSSAPI) && AUTH_HEIMDAL_GSSAPI!=2
+  " heimdal_gssapi"
+#endif
+#if defined(AUTH_PLAINTEXT) && AUTH_PLAINTEXT!=2
+  " plaintext"
+#endif
+#if defined(AUTH_SPA) && AUTH_SPA!=2
+  " spa"
+#endif
+#if defined(AUTH_TLS) && AUTH_TLS!=2
+  " tls"
+#endif
+  ;
 
 
-auth_info auths_available[] = {
-
-/* Checking by an expansion condition on plain text */
-
-#ifdef AUTH_CRAM_MD5
-  {
-  US"cram_md5",                              /* lookup name */
-  auth_cram_md5_options,
-  &auth_cram_md5_options_count,
-  &auth_cram_md5_option_defaults,
-  sizeof(auth_cram_md5_options_block),
-  auth_cram_md5_init,                        /* init function */
-  auth_cram_md5_server,                      /* server function */
-  auth_cram_md5_client                       /* client function */
-  },
-#endif
-
-#ifdef AUTH_CYRUS_SASL
-  {
-  US"cyrus_sasl",           /* lookup name */
-  auth_cyrus_sasl_options,
-  &auth_cyrus_sasl_options_count,
-  &auth_cyrus_sasl_option_defaults,
-  sizeof(auth_cyrus_sasl_options_block),
-  auth_cyrus_sasl_init,                      /* init function */
-  auth_cyrus_sasl_server,                    /* server function */
-  NULL                                       /* client function */
-  },
-#endif
-
-#ifdef AUTH_DOVECOT
-  {
-  US"dovecot",                                /* lookup name */
-  auth_dovecot_options,
-  &auth_dovecot_options_count,
-  &auth_dovecot_option_defaults,
-  sizeof(auth_dovecot_options_block),
-  auth_dovecot_init,                          /* init function */
-  auth_dovecot_server,                        /* server function */
-  NULL                                        /* client function */
-  },
-#endif
-
-#ifdef AUTH_PLAINTEXT
-  {
-  US"plaintext",                             /* lookup name */
-  auth_plaintext_options,
-  &auth_plaintext_options_count,
-  &auth_plaintext_option_defaults,
-  sizeof(auth_plaintext_options_block),
-  auth_plaintext_init,                       /* init function */
-  auth_plaintext_server,                     /* server function */
-  auth_plaintext_client                      /* client function */
-  },
-#endif
-
-#ifdef AUTH_SPA
-  {
-  US"spa",                                   /* lookup name */
-  auth_spa_options,
-  &auth_spa_options_count,
-  &auth_spa_option_defaults,
-  sizeof(auth_spa_options_block),
-  auth_spa_init,                             /* init function */
-  auth_spa_server,                           /* server function */
-  auth_spa_client                            /* client function */
-  },
-#endif
-
-{ US"", NULL, NULL, NULL, 0, NULL, NULL, NULL  }
-};
-
-
-/* Tables of information about which routers and transports are included in the
-exim binary. */
-
-/* Pull in the necessary header files */
+uschar * d = US""              /* dynamic-module authenticator names */
+#if defined(AUTH_CRAM_MD5) && AUTH_CRAM_MD5==2
+  " cram_md5"
+#endif
+#if defined(AUTH_CYRUS_SASL) && AUTH_CYRUS_SASL==2
+  " cyrus_sasl"
+#endif
+#if defined(AUTH_DOVECOT) && AUTH_DOVECOT==2
+  " dovecot"
+#endif
+#if defined(AUTH_EXTERNAL) && AUTH_EXTERNAL==2
+  " external"
+#endif
+#if defined(AUTH_GSASL) && AUTH_GSASL==2
+  " gsasl"
+#endif
+#if defined(AUTH_HEIMDAL_GSSAPI) && AUTH_HEIMDAL_GSSAPI==2
+  " heimdal_gssapi"
+#endif
+#if defined(AUTH_PLAINTEXT) && AUTH_PLAINTEXT==2
+  " plaintext"
+#endif
+#if defined(AUTH_SPA) && AUTH_SPA==2
+  " spa"
+#endif
+#if defined(AUTH_TLS) && AUTH_TLS==2
+  " tls"
+#endif
+  ;
 
 
-#include "routers/rf_functions.h"
+if (*b) g = string_fmt_append(g, "Authenticators (built-in):%s\n", b);
+if (*d) g = string_fmt_append(g, "Authenticators (dynamic): %s\n", d);
+return g;
+}
 
 
-#ifdef ROUTER_ACCEPT
-#include "routers/accept.h"
+gstring *
+route_show_supported(gstring * g)
+{
+uschar * b = US""              /* static-build router names */
+#if defined(ROUTER_ACCEPT) && ROUTER_ACCEPT!=2
+  " accept"
 #endif
 #endif
-
-#ifdef ROUTER_DNSLOOKUP
-#include "routers/dnslookup.h"
+#if defined(ROUTER_DNSLOOKUP) && ROUTER_DNSLOOKUP!=2
+  " dnslookup"
 #endif
 #endif
-
-#ifdef ROUTER_MANUALROUTE
-#include "routers/manualroute.h"
+# if defined(ROUTER_IPLITERAL) && ROUTER_IPLITERAL!=2
+  " ipliteral"
 #endif
 #endif
-
-#ifdef ROUTER_IPLITERAL
-#include "routers/ipliteral.h"
+#if defined(ROUTER_IPLOOKUP) && ROUTER_IPLOOKUP!=2
+  " iplookup"
 #endif
 #endif
-
-#ifdef ROUTER_IPLOOKUP
-#include "routers/iplookup.h"
+#if defined(ROUTER_MANUALROUTE) && ROUTER_MANUALROUTE!=2
+  " manualroute"
 #endif
 #endif
-
-#ifdef ROUTER_QUERYPROGRAM
-#include "routers/queryprogram.h"
+#if defined(ROUTER_REDIRECT) && ROUTER_REDIRECT!=2
+  " redirect"
 #endif
 #endif
-
-#ifdef ROUTER_REDIRECT
-#include "routers/redirect.h"
+#if defined(ROUTER_QUERYPROGRAM) && ROUTER_QUERYPROGRAM!=2
+  " queryprogram"
 #endif
 #endif
+  ;
 
 
-#ifdef TRANSPORT_APPENDFILE
-#include "transports/appendfile.h"
+uschar * d = US""              /* dynamic-module router names */
+#if defined(ROUTER_ACCEPT) && ROUTER_ACCEPT==2
+  " accept"
 #endif
 #endif
-
-#ifdef TRANSPORT_AUTOREPLY
-#include "transports/autoreply.h"
+#if defined(ROUTER_DNSLOOKUP) && ROUTER_DNSLOOKUP==2
+  " dnslookup"
 #endif
 #endif
-
-#ifdef TRANSPORT_LMTP
-#include "transports/lmtp.h"
+# if defined(ROUTER_IPLITERAL) && ROUTER_IPLITERAL==2
+  " ipliteral"
 #endif
 #endif
-
-#ifdef TRANSPORT_PIPE
-#include "transports/pipe.h"
+#if defined(ROUTER_IPLOOKUP) && ROUTER_IPLOOKUP==2
+  " iplookup"
 #endif
 #endif
-
-#ifdef TRANSPORT_SMTP
-#include "transports/smtp.h"
+#if defined(ROUTER_MANUALROUTE) && ROUTER_MANUALROUTE==2
+  " manualroute"
+#endif
+#if defined(ROUTER_REDIRECT) && ROUTER_REDIRECT==2
+  " redirect"
+#endif
+#if defined(ROUTER_QUERYPROGRAM) && ROUTER_QUERYPROGRAM==2
+  " queryprogram"
 #endif
 #endif
+  ;
 
 
+if (*b) g = string_fmt_append(g, "Routers (built-in):%s\n", b);
+if (*d) g = string_fmt_append(g, "Routers (dynamic): %s\n", d);
+return g;
+}
 
 
-/* Now set up the structures, terminated by an entry with a null name. */
+gstring *
+transport_show_supported(gstring * g)
+{
+uschar * b = US""              /* static-build transportnames */
+#if defined(TRANSPORT_APPENDFILE) && TRANSPORT_APPENDFILE!=2
+  " appendfile"
+# ifdef SUPPORT_MAILDIR
+    "/maildir"
+# endif
+# ifdef SUPPORT_MAILSTORE
+    "/mailstore"
+# endif
+# ifdef SUPPORT_MBX
+    "/mbx"
+# endif
+#endif
+#if defined(TRANSPORT_AUTOREPLY) && TRANSPORT_AUTOREPLY!=2
+  " autoreply"
+#endif
+#if defined(TRANSPORT_LMTP) && TRANSPORT_LMTP!=2
+  " lmtp"
+#endif
+#if defined(TRANSPORT_PIPE) && TRANSPORT_PIPE!=2
+  " pipe"
+#endif
+#if defined(EXPERIMENTAL_QUEUEFILE) && EXPERIMENTAL_QUEUEFILE!=2
+  " queuefile"
+#endif
+#if defined(TRANSPORT_SMTP) && TRANSPORT_SMTP!=2
+  " smtp"
+#endif
+  ;
+
+uschar * d = US""              /* dynamic-module transportnames */
+#if defined(TRANSPORT_APPENDFILE) && TRANSPORT_APPENDFILE==2
+  " appendfile"
+# ifdef SUPPORT_MAILDIR
+    "/maildir"
+# endif
+# ifdef SUPPORT_MAILSTORE
+    "/mailstore"
+# endif
+# ifdef SUPPORT_MBX
+    "/mbx"
+# endif
+#endif
+#if defined(TRANSPORT_AUTOREPLY) && TRANSPORT_AUTOREPLY==2
+  " autoreply"
+#endif
+#if defined(TRANSPORT_LMTP) && TRANSPORT_LMTP==2
+  " lmtp"
+#endif
+#if defined(TRANSPORT_PIPE) && TRANSPORT_PIPE==2
+  " pipe"
+#endif
+#if defined(EXPERIMENTAL_QUEUEFILE) && EXPERIMENTAL_QUEUEFILE==2
+  " queuefile"
+#endif
+#if defined(TRANSPORT_SMTP) && TRANSPORT_SMTP==2
+  " smtp"
+#endif
+  ;
+
+if (*b) g = string_fmt_append(g, "Transports (built-in):%s\n", b);
+if (*d) g = string_fmt_append(g, "Transports (dynamic): %s\n", d);
+return g;
+}
 
 
-router_info routers_available[] = {
-#ifdef ROUTER_ACCEPT
-  {
-  US"accept",
-  accept_router_options,
-  &accept_router_options_count,
-  &accept_router_option_defaults,
-  sizeof(accept_router_options_block),
-  accept_router_init,
-  accept_router_entry,
-  NULL,     /* no tidyup entry */
-  ri_yestransport
-  },
-#endif
-#ifdef ROUTER_DNSLOOKUP
-  {
-  US"dnslookup",
-  dnslookup_router_options,
-  &dnslookup_router_options_count,
-  &dnslookup_router_option_defaults,
-  sizeof(dnslookup_router_options_block),
-  dnslookup_router_init,
-  dnslookup_router_entry,
-  NULL,     /* no tidyup entry */
-  ri_yestransport
-  },
-#endif
-#ifdef ROUTER_IPLITERAL
-  {
-  US"ipliteral",
-  ipliteral_router_options,
-  &ipliteral_router_options_count,
-  &ipliteral_router_option_defaults,
-  sizeof(ipliteral_router_options_block),
-  ipliteral_router_init,
-  ipliteral_router_entry,
-  NULL,     /* no tidyup entry */
-  ri_yestransport
-  },
-#endif
-#ifdef ROUTER_IPLOOKUP
-  {
-  US"iplookup",
-  iplookup_router_options,
-  &iplookup_router_options_count,
-  &iplookup_router_option_defaults,
-  sizeof(iplookup_router_options_block),
-  iplookup_router_init,
-  iplookup_router_entry,
-  NULL,     /* no tidyup entry */
-  ri_notransport
-  },
-#endif
-#ifdef ROUTER_MANUALROUTE
-  {
-  US"manualroute",
-  manualroute_router_options,
-  &manualroute_router_options_count,
-  &manualroute_router_option_defaults,
-  sizeof(manualroute_router_options_block),
-  manualroute_router_init,
-  manualroute_router_entry,
-  NULL,     /* no tidyup entry */
-  0
-  },
-#endif
-#ifdef ROUTER_QUERYPROGRAM
-  {
-  US"queryprogram",
-  queryprogram_router_options,
-  &queryprogram_router_options_count,
-  &queryprogram_router_option_defaults,
-  sizeof(queryprogram_router_options_block),
-  queryprogram_router_init,
-  queryprogram_router_entry,
-  NULL,     /* no tidyup entry */
-  0
-  },
-#endif
-#ifdef ROUTER_REDIRECT
-  {
-  US"redirect",
-  redirect_router_options,
-  &redirect_router_options_count,
-  &redirect_router_option_defaults,
-  sizeof(redirect_router_options_block),
-  redirect_router_init,
-  redirect_router_entry,
-  NULL,     /* no tidyup entry */
-  ri_notransport
-  },
-#endif
-{ US"", NULL, NULL, NULL, 0, NULL, NULL, NULL, 0 }
-};
 
 
 
 
+static void
+add_lookup_to_tree(lookup_info * li)
+{
+tree_node * new = store_get_perm(sizeof(tree_node) + Ustrlen(li->name),
+                                                       GET_UNTAINTED);
+new->data.ptr = (void *)li;
+Ustrcpy(new->name, li->name);
+if (tree_insertnode(&lookups_tree, new))
+  li->acq_num = lookup_list_count++;
+else
+  log_write(0, LOG_MAIN|LOG_PANIC, "Duplicate lookup name '%s'", li->name);
+}
 
 
-transport_info transports_available[] = {
-#ifdef TRANSPORT_APPENDFILE
-  {
-  US"appendfile",                              /* driver name */
-  appendfile_transport_options,                /* local options table */
-  &appendfile_transport_options_count,         /* number of entries */
-  &appendfile_transport_option_defaults,       /* private options defaults */
-  sizeof(appendfile_transport_options_block),  /* size of private block */
-  appendfile_transport_init,                   /* init entry point */
-  appendfile_transport_entry,                  /* main entry point */
-  NULL,                                        /* no tidyup entry */
-  NULL,                                        /* no closedown entry */
-  TRUE,                                        /* local flag */
-  },
-#endif
-#ifdef TRANSPORT_AUTOREPLY
-  {
-  US"autoreply",                               /* driver name */
-  autoreply_transport_options,                 /* local options table */
-  &autoreply_transport_options_count,          /* number of entries */
-  &autoreply_transport_option_defaults,        /* private options defaults */
-  sizeof(autoreply_transport_options_block),   /* size of private block */
-  autoreply_transport_init,                    /* init entry point */
-  autoreply_transport_entry,                   /* main entry point */
-  NULL,                                        /* no tidyup entry */
-  NULL,                                        /* no closedown entry */
-  TRUE                                         /* local flag */
-  },
-#endif
-#ifdef TRANSPORT_LMTP
-  {
-  US"lmtp",                                    /* driver name */
-  lmtp_transport_options,                      /* local options table */
-  &lmtp_transport_options_count,               /* number of entries */
-  &lmtp_transport_option_defaults,             /* private options defaults */
-  sizeof(lmtp_transport_options_block),        /* size of private block */
-  lmtp_transport_init,                         /* init entry point */
-  lmtp_transport_entry,                        /* main entry point */
-  NULL,                                        /* no tidyup entry */
-  NULL,                                        /* no closedown entry */
-  TRUE                                         /* local flag */
-  },
-#endif
-#ifdef TRANSPORT_PIPE
-  {
-  US"pipe",                                    /* driver name */
-  pipe_transport_options,                      /* local options table */
-  &pipe_transport_options_count,               /* number of entries */
-  &pipe_transport_option_defaults,             /* private options defaults */
-  sizeof(pipe_transport_options_block),        /* size of private block */
-  pipe_transport_init,                         /* init entry point */
-  pipe_transport_entry,                        /* main entry point */
-  NULL,                                        /* no tidyup entry */
-  NULL,                                        /* no closedown entry */
-  TRUE                                         /* local flag */
-  },
-#endif
-#ifdef TRANSPORT_SMTP
-  {
-  US"smtp",                                    /* driver name */
-  smtp_transport_options,                      /* local options table */
-  &smtp_transport_options_count,               /* number of entries */
-  &smtp_transport_option_defaults,             /* private options defaults */
-  sizeof(smtp_transport_options_block),        /* size of private block */
-  smtp_transport_init,                         /* init entry point */
-  smtp_transport_entry,                        /* main entry point */
-  NULL,                                        /* no tidyup entry */
-  smtp_transport_closedown,                    /* close down passed channel */
-  FALSE                                        /* local flag */
-  },
-#endif
-{ US"", NULL, NULL, NULL, 0, NULL, NULL, NULL, NULL, FALSE }
-};
 
 
-struct lookupmodulestr
+/* Add all the lookup types provided by the module */
+static void
+addlookupmodule(const struct lookup_module_info * lmi)
 {
 {
-  void *dl;
-  struct lookup_module_info *info;
-  struct lookupmodulestr *next;
-};
+for (int j = 0; j < lmi->lookupcount; j++)
+  add_lookup_to_tree(lmi->lookups[j]);
+}
+
+
 
 
-static struct lookupmodulestr *lookupmodules = NULL;
+/* Hunt for the lookup with the given acquisition number */
 
 
-static void addlookupmodule(void *dl, struct lookup_module_info *info)
+static unsigned hunt_acq;
+
+static void
+acq_cb(uschar * name, uschar * ptr, void * ctx)
 {
 {
-  struct lookupmodulestr *p = store_malloc(sizeof(struct lookupmodulestr));
-  p->dl = dl;
-  p->info = info;
-  p->next = lookupmodules;
-  lookupmodules = p;
-  lookup_list_count += info->lookupcount;
+lookup_info * li = (lookup_info *)ptr;
+if (li->acq_num == hunt_acq) *(lookup_info **)ctx = li;
 }
 
 }
 
-/* only valid after lookup_list and lookup_list_count are assigned */
-static void add_lookup_to_list(lookup_info *info)
+const lookup_info *
+lookup_with_acq_num(unsigned k)
 {
 {
-  /* need to add the lookup to lookup_list, sorted */
-  int pos = 0;
-
-  /* strategy is to go through the list until we find
-   * either an empty spot or a name that is higher.
-   * this can't fail because we have enough space. */
-  while (lookup_list[pos]
-      && (Ustrcmp(lookup_list[pos]->name, info->name) <= 0)) {
-    pos++;
-  }
-  if (lookup_list[pos]) {
-    /* need to insert it, so move all the other items up
-     * (last slot is still empty, of course) */
-    memmove(&lookup_list[pos+1],
-            &lookup_list[pos],
-            sizeof(lookup_info **) * (lookup_list_count-pos-1));
-  }
-  lookup_list[pos] = info;
+const lookup_info * li = NULL;
+hunt_acq = k;
+tree_walk(lookups_tree, acq_cb, &li);
+return li;
 }
 
 
 }
 
 
+
 /* These need to be at file level for old versions of gcc (2.95.2 reported),
 /* These need to be at file level for old versions of gcc (2.95.2 reported),
- * which give parse errors on an extern in function scope.  Each entry needs
- * to also be invoked in init_lookup_list() below  */
+which give parse errors on an extern in function scope.  Each entry needs
+to also be invoked in init_lookup_list() below  */
 
 
-#if defined(LOOKUP_WHOSON) && LOOKUP_WHOSON!=2
-extern lookup_module_info whoson_lookup_module_info;
+#if defined(LOOKUP_CDB) && LOOKUP_CDB!=2
+extern lookup_module_info cdb_lookup_module_info;
 #endif
 #endif
-#if defined(LOOKUP_TESTDB) && LOOKUP_TESTDB!=2
-extern lookup_module_info testdb_lookup_module_info;
+#if defined(LOOKUP_DBM) && LOOKUP_DBM!=2
+extern lookup_module_info dbmdb_lookup_module_info;
 #endif
 #endif
-#if defined(LOOKUP_SQLITE) && LOOKUP_SQLITE!=2
-extern lookup_module_info sqlite_lookup_module_info;
+#if defined(LOOKUP_DNSDB) && LOOKUP_DNSDB!=2
+extern lookup_module_info dnsdb_lookup_module_info;
 #endif
 #endif
-#ifdef EXPERIMENTAL_SPF
-extern lookup_module_info spf_lookup_module_info;
+#if defined(LOOKUP_DSEARCH) && LOOKUP_DSEARCH!=2
+extern lookup_module_info dsearch_lookup_module_info;
 #endif
 #endif
-#if defined(LOOKUP_PGSQL) && LOOKUP_PGSQL!=2
-extern lookup_module_info pgsql_lookup_module_info;
+#if defined(LOOKUP_IBASE) && LOOKUP_IBASE!=2
+extern lookup_module_info ibase_lookup_module_info;
 #endif
 #endif
-#if defined(LOOKUP_PASSWD) && LOOKUP_PASSWD!=2
-extern lookup_module_info passwd_lookup_module_info;
+#if defined(LOOKUP_JSON) && LOOKUP_JSON!=2
+extern lookup_module_info json_lookup_module_info;
 #endif
 #endif
-#if defined(LOOKUP_ORACLE) && LOOKUP_ORACLE!=2
-extern lookup_module_info oracle_lookup_module_info;
+#if defined(LOOKUP_LDAP) && LOOKUP_LDAP!=2
+extern lookup_module_info ldap_lookup_module_info;
 #endif
 #endif
-#if defined(LOOKUP_NISPLUS) && LOOKUP_NISPLUS!=2
-extern lookup_module_info nisplus_lookup_module_info;
+#if defined(LOOKUP_LSEARCH) && LOOKUP_LSEARCH!=2
+extern lookup_module_info lsearch_lookup_module_info;
+#endif
+#if defined(LOOKUP_MYSQL) && LOOKUP_MYSQL!=2
+extern lookup_module_info mysql_lookup_module_info;
 #endif
 #if defined(LOOKUP_NIS) && LOOKUP_NIS!=2
 extern lookup_module_info nis_lookup_module_info;
 #endif
 #endif
 #if defined(LOOKUP_NIS) && LOOKUP_NIS!=2
 extern lookup_module_info nis_lookup_module_info;
 #endif
-#if defined(LOOKUP_MYSQL) && LOOKUP_MYSQL!=2
-extern lookup_module_info mysql_lookup_module_info;
+#if defined(LOOKUP_NISPLUS) && LOOKUP_NISPLUS!=2
+extern lookup_module_info nisplus_lookup_module_info;
 #endif
 #endif
-#if defined(LOOKUP_LSEARCH) && LOOKUP_LSEARCH!=2
-extern lookup_module_info lsearch_lookup_module_info;
+#if defined(LOOKUP_ORACLE) && LOOKUP_ORACLE!=2
+extern lookup_module_info oracle_lookup_module_info;
 #endif
 #endif
-#ifdef LOOKUP_LDAP
-extern lookup_module_info ldap_lookup_module_info;
+#if defined(LOOKUP_PASSWD) && LOOKUP_PASSWD!=2
+extern lookup_module_info passwd_lookup_module_info;
 #endif
 #endif
-#if defined(LOOKUP_IBASE) && LOOKUP_IBASE!=2
-extern lookup_module_info ibase_lookup_module_info;
+#if defined(LOOKUP_PGSQL) && LOOKUP_PGSQL!=2
+extern lookup_module_info pgsql_lookup_module_info;
 #endif
 #endif
-#if defined(LOOKUP_DSEARCH) && LOOKUP_DSEARCH!=2
-extern lookup_module_info dsearch_lookup_module_info;
+#if defined(LOOKUP_REDIS) && LOOKUP_REDIS!=2
+extern lookup_module_info redis_lookup_module_info;
 #endif
 #endif
-#if defined(LOOKUP_DNSDB) && LOOKUP_DNSDB!=2
-extern lookup_module_info dnsdb_lookup_module_info;
+#if defined(LOOKUP_LMDB) && LOOKUP_LMDB!=2
+extern lookup_module_info lmdb_lookup_module_info;
 #endif
 #endif
-#if defined(LOOKUP_DBM) && LOOKUP_DBM!=2
-extern lookup_module_info dbmdb_lookup_module_info;
+#if defined(SUPPORT_SPF)
+extern lookup_module_info spf_lookup_module_info;      /* see below */
 #endif
 #endif
-#if defined(LOOKUP_CDB) && LOOKUP_CDB!=2
-extern lookup_module_info cdb_lookup_module_info;
+#if defined(LOOKUP_SQLITE) && LOOKUP_SQLITE!=2
+extern lookup_module_info sqlite_lookup_module_info;
+#endif
+#if defined(LOOKUP_TESTDB) && LOOKUP_TESTDB!=2
+extern lookup_module_info testdb_lookup_module_info;
+#endif
+#if defined(LOOKUP_WHOSON) && LOOKUP_WHOSON!=2
+extern lookup_module_info whoson_lookup_module_info;
 #endif
 
 #endif
 
-void init_lookup_list(void)
+extern lookup_module_info readsock_lookup_module_info;
+
+
+#ifdef LOOKUP_MODULE_DIR
+static void *
+mod_open(const uschar * name, const uschar * class, uschar ** errstr)
+{
+const uschar * path = string_sprintf(
+  LOOKUP_MODULE_DIR "/%s_%s." DYNLIB_FN_EXT, name, class);
+void * dl;
+if (!(dl = dlopen(CS path, RTLD_NOW)))
+  {
+  if (errstr)
+    *errstr = string_sprintf("Error loading %s: %s", name, dlerror());
+  else
+    (void) dlerror();          /* clear out error state */
+  return NULL;
+  }
+
+/* FreeBSD nsdispatch() can trigger dlerror() errors about
+_nss_cache_cycle_prevention_function; we need to clear the dlerror()
+state before calling dlsym(), so that any error afterwards only comes
+from dlsym().  */
+
+(void) dlerror();
+return dl;
+}
+
+
+/* Try to load a lookup module with the given name.
+
+Arguments:
+    name               name of the lookup
+    errstr             if not NULL, place "open fail" error message here
+
+Return: boolean success
+*/
+
+static BOOL
+lookup_mod_load(const uschar * name, uschar ** errstr)
+{
+void * dl;
+struct lookup_module_info * info;
+const char * errormsg;
+
+if (!(dl = mod_open(name, US"lookup", errstr)))
+  return FALSE;
+
+info = (struct lookup_module_info *) dlsym(dl, "_lookup_module_info");
+if ((errormsg = dlerror()))
+  {
+  fprintf(stderr, "%s does not appear to be a lookup module (%s)\n", name, errormsg);
+  log_write(0, LOG_MAIN|LOG_PANIC, "%s does not appear to be a lookup module (%s)", name, errormsg);
+  dlclose(dl);
+  return FALSE;
+  }
+if (info->magic != LOOKUP_MODULE_INFO_MAGIC)
+  {
+  fprintf(stderr, "Lookup module %s is not compatible with this version of Exim\n", name);
+  log_write(0, LOG_MAIN|LOG_PANIC, "Lookup module %s is not compatible with this version of Exim", name);
+  dlclose(dl);
+  return FALSE;
+  }
+
+addlookupmodule(info);
+DEBUG(D_lookup) debug_printf_indent("Loaded \"%s\" (%d lookup type%s)\n",
+                                   name, info->lookupcount,
+                                   info->lookupcount > 1 ? "s" : "");
+return TRUE;
+}
+
+
+/* Try to load a lookup module, assuming the module name is the same
+as the lookup type name.  This will only work for single-method modules.
+Other have to be always-load (see the RE in init_lookup_list() below).
+*/
+
+BOOL
+lookup_one_mod_load(const uschar * name, uschar ** errstr)
 {
 {
-  DIR *dd;
-  struct dirent *ent;
-  const pcre *regex_islookupmod = regex_must_compile(US"\\.so$", FALSE, TRUE);
-  int countmodules = 0;
-  int moduleerrors = 0;
-  struct lookupmodulestr *p;
+if (!lookup_mod_load(name, errstr)) return FALSE;
+/*XXX notify daemon? */
+return TRUE;
+}
+
+#endif /*LOOKUP_MODULE_DIR*/
+
+
+
+misc_module_info * misc_module_list = NULL;
+
+static void
+misc_mod_add(misc_module_info * mi)
+{
+mi->next = misc_module_list;
+misc_module_list = mi;
+
+if (mi->init && !mi->init(mi))
+  DEBUG(D_any)
+    debug_printf_indent("module init call failed for %s\n", mi->name);
+
+DEBUG(D_any) if (mi->lib_vers_report)
+  debug_printf_indent("%Y", mi->lib_vers_report(NULL));
+
+/* fprintf(stderr,"misc_mod_add: added %s\n", mi->name); */
+}
+
+
+#ifdef LOOKUP_MODULE_DIR
+
+/* Load a "misc" module, and add to list */
+
+static misc_module_info *
+misc_mod_load(const uschar * name, uschar ** errstr)
+{
+void * dl;
+struct misc_module_info * mi;
+const char * errormsg;
+
+DEBUG(D_any) debug_printf_indent("loading module '%s'\n", name);
+if (!(dl = mod_open(name, US"miscmod", errstr)))
+  {
+  DEBUG(D_any) if (errstr) debug_printf_indent(" mod_open: %s\n", *errstr);
+  return NULL;
+  }
+
+mi = (struct misc_module_info *) dlsym(dl,
+                                   CS string_sprintf("%s_module_info", name));
+if ((errormsg = dlerror()))
+  {
+  fprintf(stderr, "%s does not appear to be a '%s' module (%s)\n",
+         name, name, errormsg);
+  log_write(0, LOG_MAIN|LOG_PANIC,
+    "%s does not contain the expected module info symbol (%s)", name, errormsg);
+  dlclose(dl);
+  return NULL;
+  }
+if (mi->dyn_magic != MISC_MODULE_MAGIC)
+  {
+  fprintf(stderr, "Module %s is not compatible with this version of Exim\n", name);
+  log_write(0, LOG_MAIN|LOG_PANIC, "Module %s is not compatible with this version of Exim", name);
+  dlclose(dl);
+  return FALSE;
+  }
+
+DEBUG(D_lookup) debug_printf_indent("Loaded \"%s\"\n", name);
+misc_mod_add(mi);
+return mi;
+}
+
+#endif /*LOOKUP_MODULE_DIR*/
+
+
+/* Find a "misc" module by name, if loaded.
+For now use a linear search down a linked list.  If the number of
+modules gets large, we might consider a tree.
+*/
+
+misc_module_info *
+misc_mod_findonly(const uschar * name)
+{
+for (misc_module_info * mi = misc_module_list; mi; mi = mi->next)
+  if (Ustrcmp(name, mi->name) == 0)
+    return mi;
+return NULL;
+}
+
+/* Find a "misc" module, possibly already loaded, by name. */
+
+misc_module_info *
+misc_mod_find(const uschar * name, uschar ** errstr)
+{
+misc_module_info * mi;
+if ((mi = misc_mod_findonly(name))) return mi;
+#ifdef LOOKUP_MODULE_DIR
+return misc_mod_load(name, errstr);
+#else
+return NULL;
+#endif /*LOOKUP_MODULE_DIR*/
+}
+
 
 
-  if (lookup_list_init_done)
-    return;
-  lookup_list_init_done = 1;
+/* For any "misc" module having a connection-init routine, call it. */
+
+int
+misc_mod_conn_init(const uschar * sender_helo_name,
+  const uschar * sender_host_address)
+{
+for (const misc_module_info * mi = misc_module_list; mi; mi = mi->next)
+  if (mi->conn_init)
+    if ((mi->conn_init) (sender_helo_name, sender_host_address) != OK)
+      return FAIL;
+return OK;
+}
+
+/* Ditto, smtp-reset */
+
+void
+misc_mod_smtp_reset(void)
+{
+for (const misc_module_info * mi = misc_module_list; mi; mi = mi->next)
+  if (mi->smtp_reset)
+    (mi->smtp_reset)();
+}
+
+/* Ditto, msg-init */
+
+int
+misc_mod_msg_init(void)
+{
+for (const misc_module_info * mi = misc_module_list; mi; mi = mi->next)
+  if (mi->msg_init)
+    if ((mi->msg_init)() != OK)
+      return FAIL;
+return OK;
+}
+
+/* Ditto, authres.  Having to sort the responses (mainly for the testsuite)
+is pretty painful - maybe we should sort the modules on insertion to
+the list? */
+
+gstring *
+misc_mod_authres(gstring * g)
+{
+typedef struct {
+  const uschar * name;
+  gstring *     res;
+} pref;
+pref prefs[] = {
+  {US"spf", NULL}, {US"dkim", NULL}, {US"dmarc", NULL}, {US"arc", NULL}
+};
+gstring * others = NULL;
+
+for (const misc_module_info * mi = misc_module_list; mi; mi = mi->next)
+  if (mi->authres)
+    {
+    pref * p;
+    for (p = prefs; p < prefs + nelem(prefs); p++)
+      if (Ustrcmp(p->name, mi->name) == 0) break;
+
+    if (p) p->res = (mi->authres)(NULL);
+    else   others = (mi->authres)(others);
+    }
+
+for (pref * p = prefs; p < prefs + nelem(prefs); p++)
+  g = gstring_append(g, p->res);
+return gstring_append(g, others);
+}
+
+
+
+
+
+
+void
+init_lookup_list(void)
+{
+#ifdef LOOKUP_MODULE_DIR
+DIR * dd;
+int countmodules = 0;
+#endif
+static BOOL lookup_list_init_done = FALSE;
+
+if (lookup_list_init_done)
+  return;
+lookup_list_init_done = TRUE;
 
 #if defined(LOOKUP_CDB) && LOOKUP_CDB!=2
 
 #if defined(LOOKUP_CDB) && LOOKUP_CDB!=2
-  addlookupmodule(NULL, &cdb_lookup_module_info);
+addlookupmodule(&cdb_lookup_module_info);
 #endif
 
 #if defined(LOOKUP_DBM) && LOOKUP_DBM!=2
 #endif
 
 #if defined(LOOKUP_DBM) && LOOKUP_DBM!=2
-  addlookupmodule(NULL, &dbmdb_lookup_module_info);
+addlookupmodule(&dbmdb_lookup_module_info);
 #endif
 
 #if defined(LOOKUP_DNSDB) && LOOKUP_DNSDB!=2
 #endif
 
 #if defined(LOOKUP_DNSDB) && LOOKUP_DNSDB!=2
-  addlookupmodule(NULL, &dnsdb_lookup_module_info);
+addlookupmodule(&dnsdb_lookup_module_info);
 #endif
 
 #if defined(LOOKUP_DSEARCH) && LOOKUP_DSEARCH!=2
 #endif
 
 #if defined(LOOKUP_DSEARCH) && LOOKUP_DSEARCH!=2
-  addlookupmodule(NULL, &dsearch_lookup_module_info);
+addlookupmodule(&dsearch_lookup_module_info);
 #endif
 
 #if defined(LOOKUP_IBASE) && LOOKUP_IBASE!=2
 #endif
 
 #if defined(LOOKUP_IBASE) && LOOKUP_IBASE!=2
-  addlookupmodule(NULL, &ibase_lookup_module_info);
+addlookupmodule(&ibase_lookup_module_info);
+#endif
+
+#if defined(LOOKUP_LDAP) && LOOKUP_LDAP!=2
+addlookupmodule(&ldap_lookup_module_info);
 #endif
 
 #endif
 
-#ifdef LOOKUP_LDAP
-  addlookupmodule(NULL, &ldap_lookup_module_info);
+#if defined(LOOKUP_JSON) && LOOKUP_JSON!=2
+addlookupmodule(&json_lookup_module_info);
 #endif
 
 #if defined(LOOKUP_LSEARCH) && LOOKUP_LSEARCH!=2
 #endif
 
 #if defined(LOOKUP_LSEARCH) && LOOKUP_LSEARCH!=2
-  addlookupmodule(NULL, &lsearch_lookup_module_info);
+addlookupmodule(&lsearch_lookup_module_info);
 #endif
 
 #if defined(LOOKUP_MYSQL) && LOOKUP_MYSQL!=2
 #endif
 
 #if defined(LOOKUP_MYSQL) && LOOKUP_MYSQL!=2
-  addlookupmodule(NULL, &mysql_lookup_module_info);
+addlookupmodule(&mysql_lookup_module_info);
 #endif
 
 #if defined(LOOKUP_NIS) && LOOKUP_NIS!=2
 #endif
 
 #if defined(LOOKUP_NIS) && LOOKUP_NIS!=2
-  addlookupmodule(NULL, &nis_lookup_module_info);
+addlookupmodule(&nis_lookup_module_info);
 #endif
 
 #if defined(LOOKUP_NISPLUS) && LOOKUP_NISPLUS!=2
 #endif
 
 #if defined(LOOKUP_NISPLUS) && LOOKUP_NISPLUS!=2
-  addlookupmodule(NULL, &nisplus_lookup_module_info);
+addlookupmodule(&nisplus_lookup_module_info);
 #endif
 
 #if defined(LOOKUP_ORACLE) && LOOKUP_ORACLE!=2
 #endif
 
 #if defined(LOOKUP_ORACLE) && LOOKUP_ORACLE!=2
-  addlookupmodule(NULL, &oracle_lookup_module_info);
+addlookupmodule(&oracle_lookup_module_info);
 #endif
 
 #if defined(LOOKUP_PASSWD) && LOOKUP_PASSWD!=2
 #endif
 
 #if defined(LOOKUP_PASSWD) && LOOKUP_PASSWD!=2
-  addlookupmodule(NULL, &passwd_lookup_module_info);
+addlookupmodule(&passwd_lookup_module_info);
 #endif
 
 #if defined(LOOKUP_PGSQL) && LOOKUP_PGSQL!=2
 #endif
 
 #if defined(LOOKUP_PGSQL) && LOOKUP_PGSQL!=2
-  addlookupmodule(NULL, &pgsql_lookup_module_info);
+addlookupmodule(&pgsql_lookup_module_info);
+#endif
+
+#if defined(LOOKUP_REDIS) && LOOKUP_REDIS!=2
+addlookupmodule(&redis_lookup_module_info);
 #endif
 
 #endif
 
-#ifdef EXPERIMENTAL_SPF
-  addlookupmodule(NULL, &spf_lookup_module_info);
+#if defined(LOOKUP_LMDB) && LOOKUP_LMDB!=2
+addlookupmodule(&lmdb_lookup_module_info);
 #endif
 
 #if defined(LOOKUP_SQLITE) && LOOKUP_SQLITE!=2
 #endif
 
 #if defined(LOOKUP_SQLITE) && LOOKUP_SQLITE!=2
-  addlookupmodule(NULL, &sqlite_lookup_module_info);
+addlookupmodule(&sqlite_lookup_module_info);
 #endif
 
 #if defined(LOOKUP_TESTDB) && LOOKUP_TESTDB!=2
 #endif
 
 #if defined(LOOKUP_TESTDB) && LOOKUP_TESTDB!=2
-  addlookupmodule(NULL, &testdb_lookup_module_info);
+addlookupmodule(&testdb_lookup_module_info);
 #endif
 
 #if defined(LOOKUP_WHOSON) && LOOKUP_WHOSON!=2
 #endif
 
 #if defined(LOOKUP_WHOSON) && LOOKUP_WHOSON!=2
-  addlookupmodule(NULL, &whoson_lookup_module_info);
+addlookupmodule(&whoson_lookup_module_info);
 #endif
 
 #endif
 
+/* This is provided by the spf "misc" module, and the lookup aspect is always
+linked statically whether or not the "misc" module (and hence libspf2) is
+dynamic-load. */
+
+#if defined(SUPPORT_SPF)
+addlookupmodule(&spf_lookup_module_info);
+#endif
+
+/* This is a custom expansion, and not available as either
+a list-syntax lookup or a lookup expansion. However, it is
+implemented by a lookup module. */
+
+addlookupmodule(&readsock_lookup_module_info);
+
+DEBUG(D_lookup) debug_printf("Total %d built-in lookups\n", lookup_list_count);
+
+
 #ifdef LOOKUP_MODULE_DIR
 #ifdef LOOKUP_MODULE_DIR
-  dd = opendir(LOOKUP_MODULE_DIR);
-  if (dd == NULL) {
-    DEBUG(D_lookup) debug_printf("Couldn't open %s: not loading lookup modules\n", LOOKUP_MODULE_DIR);
-    log_write(0, LOG_MAIN, "Couldn't open %s: not loading lookup modules\n", LOOKUP_MODULE_DIR);
+if (!(dd = exim_opendir(CUS LOOKUP_MODULE_DIR)))
+  {
+  DEBUG(D_lookup) debug_printf("Couldn't open %s: not loading lookup modules\n", LOOKUP_MODULE_DIR);
+  log_write(0, LOG_MAIN|LOG_PANIC,
+         "Couldn't open %s: not loading lookup modules\n", LOOKUP_MODULE_DIR);
   }
   }
-  else {
-    DEBUG(D_lookup) debug_printf("Loading lookup modules from %s\n", LOOKUP_MODULE_DIR);
-    while ((ent = readdir(dd)) != NULL) {
-      char *name = ent->d_name;
-      int len = (int)strlen(name);
-      if (pcre_exec(regex_islookupmod, NULL, name, len, 0, PCRE_EOPT, NULL, 0) >= 0) {
-        int pathnamelen = len + (int)strlen(LOOKUP_MODULE_DIR) + 2;
-        void *dl;
-        struct lookup_module_info *info;
-        char *errormsg;
-
-        /* SRH: am I being paranoid here or what? */
-        if (pathnamelen > big_buffer_size) {
-          fprintf(stderr, "Loading lookup modules: %s/%s: name too long\n", LOOKUP_MODULE_DIR, name);
-          log_write(0, LOG_MAIN|LOG_PANIC, "%s/%s: name too long\n", LOOKUP_MODULE_DIR, name);
-          continue;
-        }
-
-        /* SRH: snprintf here? */
-        sprintf(CS big_buffer, "%s/%s", LOOKUP_MODULE_DIR, name);
-
-        dl = dlopen(CS big_buffer, RTLD_NOW);// TJ was LAZY
-        if (dl == NULL) {
-          fprintf(stderr, "Error loading %s: %s\n", name, dlerror());
-          moduleerrors++;
-          log_write(0, LOG_MAIN|LOG_PANIC, "Error loading lookup module %s: %s\n", name, dlerror());
-          continue;
-        }
-
-        /* FreeBSD nsdispatch() can trigger dlerror() errors about
-         * _nss_cache_cycle_prevention_function; we need to clear the dlerror()
-         * state before calling dlsym(), so that any error afterwards only
-         * comes from dlsym().
-         */
-        errormsg = dlerror();
-
-        info = (struct lookup_module_info*) dlsym(dl, "_lookup_module_info");
-        if ((errormsg = dlerror()) != NULL) {
-          fprintf(stderr, "%s does not appear to be a lookup module (%s)\n", name, errormsg);
-          dlclose(dl);
-          moduleerrors++;
-          log_write(0, LOG_MAIN|LOG_PANIC, "%s does not appear to be a lookup module (%s)\n", name, errormsg);
-          continue;
-        }
-        if (info->magic != LOOKUP_MODULE_INFO_MAGIC) {
-          fprintf(stderr, "Lookup module %s is not compatible with this version of Exim\n", name);
-          dlclose(dl);
-          moduleerrors++;
-          log_write(0, LOG_MAIN|LOG_PANIC, "Lookup module %s is not compatible with this version of Exim\n", name);
-          continue;
-        }
-
-        addlookupmodule(dl, info);
-        DEBUG(D_lookup) debug_printf("Loaded \"%s\" (%d lookup types)\n", name, info->lookupcount);
-        countmodules++;
+else
+  {
+  /* Look specifically for modules we know offer several lookup types and
+  load them now, since we cannot load-on-first-use. */
+
+  struct dirent * ent;
+  const pcre2_code * regex_islookupmod = regex_must_compile(
+    US"(lsearch|ldap|nis)_lookup\\." DYNLIB_FN_EXT "$", MCS_NOFLAGS, TRUE);
+
+  DEBUG(D_lookup) debug_printf("Loading lookup modules from %s\n", LOOKUP_MODULE_DIR);
+  while ((ent = readdir(dd)))
+    {
+    char * name = ent->d_name;
+    int len = (int)strlen(name);
+    if (regex_match_and_setup(regex_islookupmod, US name, 0, 0))
+      {
+      uschar * errstr;
+      if (lookup_mod_load(expand_nstring[1], &errstr))
+       countmodules++;
+      else
+       {
+       fprintf(stderr, "%s\n", errstr);
+       log_write(0, LOG_MAIN|LOG_PANIC, "%s", errstr);
+       }
       }
     }
       }
     }
-    closedir(dd);
+  closedir(dd);
   }
 
   }
 
-  DEBUG(D_lookup) debug_printf("Loaded %d lookup modules\n", countmodules);
+DEBUG(D_lookup) debug_printf("Loaded %d lookup modules\n", countmodules);
 #endif
 #endif
+}
 
 
-  store_free((void*)regex_islookupmod);
-
-  DEBUG(D_lookup) debug_printf("Total %d lookups\n", lookup_list_count);
 
 
-  lookup_list = store_malloc(sizeof(lookup_info *) * lookup_list_count);
-  memset(lookup_list, 0, sizeof(lookup_info *) * lookup_list_count);
+/* Add module info struct to the modules list for those that are
+built as static */
 
 
-  /* now add all lookups to the real list */
-  p = lookupmodules;
-  while (p) {
-    int j;
-    struct lookupmodulestr *pnext;
+#if !defined(DISABLE_DKIM) && (!defined(SUPPORT_DKIM) || SUPPORT_DKIM!=2)
+extern misc_module_info dkim_module_info;
+#endif
+#if defined(SUPPORT_DMARC) && SUPPORT_DMARC!=2
+extern misc_module_info dmarc_module_info;
+#endif
+#if defined(SUPPORT_SPF) && SUPPORT_SPF!=2
+extern misc_module_info spf_module_info;
+#endif
+#if defined(EXPERIMENTAL_ARC) && (!defined(SUPPORT_ARC) || SUPPORT_ARC!=2)
+extern misc_module_info arc_module_info;
+#endif
+#if defined(RADIUS_CONFIG_FILE) && (!defined(SUPPORT_RADIUS) || SUPPORT_RADIUS!=2)
+extern misc_module_info radius_module_info;
+#endif
+#if defined(SUPPORT_PAM) && SUPPORT_PAM!=2
+extern misc_module_info pam_module_info;
+#endif
+#if defined(EXIM_PERL) && (!defined(SUPPORT_PERL) || SUPPORT_PERL!=2)
+extern misc_module_info perl_module_info;
+#endif
+#if !defined(DISABLE_EXIM_FILTER) && (!defined(SUPPORT_EXIM_FILTER) || SUPPORT_EXIM_FILTER!=2)
+extern misc_module_info exim_filter_module_info;
+#endif
+#if !defined(DISABLE_SIEVE_FILTER) && (!defined(SUPPORT_SIEVE_FILTER) || SUPPORT_SIEVE_FILTER!=2)
+extern misc_module_info sieve_filter_module_info;
+#endif
 
 
-    for (j = 0; j < p->info->lookupcount; j++)
-      add_lookup_to_list(p->info->lookups[j]);
+void
+init_misc_mod_list(void)
+{
+static BOOL onetime = FALSE;
+if (onetime) return;
+onetime = TRUE;
 
 
-    pnext = p->next;
-    store_free(p);
-    p = pnext;
-  }
-  /* just to be sure */
-  lookupmodules = NULL;
+#if !defined(DISABLE_DKIM) && (!defined(SUPPORT_DKIM) || SUPPORT_DKIM!=2)
+  misc_mod_add(&dkim_module_info);
+#endif
+#if defined(SUPPORT_SPF) && SUPPORT_SPF!=2
+  misc_mod_add(&spf_module_info);
+#endif
+#if defined(SUPPORT_DMARC) && SUPPORT_DMARC!=2
+/* dmarc depends on spf so this add must go after, for the both-static case */
+  misc_mod_add(&dmarc_module_info);
+#endif
+#if defined(EXPERIMENTAL_ARC) && (!defined(SUPPORT_ARC) || SUPPORT_ARC!=2)
+  misc_mod_add(&arc_module_info);
+#endif
+#if defined(RADIUS_CONFIG_FILE) && (!defined(SUPPORT_RADIUS) || SUPPORT_RADIUS!=2)
+  misc_mod_add(&radius_module_info);
+#endif
+#if defined(SUPPORT_PAM) && SUPPORT_PAM!=2
+  misc_mod_add(&pam_module_info);
+#endif
+#if defined(EXIM_PERL) && (!defined(SUPPORT_PERL) || SUPPORT_PERL!=2)
+  misc_mod_add(&perl_module_info);
+#endif
+#if !defined(DISABLE_EXIM_FILTER) && (!defined(SUPPORT_EXIM_FILTER) || SUPPORT_EXIM_FILTER!=2)
+  misc_mod_add(&exim_filter_module_info);
+#endif
+#if !defined(DISABLE_SIEVE_FILTER) && (!defined(SUPPORT_SIEVE_FILTER) || SUPPORT_SIEVE_FILTER!=2)
+  misc_mod_add(&sieve_filter_module_info);
+#endif
 }
 
 }
 
+
+#endif /*!MACRO_PREDEF*/
 /* End of drtables.c */
 /* End of drtables.c */