[evolution-data-server/openismus-work] Brute force backport of EBookBackendSqliteDB + phone number work.



commit c48698688cad87cfe1459a3a3cde75dcb556122c
Author: Tristan Van Berkom <tristanvb openismus com>
Date:   Thu Feb 21 21:58:29 2013 +0900

    Brute force backport of EBookBackendSqliteDB + phone number work.
    
    This is basically overwriting our openismus-work phone-number related
    work (plus the EBookBackendSqliteDB) from master, ensuring that the
    phone number details work the same way in master and in openismus-work.
    
    As for the direct port of EBookBackendSqliteDB, additional work was done
    there, it's more stable, mutexes work properly and I trust it more
    (plus it conforms to the same API, and has phone number related work
    from Mathias).

 addressbook/libebook-contacts/Makefile.am          |    9 +
 .../libebook-contacts/e-phone-number-private.cpp   |  311 +++
 .../libebook-contacts/e-phone-number-private.h     |   85 +
 addressbook/libebook-contacts/e-phone-number.c     |  389 ++++
 .../libebook-contacts/e-phone-number.h             |  173 +-
 addressbook/libebook-contacts/libebook-contacts.h  |    1 +
 .../libedata-book/e-book-backend-sqlitedb.c        | 2421 +++++++++++---------
 libedataserver/Makefile.am                         |    7 -
 libedataserver/e-phone-utils.cpp                   |  317 ---
 libedataserver/libedataserver.h                    |    1 -
 m4/evo_phonenumber.m4                              |   80 +-
 tests/libebook/Makefile.am                         |    3 +
 tests/libebook/client/Makefile.am                  |    2 +-
 tests/libebook/client/test-client-custom-summary.c |    2 +
 tests/libebook/client/test-client-e164-param.c     |    3 +
 .../libebook/client/test-client-get-contact-uids.c |    3 +
 tests/libebook/client/test-client-get-contact.c    |    3 +
 tests/libebook/client/test-client-get-view.c       |    3 +
 .../libebook/client/test-client-view-operations.c  |   52 +-
 tests/libebook/test-ebook-phone-number.c           |  437 ++++
 tests/libedataserver/Makefile.am                   |    4 -
 tests/libedataserver/e-phone-utils-test.c          |  273 ---
 22 files changed, 2762 insertions(+), 1817 deletions(-)
---
diff --git a/addressbook/libebook-contacts/Makefile.am b/addressbook/libebook-contacts/Makefile.am
index 876e50d..8140543 100644
--- a/addressbook/libebook-contacts/Makefile.am
+++ b/addressbook/libebook-contacts/Makefile.am
@@ -35,6 +35,8 @@ libebook_contacts_1_2_la_CPPFLAGS = \
 libebook_contacts_1_2_la_SOURCES =                             \
        $(ENUM_GENERATED)                               \
        $(MARSHAL_GENERATED)                            \
+       e-phone-number.c                                \
+       e-phone-number-private.h                        \
        e-book-contacts-types.c                         \
        e-address-western.c                             \
        e-name-western.c                                \
@@ -56,6 +58,12 @@ libebook_contacts_1_2_la_LDFLAGS =                                                   \
        $(CODE_COVERAGE_LDFLAGS) \
        $(NULL)
 
+if ENABLE_PHONENUMBER
+libebook_contacts_1_2_la_SOURCES += e-phone-number-private.cpp
+libebook_contacts_1_2_la_CPPFLAGS += $(PHONENUMBER_INCLUDES)
+libebook_contacts_1_2_la_LIBADD += $(PHONENUMBER_LIBS)
+endif # ENABLE_PHONENUMBER
+
 libebookcontactsincludedir = $(privincludedir)/libebook-contacts
 
 libebookcontactsinclude_HEADERS =                      \
@@ -67,6 +75,7 @@ libebookcontactsinclude_HEADERS =                     \
        e-name-western.h                                \
        e-contact.h                                     \
        e-vcard.h                                       \
+       e-phone-number.h                                \
        e-source-backend-summary-setup.h
 
 
diff --git a/addressbook/libebook-contacts/e-phone-number-private.cpp 
b/addressbook/libebook-contacts/e-phone-number-private.cpp
new file mode 100644
index 0000000..86c4e52
--- /dev/null
+++ b/addressbook/libebook-contacts/e-phone-number-private.cpp
@@ -0,0 +1,311 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+/*
+ * Copyright (C) 2012,2013 Intel Corporation
+ *
+ * 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.
+ *
+ * Author: Mathias Hasselmann <mathias openismus com>
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#ifndef ENABLE_PHONENUMBER
+#error Phone number support must be enabled for this file
+#endif /* ENABLE_PHONENUMBER */
+
+#include "e-phone-number-private.h"
+
+/* C++ standard library */
+#include <string>
+
+/* system headers */
+#include <langinfo.h>
+#include <locale.h>
+
+/* libphonenumber */
+#include <phonenumbers/logger.h>
+#include <phonenumbers/phonenumberutil.h>
+
+using i18n::phonenumbers::PhoneNumber;
+using i18n::phonenumbers::PhoneNumberUtil;
+
+struct _EPhoneNumber {
+       PhoneNumber priv;
+};
+
+static PhoneNumberUtil *
+e_phone_number_util_get_instance (void)
+{
+       static PhoneNumberUtil *instance = NULL;
+
+       if (g_once_init_enter (&instance)) {
+               /* FIXME: Ideally PhoneNumberUtil would not be a singleton,
+                * so that we could safely tweak it's attributes without
+                * influencing other users of the library. */
+               PhoneNumberUtil *new_instance = PhoneNumberUtil::GetInstance ();
+
+               /* Disable all logging: libphonenumber is pretty verbose. */
+               new_instance->SetLogger (new i18n::phonenumbers::NullLogger);
+               g_once_init_leave (&instance, new_instance);
+       }
+
+       return instance;
+}
+
+static EPhoneNumberError
+e_phone_number_error_code (PhoneNumberUtil::ErrorType error)
+{
+       switch (error) {
+       case PhoneNumberUtil::NO_PARSING_ERROR:
+               g_return_val_if_reached (E_PHONE_NUMBER_ERROR_UNKNOWN);
+       case PhoneNumberUtil::INVALID_COUNTRY_CODE_ERROR:
+               return E_PHONE_NUMBER_ERROR_INVALID_COUNTRY_CODE;
+       case PhoneNumberUtil::NOT_A_NUMBER:
+               return E_PHONE_NUMBER_ERROR_NOT_A_NUMBER;
+       case PhoneNumberUtil::TOO_SHORT_AFTER_IDD:
+               return E_PHONE_NUMBER_ERROR_TOO_SHORT_AFTER_IDD;
+       case PhoneNumberUtil::TOO_SHORT_NSN:
+               return E_PHONE_NUMBER_ERROR_TOO_SHORT;
+       case PhoneNumberUtil::TOO_LONG_NSN:
+               return E_PHONE_NUMBER_ERROR_TOO_LONG;
+       }
+
+       /* Please file a bug that we can add a proper error code. */
+       g_return_val_if_reached (E_PHONE_NUMBER_ERROR_UNKNOWN);
+}
+
+static std::string
+e_phone_number_make_region_code (const gchar *region_code)
+{
+       /* Get two-letter country code from current locale's address facet if supported */
+#if HAVE__NL_ADDRESS_COUNTRY_AB2
+       if (region_code == NULL || region_code[0] == '\0')
+               region_code = nl_langinfo (_NL_ADDRESS_COUNTRY_AB2);
+#endif /* HAVE__NL_ADDRESS_COUNTRY_AB2 */
+
+       /* Extract two-letter country code from current locale id if needed */
+       if (region_code == NULL || region_code[0] == '\0') {
+               /* From outside this is a C library, so we better consult the
+                * C infrastructure instead of std::locale, which might divert. */
+               std::string current_region = setlocale (LC_ADDRESS, NULL);
+               const std::string::size_type uscore = current_region.find ('_');
+
+               if (uscore != std::string::npos) {
+                       const std::string::size_type n = std::min (uscore + 3, current_region.length ());
+
+                       if (n == current_region.length() || not ::isalpha(current_region.at(n)))
+                               current_region = current_region.substr (uscore + 1, 2);
+               }
+
+               if (current_region.length() != 2)
+                       return "US";
+
+               return current_region;
+       }
+
+       return region_code;
+}
+
+gint
+_e_phone_number_cxx_get_country_code_for_region (const gchar *region_code)
+{
+       return e_phone_number_util_get_instance ()->GetCountryCodeForRegion (
+               e_phone_number_make_region_code (region_code));
+}
+
+gchar *
+_e_phone_number_cxx_get_default_region ()
+{
+       return g_strdup (e_phone_number_make_region_code (NULL).c_str ());
+}
+
+EPhoneNumber *
+_e_phone_number_cxx_from_string (const gchar *phone_number,
+                                 const gchar *region_code,
+                                 GError **error)
+{
+       g_return_val_if_fail (NULL != phone_number, NULL);
+
+       const std::string valid_region = e_phone_number_make_region_code (region_code);
+       std::auto_ptr<EPhoneNumber> parsed_number(new EPhoneNumber);
+
+       const PhoneNumberUtil::ErrorType err =
+#ifdef PHONENUMBER_RAW_INPUT_NEEDED
+               e_phone_number_util_get_instance ()->ParseAndKeepRawInput (
+                       phone_number, valid_region, &parsed_number->priv);
+#else /* PHONENUMBER_RAW_INPUT_NEEDED */
+               e_phone_number_util_get_instance ()->Parse (
+                       phone_number, valid_region, &parsed_number->priv);
+#endif /* PHONENUMBER_RAW_INPUT_NEEDED */
+
+       if (err != PhoneNumberUtil::NO_PARSING_ERROR) {
+               _e_phone_number_set_error (error, e_phone_number_error_code (err));
+               return NULL;
+       }
+
+       return parsed_number.release ();
+}
+
+gchar *
+_e_phone_number_cxx_to_string (const EPhoneNumber *phone_number,
+                               EPhoneNumberFormat format)
+{
+       g_return_val_if_fail (NULL != phone_number, NULL);
+
+       std::string formatted_number;
+
+       e_phone_number_util_get_instance ()->Format
+               (phone_number->priv,
+                static_cast<PhoneNumberUtil::PhoneNumberFormat> (format),
+                &formatted_number);
+
+       if (!formatted_number.empty ())
+               return g_strdup (formatted_number.c_str ());
+
+       return NULL;
+}
+
+static EPhoneNumberCountrySource
+e_phone_number_get_country_source (const EPhoneNumber *phone_number)
+{
+       g_return_val_if_fail (
+               phone_number->priv.has_country_code_source (),
+               E_PHONE_NUMBER_COUNTRY_FROM_DEFAULT);
+
+       switch (phone_number->priv.country_code_source ()) {
+               case PhoneNumber::FROM_NUMBER_WITH_PLUS_SIGN:
+                       return E_PHONE_NUMBER_COUNTRY_FROM_FQTN;
+
+               case PhoneNumber::FROM_NUMBER_WITH_IDD:
+                       return E_PHONE_NUMBER_COUNTRY_FROM_IDD;
+
+               /* FROM_NUMBER_WITHOUT_PLUS_SIGN only is used internally
+                * by libphonenumber to properly(???) reconstruct raw input
+                * from PhoneNumberUtil::ParseAndKeepRawInput(). Let's not
+                * bother our users with that barely understandable and
+                * almost undocumented implementation detail.
+                */
+               case PhoneNumber::FROM_NUMBER_WITHOUT_PLUS_SIGN:
+               case PhoneNumber::FROM_DEFAULT_COUNTRY:
+                       break;
+       }
+
+       return E_PHONE_NUMBER_COUNTRY_FROM_DEFAULT;
+}
+
+gint
+_e_phone_number_cxx_get_country_code (const EPhoneNumber *phone_number,
+                                      EPhoneNumberCountrySource *source)
+{
+       g_return_val_if_fail (NULL != phone_number, 0);
+
+       if (phone_number->priv.has_country_code ()) {
+               if (source)
+                       *source = e_phone_number_get_country_source (phone_number);
+
+               return phone_number->priv.country_code ();
+       }
+
+       return 0;
+}
+
+gchar *
+_e_phone_number_cxx_get_national_number (const EPhoneNumber *phone_number)
+{
+       g_return_val_if_fail (NULL != phone_number, NULL);
+
+       std::string national_number;
+
+       e_phone_number_util_get_instance ()->GetNationalSignificantNumber (
+                       phone_number->priv, &national_number);
+
+       if (!national_number.empty ())
+               return g_strdup (national_number.c_str ());
+
+       return NULL;
+}
+
+static EPhoneNumberMatch
+e_phone_number_match (PhoneNumberUtil::MatchType match_type)
+{
+       switch (match_type) {
+       case PhoneNumberUtil::NO_MATCH:
+       case PhoneNumberUtil::INVALID_NUMBER:
+               return E_PHONE_NUMBER_MATCH_NONE;
+       case PhoneNumberUtil::SHORT_NSN_MATCH:
+               return E_PHONE_NUMBER_MATCH_SHORT;
+       case PhoneNumberUtil::NSN_MATCH:
+               return E_PHONE_NUMBER_MATCH_NATIONAL;
+       case PhoneNumberUtil::EXACT_MATCH:
+               return E_PHONE_NUMBER_MATCH_EXACT;
+       }
+
+       g_return_val_if_reached (E_PHONE_NUMBER_MATCH_NONE);
+}
+
+EPhoneNumberMatch
+_e_phone_number_cxx_compare (const EPhoneNumber *first_number,
+                             const EPhoneNumber *second_number)
+{
+       g_return_val_if_fail (NULL != first_number, E_PHONE_NUMBER_MATCH_NONE);
+       g_return_val_if_fail (NULL != second_number, E_PHONE_NUMBER_MATCH_NONE);
+
+       const PhoneNumberUtil::MatchType match_type =
+               e_phone_number_util_get_instance ()->
+               IsNumberMatch (first_number->priv, second_number->priv);
+
+       g_warn_if_fail (match_type != PhoneNumberUtil::INVALID_NUMBER);
+       return e_phone_number_match (match_type);
+}
+
+EPhoneNumberMatch
+_e_phone_number_cxx_compare_strings (const gchar *first_number,
+                                     const gchar *second_number,
+                                     GError **error)
+{
+       EPhoneNumberMatch result = E_PHONE_NUMBER_MATCH_NONE;
+
+       g_return_val_if_fail (NULL != first_number, E_PHONE_NUMBER_MATCH_NONE);
+       g_return_val_if_fail (NULL != second_number, E_PHONE_NUMBER_MATCH_NONE);
+
+       const PhoneNumberUtil::MatchType match_type =
+               e_phone_number_util_get_instance ()->
+               IsNumberMatchWithTwoStrings (first_number, second_number);
+
+       if (match_type == PhoneNumberUtil::INVALID_NUMBER) {
+               _e_phone_number_set_error (error, E_PHONE_NUMBER_ERROR_NOT_A_NUMBER);
+       } else {
+               result = e_phone_number_match (match_type);
+       }
+
+       return result;
+}
+
+EPhoneNumber *
+_e_phone_number_cxx_copy (const EPhoneNumber *phone_number)
+{
+       if (phone_number)
+               return new EPhoneNumber (*phone_number);
+
+       return NULL;
+}
+
+void
+_e_phone_number_cxx_free (EPhoneNumber *phone_number)
+{
+       delete phone_number;
+}
diff --git a/addressbook/libebook-contacts/e-phone-number-private.h 
b/addressbook/libebook-contacts/e-phone-number-private.h
new file mode 100644
index 0000000..ec9c6fe
--- /dev/null
+++ b/addressbook/libebook-contacts/e-phone-number-private.h
@@ -0,0 +1,85 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+/*
+ * Copyright (C) 2012,2013 Intel Corporation
+ *
+ * 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.
+ *
+ * Author: Mathias Hasselmann <mathias openismus com>
+ */
+
+/* NOTE: Keeping API documentation in this header file because gtkdoc-mkdb
+ * explicitly only scans .h and .c files, but ignores .cpp files. */
+
+/**
+ * SECTION: e-phone-utils
+ * @include: libedataserver/libedataserver.h
+ * @short_description: Phone number support
+ *
+ * This modules provides utility functions for parsing and formatting
+ * phone numbers. Under the hood it uses Google's libphonenumber.
+ **/
+
+#if !defined (__LIBEBOOK_CONTACTS_H_INSIDE__) && !defined (LIBEBOOK_CONTACTS_COMPILATION)
+#error "Only <libebook-contacts/libebook-contacts.h> should be included directly."
+#endif
+
+#ifndef E_PHONE_NUMBER_PRIVATE_H
+#define E_PHONE_NUMBER_PRIVATE_H
+
+#include "e-phone-number.h"
+
+G_BEGIN_DECLS
+
+#if __GNUC__ >= 4
+#define E_PHONE_NUMBER_LOCAL __attribute__ ((visibility ("hidden")))
+#else
+#define E_PHONE_NUMBER_LOCAL
+#endif
+
+/* defined and used in e-phone-number.c, but also used by e-phone-number-private.cpp */
+
+E_PHONE_NUMBER_LOCAL void              _e_phone_number_set_error               (GError **error,
+                                                                                EPhoneNumberError code);
+
+#ifdef ENABLE_PHONENUMBER
+
+/* defined in e-phone-number-private.cpp, and used by by e-phone-number.c */
+
+E_PHONE_NUMBER_LOCAL gint              _e_phone_number_cxx_get_country_code_for_region
+                                                                               (const gchar *region_code);
+E_PHONE_NUMBER_LOCAL gchar *           _e_phone_number_cxx_get_default_region  (void);
+
+E_PHONE_NUMBER_LOCAL EPhoneNumber *    _e_phone_number_cxx_from_string         (const gchar *phone_number,
+                                                                                const gchar *region_code,
+                                                                                GError **error);
+E_PHONE_NUMBER_LOCAL gchar *           _e_phone_number_cxx_to_string           (const EPhoneNumber 
*phone_number,
+                                                                                EPhoneNumberFormat format);
+E_PHONE_NUMBER_LOCAL gint              _e_phone_number_cxx_get_country_code    (const EPhoneNumber 
*phone_number,
+                                                                                EPhoneNumberCountrySource 
*source);
+E_PHONE_NUMBER_LOCAL gchar *           _e_phone_number_cxx_get_national_number (const EPhoneNumber 
*phone_number);
+
+E_PHONE_NUMBER_LOCAL EPhoneNumberMatch _e_phone_number_cxx_compare             (const EPhoneNumber 
*first_number,
+                                                                                const EPhoneNumber 
*second_number);
+E_PHONE_NUMBER_LOCAL EPhoneNumberMatch _e_phone_number_cxx_compare_strings     (const gchar *first_number,
+                                                                                const gchar *second_number,
+                                                                                GError **error);
+E_PHONE_NUMBER_LOCAL EPhoneNumber *    _e_phone_number_cxx_copy                (const EPhoneNumber 
*phone_number);
+E_PHONE_NUMBER_LOCAL void              _e_phone_number_cxx_free                (EPhoneNumber *phone_number);
+
+#endif /* ENABLE_PHONENUMBER */
+
+G_END_DECLS
+
+#endif /* E_PHONE_NUMBER_PRIVATE_H */
diff --git a/addressbook/libebook-contacts/e-phone-number.c b/addressbook/libebook-contacts/e-phone-number.c
new file mode 100644
index 0000000..95beef4
--- /dev/null
+++ b/addressbook/libebook-contacts/e-phone-number.c
@@ -0,0 +1,389 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+/*
+ * Copyright (C) 2012,2013 Intel Corporation
+ *
+ * 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.
+ *
+ * Author: Mathias Hasselmann <mathias openismus com>
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include "e-phone-number.h"
+
+#include <glib/gi18n-lib.h>
+
+#include "e-phone-number-private.h"
+
+G_DEFINE_BOXED_TYPE (
+       EPhoneNumber, e_phone_number,
+       e_phone_number_copy, e_phone_number_free)
+
+G_DEFINE_QUARK (e-phone-number-error-quark, e_phone_number_error)
+
+static const gchar *
+e_phone_number_error_to_string (EPhoneNumberError code)
+{
+       switch (code) {
+       case E_PHONE_NUMBER_ERROR_NOT_IMPLEMENTED:
+               return _("The library was built without phone number support.");
+       case E_PHONE_NUMBER_ERROR_UNKNOWN:
+               return _("The phone number parser reported an yet unkown error code.");
+       case E_PHONE_NUMBER_ERROR_NOT_A_NUMBER:
+               return _("Not a phone number");
+       case E_PHONE_NUMBER_ERROR_INVALID_COUNTRY_CODE:
+               return _("Invalid country calling code");
+       case E_PHONE_NUMBER_ERROR_TOO_SHORT_AFTER_IDD:
+               return _("Remaining text after the country calling code is to short for a phone number");
+       case E_PHONE_NUMBER_ERROR_TOO_SHORT:
+               return _("Text is too short for a phone number");
+       case E_PHONE_NUMBER_ERROR_TOO_LONG:
+               return _("Text is too long for a phone number");
+       }
+
+       return _("Unknown error");
+}
+
+void
+_e_phone_number_set_error (GError **error,
+                           EPhoneNumberError code)
+{
+       const gchar *message = e_phone_number_error_to_string (code);
+       g_set_error_literal (error, E_PHONE_NUMBER_ERROR, code, message);
+}
+
+/**
+ * e_phone_number_is_supported:
+ *
+ * Checks if phone number support is available. It is recommended to call this
+ * function before using any of the phone-utils functions to ensure that the
+ * required functionality is available, and to pick alternative mechnisms if
+ * needed.
+ *
+ * Returns: %TRUE if phone number support is available.
+ *
+ * Since: 3.8
+ **/
+gboolean
+e_phone_number_is_supported (void)
+{
+#ifdef ENABLE_PHONENUMBER
+
+       return TRUE;
+
+#else /* ENABLE_PHONENUMBER */
+
+       return FALSE;
+
+#endif /* ENABLE_PHONENUMBER */
+}
+
+/**
+ * e_phone_number_get_country_code_for_region:
+ * @region_code: (allow-none): a two-letter country code, or %NULL
+ *
+ * Retrieves the preferred country calling code for @region_code,
+ * e.g. 358 for "fi".
+ *
+ * If %NULL is passed for @region_code the default region as returned by
+ * e_phone_number_get_default_region() is used.
+ *
+ * Returns: a valid country calling code, or zero if an unknown region
+ * code was passed.
+ *
+ * Since: 3.8
+ */
+gint
+e_phone_number_get_country_code_for_region (const gchar *region_code)
+{
+#ifdef ENABLE_PHONENUMBER
+
+       return _e_phone_number_cxx_get_country_code_for_region (region_code);
+
+#else /* ENABLE_PHONENUMBER */
+
+       g_warning ("%s: The library was built without phone number support.", G_STRFUNC);
+       return 0;
+
+#endif /* ENABLE_PHONENUMBER */
+}
+
+/**
+ * e_phone_number_get_default_region:
+ *
+ * Retrieves the current two-letter country code that's used by default for
+ * parsing phone numbers in e_phone_number_from_string(). It can be useful
+ * to store this number before parsing a bigger number of phone numbers.
+ *
+ * The result of this functions depends on the current setup of the
+ * %LC_ADDRESS category: If that category provides a reasonable value
+ * for %_NL_ADDRESS_COUNTRY_AB2 this value is returned. Otherwise the
+ * locale name configured for %LC_ADDRESS is parsed.
+ *
+ * Returns: (transfer full): a newly allocated string containing the
+ * current locale's two-letter code for phone number parsing.
+ *
+ * Since: 3.8
+ */
+gchar *
+e_phone_number_get_default_region (void)
+{
+#ifdef ENABLE_PHONENUMBER
+
+       return _e_phone_number_cxx_get_default_region ();
+
+#else /* ENABLE_PHONENUMBER */
+
+       g_warning ("%s: The library was built without phone number support.", G_STRFUNC);
+       return NULL;
+
+#endif /* ENABLE_PHONENUMBER */
+}
+
+/**
+ * e_phone_number_from_string:
+ * @phone_number: the phone number to parse
+ * @region_code: (allow-none): a two-letter country code, or %NULL
+ * @error: (out): a #GError to set an error, if any
+ *
+ * Parses the string passed in @phone_number. Note that no validation is
+ * performed whether the recognized phone number is valid for a particular
+ * region.
+ *
+ * The two-letter country code passed in @region_code only is used if the
+ * @phone_number is not written in international format. The application's
+ * default region as returned by e_phone_number_get_default_region() is used
+ * if @region_code is %NULL.
+ *
+ * If the number is guaranteed to start with a '+' followed by the country
+ * calling code, then "ZZ" can be passed for @region_code.
+ *
+ * Returns: (transfer full): a new EPhoneNumber instance on success,
+ * or %NULL on error. Call e_phone_number_free() to release this instance.
+ *
+ * Since: 3.8
+ **/
+EPhoneNumber *
+e_phone_number_from_string (const gchar *phone_number,
+                            const gchar *region_code,
+                            GError **error)
+{
+#ifdef ENABLE_PHONENUMBER
+
+       return _e_phone_number_cxx_from_string (phone_number, region_code, error);
+
+#else /* ENABLE_PHONENUMBER */
+
+       _e_phone_number_set_error (error, E_PHONE_NUMBER_ERROR_NOT_IMPLEMENTED);
+       return NULL;
+
+#endif /* ENABLE_PHONENUMBER */
+}
+
+/**
+ * e_phone_number_to_string:
+ * @phone_number: the phone number to format
+ * @format: the phone number format to apply
+ *
+ * Describes the @phone_number according to the rules applying to @format.
+ *
+ * Returns: (transfer full): A formatted string for @phone_number.
+ *
+ * Since: 3.8
+ **/
+gchar *
+e_phone_number_to_string (const EPhoneNumber *phone_number,
+                          EPhoneNumberFormat format)
+{
+#ifdef ENABLE_PHONENUMBER
+
+       return _e_phone_number_cxx_to_string (phone_number, format);
+
+#else /* ENABLE_PHONENUMBER */
+
+       g_warning ("%s: The library was built without phone number support.", G_STRFUNC);
+       return NULL;
+
+#endif /* ENABLE_PHONENUMBER */
+}
+
+/**
+ * e_phone_number_get_country_code:
+ * @phone_number: the phone number to query
+ * @source: an optional location for storing the phone number's origin, or %NULL
+ *
+ * Queries the @phone_number's country calling code and optionally stores the country
+ * calling code's origin in @source. For instance when parsing "+1-617-5423789" this
+ * function would return one and assing E_PHONE_NUMBER_COUNTRY_FROM_FQTN to @source.
+ *
+ * Returns: A valid country calling code, or zero if no code is known.
+ *
+ * Since: 3.8
+ **/
+gint
+e_phone_number_get_country_code (const EPhoneNumber *phone_number,
+                                 EPhoneNumberCountrySource *source)
+{
+#ifdef ENABLE_PHONENUMBER
+
+       return _e_phone_number_cxx_get_country_code (phone_number, source);
+
+#else /* ENABLE_PHONENUMBER */
+
+       g_warning ("%s: The library was built without phone number support.", G_STRFUNC);
+       return 0;
+
+#endif /* ENABLE_PHONENUMBER */
+}
+
+/**
+ * e_phone_number_get_national_number:
+ * @phone_number: the phone number to query
+ *
+ * Queries the national portion of @phone_number without any call-out
+ * prefixes. For instance when parsing "+1-617-5423789" this function would
+ * return the string "6175423789".
+ *
+ * Returns: (transfer full): The national portion of @phone_number.
+ *
+ * Since: 3.8
+ **/
+gchar *
+e_phone_number_get_national_number (const EPhoneNumber *phone_number)
+{
+#ifdef ENABLE_PHONENUMBER
+
+       return _e_phone_number_cxx_get_national_number (phone_number);
+
+#else /* ENABLE_PHONENUMBER */
+
+       g_warning ("%s: The library was built without phone number support.", G_STRFUNC);
+       return NULL;
+
+#endif /* ENABLE_PHONENUMBER */
+}
+
+/**
+ * e_phone_number_compare:
+ * @first_number: the first EPhoneNumber to compare
+ * @second_number: the second EPhoneNumber to compare
+ *
+ * Compares two phone numbers.
+ *
+ * Returns: The quality of matching for the two phone numbers.
+ *
+ * Since: 3.8
+ **/
+EPhoneNumberMatch
+e_phone_number_compare (const EPhoneNumber *first_number,
+                        const EPhoneNumber *second_number)
+{
+#ifdef ENABLE_PHONENUMBER
+
+       return _e_phone_number_cxx_compare (first_number, second_number);
+
+#else /* ENABLE_PHONENUMBER */
+
+       /* NOTE: This calls for a dedicated return value, but I sense broken
+        * client code that only checks for E_PHONE_NUMBER_MATCH_NONE and then
+        * treats the "not-implemented" return value as a match */
+       g_warning ("%s: The library was built without phone number support.", G_STRFUNC);
+       return E_PHONE_NUMBER_MATCH_NONE;
+
+#endif /* ENABLE_PHONENUMBER */
+}
+
+/**
+ * e_phone_number_compare_strings:
+ * @first_number: the first EPhoneNumber to compare
+ * @second_number: the second EPhoneNumber to compare
+ * @error: (out): a #GError to set an error, if any
+ *
+ * Compares two phone numbers.
+ *
+ * Returns: The quality of matching for the two phone numbers.
+ *
+ * Since: 3.8
+ **/
+EPhoneNumberMatch
+e_phone_number_compare_strings (const gchar *first_number,
+                                const gchar *second_number,
+                                GError **error)
+{
+#ifdef ENABLE_PHONENUMBER
+
+       return _e_phone_number_cxx_compare_strings (first_number, second_number, error);
+
+#else /* ENABLE_PHONENUMBER */
+
+       _e_phone_number_set_error (error, E_PHONE_NUMBER_ERROR_NOT_IMPLEMENTED);
+       return E_PHONE_NUMBER_MATCH_NONE;
+
+#endif /* ENABLE_PHONENUMBER */
+}
+
+/**
+ * e_phone_number_copy:
+ * @phone_number: the EPhoneNumber to copy
+ *
+ * Makes a copy of @phone_number.
+ *
+ * Returns: (transfer full): A newly allocated EPhoneNumber instance.
+ * Call e_phone_number_free() to release this instance.
+ *
+ * Since: 3.8
+ **/
+EPhoneNumber *
+e_phone_number_copy (const EPhoneNumber *phone_number)
+{
+#ifdef ENABLE_PHONENUMBER
+
+       return _e_phone_number_cxx_copy (phone_number);
+
+#else /* ENABLE_PHONENUMBER */
+
+       /* Without phonenumber support there are no instances.
+        * Any non-NULL value is a programming error in this setup. */
+       g_warn_if_fail (phone_number == NULL);
+       return NULL;
+
+#endif /* ENABLE_PHONENUMBER */
+}
+
+/**
+ * e_phone_number_free:
+ * @phone_number: the EPhoneNumber to free
+ *
+ * Released the memory occupied by @phone_number.
+ *
+ * Since: 3.8
+ **/
+void
+e_phone_number_free (EPhoneNumber *phone_number)
+{
+#ifdef ENABLE_PHONENUMBER
+
+       _e_phone_number_cxx_free (phone_number);
+
+#else /* ENABLE_PHONENUMBER */
+
+       /* Without phonenumber support there are no instances.
+        * Any non-NULL value is a programming error in this setup. */
+       g_warn_if_fail (phone_number == NULL);
+
+#endif /* ENABLE_PHONENUMBER */
+}
diff --git a/libedataserver/e-phone-utils.h b/addressbook/libebook-contacts/e-phone-number.h
similarity index 62%
rename from libedataserver/e-phone-utils.h
rename to addressbook/libebook-contacts/e-phone-number.h
index e887c4f..3c39a40 100644
--- a/libedataserver/e-phone-utils.h
+++ b/addressbook/libebook-contacts/e-phone-number.h
@@ -1,6 +1,6 @@
 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
 /*
- * Copyright Copyright (C) 2012 Intel Corporation
+ * Copyright (C) 2012,2013 Intel Corporation
  *
  * 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
@@ -19,11 +19,8 @@
  * Author: Mathias Hasselmann <mathias openismus com>
  */
 
-/* NOTE: Keeping API documentation in this header file because gtkdoc-mkdb
- * explicitly only scans .h and .c files, but ignores .cpp files. */
-
 /**
- * SECTION: e-phone-utils
+ * SECTION: e-phone-number
  * @include: libedataserver/libedataserver.h
  * @short_description: Phone number support
  *
@@ -31,12 +28,12 @@
  * phone numbers. Under the hood it uses Google's libphonenumber.
  **/
 
-#if !defined (__LIBEDATASERVER_H_INSIDE__) && !defined (LIBEDATASERVER_COMPILATION)
-#error "Only <libedataserver/libedataserver.h> should be included directly."
+#if !defined (__LIBEBOOK_CONTACTS_H_INSIDE__) && !defined (LIBEBOOK_CONTACTS_COMPILATION)
+#error "Only <libebook-contacts/libebook-contacts.h> should be included directly."
 #endif
 
-#ifndef E_PHONE_UTILS_H
-#define E_PHONE_UTILS_H
+#ifndef E_PHONE_NUMBER_H
+#define E_PHONE_NUMBER_H
 
 #include <glib-object.h>
 
@@ -51,11 +48,13 @@ G_BEGIN_DECLS
  * @E_PHONE_NUMBER_FORMAT_INTERNATIONAL: a formatted phone number always
  * starting with the country calling code: "+49 30 55667788".
  * @E_PHONE_NUMBER_FORMAT_NATIONAL: a formatted phone number in national
- * scope, that is without country code: "(030) 55667788".
+ * scope, that is without country calling code: "(030) 55667788".
  * @E_PHONE_NUMBER_FORMAT_RFC3966: a tel: URL according to RFC 3966:
  * "tel:+49-30-55667788".
  *
  * The supported formatting rules for phone numbers.
+ *
+ * Since: 3.8
  **/
 typedef enum {
        E_PHONE_NUMBER_FORMAT_E164,
@@ -68,18 +67,19 @@ typedef enum {
  * EPhoneNumberMatch:
  * @E_PHONE_NUMBER_MATCH_NONE: The phone numbers did not match.
  * @E_PHONE_NUMBER_MATCH_EXACT: The phone numbers matched exactly.
- * @E_PHONE_NUMBER_MATCH_NATIONAL: There was no country code for at least
- * one of the numbers, but the national parts matched.
- * @E_PHONE_NUMBER_MATCH_SHORT: There was no country code for at least
- * one of the numbers, but one number might be part (suffix) of the other.
+ * @E_PHONE_NUMBER_MATCH_NATIONAL: There was no country calling code
+ * for at least one of the numbers, but the national parts matched.
+ * @E_PHONE_NUMBER_MATCH_SHORT: There was no country calling code for
+ * at least one of the numbers, but one number might be part (suffix)
+ * of the other.
  *
  * The quality of a phone number match.
 
  * Let's consider the phone number "+1-221-5423789", then comparing with
  * "+1.221.542.3789" we have get E_PHONE_NUMBER_MATCH_EXACT because country
  * code, region code and local number are matching. Comparing with "2215423789"
- * will result in E_PHONE_NUMBER_MATCH_NATIONAL because the country code is
- * missing, but the national portion is matching. Finally comparing with
+ * will result in E_PHONE_NUMBER_MATCH_NATIONAL because the country calling code
+ * is missing, but the national portion is matching. Finally comparing with
  * "5423789" gives E_PHONE_NUMBER_MATCH_SHORT. For more detail have a look at
  * the following table:
  *
@@ -125,7 +125,9 @@ typedef enum {
  *   </tr>
  *  </tbody>
  * </informaltable>
- */
+ *
+ * Since: 3.8
+ **/
 typedef enum {
        E_PHONE_NUMBER_MATCH_NONE,
        E_PHONE_NUMBER_MATCH_EXACT,
@@ -140,14 +142,16 @@ typedef enum {
  * @E_PHONE_NUMBER_ERROR_UNKNOWN: the phone number parser reported an yet
  * unkown error code.
  * @E_PHONE_NUMBER_ERROR_INVALID_COUNTRY_CODE: the supplied phone number has an
- * invalid country code.
+ * invalid country calling code.
  * @E_PHONE_NUMBER_ERROR_NOT_A_NUMBER: the supplied text is not a phone number.
  * @E_PHONE_NUMBER_ERROR_TOO_SHORT_AFTER_IDD: the remaining text after the
- * country code is to short for a phone number.
+ * country calling code is to short for a phone number.
  * @E_PHONE_NUMBER_ERROR_TOO_SHORT: the text is too short for a phone number.
  * @E_PHONE_NUMBER_ERROR_TOO_LONG: the text is too long for a phone number.
  *
  * Numeric description of a phone number related error.
+ *
+ * Since: 3.8
  **/
 typedef enum {
        E_PHONE_NUMBER_ERROR_NOT_IMPLEMENTED,
@@ -156,123 +160,68 @@ typedef enum {
        E_PHONE_NUMBER_ERROR_INVALID_COUNTRY_CODE,
        E_PHONE_NUMBER_ERROR_TOO_SHORT_AFTER_IDD,
        E_PHONE_NUMBER_ERROR_TOO_SHORT,
-       E_PHONE_NUMBER_ERROR_TOO_LONG,
+       E_PHONE_NUMBER_ERROR_TOO_LONG
 } EPhoneNumberError;
 
 /**
+ * EPhoneNumberCountrySource:
+ * @E_PHONE_NUMBER_COUNTRY_FROM_FQTN: the EPhoneNumber was build from a
+ * fully qualified telephone number that contained a valid country
+ * calling code
+ * @E_PHONE_NUMBER_COUNTRY_FROM_IDD: the parsed phone number started
+ * with the current locale's international call prefix, followed by a
+ * valid country calling code
+ * @E_PHONE_NUMBER_COUNTRY_FROM_DEFAULT: the parsed phone didn't start
+ * with a (recognizable) country calling code, the code was chosen by
+ * checking the current locale settings
+ *
+ * The origin of a parsed EPhoneNumber's country calling code.
+ *
+ * Since: 3.8
+ **/
+typedef enum {
+       E_PHONE_NUMBER_COUNTRY_FROM_FQTN = 1,
+       E_PHONE_NUMBER_COUNTRY_FROM_IDD = 5,
+       E_PHONE_NUMBER_COUNTRY_FROM_DEFAULT = 20
+} EPhoneNumberCountrySource;
+
+/**
  * EPhoneNumber:
  * This opaque type describes a parsed phone number. It can be copied using
  * e_phone_number_copy(). To release it call e_phone_number_free().
- */
+ *
+ * Since: 3.8
+ **/
 typedef struct _EPhoneNumber EPhoneNumber;
 
-GType                  e_phone_number_get_type         (void) G_GNUC_CONST;
-GQuark                 e_phone_number_error_quark      (void) G_GNUC_CONST;
+GType                  e_phone_number_get_type         (void);
+GQuark                 e_phone_number_error_quark      (void);
 
-/**
- * e_phone_number_is_supported:
- *
- * Checks if phone number support is available. It is recommended to call this
- * function before using any of the phone-utils functions to ensure that the
- * required functionality is available, and to pick alternative mechnisms if
- * needed.
- *
- * Returns: %TRUE if phone number support is available.
- */
 gboolean               e_phone_number_is_supported     (void) G_GNUC_CONST;
+gint                   e_phone_number_get_country_code_for_region
+                                                       (const gchar *region_code);
+gchar *                        e_phone_number_get_default_region
+                                                       (void);
 
-/**
- * e_phone_number_from_string:
- * @phone_number: the phone number to parse
- * @country_code: (allow-none): a 2-letter country code, or %NULL
- * @error: (out): a #GError to set an error, if any
- *
- * Parses the string passed in @phone_number. Note that no validation is
- * performed whether the recognized phone number is valid for a particular
- * region.
- *
- * The 2-letter country code passed in @country_code only is used if the
- * @phone_number is not written in international format. The applications's
- * currently locale is consulted if %NULL gets passed for @country_code.
- * If the number is guaranteed to start with a '+' followed by the country
- * calling code, then "ZZ" can be passed here.
- *
- * Returns: (transfer full): a new EPhoneNumber instance on success,
- * or %NULL on error. Call e_phone_number_free() to release this instance.
- *
- * Since: 3.8
- **/
 EPhoneNumber *         e_phone_number_from_string      (const gchar *phone_number,
-                                                        const gchar *country_code,
+                                                        const gchar *region_code,
                                                         GError **error);
-
-/**
- * e_phone_number_to_string:
- * @phone_number: the phone number to format
- * @format: the phone number format to apply
- *
- * Describes the @phone_number according to the rules applying to @format.
- *
- * Returns: (transfer full): A formatted string for @phone_number.
- *
- * Since: 3.8
- **/
 gchar *                        e_phone_number_to_string        (const EPhoneNumber *phone_number,
                                                         EPhoneNumberFormat format);
+gint                   e_phone_number_get_country_code (const EPhoneNumber *phone_number,
+                                                        EPhoneNumberCountrySource *source);
+gchar *                        e_phone_number_get_national_number
+                                                       (const EPhoneNumber *phone_number);
 
-/**
- * e_phone_number_compare:
- * @first_number: the first EPhoneNumber to compare
- * @second_number: the second EPhoneNumber to compare
- *
- * Compares two phone numbers.
- *
- * Returns: The quality of matching for the two phone numbers.
- *
- * Since: 3.8
- */
 EPhoneNumberMatch      e_phone_number_compare          (const EPhoneNumber *first_number,
                                                         const EPhoneNumber *second_number);
-
-/**
- * e_phone_number_compare_strings:
- * @first_number: the first EPhoneNumber to compare
- * @second_number: the second EPhoneNumber to compare
- * @error: (out): a #GError to set an error, if any
- *
- * Compares two phone numbers.
- *
- * Returns: The quality of matching for the two phone numbers.
- *
- * Since: 3.8
- */
 EPhoneNumberMatch      e_phone_number_compare_strings  (const gchar *first_number,
                                                         const gchar *second_number,
                                                         GError **error);
 
-/**
- * e_phone_number_copy:
- * @phone_number: the EPhoneNumber to copy
- *
- * Makes a copy of @phone_number.
- *
- * Returns: (transfer full): A newly allocated EPhoneNumber instance.
- * Call e_phone_number_free() to release this instance.
- *
- * Since: 3.8
- **/
 EPhoneNumber *         e_phone_number_copy             (const EPhoneNumber *phone_number);
-
-/**
- * e_phone_number_free:
- * @phone_number: the EPhoneNumber to free
- *
- * Released the memory occupied by @phone_number.
- *
- * Since: 3.8
- **/
 void                   e_phone_number_free             (EPhoneNumber *phone_number);
 
 G_END_DECLS
 
-#endif /* E_BOOK_BACKEND_FILE_PHONE_UTILS_H */
+#endif /* E_PHONE_NUMBER_H */
diff --git a/addressbook/libebook-contacts/libebook-contacts.h 
b/addressbook/libebook-contacts/libebook-contacts.h
index 92f95f3..1d02bf1 100644
--- a/addressbook/libebook-contacts/libebook-contacts.h
+++ b/addressbook/libebook-contacts/libebook-contacts.h
@@ -31,6 +31,7 @@
 #include <libebook-contacts/e-vcard.h>
 #include <libebook-contacts/e-book-contacts-enumtypes.h>
 #include <libebook-contacts/e-source-backend-summary-setup.h>
+#include <libebook-contacts/e-phone-number.h>
 
 #undef __LIBEBOOK_CONTACTS_H_INSIDE__
 
diff --git a/addressbook/libedata-book/e-book-backend-sqlitedb.c 
b/addressbook/libedata-book/e-book-backend-sqlitedb.c
index 2577262..6e0c74c 100644
--- a/addressbook/libedata-book/e-book-backend-sqlitedb.c
+++ b/addressbook/libedata-book/e-book-backend-sqlitedb.c
@@ -19,11 +19,11 @@
  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
  */
 
+#include "e-book-backend-sqlitedb.h"
+
+#include <locale.h>
 #include <string.h>
-#include <ctype.h>
-#include <stdlib.h>
 #include <errno.h>
-#include <langinfo.h>
 
 #include <glib/gi18n.h>
 #include <glib/gstdio.h>
@@ -32,7 +32,6 @@
 #include <libebackend/libebackend.h>
 
 #include "e-book-backend-sexp.h"
-#include "e-book-backend-sqlitedb.h"
 
 #define E_BOOK_BACKEND_SQLITEDB_GET_PRIVATE(obj) \
        (G_TYPE_INSTANCE_GET_PRIVATE \
@@ -40,18 +39,33 @@
 
 #define d(x)
 
-#define DB_FILENAME "contacts.db"
-#define FOLDER_VERSION 4
+#if d(1)+0
+#  define LOCK_MUTEX(mutex)                                    \
+       G_STMT_START {                                          \
+               g_message ("%s: DB Locking ", G_STRFUNC);       \
+               g_mutex_lock (mutex);                           \
+               g_message ("%s: DB Locked ", G_STRFUNC);        \
+       } G_STMT_END
+
+
+#  define UNLOCK_MUTEX(mutex)                                  \
+       G_STMT_START {                                          \
+               g_message ("%s: Unlocking ", G_STRFUNC);        \
+               g_mutex_unlock (mutex);                         \
+               g_message ("%s: DB Unlocked ", G_STRFUNC);      \
+       } G_STMT_END
+#else
+#  define LOCK_MUTEX(mutex)   g_mutex_lock (mutex)
+#  define UNLOCK_MUTEX(mutex) g_mutex_unlock (mutex)
+#endif
 
-#define READER_LOCK(ebsdb) g_static_rw_lock_reader_lock (&ebsdb->priv->rwlock)
-#define READER_UNLOCK(ebsdb) g_static_rw_lock_reader_unlock (&ebsdb->priv->rwlock)
-#define WRITER_LOCK(ebssdb) g_static_rw_lock_writer_lock (&ebsdb->priv->rwlock)
-#define WRITER_UNLOCK(ebssdb) g_static_rw_lock_writer_unlock (&ebsdb->priv->rwlock)
+#define DB_FILENAME "contacts.db"
+#define FOLDER_VERSION 5
 
 typedef enum {
        INDEX_PREFIX = (1 << 0),
        INDEX_SUFFIX = (1 << 1),
-       INDEX_PHONE  = (1 << 2),
+       INDEX_PHONE  = (1 << 2)
 } IndexFlags;
 
 typedef struct {
@@ -66,25 +80,23 @@ struct _EBookBackendSqliteDBPrivate {
        gchar *path;
        gchar *hash_key;
 
-       gboolean store_vcard;
-       GStaticRWLock rwlock;
+       GMutex lock;
+       GMutex updates_lock; /* This is for deprecated e_book_backend_sqlitedb_lock_updates() */
 
-       GMutex *in_transaction_lock;
+       gboolean store_vcard;
        guint32 in_transaction;
 
        SummaryField   *summary_fields;
        gint            n_summary_fields;
        guint           have_attr_list : 1;
        IndexFlags      attr_list_indexes;
-
-       gchar          *country_code;
 };
 
 G_DEFINE_TYPE (EBookBackendSqliteDB, e_book_backend_sqlitedb, G_TYPE_OBJECT)
 
 
 static GHashTable *db_connections = NULL;
-static GStaticMutex dbcon_lock = G_STATIC_MUTEX_INIT;
+static GMutex dbcon_lock;
 
 static EContactField default_summary_fields[] = {
        E_CONTACT_UID,
@@ -94,21 +106,18 @@ static EContactField default_summary_fields[] = {
        E_CONTACT_FULL_NAME,
        E_CONTACT_GIVEN_NAME,
        E_CONTACT_FAMILY_NAME,
-       E_CONTACT_EMAIL_1,
-       E_CONTACT_EMAIL_2,
-       E_CONTACT_EMAIL_3,
-       E_CONTACT_EMAIL_4,
+       E_CONTACT_EMAIL,
        E_CONTACT_IS_LIST,
        E_CONTACT_LIST_SHOW_ADDRESSES,
        E_CONTACT_WANTS_HTML
 };
 
-/* Create indexes on full_name and email_1 as autocompletion queries would mainly
- * rely on this. Assuming that the frequency of matching on these would be higher than
- * on the other fields like email_2, surname etc. email_1 should be the primary email */
+/* Create indexes on full_name and email fields as autocompletion queries would mainly
+ * rely on this.
+ */
 static EContactField default_indexed_fields[] = {
        E_CONTACT_FULL_NAME,
-       E_CONTACT_EMAIL_1
+       E_CONTACT_EMAIL
 };
 
 static EBookIndexType default_index_types[] = {
@@ -116,17 +125,18 @@ static EBookIndexType default_index_types[] = {
        E_BOOK_INDEX_PREFIX
 };
 
-static gboolean append_summary_field (GArray         *array,
-                                     EContactField   field,
-                                     gboolean       *have_attr_list,
-                                     GError        **error);
+static SummaryField * append_summary_field (GArray         *array,
+                                           EContactField   field,
+                                           gboolean       *have_attr_list,
+                                           GError        **error);
 
-static gboolean validate_county_code (EBookBackendSqliteDB  *ebsdb,
-                                      const gchar           *folderid,
-                                      GError               **error);
+static gboolean upgrade_contacts_table (EBookBackendSqliteDB  *ebsdb,
+                                        const gchar           *folderid,
+                                        GError               **error);
 
 static const gchar *
-summary_dbname_from_field (EBookBackendSqliteDB *ebsdb, EContactField field)
+summary_dbname_from_field (EBookBackendSqliteDB *ebsdb,
+                           EContactField field)
 {
        gint i;
 
@@ -134,11 +144,13 @@ summary_dbname_from_field (EBookBackendSqliteDB *ebsdb, EContactField field)
                if (ebsdb->priv->summary_fields[i].field == field)
                        return ebsdb->priv->summary_fields[i].dbname;
        }
+
        return NULL;
 }
 
 static gint
-summary_index_from_field_name (EBookBackendSqliteDB *ebsdb, const gchar *field_name)
+summary_index_from_field_name (EBookBackendSqliteDB *ebsdb,
+                               const gchar *field_name)
 {
        gint i;
        EContactField field;
@@ -153,24 +165,14 @@ summary_index_from_field_name (EBookBackendSqliteDB *ebsdb, const gchar *field_n
        return -1;
 }
 
-
 typedef struct {
        EBookBackendSqliteDB *ebsdb;
        GSList *list;
 } StoreVCardData;
 
-GQuark
-e_book_backend_sqlitedb_error_quark (void)
-{
-       static GQuark quark = 0;
-
-       if (G_UNLIKELY (quark == 0)) {
-               const gchar *string = "e-book-backend-sqlitedb-error-quark";
-               quark = g_quark_from_static_string (string);
-       }
-
-       return quark;
-}
+G_DEFINE_QUARK (
+       e-book-backend-sqlitedb-error-quark,
+       e_book_backend_sqlitedb_error)
 
 static void
 e_book_backend_sqlitedb_dispose (GObject *object)
@@ -179,7 +181,7 @@ e_book_backend_sqlitedb_dispose (GObject *object)
 
        priv = E_BOOK_BACKEND_SQLITEDB_GET_PRIVATE (object);
 
-       g_static_mutex_lock (&dbcon_lock);
+       g_mutex_lock (&dbcon_lock);
        if (db_connections != NULL) {
                if (priv->hash_key != NULL) {
                        g_hash_table_remove (db_connections, priv->hash_key);
@@ -193,7 +195,7 @@ e_book_backend_sqlitedb_dispose (GObject *object)
                        priv->hash_key = NULL;
                }
        }
-       g_static_mutex_unlock (&dbcon_lock);
+       g_mutex_unlock (&dbcon_lock);
 
        /* Chain up to parent's dispose() method. */
        G_OBJECT_CLASS (e_book_backend_sqlitedb_parent_class)->dispose (object);
@@ -206,15 +208,13 @@ e_book_backend_sqlitedb_finalize (GObject *object)
 
        priv = E_BOOK_BACKEND_SQLITEDB_GET_PRIVATE (object);
 
-       g_static_rw_lock_free (&priv->rwlock);
-
        sqlite3_close (priv->db);
 
        g_free (priv->path);
        g_free (priv->summary_fields);
-       g_free (priv->country_code);
 
-       g_mutex_free (priv->in_transaction_lock);
+       g_mutex_clear (&priv->lock);
+       g_mutex_clear (&priv->updates_lock);
 
        /* Chain up to parent's finalize() method. */
        G_OBJECT_CLASS (e_book_backend_sqlitedb_parent_class)->finalize (object);
@@ -238,10 +238,10 @@ e_book_backend_sqlitedb_init (EBookBackendSqliteDB *ebsdb)
        ebsdb->priv = E_BOOK_BACKEND_SQLITEDB_GET_PRIVATE (ebsdb);
 
        ebsdb->priv->store_vcard = TRUE;
-       g_static_rw_lock_init (&ebsdb->priv->rwlock);
 
        ebsdb->priv->in_transaction = 0;
-       ebsdb->priv->in_transaction_lock = g_mutex_new ();
+       g_mutex_init (&ebsdb->priv->lock);
+       g_mutex_init (&ebsdb->priv->updates_lock);
 }
 
 static gint
@@ -278,18 +278,18 @@ get_bool_cb (gpointer ref,
  * @data:
  * @error:
  *
- *  Callers should hold the rw lock depending on read or write operation
+ * Callers should hold the rw lock depending on read or write operation
  * Returns:
  **/
 static gboolean
 book_backend_sql_exec_real (sqlite3 *db,
-                           const gchar *stmt,
-                           gint (*callback)(gpointer ,gint,gchar **,gchar **),
-                           gpointer data,
-                           GError **error)
+                            const gchar *stmt,
+                            gint (*callback)(gpointer ,gint,gchar **,gchar **),
+                            gpointer data,
+                            GError **error)
 {
        gchar *errmsg = NULL;
-       gint   ret = -1;
+       gint ret = -1;
 
        ret = sqlite3_exec (db, stmt, callback, data, &errmsg);
        while (ret == SQLITE_BUSY || ret == SQLITE_LOCKED || ret == -1) {
@@ -302,13 +302,12 @@ book_backend_sql_exec_real (sqlite3 *db,
        }
 
        if (ret != SQLITE_OK) {
-               d(g_print ("Error in SQL EXEC statement: %s [%s] RETURN CODE: %d.\n", stmt, errmsg, ret));
-
-               g_set_error (
+               d (g_printerr ("Error in SQL EXEC statement: %s [%s].\n", stmt, errmsg));
+               g_set_error_literal (
                        error, E_BOOK_SDB_ERROR,
                        ret == SQLITE_CONSTRAINT ?
                        E_BOOK_SDB_ERROR_CONSTRAINT : E_BOOK_SDB_ERROR_OTHER,
-                       "%s", errmsg);
+                       errmsg);
                sqlite3_free (errmsg);
                errmsg = NULL;
                return FALSE;
@@ -324,37 +323,57 @@ book_backend_sql_exec_real (sqlite3 *db,
 
 static gint
 print_debug_cb (gpointer ref,
-               gint col,
-               gchar **cols,
-               gchar **name)
+               gint n_cols,
+                gchar **cols,
+                gchar **name)
 {
        gint i;
 
-       g_print ("  DEBUG BEGIN: %d results\n", col);
+       g_printerr ("  DEBUG BEGIN:\n");
 
-       for (i = 0; i < col; i++)
-               g_print ("    NAME: '%s' COL: %s\n", name[i], cols[i]);
+       for (i = 0; i < n_cols; i++)
+               g_printerr ("    NAME: '%s' VALUE: %s\n", name[i], cols[i]);
 
-       g_print ("  DEBUG END\n");
+       g_printerr ("  DEBUG END\n");
 
        return 0;
 }
 
+static gint G_GNUC_CONST
+booksql_debug (void)
+{
+       static gint booksql_debug = -1;
+
+       if (booksql_debug == -1) {
+               const gchar *const tmp = g_getenv ("BOOKSQL_DEBUG");
+               booksql_debug = (tmp != NULL ? MAX (0, atoi (tmp)) : 0);
+       }
+
+       return booksql_debug;
+}
+
 static void
 book_backend_sql_debug (sqlite3 *db,
-                       const gchar *stmt,
-                       gint (*callback)(gpointer ,gint,gchar **,gchar **),
-                       gpointer data,
-                       GError **error)
+                        const gchar *stmt,
+                        gint (*callback)(gpointer ,gint,gchar **,gchar **),
+                        gpointer data,
+                        GError **error)
 {
-       gchar *debug;
        GError *local_error = NULL;
-       debug = g_strconcat ("EXPLAIN QUERY PLAN ", stmt, NULL);
 
-       g_print ("DEBUG STATEMENT: %s\n", stmt);
-       book_backend_sql_exec_real (db, debug, print_debug_cb, NULL, &local_error);
-       g_print ("DEBUG STATEMENT END: %s%s\n", local_error ? "Error: " : "", local_error ? 
local_error->message : "Success");
-       g_free (debug);
+       g_printerr ("DEBUG STATEMENT: %s\n", stmt);
+
+       if (booksql_debug () > 1) {
+               gchar *debug = g_strconcat ("EXPLAIN QUERY PLAN ", stmt, NULL);
+               book_backend_sql_exec_real (db, debug, print_debug_cb, NULL, &local_error);
+               g_free (debug);
+       }
+
+       if (local_error) {
+               g_printerr ("DEBUG STATEMENT END: Error: %s\n", local_error->message);
+       } else if (booksql_debug () > 1) {
+               g_printerr ("DEBUG STATEMENT END: Success\n");
+       }
 
        g_clear_error (&local_error);
 }
@@ -366,210 +385,233 @@ book_backend_sql_exec (sqlite3 *db,
                        gpointer data,
                        GError **error)
 {
-       static gint booksql_debug = -1;
-
-       if (booksql_debug == -1) {
-               booksql_debug = g_getenv ("BOOKSQL_DEBUG") != NULL ? 1 : 0;
-       }
-
-       if (booksql_debug)
+       if (booksql_debug ())
                book_backend_sql_debug (db, stmt, callback, data, error);
 
        return book_backend_sql_exec_real (db, stmt, callback, data, error);
 }
 
-/* the first caller holds the writer lock too */
+/* This function must always be called with the priv->lock held */
 static gboolean
 book_backend_sqlitedb_start_transaction (EBookBackendSqliteDB *ebsdb,
                                          GError **error)
 {
-       gboolean res = TRUE;
+       gboolean success = TRUE;
 
        g_return_val_if_fail (ebsdb != NULL, FALSE);
        g_return_val_if_fail (ebsdb->priv != NULL, FALSE);
        g_return_val_if_fail (ebsdb->priv->db != NULL, FALSE);
 
-       g_mutex_lock (ebsdb->priv->in_transaction_lock);
-
        ebsdb->priv->in_transaction++;
-       if (ebsdb->priv->in_transaction == 0) {
-               g_mutex_unlock (ebsdb->priv->in_transaction_lock);
-
-               g_return_val_if_fail (ebsdb->priv->in_transaction != 0, FALSE);
-               return FALSE;
-       }
+       g_return_val_if_fail (ebsdb->priv->in_transaction > 0, FALSE);
 
        if (ebsdb->priv->in_transaction == 1) {
-               WRITER_LOCK (ebsdb);
 
-               res = book_backend_sql_exec (ebsdb->priv->db, "BEGIN", NULL, NULL, error);
+               success = book_backend_sql_exec (
+                       ebsdb->priv->db, "BEGIN", NULL, NULL, error);
        }
 
-       g_mutex_unlock (ebsdb->priv->in_transaction_lock);
-
-       return res;
+       return success;
 }
 
-/* the last caller releases the writer lock too */
+/* This function must always be called with the priv->lock held */
 static gboolean
-book_backend_sqlitedb_end_transaction (EBookBackendSqliteDB *ebsdb,
-                                       gboolean do_commit,
-                                       GError **error)
+book_backend_sqlitedb_commit_transaction (EBookBackendSqliteDB *ebsdb,
+                                          GError **error)
 {
-       gboolean res = TRUE;
+       gboolean success = TRUE;
 
        g_return_val_if_fail (ebsdb != NULL, FALSE);
        g_return_val_if_fail (ebsdb->priv != NULL, FALSE);
        g_return_val_if_fail (ebsdb->priv->db != NULL, FALSE);
 
-       g_mutex_lock (ebsdb->priv->in_transaction_lock);
-       if (ebsdb->priv->in_transaction == 0) {
-               g_mutex_unlock (ebsdb->priv->in_transaction_lock);
+       g_return_val_if_fail (ebsdb->priv->in_transaction > 0, FALSE);
 
-               g_return_val_if_fail (ebsdb->priv->in_transaction > 0, FALSE);
-               return FALSE;
+       ebsdb->priv->in_transaction--;
+
+       if (ebsdb->priv->in_transaction == 0) {
+               success = book_backend_sql_exec (
+                       ebsdb->priv->db, "COMMIT", NULL, NULL, error);
        }
 
+       return success;
+}
+
+/* This function must always be called with the priv->lock held */
+static gboolean
+book_backend_sqlitedb_rollback_transaction (EBookBackendSqliteDB *ebsdb,
+                                            GError **error)
+{
+       gboolean success = TRUE;
+
+       g_return_val_if_fail (ebsdb != NULL, FALSE);
+       g_return_val_if_fail (ebsdb->priv != NULL, FALSE);
+       g_return_val_if_fail (ebsdb->priv->db != NULL, FALSE);
+
+       g_return_val_if_fail (ebsdb->priv->in_transaction > 0, FALSE);
+
        ebsdb->priv->in_transaction--;
 
        if (ebsdb->priv->in_transaction == 0) {
-               res = book_backend_sql_exec (ebsdb->priv->db, do_commit ? "COMMIT" : "ROLLBACK", NULL, NULL, 
error);
+               success = book_backend_sql_exec (
+                       ebsdb->priv->db, "ROLLBACK", NULL, NULL, error);
 
-               WRITER_UNLOCK (ebsdb);
        }
-
-       g_mutex_unlock (ebsdb->priv->in_transaction_lock);
-
-       return res;
+       return success;
 }
 
 static gint
 collect_versions_cb (gpointer ref,
-                    gint col,
-                    gchar **cols,
-                    gchar **name)
+                     gint col,
+                     gchar **cols,
+                     gchar **name)
 {
        gint *ret = ref;
 
-       /* Just collect the first result, all folders should always have the same DB version */
+       /* Just collect the first result, all folders
+        * should always have the same DB version. */
        *ret = cols [0] ? strtoul (cols [0], NULL, 10) : 0;
 
        return 0;
 }
 
-static void
+static gboolean
 create_folders_table (EBookBackendSqliteDB *ebsdb,
+                      gint *previous_schema,
                       GError **error)
 {
-       GError *err = NULL;
-       gint    version = 0;
+       gboolean success;
+       gint version = 0;
 
-       /* sync_data points to syncronization data, it could be last_modified time
-        * or a sequence number or some text depending on the backend.
+       /* sync_data points to syncronization data, it could be last_modified
+        * time or a sequence number or some text depending on the backend.
         *
-        * partial_content says whether the contents are partially downloaded for
-        * auto-completion or if it has the complete content.
+        * partial_content says whether the contents are partially downloaded
+        * for auto-completion or if it has the complete content.
         *
-        * Have not included a bdata here since the keys table should suffice any
-        * additional need that arises.
+        * Have not included a bdata here since the keys table should suffice
+        * any additional need that arises.
         */
        const gchar *stmt =
                "CREATE TABLE IF NOT EXISTS folders"
                "( folder_id  TEXT PRIMARY KEY,"
                " folder_name TEXT,"
                "  sync_data TEXT,"
-               " is_populated INTEGER,"
-               "  partial_content INTEGER,"
+               " is_populated INTEGER DEFAULT 0,"
+               "  partial_content INTEGER DEFAULT 0,"
                " version INTEGER,"
                "  revision TEXT,"
-               " multivalues TEXT,"
-               "  reverse_multivalues INTEGER,"
-               " countrycode VARCHAR(2) )";
+               " multivalues TEXT )";
 
        if (!book_backend_sqlitedb_start_transaction (ebsdb, error))
-               return;
+               return FALSE;
 
-       if (!err)
-               book_backend_sql_exec (ebsdb->priv->db, stmt, NULL, NULL , &err);
+       if (!book_backend_sql_exec (ebsdb->priv->db, stmt, NULL, NULL, error))
+               goto rollback;
 
-       /* Create a child table to store key/value pairs for a folder */
-       if (!err) {
-               stmt =  "CREATE TABLE IF NOT EXISTS keys"
-                       "( key TEXT PRIMARY KEY, value TEXT,"
-                       " folder_id TEXT REFERENCES folders)";
-               book_backend_sql_exec (ebsdb->priv->db, stmt, NULL, NULL, &err);
-       }
+       /* Create a child table to store key/value pairs for a folder. */
+       stmt =  "CREATE TABLE IF NOT EXISTS keys"
+               "( key TEXT PRIMARY KEY, value TEXT,"
+               " folder_id TEXT REFERENCES folders)";
+       if (!book_backend_sql_exec (ebsdb->priv->db, stmt, NULL, NULL, error))
+               goto rollback;
 
-       if (!err) {
-               stmt = "CREATE INDEX IF NOT EXISTS keysindex ON keys(folder_id)";
-               book_backend_sql_exec (ebsdb->priv->db, stmt, NULL, NULL, &err);
-       }
+       stmt = "CREATE INDEX IF NOT EXISTS keysindex ON keys(folder_id)";
+       if (!book_backend_sql_exec (ebsdb->priv->db, stmt, NULL, NULL, error))
+               goto rollback;
 
-       /* Fetch the version, it should be the same for all folders (hence the LIMIT) */
-       if (!err) {
-               stmt = "SELECT version FROM folders LIMIT 1";
-               book_backend_sql_exec (ebsdb->priv->db, stmt, collect_versions_cb, &version, &err);
-       }
+       /* Fetch the version, it should be the
+        * same for all folders (hence the LIMIT). */
+       stmt = "SELECT version FROM folders LIMIT 1";
+       success = book_backend_sql_exec (
+               ebsdb->priv->db, stmt, collect_versions_cb, &version, error);
+
+       if (!success)
+               goto rollback;
 
        /* Upgrade DB to version 2, add revision column
         *
-        * (version = 0 indicates that it did not exist and we just created the table)
+        * (version = 0 indicates that it did not exist and we just
+        * created the table)
         */
-       if (!err && version >= 1 && version < 2) {
+       if (version >= 1 && version < 2) {
                stmt = "ALTER TABLE folders ADD COLUMN revision TEXT";
-               book_backend_sql_exec (
-                       ebsdb->priv->db, stmt, NULL, NULL, &err);
+               success = book_backend_sql_exec (
+                       ebsdb->priv->db, stmt, NULL, NULL, error);
+
+               if (!success)
+                       goto rollback;
        }
 
        /* Upgrade DB to version 3, add multivalues introspection columns
         */
-       if (!err && version >= 1 && version < 3) {
+       if (version >= 1 && version < 3) {
                stmt = "ALTER TABLE folders ADD COLUMN multivalues TEXT";
-               book_backend_sql_exec (
-                       ebsdb->priv->db, stmt, NULL, NULL, &err);
+               success = book_backend_sql_exec (
+                       ebsdb->priv->db, stmt, NULL, NULL, error);
 
-               stmt = "ALTER TABLE folders ADD COLUMN reverse_multivalues INTEGER";
-               book_backend_sql_exec (
-                       ebsdb->priv->db, stmt, NULL, NULL, &err);
+               if (!success)
+                       goto rollback;
        }
 
-       /* Upgrade DB to version 4, add country-code column
+       /* Upgrade DB to version 4: Nothing to do. The country-code column it
+        * added got redundant already.
         */
-       if (!err && version >= 1 && version < 4) {
-               stmt = "ALTER TABLE folders ADD COLUMN countrycode VARCHAR(2)";
-               book_backend_sql_exec (
-                       ebsdb->priv->db, stmt, NULL, NULL, &err);
+
+       /* Upgrade DB to version 5: Drop the reverse_multivalues column, but
+        * wait with converting phone summary values to new format until
+        * create_contacts_table() as we need introspection details for doing
+        * that.
+        */
+       if (version >= 3 && version < FOLDER_VERSION) {
+               stmt = "UPDATE folders SET "
+                               "multivalues = REPLACE(RTRIM(REPLACE("
+                                       "multivalues || ':', ':', "
+                                       "CASE reverse_multivalues "
+                                               "WHEN 0 THEN ';prefix ' "
+                                               "ELSE ';prefix;suffix ' "
+                                       "END)), ' ', ':'), "
+                               "reverse_multivalues = NULL";
+
+               success = book_backend_sql_exec (
+                       ebsdb->priv->db, stmt, NULL, NULL, error);
+
+               if (!success)
+                       goto rollback;
        }
 
-       if (!err && version >= 1 && version < FOLDER_VERSION) {
+       /* Finish the eventual upgrade by storing the current schema version.
+        */
+       if (version >= 1 && version < FOLDER_VERSION) {
                gchar *version_update_stmt =
                        sqlite3_mprintf ("UPDATE folders SET version = %d", FOLDER_VERSION);
 
-               book_backend_sql_exec (
-                       ebsdb->priv->db, version_update_stmt, NULL, NULL, &err);
+               success = book_backend_sql_exec (
+                       ebsdb->priv->db, version_update_stmt, NULL, NULL, error);
 
                sqlite3_free (version_update_stmt);
        }
 
-       book_backend_sqlitedb_end_transaction (ebsdb, !err, err ? NULL : &err);
+       if (!success)
+               goto rollback;
 
-       if (err) {
-               g_warning ("Error creating folders table: %s", err->message);
-               g_propagate_error (error, err);
-       }
+       *previous_schema = version;
+       return book_backend_sqlitedb_commit_transaction (ebsdb, error);
 
-       return;
-}
+rollback:
+       /* The GError is already set. */
+       book_backend_sqlitedb_rollback_transaction (ebsdb, NULL);
 
+       *previous_schema = 0;
+       return FALSE;
+}
 
 static gchar *
-format_multivalues (EBookBackendSqliteDB *ebsdb,
-                   IndexFlags           *computed_multivalues)
+format_multivalues (EBookBackendSqliteDB *ebsdb)
 {
        gint i;
        GString *string;
        gboolean first = TRUE;
-       IndexFlags computed = 0;
 
        string = g_string_new (NULL);
 
@@ -583,60 +625,60 @@ format_multivalues (EBookBackendSqliteDB *ebsdb,
                        g_string_append (string, ebsdb->priv->summary_fields[i].dbname);
 
                        if ((ebsdb->priv->summary_fields[i].index & INDEX_PREFIX) != 0)
-                               computed |= INDEX_PREFIX;
+                               g_string_append (string, ";prefix");
                        if ((ebsdb->priv->summary_fields[i].index & INDEX_SUFFIX) != 0)
-                               computed |= INDEX_SUFFIX;
+                               g_string_append (string, ";suffix");
                        if ((ebsdb->priv->summary_fields[i].index & INDEX_PHONE) != 0)
-                               computed |= INDEX_PHONE;
+                               g_string_append (string, ";phone");
                }
        }
 
-       if (computed_multivalues)
-               *computed_multivalues = computed;
-
        return g_string_free (string, FALSE);
 }
 
-static void
+static gboolean
 add_folder_into_db (EBookBackendSqliteDB *ebsdb,
                     const gchar *folderid,
                     const gchar *folder_name,
                     GError **error)
 {
        gchar *stmt;
-       GError *err = NULL;
-       IndexFlags computed = 0;
+       gboolean success;
        gchar *multivalues;
 
-       book_backend_sqlitedb_start_transaction (ebsdb, &err);
+       if (!book_backend_sqlitedb_start_transaction (ebsdb, error))
+               return FALSE;
 
-       multivalues = format_multivalues (ebsdb, &computed);
+       multivalues = format_multivalues (ebsdb);
 
        stmt = sqlite3_mprintf (
-               "INSERT OR IGNORE INTO folders VALUES "
-               "( %Q, %Q, %Q, %d, %d, %d, %Q, %Q, %d, %Q ) ",
-               folderid, folder_name, NULL, 0, 0, FOLDER_VERSION,
-               NULL, multivalues, computed, NULL);
-       book_backend_sql_exec (
+               "INSERT OR IGNORE INTO "
+               "folders ( folder_id, folder_name, version, multivalues ) "
+               "VALUES ( %Q, %Q, %d, %Q ) ",
+               folderid, folder_name, FOLDER_VERSION, multivalues);
+       success = book_backend_sql_exec (
                ebsdb->priv->db, stmt, NULL, NULL, error);
        sqlite3_free (stmt);
        g_free (multivalues);
 
-       book_backend_sqlitedb_end_transaction (ebsdb, !err, err ? NULL : &err);
+       if (!success)
+               goto rollback;
+
+       return book_backend_sqlitedb_commit_transaction (ebsdb, error);
 
-       if (err)
-               g_propagate_error (error, err);
+rollback:
+       book_backend_sqlitedb_rollback_transaction (ebsdb, NULL);
 
-       return;
+       return FALSE;
 }
 
 static gint
 collect_columns_cb (gpointer ref,
-                   gint col,
-                   gchar **cols,
-                   gchar **name)
+                    gint col,
+                    gchar **cols,
+                    gchar **name)
 {
-       GList **columns = (GList **)ref;
+       GList **columns = (GList **) ref;
        gint i;
 
        for (i = 0; i < col; i++) {
@@ -660,17 +702,15 @@ collect_columns_cb (gpointer ref,
 
 static gboolean
 introspect_summary (EBookBackendSqliteDB *ebsdb,
-                   const gchar *folderid,
-                   GError **error)
+                    const gchar *folderid,
+                    GError **error)
 {
        gboolean success;
        gchar *stmt;
        GList *summary_columns = NULL, *l;
        GArray *summary_fields = NULL;
        gchar *multivalues = NULL;
-       IndexFlags computed_multivalues = 0;
-       gchar **split;
-       gint i;
+       gint i, j;
 
        stmt = sqlite3_mprintf ("PRAGMA table_info (%Q);", folderid);
        success = book_backend_sql_exec (
@@ -700,9 +740,9 @@ introspect_summary (EBookBackendSqliteDB *ebsdb,
                }
 
                /* First check exception fields */
-               if (strcmp (col, "uid") == 0)
+               if (g_ascii_strcasecmp (col, "uid") == 0)
                        field = E_CONTACT_UID;
-               else if (strcmp (col, "is_list") == 0)
+               else if (g_ascii_strcasecmp (col, "is_list") == 0)
                        field = E_CONTACT_IS_LIST;
                else
                        field = e_contact_field_id (col);
@@ -747,61 +787,46 @@ introspect_summary (EBookBackendSqliteDB *ebsdb,
        if (!success)
                goto introspect_summary_finish;
 
-       stmt = sqlite3_mprintf (
-               "SELECT reverse_multivalues FROM folders WHERE folder_id = %Q", folderid);
-       success = book_backend_sql_exec (
-               ebsdb->priv->db, stmt, get_bool_cb, &computed_multivalues, error);
-       sqlite3_free (stmt);
-
-       if (!success)
-               goto introspect_summary_finish;
-
        if (multivalues) {
-               split = g_strsplit (multivalues, ":", 0);
+               gchar **fields = g_strsplit (multivalues, ":", 0);
 
-               for (i = 0; split[i] != NULL; i++) {
+               for (i = 0; fields[i] != NULL; i++) {
                        EContactField field;
+                       SummaryField *iter;
+                       gchar **params;
+
+                       params = g_strsplit (fields[i], ";", 0);
+                       field = e_contact_field_id (params[0]);
+                       iter = append_summary_field (summary_fields, field, NULL, NULL);
+
+                       if (iter) {
+                               for (j = 1; params[j]; ++j) {
+                                       if (strcmp (params[j], "prefix") == 0) {
+                                               iter->index |= INDEX_PREFIX;
+                                       } else if (strcmp (params[j], "suffix") == 0) {
+                                               iter->index |= INDEX_SUFFIX;
+                                       } else if (strcmp (params[j], "phone") == 0) {
+                                               iter->index |= INDEX_PHONE;
+                                       }
+                               }
+                       }
 
-                       field = e_contact_field_id (split[i]);
-                       append_summary_field (summary_fields, field, NULL, NULL);
+                       g_strfreev (params);
                }
-               g_strfreev (split);
-       }
 
-       /* With at least one reverse index the multi-value table has a reverse multivalue
-        * column. Therefore it's safe to enable reverse lookups for every multivalue field.
-        */
-       computed_multivalues &= (INDEX_SUFFIX | INDEX_PHONE);
-
-       if (computed_multivalues) {
-               for (i = 0; i < summary_fields->len; i++) {
-                       SummaryField *iter = &g_array_index (summary_fields, SummaryField, i);
-
-                       if (iter->type == E_TYPE_CONTACT_ATTR_LIST)
-                               iter->index |= computed_multivalues;
-               }
+               g_strfreev (fields);
        }
 
-       /* Retreive the country code used for guessing phone numbers */
-       stmt = sqlite3_mprintf (
-               "SELECT countrycode FROM folders WHERE folder_id = %Q", folderid);
-       success = book_backend_sql_exec (
-               ebsdb->priv->db, stmt, get_string_cb, &ebsdb->priv->country_code, error);
-       sqlite3_free (stmt);
-
-       if (!success)
-               goto introspect_summary_finish;
-
  introspect_summary_finish:
 
-       g_list_free_full (summary_columns, (GDestroyNotify)g_free);
+       g_list_free_full (summary_columns, (GDestroyNotify) g_free);
        g_free (multivalues);
 
        /* Apply the introspected summary fields */
        if (success) {
                g_free (ebsdb->priv->summary_fields);
                ebsdb->priv->n_summary_fields = summary_fields->len;
-               ebsdb->priv->summary_fields = (SummaryField *)g_array_free (summary_fields, FALSE);
+               ebsdb->priv->summary_fields = (SummaryField *) g_array_free (summary_fields, FALSE);
        } else if (summary_fields) {
                g_array_free (summary_fields, TRUE);
        }
@@ -809,21 +834,21 @@ introspect_summary (EBookBackendSqliteDB *ebsdb,
        return success;
 }
 
-
 /* The column names match the fields used in book-backend-sexp */
 static gboolean
 create_contacts_table (EBookBackendSqliteDB *ebsdb,
                        const gchar *folderid,
+                       gint previous_schema,
                        GError **error)
 {
        gint i;
-       gboolean ret;
+       gboolean success;
        gchar *stmt, *tmp;
-       GError *err = NULL;
        GString *string;
 
        /* Construct the create statement from the summary fields table */
-       string = g_string_new ("CREATE TABLE IF NOT EXISTS %Q ( uid TEXT PRIMARY KEY, ");
+       string = g_string_new (
+               "CREATE TABLE IF NOT EXISTS %Q ( uid TEXT PRIMARY KEY, ");
 
        for (i = 1; i < ebsdb->priv->n_summary_fields; i++) {
                if (ebsdb->priv->summary_fields[i].type == G_TYPE_STRING) {
@@ -853,34 +878,40 @@ create_contacts_table (EBookBackendSqliteDB *ebsdb,
        stmt = sqlite3_mprintf (string->str, folderid);
        g_string_free (string, TRUE);
 
-       WRITER_LOCK (ebsdb);
-       ret = book_backend_sql_exec (ebsdb->priv->db, stmt, NULL, NULL , &err);
+       success = book_backend_sql_exec (
+               ebsdb->priv->db, stmt, NULL, NULL , error);
+
        sqlite3_free (stmt);
 
        /* Create indexes on the summary fields configured for indexing */
-       for (i = 0; !err && i < ebsdb->priv->n_summary_fields; i++) {
+       for (i = 0; success && i < ebsdb->priv->n_summary_fields; i++) {
                if ((ebsdb->priv->summary_fields[i].index & INDEX_PREFIX) != 0 &&
                    ebsdb->priv->summary_fields[i].type != E_TYPE_CONTACT_ATTR_LIST) {
                        /* Derive index name from field & folder */
-                       tmp = g_strdup_printf ("INDEX_%s_%s",
-                                              summary_dbname_from_field (ebsdb, 
ebsdb->priv->summary_fields[i].field),
-                                              folderid);
-                       stmt = sqlite3_mprintf ("CREATE INDEX IF NOT EXISTS %Q ON %Q (%s)", tmp, folderid,
+                       tmp = g_strdup_printf (
+                               "INDEX_%s_%s",
+                               summary_dbname_from_field (ebsdb, ebsdb->priv->summary_fields[i].field),
+                               folderid);
+                       stmt = sqlite3_mprintf (
+                               "CREATE INDEX IF NOT EXISTS %Q ON %Q (%s)", tmp, folderid,
                                                summary_dbname_from_field (ebsdb, 
ebsdb->priv->summary_fields[i].field));
-                       ret = book_backend_sql_exec (ebsdb->priv->db, stmt, NULL, NULL, &err);
+                       success = book_backend_sql_exec (ebsdb->priv->db, stmt, NULL, NULL, error);
                        sqlite3_free (stmt);
                        g_free (tmp);
                }
 
-               if ((ebsdb->priv->summary_fields[i].index & INDEX_SUFFIX) != 0 &&
+               if (success &&
+                   (ebsdb->priv->summary_fields[i].index & INDEX_SUFFIX) != 0 &&
                    ebsdb->priv->summary_fields[i].type != E_TYPE_CONTACT_ATTR_LIST) {
                        /* Derive index name from field & folder */
-                       tmp = g_strdup_printf ("RINDEX_%s_%s",
-                                              summary_dbname_from_field (ebsdb, 
ebsdb->priv->summary_fields[i].field),
-                                              folderid);
-                       stmt = sqlite3_mprintf ("CREATE INDEX IF NOT EXISTS %Q ON %Q (%s_reverse)", tmp, 
folderid,
+                       tmp = g_strdup_printf (
+                               "RINDEX_%s_%s",
+                               summary_dbname_from_field (ebsdb, ebsdb->priv->summary_fields[i].field),
+                               folderid);
+                       stmt = sqlite3_mprintf (
+                               "CREATE INDEX IF NOT EXISTS %Q ON %Q (%s_reverse)", tmp, folderid,
                                                summary_dbname_from_field (ebsdb, 
ebsdb->priv->summary_fields[i].field));
-                       ret = book_backend_sql_exec (ebsdb->priv->db, stmt, NULL, NULL, &err);
+                       success = book_backend_sql_exec (ebsdb->priv->db, stmt, NULL, NULL, error);
                        sqlite3_free (stmt);
                        g_free (tmp);
                }
@@ -893,16 +924,16 @@ create_contacts_table (EBookBackendSqliteDB *ebsdb,
                                               folderid);
                        stmt = sqlite3_mprintf ("CREATE INDEX IF NOT EXISTS %Q ON %Q (%s_phone)", tmp, 
folderid,
                                                summary_dbname_from_field (ebsdb, 
ebsdb->priv->summary_fields[i].field));
-                       ret = book_backend_sql_exec (ebsdb->priv->db, stmt, NULL, NULL, &err);
+                       success = book_backend_sql_exec (ebsdb->priv->db, stmt, NULL, NULL, error);
                        sqlite3_free (stmt);
                        g_free (tmp);
                }
        }
 
        /* Construct the create statement from the attribute list summary table */
-       if (!err && ebsdb->priv->have_attr_list) {
+       if (success && ebsdb->priv->have_attr_list) {
                string = g_string_new ("CREATE TABLE IF NOT EXISTS %Q ( uid TEXT NOT NULL REFERENCES %Q(uid), 
"
-                                      "field TEXT, value TEXT");
+                       "field TEXT, value TEXT");
 
                if ((ebsdb->priv->attr_list_indexes & INDEX_SUFFIX) != 0)
                        g_string_append (string, ", value_reverse TEXT");
@@ -915,186 +946,316 @@ create_contacts_table (EBookBackendSqliteDB *ebsdb,
                stmt = sqlite3_mprintf (string->str, tmp, folderid);
                g_string_free (string, TRUE);
 
-               ret = book_backend_sql_exec (ebsdb->priv->db, stmt, NULL, NULL, &err);
+               success = book_backend_sql_exec (ebsdb->priv->db, stmt, NULL, NULL, error);
                sqlite3_free (stmt);
 
                /* Give the UID an index in this table, always */
                stmt = sqlite3_mprintf ("CREATE INDEX IF NOT EXISTS LISTINDEX ON %Q (uid)", tmp);
-               ret = book_backend_sql_exec (ebsdb->priv->db, stmt, NULL, NULL, &err);
+               success = book_backend_sql_exec (ebsdb->priv->db, stmt, NULL, NULL, error);
                sqlite3_free (stmt);
 
                /* Create indexes if specified */
-               if (!err && (ebsdb->priv->attr_list_indexes & INDEX_PREFIX) != 0) {
+               if (success && (ebsdb->priv->attr_list_indexes & INDEX_PREFIX) != 0) {
                        stmt = sqlite3_mprintf ("CREATE INDEX IF NOT EXISTS VALINDEX ON %Q (value)", tmp);
-                       ret = book_backend_sql_exec (ebsdb->priv->db, stmt, NULL, NULL, &err);
+                       success = book_backend_sql_exec (ebsdb->priv->db, stmt, NULL, NULL, error);
                        sqlite3_free (stmt);
                }
 
-               if (!err && (ebsdb->priv->attr_list_indexes & INDEX_SUFFIX) != 0) {
+               if (success && (ebsdb->priv->attr_list_indexes & INDEX_SUFFIX) != 0) {
                        stmt = sqlite3_mprintf ("CREATE INDEX IF NOT EXISTS RVALINDEX ON %Q (value_reverse)", 
tmp);
-                       ret = book_backend_sql_exec (ebsdb->priv->db, stmt, NULL, NULL, &err);
+                       success = book_backend_sql_exec (ebsdb->priv->db, stmt, NULL, NULL, error);
                        sqlite3_free (stmt);
                }
 
-               if (!err && (ebsdb->priv->attr_list_indexes & INDEX_PHONE) != 0) {
+               if (success && (ebsdb->priv->attr_list_indexes & INDEX_PHONE) != 0) {
                        stmt = sqlite3_mprintf ("CREATE INDEX IF NOT EXISTS PVALINDEX ON %Q (value_phone)", 
tmp);
-                       ret = book_backend_sql_exec (ebsdb->priv->db, stmt, NULL, NULL, &err);
+                       success = book_backend_sql_exec (ebsdb->priv->db, stmt, NULL, NULL, error);
                        sqlite3_free (stmt);
                }
+
                g_free (tmp);
+
        }
 
-       WRITER_UNLOCK (ebsdb);
+       if (success)
+               success = introspect_summary (ebsdb, folderid, error);
+       if (success && previous_schema == 4)
+               success = upgrade_contacts_table (ebsdb, folderid, error);
 
-       if (!err)
-               ret = introspect_summary (ebsdb, folderid, &err);
+       return success;
+}
 
-       if (!err)
-               ret = validate_county_code (ebsdb, folderid, &err);
+typedef struct {
+       sqlite3 *db;
+       const gchar *collation;
+       const gchar *table;
+} CollationInfo;
 
-       if (err)
-               g_propagate_error (error, err);
+static gint
+create_phone_indexes_for_columns (gpointer data,
+                                 gint n_cols,
+                                 gchar **cols,
+                                 gchar **name)
+{
+       const gchar *column_name = cols[1];
+       CollationInfo *info = data;
 
-       return ret;
+       if (g_str_has_suffix (column_name, "_phone")) {
+               gchar *index_name, *stmt;
+               GError *error = NULL;
+
+               index_name = g_strdup_printf (
+                       "PINDEX_%s_ON_%s_WITH_%s", column_name, info->table, info->collation);
+               stmt = sqlite3_mprintf (
+                       "CREATE INDEX IF NOT EXISTS %Q ON %Q (%s COLLATE %Q)",
+                       index_name, info->table, column_name, info->collation);
+
+               if (!book_backend_sql_exec (info->db, stmt, NULL, NULL, &error)) {
+                       g_warning ("%s: %s", G_STRFUNC, error->message);
+                       g_error_free (error);
+               }
+
+               sqlite3_free (stmt);
+               g_free (index_name);
+       }
+
+       return 0;
 }
 
-static void
-eqphone_func (sqlite3_context    *ctxt,
-              int                 argc,
-              sqlite3_value     **argv,
-              EPhoneNumberMatch   required_match)
+static gint
+create_phone_indexes_for_tables (gpointer data,
+                                gint n_cols,
+                                gchar **cols,
+                                gchar **name)
 {
-       EPhoneNumberMatch actual_match;
-       GError *error;
+       CollationInfo *info = data;
+       GError *error = NULL;
+       gchar *tmp, *stmt;
 
-       if (argc != 2) {
-               sqlite3_result_error (ctxt, "Function requires exactly two arguments", -1);
-               return;
+       info->table = cols[0];
+       stmt = sqlite3_mprintf ("PRAGMA table_info(%Q)", info->table);
+
+       if (!book_backend_sql_exec (
+               info->db, stmt, create_phone_indexes_for_columns, info, &error)) {
+               g_warning ("%s: %s", G_STRFUNC, error->message);
+               g_clear_error (&error);
        }
 
-       actual_match = e_phone_number_compare_strings (
-                       (const char *) sqlite3_value_text (argv[0]),
-                       (const char *) sqlite3_value_text (argv[1]),
-                       &error);
+       sqlite3_free (stmt);
 
-       if (error) {
-               sqlite3_result_error (ctxt, error->message, -1);
-               g_error_free (error);
-               return;
+       info->table = tmp = g_strconcat (info->table, "_lists", NULL);
+       stmt = sqlite3_mprintf ("PRAGMA table_info(%Q)", info->table);
+
+       if (!book_backend_sql_exec (
+               info->db, stmt, create_phone_indexes_for_columns, info, &error)) {
+               g_warning ("%s: %s", G_STRFUNC, error->message);
+               g_clear_error (&error);
        }
 
-       sqlite3_result_int
-               (ctxt, actual_match >= E_PHONE_NUMBER_MATCH_EXACT
-                && actual_match <= required_match);
+
+       sqlite3_free (stmt);
+       g_free (tmp);
+
+       return 0;
 }
 
-static void
-eqphone_national_func (sqlite3_context *ctxt,
-                       int              argc,
-                       sqlite3_value  **argv)
+static GString *
+ixphone_str (gint               country_code,
+            const gchar *const national_str,
+            gint               national_len)
+{
+       GString *const str = g_string_sized_new (6 + national_len);
+       g_string_append_printf (str, "+%d|", country_code);
+       g_string_append_len (str, national_str, national_len);
+       return str;
+}
+
+static gint
+e_strcmp2n (const gchar *str1,
+           size_t       len1,
+           const gchar *str2,
+           size_t       len2)
+{
+       const gint cmp = memcmp (str1, str2, MIN (len1, len2));
+
+       return (cmp != 0 ? cmp :
+               len1 == len2 ? 0 :
+               len1 < len2 ? -1 : 1);
+}
+
+static gint
+ixphone_compare_for_country (gpointer      data,
+                            gint          len1,
+                            gconstpointer arg1,
+                            gint          len2,
+                            gconstpointer arg2)
 {
-       eqphone_func (ctxt, argc, argv, E_PHONE_NUMBER_MATCH_NATIONAL);
+       const gchar *const str1 = arg1;
+       const gchar *const str2 = arg2;
+       const gchar *const sep1 = memchr (str1, '|', len1);
+       const gchar *const sep2 = memchr (str2, '|', len2);
+       const gint country_code = GPOINTER_TO_INT (data);
+
+       g_return_val_if_fail (sep1 != NULL, 0);
+       g_return_val_if_fail (sep2 != NULL, 0);
+
+       if ((str1 == sep1) == (str2 == sep2))
+               return e_strcmp2n (str1, len1, str2, len2);
+
+       if (str1 == sep1) {
+               GString *const tmp = ixphone_str (country_code, str1, len1);
+               const gint cmp = e_strcmp2n (tmp->str, tmp->len, str2, len2);
+               g_string_free (tmp, TRUE);
+               return cmp;
+       } else {
+               GString *const tmp = ixphone_str (country_code, str2, len2);
+               const gint cmp = e_strcmp2n (str1, len1, tmp->str, tmp->len);
+               g_string_free (tmp, TRUE);
+               return cmp;
+       }
+}
+
+static gint
+ixphone_compare_national (gpointer      data,
+                         gint          len1,
+                         gconstpointer arg1,
+                         gint          len2,
+                         gconstpointer arg2)
+{
+       const gchar *const str1 = arg1;
+       const gchar *const str2 = arg2;
+       const gchar *sep1 = memchr (str1, '|', len1);
+       const gchar *sep2 = memchr (str2, '|', len2);
+
+       gint cmp;
+
+       g_return_val_if_fail (sep1 != NULL, 0);
+       g_return_val_if_fail (sep2 != NULL, 0);
+
+       cmp = e_strcmp2n (sep1 + 1, len1 - (sep1 + 1 - str1),
+                         sep2 + 1, len2 - (sep2 + 1 - str2));
+
+       if (booksql_debug ()) {
+               gchar *const tmp1 = g_strndup (str1, len1);
+               gchar *const tmp2 = g_strndup (str2, len2);
+
+               g_printerr
+                       ("  DEBUG %s('%s', '%s') = %d\n",
+                        G_STRFUNC, tmp1, tmp2, cmp);
+
+               g_free (tmp2);
+               g_free (tmp1);
+       }
+
+       return cmp;
 }
 
 static void
-eqphone_short_func (sqlite3_context *ctxt,
-                    int              argc,
-                    sqlite3_value  **argv)
+create_collation (gpointer     data,
+                 sqlite3     *db,
+                 gint         encoding,
+                 const gchar *name)
 {
-       eqphone_func (ctxt, argc, argv, E_PHONE_NUMBER_MATCH_SHORT);
+       gint ret = SQLITE_DONE;
+       gint country_code;
+
+       g_warn_if_fail (encoding == SQLITE_UTF8);
+
+       if  (1 == sscanf (name, "ixphone_%d", &country_code)) {
+               ret = sqlite3_create_collation (
+                       db, name, SQLITE_UTF8, GINT_TO_POINTER (country_code),
+                       ixphone_compare_for_country);
+       } else if (strcmp (name, "ixphone_nn") == 0) {
+               ret = sqlite3_create_collation (
+                       db, name, SQLITE_UTF8, NULL,
+                       ixphone_compare_national);
+       }
+
+       if (ret == SQLITE_OK) {
+               CollationInfo info = { db, name };
+               GError *error = NULL;
+
+               if (!book_backend_sql_exec (
+                       db, "SELECT folder_id FROM folders",
+                       create_phone_indexes_for_tables, &info, &error)) {
+                       g_warning ("%s(%s): %s", G_STRFUNC, name, error->message);
+                       g_error_free (error);
+               }
+       } else if (ret != SQLITE_DONE) {
+               g_warning ("%s(%s): %s", G_STRFUNC, name, sqlite3_errmsg (db));
+       }
 }
 
 static gboolean
 book_backend_sqlitedb_load (EBookBackendSqliteDB *ebsdb,
                             const gchar *filename,
+                            gint *previous_schema,
                             GError **error)
 {
-       EBookBackendSqliteDBPrivate *priv;
        gint ret;
 
-       priv = ebsdb->priv;
-
        e_sqlite3_vfs_init ();
 
-       ret = sqlite3_open (filename, &priv->db);
-       if (ret) {
-               if (!priv->db) {
+       ret = sqlite3_open (filename, &ebsdb->priv->db);
+
+       if (ret == SQLITE_OK)
+               ret = sqlite3_collation_needed (ebsdb->priv->db, ebsdb, create_collation);
+
+       if (ret != SQLITE_OK) {
+               if (!ebsdb->priv->db) {
                        g_set_error (
                                error, E_BOOK_SDB_ERROR,
                                E_BOOK_SDB_ERROR_OTHER,
                                _("Insufficient memory"));
                } else {
                        const gchar *errmsg;
-                       errmsg = sqlite3_errmsg (priv->db);
-                       d (g_print ("Can't open database %s: %s\n", path, errmsg));
-                       g_set_error (
-                               error, E_BOOK_SDB_ERROR,
-                               E_BOOK_SDB_ERROR_OTHER, "%s", errmsg);
-                       sqlite3_close (priv->db);
+                       errmsg = sqlite3_errmsg (ebsdb->priv->db);
+                       d (g_printerr ("Can't open database %s: %s\n", path, errmsg));
+                       g_set_error_literal (
+                               error, E_BOOK_SDB_ERROR, E_BOOK_SDB_ERROR_OTHER, errmsg);
+                       sqlite3_close (ebsdb->priv->db);
                }
                return FALSE;
        }
 
-       ret = sqlite3_create_function (priv->db, "eqphone_national",
-                                      2, SQLITE_UTF8, ebsdb,
-                                      eqphone_national_func,
-                                      NULL, NULL);
-
-       if (ret) {
-               g_set_error (error, E_BOOK_SDB_ERROR, E_BOOK_SDB_ERROR_OTHER,
-                            "%s", sqlite3_errmsg (priv->db));
-               sqlite3_close (priv->db);
-               return FALSE;
-       }
-
-       ret = sqlite3_create_function (priv->db, "eqphone_short",
-                                      2, SQLITE_UTF8, ebsdb,
-                                      eqphone_short_func,
-                                      NULL, NULL);
-
-       if (ret) {
-               g_set_error (error, E_BOOK_SDB_ERROR, E_BOOK_SDB_ERROR_OTHER,
-                            "%s", sqlite3_errmsg (priv->db));
-               sqlite3_close (priv->db);
-               return FALSE;
-       }
-
-       WRITER_LOCK (ebsdb);
-
-       book_backend_sql_exec (priv->db, "ATTACH DATABASE ':memory:' AS mem", NULL, NULL, NULL);
-       book_backend_sql_exec (priv->db, "PRAGMA foreign_keys = ON", NULL, NULL, NULL);
-       book_backend_sql_exec (priv->db, "PRAGMA case_sensitive_like = ON", NULL, NULL, NULL);
-       book_backend_sql_exec (priv->db, "PRAGMA journal_mode = WAL", NULL, NULL, NULL);
-
-       WRITER_UNLOCK (ebsdb);
-
-       create_folders_table (ebsdb, error);
+       book_backend_sql_exec (
+               ebsdb->priv->db,
+               "ATTACH DATABASE ':memory:' AS mem",
+               NULL, NULL, NULL);
+       book_backend_sql_exec (
+               ebsdb->priv->db,
+               "PRAGMA foreign_keys = ON",
+               NULL, NULL, NULL);
+       book_backend_sql_exec (
+               ebsdb->priv->db,
+               "PRAGMA case_sensitive_like = ON",
+               NULL, NULL, NULL);
 
-       return TRUE;
+       return create_folders_table (ebsdb, previous_schema, error);
 }
 
 static EBookBackendSqliteDB *
 e_book_backend_sqlitedb_new_internal (const gchar *path,
-                                     const gchar *emailid,
-                                     const gchar *folderid,
-                                     const gchar *folder_name,
-                                     gboolean store_vcard,
-                                     SummaryField *fields,
-                                     gint n_fields,
-                                     gboolean have_attr_list,
-                                     IndexFlags attr_list_indexes,
-                                     GError **error)
+                                      const gchar *emailid,
+                                      const gchar *folderid,
+                                      const gchar *folder_name,
+                                      gboolean store_vcard,
+                                      SummaryField *fields,
+                                      gint n_fields,
+                                      gboolean have_attr_list,
+                                      IndexFlags attr_list_indexes,
+                                      GError **error)
 {
        EBookBackendSqliteDB *ebsdb;
        gchar *hash_key, *filename;
-       GError *err = NULL;
+       gint previous_schema = 0;
 
        g_return_val_if_fail (path != NULL, NULL);
        g_return_val_if_fail (emailid != NULL, NULL);
        g_return_val_if_fail (folderid != NULL, NULL);
        g_return_val_if_fail (folder_name != NULL, NULL);
 
-       g_static_mutex_lock (&dbcon_lock);
+       g_mutex_lock (&dbcon_lock);
 
        hash_key = g_strdup_printf ("%s %s", emailid, path);
        if (db_connections != NULL) {
@@ -1102,7 +1263,6 @@ e_book_backend_sqlitedb_new_internal (const gchar *path,
 
                if (ebsdb) {
                        g_object_ref (ebsdb);
-                       g_static_mutex_unlock (&dbcon_lock);
                        g_free (hash_key);
                        goto exit;
                }
@@ -1116,7 +1276,7 @@ e_book_backend_sqlitedb_new_internal (const gchar *path,
        ebsdb->priv->attr_list_indexes = attr_list_indexes;
        ebsdb->priv->store_vcard = store_vcard;
        if (g_mkdir_with_parents (path, 0777) < 0) {
-               g_static_mutex_unlock (&dbcon_lock);
+               g_mutex_unlock (&dbcon_lock);
                g_set_error (
                        error, E_BOOK_SDB_ERROR, E_BOOK_SDB_ERROR_OTHER,
                        "Can not make parent directory: errno %d", errno);
@@ -1124,9 +1284,8 @@ e_book_backend_sqlitedb_new_internal (const gchar *path,
        }
        filename = g_build_filename (path, DB_FILENAME, NULL);
 
-       if (!book_backend_sqlitedb_load (ebsdb, filename, &err)) {
-               g_static_mutex_unlock (&dbcon_lock);
-               g_propagate_error (error, err);
+       if (!book_backend_sqlitedb_load (ebsdb, filename, &previous_schema, error)) {
+               g_mutex_unlock (&dbcon_lock);
                g_object_unref (ebsdb);
                g_free (filename);
                return NULL;
@@ -1134,29 +1293,43 @@ e_book_backend_sqlitedb_new_internal (const gchar *path,
        g_free (filename);
 
        if (db_connections == NULL)
-               db_connections = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL);
+               db_connections = g_hash_table_new_full (
+                       (GHashFunc) g_str_hash,
+                       (GEqualFunc) g_str_equal,
+                       (GDestroyNotify) g_free,
+                       (GDestroyNotify) NULL);
        g_hash_table_insert (db_connections, hash_key, ebsdb);
        ebsdb->priv->hash_key = g_strdup (hash_key);
 
-       g_static_mutex_unlock (&dbcon_lock);
+ exit:
+       /* While the global dbcon_lock is held, hold the ebsdb specific lock and
+        * prolong the locking on that instance until the folders are all set up
+        */
+       LOCK_MUTEX (&ebsdb->priv->lock);
+       g_mutex_unlock (&dbcon_lock);
+
+       if (!add_folder_into_db (ebsdb, folderid, folder_name, error)) {
+               UNLOCK_MUTEX (&ebsdb->priv->lock);
+               g_object_unref (ebsdb);
+               return NULL;
+       }
 
-exit:
-       if (!err)
-               add_folder_into_db (ebsdb, folderid, folder_name, &err);
-       if (!err)
-               create_contacts_table (ebsdb, folderid, &err);
+       if (!create_contacts_table (ebsdb, folderid, previous_schema, error)) {
+               UNLOCK_MUTEX (&ebsdb->priv->lock);
+               g_object_unref (ebsdb);
+               return NULL;
+       }
 
-       if (err)
-               g_propagate_error (error, err);
+       UNLOCK_MUTEX (&ebsdb->priv->lock);
 
        return ebsdb;
 }
 
-static gboolean
-append_summary_field (GArray         *array,
-                     EContactField   field,
-                     gboolean       *have_attr_list,
-                     GError        **error)
+static SummaryField *
+append_summary_field (GArray *array,
+                      EContactField field,
+                      gboolean *have_attr_list,
+                      GError **error)
 {
        const gchar *dbname = NULL;
        GType        type = G_TYPE_INVALID;
@@ -1164,16 +1337,17 @@ append_summary_field (GArray         *array,
        SummaryField new_field = { 0, };
 
        if (field < 1 || field >= E_CONTACT_FIELD_LAST) {
-               g_set_error (error, E_BOOK_SDB_ERROR,
-                            E_BOOK_SDB_ERROR_OTHER, _("Invalid contact field '%d' specified in summary"), 
field);
-               return FALSE;
+               g_set_error (
+                       error, E_BOOK_SDB_ERROR, E_BOOK_SDB_ERROR_OTHER,
+                       _("Invalid contact field '%d' specified in summary"), field);
+               return NULL;
        }
 
        /* Avoid including the same field twice in the summary */
        for (i = 0; i < array->len; i++) {
                SummaryField *iter = &g_array_index (array, SummaryField, i);
                if (field == iter->field)
-                       return TRUE;
+                       return iter;
        }
 
        /* Resolve some exceptions, we store these
@@ -1187,9 +1361,6 @@ append_summary_field (GArray         *array,
        case E_CONTACT_IS_LIST:
                dbname = "is_list";
                break;
-       case E_CONTACT_REV:
-               dbname = "rev";
-               break;
        default:
                dbname = e_contact_field_name (field);
                break;
@@ -1200,30 +1371,32 @@ append_summary_field (GArray         *array,
        if (type != G_TYPE_STRING &&
            type != G_TYPE_BOOLEAN &&
            type != E_TYPE_CONTACT_ATTR_LIST) {
-               g_set_error (error, E_BOOK_SDB_ERROR, E_BOOK_SDB_ERROR_OTHER,
-                            _("Contact field '%s' of type '%s' specified in summary, "
-                                 "but only boolean, string and string list field types are supported"),
-                            e_contact_pretty_name (field), g_type_name (type));
-               return FALSE;
+               g_set_error (
+                       error, E_BOOK_SDB_ERROR, E_BOOK_SDB_ERROR_OTHER,
+                       _("Contact field '%s' of type '%s' specified in summary, "
+                       "but only boolean, string and string list field types are supported"),
+                       e_contact_pretty_name (field), g_type_name (type));
+               return NULL;
        }
 
        if (type == E_TYPE_CONTACT_ATTR_LIST && have_attr_list)
                *have_attr_list = TRUE;
 
-       new_field.field = field;
+       new_field.field  = field;
        new_field.dbname = dbname;
        new_field.type   = type;
+       new_field.index  = INDEX_PREFIX;
        g_array_append_val (array, new_field);
 
-       return TRUE;
+       return &g_array_index (array, SummaryField, array->len - 1);
 }
 
 static void
 summary_fields_add_indexes (GArray         *array,
-                           EContactField  *indexes,
-                           EBookIndexType *index_types,
-                           gint            n_indexes,
-                           IndexFlags     *attr_list_indexes)
+                            EContactField  *indexes,
+                            EBookIndexType *index_types,
+                            gint            n_indexes,
+                            IndexFlags     *attr_list_indexes)
 {
        gint i, j;
 
@@ -1260,7 +1433,6 @@ summary_fields_add_indexes (GArray         *array,
        }
 }
 
-
 /**
  * e_book_backend_sqlitedb_new_full:
  * @path: location where the db would be created
@@ -1268,21 +1440,19 @@ summary_fields_add_indexes (GArray         *array,
  * @folderid: folder id of the address-book
  * @folder_name: name of the address-book
  * @store_vcard: True if the vcard should be stored inside db, if FALSE only the summary fields would be 
stored inside db.
- * @fields: An array of #EContactFields to be used for the summary
- * @n_fields: The number of summary fields in @fields
- * @indexed_fields: An array of #EContactFields to be indexed in the SQLite DB, this must be a subset of 
@fields
- * @index_types: An array of #EBookIndexTypes indicating the type of indexes to create for @indexed_fields
- * @n_indexed_fields: The number of fields in @indexed_fields
+ * @setup: an #ESourceBackendSummarySetup describing how the summary should be setup
  * @error: A location to store any error that may have occurred
  *
  * Like e_book_backend_sqlitedb_new(), but allows configuration of which contact fields
- * will be stored for quick reference in the summary.
+ * will be stored for quick reference in the summary. The configuration indicated by
+ * @setup will only be taken into account when initially creating the underlying table,
+ * further configurations will be ignored.
  *
  * The fields %E_CONTACT_UID and %E_CONTACT_REV are not optional,
  * they will be stored in the summary regardless of this function's parameters
  *
- * <note><para>Only #EContactFields with the type #G_TYPE_STRING or #G_TYPE_BOOLEAN
- * are currently supported.</para></note>
+ * <note><para>Only #EContactFields with the type #G_TYPE_STRING, #G_TYPE_BOOLEAN or
+ * #E_TYPE_CONTACT_ATTR_LIST are currently supported.</para></note>
  *
  * Returns: (transfer full): The newly created #EBookBackendSqliteDB
  *
@@ -1290,34 +1460,33 @@ summary_fields_add_indexes (GArray         *array,
  **/
 EBookBackendSqliteDB *
 e_book_backend_sqlitedb_new_full (const gchar *path,
-                                 const gchar *emailid,
-                                 const gchar *folderid,
-                                 const gchar *folder_name,
-                                 gboolean store_vcard,
-                                 ESourceBackendSummarySetup *setup,
-                                 GError **error)
+                                  const gchar *emailid,
+                                  const gchar *folderid,
+                                  const gchar *folder_name,
+                                  gboolean store_vcard,
+                                  ESourceBackendSummarySetup *setup,
+                                  GError **error)
 {
        EBookBackendSqliteDB *ebsdb = NULL;
        EContactField *fields;
        EContactField *indexed_fields;
-       EBookIndexType *index_types;
+       EBookIndexType *index_types = NULL;
        gboolean have_attr_list = FALSE;
        IndexFlags attr_list_indexes = 0;
        gboolean had_error = FALSE;
        GArray *summary_fields;
-       gint n_fields, n_indexed_fields, i;
+       gint n_fields = 0, n_indexed_fields = 0, i;
 
        fields         = e_source_backend_summary_setup_get_summary_fields (setup, &n_fields);
        indexed_fields = e_source_backend_summary_setup_get_indexed_fields (setup, &index_types, 
&n_indexed_fields);
 
        /* No specified summary fields indicates the default summary configuration should be used */
        if (n_fields <= 0) {
-
                ebsdb = e_book_backend_sqlitedb_new (path, emailid, folderid, folder_name, store_vcard, 
error);
                g_free (fields);
                g_free (index_types);
                g_free (indexed_fields);
-               
+
                return ebsdb;
        }
 
@@ -1343,16 +1512,18 @@ e_book_backend_sqlitedb_new_full (const gchar *path,
        }
 
        /* Add the 'indexed' flag to the SummaryField structs */
-       summary_fields_add_indexes (summary_fields, indexed_fields, index_types, n_indexed_fields,
-                                   &attr_list_indexes);
-
-       ebsdb = e_book_backend_sqlitedb_new_internal (path, emailid, folderid, folder_name,
-                                                     store_vcard,
-                                                     (SummaryField *)summary_fields->data,
-                                                     summary_fields->len,
-                                                     have_attr_list,
-                                                     attr_list_indexes,
-                                                     error);
+       summary_fields_add_indexes (
+               summary_fields, indexed_fields, index_types, n_indexed_fields,
+               &attr_list_indexes);
+
+       ebsdb = e_book_backend_sqlitedb_new_internal (
+               path, emailid, folderid, folder_name,
+               store_vcard,
+               (SummaryField *) summary_fields->data,
+               summary_fields->len,
+               have_attr_list,
+               attr_list_indexes,
+               error);
 
        g_free (fields);
        g_free (index_types);
@@ -1362,8 +1533,6 @@ e_book_backend_sqlitedb_new_full (const gchar *path,
        return ebsdb;
 }
 
-
-
 /**
  * e_book_backend_sqlitedb_new
  * @path: location where the db would be created
@@ -1394,25 +1563,28 @@ e_book_backend_sqlitedb_new (const gchar *path,
        IndexFlags attr_list_indexes = 0;
        gint i;
 
-       /* Create the default summery structs */
+       /* Create the default summary structs */
        summary_fields = g_array_new (FALSE, FALSE, sizeof (SummaryField));
        for (i = 0; i < G_N_ELEMENTS (default_summary_fields); i++)
                append_summary_field (summary_fields, default_summary_fields[i], &have_attr_list, NULL);
 
        /* Add the default index flags */
-       summary_fields_add_indexes (summary_fields,
-                                   default_indexed_fields,
-                                   default_index_types,
-                                   G_N_ELEMENTS (default_indexed_fields),
-                                   &attr_list_indexes);
-
-       ebsdb = e_book_backend_sqlitedb_new_internal (path, emailid, folderid, folder_name,
-                                                     store_vcard,
-                                                     (SummaryField *)summary_fields->data,
-                                                     summary_fields->len,
-                                                     have_attr_list,
-                                                     attr_list_indexes,
-                                                     error);
+       summary_fields_add_indexes (
+               summary_fields,
+               default_indexed_fields,
+               default_index_types,
+               G_N_ELEMENTS (default_indexed_fields),
+               &attr_list_indexes);
+
+       ebsdb = e_book_backend_sqlitedb_new_internal (
+               path, emailid, folderid, folder_name,
+               store_vcard,
+               (SummaryField *) summary_fields->data,
+               summary_fields->len,
+               have_attr_list,
+               attr_list_indexes,
+               error);
+
        g_array_free (summary_fields, FALSE);
 
        return ebsdb;
@@ -1422,9 +1594,17 @@ gboolean
 e_book_backend_sqlitedb_lock_updates (EBookBackendSqliteDB *ebsdb,
                                       GError **error)
 {
+       gboolean success;
+
        g_return_val_if_fail (E_IS_BOOK_BACKEND_SQLITEDB (ebsdb), FALSE);
 
-       return book_backend_sqlitedb_start_transaction (ebsdb, error);
+       LOCK_MUTEX (&ebsdb->priv->updates_lock);
+
+       LOCK_MUTEX (&ebsdb->priv->lock);
+       success = book_backend_sqlitedb_start_transaction (ebsdb, error);
+       UNLOCK_MUTEX (&ebsdb->priv->lock);
+
+       return success;
 }
 
 gboolean
@@ -1432,9 +1612,19 @@ e_book_backend_sqlitedb_unlock_updates (EBookBackendSqliteDB *ebsdb,
                                         gboolean do_commit,
                                         GError **error)
 {
+       gboolean success;
+
        g_return_val_if_fail (E_IS_BOOK_BACKEND_SQLITEDB (ebsdb), FALSE);
 
-       return book_backend_sqlitedb_end_transaction (ebsdb, do_commit, error);
+       LOCK_MUTEX (&ebsdb->priv->lock);
+       success = do_commit ?
+               book_backend_sqlitedb_commit_transaction (ebsdb, error) :
+               book_backend_sqlitedb_rollback_transaction (ebsdb, error);
+       UNLOCK_MUTEX (&ebsdb->priv->lock);
+
+       UNLOCK_MUTEX (&ebsdb->priv->updates_lock);
+
+       return success;
 }
 
 static gchar *
@@ -1447,114 +1637,94 @@ mprintf_suffix (const gchar *normal)
        return stmt;
 }
 
-static gchar *
-convert_phone (const gchar *normal,
-               const gchar *country_code)
+static EPhoneNumber *
+phone_number_from_string (const gchar *normal,
+                          const gchar *default_region)
 {
        EPhoneNumber *number = NULL;
-       gchar *phone_number = NULL;
        GError *error = NULL;
 
-       if (normal)
-               number = e_phone_number_from_string (normal, country_code, &error);
+       if (normal && e_phone_number_is_supported ())
+               number = e_phone_number_from_string (normal, default_region, &error);
 
        if (error) {
-               g_error ("%s:%d (%s): %s", __FILE__, __LINE__, __func__, error->message);
-               g_clear_error (&error);
-       }
+               /* Only barf on unusual errors */
+               if (error->domain != E_PHONE_NUMBER_ERROR
+                       || error->code != E_PHONE_NUMBER_ERROR_INVALID_COUNTRY_CODE) {
+                       g_warning ("%s: '%s': %s", G_STRLOC, normal, error->message);
+               }
 
-       if (number) {
-               phone_number = e_phone_number_to_string (number, E_PHONE_NUMBER_FORMAT_E164);
-               e_phone_number_free (number);
+               g_clear_error (&error);
        }
 
-       return phone_number;
+       return number;
 }
 
 static gchar *
-mprintf_phone (const gchar *normal,
-               const gchar *country_code)
+convert_phone_national (const gchar *normal,
+                        const gchar *default_region)
 {
-       gchar *phone = convert_phone (normal, country_code);
-       gchar *stmt = NULL;
+       EPhoneNumber *number = phone_number_from_string (normal, default_region);
+       gchar *indexed_phone_number = NULL;
+       gchar *national_number = NULL;
 
-       if (phone) {
-               stmt = sqlite3_mprintf ("%Q", phone);
-               g_free (phone);
+       if (number) {
+               national_number = e_phone_number_get_national_number (number);
+               e_phone_number_free (number);
        }
 
-       return stmt;
-}
-
-static EVCardAttributeParam *
-find_param (EVCardAttribute *attr,
-            const gchar     *name)
-{
-       GList *l;
-
-       for (l = e_vcard_attribute_get_params (attr); l; l = l->next) {
-               EVCardAttributeParam *const param = l->data;
-
-               if (strcmp (e_vcard_attribute_param_get_name (param), name) == 0)
-                       return param;
+       if (national_number) {
+               indexed_phone_number = g_strconcat ("|", national_number, NULL);
+               g_free (national_number);
        }
 
-       return NULL;
+       return indexed_phone_number;
 }
 
-static gboolean
-update_e164_params (EVCard *vcard,
-                    const gchar *country_code)
+static gchar *
+convert_phone (const gchar *normal,
+               const gchar *default_region)
 {
-       const GList *attr_list = e_vcard_get_attributes (vcard);
-       gboolean modified = FALSE;
+       EPhoneNumber *number = phone_number_from_string (normal, default_region);
+       gchar *indexed_phone_number = NULL;
+       gchar *national_number = NULL;
+       gint country_code = 0;
 
-       if (!e_phone_number_is_supported ())
-               return FALSE;
+       if (number) {
+               EPhoneNumberCountrySource source;
 
-       for (; attr_list; attr_list = attr_list->next) {
-               EVCardAttribute *const attr = attr_list->data;
-               char *normalized_number = NULL;
-               char *formatted_number = NULL;
-               EVCardAttributeParam *param = NULL;
+               national_number = e_phone_number_get_national_number (number);
+               country_code = e_phone_number_get_country_code (number, &source);
+               e_phone_number_free (number);
 
-               /* Skip all attributes but phone numbers. */
-               if (strcmp (e_vcard_attribute_get_name (attr), EVC_TEL) != 0)
-                       continue;
+               if (source == E_PHONE_NUMBER_COUNTRY_FROM_DEFAULT)
+                       country_code = 0;
+       }
 
-               /* Compute normalized phone number. */
-               param = find_param (attr, EVC_X_E164);
-               formatted_number = e_vcard_attribute_get_value (attr);
+       if (national_number) {
+               indexed_phone_number = country_code
+                       ? g_strdup_printf ("+%d|%s", country_code, national_number)
+                       : g_strconcat ("|", national_number, NULL);
 
-               if (formatted_number)
-                       normalized_number = convert_phone (formatted_number, country_code);
+               g_free (national_number);
+       }
 
-               /* Update the phone number attribute. */
-               if (normalized_number) {
-                       if (param == NULL) {
-                               param = e_vcard_attribute_param_new (EVC_X_E164);
-                               e_vcard_attribute_add_param_with_value (attr, param, normalized_number);
-                               modified = TRUE;
-                       } else {
-                               GList *values = e_vcard_attribute_param_get_values (param);
-
-                               if (values == NULL
-                                       || g_strcmp0 (values->data, normalized_number)
-                                       || values->next) {
-                                       e_vcard_attribute_param_remove_values (param);
-                                       e_vcard_attribute_param_add_value (param, normalized_number);
-                                       modified = TRUE;
-                               }
-                       }
+       return indexed_phone_number;
+}
 
-                       g_free (normalized_number);
-               } else if (param) {
-                       e_vcard_attribute_remove_param (attr, EVC_X_E164);
-                       modified = TRUE;
-               }
+static gchar *
+mprintf_phone (const gchar *normal,
+               const gchar *default_region)
+{
+       gchar *phone = convert_phone (normal, default_region);
+       gchar *stmt = NULL;
+
+       if (phone) {
+               stmt = sqlite3_mprintf ("%Q", phone);
+               g_free (phone);
        }
 
-       return modified;
+       return stmt;
 }
 
 /* Add Contact (free the result with g_free() ) */
@@ -1563,19 +1733,19 @@ insert_stmt_from_contact (EBookBackendSqliteDB *ebsdb,
                           EContact *contact,
                           const gchar *folderid,
                           gboolean store_vcard,
-                         gboolean replace_existing)
+                          gboolean replace_existing,
+                          const gchar *default_region)
 {
        GString *string;
-       gchar   *str, *vcard_str;
-       gint     i;
+       gchar *str, *vcard_str;
+       gint i;
 
-       str    = sqlite3_mprintf ("INSERT or %s INTO %Q VALUES (",
-                                 replace_existing ? "REPLACE" : "FAIL", folderid);
+       str = sqlite3_mprintf ("INSERT or %s INTO %Q VALUES (",
+                              replace_existing ? "REPLACE" : "FAIL", folderid);
        string = g_string_new (str);
        sqlite3_free (str);
 
        for (i = 0; i < ebsdb->priv->n_summary_fields; i++) {
-
                if (ebsdb->priv->summary_fields[i].type == G_TYPE_STRING) {
                        gchar *val;
                        gchar *normal;
@@ -1585,7 +1755,7 @@ insert_stmt_from_contact (EBookBackendSqliteDB *ebsdb,
 
                        val = e_contact_get (contact, ebsdb->priv->summary_fields[i].field);
 
-                       /* Special exception, never normalize the UID & REV string */
+                       /* Special exception, never normalize the UID or REV string */
                        if (ebsdb->priv->summary_fields[i].field != E_CONTACT_UID &&
                            ebsdb->priv->summary_fields[i].field != E_CONTACT_REV)
                                normal = e_util_utf8_normalize (val);
@@ -1604,15 +1774,14 @@ insert_stmt_from_contact (EBookBackendSqliteDB *ebsdb,
                        }
 
                        if ((ebsdb->priv->summary_fields[i].index & INDEX_PHONE) != 0) {
-                               str = mprintf_phone (normal, ebsdb->priv->country_code);
+                               str = mprintf_phone (normal, default_region);
                                g_string_append (string, ", ");
-                               g_string_append (string, str);
+                               g_string_append (string, str ? str : "NULL");
                                sqlite3_free (str);
                        }
 
                        g_free (normal);
                        g_free (val);
-
                } else if (ebsdb->priv->summary_fields[i].type == G_TYPE_BOOLEAN) {
                        gboolean val;
 
@@ -1626,13 +1795,7 @@ insert_stmt_from_contact (EBookBackendSqliteDB *ebsdb,
                        g_warn_if_reached ();
        }
 
-       if (store_vcard) {
-               update_e164_params (E_VCARD (contact), ebsdb->priv->country_code);
-               vcard_str = e_vcard_to_string (E_VCARD (contact), EVC_FORMAT_VCARD_30);
-       } else {
-               vcard_str = NULL;
-       }
-
+       vcard_str = store_vcard ? e_vcard_to_string (E_VCARD (contact), EVC_FORMAT_VCARD_30) : NULL;
        str = sqlite3_mprintf (", %Q, %Q)", vcard_str, NULL);
 
        g_string_append (string, str);
@@ -1713,6 +1876,7 @@ insert_contact (EBookBackendSqliteDB *ebsdb,
                EContact *contact,
                const gchar *folderid,
                gboolean replace_existing,
+               const gchar *default_region,
                GError **error)
 {
        EBookBackendSqliteDBPrivate *priv;
@@ -1726,7 +1890,7 @@ insert_contact (EBookBackendSqliteDB *ebsdb,
                update_e164_attribute_params (E_VCARD (contact));
 
        /* Update main summary table */
-       stmt = insert_stmt_from_contact (ebsdb, contact, folderid, priv->store_vcard, replace_existing);
+       stmt = insert_stmt_from_contact (ebsdb, contact, folderid, priv->store_vcard, replace_existing, 
default_region);
        success = book_backend_sql_exec (priv->db, stmt, NULL, NULL, error);
        g_free (stmt);
 
@@ -1750,15 +1914,18 @@ insert_contact (EBookBackendSqliteDB *ebsdb,
                        values = e_contact_get (contact, priv->summary_fields[i].field);
 
                        for (l = values; success && l != NULL; l = l->next) {
-                               gchar *value = (gchar *)l->data;
+                               gchar *value = (gchar *) l->data;
                                gchar *normal = e_util_utf8_normalize (value);
                                gchar *stmt_suffix = NULL;
                                gchar *stmt_phone = NULL;
 
-                               if ((priv->attr_list_indexes & INDEX_SUFFIX) != 0)
+                               if ((priv->attr_list_indexes & INDEX_SUFFIX) != 0
+                                       && (priv->summary_fields[i].index & INDEX_SUFFIX) != 0)
                                        stmt_suffix = mprintf_suffix (normal);
-                               if ((priv->attr_list_indexes & INDEX_PHONE) != 0)
-                                       stmt_phone = mprintf_phone (normal, ebsdb->priv->country_code);
+
+                               if ((priv->attr_list_indexes & INDEX_PHONE) != 0
+                                       && (priv->summary_fields[i].index & INDEX_PHONE) != 0)
+                                       stmt_phone = mprintf_phone (normal, default_region);
 
                                stmt = sqlite3_mprintf ("INSERT INTO %Q (uid, field, value%s%s) "
                                                        "VALUES (%Q, %Q, %Q%s%s%s%s)",
@@ -1852,26 +2019,42 @@ e_book_backend_sqlitedb_new_contacts (EBookBackendSqliteDB *ebsdb,
                                       GError **error)
 {
        GSList *l;
-       GError *err = NULL;
+       gboolean success = TRUE;
+       gchar *default_region = NULL;
 
        g_return_val_if_fail (E_IS_BOOK_BACKEND_SQLITEDB (ebsdb), FALSE);
        g_return_val_if_fail (folderid != NULL, FALSE);
        g_return_val_if_fail (contacts != NULL, FALSE);
 
-       book_backend_sqlitedb_start_transaction (ebsdb, &err);
+       LOCK_MUTEX (&ebsdb->priv->lock);
+
+       if (!book_backend_sqlitedb_start_transaction (ebsdb, error)) {
+               UNLOCK_MUTEX (&ebsdb->priv->lock);
+               return FALSE;
+       }
+
+       if (e_phone_number_is_supported ())
+               default_region = e_phone_number_get_default_region ();
 
-       for (l = contacts; !err && l != NULL; l = g_slist_next (l)) {
+       for (l = contacts; success && l != NULL; l = g_slist_next (l)) {
                EContact *contact = (EContact *) l->data;
 
-               insert_contact (ebsdb, contact, folderid, replace_existing, &err);
+               success = insert_contact (
+                       ebsdb, contact, folderid, replace_existing,
+                       default_region, error);
        }
 
-       book_backend_sqlitedb_end_transaction (ebsdb, !err, err ? NULL : &err);
+       g_free (default_region);
+
+       if (success)
+               success = book_backend_sqlitedb_commit_transaction (ebsdb, error);
+       else
+               /* The GError is already set. */
+               book_backend_sqlitedb_rollback_transaction (ebsdb, NULL);
 
-       if (err)
-               g_propagate_error (error, err);
+       UNLOCK_MUTEX (&ebsdb->priv->lock);
 
-       return err == NULL;
+       return success;
 }
 
 /**
@@ -1980,7 +2163,8 @@ generate_uid_list_for_stmt (GSList *uids)
 }
 
 static gchar *
-generate_delete_stmt (const gchar *table, GSList *uids)
+generate_delete_stmt (const gchar *table,
+                      GSList *uids)
 {
        GString *str = g_string_new (NULL);
        gchar *tmp;
@@ -1994,7 +2178,7 @@ generate_delete_stmt (const gchar *table, GSList *uids)
        g_free (tmp);
        g_string_append_c (str, ')');
 
-       return g_string_free (str, FALSE);      
+       return g_string_free (str, FALSE);
 }
 
 /**
@@ -2010,38 +2194,46 @@ e_book_backend_sqlitedb_remove_contacts (EBookBackendSqliteDB *ebsdb,
                                          GSList *uids,
                                          GError **error)
 {
-       GError *err = NULL;
+       gboolean success = TRUE;
        gchar *stmt;
 
        g_return_val_if_fail (E_IS_BOOK_BACKEND_SQLITEDB (ebsdb), FALSE);
        g_return_val_if_fail (folderid != NULL, FALSE);
        g_return_val_if_fail (uids != NULL, FALSE);
 
-       book_backend_sqlitedb_start_transaction (ebsdb, &err);
+       LOCK_MUTEX (&ebsdb->priv->lock);
 
-       /* Delete the auxillary contact infos first */
-       if (!err && ebsdb->priv->have_attr_list) {
-               gchar *lists_folder = g_strdup_printf ("%s_lists", folderid);
+       if (!book_backend_sqlitedb_start_transaction (ebsdb, error)) {
+               UNLOCK_MUTEX (&ebsdb->priv->lock);
+               return FALSE;
+       }
 
-               stmt = generate_delete_stmt (lists_folder, uids);
-               g_free (lists_folder);
+       /* Delete the auxillary contact infos first */
+       if (success && ebsdb->priv->have_attr_list) {
+               gchar *lists_folder = g_strdup_printf ("%s_lists", folderid);
 
-               book_backend_sql_exec (ebsdb->priv->db, stmt, NULL, NULL, &err);
-               g_free (stmt);
-       }
+               stmt = generate_delete_stmt (lists_folder, uids);
+               g_free (lists_folder);
 
-       stmt = generate_delete_stmt (folderid, uids);
-       if (!err)
-               book_backend_sql_exec (ebsdb->priv->db, stmt, NULL, NULL, &err);
+               success = book_backend_sql_exec (ebsdb->priv->db, stmt, NULL, NULL, error);
+               g_free (stmt);
+       }
 
-       g_free (stmt);
+       if (success) {
+               stmt = generate_delete_stmt (folderid, uids);
+               success = book_backend_sql_exec (ebsdb->priv->db, stmt, NULL, NULL, error);
+               g_free (stmt);
+       }
 
-       book_backend_sqlitedb_end_transaction (ebsdb, !err, err ? NULL : &err);
+       if (success)
+               success = book_backend_sqlitedb_commit_transaction (ebsdb, error);
+       else
+               /* The GError is already set. */
+               book_backend_sqlitedb_rollback_transaction (ebsdb, NULL);
 
-       if (err)
-               g_propagate_error (error, err);
+       UNLOCK_MUTEX (&ebsdb->priv->lock);
 
-       return !err;
+       return success;
 }
 
 struct _contact_info {
@@ -2077,9 +2269,9 @@ e_book_backend_sqlitedb_has_contact (EBookBackendSqliteDB *ebsdb,
                                      gboolean *partial_content,
                                      GError **error)
 {
-       GError *err = NULL;
-       gchar *stmt;
        struct _contact_info cinfo;
+       gboolean success;
+       gchar *stmt;
 
        g_return_val_if_fail (E_IS_BOOK_BACKEND_SQLITEDB (ebsdb), FALSE);
        g_return_val_if_fail (folderid != NULL, FALSE);
@@ -2088,20 +2280,23 @@ e_book_backend_sqlitedb_has_contact (EBookBackendSqliteDB *ebsdb,
        cinfo.exists = FALSE;
        cinfo.partial_content = FALSE;
 
-       READER_LOCK (ebsdb);
+       LOCK_MUTEX (&ebsdb->priv->lock);
 
-       stmt = sqlite3_mprintf ("SELECT partial_content FROM %Q WHERE uid = %Q", folderid, uid);
-       book_backend_sql_exec (ebsdb->priv->db, stmt, contact_found_cb , &cinfo, &err);
+       stmt = sqlite3_mprintf (
+               "SELECT partial_content FROM %Q WHERE uid = %Q",
+               folderid, uid);
+       success = book_backend_sql_exec (
+               ebsdb->priv->db, stmt, contact_found_cb , &cinfo, error);
        sqlite3_free (stmt);
 
-       if (!err)
+       if (success)
                *partial_content = cinfo.partial_content;
-       else
-               g_propagate_error (error, err);
 
-       READER_UNLOCK (ebsdb);
+       UNLOCK_MUTEX (&ebsdb->priv->lock);
 
-       return cinfo.exists;
+       /* FIXME Returning FALSE can mean either "contact not found" or
+        *       "error occurred".  Add a boolean (out) "exists" parameter. */
+       return success && cinfo.exists;
 }
 
 static gint
@@ -2133,7 +2328,6 @@ e_book_backend_sqlitedb_get_contact (EBookBackendSqliteDB *ebsdb,
                                      gboolean *with_all_required_fields,
                                      GError **error)
 {
-       GError *err = NULL;
        EContact *contact = NULL;
        gchar *vcard;
 
@@ -2143,12 +2337,12 @@ e_book_backend_sqlitedb_get_contact (EBookBackendSqliteDB *ebsdb,
 
        vcard = e_book_backend_sqlitedb_get_vcard_string (
                ebsdb, folderid, uid,
-               fields_of_interest, with_all_required_fields, &err);
-       if (!err && vcard) {
+               fields_of_interest, with_all_required_fields, error);
+
+       if (vcard != NULL) {
                contact = e_contact_new_from_vcard_with_uid (vcard, uid);
                g_free (vcard);
-       } else
-               g_propagate_error (error, err);
+       }
 
        return contact;
 }
@@ -2156,30 +2350,23 @@ e_book_backend_sqlitedb_get_contact (EBookBackendSqliteDB *ebsdb,
 static gboolean
 uid_rev_fields (GHashTable *fields_of_interest)
 {
-       gboolean uid_rev = TRUE;
        GHashTableIter iter;
        gpointer key, value;
 
-       if (!fields_of_interest)
+       if (!fields_of_interest || g_hash_table_size (fields_of_interest) > 2)
                return FALSE;
 
        g_hash_table_iter_init (&iter, fields_of_interest);
        while (g_hash_table_iter_next (&iter, &key, &value)) {
-               const gchar  *field_name = key;
-               EContactField field      = e_contact_field_id (field_name);
-               gboolean      found      = FALSE;
+               const gchar *field_name = key;
+               EContactField field = e_contact_field_id (field_name);
 
-               if (field == E_CONTACT_UID ||
-                   field == E_CONTACT_REV)
-                       found = TRUE;
-
-               if (!found) {
-                       uid_rev = FALSE;
-                       break;
-               }
+               if (field != E_CONTACT_UID &&
+                   field != E_CONTACT_REV)
+                       return FALSE;
        }
 
-       return uid_rev;
+       return TRUE;
 }
 
 /**
@@ -2247,6 +2434,8 @@ e_book_backend_sqlitedb_check_summary_fields (EBookBackendSqliteDB *ebsdb,
        if (!fields_of_interest)
                return FALSE;
 
+       LOCK_MUTEX (&ebsdb->priv->lock);
+
        g_hash_table_iter_init (&iter, fields_of_interest);
        while (g_hash_table_iter_next (&iter, &key, &value)) {
                const gchar  *field_name = key;
@@ -2258,24 +2447,26 @@ e_book_backend_sqlitedb_check_summary_fields (EBookBackendSqliteDB *ebsdb,
                }
        }
 
+       UNLOCK_MUTEX (&ebsdb->priv->lock);
+
        return summary_fields;
 }
 
 /* free return value with g_free */
 static gchar *
 summary_select_stmt (GHashTable *fields_of_interest,
-                    gboolean distinct)
+                     gboolean distinct)
 {
-       GString   *string;
+       GString *string;
 
        if (distinct)
-               string = g_string_new ("SELECT DISTINCT summary.uid AS uid");
+               string = g_string_new ("SELECT DISTINCT summary.uid");
        else
-               string = g_string_new ("SELECT summary.uid AS uid");
+               string = g_string_new ("SELECT summary.uid");
 
        /* Add the E_CONTACT_REV field if they are both requested */
        if (g_hash_table_size (fields_of_interest) == 2)
-               g_string_append (string, ", summary.rev AS rev");
+               g_string_append (string, ", Rev");
 
        return g_string_free (string, FALSE);
 }
@@ -2299,13 +2490,12 @@ store_data_to_vcard (gpointer ref,
                        continue;
 
                /* Only UID & REV can be used to create contacts from the summary columns */
-               if (!strcmp (name[i], "uid")) {
+               if (!g_ascii_strcasecmp (name[i], "uid")) {
                        e_contact_set (contact, E_CONTACT_UID, cols[i]);
-
                        search_data->uid = g_strdup (cols[i]);
-               } else if (!strcmp (name[i], "rev")) {
+               } else if (!g_ascii_strcasecmp (name[i], "Rev")) {
                        e_contact_set (contact, E_CONTACT_REV, cols[i]);
-               } else if (!strcmp (name[i], "bdata"))
+               } else if (!g_ascii_strcasecmp (name[i], "bdata"))
                        search_data->bdata = g_strdup (cols[i]);
        }
 
@@ -2355,7 +2545,7 @@ e_book_backend_sqlitedb_get_vcard_string (EBookBackendSqliteDB *ebsdb,
        g_return_val_if_fail (folderid != NULL, NULL);
        g_return_val_if_fail (uid != NULL, NULL);
 
-       READER_LOCK (ebsdb);
+       LOCK_MUTEX (&ebsdb->priv->lock);
 
        /* Try constructing contacts from only UID/REV first if that's requested */
        if (uid_rev_fields (fields_of_interest)) {
@@ -2364,18 +2554,17 @@ e_book_backend_sqlitedb_get_vcard_string (EBookBackendSqliteDB *ebsdb,
 
                select_portion = summary_select_stmt (fields_of_interest, FALSE);
 
-               stmt = sqlite3_mprintf ("%s FROM %Q AS summary WHERE uid = %Q",
-                                       select_portion, folderid, uid);
-               book_backend_sql_exec (ebsdb->priv->db, stmt,
-                                      store_data_to_vcard,
-                                      &vcards, error);
+               stmt = sqlite3_mprintf (
+                       "%s FROM %Q AS summary WHERE summary.uid = %Q",
+                       select_portion, folderid, uid);
+               book_backend_sql_exec (ebsdb->priv->db, stmt, store_data_to_vcard, &vcards, error);
                sqlite3_free (stmt);
                g_free (select_portion);
 
                if (vcards) {
                        EbSdbSearchData *s_data = (EbSdbSearchData *) vcards->data;
 
-                       vcard_str     = s_data->vcard;
+                       vcard_str = s_data->vcard;
                        s_data->vcard = NULL;
 
                        e_book_backend_sqlitedb_search_data_free (s_data);
@@ -2385,9 +2574,7 @@ e_book_backend_sqlitedb_get_vcard_string (EBookBackendSqliteDB *ebsdb,
                }
 
                local_with_all_required_fields = TRUE;
-
        } else if (ebsdb->priv->store_vcard) {
-
                stmt = sqlite3_mprintf (
                        "SELECT vcard FROM %Q WHERE uid = %Q", folderid, uid);
                book_backend_sql_exec (
@@ -2397,13 +2584,13 @@ e_book_backend_sqlitedb_get_vcard_string (EBookBackendSqliteDB *ebsdb,
 
                local_with_all_required_fields = TRUE;
        } else {
-               g_set_error (error, E_BOOK_SDB_ERROR,
-                            E_BOOK_SDB_ERROR_OTHER,
-                            _("Full search_contacts are not stored in cache. vcards cannot be returned."));
+               g_set_error (
+                       error, E_BOOK_SDB_ERROR, E_BOOK_SDB_ERROR_OTHER,
+                       _("Full search_contacts are not stored in cache. vcards cannot be returned."));
 
        }
 
-       READER_UNLOCK (ebsdb);
+       UNLOCK_MUTEX (&ebsdb->priv->lock);
 
        if (with_all_required_fields)
                *with_all_required_fields = local_with_all_required_fields;
@@ -2416,7 +2603,6 @@ e_book_backend_sqlitedb_get_vcard_string (EBookBackendSqliteDB *ebsdb,
        return vcard_str;
 }
 
-
 enum {
        CHECK_IS_SUMMARY   = (1 << 0),
        CHECK_IS_LIST_ATTR = (1 << 1),
@@ -2424,9 +2610,9 @@ enum {
 
 static ESExpResult *
 func_check_subset (ESExp *f,
-                  gint argc,
-                  struct _ESExpTerm **argv,
-                  gpointer data)
+                   gint argc,
+                   struct _ESExpTerm **argv,
+                   gpointer data)
 {
        ESExpResult *r, *r1;
        gboolean one_non_summary_query = FALSE;
@@ -2456,10 +2642,45 @@ func_check_subset (ESExp *f,
        if (one_non_summary_query)
                result = 0;
 
-       r = e_sexp_result_new (f, ESEXP_RES_INT);
-       r->value.number = result;
+       r = e_sexp_result_new (f, ESEXP_RES_INT);
+       r->value.number = result;
+
+       return r;
+}
+
+static gint
+func_check_field_test (EBookBackendSqliteDB *ebsdb,
+                       const gchar *query_name,
+                       const gchar *query_value)
+{
+       gint i;
+       gint ret_val = 0;
+
+       if (ebsdb) {
+               for (i = 0; i < ebsdb->priv->n_summary_fields; i++) {
+                       if (!g_ascii_strcasecmp (e_contact_field_name (ebsdb->priv->summary_fields[i].field), 
query_name)) {
+                               ret_val |= CHECK_IS_SUMMARY;
+
+                               if (ebsdb->priv->summary_fields[i].type == E_TYPE_CONTACT_ATTR_LIST)
+                                       ret_val |= CHECK_IS_LIST_ATTR;
+
+                               break;
+                       }
+               }
+       } else {
+               for (i = 0; i < G_N_ELEMENTS (default_summary_fields); i++) {
+                       if (!g_ascii_strcasecmp (e_contact_field_name (default_summary_fields[i]), 
query_name)) {
+                               ret_val |= CHECK_IS_SUMMARY;
+
+                               if (e_contact_field_type (default_summary_fields[i]) == 
E_TYPE_CONTACT_ATTR_LIST)
+                                       ret_val |= CHECK_IS_LIST_ATTR;
 
-       return r;
+                               break;
+                       }
+               }
+       }
+
+       return ret_val;
 }
 
 static ESExpResult *
@@ -2477,7 +2698,6 @@ func_check (struct _ESExp *f,
            && argv[1]->type == ESEXP_RES_STRING) {
                const gchar *query_name = argv[0]->value.string;
                const gchar *query_value = argv[1]->value.string;
-               gint   i;
 
                /* Special case, when testing the special symbolic 'any field' we can
                 * consider it a summary query (it's similar to a 'no query'). */
@@ -2487,29 +2707,14 @@ func_check (struct _ESExp *f,
                        goto check_finish;
                }
 
-               if (ebsdb) {
-                       for (i = 0; i < ebsdb->priv->n_summary_fields; i++) {
-                               if (!strcmp (e_contact_field_name (ebsdb->priv->summary_fields[i].field), 
query_name)) {
-                                       ret_val |= CHECK_IS_SUMMARY;
-
-                                       if (ebsdb->priv->summary_fields[i].type == E_TYPE_CONTACT_ATTR_LIST)
-                                               ret_val |= CHECK_IS_LIST_ATTR;
-
-                                       break;
-                               }
-                       }
-               } else {
-                       for (i = 0; i < G_N_ELEMENTS (default_summary_fields); i++) {
-                               if (!strcmp (e_contact_field_name (default_summary_fields[i]), query_name)) {
-                                       ret_val |= CHECK_IS_SUMMARY;
-
-                                       if (e_contact_field_type (default_summary_fields[i]) == 
E_TYPE_CONTACT_ATTR_LIST)
-                                               ret_val |= CHECK_IS_LIST_ATTR;
-
-                                       break;
-                               }
-                       }
-               }
+               ret_val |= func_check_field_test (ebsdb, query_name, query_value);
+       } else if (argc == 3
+           && argv[0]->type == ESEXP_RES_STRING
+           && argv[1]->type == ESEXP_RES_STRING
+           && argv[2]->type == ESEXP_RES_STRING) {
+               const gchar *query_name = argv[0]->value.string;
+               const gchar *query_value = argv[1]->value.string;
+               ret_val |= func_check_field_test (ebsdb, query_name, query_value);
        }
 
  check_finish:
@@ -2521,18 +2726,17 @@ func_check (struct _ESExp *f,
 
 static ESExpResult *
 func_check_phone (struct _ESExp         *f,
-                  gint                  argc,
-                  struct _ESExpResult **argv,
-                  gpointer              data)
+                  gint                  argc,
+                  struct _ESExpResult **argv,
+                  gpointer              data)
 {
-       EBookBackendSqliteDB *ebsdb = data;
        ESExpResult *const r = func_check (f, argc, argv, data);
 
        if (r && r->value.number) {
                GError *error = NULL;
                const gchar *const query_value = argv[1]->value.string;
                EPhoneNumber *const number = e_phone_number_from_string (
-                               query_value, ebsdb->priv->country_code, &error);
+                               query_value, NULL, &error);
 
                if (number == NULL) {
                        if (error) {
@@ -2570,21 +2774,10 @@ static const struct {
        { "eqphone_short", func_check_phone, 0 }
 };
 
-/**
- * e_book_backend_sqlitedb_check_summary_query:
- * @ebsdb: an #EBookBackendSqliteDB
- * @query: the query to check
- * @with_list_attrs: Return location to store whether the query touches upon list attributes
- *
- * Checks whether @query contains only checks for the summary fields
- * configured in @ebsdb
- *
- * Since: 3.8
- **/
-gboolean
-e_book_backend_sqlitedb_check_summary_query (EBookBackendSqliteDB *ebsdb,
-                                            const gchar *query,
-                                            gboolean *with_list_attrs)
+static gboolean
+e_book_backend_sqlitedb_check_summary_query_locked (EBookBackendSqliteDB *ebsdb,
+                                                   const gchar *query,
+                                                   gboolean *with_list_attrs)
 {
        ESExp *sexp;
        ESExpResult *r;
@@ -2599,8 +2792,9 @@ e_book_backend_sqlitedb_check_summary_query (EBookBackendSqliteDB *ebsdb,
 
        for (i = 0; i < G_N_ELEMENTS (check_symbols); i++) {
                if (check_symbols[i].type == 1) {
-                       e_sexp_add_ifunction (sexp, 0, check_symbols[i].name,
-                                             (ESExpIFunc *) check_symbols[i].func, ebsdb);
+                       e_sexp_add_ifunction (
+                               sexp, 0, check_symbols[i].name,
+                               (ESExpIFunc *) check_symbols[i].func, ebsdb);
                } else {
                        e_sexp_add_function (
                                sexp, 0, check_symbols[i].name,
@@ -2629,6 +2823,32 @@ e_book_backend_sqlitedb_check_summary_query (EBookBackendSqliteDB *ebsdb,
        return retval;
 }
 
+/**
+ * e_book_backend_sqlitedb_check_summary_query:
+ * @ebsdb: an #EBookBackendSqliteDB
+ * @query: the query to check
+ * @with_list_attrs: Return location to store whether the query touches upon list attributes
+ *
+ * Checks whether @query contains only checks for the summary fields
+ * configured in @ebsdb
+ *
+ * Since: 3.8
+ **/
+gboolean
+e_book_backend_sqlitedb_check_summary_query (EBookBackendSqliteDB *ebsdb,
+                                             const gchar *query,
+                                             gboolean *with_list_attrs)
+{
+       gboolean is_summary;
+
+       g_return_val_if_fail (E_IS_BOOK_BACKEND_SQLITEDB (ebsdb), FALSE);
+
+       LOCK_MUTEX (&ebsdb->priv->lock);
+       is_summary = e_book_backend_sqlitedb_check_summary_query_locked (ebsdb, query, with_list_attrs);
+       UNLOCK_MUTEX (&ebsdb->priv->lock);
+
+       return is_summary;
+}
 
 /**
  * e_book_backend_sqlitedb_is_summary_query:
@@ -2642,7 +2862,7 @@ e_book_backend_sqlitedb_check_summary_query (EBookBackendSqliteDB *ebsdb,
 gboolean
 e_book_backend_sqlitedb_is_summary_query (const gchar *query)
 {
-       return e_book_backend_sqlitedb_check_summary_query (NULL, query, NULL);
+       return e_book_backend_sqlitedb_check_summary_query_locked (NULL, query, NULL);
 }
 
 static ESExpResult *
@@ -2664,7 +2884,7 @@ func_and (ESExp *f,
                        continue;
                }
                if (r1->value.string && *r1->value.string)
-                       g_string_append_printf (string, "%s%s", r1->value.string, ((argc > 1) && (i != argc - 
1)) ?  " AND ":"");
+                       g_string_append_printf (string, "%s%s", r1->value.string, ((argc > 1) && (i != argc - 
1)) ? " AND ":"");
                e_sexp_result_free (f, r1);
        }
        g_string_append (string, " )");
@@ -2699,7 +2919,7 @@ func_or (ESExp *f,
                        continue;
                }
                if (r1->value.string && *r1->value.string)
-                       g_string_append_printf (string, "%s%s", r1->value.string, ((argc > 1) && (i != argc - 
1)) ?  " OR ":"");
+                       g_string_append_printf (string, "%s%s", r1->value.string, ((argc > 1) && (i != argc - 
1)) ? " OR ":"");
                e_sexp_result_free (f, r1);
        }
        g_string_append (string, " )");
@@ -2729,7 +2949,7 @@ typedef enum {
        CONVERT_NOTHING   =  0,
        CONVERT_NORMALIZE = (1 << 0),
        CONVERT_REVERSE   = (1 << 1),
-       CONVERT_PHONE     = (1 << 2),
+       CONVERT_PHONE     = (1 << 2)
 } ConvertFlags;
 
 static gchar *
@@ -2758,9 +2978,9 @@ extract_digits (const gchar *normal)
 
 static gchar *
 convert_string_value (EBookBackendSqliteDB *ebsdb,
-                      const gchar          *value,
-                      ConvertFlags          flags,
-                      MatchType             match)
+                      const gchar          *value,
+                      ConvertFlags          flags,
+                      MatchType             match)
 {
        GString *str;
        size_t len;
@@ -2789,7 +3009,6 @@ convert_string_value (EBookBackendSqliteDB *ebsdb,
        switch (match) {
        case MATCH_CONTAINS:
        case MATCH_ENDS_WITH:
-       case MATCH_NATIONAL_PHONE_NUMBER:
        case MATCH_SHORT_PHONE_NUMBER:
                g_string_append_c (str, '%');
                break;
@@ -2797,6 +3016,7 @@ convert_string_value (EBookBackendSqliteDB *ebsdb,
        case MATCH_BEGINS_WITH:
        case MATCH_IS:
        case MATCH_PHONE_NUMBER:
+       case MATCH_NATIONAL_PHONE_NUMBER:
                break;
        }
 
@@ -2804,7 +3024,12 @@ convert_string_value (EBookBackendSqliteDB *ebsdb,
                computed = g_utf8_strreverse (normal, -1);
                ptr = computed;
        } else if (flags & CONVERT_PHONE) {
-               computed = convert_phone (normal, ebsdb->priv->country_code);
+               if (match == MATCH_NATIONAL_PHONE_NUMBER) {
+                       computed = convert_phone_national (normal, NULL);
+               } else {
+                       computed = convert_phone (normal, NULL);
+               }
+
                ptr = computed;
        } else {
                ptr = normal;
@@ -2901,56 +3126,61 @@ field_name_and_query_term (EBookBackendSqliteDB *ebsdb,
                                field_name = g_strdup ("multi.value_reverse");
                                list_attr = TRUE;
                        } else
-                               field_name = g_strconcat ("summary.",
-                                                         ebsdb->priv->summary_fields[summary_index].dbname,
-                                                         "_reverse", NULL);
+                               field_name = g_strconcat (
+                                       "summary.",
+                                       ebsdb->priv->summary_fields[summary_index].dbname,
+                                       "_reverse", NULL);
 
                        if (ebsdb->priv->summary_fields[summary_index].field == E_CONTACT_UID ||
                            ebsdb->priv->summary_fields[summary_index].field == E_CONTACT_REV)
-                               value = convert_string_value (ebsdb, query_term_input, CONVERT_REVERSE,
-                                                             (match == MATCH_ENDS_WITH) ? MATCH_BEGINS_WITH 
: MATCH_IS);
+                               value = convert_string_value (
+                                       ebsdb, query_term_input, CONVERT_REVERSE,
+                                       (match == MATCH_ENDS_WITH) ? MATCH_BEGINS_WITH : MATCH_IS);
                        else
-                               value = convert_string_value (ebsdb, query_term_input, CONVERT_REVERSE | 
CONVERT_NORMALIZE,
-                                                             (match == MATCH_ENDS_WITH) ? MATCH_BEGINS_WITH 
: MATCH_IS);
+                               value = convert_string_value (
+                                       ebsdb, query_term_input, CONVERT_REVERSE | CONVERT_NORMALIZE,
+                                       (match == MATCH_ENDS_WITH) ? MATCH_BEGINS_WITH : MATCH_IS);
                } else if (phone_search) {
                        /* Special case for E.164 matching:
                         *  o Normalize the string
                         *  o Check the E.164 column instead
                         */
+                       const gint country_code = e_phone_number_get_country_code_for_region (NULL);
+
                        if (ebsdb->priv->summary_fields[summary_index].type == E_TYPE_CONTACT_ATTR_LIST) {
                                field_name = g_strdup ("multi.value_phone");
                                list_attr = TRUE;
-                       } else
-                               field_name = g_strconcat ("summary.",
-                                                         ebsdb->priv->summary_fields[summary_index].dbname,
-                                                         "_phone", NULL);
+                       } else {
+                               field_name = g_strdup_printf ("summary.%s_phone",
+                                       ebsdb->priv->summary_fields[summary_index].dbname);
+                       }
 
                        if (match == MATCH_PHONE_NUMBER) {
-                               value = convert_string_value (ebsdb, query_term_input,
-                                                             CONVERT_NORMALIZE | CONVERT_PHONE, match);
-                       } else {
-                               gchar *digits = extract_digits (query_term_input);
+                               extra = g_strdup_printf (" COLLATE ixphone_%d", country_code);
 
-                               value = convert_string_value (ebsdb, digits, CONVERT_NOTHING, 
MATCH_ENDS_WITH);
+                               value = convert_string_value (
+                                       ebsdb, query_term_input,
+                                       CONVERT_NORMALIZE | CONVERT_PHONE, match);
+                       } else {
+                               gchar *const digits = extract_digits (query_term_input);
+                               extra = g_strdup (" COLLATE ixphone_nn");
 
                                if (match == MATCH_NATIONAL_PHONE_NUMBER) {
-                                       extra = sqlite3_mprintf (" AND eqphone_national(%q, %Q)", field_name, 
digits);
-                               } else if (match == MATCH_SHORT_PHONE_NUMBER) {
-                                       extra = sqlite3_mprintf (" AND eqphone_short(%q, %Q)", field_name, 
digits);
+                                       value = convert_string_value (ebsdb, digits, CONVERT_PHONE, 
MATCH_NATIONAL_PHONE_NUMBER);
                                } else {
-                                       g_assert_not_reached ();
+                                       value = convert_string_value (ebsdb, digits, CONVERT_NOTHING, 
MATCH_ENDS_WITH);
                                }
 
                                g_free (digits);
                        }
                } else {
-
                        if (ebsdb->priv->summary_fields[summary_index].type == E_TYPE_CONTACT_ATTR_LIST) {
                                field_name = g_strdup ("multi.value");
                                list_attr = TRUE;
                        } else
-                               field_name = g_strconcat ("summary.",
-                                                         ebsdb->priv->summary_fields[summary_index].dbname, 
NULL);
+                               field_name = g_strconcat (
+                                       "summary.",
+                                       ebsdb->priv->summary_fields[summary_index].dbname, NULL);
 
                        if (ebsdb->priv->summary_fields[summary_index].field == E_CONTACT_UID ||
                            ebsdb->priv->summary_fields[summary_index].field == E_CONTACT_REV)
@@ -2982,12 +3212,12 @@ field_oper (MatchType match)
        switch (match) {
        case MATCH_IS:
        case MATCH_PHONE_NUMBER:
+       case MATCH_NATIONAL_PHONE_NUMBER:
                return "=";
 
        case MATCH_CONTAINS:
        case MATCH_BEGINS_WITH:
        case MATCH_ENDS_WITH:
-       case MATCH_NATIONAL_PHONE_NUMBER:
        case MATCH_SHORT_PHONE_NUMBER:
                break;
        }
@@ -3002,7 +3232,7 @@ convert_match_exp (struct _ESExp *f,
                    gpointer data,
                    MatchType match)
 {
-       BuildQueryData *qdata = (BuildQueryData *)data;
+       BuildQueryData *qdata = (BuildQueryData *) data;
        EBookBackendSqliteDB *ebsdb = qdata->ebsdb;
        ESExpResult *r;
        gchar *str = NULL;
@@ -3018,49 +3248,51 @@ convert_match_exp (struct _ESExp *f,
                        const gchar *const oper = field_oper (match);
                        gchar *field_name, *query_term, *extra_term;
 
-                       if (!strcmp (field, "full_name")) {
+                       if (!g_ascii_strcasecmp (field, "full_name")) {
                                GString *names = g_string_new (NULL);
 
-                               field_name = field_name_and_query_term (ebsdb, qdata->folderid, "full_name",
-                                                                       argv[1]->value.string,
-                                                                       match, NULL, &query_term, NULL);
-                               g_string_append_printf (names, "(%s IS NOT NULL AND %s %s %s)",
-                                                       field_name, field_name, oper, query_term);
+                               field_name = field_name_and_query_term (
+                                       ebsdb, qdata->folderid, "full_name",
+                                       argv[1]->value.string,
+                                       match, NULL, &query_term, NULL);
+                               g_string_append_printf (
+                                       names, "(%s IS NOT NULL AND %s %s %s)",
+                                       field_name, field_name, oper, query_term);
                                g_free (field_name);
                                g_free (query_term);
 
                                if (summary_dbname_from_field (ebsdb, E_CONTACT_FAMILY_NAME)) {
-
-                                       field_name = field_name_and_query_term (ebsdb, qdata->folderid, 
"family_name",
-                                                                               argv[1]->value.string,
-                                                                               match, NULL, &query_term, 
NULL);
-                                       g_string_append_printf
-                                               (names, " OR (%s IS NOT NULL AND %s %s %s)",
-                                                field_name, field_name, oper, query_term);
+                                       field_name = field_name_and_query_term (
+                                               ebsdb, qdata->folderid, "family_name",
+                                               argv[1]->value.string,
+                                               match, NULL, &query_term, NULL);
+                                       g_string_append_printf (
+                                               names, " OR (%s IS NOT NULL AND %s %s %s)",
+                                               field_name, field_name, oper, query_term);
                                        g_free (field_name);
                                        g_free (query_term);
                                }
 
                                if (summary_dbname_from_field (ebsdb, E_CONTACT_GIVEN_NAME)) {
-
-                                       field_name = field_name_and_query_term (ebsdb, qdata->folderid, 
"given_name",
-                                                                               argv[1]->value.string,
-                                                                               match, NULL, &query_term, 
NULL);
-                                       g_string_append_printf
-                                               (names, " OR (%s IS NOT NULL AND %s %s %s)",
-                                                field_name, field_name, oper, query_term);
+                                       field_name = field_name_and_query_term (
+                                               ebsdb, qdata->folderid, "given_name",
+                                               argv[1]->value.string,
+                                               match, NULL, &query_term, NULL);
+                                       g_string_append_printf (
+                                               names, " OR (%s IS NOT NULL AND %s %s %s)",
+                                               field_name, field_name, oper, query_term);
                                        g_free (field_name);
                                        g_free (query_term);
                                }
 
                                if (summary_dbname_from_field (ebsdb, E_CONTACT_NICKNAME)) {
-
-                                       field_name = field_name_and_query_term (ebsdb, qdata->folderid, 
"nickname",
-                                                                               argv[1]->value.string,
-                                                                               match, NULL, &query_term, 
NULL);
-                                       g_string_append_printf
-                                               (names, " OR (%s IS NOT NULL AND %s %s %s)",
-                                                field_name, field_name, oper, query_term);
+                                       field_name = field_name_and_query_term (
+                                               ebsdb, qdata->folderid, "nickname",
+                                               argv[1]->value.string,
+                                               match, NULL, &query_term, NULL);
+                                       g_string_append_printf (
+                                               names, " OR (%s IS NOT NULL AND %s %s %s)",
+                                               field_name, field_name, oper, query_term);
                                        g_free (field_name);
                                        g_free (query_term);
                                }
@@ -3069,12 +3301,19 @@ convert_match_exp (struct _ESExp *f,
                                g_string_free (names, FALSE);
 
                        } else {
+                               const gchar *const query_locale =
+                                       argc > 2 && argv[2]->type == ESEXP_RES_STRING ?
+                                       argv[2]->value.string : NULL;
+                               const gchar *const saved_locale = query_locale ?
+                                       setlocale (LC_ADDRESS, query_locale) : NULL;
+
                                gboolean is_list = FALSE;
 
                                /* This should ideally be the only valid case from all the above special 
casing, but oh well... */
-                               field_name = field_name_and_query_term (ebsdb, qdata->folderid, field,
-                                                                       argv[1]->value.string,
-                                                                       match, &is_list, &query_term, 
&extra_term);
+                               field_name = field_name_and_query_term (
+                                       ebsdb, qdata->folderid, field,
+                                       argv[1]->value.string,
+                                       match, &is_list, &query_term, &extra_term);
 
                                /* User functions like eqphone_national() cannot utilize indexes. Therefore we
                                 * should reduce the result set first before applying any user functions. This
@@ -3084,17 +3323,22 @@ convert_match_exp (struct _ESExp *f,
                                        gchar *tmp;
 
                                        tmp = sqlite3_mprintf ("summary.uid = multi.uid AND multi.field = 
%Q", field);
-                                       str = g_strdup_printf ("(%s AND %s %s %s%s)",
-                                                              tmp, field_name, oper, query_term,
-                                                              extra_term ? extra_term : "");
+                                       str = g_strdup_printf (
+                                               "(%s AND (%s %s %s%s))",
+                                               tmp, field_name, oper, query_term,
+                                               extra_term ? extra_term : "");
                                        sqlite3_free (tmp);
                                } else
-                                       str = g_strdup_printf ("(%s IS NOT NULL AND %s %s %s%s)",
-                                                              field_name, field_name, oper, query_term,
-                                                              extra_term ? extra_term : "");
+                                       str = g_strdup_printf (
+                                               "(%s IS NOT NULL AND (%s %s %s%s))",
+                                               field_name, field_name, oper, query_term,
+                                               extra_term ? extra_term : "");
 
                                g_free (field_name);
                                g_free (query_term);
+
+                               if (saved_locale)
+                                       setlocale (LC_ADDRESS, saved_locale);
                        }
                }
        }
@@ -3143,27 +3387,27 @@ func_endswith (struct _ESExp *f,
 
 static ESExpResult *
 func_eqphone (struct _ESExp *f,
-              gint argc,
-              struct _ESExpResult **argv,
-              gpointer data)
+              gint argc,
+              struct _ESExpResult **argv,
+              gpointer data)
 {
        return convert_match_exp (f, argc, argv, data, MATCH_PHONE_NUMBER);
 }
 
 static ESExpResult *
 func_eqphone_national (struct _ESExp *f,
-                       gint argc,
-                       struct _ESExpResult **argv,
-                       gpointer data)
+                       gint argc,
+                       struct _ESExpResult **argv,
+                       gpointer data)
 {
        return convert_match_exp (f, argc, argv, data, MATCH_NATIONAL_PHONE_NUMBER);
 }
 
 static ESExpResult *
 func_eqphone_short (struct _ESExp *f,
-                    gint argc,
-                    struct _ESExpResult **argv,
-                    gpointer data)
+                    gint argc,
+                    struct _ESExpResult **argv,
+                    gpointer data)
 {
        return convert_match_exp (f, argc, argv, data, MATCH_SHORT_PHONE_NUMBER);
 }
@@ -3188,8 +3432,8 @@ static struct {
 
 static gchar *
 sexp_to_sql_query (EBookBackendSqliteDB *ebsdb,
-                  const gchar          *folderid,
-                  const gchar          *query)
+                   const gchar *folderid,
+                   const gchar *query)
 {
        BuildQueryData data = { ebsdb, folderid };
        ESExp *sexp;
@@ -3201,8 +3445,9 @@ sexp_to_sql_query (EBookBackendSqliteDB *ebsdb,
 
        for (i = 0; i < G_N_ELEMENTS (symbols); i++) {
                if (symbols[i].immediate)
-                       e_sexp_add_ifunction (sexp, 0, symbols[i].name,
-                                            (ESExpIFunc *) symbols[i].func, &data);
+                       e_sexp_add_ifunction (
+                               sexp, 0, symbols[i].name,
+                               (ESExpIFunc *) symbols[i].func, &data);
                else
                        e_sexp_add_function (
                                sexp, 0, symbols[i].name,
@@ -3270,50 +3515,50 @@ addto_slist_cb (gpointer ref,
 
 static GSList *
 book_backend_sqlitedb_search_query (EBookBackendSqliteDB *ebsdb,
-                                         const gchar *sql,
-                                         const gchar *folderid,
-                                        /* const */ GHashTable *fields_of_interest,
-                                         gboolean *with_all_required_fields,
-                                        gboolean query_with_list_attrs,
-                                         GError **error)
+                                    const gchar *sql,
+                                    const gchar *folderid,
+                                    GHashTable *fields_of_interest,
+                                    gboolean *with_all_required_fields,
+                                    gboolean query_with_list_attrs,
+                                    GError **error)
 {
-       GError *err = NULL;
        GSList *vcard_data = NULL;
        gchar  *stmt;
        gboolean local_with_all_required_fields = FALSE;
-
-       READER_LOCK (ebsdb);
+       gboolean success = TRUE;
 
        /* Try constructing contacts from only UID/REV first if that's requested */
        if (uid_rev_fields (fields_of_interest)) {
                gchar *select_portion;
 
-               select_portion = summary_select_stmt (fields_of_interest,
-                                                     query_with_list_attrs);
+               select_portion = summary_select_stmt (
+                       fields_of_interest, query_with_list_attrs);
 
                if (sql && sql[0]) {
 
                        if (query_with_list_attrs) {
                                gchar *list_table = g_strconcat (folderid, "_lists", NULL);
 
-                               stmt = sqlite3_mprintf ("%s FROM %Q AS summary, %Q AS multi WHERE %s",
-                                                       select_portion, folderid, list_table, sql);
+                               stmt = sqlite3_mprintf (
+                                       "%s FROM %Q AS summary, %Q AS multi WHERE %s",
+                                       select_portion, folderid, list_table, sql);
                                g_free (list_table);
                        } else {
-                               stmt = sqlite3_mprintf ("%s FROM %Q AS summary WHERE %s",
-                                                       select_portion, folderid, sql);
+                               stmt = sqlite3_mprintf (
+                                       "%s FROM %Q AS summary WHERE %s",
+                                       select_portion, folderid, sql);
                        }
 
-                       book_backend_sql_exec (
-                                ebsdb->priv->db, stmt,
-                               store_data_to_vcard, &vcard_data, &err);
+                       success = book_backend_sql_exec (
+                               ebsdb->priv->db, stmt,
+                               store_data_to_vcard, &vcard_data, error);
 
                        sqlite3_free (stmt);
                } else {
                        stmt = sqlite3_mprintf ("%s FROM %Q AS summary", select_portion, folderid);
-                       book_backend_sql_exec (
+                       success = book_backend_sql_exec (
                                ebsdb->priv->db, stmt,
-                               store_data_to_vcard, &vcard_data, &err);
+                               store_data_to_vcard, &vcard_data, error);
                        sqlite3_free (stmt);
                }
 
@@ -3327,40 +3572,46 @@ book_backend_sqlitedb_search_query (EBookBackendSqliteDB *ebsdb,
                        if (query_with_list_attrs) {
                                gchar *list_table = g_strconcat (folderid, "_lists", NULL);
 
-                               stmt = sqlite3_mprintf ("SELECT DISTINCT summary.uid, vcard, bdata "
-                                                       "FROM %Q AS summary, %Q AS multi WHERE %s",
-                                                       folderid, list_table, sql);
+                               stmt = sqlite3_mprintf (
+                                       "SELECT DISTINCT summary.uid, vcard, bdata "
+                                       "FROM %Q AS summary, %Q AS multi WHERE %s",
+                                       folderid, list_table, sql);
                                g_free (list_table);
                        } else {
-                               stmt = sqlite3_mprintf ("SELECT uid, vcard, bdata FROM %Q as summary WHERE 
%s", folderid, sql);
+                               stmt = sqlite3_mprintf (
+                                       "SELECT uid, vcard, bdata FROM %Q as summary WHERE %s", folderid, 
sql);
                        }
 
-                       book_backend_sql_exec (ebsdb->priv->db, stmt, addto_vcard_list_cb , &vcard_data, 
&err);
+                       success = book_backend_sql_exec (
+                               ebsdb->priv->db, stmt,
+                               addto_vcard_list_cb , &vcard_data, error);
+
                        sqlite3_free (stmt);
                } else {
-                       stmt = sqlite3_mprintf ("SELECT uid, vcard, bdata FROM %Q", folderid);
-                       book_backend_sql_exec (ebsdb->priv->db, stmt, addto_vcard_list_cb , &vcard_data, 
&err);
+                       stmt = sqlite3_mprintf (
+                               "SELECT uid, vcard, bdata FROM %Q", folderid);
+                       success = book_backend_sql_exec (
+                               ebsdb->priv->db, stmt,
+                               addto_vcard_list_cb , &vcard_data, error);
                        sqlite3_free (stmt);
                }
+
                local_with_all_required_fields = TRUE;
        } else {
-               g_set_error (error, E_BOOK_SDB_ERROR,
-                            E_BOOK_SDB_ERROR_OTHER,
-                            _("Full search_contacts are not stored in cache. vcards cannot be returned."));
+               g_set_error (
+                       error, E_BOOK_SDB_ERROR, E_BOOK_SDB_ERROR_OTHER,
+                       _("Full search_contacts are not stored in cache. vcards cannot be returned."));
        }
 
-       READER_UNLOCK (ebsdb);
-
-       if (vcard_data)
-               vcard_data = g_slist_reverse (vcard_data);
-
-       if (err)
-               g_propagate_error (error, err);
+       if (!success) {
+               g_warn_if_fail (vcard_data == NULL);
+               return NULL;
+       }
 
        if (with_all_required_fields)
-               * with_all_required_fields = local_with_all_required_fields;
+               *with_all_required_fields = local_with_all_required_fields;
 
-       return vcard_data;
+       return g_slist_reverse (vcard_data);
 }
 
 static GSList *
@@ -3370,39 +3621,39 @@ book_backend_sqlitedb_search_full (EBookBackendSqliteDB *ebsdb,
                                    gboolean return_uids,
                                    GError **error)
 {
-       GError *err = NULL;
        GSList *r_list = NULL, *all = NULL, *l;
        EBookBackendSExp *bsexp = NULL;
+       gboolean success;
        gchar *stmt;
 
-       READER_LOCK (ebsdb);
-
        stmt = sqlite3_mprintf ("SELECT uid, vcard, bdata FROM %Q", folderid);
-       book_backend_sql_exec (ebsdb->priv->db, stmt, addto_vcard_list_cb , &all, &err);
+       success = book_backend_sql_exec (
+               ebsdb->priv->db, stmt, addto_vcard_list_cb , &all, error);
        sqlite3_free (stmt);
 
-       READER_UNLOCK (ebsdb);
+       if (!success) {
+               g_warn_if_fail (all == NULL);
+               return NULL;
+       }
 
-       if (!err) {
-               bsexp = e_book_backend_sexp_new (sexp);
+       bsexp = e_book_backend_sexp_new (sexp);
 
-               for (l = all; l != NULL; l = g_slist_next (l)) {
-                       EbSdbSearchData *s_data = (EbSdbSearchData *) l->data;
+       for (l = all; l != NULL; l = g_slist_next (l)) {
+               EbSdbSearchData *s_data = (EbSdbSearchData *) l->data;
 
-                       if (e_book_backend_sexp_match_vcard (bsexp, s_data->vcard)) {
-                               if (!return_uids)
-                                       r_list = g_slist_prepend (r_list, s_data);
-                               else {
-                                       r_list = g_slist_prepend (r_list, g_strdup (s_data->uid));
-                                       e_book_backend_sqlitedb_search_data_free (s_data);
-                               }
-                       } else
+               if (e_book_backend_sexp_match_vcard (bsexp, s_data->vcard)) {
+                       if (!return_uids)
+                               r_list = g_slist_prepend (r_list, s_data);
+                       else {
+                               r_list = g_slist_prepend (r_list, g_strdup (s_data->uid));
                                e_book_backend_sqlitedb_search_data_free (s_data);
-               }
-
-               g_object_unref (bsexp);
+                       }
+               } else
+                       e_book_backend_sqlitedb_search_data_free (s_data);
        }
 
+       g_object_unref (bsexp);
+
        g_slist_free (all);
 
        return r_list;
@@ -3412,25 +3663,30 @@ book_backend_sqlitedb_search_full (EBookBackendSqliteDB *ebsdb,
  * e_book_backend_sqlitedb_search 
  * @ebsdb: 
  * @folderid: 
- * @sexp: search expression; use NULL or an empty string to get all stored contacts.
- * @fields_of_interest: a #GHashTable containing the names of fields to return, or NULL for all. 
- *  At the moment if this is non-null, the vcard will be populated with summary fields, else it would return 
the 
- *  whole vcard if its stored in the db. [not implemented fully]
- * @searched: (allow none) (out): Whether @ebsdb was capable of searching for the provided query @sexp.
- * @with_all_required_fields: (allow none) (out): Whether all the required fields are present in the 
returned vcards.
+ * @sexp: search expression; use NULL or an empty string to get all stored
+ * contacts.
+ * @fields_of_interest: a #GHashTable containing the names of fields to return,
+ * or NULL for all.  At the moment if this is non-null, the vcard will be
+ * populated with summary fields, else it would return the whole vcard if
+ * its stored in the db. [not implemented fully]
+ * @searched: (allow none) (out): Whether @ebsdb was capable of searching
+ * for the provided query @sexp.
+ * @with_all_required_fields: (allow none) (out): Whether all the required
+ * fields are present in the returned vcards.
  * @error: 
  *
- * Searching with summary fields is always supported. Search expressions containing
- * any other field is supported only if backend chooses to store the vcard inside the db.
+ * Searching with summary fields is always supported. Search expressions
+ * containing any other field is supported only if backend chooses to store
+ * the vcard inside the db.
  *
- * Summary fields - uid, rev, nickname, given_name, family_name, file_as email_1, email_2, email_3, email_4, 
is_list, 
- * list_show_addresses, wants_html
+ * Summary fields - uid, rev, nickname, given_name, family_name, file_as
+ * email_1, email_2, email_3, email_4, is_list, list_show_addresses, wants_html
  *
  * If @ebsdb was incapable of returning vcards with results that satisfy
- * @fields_of_interest, then @with_all_required_fields will be updated to @FALSE
- * and only uid fields will be present in the returned vcards. This can be useful
- * when a summary query succeeds and the returned list can be used to iterate
- * and fetch for full required data from another persistance.
+ * @fields_of_interest, then @with_all_required_fields will be updated to
+ * @FALSE and only uid fields will be present in the returned vcards. This
+ * can be useful when a summary query succeeds and the returned list can be
+ * used to iterate and fetch for full required data from another persistance.
  *
  * Returns: List of EbSdbSearchData.
  *
@@ -3440,7 +3696,7 @@ GSList *
 e_book_backend_sqlitedb_search (EBookBackendSqliteDB *ebsdb,
                                 const gchar *folderid,
                                 const gchar *sexp,
-                                /* const */ GHashTable *fields_of_interest,
+                                GHashTable *fields_of_interest,
                                 gboolean *searched,
                                 gboolean *with_all_required_fields,
                                 GError **error)
@@ -3456,8 +3712,10 @@ e_book_backend_sqlitedb_search (EBookBackendSqliteDB *ebsdb,
        if (sexp && !*sexp)
                sexp = NULL;
 
-       if (!sexp || e_book_backend_sqlitedb_check_summary_query (ebsdb, sexp,
-                                                                 &query_with_list_attrs)) {
+       LOCK_MUTEX (&ebsdb->priv->lock);
+
+       if (!sexp || e_book_backend_sqlitedb_check_summary_query_locked (ebsdb, sexp,
+                                                                        &query_with_list_attrs)) {
                gchar *sql_query;
 
                sql_query = sexp ? sexp_to_sql_query (ebsdb, folderid, sexp) : NULL;
@@ -3471,16 +3729,21 @@ e_book_backend_sqlitedb_search (EBookBackendSqliteDB *ebsdb,
                local_searched = TRUE;
 
        } else if (ebsdb->priv->store_vcard) {
-               search_contacts = book_backend_sqlitedb_search_full (ebsdb, sexp, folderid, FALSE, error);
+               search_contacts = book_backend_sqlitedb_search_full (
+                       ebsdb, sexp, folderid, FALSE, error);
+
                local_searched = TRUE;
                local_with_all_required_fields = TRUE;
+
        } else {
                g_set_error (
                        error, E_BOOK_SDB_ERROR, E_BOOK_SDB_ERROR_OTHER,
                        _("Full search_contacts are not stored in cache. "
-                         "Hence only summary query is supported."));
+                       "Hence only summary query is supported."));
        }
 
+       UNLOCK_MUTEX (&ebsdb->priv->lock);
+
        if (searched)
                *searched = local_searched;
        if (with_all_required_fields)
@@ -3513,23 +3776,26 @@ e_book_backend_sqlitedb_search_uids (EBookBackendSqliteDB *ebsdb,
        if (sexp && !*sexp)
                sexp = NULL;
 
-       if (!sexp || e_book_backend_sqlitedb_check_summary_query (ebsdb, sexp, &query_with_list_attrs)) {
+       LOCK_MUTEX (&ebsdb->priv->lock);
+
+       if (!sexp || e_book_backend_sqlitedb_check_summary_query_locked (ebsdb, sexp, 
&query_with_list_attrs)) {
                gchar *stmt;
                gchar *sql_query = sexp ? sexp_to_sql_query (ebsdb, folderid, sexp) : NULL;
 
-               READER_LOCK (ebsdb);
-
                if (sql_query && sql_query[0]) {
 
                        if (query_with_list_attrs) {
                                gchar *list_table = g_strconcat (folderid, "_lists", NULL);
 
-                               stmt = sqlite3_mprintf ("SELECT DISTINCT summary.uid FROM %Q AS summary, %Q 
AS multi WHERE %s",
-                                                       folderid, list_table, sql_query);
+                               stmt = sqlite3_mprintf (
+                                       "SELECT DISTINCT summary.uid FROM %Q AS summary, %Q AS multi WHERE 
%s",
+                                       folderid, list_table, sql_query);
 
                                g_free (list_table);
                        } else
-                               stmt = sqlite3_mprintf ("SELECT summary.uid FROM %Q AS summary WHERE %s", 
folderid, sql_query);
+                               stmt = sqlite3_mprintf (
+                                       "SELECT summary.uid FROM %Q AS summary WHERE %s",
+                                       folderid, sql_query);
 
                        book_backend_sql_exec (ebsdb->priv->db, stmt, addto_slist_cb, &uids, error);
                        sqlite3_free (stmt);
@@ -3540,22 +3806,25 @@ e_book_backend_sqlitedb_search_uids (EBookBackendSqliteDB *ebsdb,
                        sqlite3_free (stmt);
                }
 
-               READER_UNLOCK (ebsdb);
-
                local_searched = TRUE;
 
                g_free (sql_query);
+
        } else if (ebsdb->priv->store_vcard) {
-               uids = book_backend_sqlitedb_search_full (ebsdb, sexp, folderid, TRUE, error);
+               uids = book_backend_sqlitedb_search_full (
+                       ebsdb, sexp, folderid, TRUE, error);
 
                local_searched = TRUE;
+
        } else {
                g_set_error (
                        error, E_BOOK_SDB_ERROR, E_BOOK_SDB_ERROR_OTHER,
                        _("Full vcards are not stored in cache. "
-                         "Hence only summary query is supported."));
+                       "Hence only summary query is supported."));
        }
 
+       UNLOCK_MUTEX (&ebsdb->priv->lock);
+
        if (searched)
                *searched = local_searched;
 
@@ -3599,13 +3868,15 @@ e_book_backend_sqlitedb_get_uids_and_rev (EBookBackendSqliteDB *ebsdb,
 
        uids_and_rev = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_free);
 
-       READER_LOCK (ebsdb);
+       LOCK_MUTEX (&ebsdb->priv->lock);
 
        stmt = sqlite3_mprintf ("SELECT uid,rev FROM %Q", folderid);
-       book_backend_sql_exec (ebsdb->priv->db, stmt, get_uids_and_rev_cb, uids_and_rev, error);
+       book_backend_sql_exec (
+               ebsdb->priv->db, stmt,
+               get_uids_and_rev_cb, uids_and_rev, error);
        sqlite3_free (stmt);
 
-       READER_UNLOCK (ebsdb);
+       UNLOCK_MUTEX (&ebsdb->priv->lock);
 
        return uids_and_rev;
 }
@@ -3628,13 +3899,16 @@ e_book_backend_sqlitedb_get_is_populated (EBookBackendSqliteDB *ebsdb,
        g_return_val_if_fail (E_IS_BOOK_BACKEND_SQLITEDB (ebsdb), FALSE);
        g_return_val_if_fail (folderid != NULL, FALSE);
 
-       READER_LOCK (ebsdb);
+       LOCK_MUTEX (&ebsdb->priv->lock);
 
-       stmt = sqlite3_mprintf ("SELECT is_populated FROM folders WHERE folder_id = %Q", folderid);
-       book_backend_sql_exec (ebsdb->priv->db, stmt, get_bool_cb , &ret, error);
+       stmt = sqlite3_mprintf (
+               "SELECT is_populated FROM folders WHERE folder_id = %Q",
+               folderid);
+       book_backend_sql_exec (
+               ebsdb->priv->db, stmt, get_bool_cb , &ret, error);
        sqlite3_free (stmt);
 
-       READER_UNLOCK (ebsdb);
+       UNLOCK_MUTEX (&ebsdb->priv->lock);
 
        return ret;
 
@@ -3654,34 +3928,42 @@ e_book_backend_sqlitedb_set_is_populated (EBookBackendSqliteDB *ebsdb,
                                           GError **error)
 {
        gchar *stmt = NULL;
-       GError *err = NULL;
+       gboolean success;
 
        g_return_val_if_fail (E_IS_BOOK_BACKEND_SQLITEDB (ebsdb), FALSE);
        g_return_val_if_fail (folderid != NULL, FALSE);
 
-       book_backend_sqlitedb_start_transaction (ebsdb, &err);
+       LOCK_MUTEX (&ebsdb->priv->lock);
 
-       if (!err) {
-               stmt = sqlite3_mprintf (
-                       "UPDATE folders SET is_populated = %d WHERE folder_id = %Q",
-                       populated, folderid);
-               book_backend_sql_exec (ebsdb->priv->db, stmt, NULL, NULL, &err);
-               sqlite3_free (stmt);
+       if (!book_backend_sqlitedb_start_transaction (ebsdb, error)) {
+               UNLOCK_MUTEX (&ebsdb->priv->lock);
+               return FALSE;
        }
 
-       book_backend_sqlitedb_end_transaction (ebsdb, !err, err ? NULL : &err);
+       stmt = sqlite3_mprintf (
+               "UPDATE folders SET is_populated = %d "
+               "WHERE folder_id = %Q", populated, folderid);
+       success = book_backend_sql_exec (
+                ebsdb->priv->db, stmt, NULL, NULL, error);
+       sqlite3_free (stmt);
+
+       if (success)
+               success = book_backend_sqlitedb_commit_transaction (ebsdb, error);
+       else
+               /* The GError is already set. */
+               book_backend_sqlitedb_rollback_transaction (ebsdb, NULL);
 
-       if (err)
-               g_propagate_error (error, err);
+       UNLOCK_MUTEX (&ebsdb->priv->lock);
 
-       return !err;
+       return success;
 }
 
 /**
  * e_book_backend_sqlitedb_get_revision:
  * @ebsdb: An #EBookBackendSqliteDB
  * @folderid: folder id of the address-book
- * @revision_out: (out) (transfer full): The location to return the current revision
+ * @revision_out: (out) (transfer full): The location to return the current
+ * revision
  * @error: A location to store any error that may have occurred
  *
  * Fetches the current revision for the address-book indicated by @folderid.
@@ -3695,29 +3977,28 @@ e_book_backend_sqlitedb_set_is_populated (EBookBackendSqliteDB *ebsdb,
  */
 gboolean
 e_book_backend_sqlitedb_get_revision (EBookBackendSqliteDB *ebsdb,
-                                     const gchar *folderid,
-                                     gchar **revision_out,
-                                     GError **error)
+                                      const gchar *folderid,
+                                      gchar **revision_out,
+                                      GError **error)
 {
        gchar *stmt;
-       GError *err = NULL;
+       gboolean success;
 
        g_return_val_if_fail (E_IS_BOOK_BACKEND_SQLITEDB (ebsdb), FALSE);
        g_return_val_if_fail (folderid && folderid[0], FALSE);
        g_return_val_if_fail (revision_out != NULL && *revision_out == NULL, FALSE);
 
-       READER_LOCK (ebsdb);
+       LOCK_MUTEX (&ebsdb->priv->lock);
 
-       stmt = sqlite3_mprintf ("SELECT revision FROM folders WHERE folder_id = %Q", folderid);
-       book_backend_sql_exec (ebsdb->priv->db, stmt, get_string_cb, &revision_out, &err);
+       stmt = sqlite3_mprintf (
+               "SELECT revision FROM folders WHERE folder_id = %Q", folderid);
+       success = book_backend_sql_exec (
+               ebsdb->priv->db, stmt, get_string_cb, &revision_out, error);
        sqlite3_free (stmt);
 
-       READER_UNLOCK (ebsdb);
+       UNLOCK_MUTEX (&ebsdb->priv->lock);
 
-       if (err)
-               g_propagate_error (error, err);
-
-       return !err;
+       return success;
 }
 
 /**
@@ -3735,35 +4016,41 @@ e_book_backend_sqlitedb_get_revision (EBookBackendSqliteDB *ebsdb,
  */
 gboolean
 e_book_backend_sqlitedb_set_revision (EBookBackendSqliteDB *ebsdb,
-                                     const gchar *folderid,
-                                     const gchar *revision,
-                                     GError **error)
+                                      const gchar *folderid,
+                                      const gchar *revision,
+                                      GError **error)
 {
        gchar *stmt = NULL;
-       GError *err = NULL;
+       gboolean success;
 
        g_return_val_if_fail (E_IS_BOOK_BACKEND_SQLITEDB (ebsdb), FALSE);
        g_return_val_if_fail (folderid && folderid[0], FALSE);
 
-       book_backend_sqlitedb_start_transaction (ebsdb, &err);
+       LOCK_MUTEX (&ebsdb->priv->lock);
 
-       if (!err) {
-               stmt = sqlite3_mprintf ("UPDATE folders SET revision = %Q WHERE folder_id = %Q",
-                                       revision, folderid);
-               book_backend_sql_exec (ebsdb->priv->db, stmt, NULL, NULL, &err);
-               sqlite3_free (stmt);
+       if (!book_backend_sqlitedb_start_transaction (ebsdb, error)) {
+               UNLOCK_MUTEX (&ebsdb->priv->lock);
+               return FALSE;
        }
 
-       book_backend_sqlitedb_end_transaction (ebsdb, !err, err ? NULL : &err);
+       stmt = sqlite3_mprintf (
+               "UPDATE folders SET revision = %Q "
+               "WHERE folder_id = %Q", revision, folderid);
+       success = book_backend_sql_exec (
+               ebsdb->priv->db, stmt, NULL, NULL, error);
+       sqlite3_free (stmt);
 
-       if (err)
-               g_propagate_error (error, err);
+       if (success)
+               success = book_backend_sqlitedb_commit_transaction (ebsdb, error);
+       else
+               /* The GError is already set. */
+               book_backend_sqlitedb_rollback_transaction (ebsdb, NULL);
 
-       return !err;
+       UNLOCK_MUTEX (&ebsdb->priv->lock);
 
+       return success;
 }
 
-
 /**
  * e_book_backend_sqlitedb_get_has_partial_content 
  * @ebsdb: 
@@ -3787,13 +4074,16 @@ e_book_backend_sqlitedb_get_has_partial_content (EBookBackendSqliteDB *ebsdb,
        g_return_val_if_fail (E_IS_BOOK_BACKEND_SQLITEDB (ebsdb), FALSE);
        g_return_val_if_fail (folderid != NULL, FALSE);
 
-       READER_LOCK (ebsdb);
+       LOCK_MUTEX (&ebsdb->priv->lock);
 
-       stmt = sqlite3_mprintf ("SELECT partial_content FROM folders WHERE folder_id = %Q", folderid);
-       book_backend_sql_exec (ebsdb->priv->db, stmt, get_bool_cb , &ret, error);
+       stmt = sqlite3_mprintf (
+               "SELECT partial_content FROM folders "
+               "WHERE folder_id = %Q", folderid);
+       book_backend_sql_exec (
+               ebsdb->priv->db, stmt, get_bool_cb , &ret, error);
        sqlite3_free (stmt);
 
-       READER_UNLOCK (ebsdb);
+       UNLOCK_MUTEX (&ebsdb->priv->lock);
 
        return ret;
 }
@@ -3812,27 +4102,34 @@ e_book_backend_sqlitedb_set_has_partial_content (EBookBackendSqliteDB *ebsdb,
                                                  GError **error)
 {
        gchar *stmt = NULL;
-       GError *err = NULL;
+       gboolean success;
 
        g_return_val_if_fail (E_IS_BOOK_BACKEND_SQLITEDB (ebsdb), FALSE);
        g_return_val_if_fail (folderid != NULL, FALSE);
 
-       book_backend_sqlitedb_start_transaction (ebsdb, &err);
+       LOCK_MUTEX (&ebsdb->priv->lock);
 
-       if (!err) {
-               stmt = sqlite3_mprintf (
-                       "UPDATE folders SET partial_content = %d WHERE folder_id = %Q",
-                                       partial_content, folderid);
-               book_backend_sql_exec (ebsdb->priv->db, stmt, NULL, NULL, &err);
-               sqlite3_free (stmt);
+       if (!book_backend_sqlitedb_start_transaction (ebsdb, error)) {
+               UNLOCK_MUTEX (&ebsdb->priv->lock);
+               return FALSE;
        }
 
-       book_backend_sqlitedb_end_transaction (ebsdb, !err, err ? NULL : &err);
+       stmt = sqlite3_mprintf (
+               "UPDATE folders SET partial_content = %d "
+               "WHERE folder_id = %Q", partial_content, folderid);
+       success = book_backend_sql_exec (
+               ebsdb->priv->db, stmt, NULL, NULL, error);
+       sqlite3_free (stmt);
+
+       if (success)
+               success = book_backend_sqlitedb_commit_transaction (ebsdb, error);
+       else
+               /* The GError is already set. */
+               book_backend_sqlitedb_rollback_transaction (ebsdb, NULL);
 
-       if (err)
-               g_propagate_error (error, err);
+       UNLOCK_MUTEX (&ebsdb->priv->lock);
 
-       return !err;
+       return success;
 }
 
 /**
@@ -3849,18 +4146,26 @@ e_book_backend_sqlitedb_get_contact_bdata (EBookBackendSqliteDB *ebsdb,
                                            GError **error)
 {
        gchar *stmt, *ret = NULL;
+       gboolean success;
 
        g_return_val_if_fail (E_IS_BOOK_BACKEND_SQLITEDB (ebsdb), NULL);
        g_return_val_if_fail (folderid != NULL, NULL);
        g_return_val_if_fail (uid != NULL, NULL);
 
-       READER_LOCK (ebsdb);
+       LOCK_MUTEX (&ebsdb->priv->lock);
 
-       stmt = sqlite3_mprintf ("SELECT bdata FROM %Q WHERE uid = %Q", folderid, uid);
-       book_backend_sql_exec (ebsdb->priv->db, stmt, get_string_cb , &ret, error);
+       stmt = sqlite3_mprintf (
+               "SELECT bdata FROM %Q WHERE uid = %Q", folderid, uid);
+       success = book_backend_sql_exec (
+               ebsdb->priv->db, stmt, get_string_cb , &ret, error);
        sqlite3_free (stmt);
 
-       READER_UNLOCK (ebsdb);
+       UNLOCK_MUTEX (&ebsdb->priv->lock);
+
+       if (!success) {
+               g_warn_if_fail (ret == NULL);
+               return NULL;
+       }
 
        return ret;
 }
@@ -3880,29 +4185,36 @@ e_book_backend_sqlitedb_set_contact_bdata (EBookBackendSqliteDB *ebsdb,
                                            GError **error)
 {
        gchar *stmt = NULL;
-       GError *err = NULL;
+       gboolean success;
 
        g_return_val_if_fail (E_IS_BOOK_BACKEND_SQLITEDB (ebsdb), FALSE);
        g_return_val_if_fail (folderid != NULL, FALSE);
        g_return_val_if_fail (uid != NULL, FALSE);
        g_return_val_if_fail (value != NULL, FALSE);
 
-       book_backend_sqlitedb_start_transaction (ebsdb, &err);
+       LOCK_MUTEX (&ebsdb->priv->lock);
 
-       if (!err) {
-               stmt = sqlite3_mprintf (
-                       "UPDATE %Q SET bdata = %Q WHERE uid = %Q",
-                       folderid, value, uid);
-               book_backend_sql_exec (ebsdb->priv->db, stmt, NULL, NULL, &err);
-               sqlite3_free (stmt);
+       if (!book_backend_sqlitedb_start_transaction (ebsdb, error)) {
+               UNLOCK_MUTEX (&ebsdb->priv->lock);
+               return FALSE;
        }
 
-       book_backend_sqlitedb_end_transaction (ebsdb, !err, err ? NULL : &err);
+       stmt = sqlite3_mprintf (
+               "UPDATE %Q SET bdata = %Q WHERE uid = %Q",
+               folderid, value, uid);
+       success = book_backend_sql_exec (
+               ebsdb->priv->db, stmt, NULL, NULL, error);
+       sqlite3_free (stmt);
+
+       if (success)
+               success = book_backend_sqlitedb_commit_transaction (ebsdb, error);
+       else
+               /* The GError is already set. */
+               book_backend_sqlitedb_rollback_transaction (ebsdb, NULL);
 
-       if (err)
-               g_propagate_error (error, err);
+       UNLOCK_MUTEX (&ebsdb->priv->lock);
 
-       return !err;
+       return success;
 }
 
 /**
@@ -3922,13 +4234,16 @@ e_book_backend_sqlitedb_get_sync_data (EBookBackendSqliteDB *ebsdb,
        g_return_val_if_fail (E_IS_BOOK_BACKEND_SQLITEDB (ebsdb), NULL);
        g_return_val_if_fail (folderid != NULL, NULL);
 
-       READER_LOCK (ebsdb);
+       LOCK_MUTEX (&ebsdb->priv->lock);
 
-       stmt = sqlite3_mprintf ("SELECT sync_data FROM folders WHERE folder_id = %Q", folderid);
-       book_backend_sql_exec (ebsdb->priv->db, stmt, get_string_cb , &ret, error);
+       stmt = sqlite3_mprintf (
+               "SELECT sync_data FROM folders WHERE folder_id = %Q",
+               folderid);
+       book_backend_sql_exec (
+               ebsdb->priv->db, stmt, get_string_cb , &ret, error);
        sqlite3_free (stmt);
 
-       READER_UNLOCK (ebsdb);
+       UNLOCK_MUTEX (&ebsdb->priv->lock);
 
        return ret;
 }
@@ -3947,28 +4262,35 @@ e_book_backend_sqlitedb_set_sync_data (EBookBackendSqliteDB *ebsdb,
                                        GError **error)
 {
        gchar *stmt = NULL;
-       GError *err = NULL;
+       gboolean success;
 
        g_return_val_if_fail (E_IS_BOOK_BACKEND_SQLITEDB (ebsdb), FALSE);
        g_return_val_if_fail (folderid != NULL, FALSE);
        g_return_val_if_fail (sync_data != NULL, FALSE);
 
-       book_backend_sqlitedb_start_transaction (ebsdb, &err);
+       LOCK_MUTEX (&ebsdb->priv->lock);
 
-       if (!err) {
-               stmt = sqlite3_mprintf (
-                       "UPDATE folders SET sync_data = %Q WHERE folder_id = %Q",
-                       sync_data, folderid);
-               book_backend_sql_exec (ebsdb->priv->db, stmt, NULL, NULL, &err);
-               sqlite3_free (stmt);
+       if (!book_backend_sqlitedb_start_transaction (ebsdb, error)) {
+               UNLOCK_MUTEX (&ebsdb->priv->lock);
+               return FALSE;
        }
 
-       book_backend_sqlitedb_end_transaction (ebsdb, !err, err ? NULL : &err);
+       stmt = sqlite3_mprintf (
+               "UPDATE folders SET sync_data = %Q "
+               "WHERE folder_id = %Q", sync_data, folderid);
+       success = book_backend_sql_exec (
+               ebsdb->priv->db, stmt, NULL, NULL, error);
+       sqlite3_free (stmt);
+
+       if (success)
+               success = book_backend_sqlitedb_commit_transaction (ebsdb, error);
+       else
+               /* The GError is already set. */
+               book_backend_sqlitedb_rollback_transaction (ebsdb, NULL);
 
-       if (err)
-               g_propagate_error (error, err);
+       UNLOCK_MUTEX (&ebsdb->priv->lock);
 
-       return !err;
+       return success;
 }
 
 /**
@@ -3990,15 +4312,16 @@ e_book_backend_sqlitedb_get_key_value (EBookBackendSqliteDB *ebsdb,
        g_return_val_if_fail (folderid != NULL, NULL);
        g_return_val_if_fail (key != NULL, NULL);
 
-       READER_LOCK (ebsdb);
+       LOCK_MUTEX (&ebsdb->priv->lock);
 
        stmt = sqlite3_mprintf (
                "SELECT value FROM keys WHERE folder_id = %Q AND key = %Q",
                folderid, key);
-       book_backend_sql_exec (ebsdb->priv->db, stmt, get_string_cb , &ret, error);
+       book_backend_sql_exec (
+               ebsdb->priv->db, stmt, get_string_cb , &ret, error);
        sqlite3_free (stmt);
 
-       READER_UNLOCK (ebsdb);
+       UNLOCK_MUTEX (&ebsdb->priv->lock);
 
        return ret;
 }
@@ -4018,29 +4341,36 @@ e_book_backend_sqlitedb_set_key_value (EBookBackendSqliteDB *ebsdb,
                                        GError **error)
 {
        gchar *stmt = NULL;
-       GError *err = NULL;
+       gboolean success;
 
        g_return_val_if_fail (E_IS_BOOK_BACKEND_SQLITEDB (ebsdb), FALSE);
        g_return_val_if_fail (folderid != NULL, FALSE);
        g_return_val_if_fail (key != NULL, FALSE);
        g_return_val_if_fail (value != NULL, FALSE);
 
-       book_backend_sqlitedb_start_transaction (ebsdb, &err);
+       LOCK_MUTEX (&ebsdb->priv->lock);
 
-       if (!err) {
-               stmt = sqlite3_mprintf (
-                       "INSERT or REPLACE INTO keys (key, value, folder_id) "
-                       "values (%Q, %Q, %Q)", key, value, folderid);
-               book_backend_sql_exec (ebsdb->priv->db, stmt, NULL, NULL, &err);
-               sqlite3_free (stmt);
+       if (!book_backend_sqlitedb_start_transaction (ebsdb, error)) {
+               UNLOCK_MUTEX (&ebsdb->priv->lock);
+               return FALSE;
        }
 
-       book_backend_sqlitedb_end_transaction (ebsdb, !err, err ? NULL : &err);
+       stmt = sqlite3_mprintf (
+               "INSERT or REPLACE INTO keys (key, value, folder_id) "
+               "values (%Q, %Q, %Q)", key, value, folderid);
+       success = book_backend_sql_exec (
+               ebsdb->priv->db, stmt, NULL, NULL, error);
+       sqlite3_free (stmt);
+
+       if (success)
+               success = book_backend_sqlitedb_commit_transaction (ebsdb, error);
+       else
+               /* The GError is already set. */
+               book_backend_sqlitedb_rollback_transaction (ebsdb, NULL);
 
-       if (err)
-               g_propagate_error (error, err);
+       UNLOCK_MUTEX (&ebsdb->priv->lock);
 
-       return !err;
+       return success;
 }
 
 /**
@@ -4061,15 +4391,16 @@ e_book_backend_sqlitedb_get_partially_cached_ids (EBookBackendSqliteDB *ebsdb,
        g_return_val_if_fail (E_IS_BOOK_BACKEND_SQLITEDB (ebsdb), NULL);
        g_return_val_if_fail (folderid != NULL, NULL);
 
-       READER_LOCK (ebsdb);
+       LOCK_MUTEX (&ebsdb->priv->lock);
 
        stmt = sqlite3_mprintf (
                "SELECT uid FROM %Q WHERE partial_content = 1",
                folderid);
-       book_backend_sql_exec (ebsdb->priv->db, stmt, addto_slist_cb, &uids, error);
+       book_backend_sql_exec (
+               ebsdb->priv->db, stmt, addto_slist_cb, &uids, error);
        sqlite3_free (stmt);
 
-       READER_UNLOCK (ebsdb);
+       UNLOCK_MUTEX (&ebsdb->priv->lock);
 
        return uids;
 }
@@ -4087,40 +4418,59 @@ e_book_backend_sqlitedb_delete_addressbook (EBookBackendSqliteDB *ebsdb,
                                             GError **error)
 {
        gchar *stmt;
-       GError *err = NULL;
+       gboolean success;
 
        g_return_val_if_fail (E_IS_BOOK_BACKEND_SQLITEDB (ebsdb), FALSE);
        g_return_val_if_fail (folderid != NULL, FALSE);
 
-       book_backend_sqlitedb_start_transaction (ebsdb, &err);
+       LOCK_MUTEX (&ebsdb->priv->lock);
 
-       /* delete the contacts table */
-       if (!err) {
-               stmt = sqlite3_mprintf ("DROP TABLE %Q ", folderid);
-               book_backend_sql_exec (ebsdb->priv->db, stmt, NULL, NULL, &err);
-               sqlite3_free (stmt);
+       if (!book_backend_sqlitedb_start_transaction (ebsdb, error)) {
+               UNLOCK_MUTEX (&ebsdb->priv->lock);
+               return FALSE;
        }
 
+       /* delete the contacts table */
+       stmt = sqlite3_mprintf ("DROP TABLE %Q ", folderid);
+       success = book_backend_sql_exec (
+               ebsdb->priv->db, stmt, NULL, NULL, error);
+       sqlite3_free (stmt);
+
+       if (!success)
+               goto rollback;
+
        /* delete the key/value pairs corresponding to this table */
-       if (!err) {
-               stmt = sqlite3_mprintf ("DELETE FROM keys WHERE folder_id = %Q", folderid);
-               book_backend_sql_exec (ebsdb->priv->db, stmt, NULL, NULL, &err);
-               sqlite3_free (stmt);
-       }
+       stmt = sqlite3_mprintf (
+               "DELETE FROM keys WHERE folder_id = %Q", folderid);
+       success = book_backend_sql_exec (
+               ebsdb->priv->db, stmt, NULL, NULL, error);
+       sqlite3_free (stmt);
+
+       if (!success)
+               goto rollback;
 
        /* delete the folder from the folders table */
-       if (!err) {
-               stmt = sqlite3_mprintf ("DELETE FROM folders WHERE folder_id = %Q", folderid);
-               book_backend_sql_exec (ebsdb->priv->db, stmt, NULL, NULL, &err);
-               sqlite3_free (stmt);
-       }
+       stmt = sqlite3_mprintf (
+               "DELETE FROM folders WHERE folder_id = %Q", folderid);
+       success = book_backend_sql_exec (
+               ebsdb->priv->db, stmt, NULL, NULL, error);
+       sqlite3_free (stmt);
+
+       if (!success)
+               goto rollback;
+
+       success = book_backend_sqlitedb_commit_transaction (ebsdb, error);
+       UNLOCK_MUTEX (&ebsdb->priv->lock);
 
-       book_backend_sqlitedb_end_transaction (ebsdb, !err, err ? NULL : &err);
+       return success;
+
+rollback:
+       /* The GError is already set. */
+       book_backend_sqlitedb_rollback_transaction (ebsdb, NULL);
 
-       if (err)
-               g_propagate_error (error, err);
+       UNLOCK_MUTEX (&ebsdb->priv->lock);
 
-       return !err;
+       return FALSE;
 }
 
 /**
@@ -4152,27 +4502,25 @@ gboolean
 e_book_backend_sqlitedb_remove (EBookBackendSqliteDB *ebsdb,
                                 GError **error)
 {
-       EBookBackendSqliteDBPrivate *priv;
        gchar *filename;
        gint ret;
 
        g_return_val_if_fail (E_IS_BOOK_BACKEND_SQLITEDB (ebsdb), FALSE);
 
-       priv = ebsdb->priv;
+       LOCK_MUTEX (&ebsdb->priv->lock);
 
-       WRITER_LOCK (ebsdb);
+       sqlite3_close (ebsdb->priv->db);
 
-       sqlite3_close (priv->db);
-       filename = g_build_filename (priv->path, DB_FILENAME, NULL);
+       filename = g_build_filename (ebsdb->priv->path, DB_FILENAME, NULL);
        ret = g_unlink (filename);
+       g_free (filename);
 
-       WRITER_UNLOCK (ebsdb);
+       UNLOCK_MUTEX (&ebsdb->priv->lock);
 
-       g_free (filename);
        if (ret == -1) {
                g_set_error (
-                       error, E_BOOK_SDB_ERROR,
-                       E_BOOK_SDB_ERROR_OTHER, "Unable to remove the db file: errno %d", errno);
+                       error, E_BOOK_SDB_ERROR, E_BOOK_SDB_ERROR_OTHER,
+                       _("Unable to remove the db file: errno %d"), errno);
                return FALSE;
        }
 
@@ -4186,44 +4534,27 @@ destroy_search_data (gpointer data)
 }
 
 static gboolean
-validate_county_code (EBookBackendSqliteDB  *ebsdb,
-                      const gchar           *folderid,
-                      GError               **error)
+upgrade_contacts_table (EBookBackendSqliteDB  *ebsdb,
+                        const gchar           *folderid,
+                        GError               **error)
 {
        gchar *stmt;
        gboolean success = FALSE;
        GSList *vcard_data = NULL;
        GSList *l;
+       gchar *default_region = NULL;
 
-#if HAVE__NL_ADDRESS_COUNTRY_AB2
-       const gchar *country_code = nl_langinfo (_NL_ADDRESS_COUNTRY_AB2);
-#else /* HAVE__NL_ADDRESS_COUNTRY_AB2 */
-#error Cannot resolve default 2-letter country code. Find a replacement for _NL_ADDRESS_COUNTRY_AB2 or 
implement code to parse the locale name.
-#endif /* HAVE__NL_ADDRESS_COUNTRY_AB2 */
-
-       if (country_code == NULL || strlen (country_code) != 2) {
-               g_warning ("Cannot derive 2-letter country code from current locale.");
-               country_code = "ZZ";
-       }
-
-       /* Nothing has changed. We can stop here. */
-       if (g_strcmp0 (country_code, ebsdb->priv->country_code) == 0)
-               return TRUE;
-
-       g_free (ebsdb->priv->country_code);
-       ebsdb->priv->country_code = g_strdup (country_code);
-
-       /* Filter out NULL vcards to avoid warnings when upgrading from old Berkeley DB format */
-       stmt = sqlite3_mprintf ("SELECT uid, vcard, NULL FROM %Q "
-                               "WHERE NOT vcard IS NULL", folderid);
+       stmt = sqlite3_mprintf ("SELECT uid, vcard, NULL FROM %Q", folderid);
        success = book_backend_sql_exec (
                ebsdb->priv->db, stmt, addto_vcard_list_cb, &vcard_data, error);
        sqlite3_free (stmt);
 
-       if (vcard_data) {
-               g_print ("The country code has changed to \"%s\". "
-                        "Must rebuild %s parameters and indexes for stored vCards.\n",
-                        ebsdb->priv->country_code, EVC_X_E164);
+       if (vcard_data == NULL)
+               return TRUE;
+
+       if (e_phone_number_is_supported ()) {
+               g_message ("The phone number indexes' format has changed. Rebuilding them.");
+               default_region = e_phone_number_get_default_region ();
        }
 
        for (l = vcard_data; success && l; l = l->next) {
@@ -4233,23 +4564,13 @@ validate_county_code (EBookBackendSqliteDB  *ebsdb,
                if (contact == NULL)
                        continue;
 
-               if (update_e164_params (E_VCARD (contact), ebsdb->priv->country_code))
-                       success = insert_contact (ebsdb, contact, folderid, TRUE, error);
+               success = insert_contact (ebsdb, contact, folderid, TRUE, default_region, error);
 
                g_object_unref (contact);
        }
 
        g_slist_free_full (vcard_data, destroy_search_data);
-
-       if (success) {
-               stmt = sqlite3_mprintf (
-                       "UPDATE folders SET countrycode = %Q WHERE folder_id = %Q",
-                       country_code, folderid);
-               success = book_backend_sql_exec (
-                       ebsdb->priv->db, stmt, get_string_cb, &ebsdb->priv->country_code, error);
-               sqlite3_free (stmt);
-       }
+       g_free (default_region);
 
        return success;
 }
-
diff --git a/libedataserver/Makefile.am b/libedataserver/Makefile.am
index 58fe8b4..c0a2582 100644
--- a/libedataserver/Makefile.am
+++ b/libedataserver/Makefile.am
@@ -57,7 +57,6 @@ libedataserver_1_2_la_SOURCES =               \
        e-list-iterator.c               \
        e-memory.c                      \
        e-operation-pool.c              \
-       e-phone-utils.cpp               \
        e-proxy.c                       \
        e-sexp.c                        \
        e-source.c                      \
@@ -114,11 +113,6 @@ libedataserver_1_2_la_LDFLAGS = \
        $(CODE_COVERAGE_LDFLAGS) \
        $(NULL)
 
-if ENABLE_PHONENUMBER
-libedataserver_1_2_la_CPPFLAGS += $(PHONENUMBER_INCLUDES)
-libedataserver_1_2_la_LIBADD += $(PHONENUMBER_LIBS)
-endif ENABLE_PHONENUMBER
-
 libedataserverincludedir = $(privincludedir)/libedataserver
 
 libedataserverinclude_HEADERS =                \
@@ -134,7 +128,6 @@ libedataserverinclude_HEADERS =             \
        e-list-iterator.h               \
        e-memory.h                      \
        e-operation-pool.h              \
-       e-phone-utils.h                 \
        e-proxy.h                       \
        e-sexp.h                        \
        e-source.h                      \
diff --git a/libedataserver/libedataserver.h b/libedataserver/libedataserver.h
index b2ebe2a..84797fb 100644
--- a/libedataserver/libedataserver.h
+++ b/libedataserver/libedataserver.h
@@ -34,7 +34,6 @@
 #include <libedataserver/e-list.h>
 #include <libedataserver/e-memory.h>
 #include <libedataserver/e-operation-pool.h>
-#include <libedataserver/e-phone-utils.h>
 #include <libedataserver/e-proxy.h>
 #include <libedataserver/e-sexp.h>
 #include <libedataserver/e-source-address-book.h>
diff --git a/m4/evo_phonenumber.m4 b/m4/evo_phonenumber.m4
index 395a3bc..8aa2db0 100644
--- a/m4/evo_phonenumber.m4
+++ b/m4/evo_phonenumber.m4
@@ -1,15 +1,21 @@
-dnl EVO_PHONENUMBER_SUPPORT([default])
-dnl Check for Google's libphonenumber. Adds a --with-phonenumber option
-dnl to explicitly enable and disable phonenumber support, but also for
-dnl pointing to libphonenumber's install prefix.
-AC_DEFUN([EVO_PHONENUMBER_SUPPORT],[
-       AC_MSG_CHECKING([whether to enable phonenumber support])
+dnl EVO_PHONENUMBER_ARGS([default])
+dnl
+dnl Checks configure script options for requesting libphonenumber support.
+dnl Adds a --with-phonenumber option to explicitly enable and disable
+dnl phonenumber support, but also for pointing to libphonenumber's install
+dnl prefix.
+dnl
+dnl Must be called before any other macro that might use the C++ compiler.
+AC_DEFUN([EVO_PHONENUMBER_ARGS],[
+       AC_BEFORE([$0], [AC_COMPILE_IFELSE])
+       AC_BEFORE([$0], [AC_LINK_IFELSE])
+       AC_BEFORE([$0], [AC_PROG_CXX])
+       AC_BEFORE([$0], [AC_RUN_IFELSE])
+       AC_BEFORE([$0], [LT_INIT])
 
        evo_phonenumber_prefix=
-       msg_phonenumber=no
 
-       PHONENUMBER_INCLUDES=
-       PHONENUMBER_LIBS=
+       AC_MSG_CHECKING([whether to enable phonenumber support])
 
        AC_ARG_WITH([phonenumber],
                [AS_HELP_STRING([--with-phonenumber@<:@=PREFIX@:>@],
@@ -19,6 +25,25 @@ AC_DEFUN([EVO_PHONENUMBER_SUPPORT],[
 
        AC_MSG_RESULT([$with_phonenumber])
 
+       AS_VAR_IF([with_phonenumber],[no],,[evo_with_cxx=yes])
+])
+
+dnl EVO_PHONENUMBER_SUPPORT
+dnl
+dnl Check for Google's libphonenumber. Adds a --with-phonenumber option
+dnl to explicitly enable and disable phonenumber support, but also for
+dnl pointing to libphonenumber's install prefix.
+dnl
+dnl You most probably want to place a call to EVO_PHONENUMBER_ARGS near
+dnl to the top of your configure script.
+AC_DEFUN([EVO_PHONENUMBER_SUPPORT],[
+       AC_REQUIRE([EVO_PHONENUMBER_ARGS])
+
+       msg_phonenumber=no
+
+       PHONENUMBER_INCLUDES=
+       PHONENUMBER_LIBS=
+
        AS_VAR_IF([with_phonenumber], [no],, [
                AC_LANG_PUSH(C++)
 
@@ -45,15 +70,46 @@ AC_DEFUN([EVO_PHONENUMBER_SUPPORT],[
                                AC_MSG_ERROR([libphonenumber cannot be used. Use --with-phonenumber to 
specify the library prefix.])])
                        ])
 
-               CXXFLAGS="$evo_cxxflags_saved"
-               LDFLAGS="$evo_ldflags_saved"
-               LIBS="$evo_libs_saved"
 
                AS_VAR_IF([evo_phonenumber_prefix],,
                          [msg_phonenumber=$with_phonenumber],
                          [msg_phonenumber=$evo_phonenumber_prefix])
 
                AC_MSG_RESULT([$with_phonenumber])
+
+               AS_VAR_IF(
+                       [with_phonenumber],[yes],
+                       [AC_MSG_CHECKING([whether ParseAndKeepRawInput() is needed])
+                        AC_RUN_IFELSE(
+                               [AC_LANG_PROGRAM(
+                                       [[#include <phonenumbers/phonenumberutil.h>]],
+                                       [[namespace pn = i18n::phonenumbers;i18n::phonenumbers;
+
+                                         pn::PhoneNumber n;
+
+                                         if (pn::PhoneNumberUtil::GetInstance ()->
+                                               Parse("049(800)46663", "DE", &) == 
pn::PhoneNumberUtil::NO_PARSING_ERROR
+                                                       && n.has_country_code_source ()
+                                                       && n.country_code_source () == 49)
+                                               return EXIT_SUCCESS;
+
+                                         return EXIT_FAILURE;]]
+                                       )],
+
+                               [AC_MSG_RESULT([no])],
+                               [AC_MSG_RESULT([yes])
+
+                                AC_DEFINE_UNQUOTED(
+                                       [PHONENUMBER_RAW_INPUT_NEEDED], 1,
+                                       [Whether Parse() or ParseAndKeepRawInput() must be used to get the 
country-code source])
+                               ])
+                       ])
+
+
+               CXXFLAGS="$evo_cxxflags_saved"
+               LDFLAGS="$evo_ldflags_saved"
+               LIBS="$evo_libs_saved"
+
                AC_LANG_POP(C++)
        ])
 
diff --git a/tests/libebook/Makefile.am b/tests/libebook/Makefile.am
index 2749324..3e5b640 100644
--- a/tests/libebook/Makefile.am
+++ b/tests/libebook/Makefile.am
@@ -92,6 +92,7 @@ endif
 
 noinst_PROGRAMS = \
        $(DEPRECATED_TESTS)                     \
+       test-ebook-phone-number                 \
        test-categories                         \
        test-date                               \
        test-photo                              \
@@ -109,6 +110,8 @@ EXTRA_DIST = \
        $(srcdir)/data/vcards/simple-2.vcf      \
        $(NULL)
 
+test_ebook_phone_number_LDADD=$(TEST_LIBS)
+test_ebook_phone_number_CPPFLAGS=$(TEST_CPPFLAGS)
 test_categories_LDADD=$(TEST_LIBS)
 test_categories_CPPFLAGS=$(TEST_CPPFLAGS)
 test_date_LDADD=$(TEST_LIBS)
diff --git a/tests/libebook/client/Makefile.am b/tests/libebook/client/Makefile.am
index 072e7dd..33ad444 100644
--- a/tests/libebook/client/Makefile.am
+++ b/tests/libebook/client/Makefile.am
@@ -58,7 +58,6 @@ TESTS =                                                               \
        test-client-remove-contact-by-uid                       \
        test-client-remove-contacts                             \
        test-client-photo-is-uri                                \
-       test-client-upgrade-addressbook                         \
        test-client-async                                       \
        $(NULL)
 
@@ -68,6 +67,7 @@ TESTS =                                                               \
 # not been ported to use ETestServerFixture yet.
 noinst_PROGRAMS =                                              \
        $(TESTS)                                                \
+       test-client-upgrade-addressbook                         \
        test-client-change-country-code                         \
        test-client-examine                                     \
        test-client                                             \
diff --git a/tests/libebook/client/test-client-custom-summary.c 
b/tests/libebook/client/test-client-custom-summary.c
index d9f6f10..afa8806 100644
--- a/tests/libebook/client/test-client-custom-summary.c
+++ b/tests/libebook/client/test-client-custom-summary.c
@@ -21,6 +21,7 @@
  */
 
 #include <stdlib.h>
+#include <locale.h>
 #include <libebook/libebook.h>
 
 #include "client-test-utils.h"
@@ -251,6 +252,7 @@ main (gint argc,
 #endif
        g_test_init (&argc, &argv, NULL);
 
+       setlocale (LC_ALL, "en_US.UTF-8");
 
        /* Test all queries in 8 different combinations specified by the 'suites'
         */
diff --git a/tests/libebook/client/test-client-e164-param.c b/tests/libebook/client/test-client-e164-param.c
index d415d1b..9b0f936 100644
--- a/tests/libebook/client/test-client-e164-param.c
+++ b/tests/libebook/client/test-client-e164-param.c
@@ -21,6 +21,7 @@
 
 #include <config.h>
 #include <stdlib.h>
+#include <locale.h>
 #include <libebook/libebook.h>
 
 #include "client-test-utils.h"
@@ -140,6 +141,8 @@ main (gint argc,
 #endif
        g_test_init (&argc, &argv, NULL);
 
+       setlocale (LC_ALL, "en_US.UTF-8");
+
 #ifdef ENABLE_PHONENUMBER
 
        g_test_add (
diff --git a/tests/libebook/client/test-client-get-contact-uids.c 
b/tests/libebook/client/test-client-get-contact-uids.c
index 9527333..908fa28 100644
--- a/tests/libebook/client/test-client-get-contact-uids.c
+++ b/tests/libebook/client/test-client-get-contact-uids.c
@@ -1,6 +1,7 @@
 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
 
 #include <stdlib.h>
+#include <locale.h>
 #include <libebook/libebook.h>
 
 #include "client-test-utils.h"
@@ -100,6 +101,8 @@ main (gint argc,
 #endif
        g_test_init (&argc, &argv, NULL);
 
+       setlocale (LC_ALL, "en_US.UTF-8");
+
        g_test_add (
                "/EBookClient/GetContactUids/Sync", ETestServerFixture, &book_closure,
                e_test_server_utils_setup, test_get_contact_uids_sync, e_test_server_utils_teardown);
diff --git a/tests/libebook/client/test-client-get-contact.c b/tests/libebook/client/test-client-get-contact.c
index 524db39..0fec2df 100644
--- a/tests/libebook/client/test-client-get-contact.c
+++ b/tests/libebook/client/test-client-get-contact.c
@@ -1,6 +1,7 @@
 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
 
 #include <stdlib.h>
+#include <locale.h>
 #include <libebook/libebook.h>
 
 #include "client-test-utils.h"
@@ -74,6 +75,8 @@ main (gint argc,
 #endif
        g_test_init (&argc, &argv, NULL);
 
+       setlocale (LC_ALL, "en_US.UTF-8");
+
        g_test_add (
                "/EBookClient/GetContact/Sync", ETestServerFixture, &book_closure,
                e_test_server_utils_setup, test_get_contact_sync, e_test_server_utils_teardown);
diff --git a/tests/libebook/client/test-client-get-view.c b/tests/libebook/client/test-client-get-view.c
index 1e0b8fb..1ddc68f 100644
--- a/tests/libebook/client/test-client-get-view.c
+++ b/tests/libebook/client/test-client-get-view.c
@@ -1,6 +1,7 @@
 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
 
 #include <stdlib.h>
+#include <locale.h>
 #include <libebook/libebook.h>
 
 #include "client-test-utils.h"
@@ -148,6 +149,8 @@ main (gint argc,
 #endif
        g_test_init (&argc, &argv, NULL);
 
+       setlocale (LC_ALL, "en_US.UTF-8");
+
        g_test_add (
                "/EBookClient/GetBookClientView/Sync", ETestServerFixture, &book_closure,
                e_test_server_utils_setup, test_get_view_sync, e_test_server_utils_teardown);
diff --git a/tests/libebook/client/test-client-view-operations.c 
b/tests/libebook/client/test-client-view-operations.c
index 7cba28c..b713c83 100644
--- a/tests/libebook/client/test-client-view-operations.c
+++ b/tests/libebook/client/test-client-view-operations.c
@@ -8,10 +8,9 @@
 #include "client-test-utils.h"
 #include "e-test-server-utils.h"
 
-static ETestServerClosure book_closure = { E_TEST_SERVER_ADDRESS_BOOK, NULL, 0 };
 static ETestServerClosure direct_book_closure = { E_TEST_SERVER_DIRECT_ADDRESS_BOOK, NULL, 0 };
 
-#define N_THREADS  20
+#define N_THREADS  5
 #define N_CONTACTS 5
 
 typedef struct {
@@ -80,14 +79,18 @@ complete (EBookClientView *view,
        g_mutex_unlock (&data->complete_mutex);
 }
 
-static void
-view_ready (GObject *source_object,
-           GAsyncResult *result,
-           ThreadData *data)
+static gboolean
+start_view (ThreadData *data)
 {
+       EBookQuery   *query;
+       gchar        *sexp;
        GError *error = NULL;
 
-       if (!e_book_client_get_view_finish (E_BOOK_CLIENT (source_object), result, &(data->view), &error))
+       query = e_book_query_any_field_contains ("");
+       sexp = e_book_query_to_string (query);
+
+       if (!e_book_client_get_view_sync (data->client, sexp,
+                                         &(data->view), NULL, &error))
                g_error ("Error getting view: %s", error->message);
 
        g_signal_connect (data->view, "objects-added", G_CALLBACK (objects_added), data);
@@ -102,18 +105,6 @@ view_ready (GObject *source_object,
        e_book_client_view_start (data->view, &error);
        if (error)
                g_error ("start view: %s", error->message);
-}
-
-static gboolean
-start_view (ThreadData *data)
-{
-       EBookQuery   *query;
-       gchar        *sexp;
-
-       query = e_book_query_any_field_contains ("");
-       sexp = e_book_query_to_string (query);
-
-       e_book_client_get_view (data->client, sexp, NULL, (GAsyncReadyCallback)view_ready, data);
 
        e_book_query_unref (query);
        g_free (sexp);
@@ -146,20 +137,6 @@ finish_thread_test (ThreadData *data)
        g_slice_free (ThreadData, data);
 }
 
-static void
-client_ready (GObject *source_object,
-             GAsyncResult *res,
-             ThreadData *data)
-{
-       GError *error = NULL;
-
-       if (!e_client_open_finish (E_CLIENT (source_object), res, &error))
-               g_error ("Error opening client: %s",
-                        error->message);
-
-       start_thread_test (data);
-}
-
 static gpointer
 test_view_thread (ThreadData *data)
 {
@@ -181,15 +158,12 @@ test_view_thread (ThreadData *data)
        if (!source)
                g_error ("Unable to fetch source uid '%s' from the registry", data->book_uid);
 
-       if (data->closure->type == E_TEST_SERVER_DIRECT_ADDRESS_BOOK)
-               data->client = (EBookClient *)e_book_client_connect_direct_sync (registry, source, NULL, 
&error);
-       else
-               data->client = e_book_client_new (source, &error);
+       data->client = (EBookClient *)e_book_client_connect_direct_sync (registry, source, NULL, &error);
 
        if (!data->client)
                g_error ("Unable to create EBookClient for uid '%s': %s", data->book_uid, error->message);
 
-       e_client_open (E_CLIENT (data->client), TRUE, NULL, (GAsyncReadyCallback)client_ready, data);
+       start_thread_test (data);
 
        g_main_loop_run (data->loop);
 
@@ -278,8 +252,6 @@ main (gint argc,
        g_test_init (&argc, &argv, NULL);
        setlocale (LC_ALL, "en_US.UTF-8");
 
-       g_test_add ("/EBookClient/ConcurrentViews", ETestServerFixture, &book_closure,
-                   e_test_server_utils_setup, test_concurrent_views, e_test_server_utils_teardown);
        g_test_add ("/EBookClient/DirectAccess/ConcurrentViews", ETestServerFixture, &direct_book_closure,
                    e_test_server_utils_setup, test_concurrent_views, e_test_server_utils_teardown);
 
diff --git a/tests/libebook/test-ebook-phone-number.c b/tests/libebook/test-ebook-phone-number.c
new file mode 100644
index 0000000..2b58b19
--- /dev/null
+++ b/tests/libebook/test-ebook-phone-number.c
@@ -0,0 +1,437 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+/*
+ * Copyright (C) 2012,2013 Intel Corporation
+ *
+ * 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.
+ *
+ * Author: Mathias Hasselmann <mathias openismus com>
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <libebook/libebook.h>
+#include <locale.h>
+
+static const char *match_candidates[] = {
+       "not-a-number",
+       "+1-617-4663489", "617-4663489", "4663489",
+       "+1.408.845.5246", "4088455246", "8455246",
+       "+1-857-4663489"
+};
+
+static const EPhoneNumberMatch expected_matches[] = {
+       /* not a number */
+       E_PHONE_NUMBER_MATCH_NONE,
+       E_PHONE_NUMBER_MATCH_NONE,
+       E_PHONE_NUMBER_MATCH_NONE,
+       E_PHONE_NUMBER_MATCH_NONE,
+       E_PHONE_NUMBER_MATCH_NONE,
+       E_PHONE_NUMBER_MATCH_NONE,
+       E_PHONE_NUMBER_MATCH_NONE,
+       E_PHONE_NUMBER_MATCH_NONE,
+
+       /* +1-617-4663489 */
+       E_PHONE_NUMBER_MATCH_NONE,
+       E_PHONE_NUMBER_MATCH_EXACT,
+       E_PHONE_NUMBER_MATCH_NATIONAL,
+       E_PHONE_NUMBER_MATCH_SHORT,
+       E_PHONE_NUMBER_MATCH_NONE,
+       E_PHONE_NUMBER_MATCH_NONE,
+       E_PHONE_NUMBER_MATCH_NONE,
+       E_PHONE_NUMBER_MATCH_NONE,
+
+       /* 617-4663489 */
+       E_PHONE_NUMBER_MATCH_NONE,
+       E_PHONE_NUMBER_MATCH_NATIONAL,
+       E_PHONE_NUMBER_MATCH_NATIONAL,
+       E_PHONE_NUMBER_MATCH_SHORT,
+       E_PHONE_NUMBER_MATCH_NONE,
+       E_PHONE_NUMBER_MATCH_NONE,
+       E_PHONE_NUMBER_MATCH_NONE,
+       E_PHONE_NUMBER_MATCH_NONE,
+
+       /* 4663489 */
+       E_PHONE_NUMBER_MATCH_NONE,
+       E_PHONE_NUMBER_MATCH_SHORT,
+       E_PHONE_NUMBER_MATCH_SHORT,
+       E_PHONE_NUMBER_MATCH_NATIONAL, /* XXX - Google, really? I'd expect a full match here. */
+       E_PHONE_NUMBER_MATCH_NONE,
+       E_PHONE_NUMBER_MATCH_NONE,
+       E_PHONE_NUMBER_MATCH_NONE,
+       E_PHONE_NUMBER_MATCH_SHORT,
+
+       /* +1.408.845.5246 */
+       E_PHONE_NUMBER_MATCH_NONE,
+       E_PHONE_NUMBER_MATCH_NONE,
+       E_PHONE_NUMBER_MATCH_NONE,
+       E_PHONE_NUMBER_MATCH_NONE,
+       E_PHONE_NUMBER_MATCH_EXACT,
+       E_PHONE_NUMBER_MATCH_NATIONAL,
+       E_PHONE_NUMBER_MATCH_SHORT,
+       E_PHONE_NUMBER_MATCH_NONE,
+
+       /* 4088455246 */
+       E_PHONE_NUMBER_MATCH_NONE,
+       E_PHONE_NUMBER_MATCH_NONE,
+       E_PHONE_NUMBER_MATCH_NONE,
+       E_PHONE_NUMBER_MATCH_NONE,
+       E_PHONE_NUMBER_MATCH_NATIONAL,
+       E_PHONE_NUMBER_MATCH_NATIONAL,
+       E_PHONE_NUMBER_MATCH_SHORT,
+       E_PHONE_NUMBER_MATCH_NONE,
+
+       /* 8455246 */
+       E_PHONE_NUMBER_MATCH_NONE,
+       E_PHONE_NUMBER_MATCH_NONE,
+       E_PHONE_NUMBER_MATCH_NONE,
+       E_PHONE_NUMBER_MATCH_NONE,
+       E_PHONE_NUMBER_MATCH_SHORT,
+       E_PHONE_NUMBER_MATCH_SHORT,
+       E_PHONE_NUMBER_MATCH_NATIONAL, /* XXX - Google, really?  I'd expect a full match here. */
+       E_PHONE_NUMBER_MATCH_NONE,
+
+       /* +1-857-4663489 */
+       E_PHONE_NUMBER_MATCH_NONE,
+       E_PHONE_NUMBER_MATCH_NONE,
+       E_PHONE_NUMBER_MATCH_NONE,
+       E_PHONE_NUMBER_MATCH_SHORT,
+       E_PHONE_NUMBER_MATCH_NONE,
+       E_PHONE_NUMBER_MATCH_NONE,
+       E_PHONE_NUMBER_MATCH_NONE,
+       E_PHONE_NUMBER_MATCH_EXACT
+};
+
+typedef struct {
+       gchar                           *phone_number;
+       gchar                           *region_code;
+       EPhoneNumberCountrySource        country_source;
+       gint                             country_code;
+       gchar                           *national_number;
+       gchar                           *formatted_numbers[4];
+} ParseAndFormatData;
+
+static ParseAndFormatData *
+parse_and_format_data_new (const gchar                 *phone_number,
+                           const gchar                 *region_code,
+                           EPhoneNumberCountrySource    country_source,
+                           gint                                 country_code,
+                           const gchar                 *national_number,
+                           const gchar                 *formatted_e164,
+                           const gchar                 *formatted_intl,
+                           const gchar                 *formatted_natl,
+                           const gchar                 *formatted_uri)
+{
+       ParseAndFormatData *test_data = g_slice_new0 (ParseAndFormatData);
+
+       test_data->phone_number = g_strdup (phone_number);
+       test_data->region_code = g_strdup (region_code);
+       test_data->country_source = country_source;
+       test_data->country_code = country_code;
+       test_data->national_number = g_strdup (national_number);
+       test_data->formatted_numbers[0] = g_strdup (formatted_e164);
+       test_data->formatted_numbers[1] = g_strdup (formatted_intl);
+       test_data->formatted_numbers[2] = g_strdup (formatted_natl);
+       test_data->formatted_numbers[3] = g_strdup (formatted_uri);
+
+       return test_data;
+}
+
+static void
+parse_and_format_data_free (gpointer data)
+{
+       ParseAndFormatData *const test_data = data;
+
+       g_free (test_data->phone_number);
+       g_free (test_data->region_code);
+       g_free (test_data->national_number);
+       g_free (test_data->formatted_numbers[0]);
+       g_free (test_data->formatted_numbers[1]);
+       g_free (test_data->formatted_numbers[2]);
+       g_free (test_data->formatted_numbers[3]);
+
+       g_slice_free (ParseAndFormatData, test_data);
+}
+
+static void
+test_parse_and_format (gconstpointer data)
+{
+       const ParseAndFormatData *const test_data = data;
+       GError *error = NULL;
+       EPhoneNumber *parsed;
+
+       parsed = e_phone_number_from_string (
+               test_data->phone_number, test_data->region_code, &error);
+
+#ifdef ENABLE_PHONENUMBER
+
+       {
+               EPhoneNumberCountrySource source;
+               gchar *national;
+               gint i;
+
+               g_assert_cmpint (
+                       e_phone_number_get_country_code (parsed, &source), ==,
+                       test_data->country_code);
+               g_assert_cmpuint (source, ==, test_data->country_source);
+
+               national = e_phone_number_get_national_number (parsed);
+               g_assert_cmpstr (national, ==, test_data->national_number);
+               g_free (national);
+
+               g_assert (parsed != NULL);
+               g_assert (error == NULL);
+
+               for (i = 0; i < G_N_ELEMENTS (test_data->formatted_numbers); ++i) {
+                       gchar *formatted = e_phone_number_to_string (parsed, i);
+                       g_assert (formatted != NULL);
+                       g_assert_cmpstr (formatted, ==, test_data->formatted_numbers[i]);
+                       g_free (formatted);
+               }
+
+               e_phone_number_free (parsed);
+       }
+
+#else /* ENABLE_PHONENUMBER */
+
+       g_assert (parsed == NULL);
+       g_assert (error != NULL);
+       g_assert (error->domain == E_PHONE_NUMBER_ERROR);
+       g_assert (error->code == E_PHONE_NUMBER_ERROR_NOT_IMPLEMENTED);
+       g_assert (error->message != NULL);
+
+#endif /* ENABLE_PHONENUMBER */
+
+       g_clear_error (&error);
+}
+
+static void
+test_parse_bad_number (void)
+{
+       GError *error = NULL;
+       EPhoneNumber *parsed;
+
+       parsed = e_phone_number_from_string ("+1-NOT-A-NUMBER", "US", &error);
+
+       g_assert (parsed == NULL);
+       g_assert (error != NULL);
+       g_assert (error->domain == E_PHONE_NUMBER_ERROR);
+#ifdef ENABLE_PHONENUMBER
+       g_assert (error->code == E_PHONE_NUMBER_ERROR_NOT_A_NUMBER);
+#else /* ENABLE_PHONENUMBER */
+       g_assert (error->code == E_PHONE_NUMBER_ERROR_NOT_IMPLEMENTED);
+#endif /* ENABLE_PHONENUMBER */
+       g_assert (error->message != NULL);
+
+       g_clear_error (&error);
+}
+
+static void
+test_parse_auto_region (void)
+{
+       GError *error = NULL;
+       EPhoneNumber *parsed;
+
+       parsed = e_phone_number_from_string ("212-5423789", NULL, &error);
+
+#ifdef ENABLE_PHONENUMBER
+
+       {
+               EPhoneNumberCountrySource source;
+               gchar *national;
+               gchar *formatted;
+
+               g_assert (parsed != NULL);
+               g_assert (error == NULL);
+
+               g_assert_cmpint (e_phone_number_get_country_code (parsed, &source), ==, 1);
+               g_assert_cmpuint (source, ==, E_PHONE_NUMBER_COUNTRY_FROM_DEFAULT);
+
+               national = e_phone_number_get_national_number (parsed);
+               g_assert_cmpstr (national, ==, "2125423789");
+               g_free (national);
+
+               formatted = e_phone_number_to_string (parsed, E_PHONE_NUMBER_FORMAT_E164);
+               g_assert_cmpstr (formatted, ==, "+12125423789");
+               g_free (formatted);
+
+               e_phone_number_free (parsed);
+       }
+
+#else /* ENABLE_PHONENUMBER */
+
+       g_assert (parsed == NULL);
+       g_assert (error != NULL);
+       g_assert (error->domain == E_PHONE_NUMBER_ERROR);
+       g_assert (error->code == E_PHONE_NUMBER_ERROR_NOT_IMPLEMENTED);
+       g_assert (error->message != NULL);
+       g_clear_error (&error);
+
+#endif /* ENABLE_PHONENUMBER */
+}
+
+static void
+test_compare_numbers (gconstpointer data)
+{
+       const size_t n = GPOINTER_TO_UINT (data);
+       const size_t i = n % G_N_ELEMENTS (match_candidates);
+       const size_t j = n / G_N_ELEMENTS (match_candidates);
+
+#ifdef ENABLE_PHONENUMBER
+       const gboolean error_expected = !(i && j) ;
+#else /* ENABLE_PHONENUMBER */
+       const gboolean error_expected = TRUE;
+#endif /* ENABLE_PHONENUMBER */
+
+       EPhoneNumberMatch actual_match;
+       GError *error = NULL;
+
+       actual_match = e_phone_number_compare_strings (match_candidates[i],
+                                                      match_candidates[j],
+                                                      &error);
+
+#ifdef ENABLE_PHONENUMBER
+       g_assert_cmpuint (actual_match, ==, expected_matches[n]);
+#else /* ENABLE_PHONENUMBER */
+       g_assert_cmpuint (actual_match, ==, E_PHONE_NUMBER_MATCH_NONE);
+#endif /* ENABLE_PHONENUMBER */
+
+       if (!error_expected) {
+               g_assert (error == NULL);
+       } else {
+               g_assert (error != NULL);
+               g_assert (error->domain == E_PHONE_NUMBER_ERROR);
+#ifdef ENABLE_PHONENUMBER
+               g_assert (error->code == E_PHONE_NUMBER_ERROR_NOT_A_NUMBER);
+#else /* ENABLE_PHONENUMBER */
+               g_assert (error->code == E_PHONE_NUMBER_ERROR_NOT_IMPLEMENTED);
+#endif /* ENABLE_PHONENUMBER */
+               g_assert (error->message != NULL);
+
+               g_clear_error (&error);
+       }
+}
+
+static void
+test_supported (void)
+{
+#ifdef ENABLE_PHONENUMBER
+       g_assert (e_phone_number_is_supported ());
+#else /* ENABLE_PHONENUMBER */
+       g_assert (!e_phone_number_is_supported ());
+#endif /* ENABLE_PHONENUMBER */
+}
+
+static void
+test_country_code_for_region (void)
+{
+       g_assert_cmpstr (setlocale (LC_ADDRESS, NULL), ==, "en_US.UTF-8");
+       g_assert_cmpint (e_phone_number_get_country_code_for_region ("CH"), ==, 41);
+       g_assert_cmpint (e_phone_number_get_country_code_for_region (NULL), ==, 1);
+       g_assert_cmpint (e_phone_number_get_country_code_for_region ("C"), ==, 0);
+       g_assert_cmpint (e_phone_number_get_country_code_for_region (""), ==, 1);
+}
+
+static void
+test_default_region (void)
+{
+       gchar *country;
+
+       g_assert_cmpstr (setlocale (LC_ADDRESS, NULL), ==, "en_US.UTF-8");
+
+       country = e_phone_number_get_default_region ();
+       g_assert_cmpstr (country, ==, "US");
+       g_free (country);
+}
+
+gint
+main (gint argc,
+      gchar **argv)
+{
+       size_t i, j;
+
+       setlocale (LC_ALL, "en_US.UTF-8");
+
+       g_type_init ();
+
+       g_test_init (&argc, &argv, NULL);
+
+       g_test_add_func
+               ("/ebook-phone-number/supported",
+                test_supported);
+
+       g_test_add_data_func_full (
+               "/ebook-phone-number/parse-and-format/i164", parse_and_format_data_new (
+                       "+493011223344", NULL,
+                       E_PHONE_NUMBER_COUNTRY_FROM_FQTN, 49, "3011223344",
+                       "+493011223344", "+49 30 11223344", "030 11223344", "tel:+49-30-11223344"),
+               test_parse_and_format, parse_and_format_data_free);
+       g_test_add_data_func_full (
+               "/ebook-phone-number/parse-and-format/national", parse_and_format_data_new (
+                        "(030) 22334-455", "DE",
+                        E_PHONE_NUMBER_COUNTRY_FROM_DEFAULT, 49, "3022334455",
+                        "+493022334455", "+49 30 22334455", "030 22334455", "tel:+49-30-22334455"),
+               test_parse_and_format, parse_and_format_data_free);
+       g_test_add_data_func_full (
+               "/ebook-phone-number/parse-and-format/national2", parse_and_format_data_new (
+                        "0049 (30) 22334-455", "DE",
+                        E_PHONE_NUMBER_COUNTRY_FROM_IDD, 49, "3022334455",
+                        "+493022334455", "+49 30 22334455", "030 22334455", "tel:+49-30-22334455"),
+               test_parse_and_format, parse_and_format_data_free);
+       g_test_add_data_func_full (
+               "/ebook-phone-number/parse-and-format/international", parse_and_format_data_new (
+                        "+1 212 33445566", NULL,
+                        E_PHONE_NUMBER_COUNTRY_FROM_FQTN, 1, "21233445566",
+                        "+121233445566", "+1 21233445566", "21233445566", "tel:+1-21233445566"),
+               test_parse_and_format, parse_and_format_data_free);
+       g_test_add_data_func_full (
+               "/ebook-phone-number/parse-and-format/rfc3966", parse_and_format_data_new (
+                        "tel:+358-71-44556677", NULL,
+                        E_PHONE_NUMBER_COUNTRY_FROM_FQTN, 358, "7144556677",
+                        "+3587144556677", "+358 71 44556677", "071 44556677", "tel:+358-71-44556677"),
+               test_parse_and_format, parse_and_format_data_free);
+
+       g_test_add_func (
+               "/ebook-phone-number/parse-and-format/bad-number",
+               test_parse_bad_number);
+
+       g_test_add_func (
+               "/ebook-phone-number/parse-and-format/auto-region",
+               test_parse_auto_region);
+
+       g_assert_cmpint (G_N_ELEMENTS (match_candidates) * G_N_ELEMENTS (match_candidates),
+                        ==, G_N_ELEMENTS (expected_matches));
+
+       for (i = 0; i < G_N_ELEMENTS (match_candidates); ++i) {
+               for (j = 0; j < G_N_ELEMENTS (match_candidates); ++j) {
+                       const size_t n = j + i * G_N_ELEMENTS (match_candidates);
+                       char *path = g_strdup_printf ("/ebook-phone-number/compare/%s/%s",
+                                                     match_candidates[i], match_candidates[j]);
+
+                       g_test_add_data_func (path, GUINT_TO_POINTER (n), test_compare_numbers);
+                       g_free (path);
+               }
+       }
+
+       g_test_add_func (
+               "/ebook-phone-number/country-code/for-region",
+               test_country_code_for_region);
+       g_test_add_func (
+               "/ebook-phone-number/country-code/default-region",
+               test_default_region);
+
+       return g_test_run ();
+}
diff --git a/tests/libedataserver/Makefile.am b/tests/libedataserver/Makefile.am
index 8f17b02..09d9613 100644
--- a/tests/libedataserver/Makefile.am
+++ b/tests/libedataserver/Makefile.am
@@ -1,5 +1,4 @@
 TESTS = \
-       e-phone-utils-test \
        $(NULL)
 
 noinst_PROGRAMS = \
@@ -18,9 +17,6 @@ TEST_LDADD =                                                  \
        $(E_DATA_SERVER_LIBS)                                   \
        $(GIO_UNIX_LIBS)
 
-e_phone_utils_test_CPPFLAGS = $(TEST_CPPFLAGS)
-e_phone_utils_test_LDADD = $(TEST_LDADD)
-
 e_source_test_CPPFLAGS = $(TEST_CPPFLAGS)
 e_source_test_LDADD = $(TEST_LDADD)
 


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