Added support for SQLite.
authorPhilip Hazel <ph10@hermes.cam.ac.uk>
Mon, 1 Aug 2005 13:20:28 +0000 (13:20 +0000)
committerPhilip Hazel <ph10@hermes.cam.ac.uk>
Mon, 1 Aug 2005 13:20:28 +0000 (13:20 +0000)
16 files changed:
doc/doc-txt/ChangeLog
doc/doc-txt/NewStuff
src/ACKNOWLEDGMENTS
src/scripts/MakeLinks
src/src/EDITME
src/src/config.h.defaults
src/src/drtables.c
src/src/exim.c
src/src/expand.c
src/src/lookups/Makefile
src/src/lookups/README
src/src/lookups/sqlite.c [new file with mode: 0644]
src/src/lookups/sqlite.h [new file with mode: 0644]
src/src/macros.h
src/src/match.c
src/src/verify.c

index 52519e9..2846c96 100644 (file)
@@ -1,4 +1,4 @@
-$Cambridge: exim/doc/doc-txt/ChangeLog,v 1.182 2005/07/23 20:59:16 tom Exp $
+$Cambridge: exim/doc/doc-txt/ChangeLog,v 1.183 2005/08/01 13:20:28 ph10 Exp $
 
 Change log file for Exim from version 4.21
 -------------------------------------------
@@ -9,6 +9,8 @@ Exim version 4.53
 TK/01 Added the "success_on_redirect" address verification option. See
       NewStuff for rationale and an example.
 
+PH/01 Added support for SQLite, basic code supplied by David Woodhouse.
+
 
 Exim version 4.52
 -----------------
index 4df98e9..7959448 100644 (file)
@@ -1,4 +1,4 @@
-$Cambridge: exim/doc/doc-txt/NewStuff,v 1.56 2005/07/27 18:27:55 fanf2 Exp $
+$Cambridge: exim/doc/doc-txt/NewStuff,v 1.57 2005/08/01 13:20:28 ph10 Exp $
 
 New Features in Exim
 --------------------
@@ -22,6 +22,31 @@ TK/01 Added the "success_on_redirect" address verification option. When an
       In that case, verification will succeed when a router generates a new
       address.
 
+PH/01 Support for SQLite database lookups has been added. This is another
+      query-style lookup, but it is slightly different from the others because
+      a file name is required in addition to the SQL query. This is because an
+      SQLite database is a single file and there is no daemon as in other SQL
+      databases. The interface to Exim requires the name of the file, as an
+      absolute path, to be given at the start of the query. It is separated
+      from the query by white space. This means that the path name cannot
+      contain white space. Here is a lookup expansion example:
+
+        ${lookup sqlite {/some/thing/sqlitedb \
+          select name from aliases where id='ph10';}}
+
+      In a list, the syntax is similar. For example:
+
+        domainlist relay_domains = sqlite;/some/thing/sqlitedb \
+           select * from relays where ip='$sender_host_address';
+
+      The only character affected by the ${quote_sqlite: operator is a single
+      quote, which it doubles.
+
+      Note that you must set LOOKUP_SQLITE=yes in Local/Makefile in order to
+      obtain SQLite support, and you will also need to add -lsqlite3 to the
+      EXTRALIBS setting. And of course, you have to install SQLite on your
+      host first.
+
 
 Exim version 4.52
 -----------------
index cd5a9a0..e8d3c7c 100644 (file)
@@ -1,4 +1,4 @@
-$Cambridge: exim/src/ACKNOWLEDGMENTS,v 1.28 2005/06/28 08:49:38 ph10 Exp $
+$Cambridge: exim/src/ACKNOWLEDGMENTS,v 1.29 2005/08/01 13:20:28 ph10 Exp $
 
 EXIM ACKNOWLEDGEMENTS
 
@@ -20,7 +20,7 @@ relatively small patches.
 Philip Hazel
 
 Lists created: 20 November 2002
-Last updated:  28 June 2005
+Last updated:  29 July 2005
 
 
 THE OLD LIST
@@ -231,5 +231,6 @@ Joachim Wieland           Patches for PostgreSQL socket support and other
                             PostgreSQL functionality
                           Patch for hosts_avoid_esmtp
 Stephen Wilcox            Patch for ignore_enotdir problem
+David Woodhouse           SQLite support proof of concept code
 
 ****
index 2e24cb8..120a25b 100755 (executable)
@@ -1,5 +1,5 @@
 #!/bin/sh
-# $Cambridge: exim/src/scripts/MakeLinks,v 1.5 2005/06/15 08:57:10 ph10 Exp $
+# $Cambridge: exim/src/scripts/MakeLinks,v 1.6 2005/08/01 13:20:28 ph10 Exp $
 
 # Script to build links for all the exim source files from the system-
 # specific build directory. It should be run from within that directory.
@@ -84,6 +84,8 @@ ln -s ../../src/lookups/pgsql.h          pgsql.h
 ln -s ../../src/lookups/pgsql.c          pgsql.c
 ln -s ../../src/lookups/spf.h            spf.h
 ln -s ../../src/lookups/spf.c            spf.c
+ln -s ../../src/lookups/sqlite.h         sqlite.h
+ln -s ../../src/lookups/sqlite.c         sqlite.c
 ln -s ../../src/lookups/testdb.h         testdb.h
 ln -s ../../src/lookups/testdb.c         testdb.c
 ln -s ../../src/lookups/whoson.h         whoson.h
index 9be2b71..dc0892c 100644 (file)
@@ -1,4 +1,4 @@
-# $Cambridge: exim/src/src/EDITME,v 1.13 2005/07/23 20:19:41 tom Exp $
+# $Cambridge: exim/src/src/EDITME,v 1.14 2005/08/01 13:20:28 ph10 Exp $
 
 ##################################################
 #          The Exim mail transport agent         #
@@ -266,6 +266,7 @@ LOOKUP_LSEARCH=yes
 # LOOKUP_ORACLE=yes
 # LOOKUP_PASSWD=yes
 # LOOKUP_PGSQL=yes
+# LOOKUP_SQLITE=yes
 # LOOKUP_WHOSON=yes
 
 # These two settings are obsolete; all three lookups are compiled when
index 2825f98..4991d65 100644 (file)
@@ -1,4 +1,4 @@
-/* $Cambridge: exim/src/src/config.h.defaults,v 1.6 2005/03/22 14:11:54 ph10 Exp $ */
+/* $Cambridge: exim/src/src/config.h.defaults,v 1.7 2005/08/01 13:20:28 ph10 Exp $ */
 
 /*************************************************
 *     Exim - an Internet mail transport agent    *
@@ -78,6 +78,7 @@ in config.h unless some value is defined in Local/Makefile. */
 #define LOOKUP_ORACLE
 #define LOOKUP_PASSWD
 #define LOOKUP_PGSQL
+#define LOOKUP_SQLITE
 #define LOOKUP_TESTDB
 #define LOOKUP_WHOSON
 #define LOOKUP_WILDLSEARCH
index e9084b2..ec7f527 100644 (file)
@@ -1,4 +1,4 @@
-/* $Cambridge: exim/src/src/drtables.c,v 1.4 2005/05/25 20:07:55 tom Exp $ */
+/* $Cambridge: exim/src/src/drtables.c,v 1.5 2005/08/01 13:20:28 ph10 Exp $ */
 
 /*************************************************
 *     Exim - an Internet mail transport agent    *
@@ -93,6 +93,10 @@ be NULL for methods that don't need them. */
 #include "lookups/spf.h"
 #endif
 
+#ifdef LOOKUP_SQLITE
+#include "lookups/sqlite.h"
+#endif
+
 #ifdef LOOKUP_TESTDB
 #include "lookups/testdb.h"
 #endif
@@ -458,6 +462,23 @@ Shares many functions with lsearch. */
 #endif
   },
 
+/* sqlite lookup */
+
+  {
+  US"sqlite",                    /* lookup name */
+  lookup_absfilequery,           /* query-style lookup, starts with file name */
+#ifdef LOOKUP_SQLITE
+  sqlite_open,                   /* open function */
+  NULL,                          /* no check function */
+  sqlite_find,                   /* find function */
+  sqlite_close,                  /* close function */
+  NULL,                          /* no tidy function */
+  sqlite_quote                   /* quoting function */
+#else
+  NULL, NULL, NULL, NULL, NULL, NULL /* lookup not present */
+#endif
+  },
+
 /* Testdb lookup is for testing Exim, not useful for normal running.
 For that reason, we omit the entry entirely when not building it into
 the binary, so that attempts to use it give "unknown lookup type" instead
index 5cc0cb4..98b0151 100644 (file)
@@ -1,4 +1,4 @@
-/* $Cambridge: exim/src/src/exim.c,v 1.22 2005/06/28 10:23:35 ph10 Exp $ */
+/* $Cambridge: exim/src/src/exim.c,v 1.23 2005/08/01 13:20:28 ph10 Exp $ */
 
 /*************************************************
 *     Exim - an Internet mail transport agent    *
@@ -918,6 +918,9 @@ fprintf(f, "Lookups:");
 #ifdef LOOKUP_PGSQL
   fprintf(f, " pgsql");
 #endif
+#ifdef LOOKUP_SQLITE
+  fprintf(f, " sqlite");
+#endif
 #ifdef LOOKUP_TESTDB
   fprintf(f, " testdb");
 #endif
index 632b1d9..e4e0d21 100644 (file)
@@ -1,4 +1,4 @@
-/* $Cambridge: exim/src/src/expand.c,v 1.36 2005/06/27 14:29:43 ph10 Exp $ */
+/* $Cambridge: exim/src/src/expand.c,v 1.37 2005/08/01 13:20:28 ph10 Exp $ */
 
 /*************************************************
 *     Exim - an Internet mail transport agent    *
@@ -3125,7 +3125,7 @@ while (*s != 0)
       /* 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))
+      if (!mac_islookup(stype, lookup_querystyle|lookup_absfilequery))
         {
         if (key == NULL)
           {
@@ -3145,7 +3145,9 @@ while (*s != 0)
         }
 
       /* Get the next string in brackets and expand it. It is the file name for
-      single-key+file lookups, and the whole query otherwise. */
+      single-key+file lookups, and the whole query otherwise. In the case of
+      queries that also require a file name (e.g. sqlite), the file name comes
+      first. */
 
       if (*s != '{') goto EXPAND_FAILED_CURLY;
       filename = expand_string_internal(s+1, TRUE, &s, skipping);
@@ -3154,12 +3156,30 @@ while (*s != 0)
       while (isspace(*s)) s++;
 
       /* If this isn't a single-key+file lookup, re-arrange the variables
-      to be appropriate for the search_ functions. */
+      to be appropriate for the search_ functions. For query-style lookups,
+      there is just a "key", and no file name. For the special query-style +
+      file types, the query (i.e. "key") starts with a file name. */
 
       if (key == NULL)
         {
+        while (isspace(*filename)) filename++;
         key = filename;
-        filename = NULL;
+
+        if (mac_islookup(stype, lookup_querystyle))
+          {
+          filename = NULL;
+          }
+        else
+          {
+          if (*filename != '/')
+            {
+            expand_string_message = string_sprintf(
+              "absolute file name expected for \"%s\" lookup", name);
+            goto EXPAND_FAILED;
+            }
+          while (*key != 0 && !isspace(*key)) key++;
+          if (*key != 0) *key++ = 0;
+          }
         }
 
       /* If skipping, don't do the next bit - just lookup_value == NULL, as if
index 40301e0..709ab14 100644 (file)
@@ -1,4 +1,4 @@
-# $Cambridge: exim/src/src/lookups/Makefile,v 1.3 2005/05/25 20:07:55 tom Exp $
+# $Cambridge: exim/src/src/lookups/Makefile,v 1.4 2005/08/01 13:20:28 ph10 Exp $
 
 # Make file for building a library containing all the available lookups and
 # calling it lookups.a. This is called from the main make file, after cd'ing
@@ -6,8 +6,8 @@
 # defined, dummy modules get compiled.
 
 OBJ = cdb.o dbmdb.o dnsdb.o dsearch.o ibase.o ldap.o lsearch.o mysql.o nis.o \
-      nisplus.o oracle.o passwd.o pgsql.o spf.o testdb.o whoson.o lf_check_file.o \
-      lf_quote.o
+      nisplus.o oracle.o passwd.o pgsql.o spf.o sqlite.o testdb.o whoson.o \
+      lf_check_file.o lf_quote.o
 
 lookups.a:       $(OBJ)
                 @/bin/rm -f lookups.a
@@ -37,6 +37,7 @@ oracle.o:        $(HDRS) oracle.c    oracle.h
 passwd.o:        $(HDRS) passwd.c    passwd.h
 pgsql.o:         $(HDRS) pgsql.c     pgsql.h
 spf.o:           $(HDRS) spf.c       spf.h
+sqlite.o:        $(HDRS) sqlite.c    sqlite.h
 testdb.o:        $(HDRS) testdb.c    testdb.h
 whoson.o:        $(HDRS) whoson.c    whoson.h
 
index 7a16b83..cdaf308 100644 (file)
@@ -1,4 +1,4 @@
-$Cambridge: exim/src/src/lookups/README,v 1.1 2004/10/07 13:10:01 ph10 Exp $
+$Cambridge: exim/src/src/lookups/README,v 1.2 2005/08/01 13:20:28 ph10 Exp $
 
 LOOKUPS
 -------
@@ -26,11 +26,16 @@ key" style, where the key is associated with a "file name".
 For single key lookups, this means that the file name must be an absolute path.
 It is set for lsearch and dbm, but not for NIS, for example.
 
-When a single-key lookup file is opened, the handle returned by the xxx_open()
-function is saved, along with the file name and lookup type, in a tree. The
-xxx_close() function is not called when the first lookup is completed. If there
-are subsequent lookups of the same type that quote the same file name,
-xxx_open() isn't called; instead the cached handle is re-used.
+  lookup_absfilequery
+
+This is a query-style lookup that must start with an absolute file name. For
+example, the sqlite lookup is of this type.
+
+When a single-key or absfilequery lookup file is opened, the handle returned by
+the xxx_open() function is saved, along with the file name and lookup type, in
+a tree. The xxx_close() function is not called when the first lookup is
+completed. If there are subsequent lookups of the same type that quote the same
+file name, xxx_open() isn't called; instead the cached handle is re-used.
 
 Exim calls the function search_tidyup() at strategic points in its processing
 (e.g. after all routing and directing has been done) and this function walks
diff --git a/src/src/lookups/sqlite.c b/src/src/lookups/sqlite.c
new file mode 100644 (file)
index 0000000..af4c0ea
--- /dev/null
@@ -0,0 +1,163 @@
+/* $Cambridge: exim/src/src/lookups/sqlite.c,v 1.1 2005/08/01 13:20:28 ph10 Exp $ */
+
+/*************************************************
+*     Exim - an Internet mail transport agent    *
+*************************************************/
+
+/* Copyright (c) University of Cambridge 1995 - 2005 */
+/* See the file NOTICE for conditions of use and distribution. */
+
+#include "../exim.h"
+#include "lf_functions.h"
+#include "sqlite.h"
+
+#ifndef LOOKUP_SQLITE
+static void dummy(int x) { dummy(x-1); }
+#else
+#include <sqlite3.h>
+
+
+/*************************************************
+*              Open entry point                  *
+*************************************************/
+
+/* See local README for interface description. */
+
+void *
+sqlite_open(uschar *filename, uschar **errmsg)
+{
+sqlite3 *db = NULL;
+int ret;
+
+ret = sqlite3_open((char *)filename, &db);
+if (ret != 0)
+  {
+  *errmsg = (void *)sqlite3_errmsg(db);
+  debug_printf("Error opening database: %s\n", *errmsg);
+  }
+
+return db;
+}
+
+
+/*************************************************
+*               Find entry point                 *
+*************************************************/
+
+/* See local README for interface description. */
+
+struct strbuf {
+  uschar *string;
+  int size;
+  int len;
+};
+
+static int sqlite_callback(void *arg, int argc, char **argv, char **azColName)
+{
+struct strbuf *res = arg;
+int i;
+
+/* For second and subsequent results, insert \n */
+
+if (res->string != NULL)
+  res->string = string_cat(res->string, &res->size, &res->len, US"\n", 1);
+
+if (argc > 1)
+  {
+  /* For multiple fields, include the field name too */
+  for (i = 0; i < argc; i++)
+    {
+    uschar *value = US((argv[i] != NULL)? argv[i]:"<NULL>");
+    res->string = lf_quote(US azColName[i], value, Ustrlen(value), res->string,
+      &res->size, &res->len);
+    }
+  }
+
+else
+  {
+  res->string = string_append(res->string, &res->size, &res->len, 1,
+    (argv[0] != NULL)? argv[0]:"<NULL>");
+  }
+
+res->string[res->len] = 0;
+return 0;
+}
+
+
+int
+sqlite_find(void *handle, uschar *filename, uschar *query, int length,
+  uschar **result, uschar **errmsg, BOOL *do_cache)
+{
+int ret;
+struct strbuf res = { NULL, 0, 0 };
+
+ret = sqlite3_exec(handle, (char *)query, sqlite_callback, &res, (char **)errmsg);
+if (ret != SQLITE_OK)
+  {
+  debug_printf("sqlite3_exec failed: %s\n", *errmsg);
+  return FAIL;
+  }
+
+if (res.string == NULL) *do_cache = FALSE;
+
+*result = res.string;
+return OK;
+}
+
+
+
+/*************************************************
+*               Close entry point                *
+*************************************************/
+
+/* See local README for interface description. */
+
+void sqlite_close(void *handle)
+{
+sqlite3_close(handle);
+}
+
+
+
+/*************************************************
+*               Quote entry point                *
+*************************************************/
+
+/* From what I have found so far, the only character that needs to be quoted
+for sqlite is the single quote, and it is quoted by doubling.
+
+Arguments:
+  s          the string to be quoted
+  opt        additional option text or NULL if none
+
+Returns:     the processed string or NULL for a bad option
+*/
+
+uschar *
+sqlite_quote(uschar *s, uschar *opt)
+{
+register int c;
+int count = 0;
+uschar *t = s;
+uschar *quoted;
+
+if (opt != NULL) return NULL;     /* No options recognized */
+
+while ((c = *t++) != 0) if (c == '\'') count++;
+
+if (count == 0) return s;
+t = quoted = store_get(Ustrlen(s) + count + 1);
+
+while ((c = *s++) != 0)
+  {
+  if (c == '\'') *t++ = '\'';
+  *t++ = c;
+  }
+
+*t = 0;
+return quoted;
+}
+
+#endif /* LOOKUP_SQLITE */
+
+/* End of lookups/sqlite.c */
diff --git a/src/src/lookups/sqlite.h b/src/src/lookups/sqlite.h
new file mode 100644 (file)
index 0000000..3615f4f
--- /dev/null
@@ -0,0 +1,18 @@
+/* $Cambridge: exim/src/src/lookups/sqlite.h,v 1.1 2005/08/01 13:20:28 ph10 Exp $ */
+
+/*************************************************
+*     Exim - an Internet mail transport agent    *
+*************************************************/
+
+/* Copyright (c) University of Cambridge 1995 - 2005 */
+/* See the file NOTICE for conditions of use and distribution. */
+
+/* Header for the sqlite lookup */
+
+extern void   *sqlite_open(uschar *, uschar **);
+extern int     sqlite_find(void *, uschar *, uschar *, int, uschar **,
+                 uschar **, BOOL *);
+extern void    sqlite_close(void *);
+extern uschar *sqlite_quote(uschar *, uschar *);
+
+/* End of lookups/sqlite.h */
index d4a09e8..432da93 100644 (file)
@@ -1,4 +1,4 @@
-/* $Cambridge: exim/src/src/macros.h,v 1.17 2005/07/23 20:46:42 tom Exp $ */
+/* $Cambridge: exim/src/src/macros.h,v 1.18 2005/08/01 13:20:28 ph10 Exp $ */
 
 /*************************************************
 *     Exim - an Internet mail transport agent    *
@@ -629,6 +629,7 @@ enum { v_none, v_sender, v_recipient, v_expn };
 
 #define lookup_querystyle      1    /* query-style lookup */
 #define lookup_absfile         2    /* requires absolute file name */
+#define lookup_absfilequery    4    /* query-style starts with file name */
 
 /* Status values for host_item blocks. Require hstatus_unusable and
 hstatus_unusable_expired to be last. */
index a957da3..100e4c0 100644 (file)
@@ -1,4 +1,4 @@
-/* $Cambridge: exim/src/src/match.c,v 1.7 2005/06/27 14:29:43 ph10 Exp $ */
+/* $Cambridge: exim/src/src/match.c,v 1.8 2005/08/01 13:20:28 ph10 Exp $ */
 
 /*************************************************
 *     Exim - an Internet mail transport agent    *
@@ -266,12 +266,20 @@ up user@domain for sender rejection). There's a flag to disable it. */
 
 if (!cb->use_partial) partial = -1;
 
-/* Set the parameters for the two different kinds of lookup. */
+/* Set the parameters for the three different kinds of lookup. */
 
 keyquery = semicolon + 1;
 while (isspace(*keyquery)) keyquery++;
 
-if (!mac_islookup(search_type, lookup_querystyle))
+if (mac_islookup(search_type, lookup_absfilequery))
+  {
+  filename = keyquery;
+  while (*keyquery != 0 && !isspace(*keyquery)) keyquery++;
+  filename = string_copyn(filename, keyquery - filename);
+  while (isspace(*keyquery)) keyquery++;
+  }
+
+else if (!mac_islookup(search_type, lookup_querystyle))
   {
   filename = keyquery;
   keyquery = s;
index c727177..5852aa2 100644 (file)
@@ -1,4 +1,4 @@
-/* $Cambridge: exim/src/src/verify.c,v 1.23 2005/07/23 20:46:42 tom Exp $ */
+/* $Cambridge: exim/src/src/verify.c,v 1.24 2005/08/01 13:20:28 ph10 Exp $ */
 
 /*************************************************
 *     Exim - an Internet mail transport agent    *
@@ -1938,13 +1938,22 @@ if (iplookup)
   if (search_type < 0) log_write(0, LOG_MAIN|LOG_PANIC_DIE, "%s",
     search_error_message);
 
-  /* Adjust parameters for the type of lookup. For a query-style
-  lookup, there is no file name, and the "key" is just the query. For
-  a single-key lookup, the key is the current IP address, masked
-  appropriately, and reconverted to text form, with the mask appended.
-  For IPv6 addresses, specify dot separators instead of colons. */
+  /* Adjust parameters for the type of lookup. For a query-style lookup, there
+  is no file name, and the "key" is just the query. For query-style with a file
+  name, we have to fish the file off the start of the query. For a single-key
+  lookup, the key is the current IP address, masked appropriately, and
+  reconverted to text form, with the mask appended. For IPv6 addresses, specify
+  dot separators instead of colons. */
 
-  if (mac_islookup(search_type, lookup_querystyle))
+  if (mac_islookup(search_type, lookup_absfilequery))
+    {
+    filename = semicolon + 1;
+    key = filename;
+    while (*key != 0 && !isspace(*key)) key++;
+    filename = string_copyn(filename, key - filename);
+    while (isspace(*key)) key++;
+    }
+  else if (mac_islookup(search_type, lookup_querystyle))
     {
     filename = NULL;
     key = semicolon + 1;
@@ -2047,7 +2056,7 @@ if ((semicolon = Ustrchr(ss, ';')) != NULL)
       search_error_message, ss);
     return DEFER;
     }
-  isquery = mac_islookup(id, lookup_querystyle);
+  isquery = mac_islookup(id, lookup_querystyle|lookup_absfilequery);
   }
 
 if (isquery)