diff options
| -rw-r--r-- | addressbook/backends/file/e-book-backend-file.c | 326 | ||||
| -rw-r--r-- | addressbook/libedata-book/e-book-backend.c | 26 | ||||
| -rw-r--r-- | addressbook/libedata-book/e-book-backend.h | 2 |
3 files changed, 213 insertions, 141 deletions
diff --git a/addressbook/backends/file/e-book-backend-file.c b/addressbook/backends/file/e-book-backend-file.c index 643b982e5..23b5ac42e 100644 --- a/addressbook/backends/file/e-book-backend-file.c +++ b/addressbook/backends/file/e-book-backend-file.c @@ -48,7 +48,7 @@ #include "libebook/e-contact.h" #include "libedata-book/e-book-backend-sexp.h" -#include "libedata-book/e-book-backend-summary.h" +#include "libedata-book/e-book-backend-sqlitedb.h" #include "libedata-book/e-data-book.h" #include "libedata-book/e-data-book-view.h" @@ -62,7 +62,11 @@ #define E_BOOK_BACKEND_FILE_VERSION "0.2" #define PAS_ID_PREFIX "pas-id-" -#define SUMMARY_FLUSH_TIMEOUT 5000 + +#define SQLITEDB_EMAIL_ID "addressbook@localbackend.com" +#define SQLITEDB_FOLDER_ID "folder_id" +#define SQLITEDB_FOLDER_NAME "folder" + #define EDB_ERROR(_code) e_data_book_create_error (E_DATA_BOOK_STATUS_ ## _code, NULL) #define EDB_ERROR_EX(_code, _msg) e_data_book_create_error (E_DATA_BOOK_STATUS_ ## _code, _msg) @@ -73,10 +77,11 @@ G_DEFINE_TYPE (EBookBackendFile, e_book_backend_file, E_TYPE_BOOK_BACKEND_SYNC) struct _EBookBackendFilePrivate { gchar *dirname; gchar *filename; - gchar *summary_filename; - DB *file_db; - DB_ENV *env; - EBookBackendSummary *summary; + DB *file_db; + DB_ENV *env; + + EBookBackendSqliteDB *sqlitedb; + /* for future use */ gpointer reserved1; gpointer reserved2; @@ -121,7 +126,7 @@ string_to_dbt (const gchar *str, DBT *dbt) } static EContact* -create_contact (gchar *uid, const gchar *vcard) +create_contact (const gchar *uid, const gchar *vcard) { EContact *contact = e_contact_new_from_vcard (vcard); if (!e_contact_get_const (contact, E_CONTACT_UID)) @@ -131,12 +136,14 @@ create_contact (gchar *uid, const gchar *vcard) } static gboolean -build_summary (EBookBackendFilePrivate *bfpriv) +build_sqlitedb (EBookBackendFilePrivate *bfpriv) { DB *db = bfpriv->file_db; DBC *dbc; gint db_error; - DBT id_dbt, vcard_dbt; + DBT id_dbt, vcard_dbt; + GSList *contacts = NULL; + GError *error = NULL; if (!db) { g_warning (G_STRLOC ": Not openend yet"); @@ -160,8 +167,8 @@ build_summary (EBookBackendFilePrivate *bfpriv) if (id_dbt.size != strlen (E_BOOK_BACKEND_FILE_VERSION_NAME) + 1 || strcmp (id_dbt.data, E_BOOK_BACKEND_FILE_VERSION_NAME)) { EContact *contact = create_contact (id_dbt.data, vcard_dbt.data); - e_book_backend_summary_add_contact (bfpriv->summary, contact); - g_object_unref (contact); + + contacts = g_slist_prepend (contacts, contact); } db_error = dbc->c_get (dbc, &id_dbt, &vcard_dbt, DB_NEXT); @@ -170,6 +177,25 @@ build_summary (EBookBackendFilePrivate *bfpriv) dbc->c_close (dbc); + contacts = g_slist_reverse (contacts); + + if (!e_book_backend_sqlitedb_add_contacts (bfpriv->sqlitedb, + SQLITEDB_FOLDER_ID, + contacts, FALSE, &error)) { + g_warning ("Failed to build contact summary: %s", error->message); + g_error_free (error); + return FALSE; + } + + g_slist_foreach (contacts, (GFunc)g_object_unref, NULL); + g_slist_free (contacts); + + if (!e_book_backend_sqlitedb_set_is_populated (bfpriv->sqlitedb, SQLITEDB_FOLDER_ID, TRUE, &error)) { + g_warning ("Failed to set the sqlitedb populated flag: %s", error->message); + g_error_free (error); + return FALSE; + } + return TRUE; } @@ -266,7 +292,14 @@ e_book_backend_file_create_contact (EBookBackendSync *backend, EBookBackendFile *bf = E_BOOK_BACKEND_FILE (backend); if (do_create (bf, vcard, contact, perror)) { - e_book_backend_summary_add_contact (bf->priv->summary, *contact); + GError *error = NULL; + + if (!e_book_backend_sqlitedb_add_contact (bf->priv->sqlitedb, + SQLITEDB_FOLDER_ID, + *contact, FALSE, &error)) { + g_warning ("Failed to add contact to summary: %s", error->message); + g_error_free (error); + } } } @@ -279,12 +312,13 @@ e_book_backend_file_remove_contacts (EBookBackendSync *backend, GError **perror) { EBookBackendFile *bf = E_BOOK_BACKEND_FILE (backend); - DB *db = bf->priv->file_db; - DBT id_dbt; - gint db_error; - const gchar *id; - const GSList *l; - GSList *removed_cards = NULL; + DB *db = bf->priv->file_db; + DBT id_dbt; + gint db_error; + const gchar *id; + GSList *removed_cards = NULL; + const GSList *l; + GError *error = NULL; if (!db) { g_propagate_error (perror, EDB_NOT_OPENED_ERROR); @@ -313,12 +347,14 @@ e_book_backend_file_remove_contacts (EBookBackendSync *backend, g_warning (G_STRLOC ": db->sync failed with %s", db_strerror (db_error)); } - *ids = removed_cards; - - for (l = removed_cards; l; l = l->next) { - id = l->data; - e_book_backend_summary_remove_contact (bf->priv->summary, id); + if (!e_book_backend_sqlitedb_remove_contacts (bf->priv->sqlitedb, + SQLITEDB_FOLDER_ID, + removed_cards, &error)) { + g_warning ("Failed to remove contacts from the summary: %s", error->message); + g_error_free (error); } + + *ids = removed_cards; } static void @@ -374,8 +410,19 @@ e_book_backend_file_modify_contact (EBookBackendSync *backend, if (db_error != 0) { g_warning (G_STRLOC ": db->sync failed with %s", db_strerror (db_error)); } else { - e_book_backend_summary_remove_contact (bf->priv->summary, id); - e_book_backend_summary_add_contact (bf->priv->summary, *contact); + GError *error = NULL; + + if (!e_book_backend_sqlitedb_remove_contact (bf->priv->sqlitedb, + SQLITEDB_FOLDER_ID, + id, &error)) { + g_warning ("Failed to remove contact from the summary: %s", error->message); + g_error_free (error); + } else if (!e_book_backend_sqlitedb_add_contact (bf->priv->sqlitedb, + SQLITEDB_FOLDER_ID, + *contact, FALSE, &error)) { + g_warning ("Failed to add contact to summary: %s", error->message); + g_error_free (error); + } } } else { g_warning (G_STRLOC ": db->put failed with %s", db_strerror(db_error)); @@ -438,7 +485,8 @@ e_book_backend_file_get_contact_list (EBookBackendSync *backend, EBookBackendSExp *card_sexp = NULL; gboolean search_needed; const gchar *search = query; - GSList *contact_list = NULL; + GSList *contact_list = NULL, *l; + GSList *summary_list = NULL; d(printf ("e_book_backend_file_get_contact_list (%s)\n", search)); @@ -447,33 +495,22 @@ e_book_backend_file_get_contact_list (EBookBackendSync *backend, return; } - if (e_book_backend_summary_is_summary_query (bf->priv->summary, search)) { + summary_list = e_book_backend_sqlitedb_search (bf->priv->sqlitedb, + SQLITEDB_FOLDER_ID, + search, NULL, NULL); - /* do a summary query */ - GPtrArray *ids = e_book_backend_summary_search (bf->priv->summary, search); - gint i; + if (summary_list) { - if (!ids) { - g_propagate_error (perror, EDB_ERROR (CONTACT_NOT_FOUND)); - return; + for (l = summary_list; l; l = l->next) { + EbSdbSearchData *data = l->data; + + contact_list = g_slist_prepend (contact_list, data->vcard); + data->vcard = NULL; } - for (i = 0; i < ids->len; i++) { - gchar *id = g_ptr_array_index (ids, i); - string_to_dbt (id, &id_dbt); - memset (&vcard_dbt, 0, sizeof (vcard_dbt)); - vcard_dbt.flags = DB_DBT_MALLOC; + g_slist_foreach (summary_list, (GFunc)e_book_backend_sqlitedb_search_data_free, NULL); + g_slist_free (summary_list); - db_error = db->get (db, NULL, &id_dbt, &vcard_dbt, 0); - if (db_error == 0) { - contact_list = g_slist_prepend (contact_list, vcard_dbt.data); - } else { - g_warning (G_STRLOC ": db->get failed with %s", db_strerror (db_error)); - db_error_to_gerror (db_error, perror); - break; - } - } - g_ptr_array_free (ids, TRUE); } else { search_needed = TRUE; if (!strcmp (search, "(contains \"x-evolution-any-field\" \"\")")) @@ -560,24 +597,11 @@ e_book_backend_file_get_contact_list_uids (EBookBackendSync *backend, return; } - if (e_book_backend_summary_is_summary_query (bf->priv->summary, search)) { - /* do a summary query */ - GPtrArray *ids = e_book_backend_summary_search (bf->priv->summary, search); - gint i; - - if (!ids) { - g_propagate_error (perror, EDB_ERROR (CONTACT_NOT_FOUND)); - return; - } - - for (i = 0; i < ids->len; i++) { - gchar *id = g_ptr_array_index (ids, i); - - uids = g_slist_prepend (uids, g_strdup (id)); - } + uids = e_book_backend_sqlitedb_search_uids (bf->priv->sqlitedb, + SQLITEDB_FOLDER_ID, + search, NULL); - g_ptr_array_free (ids, TRUE); - } else { + if (!uids) { search_needed = TRUE; if (!strcmp (search, "(contains \"x-evolution-any-field\" \"\")")) search_needed = FALSE; @@ -671,6 +695,18 @@ get_closure (EDataBookView *book_view) return g_object_get_data (G_OBJECT (book_view), "EBookBackendFile.BookView::closure"); } +static void +notify_update_vcard (EDataBookView *book_view, + gboolean prefiltered, + const gchar *id, + gchar *vcard) +{ + if (prefiltered) + e_data_book_view_notify_update_prefiltered_vcard (book_view, id, vcard); + else + e_data_book_view_notify_update_vcard (book_view, vcard); +} + static gpointer book_view_thread (gpointer data) { @@ -682,6 +718,8 @@ book_view_thread (gpointer data) DBT id_dbt, vcard_dbt; gint db_error; gboolean allcontacts; + GSList *summary_list, *l; + GHashTable *fields_of_interest; g_return_val_if_fail (E_IS_DATA_BOOK_VIEW (data), NULL); @@ -699,15 +737,16 @@ book_view_thread (gpointer data) when/if it's stopped */ e_data_book_view_ref (book_view); - db = bf->priv->file_db; + db = bf->priv->file_db; + query = e_data_book_view_get_card_query (book_view); + fields_of_interest = e_data_book_view_get_fields_of_interest (book_view); + if (!db) { e_data_book_view_notify_complete (book_view, EDB_NOT_OPENED_ERROR); e_data_book_view_unref (book_view); return NULL; } - query = e_data_book_view_get_card_query (book_view); - if ( !strcmp (query, "(contains \"x-evolution-any-field\" \"\")")) { e_data_book_view_notify_progress (book_view, -1, _("Loading...")); allcontacts = TRUE; @@ -719,37 +758,21 @@ book_view_thread (gpointer data) d(printf ("signalling parent thread\n")); e_flag_set (closure->running); - if (e_book_backend_summary_is_summary_query (bf->priv->summary, query)) { - /* do a summary query */ - GPtrArray *ids = e_book_backend_summary_search (bf->priv->summary, e_data_book_view_get_card_query (book_view)); - gint i; - - if (!ids) - goto done; + summary_list = e_book_backend_sqlitedb_search (bf->priv->sqlitedb, + SQLITEDB_FOLDER_ID, + query, fields_of_interest, NULL); + if (summary_list) { - for (i = 0; i < ids->len; i++) { - gchar *id = g_ptr_array_index (ids, i); + for (l = summary_list; l; l = l->next) { + EbSdbSearchData *data = l->data; - if (!e_flag_is_set (closure->running)) - break; - - string_to_dbt (id, &id_dbt); - memset (&vcard_dbt, 0, sizeof (vcard_dbt)); - vcard_dbt.flags = DB_DBT_MALLOC; - - db_error = db->get (db, NULL, &id_dbt, &vcard_dbt, 0); - - if (db_error == 0) { - e_data_book_view_notify_update_prefiltered_vcard (book_view, id, vcard_dbt.data); - } - else { - g_warning (G_STRLOC ": db->get failed with %s", db_strerror (db_error)); - } + notify_update_vcard (book_view, TRUE, data->uid, data->vcard); + data->vcard = NULL; } - g_ptr_array_free (ids, TRUE); - } - else { + g_slist_foreach (summary_list, (GFunc)e_book_backend_sqlitedb_search_data_free, NULL); + g_slist_free (summary_list); + } else { /* iterate over the db and do the query there */ DBC *dbc; @@ -768,10 +791,8 @@ book_view_thread (gpointer data) /* don't include the version in the list of cards */ if (strcmp (id_dbt.data, E_BOOK_BACKEND_FILE_VERSION_NAME)) { - if (allcontacts) - e_data_book_view_notify_update_prefiltered_vcard (book_view, id_dbt.data, vcard_dbt.data); - else - e_data_book_view_notify_update_vcard (book_view, vcard_dbt.data); + notify_update_vcard (book_view, allcontacts, + id_dbt.data, vcard_dbt.data); } else { g_free (vcard_dbt.data); } @@ -791,7 +812,7 @@ book_view_thread (gpointer data) } } -done: + if (e_flag_is_set (closure->running)) e_data_book_view_notify_complete (book_view, NULL /* Success */); @@ -1049,14 +1070,13 @@ e_book_backend_file_open (EBookBackendSync *backend, GError **perror) { EBookBackendFile *bf = E_BOOK_BACKEND_FILE (backend); - gchar *dirname, *filename; - gboolean readonly = TRUE; - ESource *source = e_book_backend_get_source (E_BOOK_BACKEND (backend)); - gint db_error; - DB *db; - DB_ENV *env; - time_t db_mtime; - struct stat sb; + gchar *dirname, *filename; + gboolean readonly = TRUE; + ESource *source = e_book_backend_get_source (E_BOOK_BACKEND (backend)); + gint db_error; + DB *db; + DB_ENV *env; + GError *local_error = NULL; #ifdef CREATE_DEFAULT_VCARD gboolean create_default_vcard = FALSE; @@ -1252,23 +1272,25 @@ e_book_backend_file_open (EBookBackendSync *backend, bf->priv->dirname = dirname; bf->priv->filename = filename; - if (g_stat (bf->priv->filename, &sb) == -1) { - db->close (db, 0); - bf->priv->file_db = NULL; - g_propagate_error (perror, e_data_book_create_error_fmt (E_DATA_BOOK_STATUS_OTHER_ERROR, "stat(%s) failed", bf->priv->filename)); + bf->priv->sqlitedb = e_book_backend_sqlitedb_new (bf->priv->dirname, + SQLITEDB_EMAIL_ID, + SQLITEDB_FOLDER_ID, + SQLITEDB_FOLDER_NAME, + FALSE, + perror); + if (!bf->priv->sqlitedb) return; - } - db_mtime = sb.st_mtime; - g_free (bf->priv->summary_filename); - bf->priv->summary_filename = g_strconcat (bf->priv->filename, ".summary", NULL); - bf->priv->summary = e_book_backend_summary_new (bf->priv->summary_filename, SUMMARY_FLUSH_TIMEOUT); - - if (e_book_backend_summary_is_up_to_date (bf->priv->summary, db_mtime) == FALSE - || e_book_backend_summary_load (bf->priv->summary) == FALSE ) { - if (!bf->priv->summary || !build_summary (bf->priv)) { - g_propagate_error (perror, e_data_book_create_error_fmt (E_DATA_BOOK_STATUS_OTHER_ERROR, "Failed to build summary for an address book %s", bf->priv->filename)); + if (!e_book_backend_sqlitedb_get_is_populated (bf->priv->sqlitedb, + SQLITEDB_FOLDER_ID, + &local_error)) { + if (local_error) { + g_propagate_error (perror, local_error); return; + } else if (!build_sqlitedb (bf->priv)) { + g_propagate_error (perror, e_data_book_create_error_fmt (E_DATA_BOOK_STATUS_OTHER_ERROR, + "Failed to build summary for an address book %s", + bf->priv->filename)); } } @@ -1313,11 +1335,12 @@ e_book_backend_file_remove (EBookBackendSync *backend, return; } - /* unref the summary before we remove the file so it's not written out again */ - g_object_unref (bf->priv->summary); - bf->priv->summary = NULL; - if (-1 == g_unlink (bf->priv->summary_filename)) - g_warning ("failed to remove summary file `%s`: %s", bf->priv->summary_filename, g_strerror (errno)); + if (!e_book_backend_sqlitedb_remove (bf->priv->sqlitedb, perror)) + return; + + /* unref the sqlitedb before we remove the file so it's not written out again */ + g_object_unref (bf->priv->sqlitedb); + bf->priv->sqlitedb = NULL; dir = g_dir_open (bf->priv->dirname, 0, NULL); if (dir) { @@ -1400,6 +1423,47 @@ e_book_backend_file_sync (EBookBackend *backend) } } +typedef struct { + EContact *contact; + EBookBackendFile *bf; +} NotifyData; + +static gboolean +view_notify_update (EDataBookView *view, gpointer data) +{ + NotifyData *ndata = data; + GHashTable *fields = e_data_book_view_get_fields_of_interest (view); + gboolean notified = FALSE; + + if (e_book_backend_sqlitedb_is_summary_query (e_data_book_view_get_card_query (view), fields)) { + + const gchar *uid = e_contact_get_const (ndata->contact, E_CONTACT_UID); + gchar *vcard; + + vcard = e_book_backend_sqlitedb_get_vcard_string (ndata->bf->priv->sqlitedb, + SQLITEDB_FOLDER_ID, uid, + fields, NULL); + + if (vcard) { + e_data_book_view_notify_update_prefiltered_vcard (view, uid, vcard); + notified = TRUE; + } + } + + if (!notified) + e_data_book_view_notify_update (view, ndata->contact); + + return TRUE; +} + +static void +e_book_backend_file_notify_update (EBookBackend *backend, const EContact *contact) +{ + NotifyData data = { (EContact *)contact, E_BOOK_BACKEND_FILE (backend) }; + + e_book_backend_foreach_view (backend, view_notify_update, &data); +} + /** * e_book_backend_file_new: */ @@ -1429,9 +1493,9 @@ e_book_backend_file_dispose (GObject *object) } G_UNLOCK (global_env); - if (bf->priv->summary) { - g_object_unref (bf->priv->summary); - bf->priv->summary = NULL; + if (bf->priv->sqlitedb) { + g_object_unref (bf->priv->sqlitedb); + bf->priv->sqlitedb = NULL; } G_OBJECT_CLASS (e_book_backend_file_parent_class)->dispose (object); @@ -1446,7 +1510,6 @@ e_book_backend_file_finalize (GObject *object) g_free (bf->priv->filename); g_free (bf->priv->dirname); - g_free (bf->priv->summary_filename); g_free (bf->priv); @@ -1512,6 +1575,7 @@ e_book_backend_file_class_init (EBookBackendFileClass *klass) backend_class->stop_book_view = e_book_backend_file_stop_book_view; backend_class->set_online = e_book_backend_file_set_online; backend_class->sync = e_book_backend_file_sync; + backend_class->notify_update = e_book_backend_file_notify_update; sync_class->open_sync = e_book_backend_file_open; sync_class->remove_sync = e_book_backend_file_remove; diff --git a/addressbook/libedata-book/e-book-backend.c b/addressbook/libedata-book/e-book-backend.c index d4b345e37..79505d355 100644 --- a/addressbook/libedata-book/e-book-backend.c +++ b/addressbook/libedata-book/e-book-backend.c @@ -177,6 +177,20 @@ book_backend_finalize (GObject *object) G_OBJECT_CLASS (e_book_backend_parent_class)->finalize (object); } +static gboolean +view_notify_update (EDataBookView *view, gpointer contact) +{ + e_data_book_view_notify_update (view, contact); + + return TRUE; +} + +static void +book_backend_notify_update (EBookBackend *backend, const EContact *contact) +{ + e_book_backend_foreach_view (backend, view_notify_update, (gpointer) contact); +} + static void e_book_backend_class_init (EBookBackendClass *klass) { @@ -192,6 +206,7 @@ e_book_backend_class_init (EBookBackendClass *klass) klass->get_backend_property = book_backend_get_backend_property; klass->set_backend_property = book_backend_set_backend_property; + klass->notify_update = book_backend_notify_update; g_object_class_install_property ( object_class, @@ -1039,15 +1054,6 @@ e_book_backend_sync (EBookBackend *backend) g_object_unref (backend); } - - -static gboolean -view_notify_update (EDataBookView *view, gpointer contact) -{ - e_data_book_view_notify_update (view, contact); - - return TRUE; -} /** * e_book_backend_notify_update: @@ -1064,7 +1070,7 @@ view_notify_update (EDataBookView *view, gpointer contact) void e_book_backend_notify_update (EBookBackend *backend, const EContact *contact) { - e_book_backend_foreach_view (backend, view_notify_update, (gpointer) contact); + E_BOOK_BACKEND_GET_CLASS (backend)->notify_update (backend, contact); } static gboolean diff --git a/addressbook/libedata-book/e-book-backend.h b/addressbook/libedata-book/e-book-backend.h index f0347309f..dbb35e617 100644 --- a/addressbook/libedata-book/e-book-backend.h +++ b/addressbook/libedata-book/e-book-backend.h @@ -79,6 +79,8 @@ struct _EBookBackendClass { void (* start_book_view) (EBookBackend *backend, EDataBookView *book_view); void (* stop_book_view) (EBookBackend *backend, EDataBookView *book_view); + void (* notify_update) (EBookBackend *backend, const EContact *contact); + /* Notification signals */ void (* last_client_gone) (EBookBackend *backend); void (* sync) (EBookBackend *backend); |
