-$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
-------------------------------------------
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
-----------------
-$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
--------------------
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
-----------------
-$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
Philip Hazel
Lists created: 20 November 2002
-Last updated: 28 June 2005
+Last updated: 29 July 2005
THE OLD LIST
PostgreSQL functionality
Patch for hosts_avoid_esmtp
Stephen Wilcox Patch for ignore_enotdir problem
+David Woodhouse SQLite support proof of concept code
****
#!/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.
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
-# $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 #
# 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
-/* $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 *
#define LOOKUP_ORACLE
#define LOOKUP_PASSWD
#define LOOKUP_PGSQL
+#define LOOKUP_SQLITE
#define LOOKUP_TESTDB
#define LOOKUP_WHOSON
#define LOOKUP_WILDLSEARCH
-/* $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 *
#include "lookups/spf.h"
#endif
+#ifdef LOOKUP_SQLITE
+#include "lookups/sqlite.h"
+#endif
+
#ifdef LOOKUP_TESTDB
#include "lookups/testdb.h"
#endif
#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
-/* $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 *
#ifdef LOOKUP_PGSQL
fprintf(f, " pgsql");
#endif
+#ifdef LOOKUP_SQLITE
+ fprintf(f, " sqlite");
+#endif
#ifdef LOOKUP_TESTDB
fprintf(f, " testdb");
#endif
-/* $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 *
/* 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)
{
}
/* 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);
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
-# $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
# 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
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
-$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
-------
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
--- /dev/null
+/* $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 */
--- /dev/null
+/* $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 */
-/* $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 *
#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. */
-/* $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 *
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;
-/* $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 *
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;
search_error_message, ss);
return DEFER;
}
- isquery = mac_islookup(id, lookup_querystyle);
+ isquery = mac_islookup(id, lookup_querystyle|lookup_absfilequery);
}
if (isquery)