diff -urN dovecot/configure.in dovecot-jh2/configure.in --- dovecot/configure.in 2006-01-16 21:15:01.000000000 +0100 +++ dovecot-jh2/configure.in 2006-01-19 11:59:34.000000000 +0100 @@ -181,6 +181,15 @@ fi, want_mysql=no) +AC_ARG_WITH(sqlite, +[ --with-sqlite Build with SQLite3 support], + if test x$withval = xno; then + want_sqlite=no + else + want_sqlite=yes + fi, + want_sqlite=no) + AC_ARG_WITH(ssl, [ --with-ssl=[gnutls|openssl] Build with GNUTLS or OpenSSL (default)], if test x$withval = xno; then @@ -1435,6 +1444,57 @@ LIBS=$old_LIBS fi +if test $want_sqlite = yes; then + # stolen from the mysql code above + for i in /usr /usr/local /usr/local; do + for j in include ""; do + if test -r "$i/$j/sqlite3.h"; then + MYSQL_INCLUDE=$i/$j + fi + done + for j in lib lib/sqlite3 ""; do + if test -f "$i/$j/libsqlite3.so" || test -f "$i/$j/libsqlite3.a"; then + MYSQL_LIBDIR=$i/$j + fi + done + done + + old_LIBS=$LIBS + if test "$SQLITE_LIBDIR" != ""; then + LIBS="$LIBS -L$SQLITE_LIBDIR" + fi + + sqlite_lib="" + LIBS="$LIBS -lz" + AC_CHECK_LIB(sqlite3, sqlite3_open, [ + sqlite_lib="-lsqlite3 -lz" + ]) + + if test "$sqlite_lib" != ""; then + old_CPPFLAGS=$CPPFLAGS + if test "$SQLITE_INCLUDE" != ""; then + CPPFLAGS="$CPPFLAGS -I $SQLITE_INCLUDE" + fi + AC_CHECK_HEADER(sqlite3.h, [ + if test "$SQLITE_INCLUDE" != ""; then + SQL_CFLAGS="$SQL_CFLAGS -I$SQLITE_INCLUDE" + fi + if test "$SQLITE_LIBDIR" != ""; then + SQL_LIBS="$SQL_LIBS -L$SQLITE_LIBDIR" + fi + SQL_LIBS="$SQL_LIBS $sqlite_lib" + + AC_DEFINE(HAVE_SQLITE,, Build with SQLite3 support) + have_sql=yes + userdb="$userdb sqlite" + passdb="$passdb sqlite" + ]) + CPPFLAGS=$old_CPPFLAGS + fi + + LIBS=$old_LIBS +fi + if test "$have_sql" = yes; then AC_DEFINE(PASSDB_SQL,, Build with SQL support) AC_DEFINE(USERDB_SQL,, Build with SQL support) diff -urN dovecot/doc/dovecot-sql.conf dovecot-jh2/doc/dovecot-sql.conf --- dovecot/doc/dovecot-sql.conf 2005-12-10 21:36:18.000000000 +0100 +++ dovecot-jh2/doc/dovecot-sql.conf 2006-01-19 11:59:52.000000000 +0100 @@ -20,7 +20,7 @@ # active CHAR(1) DEFAULT 'Y' NOT NULL # ); -# Database driver: mysql, pgsql +# Database driver: mysql, pgsql, sqlite #driver = # Database connection string. This is driver-specific setting. @@ -42,9 +42,13 @@ # You can connect to UNIX sockets by using host: host=/var/run/mysql.sock # Note that currently you can't use spaces in parameters. # +# sqlite: +# The path to the database file. +# # Examples: # connect = host=192.168.1.1 dbname=users # connect = host=sql.example.com dbname=virtual user=virtual password=blarg +# connect = /etc/dovecot/authdb.sqlite # #connect = dbname=virtual user=virtual diff -urN dovecot/src/lib-sql/driver-sqlite.c dovecot-jh2/src/lib-sql/driver-sqlite.c --- dovecot/src/lib-sql/driver-sqlite.c 1970-01-01 01:00:00.000000000 +0100 +++ dovecot-jh2/src/lib-sql/driver-sqlite.c 2006-01-19 11:59:34.000000000 +0100 @@ -0,0 +1,373 @@ +/* Copyright (C) 2003-2004 Timo Sirainen, Alex Howansky */ + +#include "lib.h" +#include "str.h" +#include "sql-api-private.h" + +#ifdef HAVE_SQLITE +#include +#include +#include + +/* retry time if db is busy (in ms) */ +const int sqlite_busy_timeout = 1000; + +struct sqlite_db { + struct sql_db api; + + pool_t pool; + const char *dbfile; + sqlite3 *sqlite; + unsigned int connected:1; + int rc; +}; + +struct sqlite_result { + struct sql_result api; + sqlite3_stmt *stmt; + unsigned int cols; + const char **row; +}; + +struct sqlite_transaction_context { + struct sql_transaction_context ctx; + unsigned int failed:1; +}; + +extern struct sql_result driver_sqlite_result; +extern struct sql_result driver_sqlite_error_result; + +static int driver_sqlite_connect(struct sql_db *_db) +{ + struct sqlite_db *db = (struct sqlite_db *)_db; + + if (db->connected) + return 1; + + db->rc = sqlite3_open(db->dbfile, &db->sqlite); + + if (db->rc == SQLITE_OK) { + db->connected = TRUE; + sqlite3_busy_timeout(db->sqlite, sqlite_busy_timeout); + return 1; + } else { + i_error("sqlite open %s: %s", db->dbfile, sqlite3_errmsg(db->sqlite)); + sqlite3_close(db->sqlite); + return -1; + } +} + +static struct sql_db *driver_sqlite_init(const char *connect_string) +{ + struct sqlite_db *db; + pool_t pool; + + i_assert(connect_string != NULL); + + pool = pool_alloconly_create("sqlite driver", 512); + db = p_new(pool, struct sqlite_db, 1); + db->pool = pool; + db->api = driver_sqlite_db; + db->dbfile = p_strdup(db->pool, connect_string); + db->connected = FALSE; + + return &db->api; +} + +static void driver_sqlite_deinit(struct sql_db *_db) +{ + struct sqlite_db *db = (struct sqlite_db *)_db; + + sqlite3_close(db->sqlite); + pool_unref(db->pool); +} + +static enum sql_db_flags +driver_sqlite_get_flags(struct sql_db *db __attr_unused__) +{ + return SQL_DB_FLAG_BLOCKING; +} + +static void driver_sqlite_exec(struct sql_db *_db, const char *query) +{ + struct sqlite_db *db = (struct sqlite_db *)_db; + + db->rc = sqlite3_exec(db->sqlite, query, NULL, 0, NULL); + if (db->rc != SQLITE_OK) + i_warning("sqlite_exec(%s) = %d (%s)", + query, db->rc, sqlite3_errmsg(db->sqlite)); +} + +static void driver_sqlite_query(struct sql_db *db, const char *query, + sql_query_callback_t *callback, void *context) +{ + struct sql_result *result; + + result = sql_query_s(db, query); + result->callback = TRUE; + callback(result, context); + sql_result_free(result); +} + +static struct sql_result * +driver_sqlite_query_s(struct sql_db *_db, const char *query) +{ + struct sqlite_db *db = (struct sqlite_db *)_db; + struct sqlite_result *result; + int rc; + const char *pzTail; + + result = i_new(struct sqlite_result, 1); + + rc = sqlite3_prepare(db->sqlite, query, -1, &result->stmt, &pzTail); + + if (rc == SQLITE_OK) { + result->api = driver_sqlite_result; + result->cols = sqlite3_column_count(result->stmt); + result->row = i_new(const char *, result->cols); + } else { + result->api = driver_sqlite_error_result; + result->stmt = NULL; + result->cols = 0; + } + result->api.db = _db; + + return &result->api; +} + +static void driver_sqlite_result_free(struct sql_result *_result) +{ + struct sqlite_result *result = (struct sqlite_result *)_result; + struct sqlite_db *db = (struct sqlite_db *) result->api.db; + int rc; + + if (result->stmt != NULL) + { + if ((rc = sqlite3_finalize(result->stmt)) != SQLITE_OK) + i_warning("sqlite3_finalize: %d (%s)", rc, sqlite3_errmsg(db->sqlite)); + i_free(result->row); + } + i_free(result); +} + +static int driver_sqlite_result_next_row(struct sql_result *_result) +{ + struct sqlite_result *result = (struct sqlite_result *)_result; + + switch (sqlite3_step(result->stmt)) { + case SQLITE_ROW: + return 1; + case SQLITE_DONE: + return 0; + default: + return -1; + } +} + +static unsigned int +driver_sqlite_result_get_fields_count(struct sql_result *_result) +{ + struct sqlite_result *result = (struct sqlite_result *)_result; + return result->cols; +} + +static const char * +driver_sqlite_result_get_field_name(struct sql_result *_result, unsigned int idx) +{ + struct sqlite_result *result = (struct sqlite_result *)_result; + + return sqlite3_column_name(result->stmt, idx); +} + +static int driver_sqlite_result_find_field(struct sql_result *_result, + const char *field_name) +{ + struct sqlite_result *result = (struct sqlite_result *)_result; + unsigned int i; + + for (i = 0; i < result->cols; ++i) { + if (strcmp(sqlite3_column_name(result->stmt, i), field_name) == 0) + return i; + } + + return -1; +} + +static const char * +driver_sqlite_result_get_field_value(struct sql_result *_result, + unsigned int idx) +{ + struct sqlite_result *result = (struct sqlite_result *)_result; + + return sqlite3_column_text(result->stmt, idx); +} + +static const char * +driver_sqlite_result_find_field_value(struct sql_result *result, + const char *field_name) +{ + int idx; + + idx = driver_sqlite_result_find_field(result, field_name); + if (idx < 0) + return NULL; + return driver_sqlite_result_get_field_value(result, idx); +} + +static const char *const * +driver_sqlite_result_get_values(struct sql_result *_result) +{ + struct sqlite_result *result = (struct sqlite_result *)_result; + unsigned int i; + + for (i = 0; i < result->cols; ++i) + result->row[i] = driver_sqlite_result_get_field_value(_result, i); + + return (const char *const *)result->row; +} + +static const char *driver_sqlite_result_get_error(struct sql_result *_result) +{ + struct sqlite_result *result = (struct sqlite_result *)_result; + struct sqlite_db *db = (struct sqlite_db *) result->api.db; + + return sqlite3_errmsg(db->sqlite); +} + +static struct sql_transaction_context * +driver_sqlite_transaction_begin(struct sql_db *_db) +{ + struct sqlite_transaction_context *ctx; + struct sqlite_db *db = (struct sqlite_db *)_db; + + ctx = i_new(struct sqlite_transaction_context, 1); + ctx->ctx.db = _db; + + sql_exec(_db, "BEGIN TRANSACTION"); + if (db->rc != SQLITE_OK) + ctx->failed = TRUE; + + return &ctx->ctx; +} + +static void +driver_sqlite_transaction_rollback(struct sql_transaction_context *_ctx) +{ + struct sqlite_transaction_context *ctx = + (struct sqlite_transaction_context *)_ctx; + + sql_exec(_ctx->db, "ROLLBACK"); + i_free(ctx); +} + +static void +driver_sqlite_transaction_commit(struct sql_transaction_context *_ctx, + sql_commit_callback_t *callback, void *context) +{ + struct sqlite_transaction_context *ctx = + (struct sqlite_transaction_context *)_ctx; + struct sqlite_db *db = (struct sqlite_db *) ctx->ctx.db; + const char * errmsg; + + if (! ctx->failed) { + sql_exec(_ctx->db, "COMMIT"); + if (db->rc != SQLITE_OK) + ctx->failed = TRUE; + } + + if (ctx->failed) { + errmsg = sqlite3_errmsg(db->sqlite); + callback(errmsg, context); + driver_sqlite_transaction_rollback(_ctx); /* also does i_free(ctx) */ + } else { + callback(NULL, context); + i_free(ctx); + } +} + +static int +driver_sqlite_transaction_commit_s(struct sql_transaction_context *_ctx, + const char **error_r) +{ + struct sqlite_transaction_context *ctx = + (struct sqlite_transaction_context *)_ctx; + struct sqlite_db *db = (struct sqlite_db *) ctx->ctx.db; + + if (ctx->failed) { + driver_sqlite_transaction_rollback(_ctx); /* also does i_free(ctx) */ + return -1; + } + + sql_exec(_ctx->db, "COMMIT"); + *error_r = sqlite3_errmsg(db->sqlite); + i_free(ctx); + return 0; +} + +static void +driver_sqlite_update(struct sql_transaction_context *_ctx, const char *query) +{ + struct sqlite_transaction_context *ctx = + (struct sqlite_transaction_context *)_ctx; + struct sqlite_db *db = (struct sqlite_db *) ctx->ctx.db; + + if (ctx->failed) + return; + + sql_exec(_ctx->db, query); + if (db->rc != SQLITE_OK) + ctx->failed = TRUE; +} + +struct sql_db driver_sqlite_db = { + "sqlite", + + driver_sqlite_init, + driver_sqlite_deinit, + driver_sqlite_get_flags, + driver_sqlite_connect, + driver_sqlite_exec, + driver_sqlite_query, + driver_sqlite_query_s, + + driver_sqlite_transaction_begin, + driver_sqlite_transaction_commit, + driver_sqlite_transaction_commit_s, + driver_sqlite_transaction_rollback, + driver_sqlite_update +}; + +struct sql_result driver_sqlite_result = { + NULL, + + driver_sqlite_result_free, + driver_sqlite_result_next_row, + driver_sqlite_result_get_fields_count, + driver_sqlite_result_get_field_name, + driver_sqlite_result_find_field, + driver_sqlite_result_get_field_value, + driver_sqlite_result_find_field_value, + driver_sqlite_result_get_values, + driver_sqlite_result_get_error, + + FALSE +}; + +static int +driver_sqlite_result_error_next_row(struct sql_result *result __attr_unused__) +{ + return -1; +} + +struct sql_result driver_sqlite_error_result = { + NULL, + + driver_sqlite_result_free, + driver_sqlite_result_error_next_row, + NULL, NULL, NULL, NULL, NULL, NULL, + driver_sqlite_result_get_error, + + FALSE +}; + +#endif diff -urN dovecot/src/lib-sql/Makefile.am dovecot-jh2/src/lib-sql/Makefile.am --- dovecot/src/lib-sql/Makefile.am 2004-10-21 01:05:57.000000000 +0200 +++ dovecot-jh2/src/lib-sql/Makefile.am 2006-01-19 11:59:34.000000000 +0100 @@ -7,6 +7,7 @@ libsql_a_SOURCES = \ driver-mysql.c \ driver-pgsql.c \ + driver-sqlite.c \ sql-api.c noinst_HEADERS = \ diff -urN dovecot/src/lib-sql/sql-api.c dovecot-jh2/src/lib-sql/sql-api.c --- dovecot/src/lib-sql/sql-api.c 2006-01-14 19:47:40.000000000 +0100 +++ dovecot-jh2/src/lib-sql/sql-api.c 2006-01-19 11:59:34.000000000 +0100 @@ -10,6 +10,9 @@ #ifdef HAVE_MYSQL &driver_mysql_db, #endif +#ifdef HAVE_SQLITE + &driver_sqlite_db, +#endif NULL }; diff -urN dovecot/src/lib-sql/sql-api-private.h dovecot-jh2/src/lib-sql/sql-api-private.h --- dovecot/src/lib-sql/sql-api-private.h 2005-12-10 19:57:11.000000000 +0100 +++ dovecot-jh2/src/lib-sql/sql-api-private.h 2006-01-19 11:59:34.000000000 +0100 @@ -56,6 +56,7 @@ extern struct sql_db driver_mysql_db; extern struct sql_db driver_pgsql_db; +extern struct sql_db driver_sqlite_db; extern struct sql_result sql_not_connected_result; diff -urN dovecot/src/master/main.c dovecot-jh2/src/master/main.c --- dovecot/src/master/main.c 2006-01-15 22:52:44.000000000 +0100 +++ dovecot-jh2/src/master/main.c 2006-01-19 11:59:34.000000000 +0100 @@ -639,6 +639,9 @@ #ifdef HAVE_PGSQL " postgresql" #endif +#ifdef HAVE_SQLITE + " sqlite" +#endif "\nPassdb: " #ifdef PASSDB_BSDAUTH "bsdauth "