--- config.h.in.orig	Thu Mar 11 00:56:25 2004
+++ config.h.in	Sat May 29 01:20:07 2004
@@ -189,6 +189,9 @@
 /* Do we have a socklen_t? */
 #undef HAVE_SOCKLEN_T
 
+/* Do we have SQLite support? */
+#undef HAVE_SQLITE
+
 /* Is there an ss_family in sockaddr_storage? */
 #undef HAVE_SS_FAMILY
 
--- plugins/Makefile.in.orig	Thu Mar 11 00:56:12 2004
+++ plugins/Makefile.in	Fri May 28 03:07:52 2004
@@ -131,6 +131,7 @@
 
 LIB_MYSQL = @LIB_MYSQL@
 LIB_PGSQL = @LIB_PGSQL@
+LIB_SQLITE = @LIB_SQLITE@
 LIB_SOCKET = @LIB_SOCKET@
 LN_S = @LN_S@
 LTGETADDRINFOOBJS = @LTGETADDRINFOOBJS@
@@ -317,7 +318,7 @@
 libsasldb_la_LIBADD = ../sasldb/libsasldb.la $(SASL_DB_LIB) $(COMPAT_OBJS)
 
 libsql_la_SOURCES = sql.c sql_init.c $(common_sources)
-libsql_la_LDFLAGS = $(LIB_MYSQL) $(LIB_PGSQL) -version-info $(sql_version)
+libsql_la_LDFLAGS = $(LIB_MYSQL) $(LIB_PGSQL) $(LIB_SQLITE) -version-info $(sql_version)
 libsql_la_DEPENDENCIES = $(COMPAT_OBJS)
 libsql_la_LIBADD = $(COMPAT_OBJS)
 
--- plugins/sql.c.orig	Fri Jan  9 00:30:26 2004
+++ plugins/sql.c	Sat May 29 01:44:57 2004
@@ -332,6 +332,129 @@
 }
 #endif /* HAVE_PGSQL */
 
+#ifdef HAVE_SQLITE
+#include <sqlite.h>
+
+static void *_sqlite_open(char *host, char *port, int usessl,
+			  const char *user, const char *password,
+			  const char *database, const sasl_utils_t *utils)
+{
+    int rc;
+    sqlite *db;
+    char *zErrMsg = NULL;
+
+    db = sqlite_open(database, 0, &zErrMsg);
+    if (db == NULL) {
+	utils->log(NULL, SASL_LOG_ERR, "sql plugin: %s", zErrMsg);
+	sqlite_freemem(zErrMsg);
+	return NULL;
+    }
+
+    rc = sqlite_exec(db, "PRAGMA empty_result_callbacks = ON", NULL, NULL, &zErrMsg);
+    if (rc != SQLITE_OK) {
+	utils->log(NULL, SASL_LOG_ERR, "sql plugin: %s", zErrMsg);
+	sqlite_freemem(zErrMsg);
+	sqlite_close(db);
+	return NULL;
+    }
+
+    return (void*)db;
+}
+
+static int _sqlite_escape_str(char *to, const char *from)
+{
+    char s;
+
+    while ( (s = *from++) != '\0' ) {
+	if (s == '\'' || s == '\\') {
+	    *to++ = '\\';
+	}
+	*to++ = s;
+    }
+    *to = '\0';
+
+    return 0;
+}
+
+static int sqlite_my_callback(void *pArg, int argc, char **argv,
+			      char **columnNames)
+{
+    char **result = (char**)pArg;
+
+    if (argv == NULL) {
+	*result = NULL;				/* no record */
+    } else if (argv[0] == NULL) {
+	*result = strdup(SQL_NULL_VALUE);	/* NULL IS SQL_NULL_VALUE */
+    } else {
+	*result = strdup(argv[0]);
+    }
+
+    return /*ABORT*/1;
+}
+
+static int _sqlite_exec(void *db, const char *cmd, char *value, size_t size,
+		        size_t *value_len, const sasl_utils_t *utils)
+{
+    int rc;
+    char *result = NULL;
+    char *zErrMsg = NULL;
+
+    rc = sqlite_exec((sqlite*)db, cmd, sqlite_my_callback, (void*)&result, &zErrMsg);
+    if (rc != SQLITE_OK && rc != SQLITE_ABORT) {
+	utils->log(NULL, SASL_LOG_DEBUG, "sql plugin: %s ", zErrMsg);
+	sqlite_freemem(zErrMsg);
+	return -1;
+    }
+
+    if (rc == SQLITE_OK) {
+	/* no results (BEGIN, COMMIT, DELETE, INSERT, UPDATE) */
+	return 0;
+    }
+
+    if (result == NULL) {
+	/* umm nothing found */
+	utils->log(NULL, SASL_LOG_NOTE, "sql plugin: no result found");
+	return -1;
+    }
+
+    /* XXX: Duplication cannot be found by this method. */
+
+    /* now get the result set value and value_len */
+    /* we only fetch one because we don't care about the rest */
+    if (value) {
+	strncpy(value, result, size - 2);
+	value[size - 1] = '\0';
+	if (value_len) {
+	    *value_len = strlen(value);
+	}
+    }
+
+    /* free result */
+    free(result);
+    return 0;
+}
+
+static int _sqlite_begin_txn(void *db, const sasl_utils_t *utils)
+{
+    return _sqlite_exec(db, "BEGIN TRANSACTION", NULL, 0, NULL, utils);
+}
+
+static int _sqlite_commit_txn(void *db, const sasl_utils_t *utils)
+{
+    return _sqlite_exec(db, "COMMIT TRANSACTION", NULL, 0, NULL, utils);
+}
+
+static int _sqlite_rollback_txn(void *db, const sasl_utils_t *utils)
+{
+    return _sqlite_exec(db, "ROLLBACK TRANSACTION", NULL, 0, NULL, utils);
+}
+
+static void _sqlite_close(void *db)
+{
+    sqlite_close((sqlite*)db);
+}
+#endif /* HAVE_SQLITE */
+
 static const sql_engine_t sql_engines[] = {
 #ifdef HAVE_MYSQL
     { "mysql", &_mysql_open, &_mysql_escape_str,
@@ -342,6 +465,11 @@
     { "pgsql", &_pgsql_open, &_pgsql_escape_str,
       &_pgsql_begin_txn, &_pgsql_commit_txn, &_pgsql_rollback_txn,
       &_pgsql_exec, &_pgsql_close },
+#endif
+#ifdef HAVE_SQLITE
+    { "sqlite", &_sqlite_open, &_sqlite_escape_str,
+      &_sqlite_begin_txn, &_sqlite_commit_txn, &_sqlite_rollback_txn,
+      &_sqlite_exec, &_sqlite_close },
 #endif
     { NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL }
 };
--- utils/Makefile.in.orig	Thu Mar 11 00:56:12 2004
+++ utils/Makefile.in	Fri May 28 03:12:47 2004
@@ -128,6 +128,7 @@
 LIB_DES = @LIB_DES@
 LIB_MYSQL = @LIB_MYSQL@
 LIB_PGSQL = @LIB_PGSQL@
+LIB_SQLITE = @LIB_SQLITE@
 LIB_SOCKET = @LIB_SOCKET@
 LN_S = @LN_S@
 LTGETADDRINFOOBJS = @LTGETADDRINFOOBJS@
@@ -225,7 +226,7 @@
 target_vendor = @target_vendor@
 
 all_sasl_libs = ../lib/libsasl2.la $(SASL_DB_LIB) $(LIB_SOCKET)
-all_sasl_static_libs = ../lib/.libs/libsasl2.a $(SASL_DB_LIB) $(LIB_SOCKET) $(GSSAPIBASE_LIBS) $(GSSAPI_LIBS) $(SASL_KRB_LIB) $(LIB_DES) $(PLAIN_LIBS) $(SRP_LIBS) $(LIB_MYSQL) $(LIB_PGSQL)
+all_sasl_static_libs = ../lib/.libs/libsasl2.a $(SASL_DB_LIB) $(LIB_SOCKET) $(GSSAPIBASE_LIBS) $(GSSAPI_LIBS) $(SASL_KRB_LIB) $(LIB_DES) $(PLAIN_LIBS) $(SRP_LIBS) $(LIB_MYSQL) $(LIB_PGSQL) $(LIB_SQLITE)
 
 sbin_PROGRAMS = @SASL_DB_UTILS@ @SMTPTEST_PROGRAM@
 EXTRA_PROGRAMS = saslpasswd2 sasldblistusers2 testsuite testsuitestatic smtptest
--- doc/options.html.orig	Thu Jan  8 01:35:07 2004
+++ doc/options.html	Sat May 29 02:31:07 2004
@@ -104,7 +104,7 @@
 <TD>Path to sasldb file</TD><TD><tt>/etc/sasldb2</tt> (system dependant)</TD>
 <TR>
 <TD>sql_engine</TD><TD>SQL plugin</TD>
-<TD>Name of SQL engine to use (possible values: 'mysql', 'pgsql').</TD>
+<TD>Name of SQL engine to use (possible values: 'mysql', 'pgsql', 'sqlite').</TD>
 <TD><tt>mysql</tt></TD>
 </TR>
 <TR>
