From 653cfffc0e00dfb59b36813c1b45c53d3f773c65 Mon Sep 17 00:00:00 2001 From: Ettore Perazzoli Date: Tue, 21 Oct 2003 18:49:34 +0000 Subject: Merge new-ui-branch to the trunk. svn path=/trunk/; revision=22965 --- addressbook/backend/pas/pas-backend-file.c | 1315 +++++++++------------------- 1 file changed, 430 insertions(+), 885 deletions(-) (limited to 'addressbook/backend/pas/pas-backend-file.c') diff --git a/addressbook/backend/pas/pas-backend-file.c b/addressbook/backend/pas/pas-backend-file.c index b11c62cb86..06923d7b08 100644 --- a/addressbook/backend/pas/pas-backend-file.c +++ b/addressbook/backend/pas/pas-backend-file.c @@ -8,12 +8,18 @@ #include "config.h" #include "pas-backend-file.h" +#include "pas-backend-card-sexp.h" +#include "pas-backend-summary.h" +#include "pas-book.h" +#include "pas-book-view.h" #include #include #include #include +#include #include +#include #include #include @@ -28,15 +34,12 @@ #include #include -#include +#include #include #include #include -#include "pas-book.h" -#include "pas-card-cursor.h" -#include "pas-backend-card-sexp.h" -#include "pas-backend-summary.h" +#define CHANGES_DB_SUFFIX ".changes.db" #define PAS_BACKEND_FILE_VERSION_NAME "PAS-DB-VERSION" #define PAS_BACKEND_FILE_VERSION "0.2" @@ -44,47 +47,17 @@ #define PAS_ID_PREFIX "pas-id-" #define SUMMARY_FLUSH_TIMEOUT 5000 -static PASBackendClass *pas_backend_file_parent_class; -typedef struct _PASBackendFileCursorPrivate PASBackendFileCursorPrivate; -typedef struct _PASBackendFileBookView PASBackendFileBookView; -typedef struct _PASBackendFileSearchContext PASBackendFileSearchContext; -typedef struct _PasBackendFileChangeContext PASBackendFileChangeContext; +static PASBackendSyncClass *pas_backend_file_parent_class; struct _PASBackendFilePrivate { char *uri; + char *dirname; char *filename; + char *summary_filename; DB *file_db; - EList *book_views; - GHashTable *address_lists; PASBackendSummary *summary; }; -struct _PASBackendFileCursorPrivate { - PASBackend *backend; - PASBook *book; - - GList *elements; - guint32 num_elements; -}; - -struct _PASBackendFileBookView { - PASBookView *book_view; - gchar *search; - PASBackendCardSExp *card_sexp; - gchar *change_id; - PASBackendFileChangeContext *change_context; -}; - -struct _PasBackendFileChangeContext { - DB *db; - - GList *add_cards; - GList *add_ids; - GList *mod_cards; - GList *mod_ids; - GList *del_ids; -}; - static void string_to_dbt(const char *str, DBT *dbt) { @@ -104,7 +77,8 @@ build_summary (PASBackendFilePrivate *bfpriv) db_error = db->cursor (db, NULL, &dbc, 0); if (db_error != 0) { - g_warning ("pas_backend_file_build_all_cards_list: error building list\n"); + g_warning ("build_summary: error building list\n"); + return; } memset (&vcard_dbt, 0, sizeof (vcard_dbt)); @@ -117,7 +91,7 @@ build_summary (PASBackendFilePrivate *bfpriv) if (id_dbt.size != strlen(PAS_BACKEND_FILE_VERSION_NAME) + 1 || strcmp (id_dbt.data, PAS_BACKEND_FILE_VERSION_NAME)) { - pas_backend_summary_add_card (bfpriv->summary, vcard_dbt.data); + pas_backend_summary_add_contact (bfpriv->summary, vcard_dbt.data); } db_error = dbc->c_get(dbc, &id_dbt, &vcard_dbt, DB_NEXT); @@ -126,21 +100,17 @@ build_summary (PASBackendFilePrivate *bfpriv) } static void -do_summary_query (PASBackendFile *bf, - PASBackendFileBookView *view, - gboolean completion_search) +do_summary_query (PASBackendFile *bf, + PASBookView *view) { - GPtrArray *ids = pas_backend_summary_search (bf->priv->summary, view->search); + GPtrArray *ids = pas_backend_summary_search (bf->priv->summary, pas_book_view_get_card_query (view)); int db_error = 0; - GList *cards = NULL; - gint card_count = 0, card_threshold = 20, card_threshold_max = 3000; DB *db = bf->priv->file_db; DBT id_dbt, vcard_dbt; int i; for (i = 0; i < ids->len; i ++) { char *id = g_ptr_array_index (ids, i); - char *vcard = NULL; #if SUMMARY_STORES_ENOUGH_INFO /* this is disabled for the time being because lists @@ -150,6 +120,11 @@ do_summary_query (PASBackendFile *bf, if (completion_search) { vcard = pas_backend_summary_get_summary_vcard (bf->priv->summary, id); + if (vcard) { + EContact *contact = e_contact_new_from_vcard (vcard_dbt.data); + pas_book_view_notify_update (view, contact); + g_object_unref (contact); + } } else { #endif @@ -159,166 +134,19 @@ do_summary_query (PASBackendFile *bf, db_error = db->get (db, NULL, &id_dbt, &vcard_dbt, 0); if (db_error == 0) - vcard = g_strdup (vcard_dbt.data); + pas_book_view_notify_update (view, vcard_dbt.data); #if SUMMARY_STORES_ENOUGH_INFO } #endif - - if (vcard) { - cards = g_list_prepend (cards, vcard); - card_count ++; - - /* If we've accumulated a number of checks, pass them off to the client. */ - if (card_count >= card_threshold) { - pas_book_view_notify_add (view->book_view, cards); - /* Clean up the handed-off data. */ - g_list_foreach (cards, (GFunc)g_free, NULL); - g_list_free (cards); - cards = NULL; - card_count = 0; - - /* Yeah, this scheme is overly complicated. But I like it. */ - if (card_threshold < card_threshold_max) { - card_threshold = MIN (2*card_threshold, card_threshold_max); - } - } - } - else - continue; /* XXX */ } g_ptr_array_free (ids, TRUE); - if (card_count) - pas_book_view_notify_add (view->book_view, cards); - - pas_book_view_notify_complete (view->book_view, GNOME_Evolution_Addressbook_BookViewListener_Success); - - g_list_foreach (cards, (GFunc)g_free, NULL); - g_list_free (cards); -} - -static PASBackendFileBookView * -pas_backend_file_book_view_copy(const PASBackendFileBookView *book_view, void *closure) -{ - PASBackendFileBookView *new_book_view; - new_book_view = g_new (PASBackendFileBookView, 1); - new_book_view->book_view = book_view->book_view; - - new_book_view->search = g_strdup(book_view->search); - new_book_view->card_sexp = book_view->card_sexp; - if (new_book_view->card_sexp) - g_object_ref(new_book_view->card_sexp); - - new_book_view->change_id = g_strdup(book_view->change_id); - if (book_view->change_context) { - new_book_view->change_context = g_new(PASBackendFileChangeContext, 1); - new_book_view->change_context->db = book_view->change_context->db; - new_book_view->change_context->add_cards = book_view->change_context->add_cards; - new_book_view->change_context->add_ids = book_view->change_context->add_ids; - new_book_view->change_context->mod_cards = book_view->change_context->mod_cards; - new_book_view->change_context->mod_ids = book_view->change_context->mod_ids; - new_book_view->change_context->del_ids = book_view->change_context->del_ids; - } else - new_book_view->change_context = NULL; - - return new_book_view; -} - -static void -pas_backend_file_book_view_free(PASBackendFileBookView *book_view, void *closure) -{ - g_free(book_view->search); - if (book_view->card_sexp) - g_object_unref (book_view->card_sexp); - - g_free(book_view->change_id); - if (book_view->change_context) { - g_list_foreach (book_view->change_context->add_cards, (GFunc)g_free, NULL); - g_list_foreach (book_view->change_context->add_ids, (GFunc)g_free, NULL); - g_list_foreach (book_view->change_context->mod_cards, (GFunc)g_free, NULL); - g_list_foreach (book_view->change_context->mod_ids, (GFunc)g_free, NULL); - g_list_foreach (book_view->change_context->del_ids, (GFunc)g_free, NULL); - g_list_free (book_view->change_context->add_cards); - g_list_free (book_view->change_context->add_ids); - g_list_free (book_view->change_context->mod_cards); - g_list_free (book_view->change_context->mod_ids); - g_list_free (book_view->change_context->del_ids); - } - g_free(book_view->change_context); - - g_free(book_view); -} - -static long -get_length(PASCardCursor *cursor, gpointer data) -{ - PASBackendFileCursorPrivate *cursor_data = (PASBackendFileCursorPrivate *) data; - - return cursor_data->num_elements; + pas_book_view_notify_complete (view, GNOME_Evolution_Addressbook_Success); } static char * -get_nth(PASCardCursor *cursor, long n, gpointer data) -{ - PASBackendFileCursorPrivate *cursor_data = (PASBackendFileCursorPrivate *) data; - GList *nth_item = g_list_nth(cursor_data->elements, n); - - return g_strdup((char*)nth_item->data); -} - -static void -cursor_destroy(gpointer data, GObject *where_object_was) -{ - CORBA_Environment ev; - GNOME_Evolution_Addressbook_Book corba_book; - PASBackendFileCursorPrivate *cursor_data = (PASBackendFileCursorPrivate *) data; - - corba_book = bonobo_object_corba_objref(BONOBO_OBJECT(cursor_data->book)); - - CORBA_exception_init(&ev); - - GNOME_Evolution_Addressbook_Book_unref(corba_book, &ev); - - if (ev._major != CORBA_NO_EXCEPTION) { - g_warning("cursor_destroy: Exception unreffing " - "corba book.\n"); - } - - CORBA_exception_free(&ev); - - g_list_foreach(cursor_data->elements, (GFunc)g_free, NULL); - g_list_free (cursor_data->elements); - - g_free(cursor_data); -} - -static void -view_destroy(gpointer data, GObject *where_object_was) -{ - PASBook *book = (PASBook *)data; - PASBackendFile *bf; - EIterator *iterator; - gboolean success = FALSE; - - bf = PAS_BACKEND_FILE(pas_book_get_backend(book)); - for (iterator = e_list_get_iterator(bf->priv->book_views); e_iterator_is_valid(iterator); e_iterator_next(iterator)) { - const PASBackendFileBookView *view = e_iterator_get(iterator); - if (view->book_view == (PASBookView*)where_object_was) { - e_iterator_delete(iterator); - success = TRUE; - break; - } - } - if (!success) - g_warning ("Failed to remove from book_views list"); - g_object_unref(iterator); - - bonobo_object_unref(BONOBO_OBJECT(book)); -} - -static char * -pas_backend_file_create_unique_id (char *vcard) +pas_backend_file_create_unique_id (void) { /* use a 32 counter and the 32 bit timestamp to make an id. it's doubtful 2^32 id's will be created in a second, so we @@ -327,46 +155,18 @@ pas_backend_file_create_unique_id (char *vcard) return g_strdup_printf (PAS_ID_PREFIX "%08lX%08X", time(NULL), c++); } -static gboolean -vcard_matches_search (const PASBackendFileBookView *view, char *vcard_string) -{ - /* If this is not a search context view, it doesn't match be default */ - if (view->card_sexp == NULL) - return FALSE; - - return pas_backend_card_sexp_match_vcard (view->card_sexp, vcard_string); -} - -static gboolean -ecard_matches_search (const PASBackendFileBookView *view, ECard *card) -{ - /* If this is not a search context view, it doesn't match be default */ - if (view->card_sexp == NULL) - return FALSE; - - return pas_backend_card_sexp_match_ecard (view->card_sexp, card); -} - typedef struct { PASBackendFile *bf; PASBook *book; - const PASBackendFileBookView *view; + PASBookView *view; DBC *dbc; - int card_count; - int card_threshold; - int card_threshold_max; - GList *cards; - gboolean done_first; - gboolean search_needed; } FileBackendSearchClosure; static void free_search_closure (FileBackendSearchClosure *closure) { - g_list_foreach (closure->cards, (GFunc)g_free, NULL); - g_list_free (closure->cards); g_free (closure); } @@ -397,32 +197,11 @@ pas_backend_file_search_timeout (gpointer data) /* don't include the version in the list of cards */ if (strcmp (id_dbt.data, PAS_BACKEND_FILE_VERSION_NAME)) { char *vcard_string = vcard_dbt.data; + EContact *contact = e_contact_new_from_vcard (vcard_string); - /* check if the vcard matches the search sexp */ - if ((!closure->search_needed) || vcard_matches_search (closure->view, vcard_string)) { - closure->cards = g_list_prepend (closure->cards, g_strdup (vcard_string)); - closure->card_count ++; - } - - /* If we've accumulated a number of checks, pass them off to the client. */ - if (closure->card_count >= closure->card_threshold) { - pas_book_view_notify_add (closure->view->book_view, closure->cards); - /* Clean up the handed-off data. */ - g_list_foreach (closure->cards, (GFunc)g_free, NULL); - g_list_free (closure->cards); - closure->cards = NULL; - closure->card_count = 0; - - /* Yeah, this scheme is overly complicated. But I like it. */ - if (closure->card_threshold < closure->card_threshold_max) { - closure->card_threshold = MIN (2*closure->card_threshold, closure->card_threshold_max); - } - - /* return here, we'll do the next lump in the next callback */ - g_timeout_add (200, pas_backend_file_search_timeout, closure); - - return FALSE; - } + /* notify_update will check if it matches for us */ + pas_book_view_notify_update (closure->view, contact); + g_object_unref (contact); } db_error = dbc->c_get(dbc, &id_dbt, &vcard_dbt, DB_NEXT); @@ -435,10 +214,7 @@ pas_backend_file_search_timeout (gpointer data) free_search_closure (closure); } - if (closure->card_count) - pas_book_view_notify_add (closure->view->book_view, closure->cards); - - pas_book_view_notify_complete (closure->view->book_view, GNOME_Evolution_Addressbook_BookViewListener_Success); + pas_book_view_notify_complete (closure->view, GNOME_Evolution_Addressbook_Success); free_search_closure (closure); @@ -448,49 +224,25 @@ pas_backend_file_search_timeout (gpointer data) static void pas_backend_file_search (PASBackendFile *bf, - PASBook *book, - const PASBackendFileBookView *cnstview, - gboolean completion_search) + PASBookView *book_view) { - PASBackendFileBookView *view = (PASBackendFileBookView *)cnstview; - gboolean search_needed; - - search_needed = TRUE; - - if ( ! strcmp (view->search, "(contains \"x-evolution-any-field\" \"\")")) - search_needed = FALSE; + const char *query = pas_book_view_get_card_query (book_view); - if (search_needed) - pas_book_view_notify_status_message (view->book_view, _("Searching...")); + if ( ! strcmp (query, "(contains \"x-evolution-any-field\" \"\")")) + pas_book_view_notify_status_message (book_view, _("Loading...")); else - pas_book_view_notify_status_message (view->book_view, _("Loading...")); - - if (view->card_sexp) { - g_object_unref (view->card_sexp); - view->card_sexp = NULL; - } - - view->card_sexp = pas_backend_card_sexp_new (view->search); - - if (!view->card_sexp) { - pas_book_view_notify_complete (view->book_view, GNOME_Evolution_Addressbook_BookViewListener_InvalidQuery); - return; - } + pas_book_view_notify_status_message (book_view, _("Searching...")); - if (pas_backend_summary_is_summary_query (bf->priv->summary, view->search)) { - do_summary_query (bf, view, completion_search); + if (pas_backend_summary_is_summary_query (bf->priv->summary, query)) { + do_summary_query (bf, book_view); } else { FileBackendSearchClosure *closure = g_new0 (FileBackendSearchClosure, 1); DB *db = bf->priv->file_db; int db_error; - closure->card_threshold = 20; - closure->card_threshold_max = 3000; - closure->search_needed = search_needed; - closure->view = view; + closure->view = book_view; closure->bf = bf; - closure->book = book; db_error = db->cursor (db, NULL, &closure->dbc, 0); @@ -502,257 +254,81 @@ pas_backend_file_search (PASBackendFile *bf, } } -static void -pas_backend_file_changes_foreach_key (const char *key, gpointer user_data) +static EContact * +do_create(PASBackendFile *bf, + const char *vcard_req) { - PASBackendFileChangeContext *ctx = user_data; - DB *db = ctx->db; - DBT id_dbt, vcard_dbt; - int db_error = 0; - - string_to_dbt (key, &id_dbt); - memset (&vcard_dbt, 0, sizeof (vcard_dbt)); - db_error = db->get (db, NULL, &id_dbt, &vcard_dbt, 0); - - if (db_error != 0) { - char *id = id_dbt.data; - - ctx->del_ids = g_list_append (ctx->del_ids, g_strdup (id)); - } -} - -static void -pas_backend_file_changes (PASBackendFile *bf, - PASBook *book, - const PASBackendFileBookView *cnstview) -{ - int db_error = 0; - DBT id_dbt, vcard_dbt; - char *filename; - EDbHash *ehash; - GList *i, *v; - DB *db = bf->priv->file_db; - DBC *dbc; - PASBackendFileBookView *view = (PASBackendFileBookView *)cnstview; - PASBackendFileChangeContext *ctx = cnstview->change_context; - char *dirname, *slash; - - memset (&id_dbt, 0, sizeof (id_dbt)); - memset (&vcard_dbt, 0, sizeof (vcard_dbt)); - - /* Find the changed ids */ - dirname = g_strdup (bf->priv->filename); - slash = strrchr (dirname, '/'); - *slash = '\0'; - - filename = g_strdup_printf ("%s/%s.db", dirname, view->change_id); - ehash = e_dbhash_new (filename); - g_free (filename); - g_free (dirname); - - db_error = db->cursor (db, NULL, &dbc, 0); - - if (db_error != 0) { - g_warning ("pas_backend_file_changes: error building list\n"); - } else { - db_error = dbc->c_get(dbc, &id_dbt, &vcard_dbt, DB_FIRST); - - while (db_error == 0) { - - /* don't include the version in the list of cards */ - if (id_dbt.size != strlen(PAS_BACKEND_FILE_VERSION_NAME) + 1 - || strcmp (id_dbt.data, PAS_BACKEND_FILE_VERSION_NAME)) { - ECard *card; - char *id = id_dbt.data; - char *vcard_string; - - /* Remove fields the user can't change - * and can change without the rest of the - * card changing - */ - card = e_card_new (vcard_dbt.data); - g_object_set (card, "last_use", NULL, "use_score", 0.0, NULL); - vcard_string = e_card_get_vcard_assume_utf8 (card); - g_object_unref (card); - - /* check what type of change has occurred, if any */ - switch (e_dbhash_compare (ehash, id, vcard_string)) { - case E_DBHASH_STATUS_SAME: - break; - case E_DBHASH_STATUS_NOT_FOUND: - ctx->add_cards = g_list_append (ctx->add_cards, - vcard_string); - ctx->add_ids = g_list_append (ctx->add_ids, g_strdup(id)); - break; - case E_DBHASH_STATUS_DIFFERENT: - ctx->mod_cards = g_list_append (ctx->mod_cards, - vcard_string); - ctx->mod_ids = g_list_append (ctx->mod_ids, g_strdup(id)); - break; - } - } - - db_error = dbc->c_get(dbc, &id_dbt, &vcard_dbt, DB_NEXT); - } - dbc->c_close (dbc); - } - - e_dbhash_foreach_key (ehash, (EDbHashFunc)pas_backend_file_changes_foreach_key, view->change_context); - - /* Send the changes */ - if (db_error != DB_NOTFOUND) { - g_warning ("pas_backend_file_changes: error building list\n"); - } else { - if (ctx->add_cards != NULL) - pas_book_view_notify_add (view->book_view, ctx->add_cards); - - if (ctx->mod_cards != NULL) - pas_book_view_notify_change (view->book_view, ctx->mod_cards); - - for (v = ctx->del_ids; v != NULL; v = v->next){ - char *id = v->data; - pas_book_view_notify_remove_1 (view->book_view, id); - } - - pas_book_view_notify_complete (view->book_view, GNOME_Evolution_Addressbook_BookViewListener_Success); - } - - /* Update the hash */ - for (i = ctx->add_ids, v = ctx->add_cards; i != NULL; i = i->next, v = v->next){ - char *id = i->data; - char *vcard = v->data; - - e_dbhash_add (ehash, id, vcard); - g_free (i->data); - g_free (v->data); - } - for (i = ctx->mod_ids, v = ctx->mod_cards; i != NULL; i = i->next, v = v->next){ - char *id = i->data; - char *vcard = v->data; - - e_dbhash_add (ehash, id, vcard); - g_free (i->data); - g_free (v->data); - } - for (i = ctx->del_ids; i != NULL; i = i->next){ - char *id = i->data; - - e_dbhash_remove (ehash, id); - g_free (i->data); - } - - e_dbhash_write (ehash); - e_dbhash_destroy (ehash); -} - -static char * -do_create(PASBackend *backend, - char *vcard_req, - char **vcard_ptr) -{ - PASBackendFile *bf = PAS_BACKEND_FILE (backend); DB *db = bf->priv->file_db; DBT id_dbt, vcard_dbt; int db_error; char *id; - ECard *card; + EContact *contact; char *vcard; - char *ret_val; - id = pas_backend_file_create_unique_id (vcard_req); + id = pas_backend_file_create_unique_id (); string_to_dbt (id, &id_dbt); - - card = e_card_new(vcard_req); - e_card_set_id(card, id); - vcard = e_card_get_vcard_assume_utf8(card); + + contact = e_contact_new_from_vcard (vcard_req); + e_contact_set(contact, E_CONTACT_UID, id); + vcard = e_vcard_to_string (E_VCARD (contact), EVC_FORMAT_VCARD_30); string_to_dbt (vcard, &vcard_dbt); db_error = db->put (db, NULL, &id_dbt, &vcard_dbt, 0); + g_free (vcard); + if (0 == db_error) { db_error = db->sync (db, 0); if (db_error != 0) g_warning ("db->sync failed.\n"); - ret_val = id; - } else { - g_free (id); - ret_val = NULL; + g_object_unref (contact); + contact = NULL; } - g_object_unref(card); - card = NULL; - - if (vcard_ptr && ret_val) - *vcard_ptr = vcard; - else - g_free (vcard); - - return ret_val; + g_free (id); + return contact; } -static void -pas_backend_file_process_create_card (PASBackend *backend, - PASBook *book, - PASCreateCardRequest *req) +static PASBackendSyncStatus +pas_backend_file_create_contact (PASBackendSync *backend, + PASBook *book, + const char *vcard, + EContact **contact) { - char *id; - char *vcard; - EIterator *iterator; PASBackendFile *bf = PAS_BACKEND_FILE (backend); - id = do_create(backend, req->vcard, &vcard); - if (id) { - for (iterator = e_list_get_iterator(bf->priv->book_views); e_iterator_is_valid(iterator); e_iterator_next(iterator)) { - const PASBackendFileBookView *view = e_iterator_get(iterator); - if (vcard_matches_search (view, vcard)) { - bonobo_object_ref (BONOBO_OBJECT (view->book_view)); - pas_book_view_notify_add_1 (view->book_view, vcard); - pas_book_view_notify_complete (view->book_view, GNOME_Evolution_Addressbook_BookViewListener_Success); - bonobo_object_unref (BONOBO_OBJECT (view->book_view)); - } - } - g_object_unref(iterator); - - pas_book_respond_create ( - book, - GNOME_Evolution_Addressbook_BookListener_Success, - id); - - pas_backend_summary_add_card (bf->priv->summary, vcard); - - g_free(vcard); - g_free(id); + *contact = do_create (bf, vcard); + if (*contact) { + pas_backend_summary_add_contact (bf->priv->summary, *contact); + return GNOME_Evolution_Addressbook_Success; } else { /* XXX need a different call status for this case, i think */ - pas_book_respond_create ( - book, - GNOME_Evolution_Addressbook_BookListener_CardNotFound, - ""); + return GNOME_Evolution_Addressbook_ContactNotFound; } } -static void -pas_backend_file_process_remove_cards (PASBackend *backend, - PASBook *book, - PASRemoveCardsRequest *req) +static PASBackendSyncStatus +pas_backend_file_remove_contacts (PASBackendSync *backend, + PASBook *book, + GList *id_list, + GList **ids) { PASBackendFile *bf = PAS_BACKEND_FILE (backend); DB *db = bf->priv->file_db; DBT id_dbt, vcard_dbt; int db_error; - EIterator *iterator; - const char *id; + char *id; GList *l; GList *removed_cards = NULL; - GNOME_Evolution_Addressbook_BookListener_CallStatus rv = GNOME_Evolution_Addressbook_BookListener_Success; + GNOME_Evolution_Addressbook_CallStatus rv = GNOME_Evolution_Addressbook_Success; - for (l = req->ids; l; l = l->next) { + for (l = id_list; l; l = l->next) { id = l->data; string_to_dbt (id, &id_dbt); @@ -760,17 +336,17 @@ pas_backend_file_process_remove_cards (PASBackend *backend, db_error = db->get (db, NULL, &id_dbt, &vcard_dbt, 0); if (0 != db_error) { - rv = GNOME_Evolution_Addressbook_BookListener_CardNotFound; + rv = GNOME_Evolution_Addressbook_ContactNotFound; continue; } db_error = db->del (db, NULL, &id_dbt, 0); if (0 != db_error) { - rv = GNOME_Evolution_Addressbook_BookListener_CardNotFound; + rv = GNOME_Evolution_Addressbook_ContactNotFound; continue; } - removed_cards = g_list_prepend (removed_cards, e_card_new (vcard_dbt.data)); + removed_cards = g_list_prepend (removed_cards, id); } /* if we actually removed some, try to sync */ @@ -780,53 +356,30 @@ pas_backend_file_process_remove_cards (PASBackend *backend, g_warning ("db->sync failed.\n"); } - for (iterator = e_list_get_iterator (bf->priv->book_views); e_iterator_is_valid(iterator); e_iterator_next(iterator)) { - const PASBackendFileBookView *view = e_iterator_get(iterator); - GList *view_removed = NULL; - for (l = removed_cards; l; l = l->next) { - ECard *removed_card = l->data; - if (ecard_matches_search (view, removed_card)) { - view_removed = g_list_prepend (view_removed, (char*)e_card_get_id (removed_card)); - } - } - if (view_removed) { - bonobo_object_ref (BONOBO_OBJECT (view->book_view)); - pas_book_view_notify_remove (view->book_view, view_removed); - pas_book_view_notify_complete (view->book_view, GNOME_Evolution_Addressbook_BookViewListener_Success); - bonobo_object_unref (BONOBO_OBJECT (view->book_view)); - g_list_free (view_removed); - } - } - g_object_unref(iterator); - - pas_book_respond_remove (book, rv); + *ids = removed_cards; for (l = removed_cards; l; l = l->next) { - ECard *c = l->data; - pas_backend_summary_remove_card (bf->priv->summary, e_card_get_id (c)); - g_object_unref (c); + char *id = l->data; + pas_backend_summary_remove_contact (bf->priv->summary, id); } - g_list_free (removed_cards); + return rv; } -static void -pas_backend_file_process_modify_card (PASBackend *backend, - PASBook *book, - PASModifyCardRequest *req) +static PASBackendSyncStatus +pas_backend_file_modify_contact (PASBackendSync *backend, + PASBook *book, + const char *vcard, + EContact **contact) { PASBackendFile *bf = PAS_BACKEND_FILE (backend); DB *db = bf->priv->file_db; DBT id_dbt, vcard_dbt; int db_error; - EIterator *iterator; - ECard *card; - const char *id, *lookup_id; - char *old_vcard_string; + char *id, *lookup_id; - /* create a new ecard from the request data */ - card = e_card_new(req->vcard); - id = e_card_get_id(card); + *contact = e_contact_new_from_vcard (vcard); + id = e_contact_get(*contact, E_CONTACT_UID); /* This is disgusting, but for a time cards were added with ID's that are no longer used (they contained both the uri @@ -844,15 +397,10 @@ pas_backend_file_process_modify_card (PASBackend *backend, /* get the old ecard - the one that's presently in the db */ db_error = db->get (db, NULL, &id_dbt, &vcard_dbt, 0); - if (0 != db_error) { - pas_book_respond_modify ( - book, - GNOME_Evolution_Addressbook_BookListener_CardNotFound); - return; - } - old_vcard_string = g_strdup(vcard_dbt.data); + if (0 != db_error) + return GNOME_Evolution_Addressbook_ContactNotFound; - string_to_dbt (req->vcard, &vcard_dbt); + string_to_dbt (vcard, &vcard_dbt); db_error = db->put (db, NULL, &id_dbt, &vcard_dbt, 0); @@ -861,55 +409,50 @@ pas_backend_file_process_modify_card (PASBackend *backend, if (db_error != 0) g_warning ("db->sync failed.\n"); - for (iterator = e_list_get_iterator(bf->priv->book_views); e_iterator_is_valid(iterator); e_iterator_next(iterator)) { - CORBA_Environment ev; - const PASBackendFileBookView *view = e_iterator_get(iterator); - gboolean old_match, new_match; - - CORBA_exception_init(&ev); - - bonobo_object_dup_ref(bonobo_object_corba_objref(BONOBO_OBJECT(view->book_view)), &ev); - - old_match = vcard_matches_search (view, old_vcard_string); - new_match = vcard_matches_search (view, req->vcard); - if (old_match && new_match) - pas_book_view_notify_change_1 (view->book_view, req->vcard); - else if (new_match) - pas_book_view_notify_add_1 (view->book_view, req->vcard); - else /* if (old_match) */ - pas_book_view_notify_remove_1 (view->book_view, id); + pas_backend_summary_remove_contact (bf->priv->summary, id); + pas_backend_summary_add_contact (bf->priv->summary, *contact); + } + g_free (id); - pas_book_view_notify_complete (view->book_view, GNOME_Evolution_Addressbook_BookViewListener_Success); + if (0 == db_error) + return GNOME_Evolution_Addressbook_Success; + else + return GNOME_Evolution_Addressbook_ContactNotFound; +} - bonobo_object_release_unref(bonobo_object_corba_objref(BONOBO_OBJECT(view->book_view)), &ev); +static PASBackendSyncStatus +pas_backend_file_get_contact (PASBackendSync *backend, + PASBook *book, + const char *id, + char **vcard) +{ + PASBackendFile *bf; + DB *db; + DBT id_dbt, vcard_dbt; + int db_error = 0; - CORBA_exception_free (&ev); - } + bf = PAS_BACKEND_FILE (pas_book_get_backend (book)); + db = bf->priv->file_db; - g_object_unref(iterator); + string_to_dbt (id, &id_dbt); + memset (&vcard_dbt, 0, sizeof (vcard_dbt)); - pas_book_respond_modify ( - book, - GNOME_Evolution_Addressbook_BookListener_Success); + db_error = db->get (db, NULL, &id_dbt, &vcard_dbt, 0); - pas_backend_summary_remove_card (bf->priv->summary, id); - pas_backend_summary_add_card (bf->priv->summary, req->vcard); - } - else { - pas_book_respond_modify ( - book, - GNOME_Evolution_Addressbook_BookListener_CardNotFound); + if (db_error == 0) { + *vcard = g_strdup (vcard_dbt.data); + return GNOME_Evolution_Addressbook_Success; + } else { + *vcard = g_strdup (""); + return GNOME_Evolution_Addressbook_ContactNotFound; } - - g_free(old_vcard_string); - - g_object_unref(card); } -static void -pas_backend_file_build_cards_list(PASBackend *backend, - PASBackendFileCursorPrivate *cursor_data, - char *search) +static PASBackendSyncStatus +pas_backend_file_get_contact_list (PASBackendSync *backend, + PASBook *book, + const char *query, + GList **contacts) { PASBackendFile *bf = PAS_BACKEND_FILE (backend); DB *db = bf->priv->file_db; @@ -918,8 +461,10 @@ pas_backend_file_build_cards_list(PASBackend *backend, DBT id_dbt, vcard_dbt; PASBackendCardSExp *card_sexp = NULL; gboolean search_needed; - - cursor_data->elements = NULL; + const char *search = query; + GList *contact_list = NULL; + + printf ("pas_backend_file_get_contact_list (%s)\n", search); search_needed = TRUE; @@ -927,14 +472,16 @@ pas_backend_file_build_cards_list(PASBackend *backend, search_needed = FALSE; card_sexp = pas_backend_card_sexp_new (search); - - if (!card_sexp) - g_warning ("pas_backend_file_build_all_cards_list: error building list\n"); + if (!card_sexp) { + /* XXX this needs to be an invalid query error of some sort*/ + return GNOME_Evolution_Addressbook_ContactNotFound; + } db_error = db->cursor (db, NULL, &dbc, 0); if (db_error != 0) { - g_warning ("pas_backend_file_build_all_cards_list: error building list\n"); + /* XXX this needs to be some CouldNotOpen error */ + return GNOME_Evolution_Addressbook_ContactNotFound; } memset (&vcard_dbt, 0, sizeof (vcard_dbt)); @@ -948,7 +495,7 @@ pas_backend_file_build_cards_list(PASBackend *backend, || strcmp (id_dbt.data, PAS_BACKEND_FILE_VERSION_NAME)) { if ((!search_needed) || (card_sexp != NULL && pas_backend_card_sexp_match_vcard (card_sexp, vcard_dbt.data))) { - cursor_data->elements = g_list_prepend (cursor_data->elements, g_strdup (vcard_dbt.data)); + contact_list = g_list_append (contact_list, g_strdup (vcard_dbt.data)); } } @@ -956,274 +503,211 @@ pas_backend_file_build_cards_list(PASBackend *backend, } - if (db_error != DB_NOTFOUND) { - g_warning ("pas_backend_file_build_all_cards_list: error building list\n"); - } - else { - cursor_data->num_elements = g_list_length (cursor_data->elements); - cursor_data->elements = g_list_reverse (cursor_data->elements); - } + *contacts = contact_list; + return db_error != DB_NOTFOUND + ? GNOME_Evolution_Addressbook_OtherError + : GNOME_Evolution_Addressbook_Success; } static void -pas_backend_file_process_get_vcard (PASBackend *backend, - PASBook *book, - PASGetVCardRequest *req) +pas_backend_file_start_book_view (PASBackend *backend, + PASBookView *book_view) { - PASBackendFile *bf; - DB *db; - DBT id_dbt, vcard_dbt; - int db_error = 0; - char *card; - GNOME_Evolution_Addressbook_BookListener_CallStatus status; - - bf = PAS_BACKEND_FILE (pas_book_get_backend (book)); - db = bf->priv->file_db; - - string_to_dbt (req->id, &id_dbt); - memset (&vcard_dbt, 0, sizeof (vcard_dbt)); - - db_error = db->get (db, NULL, &id_dbt, &vcard_dbt, 0); + pas_backend_file_search (PAS_BACKEND_FILE (backend), book_view); +} - if (db_error == 0) { - card = vcard_dbt.data; - status = GNOME_Evolution_Addressbook_BookListener_Success; - } else { - card = ""; - status = GNOME_Evolution_Addressbook_BookListener_CardNotFound; - } +typedef struct { + DB *db; - pas_book_respond_get_vcard (book, - status, - card); -} + GList *add_cards; + GList *add_ids; + GList *mod_cards; + GList *mod_ids; + GList *del_ids; +} PASBackendFileChangeContext; static void -pas_backend_file_process_get_cursor (PASBackend *backend, - PASBook *book, - PASGetCursorRequest *req) +pas_backend_file_changes_foreach_key (const char *key, gpointer user_data) { - /* - PASBackendFile *bf = PAS_BACKEND_FILE (backend); - DB *db = bf->priv->file_db; - DBT id_dbt, vcard_dbt; - */ - CORBA_Environment ev; - int db_error = 0; - PASBackendFileCursorPrivate *cursor_data; - PASCardCursor *cursor; - GNOME_Evolution_Addressbook_Book corba_book; - - cursor_data = g_new(PASBackendFileCursorPrivate, 1); - cursor_data->backend = backend; - cursor_data->book = book; - - pas_backend_file_build_cards_list(backend, cursor_data, req->search); - - corba_book = bonobo_object_corba_objref(BONOBO_OBJECT(book)); - - CORBA_exception_init(&ev); - - GNOME_Evolution_Addressbook_Book_ref(corba_book, &ev); + PASBackendFileChangeContext *ctx = user_data; + DB *db = ctx->db; + DBT id_dbt, vcard_dbt; + int db_error = 0; - if (ev._major != CORBA_NO_EXCEPTION) { - g_warning("pas_backend_file_process_get_cursor: Exception reffing " - "corba book.\n"); - } - - CORBA_exception_free(&ev); + string_to_dbt (key, &id_dbt); + memset (&vcard_dbt, 0, sizeof (vcard_dbt)); + db_error = db->get (db, NULL, &id_dbt, &vcard_dbt, 0); - cursor = pas_card_cursor_new(get_length, - get_nth, - cursor_data); + if (db_error != 0) { + char *id = id_dbt.data; - g_object_weak_ref (G_OBJECT (cursor), - cursor_destroy, cursor_data); - - pas_book_respond_get_cursor ( - book, - (db_error == 0 - ? GNOME_Evolution_Addressbook_BookListener_Success - : GNOME_Evolution_Addressbook_BookListener_CardNotFound), - cursor); + ctx->del_ids = g_list_append (ctx->del_ids, + g_strdup (id)); + } } -static void -pas_backend_file_process_get_book_view (PASBackend *backend, - PASBook *book, - PASGetBookViewRequest *req) +static PASBackendSyncStatus +pas_backend_file_get_changes (PASBackendSync *backend, + PASBook *book, + const char *change_id, + GList **changes_out) { PASBackendFile *bf = PAS_BACKEND_FILE (backend); - PASBookView *book_view; - PASBackendFileBookView view; - EIterator *iterator; - - bonobo_object_ref(BONOBO_OBJECT(book)); - - book_view = pas_book_view_new (req->listener); - - g_object_weak_ref (G_OBJECT (book_view), view_destroy, book); - - view.book_view = book_view; - view.search = g_strdup (req->search); - view.card_sexp = NULL; - view.change_id = NULL; - view.change_context = NULL; - - e_list_append(bf->priv->book_views, &view); - - pas_book_respond_get_book_view (book, - (book_view != NULL - ? GNOME_Evolution_Addressbook_BookListener_Success - : GNOME_Evolution_Addressbook_BookListener_CardNotFound /* XXX */), - book_view); - - if (!pas_backend_is_loaded (backend)) - return; + int db_error = 0; + DBT id_dbt, vcard_dbt; + char *filename; + EDbHash *ehash; + GList *i, *v; + DB *db = bf->priv->file_db; + DBC *dbc; + GList *changes = NULL; + PASBackendFileChangeContext ctx; + PASBackendSyncStatus result; - iterator = e_list_get_iterator(bf->priv->book_views); - e_iterator_last(iterator); - pas_backend_file_search (bf, book, e_iterator_get(iterator), FALSE); - g_object_unref(iterator); -} + memset (&id_dbt, 0, sizeof (id_dbt)); + memset (&vcard_dbt, 0, sizeof (vcard_dbt)); -static void -pas_backend_file_process_get_completion_view (PASBackend *backend, - PASBook *book, - PASGetCompletionViewRequest *req) -{ - PASBackendFile *bf = PAS_BACKEND_FILE (backend); - PASBookView *book_view; - PASBackendFileBookView view; - EIterator *iterator; + memset (&ctx, 0, sizeof (ctx)); - bonobo_object_ref(BONOBO_OBJECT(book)); + ctx.db = db; - book_view = pas_book_view_new (req->listener); + /* Find the changed ids */ + filename = g_strdup_printf ("%s/%s" CHANGES_DB_SUFFIX, bf->priv->dirname, change_id); + ehash = e_dbhash_new (filename); + g_free (filename); - g_object_weak_ref (G_OBJECT (book_view), view_destroy, book); + db_error = db->cursor (db, NULL, &dbc, 0); - view.book_view = book_view; - view.search = g_strdup (req->search); - view.card_sexp = NULL; - view.change_id = NULL; - view.change_context = NULL; + if (db_error != 0) { + g_warning ("pas_backend_file_changes: error building list\n"); + } else { + db_error = dbc->c_get(dbc, &id_dbt, &vcard_dbt, DB_FIRST); - e_list_append(bf->priv->book_views, &view); + while (db_error == 0) { - pas_book_respond_get_completion_view (book, - (book_view != NULL - ? GNOME_Evolution_Addressbook_BookListener_Success - : GNOME_Evolution_Addressbook_BookListener_CardNotFound /* XXX */), - book_view); + /* don't include the version in the list of cards */ + if (id_dbt.size != strlen(PAS_BACKEND_FILE_VERSION_NAME) + 1 + || strcmp (id_dbt.data, PAS_BACKEND_FILE_VERSION_NAME)) { + EContact *contact; + char *id = id_dbt.data; + char *vcard_string; + + /* Remove fields the user can't change + * and can change without the rest of the + * card changing + */ + contact = e_contact_new_from_vcard (vcard_dbt.data); +#if notyet + g_object_set (card, "last_use", NULL, "use_score", 0.0, NULL); +#endif + vcard_string = e_vcard_to_string (E_VCARD (contact), EVC_FORMAT_VCARD_30); + g_object_unref (contact); + + /* check what type of change has occurred, if any */ + switch (e_dbhash_compare (ehash, id, vcard_string)) { + case E_DBHASH_STATUS_SAME: + break; + case E_DBHASH_STATUS_NOT_FOUND: + ctx.add_cards = g_list_append (ctx.add_cards, vcard_string); + ctx.add_ids = g_list_append (ctx.add_ids, g_strdup(id)); + break; + case E_DBHASH_STATUS_DIFFERENT: + ctx.mod_cards = g_list_append (ctx.mod_cards, vcard_string); + ctx.mod_ids = g_list_append (ctx.mod_ids, g_strdup(id)); + break; + } + } - if (!pas_backend_is_loaded (backend)) - return; + db_error = dbc->c_get(dbc, &id_dbt, &vcard_dbt, DB_NEXT); + } + dbc->c_close (dbc); + } - iterator = e_list_get_iterator(bf->priv->book_views); - e_iterator_last(iterator); - pas_backend_file_search (bf, book, e_iterator_get(iterator), TRUE); - g_object_unref(iterator); -} + e_dbhash_foreach_key (ehash, (EDbHashFunc)pas_backend_file_changes_foreach_key, &ctx); -static void -pas_backend_file_process_get_changes (PASBackend *backend, - PASBook *book, - PASGetChangesRequest *req) -{ - PASBackendFile *bf = PAS_BACKEND_FILE (backend); - PASBookView *book_view; - PASBackendFileBookView view; - PASBackendFileChangeContext ctx; - EIterator *iterator; - - bonobo_object_ref(BONOBO_OBJECT(book)); - - book_view = pas_book_view_new (req->listener); - - g_object_weak_ref (G_OBJECT (book_view), view_destroy, book); - - pas_book_respond_get_changes (book, - (book_view != NULL - ? GNOME_Evolution_Addressbook_BookListener_Success - : GNOME_Evolution_Addressbook_BookListener_CardNotFound /* XXX */), - book_view); - - view.book_view = book_view; - view.change_id = req->change_id; - view.change_context = &ctx; - ctx.db = bf->priv->file_db; - ctx.add_cards = NULL; - ctx.add_ids = NULL; - ctx.mod_cards = NULL; - ctx.mod_ids = NULL; - ctx.del_ids = NULL; - view.search = NULL; - view.card_sexp = NULL; - - e_list_append(bf->priv->book_views, &view); + /* Send the changes */ + if (db_error != DB_NOTFOUND) { + g_warning ("pas_backend_file_changes: error building list\n"); + *changes_out = NULL; + result = GNOME_Evolution_Addressbook_OtherError; + } + else { + /* Update the hash and build our changes list */ + for (i = ctx.add_ids, v = ctx.add_cards; i != NULL; i = i->next, v = v->next){ + char *id = i->data; + char *vcard = v->data; + + e_dbhash_add (ehash, id, vcard); + changes = g_list_prepend (changes, + pas_backend_change_add_new (vcard)); + + g_free (i->data); + g_free (v->data); + } + for (i = ctx.mod_ids, v = ctx.mod_cards; i != NULL; i = i->next, v = v->next){ + char *id = i->data; + char *vcard = v->data; + + e_dbhash_add (ehash, id, vcard); + changes = g_list_prepend (changes, + pas_backend_change_modify_new (vcard)); + + g_free (i->data); + g_free (v->data); + } + for (i = ctx.del_ids; i != NULL; i = i->next){ + char *id = i->data; + + e_dbhash_remove (ehash, id); + changes = g_list_prepend (changes, + pas_backend_change_delete_new (id)); + g_free (i->data); + } - if (!pas_backend_is_loaded (backend)) - return; + e_dbhash_write (ehash); - iterator = e_list_get_iterator(bf->priv->book_views); - e_iterator_last(iterator); - pas_backend_file_changes (bf, book, e_iterator_get(iterator)); - g_object_unref(iterator); -} + result = GNOME_Evolution_Addressbook_Success; + *changes_out = changes; + } -static void -pas_backend_file_process_check_connection (PASBackend *backend, - PASBook *book, - PASCheckConnectionRequest *req) -{ - PASBackendFile *bf = PAS_BACKEND_FILE (backend); + e_dbhash_destroy (ehash); - pas_book_report_connection (book, bf->priv->file_db != NULL); + return GNOME_Evolution_Addressbook_Success; } static char * pas_backend_file_extract_path_from_uri (const char *uri) { - g_assert (strncasecmp (uri, "file:", 5) == 0); + g_assert (strncasecmp (uri, "file://", 7) == 0); - return g_strdup (uri + 5); + return g_strdup (uri + 7); } -static void -pas_backend_file_process_authenticate_user (PASBackend *backend, - PASBook *book, - PASAuthenticateUserRequest *req) +static PASBackendSyncStatus +pas_backend_file_authenticate_user (PASBackendSync *backend, + PASBook *book, + const char *user, + const char *passwd, + const char *auth_method) { - pas_book_respond_authenticate_user (book, - GNOME_Evolution_Addressbook_BookListener_Success); + return GNOME_Evolution_Addressbook_Success; } -static void -pas_backend_file_process_get_supported_fields (PASBackend *backend, - PASBook *book, - PASGetSupportedFieldsRequest *req) +static PASBackendSyncStatus +pas_backend_file_get_supported_fields (PASBackendSync *backend, + PASBook *book, + GList **fields_out) { - EList *fields = e_list_new ((EListCopyFunc)g_strdup, (EListFreeFunc)g_free, NULL); - ECardSimple *simple; - ECard *card; + GList *fields = NULL; int i; - /* we support everything, so instantiate an e-card, and loop - through all fields, adding their ecard_fields. */ + /* XXX we need a way to say "we support everything", since the + file backend does */ + for (i = 1; i < E_CONTACT_FIELD_LAST; i ++) + fields = g_list_append (fields, g_strdup (e_contact_field_name (i))); - card = e_card_new (""); - simple = e_card_simple_new (card); - - for (i = 0; i < E_CARD_SIMPLE_FIELD_LAST; i ++) - e_list_append (fields, e_card_simple_get_ecard_field (simple, i)); - - g_object_unref (card); - g_object_unref (simple); - - pas_book_respond_get_supported_fields (book, - GNOME_Evolution_Addressbook_BookListener_Success, - fields); + *fields_out = fields; + return GNOME_Evolution_Addressbook_Success; } /* @@ -1273,9 +757,9 @@ pas_backend_file_upgrade_db (PASBackendFile *bf, char *old_version) while (db_error == 0) { if (id_dbt.size != strlen(PAS_BACKEND_FILE_VERSION_NAME) + 1 || strcmp (id_dbt.data, PAS_BACKEND_FILE_VERSION_NAME)) { - ECard *card; + EContact *contact; - card = e_card_new (vcard_dbt.data); + contact = e_contact_new_from_vcard (vcard_dbt.data); /* the cards we're looking for are created with a normal id dbt, but @@ -1283,12 +767,12 @@ pas_backend_file_upgrade_db (PASBackendFile *bf, char *old_version) to something that doesn't match. so, we need to modify the card to have the same id as the the dbt. */ - if (strcmp (id_dbt.data, e_card_get_id (card))) { + if (strcmp (id_dbt.data, e_contact_get_const (contact, E_CONTACT_UID))) { char *vcard; - e_card_set_id (card, id_dbt.data); + e_contact_set (contact, E_CONTACT_UID, id_dbt.data); - vcard = e_card_get_vcard (card); + vcard = e_vcard_to_string (E_VCARD (contact), EVC_FORMAT_VCARD_30); string_to_dbt (vcard, &vcard_dbt); db_error = db->put (db, NULL, @@ -1300,7 +784,7 @@ pas_backend_file_upgrade_db (PASBackendFile *bf, char *old_version) card_failed++; } - g_object_unref (card); + g_object_unref (contact); } db_error = dbc->c_get(dbc, &id_dbt, &vcard_dbt, DB_NEXT); @@ -1352,30 +836,21 @@ pas_backend_file_maybe_upgrade_db (PASBackendFile *bf) return ret_val; } -#define INITIAL_VCARD "BEGIN:VCARD\n\ -X-EVOLUTION-FILE-AS:Ximian, Inc.\n\ -LABEL;WORK;QUOTED-PRINTABLE:401 Park Drive 3 West=0ABoston, MA 02215=0AUSA\n\ -TEL;WORK;VOICE:(617) 375-3800\n\ -TEL;WORK;FAX:(617) 236-8630\n\ -EMAIL;INTERNET:hello@ximian.com\n\ -URL:www.ximian.com/\n\ -ORG:Ximian, Inc.;\n\ -NOTE:Welcome to the Ximian Addressbook.\n\ -END:VCARD" - -static GNOME_Evolution_Addressbook_BookListener_CallStatus +#include "ximian-vcard.h" + +static GNOME_Evolution_Addressbook_CallStatus pas_backend_file_load_uri (PASBackend *backend, - const char *uri) + const char *uri, + gboolean only_if_exists) { PASBackendFile *bf = PAS_BACKEND_FILE (backend); - char *filename; + char *dirname, *filename; gboolean writable = FALSE; int db_error; DB *db; int major, minor, patch; time_t db_mtime; struct stat sb; - char *summary_filename; g_free(bf->priv->uri); bf->priv->uri = g_strdup (uri); @@ -1386,18 +861,19 @@ pas_backend_file_load_uri (PASBackend *backend, minor != 1 || patch != 17) { g_warning ("Wrong version of libdb."); - return GNOME_Evolution_Addressbook_BookListener_OtherError; + return GNOME_Evolution_Addressbook_OtherError; } - filename = pas_backend_file_extract_path_from_uri (uri); + dirname = pas_backend_file_extract_path_from_uri (uri); + filename = g_build_filename (dirname, "addressbook.db", NULL); db_error = e_db3_utils_maybe_recover (filename); if (db_error != 0) - return GNOME_Evolution_Addressbook_BookListener_OtherError; + return GNOME_Evolution_Addressbook_OtherError; db_error = db_create (&db, NULL, 0); if (db_error != 0) - return GNOME_Evolution_Addressbook_BookListener_OtherError; + return GNOME_Evolution_Addressbook_OtherError; db_error = db->open (db, filename, NULL, DB_HASH, 0, 0666); @@ -1405,7 +881,7 @@ pas_backend_file_load_uri (PASBackend *backend, db_error = e_db3_utils_upgrade_format (filename); if (db_error != 0) - return GNOME_Evolution_Addressbook_BookListener_OtherError; + return GNOME_Evolution_Addressbook_OtherError; db_error = db->open (db, filename, NULL, DB_HASH, 0, 0666); } @@ -1418,23 +894,27 @@ pas_backend_file_load_uri (PASBackend *backend, db_error = db->open (db, filename, NULL, DB_HASH, DB_RDONLY, 0666); if (db_error != 0) { - db_error = db->open (db, filename, NULL, DB_HASH, DB_CREATE, 0666); - - if (db_error == 0) { - char *create_initial_file; - char *dir; + int rv; + + /* the database didn't exist, so we create the + directory then the .db */ + rv = mkdir (dirname, 0777); + if (rv == -1 && errno != EEXIST) { + g_warning ("failed to make directory %s: %s", dirname, strerror (errno)); + if (errno == EACCES || errno == EPERM) + return GNOME_Evolution_Addressbook_PermissionDenied; + else + return GNOME_Evolution_Addressbook_OtherError; + } - dir = g_path_get_dirname(filename); - create_initial_file = g_build_filename (dir, "create-initial", NULL); + db_error = db->open (db, filename, NULL, DB_HASH, DB_CREATE, 0666); - if (g_file_test(create_initial_file, G_FILE_TEST_EXISTS)) { - char *id; - id = do_create(backend, INITIAL_VCARD, NULL); - g_free (id); - } + if (db_error == 0 && !only_if_exists) { + EContact *contact; - g_free(create_initial_file); - g_free(dir); + contact = do_create(bf, XIMIAN_VCARD); + /* XXX check errors here */ + g_object_unref (contact); writable = TRUE; } @@ -1443,28 +923,30 @@ pas_backend_file_load_uri (PASBackend *backend, if (db_error != 0) { bf->priv->file_db = NULL; - return GNOME_Evolution_Addressbook_BookListener_OtherError; + return GNOME_Evolution_Addressbook_OtherError; } if (!pas_backend_file_maybe_upgrade_db (bf)) { db->close (db, 0); bf->priv->file_db = NULL; - return GNOME_Evolution_Addressbook_BookListener_OtherError; + return GNOME_Evolution_Addressbook_OtherError; } + g_free (bf->priv->dirname); g_free (bf->priv->filename); + bf->priv->dirname = dirname; bf->priv->filename = filename; if (stat (bf->priv->filename, &sb) == -1) { db->close (db, 0); bf->priv->file_db = NULL; - return GNOME_Evolution_Addressbook_BookListener_OtherError; + return GNOME_Evolution_Addressbook_OtherError; } db_mtime = sb.st_mtime; - summary_filename = g_strconcat (bf->priv->filename, ".summary", NULL); - bf->priv->summary = pas_backend_summary_new (summary_filename, SUMMARY_FLUSH_TIMEOUT); - g_free (summary_filename); + g_free (bf->priv->summary_filename); + bf->priv->summary_filename = g_strconcat (bf->priv->filename, ".summary", NULL); + bf->priv->summary = pas_backend_summary_new (bf->priv->summary_filename, SUMMARY_FLUSH_TIMEOUT); if (pas_backend_summary_is_up_to_date (bf->priv->summary, db_mtime) == FALSE || pas_backend_summary_load (bf->priv->summary) == FALSE ) { @@ -1473,20 +955,76 @@ pas_backend_file_load_uri (PASBackend *backend, pas_backend_set_is_loaded (backend, TRUE); pas_backend_set_is_writable (backend, writable); - return GNOME_Evolution_Addressbook_BookListener_Success; + + return GNOME_Evolution_Addressbook_Success; } -/* Get_uri handler for the addressbook file backend */ -static const char * -pas_backend_file_get_uri (PASBackend *backend) +static int +select_changes (const struct dirent *d) { - PASBackendFile *bf; + char *p; + + if (strlen (d->d_name) < strlen (CHANGES_DB_SUFFIX)) + return 0; + + p = strstr (d->d_name, CHANGES_DB_SUFFIX); + if (!p) + return 0; + + if (strlen (p) != strlen (CHANGES_DB_SUFFIX)) + return 0; + + return 1; +} + +static PASBackendSyncStatus +pas_backend_file_remove (PASBackendSync *backend, + PASBook *book) +{ + PASBackendFile *bf = PAS_BACKEND_FILE (backend); + struct dirent **namelist; + int n; + + if (-1 == unlink (bf->priv->filename)) { + if (errno == EACCES || errno == EPERM) + return GNOME_Evolution_Addressbook_PermissionDenied; + else + return GNOME_Evolution_Addressbook_OtherError; + } - bf = PAS_BACKEND_FILE (backend); + /* 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 == unlink (bf->priv->filename)) + g_warning ("failed to remove summary file `%s`: %s", bf->priv->summary_filename, strerror (errno)); + + /* scandir to select all the "*.changes.db" files, then remove them */ + n = scandir (bf->priv->dirname, + &namelist, select_changes, alphasort); + if (n < 0) { + g_warning ("scandir of directory `%s' failed: %s", bf->priv->dirname, strerror (errno)); + } + else { + while (n -- ) { + char *full_path = g_build_filename (bf->priv->dirname, namelist[n]->d_name, NULL); + if (-1 == unlink (full_path)) { + g_warning ("failed to remove change db `%s': %s", full_path, strerror (errno)); + } + g_free (full_path); + free (namelist[n]); + } + free (namelist); + } - g_assert (bf->priv->uri != NULL); + if (-1 == rmdir (bf->priv->dirname)) + g_warning ("failed to remove directory `%s`: %s", bf->priv->dirname, strerror (errno)); - return bf->priv->uri; + /* we may not have actually succeeded in removing the + backend's files/dirs, but there's nothing we can do about + it here.. the only time we should return failure is if we + failed to remove the actual data. a failure should mean + that the addressbook is still valid */ + return GNOME_Evolution_Addressbook_Success; } static char * @@ -1495,6 +1033,12 @@ pas_backend_file_get_static_capabilities (PASBackend *backend) return g_strdup("local,do-initial-query,bulk-removes"); } +static GNOME_Evolution_Addressbook_CallStatus +pas_backend_file_cancel_operation (PASBackend *backend, PASBook *book) +{ + return GNOME_Evolution_Addressbook_CouldNotCancel; +} + static gboolean pas_backend_file_construct (PASBackendFile *backend) { @@ -1534,11 +1078,12 @@ pas_backend_file_dispose (GObject *object) bf = PAS_BACKEND_FILE (object); if (bf->priv) { - g_object_unref(bf->priv->book_views); if (bf->priv->summary) g_object_unref(bf->priv->summary); g_free (bf->priv->uri); g_free (bf->priv->filename); + g_free (bf->priv->dirname); + g_free (bf->priv->summary_filename); g_free (bf->priv); bf->priv = NULL; @@ -1551,28 +1096,29 @@ static void pas_backend_file_class_init (PASBackendFileClass *klass) { GObjectClass *object_class = G_OBJECT_CLASS (klass); - PASBackendClass *parent_class; + PASBackendSyncClass *sync_class; + PASBackendClass *backend_class; pas_backend_file_parent_class = g_type_class_peek_parent (klass); - parent_class = PAS_BACKEND_CLASS (klass); + sync_class = PAS_BACKEND_SYNC_CLASS (klass); + backend_class = PAS_BACKEND_CLASS (klass); /* Set the virtual methods. */ - parent_class->load_uri = pas_backend_file_load_uri; - parent_class->get_uri = pas_backend_file_get_uri; - parent_class->get_static_capabilities = pas_backend_file_get_static_capabilities; - - parent_class->create_card = pas_backend_file_process_create_card; - parent_class->remove_cards = pas_backend_file_process_remove_cards; - parent_class->modify_card = pas_backend_file_process_modify_card; - parent_class->check_connection = pas_backend_file_process_check_connection; - parent_class->get_vcard = pas_backend_file_process_get_vcard; - parent_class->get_cursor = pas_backend_file_process_get_cursor; - parent_class->get_book_view = pas_backend_file_process_get_book_view; - parent_class->get_completion_view = pas_backend_file_process_get_completion_view; - parent_class->get_changes = pas_backend_file_process_get_changes; - parent_class->authenticate_user = pas_backend_file_process_authenticate_user; - parent_class->get_supported_fields = pas_backend_file_process_get_supported_fields; + backend_class->load_uri = pas_backend_file_load_uri; + backend_class->get_static_capabilities = pas_backend_file_get_static_capabilities; + backend_class->start_book_view = pas_backend_file_start_book_view; + backend_class->cancel_operation = pas_backend_file_cancel_operation; + + sync_class->remove_sync = pas_backend_file_remove; + sync_class->create_contact_sync = pas_backend_file_create_contact; + sync_class->remove_contacts_sync = pas_backend_file_remove_contacts; + sync_class->modify_contact_sync = pas_backend_file_modify_contact; + sync_class->get_contact_sync = pas_backend_file_get_contact; + sync_class->get_contact_list_sync = pas_backend_file_get_contact_list; + sync_class->get_changes_sync = pas_backend_file_get_changes; + sync_class->authenticate_user_sync = pas_backend_file_authenticate_user; + sync_class->get_supported_fields_sync = pas_backend_file_get_supported_fields; object_class->dispose = pas_backend_file_dispose; } @@ -1583,7 +1129,6 @@ pas_backend_file_init (PASBackendFile *backend) PASBackendFilePrivate *priv; priv = g_new0 (PASBackendFilePrivate, 1); - priv->book_views = e_list_new((EListCopyFunc) pas_backend_file_book_view_copy, (EListFreeFunc) pas_backend_file_book_view_free, NULL); priv->uri = NULL; backend->priv = priv; @@ -1610,7 +1155,7 @@ pas_backend_file_get_type (void) (GInstanceInitFunc) pas_backend_file_init }; - type = g_type_register_static (PAS_TYPE_BACKEND, "PASBackendFile", &info, 0); + type = g_type_register_static (PAS_TYPE_BACKEND_SYNC, "PASBackendFile", &info, 0); } return type; -- cgit v1.2.3