[evolution-data-server/openismus-work] Local file backend modified to use sqlite db exclusively



commit 8df827d68f8f265dfb3370aab641410a19c09d65
Author: Tristan Van Berkom <tristanvb openismus com>
Date:   Mon Oct 29 15:33:09 2012 +0900

    Local file backend modified to use sqlite db exclusively
    
    Patch includes a migration routine to migrate data from a previously
    installed BDB.

 addressbook/backends/file/Makefile.am              |    2 +
 .../file/e-book-backend-file-migrate-bdb.c         |  528 +++++++
 .../file/e-book-backend-file-migrate-bdb.h         |   43 +
 addressbook/backends/file/e-book-backend-file.c    | 1432 ++++----------------
 4 files changed, 869 insertions(+), 1136 deletions(-)
---
diff --git a/addressbook/backends/file/Makefile.am b/addressbook/backends/file/Makefile.am
index c52c7e3..92ca13d 100644
--- a/addressbook/backends/file/Makefile.am
+++ b/addressbook/backends/file/Makefile.am
@@ -16,6 +16,8 @@ libebookbackendfile_la_CPPFLAGS = \
 libebookbackendfile_la_SOURCES =			\
 	e-book-backend-file.c				\
 	e-book-backend-file.h				\
+	e-book-backend-file-migrate-bdb.c		\
+	e-book-backend-file-migrate-bdb.h		\
 	e-book-backend-file-factory.c
 
 libebookbackendfile_la_LIBADD =						\
diff --git a/addressbook/backends/file/e-book-backend-file-migrate-bdb.c b/addressbook/backends/file/e-book-backend-file-migrate-bdb.c
new file mode 100644
index 0000000..1e971cd
--- /dev/null
+++ b/addressbook/backends/file/e-book-backend-file-migrate-bdb.c
@@ -0,0 +1,528 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+
+/* e-book-backend-file-migrate-bdb.c - Migration of old BDB database to the new sqlite DB.
+ *
+ * Copyright (C) 2012 Openismus GmbH
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of version 2 of the GNU Lesser General Public
+ * License as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this program; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ *
+ * Authors: Tristan Van Berkom <tristanvb openismus com>
+ *
+ * Based on work by Nat Friedman, Chris Toshok and Hans Petter Jansson.
+ */
+
+#include <config.h>
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <time.h>
+#include <errno.h>
+#include "db.h"
+#include <sys/stat.h>
+#include <sys/time.h>
+
+#include <glib/gstdio.h>
+#include <glib/gi18n-lib.h>
+
+#include <libedata-book/libedata-book.h>
+
+#include "e-book-backend-file-migrate-bdb.h"
+
+
+#define E_BOOK_BACKEND_FILE_REVISION_NAME         "PAS-DB-REVISION"
+#define E_BOOK_BACKEND_FILE_VERSION_NAME          "PAS-DB-VERSION"
+#define E_BOOK_BACKEND_FILE_LAST_BDB_VERSION      "0.2"
+
+#define EDB_ERROR(_code)          e_data_book_create_error (E_DATA_BOOK_STATUS_ ## _code, NULL)
+#define EDB_ERROR_EX(_code, _msg) e_data_book_create_error (E_DATA_BOOK_STATUS_ ## _code, _msg)
+
+
+G_LOCK_DEFINE_STATIC (db_env);
+static DB_ENV *db_env = NULL;
+
+#ifdef G_OS_WIN32
+static gboolean db_env_initialized = FALSE;
+#endif
+
+/**************************************************************
+ *             Low level BDB interfacing tools                *
+ **************************************************************/
+
+#ifdef G_OS_WIN32
+/* Avoid compiler warning by providing a function with exactly the
+ * prototype that db_env_set_func_open() wants for the open method.
+ */
+
+static gint
+my_open (const gchar *name,
+         gint oflag,
+         ...)
+{
+	gint mode = 0;
+
+	if (oflag & O_CREAT) {
+		va_list arg;
+		va_start (arg, oflag);
+		mode = va_arg (arg, gint);
+		va_end (arg);
+	}
+
+	return g_open (name, oflag, mode);
+}
+
+gint
+my_rename (const gchar *oldname,
+           const gchar *newname)
+{
+	return g_rename (oldname, newname);
+}
+
+gint
+my_exists (const gchar *name,
+           gint *isdirp)
+{
+	if (!g_file_test (name, G_FILE_TEST_EXISTS))
+		return ENOENT;
+	if (isdirp != NULL)
+		*isdirp = g_file_test (name, G_FILE_TEST_IS_DIR);
+	return 0;
+}
+
+gint
+my_unlink (const gchar *name)
+{
+	return g_unlink (name);
+}
+
+#endif
+
+static void
+#if (DB_VERSION_MAJOR > 4) || (DB_VERSION_MAJOR == 4 && DB_VERSION_MINOR >= 3)
+file_errcall (const DB_ENV *env,
+              const gchar *buf1,
+              const gchar *buf2)
+#else
+file_errcall (const gchar *buf1,
+              gchar *buf2)
+#endif
+{
+	g_warning ("libdb error: %s", buf2);
+}
+
+static void
+db_error_to_gerror (const gint db_error,
+                    GError **perror)
+{
+	if (db_error && perror && *perror)
+		g_clear_error (perror);
+
+	switch (db_error) {
+	case 0:
+		return;
+	case DB_NOTFOUND:
+		g_propagate_error (perror, EDB_ERROR (CONTACT_NOT_FOUND));
+		return;
+	case EACCES:
+		g_propagate_error (perror, EDB_ERROR (PERMISSION_DENIED));
+		return;
+	default:
+		g_propagate_error (perror, e_data_book_create_error_fmt (E_DATA_BOOK_STATUS_OTHER_ERROR, "db error 0x%x (%s)", db_error, db_strerror (db_error) ? db_strerror (db_error) : _("Unknown error")));
+		return;
+	}
+}
+
+static void
+string_to_dbt (const gchar *str,
+               DBT *dbt)
+{
+	memset (dbt, 0, sizeof (*dbt));
+	dbt->data = (gpointer) str;
+	dbt->size = strlen (str) + 1;
+	dbt->flags = DB_DBT_USERMEM;
+}
+
+/**************************************************************
+ *       Include the previous migration routines first        *
+ **************************************************************/
+/*
+** versions:
+**
+** 0.0 just a list of cards
+**
+** 0.1 same as 0.0, but with the version tag
+**
+** 0.2 not a real format upgrade, just a hack to fix broken ids caused
+**     by a bug in early betas, but we only need to convert them if
+**     the previous version is 0.1, since the bug existed after 0.1
+**     came about.
+*/
+static gboolean
+e_book_backend_file_upgrade_db (DB    *db,
+                                gchar *old_version)
+{
+	gint db_error;
+	DBT  version_name_dbt, version_dbt;
+
+	if (!db) {
+		g_warning (G_STRLOC ": No DB opened");
+		return FALSE;
+	}
+
+	if (strcmp (old_version, "0.0")
+	    && strcmp (old_version, "0.1")) {
+		g_warning ("unsupported version '%s' found in PAS backend file\n",
+			   old_version);
+		return FALSE;
+	}
+
+	if (!strcmp (old_version, "0.1")) {
+		/* we just loop through all the cards in the db,
+		 * giving them valid ids if they don't have them */
+		DBT  id_dbt, vcard_dbt;
+		DBC *dbc;
+		gint  card_failed = 0;
+
+		db_error = db->cursor (db, NULL, &dbc, 0);
+		if (db_error != 0) {
+			g_warning (G_STRLOC ": db->cursor failed with %s", db_strerror (db_error));
+			return FALSE;
+		}
+
+		memset (&id_dbt, 0, sizeof (id_dbt));
+		memset (&vcard_dbt, 0, sizeof (vcard_dbt));
+
+		db_error = dbc->c_get (dbc, &id_dbt, &vcard_dbt, DB_FIRST);
+
+		while (db_error == 0) {
+			if ((id_dbt.size != strlen (E_BOOK_BACKEND_FILE_VERSION_NAME) + 1
+			     || strcmp (id_dbt.data, E_BOOK_BACKEND_FILE_VERSION_NAME)) &&
+			    (id_dbt.size != strlen (E_BOOK_BACKEND_FILE_REVISION_NAME) + 1
+			     || strcmp (id_dbt.data, E_BOOK_BACKEND_FILE_REVISION_NAME))) {
+				EContact *contact;
+
+				contact = e_contact_new_from_vcard_with_uid (vcard_dbt.data, id_dbt.data);
+
+				/* the cards we're looking for are
+				 * created with a normal id dbt, but
+				 * with the id field in the vcard set
+				 * to something that doesn't match.
+				 * so, we need to modify the card to
+				 * have the same id as the the dbt. */
+				if (strcmp (id_dbt.data, e_contact_get_const (contact, E_CONTACT_UID))) {
+					gchar *vcard;
+
+					e_contact_set (contact, E_CONTACT_UID, id_dbt.data);
+
+					vcard = e_vcard_to_string (E_VCARD (contact), EVC_FORMAT_VCARD_30);
+					string_to_dbt (vcard, &vcard_dbt);
+
+					db_error = db->put (db, NULL,
+							    &id_dbt, &vcard_dbt, 0);
+
+					g_free (vcard);
+
+					if (db_error != 0)
+						card_failed++;
+				}
+
+				g_object_unref (contact);
+			}
+
+			db_error = dbc->c_get (dbc, &id_dbt, &vcard_dbt, DB_NEXT);
+		}
+
+		dbc->c_close (dbc);
+
+		if (card_failed) {
+			g_warning ("failed to update %d cards", card_failed);
+			return FALSE;
+		}
+	}
+
+	string_to_dbt (E_BOOK_BACKEND_FILE_VERSION_NAME, &version_name_dbt);
+	string_to_dbt (E_BOOK_BACKEND_FILE_LAST_BDB_VERSION, &version_dbt);
+
+	db_error = db->put (db, NULL, &version_name_dbt, &version_dbt, 0);
+	if (db_error == 0)
+		return TRUE;
+	else
+		return FALSE;
+}
+
+static gboolean
+e_book_backend_file_maybe_upgrade_db (DB *db)
+{
+	DBT  version_name_dbt, version_dbt;
+	gint  db_error;
+	gchar *version;
+	gboolean ret_val = TRUE;
+
+	if (!db) {
+		g_warning (G_STRLOC ": No DB opened");
+		return FALSE;
+	}
+
+	string_to_dbt (E_BOOK_BACKEND_FILE_VERSION_NAME, &version_name_dbt);
+	memset (&version_dbt, 0, sizeof (version_dbt));
+	version_dbt.flags = DB_DBT_MALLOC;
+
+	db_error = db->get (db, NULL, &version_name_dbt, &version_dbt, 0);
+	if (db_error == 0) {
+		/* success */
+		version = version_dbt.data;
+	}
+	else {
+		/* key was not in file */
+		version = g_strdup ("0.0");
+	}
+
+	if (strcmp (version, E_BOOK_BACKEND_FILE_LAST_BDB_VERSION))
+		ret_val = e_book_backend_file_upgrade_db (db, version);
+
+	g_free (version);
+
+	return ret_val;
+}
+
+
+static gboolean
+migrate_bdb_to_sqlitedb (EBookBackendSqliteDB   *sqlitedb,
+			 const gchar            *sqlite_folder_id,
+			 DB                     *db,
+			 GError                **error)
+{
+	DBC            *dbc;
+	DBT             id_dbt, vcard_dbt;
+	gint            db_error;
+	gboolean        skipped_version = FALSE;
+	gboolean        skipped_revision = FALSE;
+	GSList         *contacts = NULL;
+
+	db_error = db->cursor (db, NULL, &dbc, 0);
+
+	if (db_error != 0) {
+		g_warning (G_STRLOC ": db->cursor failed with %s", db_strerror (db_error));
+		db_error_to_gerror (db_error, error);
+		return FALSE;
+	}
+
+	memset (&vcard_dbt, 0, sizeof (vcard_dbt));
+	memset (&id_dbt, 0, sizeof (id_dbt));
+	db_error = dbc->c_get (dbc, &id_dbt, &vcard_dbt, DB_FIRST);
+
+	while (db_error == 0) {
+		gboolean skip = FALSE;
+
+		/* don't include the version and revision in the list of cards */
+		if (!skipped_version && !strcmp (id_dbt.data, E_BOOK_BACKEND_FILE_VERSION_NAME)) {
+			skipped_version = TRUE;
+			skip = TRUE;
+		} else if (!skipped_revision && !strcmp (id_dbt.data, E_BOOK_BACKEND_FILE_REVISION_NAME)) {
+			skipped_revision = TRUE;
+			skip = TRUE;
+		}
+
+		if (!skip) {
+			EContact *contact = e_contact_new_from_vcard_with_uid (vcard_dbt.data, id_dbt.data);
+
+			contacts = g_slist_prepend (contacts, contact);
+		}
+
+		db_error = dbc->c_get (dbc, &id_dbt, &vcard_dbt, DB_NEXT);
+	}
+
+	dbc->c_close (dbc);
+
+	/* Detect error case */
+	if (db_error != DB_NOTFOUND) {
+		g_warning (G_STRLOC ": dbc->c_get failed with %s", db_strerror (db_error));
+		e_util_free_object_slist (contacts);
+		db_error_to_gerror (db_error, error);
+		return FALSE;
+	}
+
+	/* Add the contacts to the SQLite (only if there are any contacts to add) */
+	if (contacts &&
+	    !e_book_backend_sqlitedb_add_contacts (sqlitedb,
+						   sqlite_folder_id,
+						   contacts, FALSE, error)) {
+		if (error && *error) {
+			g_warning ("Failed to add contacts to sqlite db: %s", (*error)->message);
+		} else {
+			g_warning ("Failed to add contacts to sqlite db: unknown error");
+		}
+
+		e_util_free_object_slist (contacts);
+		return FALSE;
+	}
+
+	e_util_free_object_slist (contacts);
+
+	if (!e_book_backend_sqlitedb_set_is_populated (sqlitedb, sqlite_folder_id, TRUE, error)) {
+		if (error && *error) {
+			g_warning ("Failed to set the sqlitedb populated flag: %s", (*error)->message);
+		} else {
+			g_warning ("Failed to set the sqlitedb populated flag: unknown error");
+		}
+		return FALSE;
+	}
+
+	return TRUE;
+}
+
+gboolean
+e_book_backend_file_migrate_bdb (EBookBackendSqliteDB  *sqlitedb,
+				 const gchar           *sqlite_folder_id,
+				 const gchar           *dirname,
+				 const gchar           *filename,
+				 GError               **error)
+{
+	DB        *db = NULL;
+	gint       db_error;
+	gboolean   status = FALSE;
+
+
+	G_LOCK (db_env);
+
+#ifdef G_OS_WIN32
+	if (!db_env_initialized) {
+		/* Use the gstdio wrappers to open, check, rename and unlink
+		 * files from libdb.
+		 */
+		db_env_set_func_open (my_open);
+		db_env_set_func_close (close);
+		db_env_set_func_exists (my_exists);
+		db_env_set_func_rename (my_rename);
+		db_env_set_func_unlink (my_unlink);
+
+		db_env_initialized = TRUE;
+	}
+#endif
+
+	db_error = e_db3_utils_maybe_recover (filename);
+	if (db_error != 0) {
+		g_warning ("db recovery failed with %s", db_strerror (db_error));
+		db_error_to_gerror (db_error, error);
+		goto unlock_env;
+	}
+
+	db_error = db_env_create (&db_env, 0);
+	if (db_error != 0) {
+		g_warning ("db_env_create failed with %s", db_strerror (db_error));
+		db_error_to_gerror (db_error, error);
+		goto unlock_env;
+	}
+
+	db_env->set_errcall (db_env, file_errcall);
+
+	/* Set the allocation routines to the non-aborting GLib functions */
+	db_env->set_alloc (db_env, (gpointer (*)(gsize)) g_try_malloc,
+			   (gpointer (*)(gpointer , gsize)) g_try_realloc,
+			   g_free);
+
+	/*
+	 * DB_INIT_TXN enables transaction support. It requires DB_INIT_LOCK to
+	 * initialize the locking subsystem and DB_INIT_LOG for the logging
+	 * subsystem.
+	 *
+	 * DB_INIT_MPOOL enables the in-memory cache.
+	 *
+	 * Note that historically we needed either DB_INIT_CDB or DB_INIT_LOCK, because we
+	 * had multiple threads reading and writing concurrently without
+	 * any locking above libdb. DB_INIT_LOCK was used because
+	 * DB_INIT_TXN conflicts with DB_INIT_CDB.
+	 *
+	 * Currently we leave this in place because it is known to work.
+	 */
+	db_error = (*db_env->open) (db_env, dirname, DB_INIT_LOCK | DB_INIT_TXN | DB_INIT_LOG | DB_CREATE | DB_INIT_MPOOL | DB_PRIVATE | DB_THREAD, 0);
+	if (db_error != 0) {
+		g_warning ("db_env_open failed with %s", db_strerror (db_error));
+		db_error_to_gerror (db_error, error);
+		goto close_env;
+	}
+
+	db_error = db_create (&db, db_env, 0);
+	if (db_error != 0) {
+		g_warning ("db_create failed with %s", db_strerror (db_error));
+		db_error_to_gerror (db_error, error);
+		goto close_env;
+	}
+
+	/* First try opening the DB... we want write permission because it's possible we need to update
+	 * an out of date DB before actually migrating it to the SQLite DB */
+	db_error = (*db->open) (db, NULL, filename, NULL, DB_HASH, DB_THREAD | DB_AUTO_COMMIT, 0666);
+
+	/* Was an old version,  lets upgrade the format ... */
+	if (db_error == DB_OLD_VERSION) {
+		db_error = e_db3_utils_upgrade_format (filename);
+
+		if (db_error != 0) {
+			g_warning ("db format upgrade failed with %s", db_strerror (db_error));
+			db_error_to_gerror (db_error, error);
+			goto close_env;
+		}
+
+		db->close (db, 0);
+		db_error = db_create (&db, db_env, 0);
+		if (db_error != 0) {
+			g_warning ("db_create failed with %s", db_strerror (db_error));
+			db_error_to_gerror (db_error, error);
+			goto close_env;
+		}
+
+		/* Try again after the upgrade... */
+		db_error = (*db->open) (db, NULL, filename, NULL, DB_HASH, DB_THREAD | DB_AUTO_COMMIT, 0666);
+
+		if (db_error != 0) {
+			/* Another error, clean up and get out of here */
+			goto close_db;
+		}
+	}
+
+	/* Unable to open the DB for some reason */
+	if (db_error != 0) {
+		db_error_to_gerror (db_error, error);
+		goto close_env;
+	}
+
+	/* Try another upgrade */
+	if (!e_book_backend_file_maybe_upgrade_db (db)) {
+		g_propagate_error (error, EDB_ERROR_EX (OTHER_ERROR, "e_book_backend_file_maybe_upgrade_db failed"));
+		goto close_db;
+	}
+
+	/* Now we have our old BDB up and running and migrated to the latest known BDB version,
+	 * lets go ahead and now migrate it to the sqlite DB
+	 */
+	if (migrate_bdb_to_sqlitedb (sqlitedb, sqlite_folder_id, db, error))
+		status = TRUE;
+
+ close_db:
+	db->close (db, 0);
+	db = NULL;
+
+ close_env:
+	db_env->close (db_env, 0);
+	db_env = NULL;
+
+ unlock_env:
+
+	G_UNLOCK (db_env);
+
+	return status;
+}
diff --git a/addressbook/backends/file/e-book-backend-file-migrate-bdb.h b/addressbook/backends/file/e-book-backend-file-migrate-bdb.h
new file mode 100644
index 0000000..e108d13
--- /dev/null
+++ b/addressbook/backends/file/e-book-backend-file-migrate-bdb.h
@@ -0,0 +1,43 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+
+/* e-book-backend-file-migrate-bdb.c - Migration of old BDB database to the new sqlite DB.
+ *
+ * Copyright (C) 2012 Openismus GmbH
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of version 2 of the GNU Lesser General Public
+ * License as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this program; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ *
+ * Authors: Tristan Van Berkom <tristanvb openismus com>
+ *
+ * Based on work by Nat Friedman, Chris Toshok and Hans Petter Jansson.
+ */
+
+#ifndef E_BOOK_BACKEND_MIGRATE_BDB_H
+#define E_BOOK_BACKEND_MIGRATE_BDB_H
+
+G_BEGIN_DECLS
+
+gboolean e_book_backend_file_migrate_bdb (EBookBackendSqliteDB  *sqlitedb,
+					  const gchar           *sqlite_folder_id,
+					  const gchar           *dirname,
+					  const gchar           *filename,
+					  GError               **error);
+
+
+
+G_END_DECLS
+
+
+
+#endif /* E_BOOK_BACKEND_MIGRATE_BDB_H */
diff --git a/addressbook/backends/file/e-book-backend-file.c b/addressbook/backends/file/e-book-backend-file.c
index 16d269b..1feb3bc 100644
--- a/addressbook/backends/file/e-book-backend-file.c
+++ b/addressbook/backends/file/e-book-backend-file.c
@@ -21,6 +21,7 @@
  * Authors: Nat Friedman <nat novell com>
  *          Chris Toshok <toshok ximian com>
  *          Hans Petter Jansson <hpj novell com>
+ *          Tristan Van Berkom <tristanvb openismus com>
  */
 
 #include <config.h>
@@ -32,7 +33,6 @@
 #include <fcntl.h>
 #include <time.h>
 #include <errno.h>
-#include "db.h"
 #include <sys/stat.h>
 #include <sys/time.h>
 
@@ -40,14 +40,13 @@
 #include <glib/gi18n-lib.h>
 
 #include "e-book-backend-file.h"
+#include "e-book-backend-file-migrate-bdb.h"
 
 #define E_BOOK_BACKEND_FILE_GET_PRIVATE(obj) \
 	(G_TYPE_INSTANCE_GET_PRIVATE \
 	((obj), E_TYPE_BOOK_BACKEND_FILE, EBookBackendFilePrivate))
 
-#define d(x)
-
-#define CHANGES_DB_SUFFIX ".changes.db"
+#define d(x)  x
 
 #define E_BOOK_BACKEND_FILE_VERSION_NAME "PAS-DB-VERSION"
 #define E_BOOK_BACKEND_FILE_VERSION "0.2"
@@ -60,24 +59,25 @@
 #define SQLITEDB_FOLDER_ID   "folder_id"
 #define SQLITEDB_FOLDER_NAME "folder"
 
-#define EDB_ERROR(_code) e_data_book_create_error (E_DATA_BOOK_STATUS_ ## _code, NULL)
+#define EDB_ERROR(_code)          e_data_book_create_error (E_DATA_BOOK_STATUS_ ## _code, NULL)
 #define EDB_ERROR_EX(_code, _msg) e_data_book_create_error (E_DATA_BOOK_STATUS_ ## _code, _msg)
-#define EDB_NOT_OPENED_ERROR EDB_ERROR(NOT_OPENED)
+#define EDB_NOT_OPENED_ERROR      EDB_ERROR(NOT_OPENED)
+
 
 G_DEFINE_TYPE (EBookBackendFile, e_book_backend_file, E_TYPE_BOOK_BACKEND_SYNC)
 
 struct _EBookBackendFilePrivate {
-	gchar     *dirname;
-	gchar     *filename;
 	gchar     *photo_dirname;
 	gchar     *revision;
 	gint       rev_counter;
-	DB        *file_db;
-	DB_ENV    *env;
 
 	EBookBackendSqliteDB *sqlitedb;
 };
 
+
+/****************************************************************
+ *                   File Management helper APIs                *
+ ****************************************************************/
 typedef enum {
 	GET_PATH_DB_DIR,
 	GET_PATH_PHOTO_DIR
@@ -89,45 +89,6 @@ typedef enum {
 	STATUS_ERROR
 } PhotoModifiedStatus;
 
-G_LOCK_DEFINE_STATIC (db_environments);
-static GHashTable *db_environments = NULL;
-typedef struct {
-	gint ref_count;
-	DB_ENV *env;
-} global_env;
-
-static void
-db_error_to_gerror (const gint db_error,
-                    GError **perror)
-{
-	if (db_error && perror && *perror)
-		g_clear_error (perror);
-
-	switch (db_error) {
-	case 0:
-		return;
-	case DB_NOTFOUND:
-		g_propagate_error (perror, EDB_ERROR (CONTACT_NOT_FOUND));
-		return;
-	case EACCES:
-		g_propagate_error (perror, EDB_ERROR (PERMISSION_DENIED));
-		return;
-	default:
-		g_propagate_error (perror, e_data_book_create_error_fmt (E_DATA_BOOK_STATUS_OTHER_ERROR, "db error 0x%x (%s)", db_error, db_strerror (db_error) ? db_strerror (db_error) : _("Unknown error")));
-		return;
-	}
-}
-
-static void
-string_to_dbt (const gchar *str,
-               DBT *dbt)
-{
-	memset (dbt, 0, sizeof (*dbt));
-	dbt->data = (gpointer) str;
-	dbt->size = strlen (str) + 1;
-	dbt->flags = DB_DBT_USERMEM;
-}
-
 static gboolean
 remove_file (const gchar *filename,
              GError **error)
@@ -170,59 +131,6 @@ create_directory (const gchar *dirname,
 	return TRUE;
 }
 
-static EContact *
-create_contact (const gchar *uid,
-                const gchar *vcard)
-{
-	return e_contact_new_from_vcard_with_uid (vcard, uid);
-}
-
-static gchar *
-load_vcard (EBookBackendFile *bf,
-            DB_TXN *txn,
-            const gchar *uid,
-            GError **error)
-{
-	DB     *db = bf->priv->file_db;
-	DBT     id_dbt, vcard_dbt;
-	gchar  *vcard;
-	gint    db_error;
-
-	/* Get the old contact from the db and compare the photo fields */
-	string_to_dbt (uid, &id_dbt);
-	memset (&vcard_dbt, 0, sizeof (vcard_dbt));
-	vcard_dbt.flags = DB_DBT_MALLOC;
-
-	db_error = db->get (db, txn, &id_dbt, &vcard_dbt, 0);
-
-	if (db_error == 0) {
-		vcard = vcard_dbt.data;
-	} else {
-		g_warning (G_STRLOC ": db->get failed with %s", db_strerror (db_error));
-		g_propagate_error (error, EDB_ERROR (CONTACT_NOT_FOUND));
-		return NULL;
-	}
-
-	return vcard;
-}
-
-static EContact *
-load_contact (EBookBackendFile *bf,
-              DB_TXN *txn,
-              const gchar *uid,
-              GError **error)
-{
-	EContact *contact = NULL;
-	gchar    *vcard;
-
-	if ((vcard = load_vcard (bf, txn, uid, error)) != NULL) {
-		contact = create_contact (uid, vcard);
-		g_free (vcard);
-	}
-
-	return contact;
-}
-
 static gchar *
 check_remove_uri_for_field (EContact *old_contact,
                             EContact *new_contact,
@@ -649,7 +557,6 @@ static PhotoModifiedStatus
 maybe_transform_vcard_for_photo (EBookBackendFile *bf,
                                  EContact *old_contact,
                                  EContact *contact,
-                                 gchar **vcard_ret,
                                  GError **error)
 {
 	PhotoModifiedStatus status;
@@ -667,96 +574,16 @@ maybe_transform_vcard_for_photo (EBookBackendFile *bf,
 		modified = modified || (status == STATUS_MODIFIED);
 	}
 
-	if (status != STATUS_ERROR) {
-		if (modified) {
-			if (vcard_ret)
-				*vcard_ret = e_vcard_to_string (E_VCARD (contact), EVC_FORMAT_VCARD_30);
-			status = STATUS_MODIFIED;
-		}
-	}
+	if (status != STATUS_ERROR && modified)
+		status = STATUS_MODIFIED;
 
 	return status;
 }
 
-static gboolean
-build_sqlitedb (EBookBackendFilePrivate *bfpriv)
-{
-	DB             *db = bfpriv->file_db;
-	DBC            *dbc;
-	gint            db_error;
-	DBT             id_dbt, vcard_dbt;
-	GSList         *contacts = NULL;
-	GError         *error = NULL;
-	gboolean        skipped_version = FALSE;
-	gboolean        skipped_revision = FALSE;
-
-	if (!db) {
-		g_warning (G_STRLOC ": Not opened yet");
-		return FALSE;
-	}
-
-	db_error = db->cursor (db, NULL, &dbc, 0);
-
-	if (db_error != 0) {
-		g_warning (G_STRLOC ": db->cursor failed with %s", db_strerror (db_error));
-		return FALSE;
-	}
-
-	memset (&vcard_dbt, 0, sizeof (vcard_dbt));
-	memset (&id_dbt, 0, sizeof (id_dbt));
-	db_error = dbc->c_get (dbc, &id_dbt, &vcard_dbt, DB_FIRST);
-
-	while (db_error == 0) {
-		gboolean skip = FALSE;
-
-		/* don't include the version and revision in the list of cards */
-		if (!skipped_version && !strcmp (id_dbt.data, E_BOOK_BACKEND_FILE_VERSION_NAME)) {
-			skipped_version = TRUE;
-			skip = TRUE;
-		} else if (!skipped_revision && !strcmp (id_dbt.data, E_BOOK_BACKEND_FILE_REVISION_NAME)) {
-			skipped_revision = TRUE;
-			skip = TRUE;
-		}
-
-		if (!skip) {
-			EContact *contact = create_contact (id_dbt.data, vcard_dbt.data);
-
-			contacts = g_slist_prepend (contacts, contact);
-		}
-
-		db_error = dbc->c_get (dbc, &id_dbt, &vcard_dbt, DB_NEXT);
-
-	}
-
-	dbc->c_close (dbc);
-
-	/* Detect error case */
-	if (db_error != DB_NOTFOUND) {
-		g_warning (G_STRLOC ": dbc->c_get failed with %s", db_strerror (db_error));
-		e_util_free_object_slist (contacts);
-		return FALSE;
-	}
-
-	if (contacts && !e_book_backend_sqlitedb_add_contacts (bfpriv->sqlitedb,
-						   SQLITEDB_FOLDER_ID,
-						   contacts, FALSE, &error)) {
-		g_warning ("Failed to build contact summary: %s", error ? error->message : "Unknown error");
-		g_clear_error (&error);
-		e_util_free_object_slist (contacts);
-		return FALSE;
-	}
-
-	e_util_free_object_slist (contacts);
-
-	if (!e_book_backend_sqlitedb_set_is_populated (bfpriv->sqlitedb, SQLITEDB_FOLDER_ID, TRUE, &error)) {
-		g_warning ("Failed to set the sqlitedb populated flag: %s", error->message);
-		g_error_free (error);
-		return FALSE;
-	}
-
-	return TRUE;
-}
 
+/****************************************************************
+ *                     Global Revisioning Tools                 *
+ ****************************************************************/
 static gchar *
 e_book_backend_file_create_unique_id (void)
 {
@@ -790,21 +617,19 @@ e_book_backend_file_new_revision (EBookBackendFile *bf)
 static void
 e_book_backend_file_bump_revision (EBookBackendFile *bf)
 {
-	DB   *db = bf->priv->file_db;
-	DBT  revision_name_dbt, revision_dbt;
-	gint  db_error;
+	GError *error = NULL;
 
 	g_free (bf->priv->revision);
 	bf->priv->revision = e_book_backend_file_new_revision (bf);
 
-	string_to_dbt (E_BOOK_BACKEND_FILE_REVISION_NAME, &revision_name_dbt);
-	string_to_dbt (bf->priv->revision,                &revision_dbt);
-	db_error = db->put (db, NULL, &revision_name_dbt, &revision_dbt, 0);
-
-	if (db_error != 0)
-		g_warning (
-			G_STRLOC ": db->put failed while bumping the revision string: %s",
-			db_strerror (db_error));
+	if (!e_book_backend_sqlitedb_set_revision (bf->priv->sqlitedb,
+						   SQLITEDB_FOLDER_ID,
+						   bf->priv->revision,
+						   &error)) {
+		g_warning (G_STRLOC ": Error setting database revision: %s",
+			   error->message);
+		g_error_free (error);
+	}
 
 	e_book_backend_notify_property_changed (E_BOOK_BACKEND (bf),
 						BOOK_BACKEND_PROPERTY_REVISION,
@@ -814,22 +639,17 @@ e_book_backend_file_bump_revision (EBookBackendFile *bf)
 static void
 e_book_backend_file_load_revision (EBookBackendFile *bf)
 {
-	DB   *db = bf->priv->file_db;
-	DBT  version_name_dbt, version_dbt;
-	gint  db_error;
-
-	string_to_dbt (E_BOOK_BACKEND_FILE_REVISION_NAME, &version_name_dbt);
-	memset (&version_dbt, 0, sizeof (version_dbt));
-	version_dbt.flags = DB_DBT_MALLOC;
-
-	db_error = db->get (db, NULL, &version_name_dbt, &version_dbt, 0);
-	if (db_error == 0) {
-		/* success */
-		bf->priv->revision = version_dbt.data;
-	}
-	else {
-		/* key was not in file */
-		bf->priv->revision = e_book_backend_file_new_revision (bf);
+	GError *error = NULL;
+
+	if (!e_book_backend_sqlitedb_get_revision (bf->priv->sqlitedb,
+						   SQLITEDB_FOLDER_ID,
+						   &bf->priv->revision,
+						   &error)) {
+		g_warning (G_STRLOC ": Error loading database revision: %s",
+			   error->message);
+		g_error_free (error);
+	} else if (bf->priv->revision == NULL) {
+		e_book_backend_file_bump_revision (bf);
 	}
 }
 
@@ -848,6 +668,11 @@ set_revision (EContact *contact)
 
 }
 
+
+/****************************************************************
+ *                   Main Backend Implementation                *
+ ****************************************************************/
+
 /**
  * This method will return TRUE if all the contacts were properly created.
  * If at least one contact fails, the method will return FALSE, all
@@ -856,38 +681,25 @@ set_revision (EContact *contact)
  */
 static gboolean
 do_create (EBookBackendFile *bf,
-          const GSList *vcards_req,
-          GSList **contacts,
-          GError **perror)
+	   const GSList *vcards_req,
+	   GSList **contacts,
+	   GError **perror)
 {
-	DB *db = bf->priv->file_db;
-	DB_ENV *env = bf->priv->env;
-	DB_TXN *txn = NULL;
 	GSList *slist = NULL;
 	const GSList *l;
-	gint db_error = 0;
 	PhotoModifiedStatus status = STATUS_NORMAL;
+	GError *local_error = NULL;
 
 	g_assert (bf);
 	g_assert (vcards_req);
 
-	if (!db) {
+	if (!bf || !bf->priv || !bf->priv->sqlitedb) {
 		g_propagate_error (perror, EDB_NOT_OPENED_ERROR);
 		return FALSE;
 	}
 
-	/* Begin transaction */
-	db_error = env->txn_begin (env, NULL, &txn, 0);
-	if (db_error != 0) {
-		g_warning (G_STRLOC ": env->txn_begin failed with %s", db_strerror (db_error));
-		db_error_to_gerror (db_error, perror);
-		return FALSE;
-	}
-
 	for (l = vcards_req; l != NULL; l = l->next) {
-		DBT              id_dbt, vcard_dbt;
 		gchar           *id;
-		gchar           *vcard;
 		const gchar     *rev;
 		const gchar     *vcard_req;
 		EContact        *contact;
@@ -901,37 +713,17 @@ do_create (EBookBackendFile *bf,
 		if (!(rev && *rev))
 			set_revision (contact);
 
-		status = maybe_transform_vcard_for_photo (bf, NULL, contact, NULL, perror);
-
-		if (status != STATUS_ERROR) {
-			vcard = e_vcard_to_string (E_VCARD (contact), EVC_FORMAT_VCARD_30);
-
-			string_to_dbt (id,    &id_dbt);
-			string_to_dbt (vcard, &vcard_dbt);
-
-			db_error = db->put (db, txn, &id_dbt, &vcard_dbt, 0);
-
-			g_free (vcard);
-		}
+		status = maybe_transform_vcard_for_photo (bf, NULL, contact, perror);
 
 		g_free (id);
 
-		if (db_error == 0 && status != STATUS_ERROR) {
-			/* Contact was added successfully, add it to the return list */
-			if (contacts != NULL)
-				slist = g_slist_prepend (slist, contact);
-		} else if (db_error != 0) {
-			/* Contact could not be added */
-			g_warning (G_STRLOC ": db->put failed with %s", db_strerror (db_error));
-			g_object_unref (contact);
-			db_error_to_gerror (db_error, perror);
+		if (status != STATUS_ERROR) {
 
-			/* Abort as soon as an error occurs */
-			break;
-		} else if (status == STATUS_ERROR) {
-			/* Contact could not be added */
-			g_warning (
-				G_STRLOC ": db->put failed with %s",
+			/* Contact was added successfully, add it to the local list */
+			slist = g_slist_prepend (slist, contact);
+		} else {
+			/* Contact could not be transformed */
+			g_warning (G_STRLOC ": Error transforming vcard with image data %s",
 				(perror && *perror) ? (*perror)->message :
 				"Unknown error transforming vcard");
 			g_object_unref (contact);
@@ -941,36 +733,31 @@ do_create (EBookBackendFile *bf,
 		}
 	}
 
-	if (db_error == 0 && status != STATUS_ERROR) {
-		/* Commit transaction */
-		db_error = txn->commit (txn, 0);
-		if (db_error == 0) {
-			/* Flush cache information to disk */
-			if (db->sync (db, 0) != 0) {
-				g_warning ("db->sync failed with %s", db_strerror (db_error));
-			}
-		} else {
-			g_warning (G_STRLOC ": txn->commit failed with %s", db_strerror (db_error));
-			db_error_to_gerror (db_error, perror);
-		}
+	if (status != STATUS_ERROR) {
 
-	} else {
-		/* Rollback transaction */
-		txn->abort (txn);
-	}
+		if (!e_book_backend_sqlitedb_add_contacts (bf->priv->sqlitedb,
+							   SQLITEDB_FOLDER_ID,
+							   slist, FALSE,
+							   &local_error)) {
+			
+			g_warning ("Failed to add contacts: %s", local_error->message);
+			g_propagate_error (perror, local_error);
 
-	if (db_error == 0 && status != STATUS_ERROR) {
-		if (contacts != NULL)
-			*contacts = g_slist_reverse (slist);
+			status = STATUS_ERROR;
+		}
+	}
 
-		return TRUE;
+	if (status != STATUS_ERROR && contacts != NULL) {
+		*contacts = g_slist_reverse (slist);
 	} else {
-		if (contacts != NULL)
+
+		if (contacts)
 			*contacts = NULL;
 
 		e_util_free_object_slist (slist);
-		return FALSE;
 	}
+
+	return (status != STATUS_ERROR);
 }
 
 static void
@@ -984,15 +771,6 @@ e_book_backend_file_create_contacts (EBookBackendSync *backend,
 	EBookBackendFile *bf = E_BOOK_BACKEND_FILE (backend);
 
 	if (do_create (bf, vcards, added_contacts, perror)) {
-		GError *error = NULL;
-
-		if (!e_book_backend_sqlitedb_add_contacts (bf->priv->sqlitedb,
-							  SQLITEDB_FOLDER_ID,
-							  *added_contacts, FALSE, &error)) {
-			g_warning ("Failed to add contacts to summary: %s", error->message);
-			g_error_free (error);
-		}
-
 		e_book_backend_file_bump_revision (bf);
 	}
 }
@@ -1006,70 +784,42 @@ e_book_backend_file_remove_contacts (EBookBackendSync *backend,
                                      GError **perror)
 {
 	EBookBackendFile *bf = E_BOOK_BACKEND_FILE (backend);
-	DB               *db = bf->priv->file_db;
-	DB_ENV           *env = bf->priv->env;
-	DB_TXN           *txn = NULL;
-	gint              db_error;
 	GSList           *removed_ids = NULL, *removed_contacts = NULL;
+	GError           *local_error = NULL;
+	gboolean          delete_failed = FALSE;
 	const GSList     *l;
 
-	if (!db) {
-		g_propagate_error (perror, EDB_NOT_OPENED_ERROR);
-		return;
-	}
-
-	/* Begin transaction */
-	db_error = env->txn_begin (env, NULL, &txn, 0);
-	if (db_error != 0) {
-		g_warning (G_STRLOC ": env->txn_begin failed with %s", db_strerror (db_error));
-		db_error_to_gerror (db_error, perror);
-		return;
-	}
-
 	for (l = id_list; l != NULL; l = l->next) {
 		const gchar *id;
 		EContact *contact;
-		DBT id_dbt;
 
 		id = l->data;
 
-		contact = load_contact (bf, txn, id, NULL);
-		if (contact)
-			removed_contacts = g_slist_prepend (removed_contacts, contact);
+		/* First load the EContacts which need to be removed, we might delete some
+		 * photos from disk because of this...
+		 *
+		 * Note: sqlitedb backend can probably make this faster by executing a
+		 * single query to fetch a list of contacts for a list of ids, the
+		 * current method makes a query for each UID.
+		 */
+		contact = e_book_backend_sqlitedb_get_contact (bf->priv->sqlitedb,
+							       SQLITEDB_FOLDER_ID, id,
+							       NULL, NULL, &local_error);
 
-		/* Then go on to delete from the db */
-		string_to_dbt (id, &id_dbt);
+		if (contact) {
+			removed_ids      = g_slist_prepend (removed_ids, g_strdup (id));
+			removed_contacts = g_slist_prepend (removed_contacts, contact);
+		} else {
+			g_warning ("Failed to fetch contact to be removed: %s", local_error->message);
+			g_propagate_error (perror, local_error);
 
-		db_error = db->del (db, txn, &id_dbt, 0);
-		if (db_error != 0) {
-			g_warning (G_STRLOC ": db->del failed with %s", db_strerror (db_error));
-			db_error_to_gerror (db_error, perror);
-			/* Abort as soon as a removal fails */
+			/* Abort as soon as missing contact is to be deleted */
+			delete_failed = TRUE;
 			break;
 		}
-
-		removed_ids = g_slist_prepend (removed_ids, g_strdup (id));
 	}
 
-	if (db_error == 0) {
-		/* Commit transaction */
-		db_error = txn->commit (txn, 0);
-		if (db_error == 0) {
-			/* Flush cache information to disk */
-			if (db->sync (db, 0) != 0) {
-				g_warning ("db->sync failed with %s", db_strerror (db_error));
-			}
-		} else {
-			g_warning (G_STRLOC ": txn->commit failed with %s", db_strerror (db_error));
-			db_error_to_gerror (db_error, perror);
-		}
-	} else {
-		/* Rollback transaction */
-		txn->abort (txn);
-	}
-
-	if (db_error == 0) {
-		GError *error = NULL;
+	if (!delete_failed) {
 
 		/* Delete URI associated to those contacts */
 		for (l = removed_contacts; l; l = l->next) {
@@ -1079,9 +829,9 @@ e_book_backend_file_remove_contacts (EBookBackendSync *backend,
 		/* Remove from summary as well */
 		if (!e_book_backend_sqlitedb_remove_contacts (bf->priv->sqlitedb,
 						      SQLITEDB_FOLDER_ID,
-						      removed_ids, &error)) {
-			g_warning ("Failed to remove contacts from the summary: %s", error->message);
-			g_error_free (error);
+						      removed_ids, &local_error)) {
+			g_warning ("Failed to remove contacts: %s", local_error->message);
+			g_propagate_error (perror, local_error);
 		}
 
 		*ids = removed_ids;
@@ -1091,7 +841,7 @@ e_book_backend_file_remove_contacts (EBookBackendSync *backend,
 	}
 
 	e_book_backend_file_bump_revision (bf);
-	g_slist_free_full (removed_contacts, g_object_unref);
+	e_util_free_object_slist (removed_contacts);
 }
 
 static void
@@ -1103,46 +853,39 @@ e_book_backend_file_modify_contacts (EBookBackendSync *backend,
                                      GError **perror)
 {
 	EBookBackendFile *bf = E_BOOK_BACKEND_FILE (backend);
-	DB               *db = bf->priv->file_db;
-	DB_ENV           *env = bf->priv->env;
-	DB_TXN           *txn = NULL;
-	gint              db_error;
 	const GSList     *lold, *l;
 	GSList           *old_contacts = NULL, *modified_contacts = NULL;
 	GSList           *ids = NULL;
+	GError           *local_error = NULL;
 	PhotoModifiedStatus status = STATUS_NORMAL;
 
-	if (!db) {
+	if (!bf || !bf->priv || !bf->priv->sqlitedb) {
 		g_propagate_error (perror, EDB_NOT_OPENED_ERROR);
 		return;
 	}
 
-	/* Begin transaction */
-	db_error = env->txn_begin (env, NULL, &txn, 0);
-	if (db_error != 0) {
-		g_warning (G_STRLOC ": env->txn_begin failed with %s", db_strerror (db_error));
-		db_error_to_gerror (db_error, perror);
-		return;
-	}
-
 	for (l = vcards; l != NULL; l = l->next) {
-		gchar *id, *lookup_id;
-		gchar *vcard_with_rev;
-		DBT id_dbt, vcard_dbt;
+		gchar *id;
 		EContact *contact, *old_contact;
 
 		contact = e_contact_new_from_vcard (l->data);
 		id = e_contact_get (contact, E_CONTACT_UID);
 
 		if (id == NULL) {
+			status = STATUS_ERROR;
+
 			g_propagate_error (perror, EDB_ERROR_EX (OTHER_ERROR, _("No UID in the contact")));
 			g_object_unref (contact);
 			break;
 		}
 
-		old_contact = load_contact (bf, txn, id, perror);
+		old_contact = e_book_backend_sqlitedb_get_contact (bf->priv->sqlitedb,
+								   SQLITEDB_FOLDER_ID, id,
+								   NULL, NULL, &local_error);
 		if (!old_contact) {
-			g_warning (G_STRLOC ": Failed to load contact %s", id);
+			g_warning (G_STRLOC ": Failed to load contact %s: %s", id, local_error->message);
+			g_propagate_error (perror, local_error);
+
 			status = STATUS_ERROR;
 
 			g_free (id);
@@ -1152,11 +895,10 @@ e_book_backend_file_modify_contacts (EBookBackendSync *backend,
 		old_contacts = g_slist_prepend (old_contacts, old_contact);
 
 		/* Transform incomming photo blobs to uris before storing this to the DB */
-		status = maybe_transform_vcard_for_photo (bf, old_contact, contact, NULL, perror);
+		status = maybe_transform_vcard_for_photo (bf, old_contact, contact, &local_error);
 		if (status == STATUS_ERROR) {
-			g_warning (
-				G_STRLOC ": Error transforming contact %s: %s",
-				id, (perror && *perror) ? (*perror)->message : "Unknown Error");
+			g_warning (G_STRLOC ": Error transforming contact %s: %s", id, local_error->message);
+			g_propagate_error (perror, local_error);
 
 			g_free (id);
 			g_object_unref (old_contact);
@@ -1166,63 +908,17 @@ e_book_backend_file_modify_contacts (EBookBackendSync *backend,
 
 		/* update the revision (modified time of contact) */
 		set_revision (contact);
-		vcard_with_rev = e_vcard_to_string (E_VCARD (contact), EVC_FORMAT_VCARD_30);
-
-		/* This is disgusting, but for a time cards were added with
-		 * ID's that are no longer used (they contained both the uri
-		 * and the id.) If we recognize it as a uri (file:///...) trim
-		 * off everything before the last '/', and use that as the
-		 * id.*/
-		if (!strncmp (id, "file:///", strlen ("file:///"))) {
-			lookup_id = strrchr (id, '/') + 1;
-		}
-		else
-			lookup_id = id;
-
-		string_to_dbt (lookup_id,      &id_dbt);
-		string_to_dbt (vcard_with_rev, &vcard_dbt);
-
-		db_error = db->put (db, txn, &id_dbt, &vcard_dbt, 0);
-		g_free (vcard_with_rev);
-
-		if (db_error != 0) {
-			g_warning (G_STRLOC ": db->put failed with %s", db_strerror (db_error));
-			db_error_to_gerror (db_error, perror);
-
-			/* Abort as soon as a modification fails */
-			g_free (id);
-			g_object_unref (contact);
-			break;
-		}
 
 		modified_contacts = g_slist_prepend (modified_contacts, contact);
-		ids = g_slist_prepend (ids, id);
+		ids               = g_slist_prepend (ids, id);
 	}
 
-	if (db_error == 0 && status != STATUS_ERROR) {
-		/* Commit transaction */
-		db_error = txn->commit (txn, 0);
-		if (db_error == 0) {
-			/* Flush cache information to disk */
-			if (db->sync (db, 0) != 0) {
-				g_warning ("db->sync failed with %s", db_strerror (db_error));
-			}
-		} else {
-			g_warning (G_STRLOC ": txn->commit failed with %s", db_strerror (db_error));
-			db_error_to_gerror (db_error, perror);
-		}
-	} else {
-		/* Rollback transaction */
-		txn->abort (txn);
-	}
-
-	if (db_error == 0 && status != STATUS_ERROR) {
-		GError *error = NULL;
+	if (status != STATUS_ERROR) {
 
 		/* Delete old photo file uris if need be (this will compare the new contact
 		 * with the current copy in the BDB to extract the uris to delete) */
 		lold = old_contacts;
-		l = modified_contacts;
+		l    = modified_contacts;
 		while (lold && l) {
 			maybe_delete_unused_uris (bf, E_CONTACT (lold->data), E_CONTACT (l->data));
 			lold = lold->next;
@@ -1230,18 +926,17 @@ e_book_backend_file_modify_contacts (EBookBackendSync *backend,
 		}
 
 		/* Update summary as well */
-		if (!e_book_backend_sqlitedb_remove_contacts (bf->priv->sqlitedb,
-							      SQLITEDB_FOLDER_ID,
-							      ids, &error)) {
-			g_warning ("Failed to remove contacts from the summary: %s", error->message);
-			g_error_free (error);
-		} else if (!e_book_backend_sqlitedb_add_contacts (bf->priv->sqlitedb,
-								  SQLITEDB_FOLDER_ID,
-								  modified_contacts, FALSE, &error)) {
-			g_warning ("Failed to add contacts to summary: %s", error->message);
-			g_error_free (error);
+		if (!e_book_backend_sqlitedb_add_contacts (bf->priv->sqlitedb,
+							   SQLITEDB_FOLDER_ID,
+							   modified_contacts, FALSE, &local_error)) {
+			g_warning ("Failed to modify contacts: %s", local_error->message);
+			g_propagate_error (perror, local_error);
+
+			status = STATUS_ERROR;
 		}
+	}
 
+	if (status != STATUS_ERROR) {
 		*contacts = g_slist_reverse (modified_contacts);
 	} else {
 		*contacts = NULL;
@@ -1264,12 +959,14 @@ e_book_backend_file_get_contact (EBookBackendSync *backend,
 {
 	EBookBackendFile *bf = E_BOOK_BACKEND_FILE (backend);
 
-	if (!bf || !bf->priv || !bf->priv->file_db) {
+	if (!bf || !bf->priv || !bf->priv->sqlitedb) {
 		g_propagate_error (perror, EDB_NOT_OPENED_ERROR);
 		return;
 	}
 
-	*vcard = load_vcard (bf, NULL, id, perror);
+	*vcard = e_book_backend_sqlitedb_get_vcard_string (bf->priv->sqlitedb,
+							   SQLITEDB_FOLDER_ID, id,
+							   NULL, NULL, perror);
 }
 
 static void
@@ -1281,117 +978,38 @@ e_book_backend_file_get_contact_list (EBookBackendSync *backend,
                                       GError **perror)
 {
 	EBookBackendFile *bf = E_BOOK_BACKEND_FILE (backend);
-	DB             *db = bf->priv->file_db;
-	DBC            *dbc;
-	gint            db_error;
-	DBT  id_dbt, vcard_dbt;
-	EBookBackendSExp *card_sexp = NULL;
-	gboolean search_needed;
-	const gchar *search = query;
-	GSList *contact_list = NULL, *l;
-	GSList *summary_list = NULL;
-	gboolean searched_summary = FALSE;
-	gboolean with_all_required_fields = FALSE;
-
-	d (printf ("e_book_backend_file_get_contact_list (%s)\n", search));
-
-	if (!db) {
+	GSList           *contact_list = NULL, *l;
+	GSList           *summary_list = NULL;
+	GError           *local_error = NULL;
+
+	d (printf ("e_book_backend_file_get_contact_list (%s)\n", query));
+
+	if (!bf || !bf->priv || !bf->priv->sqlitedb) {
 		g_propagate_error (perror, EDB_NOT_OPENED_ERROR);
 		return;
 	}
 
 	summary_list = e_book_backend_sqlitedb_search (
-		bf->priv->sqlitedb,
-		SQLITEDB_FOLDER_ID,
-		search, NULL,
-		&searched_summary,
-		&with_all_required_fields, NULL);
+		bf->priv->sqlitedb, SQLITEDB_FOLDER_ID,
+		query, NULL,
+		NULL, NULL, &local_error);
 
 	if (summary_list) {
 
 		for (l = summary_list; l; l = l->next) {
 			EbSdbSearchData *data = l->data;
 
-			if (with_all_required_fields) {
-				contact_list = g_slist_prepend (contact_list, data->vcard);
-				data->vcard  = NULL;
-			} else {
-				/* In this case the sqlitedb helped us with the query, but
-				 * the return information is incomplete so we need to load it up.
-				 */
-				gchar *vcard;
-
-				vcard = load_vcard (bf, NULL, data->uid, perror);
-
-				/* Break out on the first BDB error */
-				if (!vcard)
-					break;
-
-				contact_list = g_slist_prepend (contact_list, vcard);
-			}
+			/* Steal the memory directly from the returned query */
+			contact_list = g_slist_prepend (contact_list, data->vcard);
+			data->vcard  = NULL;
 		}
 
 		g_slist_foreach (summary_list, (GFunc) e_book_backend_sqlitedb_search_data_free, NULL);
 		g_slist_free (summary_list);
 
-	} else {
-		search_needed = TRUE;
-		if (!strcmp (search, "(contains \"x-evolution-any-field\" \"\")"))
-			search_needed = FALSE;
-
-		card_sexp = e_book_backend_sexp_new (search);
-		if (!card_sexp) {
-			g_propagate_error (perror, EDB_ERROR (INVALID_QUERY));
-			return;
-		}
-
-		db_error = db->cursor (db, NULL, &dbc, 0);
-
-		if (db_error != 0) {
-			g_warning (G_STRLOC ": db->cursor failed with %s", db_strerror (db_error));
-			/* XXX this needs to be some CouldNotOpen error */
-			db_error_to_gerror (db_error, perror);
-			return;
-		}
-
-		memset (&vcard_dbt, 0, sizeof (vcard_dbt));
-		vcard_dbt.flags = DB_DBT_MALLOC;
-		memset (&id_dbt, 0, sizeof (id_dbt));
-		db_error = dbc->c_get (dbc, &id_dbt, &vcard_dbt, DB_FIRST);
-
-		while (db_error == 0) {
-
-			/* don't include the version or revision in the list of cards */
-			if ((id_dbt.size != strlen (E_BOOK_BACKEND_FILE_VERSION_NAME) + 1
-			     || strcmp (id_dbt.data, E_BOOK_BACKEND_FILE_VERSION_NAME)) &&
-			    (id_dbt.size != strlen (E_BOOK_BACKEND_FILE_REVISION_NAME) + 1
-			     || strcmp (id_dbt.data, E_BOOK_BACKEND_FILE_REVISION_NAME))) {
-
-				if ((!search_needed) || (card_sexp != NULL && e_book_backend_sexp_match_vcard  (card_sexp, vcard_dbt.data))) {
-					contact_list = g_slist_prepend (contact_list, vcard_dbt.data);
-				} else {
-					free (vcard_dbt.data);
-				}
-			} else {
-				free (vcard_dbt.data);
-			}
-
-			db_error = dbc->c_get (dbc, &id_dbt, &vcard_dbt, DB_NEXT);
-
-		}
-		g_object_unref (card_sexp);
-
-		if (db_error == DB_NOTFOUND) {
-			/* Success */
-		} else {
-			g_warning (G_STRLOC ": dbc->c_get failed with %s", db_strerror (db_error));
-			db_error_to_gerror (db_error, perror);
-		}
-
-		db_error = dbc->c_close (dbc);
-		if (db_error != 0) {
-			g_warning (G_STRLOC ": dbc->c_close failed with %s", db_strerror (db_error));
-		}
+	} else if (local_error != NULL) {
+		g_warning ("Failed to fetch contacts: %s", local_error->message);
+		g_propagate_error (perror, local_error);
 	}
 
 	*contacts = contact_list;
@@ -1406,19 +1024,12 @@ e_book_backend_file_get_contact_list_uids (EBookBackendSync *backend,
                                            GError **perror)
 {
 	EBookBackendFile *bf = E_BOOK_BACKEND_FILE (backend);
-	DB             *db = bf->priv->file_db;
-	DBC            *dbc;
-	gint            db_error;
-	DBT  id_dbt, vcard_dbt;
-	EBookBackendSExp *card_sexp = NULL;
-	gboolean search_needed;
-	const gchar *search = query;
-	GSList *uids = NULL;
-	gboolean searched = FALSE;
-
-	d (printf ("e_book_backend_file_get_contact_list (%s)\n", search));
-
-	if (!db) {
+	GSList           *uids = NULL;
+	GError           *local_error = NULL;
+
+	d (printf ("e_book_backend_file_get_contact_list (%s)\n", query));
+
+	if (!bf || !bf->priv || !bf->priv->sqlitedb) {
 		g_propagate_error (perror, EDB_NOT_OPENED_ERROR);
 		return;
 	}
@@ -1426,64 +1037,11 @@ e_book_backend_file_get_contact_list_uids (EBookBackendSync *backend,
 	uids = e_book_backend_sqlitedb_search_uids (
 		bf->priv->sqlitedb,
 		SQLITEDB_FOLDER_ID,
-		search, &searched, NULL);
+		query, NULL, &local_error);
 
-	if (!searched) {
-		search_needed = TRUE;
-		if (!strcmp (search, "(contains \"x-evolution-any-field\" \"\")"))
-			search_needed = FALSE;
-
-		card_sexp = e_book_backend_sexp_new (search);
-		if (!card_sexp) {
-			g_propagate_error (perror, EDB_ERROR (INVALID_QUERY));
-			return;
-		}
-
-		db_error = db->cursor (db, NULL, &dbc, 0);
-
-		if (db_error != 0) {
-			g_warning (G_STRLOC ": db->cursor failed with %s", db_strerror (db_error));
-			/* XXX this needs to be some CouldNotOpen error */
-			db_error_to_gerror (db_error, perror);
-			return;
-		}
-
-		memset (&vcard_dbt, 0, sizeof (vcard_dbt));
-		vcard_dbt.flags = DB_DBT_MALLOC;
-		memset (&id_dbt, 0, sizeof (id_dbt));
-		db_error = dbc->c_get (dbc, &id_dbt, &vcard_dbt, DB_FIRST);
-
-		while (db_error == 0) {
-
-			/* don't include the version or revision in the list of cards */
-			if ((id_dbt.size != strlen (E_BOOK_BACKEND_FILE_VERSION_NAME) + 1
-			     || strcmp (id_dbt.data, E_BOOK_BACKEND_FILE_VERSION_NAME)) &&
-			    (id_dbt.size != strlen (E_BOOK_BACKEND_FILE_REVISION_NAME) + 1
-			     || strcmp (id_dbt.data, E_BOOK_BACKEND_FILE_REVISION_NAME))) {
-
-				if ((!search_needed) || (card_sexp != NULL && e_book_backend_sexp_match_vcard  (card_sexp, vcard_dbt.data))) {
-					uids = g_slist_prepend (uids, g_strdup (id_dbt.data));
-				}
-			}
-
-			g_free (vcard_dbt.data);
-
-			db_error = dbc->c_get (dbc, &id_dbt, &vcard_dbt, DB_NEXT);
-
-		}
-		g_object_unref (card_sexp);
-
-		if (db_error == DB_NOTFOUND) {
-			/* Success */
-		} else {
-			g_warning (G_STRLOC ": dbc->c_get failed with %s", db_strerror (db_error));
-			db_error_to_gerror (db_error, perror);
-		}
-
-		db_error = dbc->c_close (dbc);
-		if (db_error != 0) {
-			g_warning (G_STRLOC ": dbc->c_close failed with %s", db_strerror (db_error));
-		}
+	if (uids == NULL && local_error != NULL) {
+		g_warning ("Failed to fetch contact ids: %s", local_error->message);
+		g_propagate_error (perror, local_error);
 	}
 
 	*contacts_uids = g_slist_reverse (uids);
@@ -1548,14 +1106,9 @@ book_view_thread (gpointer data)
 	FileBackendSearchClosure *closure;
 	EBookBackendFile *bf;
 	const gchar *query;
-	DB  *db;
-	DBT id_dbt, vcard_dbt;
-	gint db_error;
-	gboolean allcontacts;
 	GSList *summary_list, *l;
 	GHashTable *fields_of_interest;
-	gboolean searched = FALSE;
-	gboolean with_all_required_fields = FALSE;
+	GError *local_error = NULL;
 
 	g_return_val_if_fail (E_IS_DATA_BOOK_VIEW (data), NULL);
 
@@ -1573,11 +1126,12 @@ book_view_thread (gpointer data)
 	 * when/if it's stopped */
 	e_data_book_view_ref (book_view);
 
-	db                 = bf->priv->file_db;
-	query              = e_data_book_view_get_card_query (book_view);
+	sexp = e_data_book_view_get_sexp (book_view);
+	query = e_book_backend_sexp_text (sexp);
+
 	fields_of_interest = e_data_book_view_get_fields_of_interest (book_view);
 
-	if (!db) {
+	if (!bf->priv->sqlitedb) {
 		e_data_book_view_notify_complete (book_view, EDB_NOT_OPENED_ERROR);
 		e_data_book_view_unref (book_view);
 		return NULL;
@@ -1585,10 +1139,8 @@ book_view_thread (gpointer data)
 
 	if ( !strcmp (query, "(contains \"x-evolution-any-field\" \"\")")) {
 		e_data_book_view_notify_progress (book_view, -1, _("Loading..."));
-		allcontacts = TRUE;
 	} else {
 		e_data_book_view_notify_progress (book_view, -1, _("Searching..."));
-		allcontacts = FALSE;
 	}
 
 	d (printf ("signalling parent thread\n"));
@@ -1598,84 +1150,29 @@ book_view_thread (gpointer data)
 		bf->priv->sqlitedb,
 		SQLITEDB_FOLDER_ID,
 		query, fields_of_interest,
-		&searched, &with_all_required_fields, NULL);
-
-	if (searched) {
-
-		for (l = summary_list; l; l = l->next) {
-			EbSdbSearchData *data = l->data;
-			gchar *vcard = NULL;
+		NULL, NULL, &local_error);
 
-			if (with_all_required_fields) {
-				vcard = data->vcard;
-				data->vcard = NULL;
-			} else {
-				GError *error = NULL;
-
-				/* The sqlitedb summary did not satisfy 'fields-of-interest',
-				 * load the complete vcard here. */
-				vcard = load_vcard (bf, NULL, data->uid, &error);
-
-				if (error) {
-					g_warning (
-						"Error loading contact %s: %s",
-						data->uid, error->message);
-					g_error_free (error);
-				}
-
-				if (!vcard)
-					continue;
-
-			}
-
-			notify_update_vcard (book_view, TRUE, data->uid, vcard);
-			g_free (vcard);
-		}
-
-		g_slist_foreach (summary_list, (GFunc) e_book_backend_sqlitedb_search_data_free, NULL);
-		g_slist_free (summary_list);
-	} else {
-		/* iterate over the db and do the query there */
-		DBC    *dbc;
-
-		memset (&id_dbt, 0, sizeof (id_dbt));
-		memset (&vcard_dbt, 0, sizeof (vcard_dbt));
-		vcard_dbt.flags = DB_DBT_MALLOC;
-
-		db_error = db->cursor (db, NULL, &dbc, 0);
-		if (db_error == 0) {
-
-			db_error = dbc->c_get (dbc, &id_dbt, &vcard_dbt, DB_FIRST);
-			while (db_error == 0) {
-
-				if (!e_flag_is_set (closure->running))
-					break;
-
-				/* don't include the version in the list of cards */
-				if (strcmp (id_dbt.data, E_BOOK_BACKEND_FILE_VERSION_NAME) &&
-				    strcmp (id_dbt.data, E_BOOK_BACKEND_FILE_REVISION_NAME)) {
-					notify_update_vcard (book_view, allcontacts,
-							     id_dbt.data, vcard_dbt.data);
-				}
-
-				g_free (vcard_dbt.data);
-				db_error = dbc->c_get (dbc, &id_dbt, &vcard_dbt, DB_NEXT);
-			}
+	if (!summary_list && local_error != NULL) {
+		g_warning (G_STRLOC ": Failed to query initial contacts: %s", local_error->message);
+		g_error_free (local_error);
+		e_data_book_view_notify_complete (book_view, EDB_NOT_OPENED_ERROR);
+		g_object_unref (book_view);
+		return NULL;
+	}
 
-			dbc->c_close (dbc);
-			if (db_error && db_error != DB_NOTFOUND)
-				g_warning (
-					"e_book_backend_file_search: error building list: %s",
-					db_strerror (db_error));
-		}
-		else if (db_error == DB_RUNRECOVERY) {
-			g_warning (
-				"e_book_backend_file_search: error getting the cursor for %s",
-				bf->priv->filename);
-			abort ();
-		}
+	for (l = summary_list; l; l = l->next) {
+		EbSdbSearchData *data = l->data;
+		gchar *vcard = NULL;
 
-	}
+		vcard = data->vcard;
+		data->vcard = NULL;
+ 
+		notify_update_vcard (book_view, TRUE, data->uid, vcard);
+		g_free (vcard);
+ 	}
+ 
+	g_slist_foreach (summary_list, (GFunc) e_book_backend_sqlitedb_search_data_free, NULL);
+	g_slist_free (summary_list);
 
 	if (e_flag_is_set (closure->running))
 		e_data_book_view_notify_complete (book_view, NULL /* Success */);
@@ -1720,167 +1217,12 @@ e_book_backend_file_stop_book_view (EBookBackend *backend,
 		g_thread_join (closure->thread);
 }
 
-/*
-** versions:
-**
-** 0.0 just a list of cards
-**
-** 0.1 same as 0.0, but with the version tag
-**
-** 0.2 not a real format upgrade, just a hack to fix broken ids caused
-**     by a bug in early betas, but we only need to convert them if
-**     the previous version is 0.1, since the bug existed after 0.1
-**     came about.
-*/
-static gboolean
-e_book_backend_file_upgrade_db (EBookBackendFile *bf,
-                                gchar *old_version)
-{
-	DB  *db = bf->priv->file_db;
-	gint db_error;
-	DBT version_name_dbt, version_dbt;
-
-	if (!db) {
-		g_warning (G_STRLOC ": No DB opened");
-		return FALSE;
-	}
-
-	if (strcmp (old_version, "0.0")
-	    && strcmp (old_version, "0.1")) {
-		g_warning (
-			"unsupported version '%s' found in PAS backend file\n",
-			old_version);
-		return FALSE;
-	}
-
-	if (!strcmp (old_version, "0.1")) {
-		/* we just loop through all the cards in the db,
-		 * giving them valid ids if they don't have them */
-		DBT  id_dbt, vcard_dbt;
-		DBC *dbc;
-		gint  card_failed = 0;
-
-		db_error = db->cursor (db, NULL, &dbc, 0);
-		if (db_error != 0) {
-			g_warning (G_STRLOC ": db->cursor failed with %s", db_strerror (db_error));
-			return FALSE;
-		}
-
-		memset (&id_dbt, 0, sizeof (id_dbt));
-		memset (&vcard_dbt, 0, sizeof (vcard_dbt));
-
-		db_error = dbc->c_get (dbc, &id_dbt, &vcard_dbt, DB_FIRST);
-
-		while (db_error == 0) {
-			if ((id_dbt.size != strlen (E_BOOK_BACKEND_FILE_VERSION_NAME) + 1
-			     || strcmp (id_dbt.data, E_BOOK_BACKEND_FILE_VERSION_NAME)) &&
-			    (id_dbt.size != strlen (E_BOOK_BACKEND_FILE_REVISION_NAME) + 1
-			     || strcmp (id_dbt.data, E_BOOK_BACKEND_FILE_REVISION_NAME))) {
-				EContact *contact;
-
-				contact = create_contact (id_dbt.data, vcard_dbt.data);
-
-				/* the cards we're looking for are
-				 * created with a normal id dbt, but
-				 * with the id field in the vcard set
-				 * to something that doesn't match.
-				 * so, we need to modify the card to
-				 * have the same id as the the dbt. */
-				if (strcmp (id_dbt.data, e_contact_get_const (contact, E_CONTACT_UID))) {
-					gchar *vcard;
-
-					e_contact_set (contact, E_CONTACT_UID, id_dbt.data);
-
-					vcard = e_vcard_to_string (E_VCARD (contact), EVC_FORMAT_VCARD_30);
-					string_to_dbt (vcard, &vcard_dbt);
-
-					db_error = db->put (db, NULL,
-							    &id_dbt, &vcard_dbt, 0);
-
-					g_free (vcard);
-
-					if (db_error != 0)
-						card_failed++;
-				}
-
-				g_object_unref (contact);
-			}
-
-			db_error = dbc->c_get (dbc, &id_dbt, &vcard_dbt, DB_NEXT);
-		}
-
-		dbc->c_close (dbc);
-
-		if (card_failed) {
-			g_warning ("failed to update %d cards", card_failed);
-			return FALSE;
-		}
-	}
-
-	string_to_dbt (E_BOOK_BACKEND_FILE_VERSION_NAME, &version_name_dbt);
-	string_to_dbt (E_BOOK_BACKEND_FILE_VERSION, &version_dbt);
-
-	db_error = db->put (db, NULL, &version_name_dbt, &version_dbt, 0);
-	if (db_error == 0)
-		return TRUE;
-	else
-		return FALSE;
-}
-
-static gboolean
-e_book_backend_file_maybe_upgrade_db (EBookBackendFile *bf)
-{
-	DB   *db = bf->priv->file_db;
-	DBT  version_name_dbt, version_dbt;
-	gint  db_error;
-	gchar *version;
-	gboolean ret_val = TRUE;
-
-	if (!db) {
-		g_warning (G_STRLOC ": No DB opened");
-		return FALSE;
-	}
-
-	string_to_dbt (E_BOOK_BACKEND_FILE_VERSION_NAME, &version_name_dbt);
-	memset (&version_dbt, 0, sizeof (version_dbt));
-	version_dbt.flags = DB_DBT_MALLOC;
-
-	db_error = db->get (db, NULL, &version_name_dbt, &version_dbt, 0);
-	if (db_error == 0) {
-		/* success */
-		version = version_dbt.data;
-	}
-	else {
-		/* key was not in file */
-		version = g_strdup ("0.0");
-	}
-
-	if (strcmp (version, E_BOOK_BACKEND_FILE_VERSION))
-		ret_val = e_book_backend_file_upgrade_db (bf, version);
-
-	g_free (version);
-
-	return ret_val;
-}
 
 #ifdef CREATE_DEFAULT_VCARD
 # include <libedata-book/ximian-vcard.h>
 #endif
 
 static void
-#if (DB_VERSION_MAJOR > 4) || (DB_VERSION_MAJOR == 4 && DB_VERSION_MINOR >= 3)
-file_errcall (const DB_ENV *env,
-              const gchar *buf1,
-              const gchar *buf2)
-#else
-file_errcall (const gchar *buf1,
-              gchar *buf2)
-#endif
-{
-	g_warning ("libdb error: %s", buf2);
-}
-
-static void
 e_book_backend_file_open (EBookBackendSync *backend,
                           EDataBook *book,
                           GCancellable *cancellable,
@@ -1888,260 +1230,168 @@ e_book_backend_file_open (EBookBackendSync *backend,
                           GError **perror)
 {
 	EBookBackendFile *bf = E_BOOK_BACKEND_FILE (backend);
-	gchar            *dirname, *filename;
-	gboolean          readonly = TRUE;
+	gchar            *dirname, *filename, *backup;
 	ESourceRegistry  *registry;
 	ESource          *source;
-	gint              db_error;
-	DB               *db;
-	DB_ENV           *env;
 	GError           *local_error = NULL;
-	global_env       *genv = NULL;
-
-#ifdef CREATE_DEFAULT_VCARD
-	gboolean create_default_vcard = FALSE;
-#endif
+	gboolean          populated;
 
 	source = e_backend_get_source (E_BACKEND (backend));
 	registry = e_book_backend_get_registry (E_BOOK_BACKEND (backend));
 	dirname = e_book_backend_file_extract_path_from_source (
 		registry, source, GET_PATH_DB_DIR);
-
-	if (only_if_exists && !g_file_test (dirname, G_FILE_TEST_IS_DIR)) {
-		g_free (dirname);
-		g_propagate_error (perror, EDB_ERROR (NO_SUCH_BOOK));
-		return;
-	}
-
 	filename = g_build_filename (dirname, "addressbook.db", NULL);
+	backup   = g_build_filename (dirname, "addressbook.db.old", NULL);
 
-	db_error = e_db3_utils_maybe_recover (filename);
-	if (db_error != 0) {
-		g_warning ("db recovery failed with %s", db_strerror (db_error));
-		g_free (dirname);
-		g_free (filename);
-		db_error_to_gerror (db_error, perror);
-		return;
-	}
+	/* The old BDB exists, lets migrate that to sqlite right away
+	 */
+	if (g_file_test (filename, G_FILE_TEST_EXISTS)) {
+		bf->priv->sqlitedb = e_book_backend_sqlitedb_new (dirname,
+								  SQLITEDB_EMAIL_ID,
+								  SQLITEDB_FOLDER_ID,
+								  SQLITEDB_FOLDER_NAME,
+								  TRUE,
+								  &local_error);
 
-	G_LOCK (db_environments);
-	if (db_environments) {
-		genv = g_hash_table_lookup (db_environments, dirname);
-	}
-	if (genv && genv->ref_count > 0) {
-		genv->ref_count++;
-		env = genv->env;
-	} else {
-		db_error = db_env_create (&env, 0);
-		if (db_error != 0) {
-			g_warning ("db_env_create failed with %s", db_strerror (db_error));
-			G_UNLOCK (db_environments);
+		if (!bf->priv->sqlitedb) {
+			g_warning (G_STRLOC ": Failed to open sqlitedb: %s", local_error->message);
+			g_propagate_error (perror, local_error);
 			g_free (dirname);
 			g_free (filename);
-			db_error_to_gerror (db_error, perror);
+			g_free (backup);
 			return;
 		}
 
-		env->set_errcall (env, file_errcall);
-
-		/* Set the allocation routines to the non-aborting GLib functions */
-		env->set_alloc (env, (gpointer (*)(gsize)) g_try_malloc,
-				(gpointer (*)(gpointer , gsize)) g_try_realloc,
-				g_free);
-
-		/* Make sure the database directory is created
-		 * or env->open will fail */
-		if (!only_if_exists) {
-			if (!create_directory (dirname, perror)) {
-				g_warning ("failed to create directory at %s", dirname);
-				G_UNLOCK (db_environments);
-				g_free (dirname);
-				g_free (filename);
-				return;
-			}
-		}
+		if (!e_book_backend_file_migrate_bdb (bf->priv->sqlitedb,
+						      SQLITEDB_FOLDER_ID,
+						      dirname, filename, &local_error)) {
 
-		/*
-		 * DB_INIT_TXN enables transaction support. It requires DB_INIT_LOCK to
-		 * initialize the locking subsystem and DB_INIT_LOG for the logging
-		 * subsystem.
-		 *
-		 * DB_INIT_MPOOL enables the in-memory cache.
-		 *
-		 * Note that we need either DB_INIT_CDB or DB_INIT_LOCK, because we will
-		 * have multiple threads reading and writing concurrently without
-		 * any locking above libdb. Right now DB_INIT_LOCK is used because
-		 * DB_INIT_TXN conflicts with DB_INIT_CDB.
-		 */
-		db_error = (*env->open) (env, dirname, DB_INIT_LOCK | DB_INIT_TXN | DB_INIT_LOG | DB_CREATE | DB_INIT_MPOOL | DB_PRIVATE | DB_THREAD, 0);
-		if (db_error != 0) {
-			env->close (env, 0);
-			g_warning ("db_env_open failed with %s", db_strerror (db_error));
-			G_UNLOCK (db_environments);
+			/* Perhaps this error should not be fatal */
+			g_warning (G_STRLOC ": Failed to migrate old BDB to sqlitedb: %s", local_error->message);
+			g_propagate_error (perror, local_error);
 			g_free (dirname);
 			g_free (filename);
-			db_error_to_gerror (db_error, perror);
+			g_free (backup);
+ 
+			g_object_unref (bf->priv->sqlitedb);
+			bf->priv->sqlitedb = NULL;
 			return;
 		}
 
-		/* Insert in the db_environments hash table */
-		if (!db_environments) {
-			db_environments = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL);
-		}
-		genv = g_malloc0 (sizeof (global_env));
-		genv->ref_count = 1;
-		genv->env = env;
-		g_hash_table_insert (db_environments, g_strdup (dirname), genv);
-	}
-	G_UNLOCK (db_environments);
-
-	bf->priv->env = env;
+		/* Now we've migrated the database, lets rename it instead of unlinking it */
+		if (g_rename (filename, backup) < 0) {
 
-	db_error = db_create (&db, env, 0);
-	if (db_error != 0) {
-		g_warning ("db_create failed with %s", db_strerror (db_error));
-		g_free (dirname);
-		g_free (filename);
-		db_error_to_gerror (db_error, perror);
-		return;
-	}
+			g_warning (G_STRLOC ": Failed to rename old database from '%s' to '%s': %s",
+				   filename, backup, g_strerror (errno));
 
-	db_error = (*db->open) (db, NULL, filename, NULL, DB_HASH, DB_THREAD | DB_AUTO_COMMIT, 0666);
-
-	if (db_error == DB_OLD_VERSION) {
-		db_error = e_db3_utils_upgrade_format (filename);
-
-		if (db_error != 0) {
-			g_warning ("db format upgrade failed with %s", db_strerror (db_error));
-			g_free (dirname);
-			g_free (filename);
-			db_error_to_gerror (db_error, perror);
-			return;
-		}
+			g_propagate_error (perror, e_data_book_create_error_fmt
+					   (E_DATA_BOOK_STATUS_OTHER_ERROR,
+					    _("Failed to rename old database from '%s' to '%s': %s"),
+					    filename, backup, g_strerror (errno)));
 
-		db->close (db, 0);
-		db_error = db_create (&db, env, 0);
-		if (db_error != 0) {
-			g_warning ("db_create failed with %s", db_strerror (db_error));
 			g_free (dirname);
 			g_free (filename);
-			db_error_to_gerror (db_error, perror);
+			g_free (backup);
+			bf->priv->sqlitedb = NULL;
 			return;
-		}
-
-		db_error = (*db->open) (db, NULL, filename, NULL, DB_HASH, DB_THREAD | DB_AUTO_COMMIT, 0666);
+ 		}
 	}
 
-	if (db_error == 0) {
-		readonly = FALSE;
-	} else {
-		db->close (db, 0);
-		db_error = db_create (&db, env, 0);
-		if (db_error != 0) {
-			g_warning ("db_create failed with %s", db_strerror (db_error));
-			g_free (dirname);
-			g_free (filename);
-			db_error_to_gerror (db_error, perror);
-			return;
-		}
+	/* If we already have a handle on this, it means there was an old BDB migrated
+	 * and no need to reopen it
+	 */
+	if (bf->priv->sqlitedb == NULL) {
 
-		db_error = (*db->open) (db, NULL, filename, NULL, DB_HASH, DB_RDONLY | DB_THREAD | DB_AUTO_COMMIT, 0666);
+		/* ensure the directory exists first */
+		if (!only_if_exists && !create_directory (dirname, &local_error)) {
 
-		if (db_error != 0 && !only_if_exists) {
+			g_warning (G_STRLOC ": Failed to create directory for sqlite db: %s", local_error->message);
+			g_propagate_error (perror, local_error);
 
-			/* the database didn't exist, so we create the
-			 * directory then the .db */
-			db->close (db, 0);
+ 			g_free (dirname);
+ 			g_free (filename);
+			g_free (backup);
+ 			return;
+ 		}
 
-			if (!create_directory (dirname, perror)) {
-				g_free (dirname);
-				g_free (filename);
-				return;
-			}
+		/* Create the sqlitedb */
+		bf->priv->sqlitedb = e_book_backend_sqlitedb_new (dirname,
+								  SQLITEDB_EMAIL_ID,
+								  SQLITEDB_FOLDER_ID,
+								  SQLITEDB_FOLDER_NAME,
+								  TRUE, &local_error);
 
-			db_error = db_create (&db, env, 0);
-			if (db_error != 0) {
-				g_warning ("db_create failed with %s", db_strerror (db_error));
-				g_free (dirname);
-				g_free (filename);
-				db_error_to_gerror (db_error, perror);
+		if (!bf->priv->sqlitedb) {
+			g_warning (G_STRLOC ": Failed to open sqlitedb: %s", local_error->message);
+			g_propagate_error (perror, local_error);
+ 			g_free (dirname);
+ 			g_free (filename);
+			g_free (backup);
+ 			return;
+ 		}
+
+		/* An sqlite DB only 'exists' if the populated flag is set */
+		populated = e_book_backend_sqlitedb_get_is_populated (bf->priv->sqlitedb,
+								      SQLITEDB_FOLDER_ID,
+								      &local_error);
+
+		if (local_error != NULL) {
+			/* Perhaps this error should not be fatal */
+			g_warning (G_STRLOC ": Failed to check populated flag in sqlite db: %s", local_error->message);
+			g_propagate_error (perror, local_error);
+ 			g_free (dirname);
+ 			g_free (filename);
+			g_free (backup);
+
+			g_object_unref (bf->priv->sqlitedb);
+			bf->priv->sqlitedb = NULL;
+			return;
+ 		}
+
+		if (!populated) {
+			/* Shutdown, no such book ! */
+			if (only_if_exists) {
+ 				g_free (dirname);
+ 				g_free (filename);
+				g_free (backup);
+				g_object_unref (bf->priv->sqlitedb);
+				bf->priv->sqlitedb = NULL;
+				g_propagate_error (perror, EDB_ERROR (NO_SUCH_BOOK));
 				return;
-			}
+ 			}
 
-			db_error = (*db->open) (db, NULL, filename, NULL, DB_HASH, DB_CREATE | DB_THREAD | DB_AUTO_COMMIT, 0666);
-			if (db_error != 0) {
-				db->close (db, 0);
-				g_warning ("db->open (... %s ... DB_CREATE ...) failed with %s", filename, db_strerror (db_error));
-			}
-			else {
 #ifdef CREATE_DEFAULT_VCARD
-				create_default_vcard = TRUE;
-#endif
+			{
+				GSList l;
+				l.data = XIMIAN_VCARD;
+				l.next = NULL;
 
-				readonly = FALSE;
+				if (!do_create (bf, &l, NULL, NULL))
+					g_warning ("Cannot create default contact");
 			}
-		}
-	}
-
-	bf->priv->file_db = db;
-
-	if (db_error != 0) {
-		bf->priv->file_db = NULL;
-		g_free (dirname);
-		g_free (filename);
-		db_error_to_gerror (db_error, perror);
-		return;
-	}
-
-#ifdef CREATE_DEFAULT_VCARD
-	if (create_default_vcard) {
-		GSList l;
-		l.data = XIMIAN_VCARD;
-		l.next = NULL;
-
-		if (!do_create (bf, &l, NULL, NULL))
-			g_warning ("Cannot create default contact");
-	}
 #endif
 
-	if (!e_book_backend_file_maybe_upgrade_db (bf)) {
-		db->close (db, 0);
-		bf->priv->file_db = NULL;
-		g_free (dirname);
-		g_free (filename);
-		g_propagate_error (perror, EDB_ERROR_EX (OTHER_ERROR, "e_book_backend_file_maybe_upgrade_db failed"));
-		return;
-	}
-
-	g_free (bf->priv->dirname);
-	g_free (bf->priv->filename);
-	bf->priv->dirname = dirname;
-	bf->priv->filename = filename;
-
-	bf->priv->sqlitedb = e_book_backend_sqlitedb_new (
-		bf->priv->dirname,
-		SQLITEDB_EMAIL_ID,
-		SQLITEDB_FOLDER_ID,
-		SQLITEDB_FOLDER_NAME,
-		FALSE,
-		perror);
-	if (!bf->priv->sqlitedb)
-		return;
+			/* Set the populated flag */
+			if (!e_book_backend_sqlitedb_set_is_populated (bf->priv->sqlitedb,
+								       SQLITEDB_FOLDER_ID,
+								       TRUE,
+								       &local_error)) {
+				g_warning (G_STRLOC ": Failed to set populated flag in sqlite db: %s",
+					   local_error->message);
+				g_propagate_error (perror, local_error);
+				g_free (dirname);
+				g_free (filename);
+				g_free (backup);
+				g_object_unref (bf->priv->sqlitedb);
+				bf->priv->sqlitedb = NULL;
+				return;
+			}
+ 		}
+ 	}
 
-	if (!e_book_backend_sqlitedb_get_is_populated (bf->priv->sqlitedb,
-						       SQLITEDB_FOLDER_ID,
-						       &local_error)) {
-		if (local_error) {
-			g_propagate_error (perror, local_error);
-			return;
-		} else if (!build_sqlitedb (bf->priv)) {
-			g_propagate_error (
-				perror, e_data_book_create_error_fmt (
-				E_DATA_BOOK_STATUS_OTHER_ERROR,
-				_("Failed to build summary for an address book %s"),
-				bf->priv->filename));
-		}
-	}
+	g_free (dirname);
+	g_free (filename);
+	g_free (backup);
 
 	/* Resolve the photo directory here */
 	dirname = e_book_backend_file_extract_path_from_source (
@@ -2153,7 +1403,7 @@ e_book_backend_file_open (EBookBackendSync *backend,
 	e_book_backend_file_load_revision (bf);
 
 	e_book_backend_notify_online (E_BOOK_BACKEND (backend), TRUE);
-	e_book_backend_notify_readonly (E_BOOK_BACKEND (backend), readonly);
+	e_book_backend_notify_readonly (E_BOOK_BACKEND (backend), FALSE);
 	e_book_backend_notify_opened (E_BOOK_BACKEND (backend), NULL /* Success */);
 
 	e_book_backend_notify_property_changed (E_BOOK_BACKEND (backend),
@@ -2213,15 +1463,10 @@ static void
 e_book_backend_file_sync (EBookBackend *backend)
 {
 	EBookBackendFile *bf = E_BOOK_BACKEND_FILE (backend);
-	gint db_error;
 
 	g_return_if_fail (bf != NULL);
 
-	if (bf->priv->file_db) {
-		db_error = bf->priv->file_db->sync (bf->priv->file_db, 0);
-		if (db_error != 0)
-			g_warning (G_STRLOC ": db->sync failed with %s", db_strerror (db_error));
-	}
+	/* FIXME: Tell sqlite to dump NOW ! */
 }
 
 typedef struct {
@@ -2277,33 +1522,9 @@ static void
 e_book_backend_file_dispose (GObject *object)
 {
 	EBookBackendFile *bf;
-	global_env *genv;
 
 	bf = E_BOOK_BACKEND_FILE (object);
 
-	if (bf->priv->file_db) {
-		bf->priv->file_db->close (bf->priv->file_db, 0);
-		bf->priv->file_db = NULL;
-	}
-
-	G_LOCK (db_environments);
-	if (bf->priv->dirname) {
-		genv = g_hash_table_lookup (db_environments, bf->priv->dirname);
-		if (genv) {
-			genv->ref_count--;
-			if (genv->ref_count == 0) {
-				genv->env->close (genv->env, 0);
-				g_free (genv);
-				g_hash_table_remove (db_environments, bf->priv->dirname);
-			}
-			if (g_hash_table_size (db_environments) == 0) {
-				g_hash_table_destroy (db_environments);
-				db_environments = NULL;
-			}
-		}
-	}
-	G_UNLOCK (db_environments);
-
 	if (bf->priv->sqlitedb) {
 		g_object_unref (bf->priv->sqlitedb);
 		bf->priv->sqlitedb = NULL;
@@ -2319,8 +1540,6 @@ e_book_backend_file_finalize (GObject *object)
 
 	priv = E_BOOK_BACKEND_FILE_GET_PRIVATE (object);
 
-	g_free (priv->filename);
-	g_free (priv->dirname);
 	g_free (priv->photo_dirname);
 	g_free (priv->revision);
 
@@ -2328,54 +1547,6 @@ e_book_backend_file_finalize (GObject *object)
 	G_OBJECT_CLASS (e_book_backend_file_parent_class)->finalize (object);
 }
 
-#ifdef G_OS_WIN32
-/* Avoid compiler warning by providing a function with exactly the
- * prototype that db_env_set_func_open() wants for the open method.
- */
-
-static gint
-my_open (const gchar *name,
-         gint oflag,
-         ...)
-{
-	gint mode = 0;
-
-	if (oflag & O_CREAT) {
-		va_list arg;
-		va_start (arg, oflag);
-		mode = va_arg (arg, gint);
-		va_end (arg);
-	}
-
-	return g_open (name, oflag, mode);
-}
-
-gint
-my_rename (const gchar *oldname,
-           const gchar *newname)
-{
-	return g_rename (oldname, newname);
-}
-
-gint
-my_exists (const gchar *name,
-           gint *isdirp)
-{
-	if (!g_file_test (name, G_FILE_TEST_EXISTS))
-		return ENOENT;
-	if (isdirp != NULL)
-		*isdirp = g_file_test (name, G_FILE_TEST_IS_DIR);
-	return 0;
-}
-
-gint
-my_unlink (const gchar *name)
-{
-	return g_unlink (name);
-}
-
-#endif
-
 static void
 e_book_backend_file_class_init (EBookBackendFileClass *class)
 {
@@ -2405,17 +1576,6 @@ e_book_backend_file_class_init (EBookBackendFileClass *class)
 
 	object_class->dispose = e_book_backend_file_dispose;
 	object_class->finalize = e_book_backend_file_finalize;
-
-#ifdef G_OS_WIN32
-	/* Use the gstdio wrappers to open, check, rename and unlink
-	 * files from libdb.
-	 */
-	db_env_set_func_open (my_open);
-	db_env_set_func_close (close);
-	db_env_set_func_exists (my_exists);
-	db_env_set_func_rename (my_rename);
-	db_env_set_func_unlink (my_unlink);
-#endif
 }
 
 static void



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]