From 35624a9226fbb36f075ed40d1a61369f73570252 Mon Sep 17 00:00:00 2001 From: Chris Toshok Date: Wed, 10 Jul 2002 08:47:11 +0000 Subject: add Book.getCompletionView. 2002-07-10 Chris Toshok * backend/idl/addressbook.idl: add Book.getCompletionView. * backend/ebook/e-book.c (e_book_get_completion_view): new function, basically c&p of e_book_get_book_view, but call getCompletionView. * backend/ebook/e-book.h: add prototype for e_book_get_completion_view. * backend/pas/pas-backend-ldap.c (pas_backend_ldap_process_client_requests): add a GetCompletionView case here that just calls the same code as GetBookView (since we don't build summaries for the ldap backend.) * backend/pas/pas-backend-file.c (do_summary_query): add @completion_search. If it's TRUE, just create the vcards from the summary using pas_backend_summary_get_summary_vcard instead of looking them up from the db. (pas_backend_file_search): add @completion_search and pass it on to do_summary_query. (pas_backend_file_process_get_book_view): pass FALSE to pas_backend_file_search. (pas_backend_file_process_get_completion_view): new function, basically c&p pas_backend_file_process_get_book_view, but pass TRUE to pas_backend_file_search. (pas_backend_file_process_client_requests): add a case for GetCompletionView. (pas_backend_file_load_uri): track the change to the summary api - create the summary filename * backend/pas/pas-book.c (pas_book_queue_get_completion_view): new function, queue a GetCompletionView request to our queue. (impl_GNOME_Evolution_Addressbook_Book_getCompletionView): new function, call pas_book_queue_get_completion_view. (pas_book_respond_get_completion_view): new function, just call notifyViewRequested. (pas_book_free_request): add a case for GetCompletionView. (pas_book_get_epv): fill in epv->getCompletionView. * backend/pas/pas-book.h: add a GetCompletionView PASOperation, and a new structure (PASGetCompletionViewRequest). Also, add get_completion_view to PASRequest. * backend/pas/pas-backend-summary.c (clear_items): remove the items from the hash table. (pas_backend_summary_new): db_path -> summary_path. (pas_backend_summary_destroy): db_.path -> summary_path, and destroy the hash table. (pas_backend_summary_init): db_path = summary_path, and initialize the id_to_item hashtable. (pas_backend_summary_load_header): handle the upgrading from version 1.0 to version 2.0 (the addition of an mtime field in the header) (pas_backend_summary_load_item): version 1.0 and 2.0 have the same format for items. (pas_backend_summary_open): new function. open the summary so we can load the header (and get the mtime). (pas_backend_summary_load): rework this a bit since the header has already been loaded, and also add the items to the hashtable. (pas_backend_summary_add_card): add the new item to the hashtable. (pas_backend_summary_remove_card): remove the item from the hash table. (pas_backend_summary_is_up_to_date): new function, chekc @t against the summary's mtime. (pas_backend_summary_get_summary_vcard): create a vcard from the fields we have in the summary. * backend/pas/pas-backend-summary.h: add prorotypes for pas_backend_summary_is_up_to_date and pas_backend_summary_get_summary_vcard. svn path=/trunk/; revision=17402 --- addressbook/ChangeLog | 73 +++++++++ addressbook/backend/ebook/e-book.c | 41 +++++ addressbook/backend/ebook/e-book.h | 5 + addressbook/backend/idl/addressbook.idl | 10 ++ addressbook/backend/pas/pas-backend-file.c | 97 +++++++++-- addressbook/backend/pas/pas-backend-ldap.c | 5 + addressbook/backend/pas/pas-backend-summary.c | 223 +++++++++++++++++--------- addressbook/backend/pas/pas-backend-summary.h | 21 ++- addressbook/backend/pas/pas-book.c | 73 +++++++++ addressbook/backend/pas/pas-book.h | 33 ++-- 10 files changed, 471 insertions(+), 110 deletions(-) diff --git a/addressbook/ChangeLog b/addressbook/ChangeLog index 343c9a394b..001132267e 100644 --- a/addressbook/ChangeLog +++ b/addressbook/ChangeLog @@ -1,3 +1,76 @@ +2002-07-10 Chris Toshok + + * backend/idl/addressbook.idl: add Book.getCompletionView. + + * backend/ebook/e-book.c (e_book_get_completion_view): new + function, basically c&p of e_book_get_book_view, but call + getCompletionView. + + * backend/ebook/e-book.h: add prototype for + e_book_get_completion_view. + + * backend/pas/pas-backend-ldap.c + (pas_backend_ldap_process_client_requests): add a + GetCompletionView case here that just calls the same code as + GetBookView (since we don't build summaries for the ldap backend.) + + * backend/pas/pas-backend-file.c (do_summary_query): add + @completion_search. If it's TRUE, just create the vcards from the + summary using pas_backend_summary_get_summary_vcard instead of + looking them up from the db. + (pas_backend_file_search): add @completion_search and pass it on + to do_summary_query. + (pas_backend_file_process_get_book_view): pass FALSE to + pas_backend_file_search. + (pas_backend_file_process_get_completion_view): new function, + basically c&p pas_backend_file_process_get_book_view, but pass + TRUE to pas_backend_file_search. + (pas_backend_file_process_client_requests): add a case for + GetCompletionView. + (pas_backend_file_load_uri): track the change to the summary api - + create the summary filename + + * backend/pas/pas-book.c (pas_book_queue_get_completion_view): new + function, queue a GetCompletionView request to our queue. + (impl_GNOME_Evolution_Addressbook_Book_getCompletionView): new + function, call pas_book_queue_get_completion_view. + (pas_book_respond_get_completion_view): new function, just call + notifyViewRequested. + (pas_book_free_request): add a case for GetCompletionView. + (pas_book_get_epv): fill in epv->getCompletionView. + + * backend/pas/pas-book.h: add a GetCompletionView PASOperation, + and a new structure (PASGetCompletionViewRequest). Also, add + get_completion_view to PASRequest. + + * backend/pas/pas-backend-summary.c (clear_items): remove the + items from the hash table. + (pas_backend_summary_new): db_path -> summary_path. + (pas_backend_summary_destroy): db_.path -> summary_path, and + destroy the hash table. + (pas_backend_summary_init): db_path = summary_path, and initialize + the id_to_item hashtable. + (pas_backend_summary_load_header): handle the upgrading from + version 1.0 to version 2.0 (the addition of an mtime field in the + header) + (pas_backend_summary_load_item): version 1.0 and 2.0 have the same + format for items. + (pas_backend_summary_open): new function. open the summary so we + can load the header (and get the mtime). + (pas_backend_summary_load): rework this a bit since the header has + already been loaded, and also add the items to the hashtable. + (pas_backend_summary_add_card): add the new item to the hashtable. + (pas_backend_summary_remove_card): remove the item from the hash + table. + (pas_backend_summary_is_up_to_date): new function, chekc @t + against the summary's mtime. + (pas_backend_summary_get_summary_vcard): create a vcard from the + fields we have in the summary. + + * backend/pas/pas-backend-summary.h: add prorotypes for + pas_backend_summary_is_up_to_date and + pas_backend_summary_get_summary_vcard. + 2002-07-09 Ettore Perazzoli * gui/component/addressbook-storage.c (load_source_data): Pass diff --git a/addressbook/backend/ebook/e-book.c b/addressbook/backend/ebook/e-book.c index ca9faff929..3fa0852dc4 100644 --- a/addressbook/backend/ebook/e-book.c +++ b/addressbook/backend/ebook/e-book.c @@ -1305,6 +1305,47 @@ e_book_get_book_view (EBook *book, return tag; } +guint +e_book_get_completion_view (EBook *book, + const gchar *query, + EBookBookViewCallback cb, + gpointer closure) +{ + CORBA_Environment ev; + EBookViewListener *listener; + guint tag; + + g_return_val_if_fail (book != NULL, 0); + g_return_val_if_fail (E_IS_BOOK (book), 0); + + if (book->priv->load_state != URILoaded) { + g_warning ("e_book_get_completion_view: No URI loaded!\n"); + return 0; + } + + listener = e_book_view_listener_new(); + + CORBA_exception_init (&ev); + + tag = e_book_queue_op (book, cb, closure, listener); + + GNOME_Evolution_Addressbook_Book_getCompletionView (book->priv->corba_book, + bonobo_object_corba_objref(BONOBO_OBJECT(listener)), + query, &ev); + + if (ev._major != CORBA_NO_EXCEPTION) { + g_warning ("e_book_get_completion_view: Exception " + "getting completion_view!\n"); + CORBA_exception_free (&ev); + e_book_unqueue_op (book); + return 0; + } + + CORBA_exception_free (&ev); + + return tag; +} + guint e_book_get_changes (EBook *book, gchar *changeid, diff --git a/addressbook/backend/ebook/e-book.h b/addressbook/backend/ebook/e-book.h index 1403a23f60..b1549f4f8e 100644 --- a/addressbook/backend/ebook/e-book.h +++ b/addressbook/backend/ebook/e-book.h @@ -126,6 +126,11 @@ guint e_book_get_book_view (EBook *book, EBookBookViewCallback cb, gpointer closure); +guint e_book_get_completion_view (EBook *book, + const gchar *query, + EBookBookViewCallback cb, + gpointer closure); + guint e_book_get_changes (EBook *book, char *changeid, EBookBookViewCallback cb, diff --git a/addressbook/backend/idl/addressbook.idl b/addressbook/backend/idl/addressbook.idl index f708026424..1d597189c5 100644 --- a/addressbook/backend/idl/addressbook.idl +++ b/addressbook/backend/idl/addressbook.idl @@ -77,6 +77,16 @@ module Addressbook { void getChanges (in BookViewListener listener, in string change_id); + /* + * This function returns a book view that is identical + * to a normal book view, except in one way - The only + * values reflected in the cards that are transfered + * back are: File As, family name, given name, email + * addresses, and nickname. It is intended for use in + * completion searches. + */ + void getCompletionView (in BookViewListener listener, in string query); + void checkConnection (); void getSupportedFields (); diff --git a/addressbook/backend/pas/pas-backend-file.c b/addressbook/backend/pas/pas-backend-file.c index a6216cf98e..329b919e7d 100644 --- a/addressbook/backend/pas/pas-backend-file.c +++ b/addressbook/backend/pas/pas-backend-file.c @@ -14,6 +14,7 @@ #include #include #include +#include #include #include @@ -131,8 +132,9 @@ build_summary (PASBackendFilePrivate *bfpriv) } static void -do_summary_query (PASBackendFile *bf, - PASBackendFileBookView *view) +do_summary_query (PASBackendFile *bf, + PASBackendFileBookView *view, + gboolean completion_search) { GPtrArray *ids = pas_backend_summary_search (bf->priv->summary, view->search); int db_error = 0; @@ -144,14 +146,24 @@ do_summary_query (PASBackendFile *bf, for (i = 0; i < ids->len; i ++) { char *id = g_ptr_array_index (ids, i); - - string_to_dbt (id, &id_dbt); - memset (&vcard_dbt, 0, sizeof (vcard_dbt)); + char *vcard = NULL; + + if (completion_search) { + vcard = pas_backend_summary_get_summary_vcard (bf->priv->summary, + id); + } + else { + string_to_dbt (id, &id_dbt); + memset (&vcard_dbt, 0, sizeof (vcard_dbt)); - db_error = db->get (db, NULL, &id_dbt, &vcard_dbt, 0); + db_error = db->get (db, NULL, &id_dbt, &vcard_dbt, 0); - if (db_error == 0) { - cards = g_list_prepend (cards, g_strdup (vcard_dbt.data)); + if (db_error == 0) + vcard = g_strdup (vcard_dbt.data); + } + + if (vcard) { + cards = g_list_prepend (cards, vcard); card_count ++; /* If we've accumulated a number of checks, pass them off to the client. */ @@ -326,7 +338,8 @@ vcard_matches_search (const PASBackendFileBookView *view, char *vcard_string) static void pas_backend_file_search (PASBackendFile *bf, PASBook *book, - const PASBackendFileBookView *cnstview) + const PASBackendFileBookView *cnstview, + gboolean completion_search) { PASBackendFileBookView *view = (PASBackendFileBookView *)cnstview; gboolean search_needed; @@ -350,7 +363,7 @@ pas_backend_file_search (PASBackendFile *bf, } if (pas_backend_summary_is_summary_query (bf->priv->summary, view->search)) { - do_summary_query (bf, view); + do_summary_query (bf, view, completion_search); } else { gint card_count = 0, card_threshold = 20, card_threshold_max = 3000; @@ -1000,7 +1013,46 @@ pas_backend_file_process_get_book_view (PASBackend *backend, iterator = e_list_get_iterator(bf->priv->book_views); e_iterator_last(iterator); - pas_backend_file_search (bf, book, e_iterator_get(iterator)); + pas_backend_file_search (bf, book, e_iterator_get(iterator), FALSE); + gtk_object_unref(GTK_OBJECT(iterator)); +} + +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; + + g_return_if_fail (req->listener != NULL); + + bonobo_object_ref(BONOBO_OBJECT(book)); + + book_view = pas_book_view_new (req->listener); + + gtk_signal_connect(GTK_OBJECT(book_view), "destroy", + GTK_SIGNAL_FUNC(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_completion_view (book, + (book_view != NULL + ? GNOME_Evolution_Addressbook_BookListener_Success + : GNOME_Evolution_Addressbook_BookListener_CardNotFound /* XXX */), + book_view); + + iterator = e_list_get_iterator(bf->priv->book_views); + e_iterator_last(iterator); + pas_backend_file_search (bf, book, e_iterator_get(iterator), TRUE); gtk_object_unref(GTK_OBJECT(iterator)); } @@ -1145,6 +1197,10 @@ pas_backend_file_process_client_requests (PASBook *book) pas_backend_file_process_get_book_view (backend, book, (PASGetBookViewRequest*)req); break; + case GetCompletionView: + pas_backend_file_process_get_completion_view (backend, book, (PASGetCompletionViewRequest*)req); + break; + case GetChanges: pas_backend_file_process_get_changes (backend, book, (PASGetChangesRequest*)req); break; @@ -1319,6 +1375,9 @@ pas_backend_file_load_uri (PASBackend *backend, int db_error; DB *db; int major, minor, patch; + time_t db_mtime; + struct stat sb; + char *summary_filename; g_assert (bf->priv->loaded == FALSE); @@ -1405,10 +1464,22 @@ pas_backend_file_load_uri (PASBackend *backend, g_free (bf->priv->filename); bf->priv->filename = filename; - bf->priv->summary = pas_backend_summary_new (filename, SUMMARY_FLUSH_TIMEOUT); + if (stat (bf->priv->filename, &sb) == -1) { + db->close (db, 0); + bf->priv->file_db = NULL; + bf->priv->writable = FALSE; + return GNOME_Evolution_Addressbook_BookListener_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); - if (!pas_backend_summary_load (bf->priv->summary)) + if (pas_backend_summary_is_up_to_date (bf->priv->summary, db_mtime) == FALSE + || pas_backend_summary_load (bf->priv->summary) == FALSE ) { build_summary (bf->priv); + } return GNOME_Evolution_Addressbook_BookListener_Success; } diff --git a/addressbook/backend/pas/pas-backend-ldap.c b/addressbook/backend/pas/pas-backend-ldap.c index ceedc1419f..e7a19c2d2c 100644 --- a/addressbook/backend/pas/pas-backend-ldap.c +++ b/addressbook/backend/pas/pas-backend-ldap.c @@ -2948,6 +2948,11 @@ pas_backend_ldap_process_client_requests (PASBook *book) pas_backend_ldap_process_get_book_view (backend, book, req); break; + case GetCompletionView: + /* we don't support summaries so completion view requests are the same as book view requests */ + pas_backend_ldap_process_get_book_view (backend, book, req); + break; + case GetChanges: /* FIXME: Code this. */ break; diff --git a/addressbook/backend/pas/pas-backend-summary.c b/addressbook/backend/pas/pas-backend-summary.c index 3972426367..23a24c879e 100644 --- a/addressbook/backend/pas/pas-backend-summary.c +++ b/addressbook/backend/pas/pas-backend-summary.c @@ -39,13 +39,16 @@ static GtkObjectClass *parent_class; struct _PASBackendSummaryPrivate { - char *db_path; char *summary_path; + FILE *fp; guint32 file_version; + time_t mtime; gboolean dirty; int flush_timeout_millis; int flush_timeout; GPtrArray *items; + GHashTable *id_to_item; + guint32 num_items; /* used only for loading */ #ifdef SUMMARY_STATS int size; #endif @@ -73,19 +76,21 @@ typedef struct { guint16 email_1_len; guint16 email_2_len; guint16 email_3_len; -} PASBackendSummaryDiskItem_1_0; +} PASBackendSummaryDiskItem; typedef struct { guint32 file_version; guint32 num_items; + guint32 summary_mtime; /* version 2.0 field */ } PASBackendSummaryHeader; #define PAS_SUMMARY_MAGIC "PAS-SUMMARY" #define PAS_SUMMARY_MAGIC_LEN 11 #define PAS_SUMMARY_FILE_VERSION_1_0 1000 +#define PAS_SUMMARY_FILE_VERSION_2_0 2000 -#define PAS_SUMMARY_FILE_VERSION PAS_SUMMARY_FILE_VERSION_1_0 +#define PAS_SUMMARY_FILE_VERSION PAS_SUMMARY_FILE_VERSION_2_0 static void free_summary_item (PASBackendSummaryItem *item) @@ -106,17 +111,17 @@ clear_items (PASBackendSummary *summary) int i; for (i = 0; i < summary->priv->items->len; i++) { PASBackendSummaryItem *item = g_ptr_array_index (summary->priv->items, i); + g_hash_table_remove (summary->priv->id_to_item, item->id); free_summary_item (item); } } PASBackendSummary* -pas_backend_summary_new (const char *db_path, int flush_timeout_millis) +pas_backend_summary_new (const char *summary_path, int flush_timeout_millis) { PASBackendSummary *summary = gtk_type_new (PAS_BACKEND_SUMMARY_TYPE); - summary->priv->db_path = g_strdup (db_path); - summary->priv->summary_path = g_strconcat (db_path, ".summary", NULL); + summary->priv->summary_path = g_strdup (summary_path); summary->priv->flush_timeout_millis = flush_timeout_millis; summary->priv->file_version = PAS_SUMMARY_FILE_VERSION_1_0; @@ -136,11 +141,15 @@ pas_backend_summary_destroy (GtkObject *object) summary->priv->flush_timeout = 0; } - g_free (summary->priv->db_path); + if (summary->priv->fp) + fclose (summary->priv->fp); + g_free (summary->priv->summary_path); clear_items (summary); g_ptr_array_free (summary->priv->items, TRUE); + g_hash_table_destroy (summary->priv->id_to_item); + g_free (summary->priv); GTK_OBJECT_CLASS (parent_class)->destroy (object); @@ -167,10 +176,11 @@ pas_backend_summary_init (PASBackendSummary *summary) summary->priv = priv; - priv->db_path = NULL; priv->summary_path = NULL; + priv->fp = NULL; priv->dirty = FALSE; priv->items = g_ptr_array_new(); + priv->id_to_item = g_hash_table_new (g_str_hash, g_str_equal); priv->flush_timeout_millis = 0; priv->flush_timeout = 0; #ifdef SUMMARY_STATS @@ -233,10 +243,33 @@ pas_backend_summary_load_header (PASBackendSummary *summary, FILE *fp, return FALSE; header->file_version = ntohl (header->file_version); - if (header->file_version != PAS_SUMMARY_FILE_VERSION) { - /* XXX upgrade stuff in here, but since there's only 1 - version now return FALSE */ - return FALSE; + + if (header->file_version == PAS_SUMMARY_FILE_VERSION) { + rv = fread (&header->summary_mtime, sizeof (header->summary_mtime), 1, fp); + if (rv != 1) + return FALSE; + header->summary_mtime = ntohl (header->summary_mtime); + } + else { + if (header->file_version == PAS_SUMMARY_FILE_VERSION_1_0) { + /* the header lacks the mtime of the file. + set it to the mtime of the on-disk file, + and we'll save it out properly next time */ + int fd; + struct stat sb; + + fd = fileno (fp); + if (fstat (fd, &sb) == -1) { + g_warning ("error fstat'ing summary file."); + /* just set the mtime to zero and hope for the best */ + header->summary_mtime = 0; + } + header->summary_mtime = sb.st_mtime; + } + else { + /* unknown version */ + return FALSE; + } } rv = fread (&header->num_items, sizeof (header->num_items), 1, fp); @@ -266,14 +299,15 @@ read_string (FILE *fp, int len) } static gboolean -pas_backend_summary_load_item (PASBackendSummary *summary, FILE *fp, +pas_backend_summary_load_item (PASBackendSummary *summary, PASBackendSummaryItem **new_item) { PASBackendSummaryItem *item; char *buf; + FILE *fp = summary->priv->fp; - if (summary->priv->file_version == PAS_SUMMARY_FILE_VERSION_1_0) { - PASBackendSummaryDiskItem_1_0 disk_item; + if (summary->priv->file_version <= PAS_SUMMARY_FILE_VERSION_2_0) { + PASBackendSummaryDiskItem disk_item; int rv = fread (&disk_item, sizeof (disk_item), 1, fp); if (rv != 1) return FALSE; @@ -376,22 +410,13 @@ pas_backend_summary_load_item (PASBackendSummary *summary, FILE *fp, return TRUE; } -gboolean -pas_backend_summary_load (PASBackendSummary *summary) +/* opens the file and loads the header */ +static void +pas_backend_summary_open (PASBackendSummary *summary) { + FILE *fp; + PASBackendSummaryHeader header; struct stat sb; - time_t db_mtime, summary_mtime; - - /* we don't have a way to determine what was added since we - last updated the summary (without traversing the entire db - anyway), so if the db is newer we just lose the on-disk - summary */ - - if (stat (summary->priv->db_path, &sb) == -1) { - g_warning ("no db present for summary load"); - return FALSE; - } - db_mtime = sb.st_mtime; if (stat (summary->priv->summary_path, &sb) == -1) { /* if there's no summary present, look for the .new @@ -401,61 +426,63 @@ pas_backend_summary_load (PASBackendSummary *summary) if (stat (new_filename, &sb) == -1) { g_warning ("no summary present"); g_free (new_filename); - return FALSE; + return; } else { rename (new_filename, summary->priv->summary_path); - stat (summary->priv->summary_path, &sb); g_free (new_filename); } - } - summary_mtime = sb.st_mtime; - if (summary_mtime < db_mtime) { - /* we need to regenerate the summary */ - return FALSE; + fp = fopen (summary->priv->summary_path, "r"); + if (!fp) { + g_warning ("failed to open summary file"); + return; } - else { - /* the mtime is ok, load the summary */ - PASBackendSummaryHeader header; - PASBackendSummaryItem *new_item; - FILE *fp = fopen (summary->priv->summary_path, "r"); - int i; - if (!fp) { - g_warning ("failed to open summary file"); - return FALSE; - } + if (!pas_backend_summary_check_magic (summary, fp)) { + g_warning ("file is not a valid summary file"); + fclose (fp); + return; + } - if (!pas_backend_summary_check_magic (summary, fp)) { - g_warning ("file is not a valid summary file"); - fclose (fp); - return FALSE; - } + if (!pas_backend_summary_load_header (summary, fp, &header)) { + g_warning ("failed to read summary header"); + fclose (fp); + return; + } - if (!pas_backend_summary_load_header (summary, fp, &header)) { - g_warning ("failed to read summary header"); - fclose (fp); - return FALSE; - } + summary->priv->num_items = header.num_items; + summary->priv->file_version = header.file_version; + summary->priv->mtime = header.summary_mtime; + summary->priv->fp = fp; +} - summary->priv->file_version = header.file_version; +gboolean +pas_backend_summary_load (PASBackendSummary *summary) +{ + PASBackendSummaryItem *new_item; + int i; + + pas_backend_summary_open (summary); - for (i = 0; i < header.num_items; i ++) { - if (!pas_backend_summary_load_item (summary, fp, &new_item)) { - g_warning ("error while reading summary item"); - clear_items (summary); - fclose (fp); - return FALSE; - } + if (!summary->priv->fp) + return FALSE; - g_ptr_array_add (summary->priv->items, new_item); + for (i = 0; i < summary->priv->num_items; i ++) { + if (!pas_backend_summary_load_item (summary, &new_item)) { + g_warning ("error while reading summary item"); + clear_items (summary); + fclose (summary->priv->fp); + summary->priv->fp = NULL; + return FALSE; } - /* XXX for now return FALSE so we'll regenerate the summary */ - return TRUE; + g_ptr_array_add (summary->priv->items, new_item); + g_hash_table_insert (summary->priv->id_to_item, new_item->id, new_item); } + + return TRUE; } static gboolean @@ -475,8 +502,9 @@ pas_backend_summary_save_header (PASBackendSummary *summary, FILE *fp) PASBackendSummaryHeader header; int rv; - header.file_version = htonl (summary->priv->file_version); + header.file_version = htonl (PAS_SUMMARY_FILE_VERSION); header.num_items = htonl (summary->priv->items->len); + header.summary_mtime = htonl (time (NULL)); rv = fwrite (&header, sizeof (header), 1, fp); if (rv != 1) @@ -500,7 +528,7 @@ save_string (const char *str, FILE *fp) static gboolean pas_backend_summary_save_item (PASBackendSummary *summary, FILE *fp, PASBackendSummaryItem *item) { - PASBackendSummaryDiskItem_1_0 disk_item; + PASBackendSummaryDiskItem disk_item; int len; int rv; @@ -635,6 +663,7 @@ pas_backend_summary_add_card (PASBackendSummary *summary, const char *vcard) new_item->email_3 = e_card_simple_get (simple, E_CARD_SIMPLE_FIELD_EMAIL_3); g_ptr_array_add (summary->priv->items, new_item); + g_hash_table_insert (summary->priv->id_to_item, new_item->id, new_item); gtk_object_unref (GTK_OBJECT (simple)); gtk_object_unref (GTK_OBJECT (card)); @@ -656,16 +685,14 @@ pas_backend_summary_add_card (PASBackendSummary *summary, const char *vcard) void pas_backend_summary_remove_card (PASBackendSummary *summary, const char *id) { - int i; + PASBackendSummaryItem *item = g_hash_table_lookup (summary->priv->id_to_item, id); - for (i = 0; i < summary->priv->items->len; i ++) { - PASBackendSummaryItem *item = g_ptr_array_index (summary->priv->items, i); - if (!strcmp (item->id, id)) { - g_ptr_array_remove_index (summary->priv->items, i); - free_summary_item (item); - pas_backend_summary_touch (summary); - return; - } + if (item) { + g_ptr_array_remove (summary->priv->items, item); + g_hash_table_remove (summary->priv->id_to_item, id); + free_summary_item (item); + pas_backend_summary_touch (summary); + return; } g_warning ("pas_backend_summary_remove_card: unable to locate id `%s'", id); @@ -702,6 +729,12 @@ pas_backend_summary_touch (PASBackendSummary *summary) summary_flush_func, summary); } +gboolean +pas_backend_summary_is_up_to_date (PASBackendSummary *summary, time_t t) +{ + return summary->priv->mtime >= t; +} + /* we only want to do summary queries if the query is over the set fields in the summary */ @@ -955,3 +988,37 @@ pas_backend_summary_search (PASBackendSummary *summary, const char *query) return retval; } + +char* +pas_backend_summary_get_summary_vcard(PASBackendSummary *summary, const char *id) +{ + PASBackendSummaryItem *item = g_hash_table_lookup (summary->priv->id_to_item, id); + + if (item) { + ECard *card = e_card_new (""); + ECardSimple *simple = e_card_simple_new (card); + char *vcard; + + e_card_simple_set_id (simple, item->id); + e_card_simple_set (simple, E_CARD_SIMPLE_FIELD_FILE_AS, item->file_as); + e_card_simple_set (simple, E_CARD_SIMPLE_FIELD_GIVEN_NAME, item->given_name); + e_card_simple_set (simple, E_CARD_SIMPLE_FIELD_FAMILY_NAME, item->surname); + e_card_simple_set (simple, E_CARD_SIMPLE_FIELD_NICKNAME, item->nickname); + e_card_simple_set_email (simple, E_CARD_SIMPLE_EMAIL_ID_EMAIL, item->email_1); + e_card_simple_set_email (simple, E_CARD_SIMPLE_EMAIL_ID_EMAIL_2, item->email_2); + e_card_simple_set_email (simple, E_CARD_SIMPLE_EMAIL_ID_EMAIL_3, item->email_3); + + e_card_simple_sync_card (simple); + + vcard = e_card_simple_get_vcard (simple); + + gtk_object_unref (GTK_OBJECT (simple)); + gtk_object_unref (GTK_OBJECT (card)); + + return vcard; + } + else { + g_warning ("in unable to locate card `%s' in summary", id); + } +} + diff --git a/addressbook/backend/pas/pas-backend-summary.h b/addressbook/backend/pas/pas-backend-summary.h index 8feac77339..fb989332fe 100644 --- a/addressbook/backend/pas/pas-backend-summary.h +++ b/addressbook/backend/pas/pas-backend-summary.h @@ -37,22 +37,27 @@ typedef struct { GtkObjectClass parent_class; } PASBackendSummaryClass; -PASBackendSummary* pas_backend_summary_new (const char *db_path, int flush_timeout_millis); +PASBackendSummary* pas_backend_summary_new (const char *summary_path, + int flush_timeout_millis); GtkType pas_backend_summary_get_type (void); /* returns FALSE if the load fails for any reason (including that the summary is out of date), TRUE if it succeeds */ -gboolean pas_backend_summary_load (PASBackendSummary *summary); +gboolean pas_backend_summary_load f (PASBackendSummary *summary); /* returns FALSE if the save fails, TRUE if it succeeds (or isn't required due to no changes) */ -gboolean pas_backend_summary_save (PASBackendSummary *summary); +gboolean pas_backend_summary_save (PASBackendSummary *summary); -void pas_backend_summary_add_card (PASBackendSummary *summary, const char *vcard); -void pas_backend_summary_remove_card (PASBackendSummary *summary, const char *id); +void pas_backend_summary_add_card (PASBackendSummary *summary, const char *vcard); +void pas_backend_summary_remove_card (PASBackendSummary *summary, const char *id); -void pas_backend_summary_touch (PASBackendSummary *summary); +void pas_backend_summary_touch (PASBackendSummary *summary); -gboolean pas_backend_summary_is_summary_query (PASBackendSummary *summary, const char *query); -GPtrArray* pas_backend_summary_search (PASBackendSummary *summary, const char *query); +/* returns TRUE if the summary's mtime is >= @t. */ +gboolean pas_backend_summary_is_up_to_date (PASBackendSummary *summary, time_t t); + +gboolean pas_backend_summary_is_summary_query (PASBackendSummary *summary, const char *query); +GPtrArray* pas_backend_summary_search (PASBackendSummary *summary, const char *query); +char* pas_backend_summary_get_summary_vcard (PASBackendSummary *summary, const char *id); #define PAS_BACKEND_SUMMARY_TYPE (pas_backend_summary_get_type ()) #define PAS_BACKEND_SUMMARY(o) (GTK_CHECK_CAST ((o), PAS_BACKEND_SUMMARY_TYPE, PASBackendSummary)) diff --git a/addressbook/backend/pas/pas-book.c b/addressbook/backend/pas/pas-book.c index 9bb2cd348e..7a3ab55f92 100644 --- a/addressbook/backend/pas/pas-book.c +++ b/addressbook/backend/pas/pas-book.c @@ -178,6 +178,30 @@ pas_book_queue_get_book_view (PASBook *book, const GNOME_Evolution_Addressbook_B pas_book_queue_request (book, req); } +static void +pas_book_queue_get_completion_view (PASBook *book, const GNOME_Evolution_Addressbook_BookViewListener listener, const char *search) +{ + PASRequest *req; + CORBA_Environment ev; + + req = g_new0 (PASRequest, 1); + req->op = GetCompletionView; + req->get_book_view.search = g_strdup(search); + + CORBA_exception_init (&ev); + + req->get_book_view.listener = bonobo_object_dup_ref(listener, &ev); + + if (ev._major != CORBA_NO_EXCEPTION) { + g_warning ("pas_book_queue_get_completion_view: Exception " + "duplicating BookViewListener!\n"); + } + + CORBA_exception_free (&ev); + + pas_book_queue_request (book, req); +} + static void pas_book_queue_get_changes (PASBook *book, const GNOME_Evolution_Addressbook_BookViewListener listener, const char *change_id) { @@ -286,6 +310,18 @@ impl_GNOME_Evolution_Addressbook_Book_getBookView (PortableServer_Servant servan pas_book_queue_get_book_view (book, listener, search); } + +static void +impl_GNOME_Evolution_Addressbook_Book_getCompletionView (PortableServer_Servant servant, + const GNOME_Evolution_Addressbook_BookViewListener listener, + const CORBA_char *search, + CORBA_Environment *ev) +{ + PASBook *book = PAS_BOOK (bonobo_object_from_servant (servant)); + + pas_book_queue_get_completion_view (book, listener, search); +} + static void impl_GNOME_Evolution_Addressbook_Book_getChanges (PortableServer_Servant servant, const GNOME_Evolution_Addressbook_BookViewListener listener, @@ -600,6 +636,32 @@ pas_book_respond_get_book_view (PASBook *book, CORBA_exception_free (&ev); } +/** + * pas_book_respond_get_book_view: + */ +void +pas_book_respond_get_completion_view (PASBook *book, + GNOME_Evolution_Addressbook_BookListener_CallStatus status, + PASBookView *completion_view) +{ + CORBA_Environment ev; + CORBA_Object object; + + CORBA_exception_init (&ev); + + object = bonobo_object_corba_objref(BONOBO_OBJECT(completion_view)); + + GNOME_Evolution_Addressbook_BookListener_notifyViewRequested ( + book->priv->listener, status, object, &ev); + + if (ev._major != CORBA_NO_EXCEPTION) { + g_warning ("pas_book_respond_get_completion_view: Exception " + "responding to BookListener!\n"); + } + + CORBA_exception_free (&ev); +} + /** * pas_book_respond_get_changes: */ @@ -795,6 +857,16 @@ pas_book_free_request (PASRequest *req) if (ev._major != CORBA_NO_EXCEPTION) g_message ("pas_book_free_request(GetBookView): could not release the listener"); + CORBA_exception_free (&ev); + break; + case GetCompletionView: + g_free (req->get_completion_view.search); + CORBA_exception_init (&ev); + bonobo_object_release_unref (req->get_completion_view.listener, &ev); + + if (ev._major != CORBA_NO_EXCEPTION) + g_message ("pas_book_free_request(GetCompletionView): could not release the listener"); + CORBA_exception_free (&ev); break; case GetChanges: @@ -875,6 +947,7 @@ pas_book_get_epv (void) epv->getSupportedFields = impl_GNOME_Evolution_Addressbook_Book_getSupportedFields; epv->getCursor = impl_GNOME_Evolution_Addressbook_Book_getCursor; epv->getBookView = impl_GNOME_Evolution_Addressbook_Book_getBookView; + epv->getCompletionView = impl_GNOME_Evolution_Addressbook_Book_getCompletionView; epv->getChanges = impl_GNOME_Evolution_Addressbook_Book_getChanges; return epv; diff --git a/addressbook/backend/pas/pas-book.h b/addressbook/backend/pas/pas-book.h index a6f2fda3cc..4dcd1e205d 100644 --- a/addressbook/backend/pas/pas-book.h +++ b/addressbook/backend/pas/pas-book.h @@ -31,6 +31,7 @@ typedef enum { GetVCard, GetCursor, GetBookView, + GetCompletionView, GetChanges, CheckConnection, AuthenticateUser, @@ -69,6 +70,12 @@ typedef struct { GNOME_Evolution_Addressbook_BookViewListener listener; } PASGetBookViewRequest; +typedef struct { + PASOperation op; + char *search; + GNOME_Evolution_Addressbook_BookViewListener listener; +} PASGetCompletionViewRequest; + typedef struct { PASOperation op; char *change_id; @@ -91,17 +98,18 @@ typedef struct { } PASGetSupportedFieldsRequest; typedef union { - PASOperation op; - - PASCreateCardRequest create; - PASRemoveCardRequest remove; - PASModifyCardRequest modify; - PASGetVCardRequest get_vcard; - PASGetCursorRequest get_cursor; - PASGetBookViewRequest get_book_view; - PASGetChangesRequest get_changes; - PASCheckConnectionRequest check_connection; - PASAuthenticateUserRequest auth_user; + PASOperation op; + + PASCreateCardRequest create; + PASRemoveCardRequest remove; + PASModifyCardRequest modify; + PASGetVCardRequest get_vcard; + PASGetCursorRequest get_cursor; + PASGetBookViewRequest get_book_view; + PASGetCompletionViewRequest get_completion_view; + PASGetChangesRequest get_changes; + PASCheckConnectionRequest check_connection; + PASAuthenticateUserRequest auth_user; PASGetSupportedFieldsRequest get_supported_fields; } PASRequest; @@ -148,6 +156,9 @@ void pas_book_respond_get_cursor (PASBook void pas_book_respond_get_book_view (PASBook *book, GNOME_Evolution_Addressbook_BookListener_CallStatus status, PASBookView *book_view); +void pas_book_respond_get_completion_view (PASBook *book, + GNOME_Evolution_Addressbook_BookListener_CallStatus status, + PASBookView *completion_view); void pas_book_respond_get_vcard (PASBook *book, GNOME_Evolution_Addressbook_BookListener_CallStatus status, char *vcard); -- cgit v1.2.3