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 --- ChangeLog | 8 + Makefile.am | 1 - addressbook/ChangeLog | 2073 ++++++++++- addressbook/Makefile.am | 4 +- addressbook/backend/ebook/.cvsignore | 1 + addressbook/backend/ebook/Makefile.am | 114 +- addressbook/backend/ebook/docs/rfc2739.txt | 899 +++++ addressbook/backend/ebook/e-book-async.c | 1120 ++++++ addressbook/backend/ebook/e-book-async.h | 107 + addressbook/backend/ebook/e-book-listener.c | 779 +--- addressbook/backend/ebook/e-book-listener.h | 42 +- addressbook/backend/ebook/e-book-query.c | 524 +++ addressbook/backend/ebook/e-book-query.h | 49 + addressbook/backend/ebook/e-book-types.h | 59 +- addressbook/backend/ebook/e-book-util.c | 808 ----- addressbook/backend/ebook/e-book-util.h | 94 - addressbook/backend/ebook/e-book-view-listener.c | 263 +- addressbook/backend/ebook/e-book-view-listener.h | 30 +- addressbook/backend/ebook/e-book-view.c | 101 +- addressbook/backend/ebook/e-book-view.h | 15 +- addressbook/backend/ebook/e-book.c | 2579 +++++++------ addressbook/backend/ebook/e-book.h | 212 +- addressbook/backend/ebook/e-card-compare.c | 706 ---- addressbook/backend/ebook/e-card-compare.h | 72 - addressbook/backend/ebook/e-card-cursor.c | 239 -- addressbook/backend/ebook/e-card-cursor.h | 53 - addressbook/backend/ebook/e-card-pairs.h | 118 - addressbook/backend/ebook/e-card-simple.c | 1344 ------- addressbook/backend/ebook/e-card-simple.h | 234 -- addressbook/backend/ebook/e-card-types.h | 101 - addressbook/backend/ebook/e-card.c | 2807 --------------- addressbook/backend/ebook/e-card.h | 209 -- addressbook/backend/ebook/e-contact.c | 1288 +++++++ addressbook/backend/ebook/e-contact.h | 227 ++ addressbook/backend/ebook/e-destination.h | 140 - addressbook/backend/ebook/e-vcard.c | 488 ++- addressbook/backend/ebook/e-vcard.h | 99 +- addressbook/backend/ebook/test-client-list.c | 65 - addressbook/backend/ebook/test-client.c | 191 - addressbook/backend/ebook/tests/Makefile.am | 2 +- addressbook/backend/ebook/tests/ebook/.cvsignore | 7 + addressbook/backend/ebook/tests/ebook/Makefile.am | 12 + .../backend/ebook/tests/ebook/test-changes.c | 89 + addressbook/backend/ebook/tests/ebook/test-date.c | 36 + addressbook/backend/ebook/tests/ebook/test-ebook.c | 110 + addressbook/backend/ebook/tests/ebook/test-photo.c | 59 + .../backend/ebook/tests/ebook/test-string.c | 27 + addressbook/backend/ebook/tests/vcard/Makefile.am | 6 +- addressbook/backend/ebook/tests/vcard/dump-vcard.c | 2 +- addressbook/backend/idl/addressbook.idl | 218 +- addressbook/backend/pas/Makefile.am | 14 +- addressbook/backend/pas/pas-backend-card-sexp.c | 239 +- addressbook/backend/pas/pas-backend-card-sexp.h | 13 +- addressbook/backend/pas/pas-backend-file.c | 1315 +++---- addressbook/backend/pas/pas-backend-file.h | 6 +- addressbook/backend/pas/pas-backend-ldap.c | 1405 +++----- addressbook/backend/pas/pas-backend-summary.c | 80 +- addressbook/backend/pas/pas-backend-summary.h | 14 +- addressbook/backend/pas/pas-backend-sync.c | 395 ++ addressbook/backend/pas/pas-backend-sync.h | 81 + addressbook/backend/pas/pas-backend-vcf.c | 632 ++++ addressbook/backend/pas/pas-backend-vcf.h | 35 + addressbook/backend/pas/pas-backend.c | 582 +-- addressbook/backend/pas/pas-backend.h | 119 +- addressbook/backend/pas/pas-book-factory.c | 260 +- addressbook/backend/pas/pas-book-view.c | 362 +- addressbook/backend/pas/pas-book-view.h | 29 +- addressbook/backend/pas/pas-book.c | 830 ++--- addressbook/backend/pas/pas-book.h | 202 +- addressbook/backend/pas/pas-card-cursor.c | 139 - addressbook/backend/pas/pas-card-cursor.h | 56 - addressbook/backend/pas/pas-marshal.list | 1 + addressbook/backend/pas/pas-types.h | 32 + addressbook/backend/pas/ximian-vcard.h | 81 + .../GNOME_Evolution_Addressbook.server.in.in | 27 +- addressbook/gui/component/Makefile.am | 21 +- addressbook/gui/component/addressbook-component.c | 653 +--- addressbook/gui/component/addressbook-component.h | 45 +- addressbook/gui/component/addressbook-config.c | 16 +- addressbook/gui/component/addressbook.c | 216 +- addressbook/gui/component/addressbook.h | 4 +- addressbook/gui/component/component-factory.c | 29 +- addressbook/gui/component/e-address-popup.c | 1261 ------- addressbook/gui/component/e-address-popup.h | 88 - addressbook/gui/component/e-address-widget.c | 568 --- addressbook/gui/component/e-address-widget.h | 82 - addressbook/gui/component/e-cardlist-model.c | 239 -- addressbook/gui/component/e-cardlist-model.h | 42 - .../Evolution-Addressbook-SelectNames.idl | 72 - ..._Evolution_Addressbook_SelectNames.server.in.in | 4 +- addressbook/gui/component/select-names/Makefile.am | 4 +- .../component/select-names/e-select-names-bonobo.c | 41 +- .../select-names/e-select-names-completion.c | 238 +- .../select-names/e-select-names-completion.h | 2 +- .../select-names/e-select-names-manager.c | 27 +- .../component/select-names/e-select-names-model.c | 181 +- .../component/select-names/e-select-names-model.h | 27 +- .../component/select-names/e-select-names-popup.c | 96 +- .../select-names/e-select-names-table-model.c | 18 +- .../select-names/e-select-names-text-model.c | 65 +- .../gui/component/select-names/e-select-names.c | 83 +- .../gui/component/select-names/e-select-names.h | 2 +- .../component/select-names/e-simple-card-bonobo.c | 216 -- .../component/select-names/e-simple-card-bonobo.h | 71 - addressbook/gui/contact-editor/Makefile.am | 2 - .../gui/contact-editor/contact-editor.glade | 43 + .../gui/contact-editor/e-contact-editor-address.c | 16 +- .../gui/contact-editor/e-contact-editor-address.h | 6 +- .../gui/contact-editor/e-contact-editor-fullname.c | 34 +- .../gui/contact-editor/e-contact-editor-fullname.h | 6 +- addressbook/gui/contact-editor/e-contact-editor.c | 765 ++-- addressbook/gui/contact-editor/e-contact-editor.h | 40 +- .../gui/contact-editor/e-contact-quick-add.c | 60 +- .../gui/contact-editor/e-contact-quick-add.h | 4 +- addressbook/gui/contact-editor/e-contact-save-as.c | 218 -- addressbook/gui/contact-editor/e-contact-save-as.h | 41 - .../contact-list-editor/contact-list-editor.glade | 2 +- .../contact-list-editor/e-contact-list-editor.c | 460 ++- .../contact-list-editor/e-contact-list-editor.h | 26 +- .../gui/contact-list-editor/e-contact-list-model.c | 32 +- .../gui/contact-list-editor/e-contact-list-model.h | 15 +- addressbook/gui/merging/.cvsignore | 1 + addressbook/gui/merging/Makefile.am | 17 +- .../gui/merging/e-card-duplicate-detected.glade | 212 -- ...rd-merging-book-commit-duplicate-detected.glade | 212 -- addressbook/gui/merging/e-card-merging.c | 198 - addressbook/gui/merging/e-card-merging.h | 29 - .../eab-contact-commit-duplicate-detected.glade | 212 ++ addressbook/gui/merging/eab-contact-compare.c | 736 ++++ addressbook/gui/merging/eab-contact-compare.h | 73 + .../merging/eab-contact-duplicate-detected.glade | 212 ++ addressbook/gui/merging/eab-contact-merging.c | 197 + addressbook/gui/merging/eab-contact-merging.h | 30 + .../gui/search/e-addressbook-search-dialog.c | 38 +- .../gui/search/e-addressbook-search-dialog.h | 31 +- addressbook/gui/widgets/.cvsignore | 4 +- addressbook/gui/widgets/Makefile.am | 115 +- addressbook/gui/widgets/e-addressbook-marshal.list | 11 - addressbook/gui/widgets/e-addressbook-model.c | 382 +- addressbook/gui/widgets/e-addressbook-model.h | 83 +- .../gui/widgets/e-addressbook-reflow-adapter.c | 152 +- .../gui/widgets/e-addressbook-reflow-adapter.h | 11 +- .../gui/widgets/e-addressbook-table-adapter.c | 207 +- .../gui/widgets/e-addressbook-table-adapter.h | 32 +- .../gui/widgets/e-addressbook-treeview-adapter.c | 6 +- addressbook/gui/widgets/e-addressbook-util.c | 636 ---- addressbook/gui/widgets/e-addressbook-util.h | 65 - addressbook/gui/widgets/e-addressbook-view.c | 1147 +++--- addressbook/gui/widgets/e-addressbook-view.etspec | 30 +- addressbook/gui/widgets/e-addressbook-view.h | 153 +- addressbook/gui/widgets/e-minicard-control.c | 357 -- addressbook/gui/widgets/e-minicard-control.h | 8 - addressbook/gui/widgets/e-minicard-label.c | 4 +- addressbook/gui/widgets/e-minicard-view-widget.c | 49 +- addressbook/gui/widgets/e-minicard-view.c | 48 +- addressbook/gui/widgets/e-minicard-widget-test.c | 117 - addressbook/gui/widgets/e-minicard-widget.c | 264 -- addressbook/gui/widgets/e-minicard-widget.h | 76 - addressbook/gui/widgets/e-minicard.c | 264 +- addressbook/gui/widgets/e-minicard.h | 6 +- addressbook/gui/widgets/eab-contact-display.c | 486 +++ addressbook/gui/widgets/eab-contact-display.h | 61 + addressbook/gui/widgets/eab-gui-util.c | 823 +++++ addressbook/gui/widgets/eab-gui-util.h | 70 + addressbook/gui/widgets/eab-marshal.list | 11 + addressbook/gui/widgets/eab-popup-control.c | 1236 +++++++ addressbook/gui/widgets/eab-popup-control.h | 85 + addressbook/gui/widgets/eab-vcard-control.c | 310 ++ addressbook/gui/widgets/eab-vcard-control.h | 8 + addressbook/gui/widgets/test-minicard-label.c | 129 - addressbook/gui/widgets/test-minicard-view.c | 203 -- addressbook/gui/widgets/test-minicard.c | 120 - addressbook/printing/Makefile.am | 6 +- addressbook/printing/e-contact-print-envelope.c | 31 +- addressbook/printing/e-contact-print-envelope.h | 4 +- addressbook/printing/e-contact-print.c | 327 +- addressbook/printing/e-contact-print.h | 6 +- addressbook/tools/Makefile.am | 25 +- addressbook/tools/csv2vcard | 236 ++ addressbook/tools/evolution-addressbook-abuse.c | 127 + addressbook/tools/evolution-addressbook-clean.in | 24 + addressbook/tools/evolution-addressbook-import.c | 90 + addressbook/util/.cvsignore | 4 + addressbook/util/Makefile.am | 41 + addressbook/util/eab-book-util.c | 293 ++ addressbook/util/eab-book-util.h | 69 + addressbook/util/eab-destination.c | 1569 ++++++++ addressbook/util/eab-destination.h | 128 + addressbook/util/eab-marshal.list | 5 + calendar/ChangeLog | 2147 ++++++++++- calendar/cal-client/.cvsignore | 2 + calendar/cal-client/Makefile.am | 7 +- calendar/cal-client/cal-client-types.h | 26 + calendar/cal-client/cal-client.c | 3800 ++++++++++++-------- calendar/cal-client/cal-client.h | 101 +- calendar/cal-client/cal-listener.c | 895 ++++- calendar/cal-client/cal-listener.h | 53 +- calendar/cal-client/cal-marshal.list | 6 + calendar/cal-client/cal-query.c | 470 ++- calendar/cal-client/cal-query.h | 37 +- calendar/cal-client/client-test.c | 155 +- calendar/cal-client/query-listener.c | 393 +- calendar/cal-client/query-listener.h | 44 +- calendar/cal-util/cal-util.c | 24 +- calendar/conduits/calendar/calendar-conduit.c | 125 +- calendar/conduits/todo/todo-conduit.c | 101 +- calendar/gui/GNOME_Evolution_Calendar.server.in.in | 26 +- calendar/gui/Makefile.am | 5 +- calendar/gui/alarm-notify/alarm-notify.c | 209 +- calendar/gui/alarm-notify/alarm-queue.c | 2 +- calendar/gui/calendar-commands.c | 157 +- calendar/gui/calendar-commands.h | 2 + calendar/gui/calendar-component.c | 849 +---- calendar/gui/calendar-component.h | 48 +- calendar/gui/calendar-offline-handler.c | 18 +- calendar/gui/comp-editor-factory.c | 46 +- calendar/gui/comp-util.c | 46 +- calendar/gui/control-factory.c | 18 +- calendar/gui/control-factory.h | 2 + calendar/gui/dialogs/Makefile.am | 3 + calendar/gui/dialogs/alarm-options.c | 34 +- calendar/gui/e-cal-model-calendar.c | 10 +- calendar/gui/e-cal-model-tasks.c | 14 +- calendar/gui/e-cal-model.c | 282 +- calendar/gui/e-cal-model.h | 2 + calendar/gui/e-cal-view.c | 497 ++- calendar/gui/e-cal-view.h | 13 + calendar/gui/e-calendar-table.c | 38 +- calendar/gui/e-calendar-view.c | 497 ++- calendar/gui/e-calendar-view.h | 13 + calendar/gui/e-day-view.c | 352 +- calendar/gui/e-day-view.h | 7 - calendar/gui/e-itip-control.c | 162 +- calendar/gui/e-meeting-list-view.c | 101 +- calendar/gui/e-meeting-model.c | 1780 +++++++++ calendar/gui/e-meeting-model.h | 116 + calendar/gui/e-meeting-store.c | 36 +- calendar/gui/e-meeting-time-sel.c | 6 + calendar/gui/e-select-names-editable.c | 18 +- calendar/gui/e-tasks.c | 128 +- calendar/gui/e-week-view-event-item.c | 7 +- calendar/gui/e-week-view.c | 173 +- calendar/gui/e-week-view.h | 8 - calendar/gui/gnome-cal.c | 617 +--- calendar/gui/gnome-cal.h | 18 +- calendar/gui/itip-utils.c | 53 +- calendar/gui/main.c | 28 +- calendar/gui/migration.c | 126 + calendar/gui/migration.h | 30 + calendar/gui/print.c | 31 +- calendar/gui/tag-calendar.c | 3 +- calendar/gui/tasks-control.c | 4 +- configure.in | 13 +- evolution-calendar.pc.in | 2 +- 254 files changed, 32550 insertions(+), 27399 deletions(-) create mode 100644 addressbook/backend/ebook/docs/rfc2739.txt create mode 100644 addressbook/backend/ebook/e-book-async.c create mode 100644 addressbook/backend/ebook/e-book-async.h create mode 100644 addressbook/backend/ebook/e-book-query.c create mode 100644 addressbook/backend/ebook/e-book-query.h delete mode 100644 addressbook/backend/ebook/e-book-util.c delete mode 100644 addressbook/backend/ebook/e-book-util.h delete mode 100644 addressbook/backend/ebook/e-card-compare.c delete mode 100644 addressbook/backend/ebook/e-card-compare.h delete mode 100644 addressbook/backend/ebook/e-card-cursor.c delete mode 100644 addressbook/backend/ebook/e-card-cursor.h delete mode 100644 addressbook/backend/ebook/e-card-pairs.h delete mode 100644 addressbook/backend/ebook/e-card-simple.c delete mode 100644 addressbook/backend/ebook/e-card-simple.h delete mode 100644 addressbook/backend/ebook/e-card-types.h delete mode 100644 addressbook/backend/ebook/e-card.c delete mode 100644 addressbook/backend/ebook/e-card.h create mode 100644 addressbook/backend/ebook/e-contact.c create mode 100644 addressbook/backend/ebook/e-contact.h delete mode 100644 addressbook/backend/ebook/e-destination.h delete mode 100644 addressbook/backend/ebook/test-client-list.c delete mode 100644 addressbook/backend/ebook/test-client.c create mode 100644 addressbook/backend/ebook/tests/ebook/.cvsignore create mode 100644 addressbook/backend/ebook/tests/ebook/Makefile.am create mode 100644 addressbook/backend/ebook/tests/ebook/test-changes.c create mode 100644 addressbook/backend/ebook/tests/ebook/test-date.c create mode 100644 addressbook/backend/ebook/tests/ebook/test-ebook.c create mode 100644 addressbook/backend/ebook/tests/ebook/test-photo.c create mode 100644 addressbook/backend/ebook/tests/ebook/test-string.c create mode 100644 addressbook/backend/pas/pas-backend-sync.c create mode 100644 addressbook/backend/pas/pas-backend-sync.h create mode 100644 addressbook/backend/pas/pas-backend-vcf.c create mode 100644 addressbook/backend/pas/pas-backend-vcf.h delete mode 100644 addressbook/backend/pas/pas-card-cursor.c delete mode 100644 addressbook/backend/pas/pas-card-cursor.h create mode 100644 addressbook/backend/pas/pas-types.h create mode 100644 addressbook/backend/pas/ximian-vcard.h delete mode 100644 addressbook/gui/component/e-address-popup.c delete mode 100644 addressbook/gui/component/e-address-popup.h delete mode 100644 addressbook/gui/component/e-address-widget.c delete mode 100644 addressbook/gui/component/e-address-widget.h delete mode 100644 addressbook/gui/component/e-cardlist-model.c delete mode 100644 addressbook/gui/component/e-cardlist-model.h delete mode 100644 addressbook/gui/component/select-names/e-simple-card-bonobo.c delete mode 100644 addressbook/gui/component/select-names/e-simple-card-bonobo.h delete mode 100644 addressbook/gui/contact-editor/e-contact-save-as.c delete mode 100644 addressbook/gui/contact-editor/e-contact-save-as.h delete mode 100644 addressbook/gui/merging/e-card-duplicate-detected.glade delete mode 100644 addressbook/gui/merging/e-card-merging-book-commit-duplicate-detected.glade delete mode 100644 addressbook/gui/merging/e-card-merging.c delete mode 100644 addressbook/gui/merging/e-card-merging.h create mode 100644 addressbook/gui/merging/eab-contact-commit-duplicate-detected.glade create mode 100644 addressbook/gui/merging/eab-contact-compare.c create mode 100644 addressbook/gui/merging/eab-contact-compare.h create mode 100644 addressbook/gui/merging/eab-contact-duplicate-detected.glade create mode 100644 addressbook/gui/merging/eab-contact-merging.c create mode 100644 addressbook/gui/merging/eab-contact-merging.h delete mode 100644 addressbook/gui/widgets/e-addressbook-marshal.list delete mode 100644 addressbook/gui/widgets/e-addressbook-util.c delete mode 100644 addressbook/gui/widgets/e-addressbook-util.h delete mode 100644 addressbook/gui/widgets/e-minicard-control.c delete mode 100644 addressbook/gui/widgets/e-minicard-control.h delete mode 100644 addressbook/gui/widgets/e-minicard-widget-test.c delete mode 100644 addressbook/gui/widgets/e-minicard-widget.c delete mode 100644 addressbook/gui/widgets/e-minicard-widget.h create mode 100644 addressbook/gui/widgets/eab-contact-display.c create mode 100644 addressbook/gui/widgets/eab-contact-display.h create mode 100644 addressbook/gui/widgets/eab-gui-util.c create mode 100644 addressbook/gui/widgets/eab-gui-util.h create mode 100644 addressbook/gui/widgets/eab-marshal.list create mode 100644 addressbook/gui/widgets/eab-popup-control.c create mode 100644 addressbook/gui/widgets/eab-popup-control.h create mode 100644 addressbook/gui/widgets/eab-vcard-control.c create mode 100644 addressbook/gui/widgets/eab-vcard-control.h delete mode 100644 addressbook/gui/widgets/test-minicard-label.c delete mode 100644 addressbook/gui/widgets/test-minicard-view.c delete mode 100644 addressbook/gui/widgets/test-minicard.c create mode 100755 addressbook/tools/csv2vcard create mode 100644 addressbook/tools/evolution-addressbook-abuse.c create mode 100644 addressbook/tools/evolution-addressbook-clean.in create mode 100644 addressbook/tools/evolution-addressbook-import.c create mode 100644 addressbook/util/.cvsignore create mode 100644 addressbook/util/Makefile.am create mode 100644 addressbook/util/eab-book-util.c create mode 100644 addressbook/util/eab-book-util.h create mode 100644 addressbook/util/eab-destination.c create mode 100644 addressbook/util/eab-destination.h create mode 100644 addressbook/util/eab-marshal.list create mode 100644 calendar/cal-client/cal-marshal.list create mode 100644 calendar/gui/e-meeting-model.c create mode 100644 calendar/gui/e-meeting-model.h create mode 100644 calendar/gui/migration.c create mode 100644 calendar/gui/migration.h diff --git a/ChangeLog b/ChangeLog index 7a6110f55f..f1d7482fe9 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,11 @@ +2003-10-21 Dan Winship + + * configure.in (GNOME_COMPILE_WARNINGS): Turn off the annoying + "comparison between signed and unsigned" warning in gcc 3.3 + + * evolution-calendar.pc.in (Cflags): add + -I${privincludedir}/libical + 2003-10-08 Frederic Crozat * configure.in: Check for gnome-thumbnail.h existence. diff --git a/Makefile.am b/Makefile.am index 1915b78db7..43368cdf25 100644 --- a/Makefile.am +++ b/Makefile.am @@ -36,7 +36,6 @@ SUBDIRS = \ filter \ addressbook \ calendar \ - my-evolution \ art \ composer \ mail \ diff --git a/addressbook/ChangeLog b/addressbook/ChangeLog index ed3992ba42..881c16f422 100644 --- a/addressbook/ChangeLog +++ b/addressbook/ChangeLog @@ -1,3 +1,893 @@ +2003-10-20 Dan Winship + + * backend/pas/pas-book-view.c: Queue up removes and modifies as + well as adds, and remove the calls that took a list of changes + rather than a single change, since no one was really using the + list versions. Keep a list of IDs currently in the view so we can + more easily figure out what changes count as adds, modifies, and + removes. + (send_pending_adds): Don't reset next_threshold if it's being + called from notify_add. + (send_pending_changes, send_pending_removes): New + (pas_book_view_notify_update): Simplified add/change interface. + Takes an EContact and figures out if it's new, modified, or + removed relative to this view. + (pas_book_view_notify_change, pas_book_view_notify_change_1, + pas_book_view_notify_add, pas_book_view_notify_add_1): Gone. + (pas_book_view_notify_remove): Now does what remove_1 used to do. + (pas_book_view_vcard_matches): Remove this; no longer used. + + * backend/pas/pas-backend.c (pas_backend_notify_update): New. + Calls pas_book_view_notify_update() on each of the backend's views. + (pas_backend_notify_remove): Likewise for notify_remove(). + (pas_backend_notify_complete): And notify_complete(). + + * backend/pas/pas-book.c (pas_book_respond_create): Take an + EContact instead of an id and a vcard. Use + pas_backend_notify_update. + (pas_book_respond_remove_contacts): Use pas_backend_notify_remove. + (pas_book_respond_modify): Take a single EContact instead of two + vcards. Use pas_backend_notify_update. + + * backend/pas/pas-backend-sync.c + (pas_backend_sync_create_contact): Return an EContact rather than + an id. + (pas_backend_sync_modify_contact): Return an EContact rather than + the old_vcard. + (_pas_backend_create_contact, _pas_backend_modify_contact): Update + + * backend/pas/pas-backend-file.c (do_summary_query): Use + pas_book_view_notify_update. + (pas_backend_file_search_timeout): Likewise + (pas_backend_file_create_contact): Update for API changes + (pas_backend_file_modify_contact): Likewise. + + * backend/pas/pas-backend-ldap.c (create_contact_handler, + pas_backend_ldap_process_create_contact): Update for API changes + (modify_contact_modify_handler, modify_contact_search_handler, + pas_backend_ldap_process_modify_contact): Likewise + (ldap_search_handler): Use pas_book_view_notify_update + + * backend/pas/pas-backend-vcf.c (foreach_search_compare): Use + pas_book_view_notify_update. + (pas_backend_vcf_process_create_contact): Update for API changes + (pas_backend_vcf_process_modify_contact): Likewise + + * backend/pas/pas-backend-summary.c + (pas_backend_summary_add_contact): Take an EContact instead of a + const char *vcard. + + * backend/ebook/e-contact.c (photo_getter): s/malloc/g_malloc/ + + * backend/ebook/tests/ebook/Makefile.am: + * backend/ebook/tests/vcard/Makefile.am: Make these automake-1.7 + compliant + +2003-10-20 JP Rosevear + + * backend/pas/pas-backend-vcf.c (pas_backend_vcf_search): compiler + with non-c99 compilers + +2003-10-17 Chris Toshok + + * backend/ebook/e-contact.c (fn_getter): new function, just return + the full name value. + (fn_setter): rather distasteful hack. set the N attribute if it's + not already present. + (n_setter): set the X-EVOLUTION-FILE-AS attribute if it's not + already set. + + * backend/pas/pas-backend-ldap.c (prop_info): add PROP_WRITE_ONLY + flag for properties (right now just 'sn') that we don't want to + use when building the EContact - we only use it when storing the + contact out to the ldap server. + (build_contact_from_entry): skip WRITE_ONLY properties. + +2003-10-17 Chris Toshok + + * gui/widgets/e-addressbook-view.c (init_collection): add the + minicard factory back in. + (display_view): add the minicard case back in. + (get_selection_model): same. + (minicard_right_click): resurrect. + (create_minicard_view): same. + (change_view_type): add the minicard case back in. + (eab_view_print): same. + (eab_view_print_preview): same. + + * gui/widgets/e-addressbook-view.h (EABViewType): add MINICARD + back in. + + * gui/widgets/e-addressbook-model.c (eab_model_new): + E_TYPE_AB_MODEL -> EAB_TYPE_MODEL. + + * gui/widgets/e-addressbook-model.h: rename E_TYPE_AB_MODEL to + EAB_TYPE_MODEL. + + * gui/widgets/Makefile.am (libeabwidgets_la_SOURCES): add the + minicard stuff back into the build. + + * gui/widgets/e-addressbook-reflow-adapter.[ch], + gui/widgets/e-minicard-label.[ch], + gui/widgets/e-minicard-view-widget.[ch], + gui/widgets/e-minicard-view.[ch], gui/widgets/e-minicard.[ch], + gui/widgets/gal-view-factory-minicard.[ch], gal-view-minicard.h: + resurrect the minicard stuff, in a new uneditable, + EContact-friendly state. no in-place editing anymore. + + +2003-10-10 Chris Toshok + + * gui/contact-editor/e-contact-editor.c (fill_in_info): un-ifdef + the date handling code. + (extract_info): same. + + * backend/pas/pas-backend-ldap.c (prop_info): add the address + labels and dates to the build. + (anniversary_populate): un-ifdef and get this working. + (anniversary_ber): same. + (anniversary_compare): same. + (birthday_populate): same. + (birthday_ber): same. + (birthday_compare): same. + + * backend/ebook/tests/ebook/.cvsignore, + backend/ebook/tests/ebook/Makefile.am + backend/ebook/tests/ebook/test-date.c: add a test for EContactDate + getting/setting. + + * backend/ebook/e-vcard.h: add EVC_BDAY. + + * backend/ebook/e-contact.h: add prototypes for the + e_contact_date_* functions. + + * backend/ebook/e-contact.c (field_info): add + BIRTH_DATE/ANNIVERSARY fields. + (date_getter): new + (date_setter): new + (e_contact_date_new): new + (e_contact_date_from_string): new + (e_contact_date_to_string): new + (e_contact_date_free): new + +2003-10-10 Not Zed + + * + gui/component/select-names/GNOME_Evolution_Addressbook_SelectNames.server.in.in: + Use the main factory on the .so file, so it can be found. + +2003-10-08 Chris Toshok + + * gui/component/select-names/e-select-names.c (contact_key): add a + descriptive comment about this "#if notyet". + + * gui/component/select-names/e-select-names-model.h + (e_select_names_model_thaw): add prorotype for + e_select_names_model_cancel_all_contact_load. + + * gui/component/select-names/e-select-names-bonobo.c + (_EntryPropertyID): remove the SIMPLE_CARD_LIST property. + (entry_get_property_fn): same. + (impl_SelectNames_get_entry_for_section): same. + + * backend/ebook/e-contact.h: add prototype for + e_contact_name_to_string. + +2003-10-07 Chris Toshok + + * util/eab-book-util.c: remove a bunch of ifdef'ed code (that's + going to be living in e-book.c) + + * backend/pas/pas-backend-summary.c + (pas_backend_summary_add_contact): un-ifdef some code. + (pas_backend_summary_get_summary_vcard): same. + + * backend/pas/pas-backend-ldap.c (prop_info): remove the + query_prop field since we can get it from e_contact_field_name. + also remove it from all the macros and their uses. + (homephone_populate): un-ifdef. + (homephone_ber): same. + (homephone_compare): same. + (business_populate): same. + (business_ber): same. + (business_compare): same. + (query_prop_to_ldap): use e_contact_field_name to get the query + prop for a given attribute. + (add_oc_attributes_to_supported_fields): same. + + * backend/pas/pas-backend-card-sexp.c (compare_phone): use the new + EContactField constants to iterate over the phone list. + + * backend/ebook/e-contact.h (EContactField): add some useful + constants for those pieces of code that iterate over + email/phones/addresses. + +2003-10-07 Chris Toshok + + * gui/widgets/eab-vcard-control.c (book_open_cb): un-ifdef this. + (eab_vcard_control_new): put the buttons above the vcard so they + don't move when it's expanded. + + * gui/widgets/eab-popup-control.h: remove prototypes for + eab_popup_control_set_name and eab_popup_control_set_email. + + * gui/widgets/eab-popup-control.c (email_table_ok_cb): remove the + stupid idle function and do the work here. + (eab_popup_control_set_name): make this static - noone uses it. + (eab_popup_control_set_email): same. + + * gui/widgets/eab-gui-util.c (eab_show_contact_editor): + e_contact_editor_new is what we use for the time being. + + * gui/widgets/eab-contact-display.c (render_string): abstract this + code out. + (render_url): same. + (eab_contact_display_render_normal): make use of render_string and + render_url. + + * gui/widgets/e-addressbook-view.c (delete): un-ifdef this and get + it working. + (selection_received): same. + + * gui/widgets/e-addressbook-model.c (get_view): nuke some code + that was moved to another function. + (eab_model_set_property): get the writable state when we set the + book - don't rely on the timing of signals. + + * gui/contact/editor/contact-editor.glade: add the blog field + below the homepage url field. + + * gui/contact/editor/e-contact-editor-address.[ch]: get this + building with the new stuff. + + * gui/contact/editor/e-contact-editor-fullname.[ch]: get this + building with the new stuff. + + * gui/contact-editor/e-contact-editor.[ch]: get this most of the + way there. + + * gui/contact-editor/e-contact-quick-add.[ch]: get this building + with the new stuff. + + * gui/contact-editor/Makefile.am (libecontacteditor_la_SOURCES): + remove e-contact-save-as.[ch]. They're in + addressbook/widgets/eab-gui-util.[ch] now. + + * gui/merging/Makefile.am: track all the naming changes. + + * gui/merging/*.glade: gratuitous renaming. + + * gui/merging/eab-contact-compare.[ch]: gratuitous renaming, and + move this from the old ebook/ + + * gui/merging/eab-contact-merging.[ch]: gratuitous renaming. + + * backend/ebook/e-contact.[ch]: lots of overly complicated changes + for an overly complicated piece of code. + + * backend/ebook/e-book-view.c (e_book_view_do_added_event): remove + some ifdef'ed code. + (e_book_view_do_modified_event): same. + + * backend/ebook/e-vcard.c (parse): plug a memory leak. + (escape_string): deal with @s being NULL. + (e_vcard_remove_attribute): new function. + (e_vcard_attribute_remove_params): same. + (e_vcard_attribute_param_free): same. + (e_vcard_attribute_param_remove_values): same. + + * backend/ebook/e-vcard.h: add prototypes for + e_vcard_remove_attribute, e_vcard_attribute_remove_params, and + e_vcard_attribute_param_remove_values. + + * backend/ebook/e-book.c (e_book_handle_response): cache the + writable state of the ebook before generating the signal. + (e_book_unload_uri): initialize cap to NULL and writable to FALSE. + + * backend/ebook/e-book.h: add prototype for e_book_is_writable. + + * backend/ebook/e-book-async.c (_get_fields_response_handler): + don't call the callback if it's NULL. + (_get_methods_response_handler): same. + (_auth_user_response_handler): same. + (_get_contact_response_handler): same. + (_remove_contacts_response_handler): same. + (_add_contact_response_handler): same. + (_commit_contact_response_handler): same. + (_get_book_view_response_handler): same. + (_get_contacts_response_handler): same. + (_remove_contacts_dtor): free the list. + (e_book_async_remove_contacts): duplicate the list. + + * backend/pas/pas-backend.c (pas_backend_open): if we successfully + load the uri, report the writable status back. + + * backend/pas/pas-backend-sync.c (_pas_backend_remove_contacts): + free the list of ids. + + * backend/pas/pas-backend-file.c (do_create): return the contact + we create here. + (pas_backend_file_create_contact): format the newly created + contact as a string to add to the summary. + (pas_backend_file_remove_contacts): don't free the list of removed + cards here - it happens in pas-backend-sync. + (pas_backend_file_load_uri): pass NULL for @contact to do_create. + +2003-10-01 Chris Toshok + + * gui/widgets/eab-contact-display.c (render_address): move the :'s + inside the 's. Thanks for pointing this out, guenther. :) + (eab_contact_display_render_normal): same. + (eab_contact_display_render_compact): same. + + * gui/widgets/eab-vcard-control.c (save_in_addressbook): track + change to address_load_default_book. + +2003-10-01 Chris Toshok + + * gui/component/Makefile.am: remove some commented out crap about + e-address-popup.[ch]. + + * gui/component/component-factory.c (factory): use + eab_popup_control_new for the AddressPopup iid. + + * gui/widgets/Makefile.am (libeabwidgets_la_SOURCES): add + eab-popup-control.[ch]. + + * backend/ebook/e-book.c (e_book_get_default_addressbook): hack + this so it at least sorta works - hardcode the + ~/evolution/local/Contacts uri for now. + + * gui/component/addressbook.[ch] (addressbook_load_default_book): + remove the EBook argument, and call + e_book_async_get_default_addressbook. + + * gui/component/e-address-popup.[ch]: nuke. + + * gui/widgets/eab-popup-control.c: rename + gui/component/e-address-popup.c to this. + + * gui/widgets/eab-popup-control.h: rename + gui/component/e-address-popup.h to this. + + * backend/ebook/e-book-async.h: add prototype for + e_book_async_get_default_addressbook. + + * backend/ebook/e-book-async.c + (e_book_async_get_default_addressbook): new function. + +2003-10-01 Chris Toshok + + * gui/widgets/e-addressbook-view.c (eab_view_new): create the + scrolled window to embed the EABContactDisplay widget inside of. + + * gui/widgets/e-addressbook-view.h (struct _EABView): add scrolled; + + * gui/widgets/eab-contact-display.h: add + EABContactDisplayRenderMode enum, and add @render_mode arg to + eab_contact_display_render. + + * gui/widgets/eab-contact-display.c + (eab_contact_display_render_compact): new function, render a + compact format suitable for inclusion in the mail display. + (eab_contact_display_render_normal): move the previouw contents of + eab_contact_display_render here. + (eab_contact_display_render): render in either compact or normal + mode depending on @mode. + (eab_contact_display_new): remove the scrolled window stuff from + here, as in the compact mode we don't want it present. push it up + into the e-addressbook-view.c code. + + * gui/widgets/eab-vcard-control.[ch]: bonobo control that wraps up + the EABContactDisplay stuff and lets us display vcards in a pretty + format in mail messages. + + * gui/component/component-factory.c (factory): replace the #if + notyet'ed minicard control code with the new vcard control. + + * gui/component/Makefile.am (INCLUDES): remove gui/minicard. + + * gui/component/GNOME_Evolution_Addressbook.server.in.in: remove + the MiniCard_Control iid, and replace it with VCard_Control. + +2003-10-01 Chris Toshok + + * gui/component/addressbook-component.c + (destination_folder_handle_drop): use + eab_contact_list_from_string, and un-"#if notyet" this. + + * gui/component/addressbook.c: remove #include + "e-contact-save-as.h" + + * gui/contact-list-editor/e-contact-list-editor.c + (file_save_as_cb): use eab_contact_save. + (file_send_as_cb): use eab_send_contact, un-"#if notyet" this. + (file_send_to_cb): same. + (table_drag_data_received_cb): use eab_contact_list_from_string. + + * gui/widgets/e-addressbook-reflow-adapter.[ch]: nuke. last + vestiges of the minicard view. + + * gui/widgets/e-addressbook-view.c (eab_view_init): + s/clipboard_cards/cliboard_contacts. + (eab_view_dispose): same. + (get_contact_list_1): s/card/contact + (get_contact_list): same. + (save_as): same, and use eab_contact_list_save. + (send_as): reenable this code, s/card/contact, and use + eab_send_contact_list. + (send_to): same. + (print): s/card/contact. + (delete): same. + (new_card): same, and un-"#if notyet" some code. + (selection_get): use eab_contact_list_to_string. + (selection_clear_event): s/card/contact + (selection_received): same. + (get_selected_contacts): same. + (eab_view_save_as): same, and use eab_contact_list_save. + (eab_view_view): same, and use eab_show_multiple_contacts. + (eab_view_send): reenable this code, s/card/contact, and use + eab_send_contact_list. + (eab_view_send_to): same. + (eab_view_copy): s/card/contact. + (view_transfer_contacts): same. + (eab_view_copy_to_folder): same. + (eab_view_move_to_folder): same. + + * gui/widgets/e-addressbook-view.h (struct _EABView): rename + clipboard_cards to clipboard_contacts. + + * gui/widgets/eab-gui-util.c (view_contacts): un-"#if notyet" + (file_exists): moved from e-contact-save-as.c + (save_it): same. + (close_it): same. + (destroy_it): same. + (make_safe_filename): same. + (eab_contact_save): same, and renamed from e_contact_save_as. + (eab_contact_list_save): same, and renamed from + e_contact_list_save_as. + (contact_deleted_cb): s/card/contact. + (do_delete): same, and use e_book_async. + (delete_contacts): s/card/contact. + (process_unref): same. + (contact_added_cb): same. + (do_copy): same, and use e_book_async. + (got_book_cb): same. + (eab_transfer_contacts): same, and use e_book_async. + (eab_send_contact_list): s/card/contact + (eab_send_contact): same. + + * gui/widgets/eab-gui-util.h: some random s/card/contact work, and + move the contents of e-contact-save-as.h here. + + * util/eab-book-util.c (eab_contact_list_from_string): rename + eab_load_contacts_from_string to this. + (eab_contact_list_to_string): new function. + + * util/eab-book-util.h: add prototype for + eab_contact_list_to_string, and rename + eab_load_contacts_from_string to eab_contact_list_from_string. + + * gui/contact-editor/e-contact-save-as.[ch]: nuke. the contents + of these files has been wrapped up in + gui/widgets/eab-gui-util.[ch]. + +2003-09-30 Chris Toshok + + * gui/component/Makefile.am (libevolution_addressbook_la_LIBADD): + add libecontactlisteditor.la back into the build. + + * gui/component/addressbook-component.c (new_item_cb): enable the + contact list editor portion. + + * util/eab-book-util.c (eab_load_contacts_from_string): new + function, return a GList of EContact*'s parsed from the string. + + * util/eab-book-util.h: add prototype for + eab_load_contacts_from_string. + + * gui/contact-list-editor/contact-list-editor.glade: set the id of + the list-image widget. + + * gui/contact-list-editor/e-contact-list-editor.c + (e_contact_list_editor_class_init): PROP_CARD -> PROP_CONTACT. + (e_contact_list_editor_init): initialize image_buf to null and + card -> contact. also, hook up the dnd signals on the list_image + widget so we can drop images. + (e_contact_list_editor_dispose): free the image_buf. + (list_added_cb): card -> contact. + (list_modified_cb): same. + (save_contact): same, and use the ebook-async api. + (prompt_to_save_changes): card -> contact. + (file_save_cb): same. + (file_save_as_cb): same. + (file_send_as_cb): #if notyet for now. + (file_send_to_cb): same. + (tb_save_and_close_cb): card -> contact. + (list_deleted_cb): same. + (delete_cb): same. + (delete_cb): same, and use ebook-async. + (e_contact_list_editor_new): card -> contact. + (e_contact_list_editor_set_property): same. + (table_drag_motion_cb): use GDK_POINTER_TO_ATOM instead of + casting. + (table_drag_data_received_cb): use eab_load_contacts_from_string, + and card -> contact. + (set_image_from_data): new function. create a pixbuf from the + image data and composite it in an image that's the same size as + the initial list_image widget. + (image_drag_motion_cb): new function. + (image_drag_drop_cb): new function. + (image_drag_data_received_cb): new function. + (extract_info): port to EContact, and add support for the image. + (fill_in_info): same. + + * gui/contact-list-editor/e-contact-list-editor.h (struct + _EContactListEditor): add image stuff, and ECard -> EContact. + + * gui/contact-list-editor/e-contact-list-model.c + (contact_list_value_at): e_destination -> eab_destination. + (e_contact_list_model_init): same. + (e_contact_list_model_add_destination): same. + (e_contact_list_model_add_email): same. + (e_contact_list_model_add_contact): same, and card -> contact. + (e_contact_list_model_remove_row): e_destination -> + eab_destination. + (e_contact_list_model_get_destination): same. + + * gui/contact-list-editor/e-contact-list-model.h: card -> contact, + and e-destination -> eab-destination. + + * gui/widgets/e-addressbook-view.etspec: fix a couple of + fields.. this needs a completely once-over at some point soon. + + * gui/widgets/e-addressbook-view.c (table_double_click): reenable + all of this. + + * gui/widgets/eab-contact-display.c (render_address): use + e_text_to_html to convert the \n's to
's. + (on_url_requested): get PHOTO if there is one, otherwise LOGO. + (eab_contact_display_render): escape all the text we're sending to + gtkhtml with e_text_to_html. also, if it's a contact list, output + _("List Members") with the contents of _EMAIL. + + * gui/widgets/eab-gui-util.h: rename eab_send_card{_list} to + eab_send_contact{_list}. + +2003-09-30 Chris Toshok + + * backend/ebook/tests/ebook/Makefile.am (noinst_PROGRAMS): add + test-string. + + * backend/ebook/tests/ebook/test-string.c: test setting/getting a + string attribute. + + * backend/ebook/e-contact.c (photo_setter): do gnome-vfs mime type + sniffing before we set the attribute value. + (e_contact_set_property): implement setting of MULTI list + attributes (like MAIL). + (e_contact_get_property): rework the ATTR_TYPE attribute handling + so we aren't calling g_value_set_pointer on a value that holds a + string (and vice versa). + + * backend/ebook/e-vcard.c (e_vcard_remove_attributes): implement. + (e_vcard_attribute_add_param): use g_ascii_strcasecmp. + + * backend/ebook/e-vcard.h: rename e_vcard_remove_attribute to + e_vcard_remove_attributes, since it removes all matching + attributes. + + * backend/ebook/e-book.c (e_book_response_add_contact): we need to + strdup the id here since the listener frees it. + (e_book_handle_response): implement the WritableStatusEvent part + of the switch. + + * backend/ebook/e-book-listener.c + (impl_BookListener_report_writable): un-"#if notyet" this. + + * backend/ebook/e-book-async.c (_add_contact_handler): fill in + response->id. + +2003-09-29 Chris Toshok + + * printing/e-contact-print-envelope.c: card -> contact. + + * printing/e-contact-print-envelope.h: card -> contact. + + * printing/e-contact-print.c: card -> contact. + + * printing/e-contact-print.h: card -> contact. + + * printing/Makefile.am (contact_print_test_LDADD): add + libeabutil.la and reorder things so it links. + (contact_print_style_editor_test_LDADD): same. + +2003-09-29 Chris Toshok + + * gui/component/select-names/e-select-names-text-model.c: + e-addressbook-util.h -> eab-gui-util.h. + + * gui/component/select-names/e-select-names-popup.c: + e-addressbook-util.h -> eab-gui-util.h. + + * gui/component/e-address-popup.c: e-addressbook-util.h -> + eab-gui-util.h. + + * gui/component/component-factory.c: #if notyet the minicard + control stuff, since it's been completely nuked from the tree. + + * gui/component/addressbook.c: e-addressbook-util.h -> + eab-gui-util.h. + + * gui/component/addressbook-component.c: e-addressbook-util.h -> + eab-gui-util.h. + + * gui/component/Makefile.am (libevolution_addressbook_la_LIBADD): + rename libeminicard to libeabwidgets. + + * Makefile.am (SUBDIRS): add util/ to the build. + +2003-09-29 Chris Toshok + + * gui/widgets/e-addressbook-treeview-adapter.c: + e-addressbook-util.h -> eab-gui-util.h, and convert some + EDestination code to EABDestination. + + * gui/widgets/e-addressbook-table-adapter.c: e-addressbook-util.h + -> eab-gui-util.h, and include util/eab-destination.h. + (addressbook_value_at): un-#if 0 some code. + + * gui/widgets/e-addressbook-model.c: e-addressbook-util.h -> + eab-gui-util.h + + * gui/widgets/e-addressbook-view.c: e-addressbook-util.h -> + eab-gui-util.h + + * gui/widgets/e-minicard-control.c, + gui/widgets/e-minicard-control.h, gui/widgets/e-minicard-label.c, + gui/widgets/e-minicard-label.h, + gui/widgets/e-minicard-view-widget.c, + gui/widgets/e-minicard-view-widget.h, + gui/widgets/e-minicard-view.c, gui/widgets/e-minicard-view.h, + gui/widgets/e-minicard-widget-test.c, + gui/widgets/e-minicard-widget.c, gui/widgets/e-minicard-widget.h, + gui/widgets/e-minicard.c, gui/widgets/e-minicard.h, + test-minicard-label.c, test-minicard-view.c, test-minicard.c: nuke + all of the old minicard stuff. + + * gui/widgets/eab-gui-util.[ch]: rename e-addressbook-util.[ch] to + this and nuke e-addressbook-util.[ch]. + + * gui/widgets/Makefile.am (INCLUDES): change G_LOG_DOMAIN to + eab-widgets, and add -I$(top_srcdir)/addressbook. + (noinst_LTLIBRARIES): rename to libeabwidgets.la + (libeabwidgets_la_SOURCES): rename e-addressbook-util.[ch] to + eab-gui-util.[ch]. + +2003-09-29 Chris Toshok + + * gui/widgets/eab-contact-display.c (eab_contact_display_new): + track change from E_TYPE_AB_CONTACT_DISPLAY to + EAB_TYPE_CONTACT_DISPLAY. + + * gui/widgets/eab-contact-display.h: change from E_* type foo to + EAB_* type foo. + +2003-09-29 Chris Toshok + + * gui/search/e-addressbook-search-dialog.[ch]: convert everything + from e_addressbook_search_dialog to eab_search_dialog, and + EAddressbookSearchDialog to EABSearchDialog. + + * gui/component/addressbook.c (search_cb): + e_addressbook_search_dialog -> eab_search_dialog. + (addressbook_search_activated): same. + (addressbook_query_changed): same. + +2003-09-29 Chris Toshok + + * backend/pas/pas-book.c (pas_book_respond_get_supported_fields): + don't free the fields here - the backends hold onto them. + (pas_book_respond_get_supported_auth_methods): don't free the + auth_methods here - the backends hold onto them. + + * backend/pas/pas-backend-file.c + (pas_backend_file_get_supported_fields): fields go from 1 to + E_CONTACT_FIELD_LAST, not 0. + +2003-09-29 Chris Toshok + + * gui/component/addressbook.c: e-book-util.h -> eab-book-util.h + + * gui/component/addressbook-component.c: e-book-util.h -> + eab-book-util.h. + (new_item_cb): enable the contact editor portion of this. + (user_create_new_item_cb): convert to async_load_uri api, and + ifdef the _use_default_book crap. + (ensure_completion_uris_exist): e_book_get_config_database -> + eab_get_config_database. + + * gui/component/e-address-widget.h: e-book-util.h -> + eab-book-util.h. + + * gui/component/Makefile.am (libevolution_addressbook_la_LIBADD): + add selectnames back in, and add util/libeabutil.la. + +2003-09-29 Chris Toshok + + * backend/ebook/e-contact.c: my head explodes from so many + changes. + + * backend/ebook/e-contact.h: reorder fields such that all the + string fields are first in the enum (and add a + E_CONTACT_LAST_SIMPLE_STRING value, ala the old e-card-simple + stuff.) Also, add E_CONTACT_LOGO, WANTS_HTML, IS_LIST, and + LIST_SHOW_ADDRESSES. remove E_CONTACT_PHOTO_URI. + + * backend/ebook/e-vcard.c (e_vcard_remove_attribute): rename from + e_card_remove_attribute, and add a g_assert_not_reached. + (_evc_base64_encode_simple): make this not static (we need it for + a test.) + (_evc_base64_decode_simple): same. + + * backend/ebook/e-vcard.h: add LOGO, X-MOZILLA-HTML, + X-EVOLUTION-LIST, and X-EVOLUTION-LIST-SHOW_ADDRESSES #defines. + + * backend/ebook/e-book.c (EBookLoadState): change from + UriNotLoaded to E_BOOK_URI_NOT_LOADED, etc. + (e_book_add_contact): track _URI_ change. + (e_book_get_supported_fields): same. + (e_book_get_supported_auth_methods): same. + (e_book_authenticate_user): same. + (e_book_get_contact): same. + (e_book_response_get_contact): remove the ifdefed call to + e_contact_set_book. + (e_book_remove_contacts): track _URI_ change. + (e_book_get_book_view): same. + (e_book_get_contacts): same. + (e_book_get_changes): same. + (e_book_remove): same. + (e_book_unload_uri): same. + (e_book_load_uri): same. + (e_book_load_uri): same. + (e_book_get_self): start the implementation of this. + (e_book_get_default_addressbook): ifdef out a possible + implementation of this (it's broken.) + (e_book_init): track _URI_ change. + (e_book_dispose): same. + + * backend/ebook/e-book.h: move get_default_addressbook out of the + ifdef, and change get_default_addressbook/get_addressbooks to be + more like the rest of the api. + + * backend/ebook/e-book-util.[ch]: nuke. + + * backend/ebook/e-card-compare.[ch]: nuke. + + * backend/ebook/e-destination.[ch]: nuke. + + * backend/ebook/e-book-query.c (func_and): fix valgrind error. + (func_or): same. + + * backend/ebook/e-book-listener.h: drop #include of e-list.h + + * backend/ebook/e-book-async.c (_get_contacts_response_handler) + (_get_contacts_response_dtor, _get_contacts_handler) + (_get_contacts_dtor, e_book_async_get_contacts): new functions, + implementing e_book_async_get_contacts. + + * backend/ebook/e-book-async.h: add e_book_async_get_contacts. + +2003-09-29 Chris Toshok + + * util/eab-marshal.list: new file. + + * util/eab-destination.[ch]: rename + backend/ebook/e-destination.[ch] to this, and change all the entry + point names too. + + * util/eab-book-util.[ch]: rename backend/ebook/e-book-util.[ch] + to this, and change all the entry point names too. + + * util/Makefile.am: new file, build libeabutil.la + +2003-09-29 Chris Toshok + + * gui/component/select-names/e-select-names.c + (addressbook_model_set_uri): e_addressbook_model -> eab_model. + (contact_key): e-contactify this, and remove the call to + e_contact_get_book since we don't have it. + (sync_one_model): card -> contact. + (real_add_address_cb): track various name changes. + (esn_get_key_fn): same. + (e_addressbook_create_ebook_table): same. + (folder_selected): same. + (select_entry_changed): same. + (e_select_names_new): same. + + * gui/component/select-names/e-select-names-text-model.c + (dump_model): s/card/contact. + (e_select_names_text_model_insert_length): e-destination -> + eab-destination. + (e_select_names_text_model_delete): same. + (e_select_names_text_model_obj_count): same. + (nth_obj_index): same. + (e_select_names_text_model_activate_obj): ifdef this out since we + don't have e_contact_get_book in the new api. + + * gui/component/select-names/e-select-names-table-model.c + (fill_in_info): convert to e_contact/eab_destination. + + * gui/component/select-names/e-select-names-popup.c + (change_email_num_cb): e_destination -> eab_destination. + (populate_popup_contact): same, and ECard -> EContact. Also, the + email attribute is a GList, not an EList. lastly, rename from + populate_popup_card. + (populate_popup_nocontact): same, and rename from + populate_popup_nocard. + (e_select_names_populate_popup): same. + + * gui/component/select-names/e-select-names-model.h: track changes + to e_destination, and rename the cardify methods to something mode + descriptive. + + * gui/component/select-names/e-select-names-model.c + (e_select_names_model_duplicate): e_destination -> + eab_destination. + (e_select_names_model_get_textification): same. + (e_select_names_model_get_address_text): same. + (e_select_names_model_get_destination): same. + (e_select_names_model_export_destinationv): same. + (send_changed): same. + (e_select_names_model_import_destinationv): same. + (e_select_names_model_get_contact): same, and rename from + _get_card + (e_select_names_model_get_string): same. + (connect_destination): same. + (disconnect_destination): same. + (e_select_names_model_contains): same. + (e_select_names_model_insert): same. + (e_select_names_model_append): same. + (e_select_names_model_replace): same. + (e_select_names_model_delete): same. + (e_select_names_model_clean): same. + (delete_all_iter): same. + (e_select_names_model_overwrite_copy): same. + (e_select_names_model_merge): same. + (e_select_names_model_name_pos): same. + (e_select_names_model_text_pos): same. + (e_select_names_model_cardify): nuke. + (e_select_names_model_uncardify): nuke. + (e_select_names_model_cancel_cardify): nuke. + (e_select_names_model_load_all_contacts): rename _cardify_all to + this. + (e_select_names_model_cancel_all_contact_load): rename + _cancel_cardify to this. + + * gui/component/select-names/e-select-names-manager.c + (focus_in_cb): cancel_cardify_all -> cancel_all_contact_load + (focus_out_cb): cardify_all -> load_all_contacts. + (completion_popup_cb): same. + (load_completion_books): no e_book_expand_uri anymore. + (e_select_names_manager_new): e_book_get_config_database -> + eab_get_config_database. + (e_select_names_manager_dispose): same. + + * gui/component/select-names/e-select-names-completion.h: e-book.h + -> e-book-async.h + + * gui/component/select-names/e-select-names-completion.c: + EContactify this. + + * gui/component/select-names/e-select-names-bonobo.c + (entry_get_property_fn): ifdef out the SIMPLE_CARD_LIST getter, + and cardify_all -> load_all_contacts. + + * gui/component/select-names/Evolution-Addressbook-SelectNames.idl: + nuke all the SimpleCard stuff. It's a horribly inefficient way to + deal with vcards, and since ebook is platform level now, we can + (and should) promote just linking to ebook to do this. + 2003-09-19 Gilbert Fang * addressbook/gui/component/addressbook-component.c (xfer_folder): @@ -12,17 +902,715 @@ non-static versions of libraries: the static ones were only needed for libtool 1.3. +2003-09-07 Chris Toshok + + * backend/ebook/e-contact.c (e_contact_get_property): implement + getters for the address labels. they aren't really synthetic, but + we can't handle them as normal strings because they switch off the + TYPE parameter, not the attribute name (go go vcard.) Also add + getters for the structured address fields (ADR). Also fix a spot + where we were using strcmp instead of strcasecmp. + (e_contact_address_free): new function. + + * backend/ebook/e-contact.h: Add EContactAddress structure, which + will probably go away once i merge in my cool spiffy address + editor. Add LABEL fields for the address labels, and add + prototype for e_contact_address_free. + + * backend/ebook/e-vcard.h: add EVC_LABEL and EVC_X_BLOG_URL. + + * backend/ebook/e-vcard.c (read_attribute_value): step to the next + character after unescaping \-escaped characters. keeps commas + from multiplying. + + * gui/widgets/eab-contact-display.c (render_address): new function + (eab_contact_display_render): display email, delivery addresses, + and the blog url. + +2003-09-06 Chris Toshok + + * backend/ebook/e-contact.c (e_contact_set_property): implement + E_CONTACT_EMAIL_*. + + * backend/pas/pas-backend-ldap.c (email_ber): EContact-ify and + re-enable this code. + (email_compare): same. + (email_populate): same. + + * backend/pas/pas-backend-vcf.c (pas_backend_vcf_load_uri): use + XIMIAN_VCARD. + + * backend/pas/pas-backend-file.c (pas_backend_file_load_uri): use + XIMIAN_VCARD, and don't fail if the directory already exists. + just try to create the db anyway. + + * backend/pas/Makefile.am (libpas_a_SOURCES): add ximian-vcard.h + + * backend/pas/ximian-vcard.h (XIMIAN_VCARD): put the initial vcard + here, so we can share 1 #define between file/vcf backends. Also, + add a jpeg photo. + +2003-09-06 Chris Toshok + + * gui/widgets/Makefile.am (libeminicard_la_SOURCES): add + eab-contact-display.[ch] + + * gui/widgets/e-addressbook-view.c (eab_view_init): just init + everything to NULL. + (eab_view_new): move a bunch of stuff that was in eab_view_init + here. create a vpaned to hold the contact display, and create the + contact display. + (render_contact): render the selected contact to the + contact_display. + (selection_changed): add logic to display the currently selected + contact in the preview pane. + (create_table_view): add the table to the paned. + (create_treeview_view): add the scrolled to the paned. + (change_view_type): remove view->widget from the paned. + + * gui/widgets/e-addressbook-view.h: switch from using a GtkTable + to a GtkEventBox - we don't need the table logic anymore. + + * gui/widgets/e-addressbook-model.c (create_contact): indent + (eab_model_get_contact): same. + + * gui/widgets/eab-contact-display.[ch]: new files - this + implements the preview pane. + +2003-09-06 Chris Toshok + + * backend/pas/pas-backend-ldap.c (BINARY_PROP): new type of + property, for specifying data coming back from the ldap server + with both data/length (like photos). + (photo_populate): set the contact's photo. + (build_contact_from_entry): add PROP_TYPE_BINARY handling. + + * backend/ebook/e-vcard.c (EVCardEncoding): new enum for use with + the ENCODING attribute parameter. Right now, just "raw", + "base64", and "quoted-printable". + (struct _EVCardAttribute): add a "decoded_values" list of + GString*'s, as well as fields to hold encoding/encoding_set. + (e_vcard_class_init): call _evc_base64_init. + (e_vcard_attribute_add_value_decoded): based on what encoding the + attribute uses, add the value properly. + (e_vcard_attribute_add_param): if the parameter is ENCODING, work + our magic. + (e_vcard_attribute_get_values_decoded): spit out properly decoded + values depending on the decoding type. + (_evc_base64*): copy the camel base64 routines here. + + * backend/ebook/e-vcard.h: add prototypes for + e_vcard_attribute_add_value_decoded and + e_vcard_attribute_get_values_decoded. + + * backend/ebook/e-contact.c (e_contact_get_first_attr): move this + to above _set_property so we can make use of it there. + (e_contact_set_property): fix up the generic STRING field handler, + and implement E_CONTACT_PHOTO setting. + (e_contact_get_property): add handling for + E_CONTACT_PHOTO/E_CONTACT_PHOTO_URI. + (e_contact_photo_free): new function. + + * backend/ebook/e-contact.h: add EContactPhoto struct, a prototype + for e_contact_photo_free, and two new EContactField elements (PHOTO and + PHOTO_URI). + + * backend/ebook/tests/ebook/.cvsignore: ignore test-photo + + * backend/ebook/tests/ebook/Makefile.am (noinst_PROGRAMS): add test-photo + + * backend/ebook/tests/ebook/test-photo.c: test for the photo + set/get routines (which do base64 encoding/decoding). + +2003-09-02 Chris Toshok + + * gui/component/Makefile.am: comment out a buncha stuff just to + get this building. + + * gui/component/select-names/e-select-names.c: #include + e-book-async.h + (search_result): EAddressbookModel -> EABModel. + (addressbook_model_set_uri): same, and don't use + e_book_expand_uri, as it's dead. + (esn_get_key_fn): EAddressbookModel -> EABModel. + (e_addressbook_create_ebook_table): same. + (status_message): same. + + * gui/component/select-names/e-select-names.h (struct + _ESelectNames): EAddressbookModel -> EABModel. + + * gui/component/addressbook-component.c (new_item_cb): ifdef out + for now. + (dnd_drop_book_open_cb): s/card/contact. + (destination_folder_handle_drop): ifdef out. + (request_quit): same. + + * gui/component/addressbook.c: track api changes - e_addressbook_ + -> eab_, and e_book_* becomes e_book_async_*. + + * gui/component/addressbook.h: #include e-book-async.h + + * gui/component/e-address-widget.c (query_results_cb): + e/EBookSimpleQueryStatus/EBookStatus + + * gui/component/e-address-widget.h: s/ECard/EContact. + + * gui/component/e-cardlist-model.[ch]: nuke. + + * gui/component/e-address-popup.c: s/e-book.h/e-book-async.h + + * gui/component/e-address-popup.h: s/ECard/EContact + +2003-09-02 Chris Toshok + + * backend/ebook/Makefile.am (libebook_la_SOURCES): remove + e-card.c,e-card.simple.c + + * backend/ebook/tests/ebook/test-ebook.c: remove #include of + e-card-simple.h + + * backend/ebook/tests/ebook/test-changes.c: remove #include of + e-card-simple.h + + * backend/ebook/e-card.[ch], backend/ebook/e-card-simple.[ch]: + nuke. + + * backend/ebook/e-book-util.h: s/card/contact. + + * backend/ebook/e-book-util.c: ifdef out an #include. + + * backend/ebook/e-book-async.[ch]: stop doing the stupid #define + renaming trick, and just rename all the prototypes from e_book_* + to e_book_async_*. Also, get rid of the *_vcard variants. + +2003-09-02 Chris Toshok + + * backend/pas/pas-backend-card-sexp.[ch] + (pas_backend_card_sexp_match_contact): rename + pas_backend_card_sexp_match_card, and it takes an EContact now. + Also, port this file to use EContact instead of ECard, and ifdef + out lots of stuff. + + * backend/pas/pas-backend-ldap.c: convert this to use EContact + instead of ECard, and ifdef great swaths of code to make it + compile. + + * backend/pas/pas-book.c (pas_book_respond_modify): convert this + from ECard to EContact. + +2003-09-02 Chris Toshok + + * gui/widgets/Makefile.am (libeminicard_la_SOURCES): remove all + the reflow/minicard stuff from the build. + (e-addressbook-marshal.[ch]): change the prefix on the marshallers to + eab_marshal. + + * gui/widgets/e-addressbook-view.etspec: bring this more in line + with the field ids for EContact, and comment out a ton of them + that aren't there yet. + + * gui/widgets/e-addressbook-view.[ch]: big renaming - rename + e_addressbook_view to eab_view, and EAddressbookView to EABView. + + * gui/widgets/e-addressbook-util.c (eab_error_dialog): rename, and + change a few of the error strings s/Card/Contact. + (added_cb): E_BOOK_STATUS_SUCCESS => E_BOOK_ERROR_OK. + (modified_cb): same. + (e_addressbook_show_contact_editor): this takes an EContact now, + and track the change to the contact editor signal names. + (e_addressbook_show_contact_list_editor): this takes an EContact + now. + (view_contacts): rename view_cards to this, and ifdef the body. + (e_addressbook_show_multiple_contacts): rename + e_addressbook_show_multiple_cards to this, and s/card/contact. + + * gui/widgets/e-addressbook-util.h: ifdef some things out, and + rename e_addressbook_error_dialog to eab_error_dialog. + + * gui/widgets/e-addressbook-table-adapter.[ch]: big renaming - + rename e_addressbook_table_adapter to eab_table_adapter, and + EAddressbookTableAdapter to EABTableAdapter. Also, remove the + simple mapping - we can do ECardSimple-like operations directly on + the EContacts from the EABModel. + + * gui/widgets/e-addressbook-model.[ch]: big renaming - rename + e_addressbook_model to eab_model, and EAddressbookModel to + EABModel. Also, convert everything from ECard to EContact. + +2003-09-01 Chris Toshok + + * backend/ebook/e-vcard.c (e_vcard_new_from_string): omg i'm dumb. + don't call e_vcard_new here since it just turns around and calls + e_vcard_new_from_string again. + +2003-09-01 Chris Toshok + + * backend/pas/pas-book-view.c (pas_book_view_notify_change): guard + pending adds foo. + (pas_book_view_notify_remove): same. + (pas_book_view_notify_add): same. + (pas_book_view_notify_complete): same. + (pas_book_view_construct): init mutex + (pas_book_view_dispose): free mutex + + * backend/pas/pas-backend-ldap.c (func_exists): new function. + (send_pending_adds): remove + (ldap_search_handler): let the BookView stuff handle the pending + adds for us. + (ldap_search_dtor): remove pending adds stuff. + (pas_backend_ldap_search): same + + * backend/pas/pas-backend-card-sexp.c (func_exists): new function. + + * backend/ebook/tests/ebook/test-ebook.c (print_all_emails): use + an exists query. + +2003-08-31 Chris Toshok + + * backend/ebook/e-book-query.c (func_and, func_or, func_not) + (func_contains, func_is, func_beginswith, func_endswith) + (e_book_query_from_string): adapt the pas ldap backend sexp + parsing code to this, build up an EBookQuery that represents the + sexp. + + * backend/ebook/e-contact.h (e_contact_field_id): add prototype. + + * backend/ebook/e-contact.c (e_contact_field_id): new function. + + * backend/ebook/Makefile.am (libebook_la_SOURCES): add + e-book-util.c back into the build, if only for the config_database + thingy. + +2003-08-31 Chris Toshok + + * backend/ebook/e-contact.c (e_contact_duplicate): new function. + + * backend/ebook/e-contact.h: add prototype for + e_contact_duplicate. + + * backend/ebook/e-book-util.[ch]: massive ifdeffing. most of this + is either gone or will be unnecessary soon. + + * backend/ebook/e-book-query.c (e_book_query_from_string): hack + this so it'll at least generate a query. + + * backend/ebook/e-book-listener.c + (impl_BookListener_respond_get_view): add some debug spew and + remove a c&p'ed comment. + + * backend/ebook/e-book-async.h: add prototype for + e_book_async_unload_uri. + + * backend/ebook/e-book-async.c (e_book_async_unload_uri): new + function. + + * backend/pas/pas-book-view.c (pas_book_view_construct): switch to + CORBA_Object_duplicate, ala pas_book. + + * backend/pas/pas-backend-sync.c (pas_backend_sync_class_init): + fix typo and the build. + +2003-08-29 Chris Toshok + + * backend/pas/pas-backend-ldap.c (ldap_error_to_response): + s/card/contact. + (pas_backend_ldap_process_create_contact): same. + (remove_contact_handler): same. + (remove_contact_dtor): same. + (pas_backend_ldap_process_remove_contacts): same. + (modify_contact_modify_handler): same. + (modify_contact_dtor): same. + (pas_backend_ldap_process_modify_contact): same. + (get_contact_handler): same. + (get_contact_dtor): same. + (pas_backend_ldap_process_get_contact): same. + (pas_backend_ldap_class_init): same. + + * backend/pas/pas-backend-summary.c + (pas_backend_summary_add_contact): s/card/contact, and mostly + switch from ECard{Simple} to EContact. + (pas_backend_summary_get_summary_vcard): same. + (pas_backend_summary_remove_contact): s/card/contact + + * backend/pas/pas-backend-summary.h: s/card/contact. + + * backend/pas/pas-backend-file.c (build_summary): fix g_warning, + and return immediately if the db->cursor call fails. + (pas_backend_file_create_contact): s/card/contact + (pas_backend_file_remove_contacts): same. + (pas_backend_file_modify_contact): same. + (pas_backend_file_get_contact): same. + (pas_backend_file_get_contact_list): same. + (pas_backend_file_class_init): same. + + * backend/pas/pas-backend-vcf.c + (pas_backend_vcf_process_create_contact): s/card/contact. + (pas_backend_vcf_process_remove_contacts): same. + (pas_backend_vcf_process_modify_contact): same. + (pas_backend_vcf_process_get_contact): same. + (pas_backend_vcf_process_get_contact_list): same. + (pas_backend_vcf_class_init): same. + + * backend/pas/pas-backend-sync.c (pas_backend_sync_create_contact): s/card/contact. + (pas_backend_sync_remove_contacts): same. + (pas_backend_sync_modify_contact): same. + (pas_backend_sync_get_contact): same. + (pas_backend_sync_get_contact_list): same. + (_pas_backend_create_contact): same. + (_pas_backend_remove_contacts): same. + (_pas_backend_modify_contact): same. + (_pas_backend_get_contact): same. + (_pas_backend_get_contact_list): same. + (pas_backend_sync_class_init): same. + + * backend/pas/pas-backend-sync.h: s/card/contact. + + * backend/pas/pas-backend.c (pas_backend_create_contact): s/card/contact. + (pas_backend_remove_contacts): same. + (pas_backend_modify_contact): same. + (pas_backend_get_contact): same. + (pas_backend_get_contact_list): same. + (pas_backend_change_add_new): same. + (pas_backend_change_modify_new): same. + (pas_backend_change_delete_new): same. + + * backend/pas/pas-backend.h: s/card/contact. + + * backend/pas/pas-book-view.c (send_pending_adds): s/card/contact + (pas_book_view_notify_change): same. + (pas_book_view_notify_remove): same. + + * backend/pas/pas-book.c + (impl_GNOME_Evolution_Addressbook_Book_getContact): s/card/contact + (impl_GNOME_Evolution_Addressbook_Book_getContactList): same. + (impl_GNOME_Evolution_Addressbook_Book_addContact): same. + (impl_GNOME_Evolution_Addressbook_Book_removeContacts): same. + (impl_GNOME_Evolution_Addressbook_Book_modifyContact): same. + (pas_book_respond_create): same. + (pas_book_respond_remove_contacts): same. + (pas_book_respond_modify): same. + (pas_book_respond_get_contact): same. + (pas_book_respond_get_contact_list): same. + (pas_book_respond_get_changes): same. + (pas_book_class_init): same. + + * backend/pas/pas-book.h: s/card/contact + + * backend/ebook/tests/vcard/dump-vcard.c: #include + "ebook/e-vcard.h" + + * backend/ebook/tests/vcard/Makefile.am (TEST_LIBS): use + top_builddir. + (CFLAGS): same. + + * backend/ebook/tests/ebook/Makefile.am (TEST_LIBS): use + top_builddir. + (CFLAGS): use srcdir + + * backend/ebook/test-card.c, backend/ebook/test-client-list.c, + backend/ebook/test-client.c, backend/ebook/test-ebook.c: remove. + + * backend/ebook/e-card-cursor.[ch]: remove. + + * backend/ebook/e-card-pairs.h: remove. + + * backend/ebook/e-book.c (e_book_add_contact): s/Card/Contact. + (e_book_commit_contact): same + (e_book_get_contact): same. + (e_book_remove_contacts): same. + (e_book_get_contacts): same. + (e_book_handle_response): same. + + * backend/ebook/e-book-view.c (e_book_view_do_added_event): + s/card/contact + (e_book_view_do_modified_event): same. + (e_book_view_do_removed_event): same. + (e_book_view_handle_response): same. + (e_book_view_class_init): same. + + * backend/ebook/e-book-view.h: s/card/contact and pad the class + struct. + + * backend/ebook/e-book-view-listener.c + (e_book_view_listener_queue_response): s/Card/Contact. + (e_book_view_listener_queue_status_event): no need to assign + things to NULL, we g_new0. + (e_book_view_listener_queue_idlist_event): s/Card/Contact, and no + need to assign things to NULL, we g_new0. + (e_book_view_listener_queue_sequence_event): same. + (e_book_view_listener_queue_message_event): same. + (impl_BookViewListener_notify_contacts_added): s/Card/Contact. + (impl_BookViewListener_notify_contacts_removed): same. + (impl_BookViewListener_notify_contacts_changed): same. + (e_book_view_listener_class_init): same. + + * backend/ebook/e-book-view-listener.h: s/Card/Contact + + * backend/ebook/e-book-types.h: s/CARD/CONTACT + + * backend/ebook/e-book-listener.c + (e_book_listener_convert_status): s/Card/Contact + (impl_BookListener_respond_create_contact): same. + (impl_BookListener_respond_remove_contacts): same. + (impl_BookListener_respond_modify_contact): same. + (impl_BookListener_respond_get_contact): same. + (impl_BookListener_respond_get_contact_list): same. + (impl_BookListener_respond_get_changes): same. + (e_book_listener_class_init): same. + + * backend/ebook/e-book-listener.h: pad the class struct, and + s/Card/Contact. + + * backend/ebook/e-book-async.c (_load_uri_handler): GError + changes. + (_get_fields_handler): same. + (_get_methods_handler): same. + (_auth_user_handler): same. + (_get_card_handler): same. + (_remove_cards_handler): same. + (_add_vcard_handler): same. + (_commit_vcard_handler): same. + (_get_book_view_handler): same. + (e_book_async_get_book_view): use an EBookQuery instead of a char*. + + * backend/ebook/Makefile.am: remove the test handling. + (SUBDIRS): set to ". tests" + (libebook_la_SOURCES): add e-book-async.c + + * backend/idl/addressbook.idl: possibly gratuitous renaming, but i + was sick of seeing "Card" being used everywhere. "Contact" is the + new "Card". + +2003-08-28 Chris Toshok + + * backend/ebook/e-book.c (e_book_op_free): rename from + e_book_free_op. + (e_book_op_remove): rename from e_book_remove_op. + (e_book_clear_op): new function, remove the op, unlock its mutex, + and free it. + (e_book_add_contact): use e_book_clear_op. + (e_book_commit_contact): same. + (e_book_get_supported_fields): same. + (e_book_get_supported_auth_methods): same. + (e_book_authenticate_user): same. + (e_book_get_contact): same. + (e_book_remove_contacts): same. + (e_book_get_book_view): same. + (e_book_get_contacts): same. + (e_book_get_changes): same. + (e_book_load_uri): same. + (e_book_remove): new function. + (e_book_response_remove): new function. + (e_book_handle_response): add handling for RemoveBookResponse. + (e_book_load_local_addressbook): pass TRUE for e_book_load_uri + @only_if_exists. + + * backend/ebook/e-book.h: add @only_if_exists arg to + e_book_load_uri so we can support folder creation at load_uri + time, and add prototype for e_book_remove. + + * backend/ebook/e-book-types.h: add an "id" slot in EBookChange. + + * backend/ebook/e-book-listener.c + (impl_BookListener_respond_get_changes): handle union in idl. + (impl_BookListener_respond_open_book): remove unnecessary + exception check. + (impl_BookListener_respond_remove_book): new function. + (impl_BookListener_respond_get_supported_fields): rename this from + _response_. + (impl_BookListener_respond_get_supported_auth_methods): same. + (e_book_listener_class_init): add _remove_book and track change to + get_supported_fields/get_supported_auth_methods names. + + * backend/ebook/e-book-listener.h: add RemoveBookResponse to + EBookListenerOperation enum. + + * backend/idl/addressbook.idl: make BookChangeItem a union that + switches over BookChangeType. + + * backend/pas/pas-backend.c (pas_backend_change_add_new): new + function, create a BookChangeItem representing the addition of a + contact. + (pas_backend_change_modify_new): same, but for modifications. + (pas_backend_change_delete_new): same, but for deletions. + + * backend/pas/pas-backend.h: add prototypes for + pas_backend_change_{add,modify,delete}_new + + * backend/pas/pas-backend-file.c (pas_backend_file_changes): nuke. + (do_create): fix memory corruption. + (pas_backend_file_get_changes): copy the body of + pas_backend_file_changes here, and rework so that it's synchronous + and return a list instead of the book view hack. + (pas_backend_file_load_uri): mkdir the directory (we need a mkdir + -p here). + (select_changes): new function, scandir helper. + (pas_backend_file_remove): NULL out bf->priv->summary to quiet + valgrind, and call scandir to accumulate the .changes.db files + then unlink them. + + * backend/pas/pas-book.c (pas_book_respond_remove): new function. + (pas_book_respond_get_supported_fields): unifdef this, and make it + use a glist. + (pas_book_respond_get_supported_auth_methods): same. + (pas_book_respond_get_changes): this code is kinda gross... lots + of copying going on, there's got to be a better way. but it + works. + +2003-08-26 Chris Toshok + + * backend/idl/addressbook.idl: add oneway void Book::remove() and + oneway void notifyBookRemoved() + +2003-08-26 Chris Toshok + + * backend/pas/pas-backend.c (pas_backend_remove): new function. + (pas_backend_add_book_view): new function. + (pas_backend_add_client): move the "real_add_client" code here. + (pas_backend_remove_client): move the "real_remove_client" code + here. + (pas_backend_class_init): remove assignments of add_client and + remove_client vtable entries. + (pas_backend_is_removed): new function. + (pas_backend_set_is_removed): new function. + (pas_backend_init): init clients_mutex and views_mutex. + + * backend/pas/pas-backend.h: remove the vtable entries for + add/remove_client, since these are fully handled in PASBackend. + Add prototypes for + pas_backend_is_removed/pas_backend_add_book_view/pas_backend_set_is_removed. + + * backend/pas/pas-book.c + (impl_GNOME_Evolution_Addressbook_Book_remove): new function. + (impl_GNOME_Evolution_Addressbook_Book_getBookView): clean things + up a bit, and don't use pas_backend_get_book_views as it can't + lock the list of views. + (pas_book_respond_get_supported_auth_methods): remove the extra + unnecessary arg from the corba call. + (pas_book_respond_get_changes): same. + (pas_book_class_init): fill in epv "remove" slot. + + * backend/pas/pas-book.h: rename pas_book_respond_remove to + pas_book_respond_remove_cards, and add a new + pas_book_respond_remove for use with removing books. + + * backend/pas/pas-backend-sync.c (pas_backend_sync_remove): new + function. + (_pas_backend_remove): new function. + (pas_backend_sync_class_init): fill in the "remove" vtable entry. + (_pas_backend_remove_cards): track change to + pas_book_respond_remove_cards (pas_book_respond_remove is used for + removing the book, not the cards.) + + * backend/pas/pas-backend-sync.h: add pas_backend_sync_remove + prototype and add remove_sync virtual function. + +2003-08-26 Chris Toshok + + * backend/pas/pas-backend-file.c (pas_backend_file_create_card, + pas_backend_file_remove_cards, pas_backend_file_modify_card, + pas_backend_file_get_vcard, pas_backend_file_get_card_list, + pas_backend_file_start_book_view, pas_backend_file_get_changes, + pas_backend_file_authenticate_user, + pas_backend_file_get_supported_fields): rename from + pas_backend_file_process_* + (pas_backend_file_load_uri): save off the dirname/summary + filename. + (pas_backend_file_remove): new function, unlink all the files we + know about. + (pas_backend_file_class_init): track changes to functions, and add + pas_backend_file_remove. + 2003-08-26 JP Rosevear - * conduit/address-conduit.c (ecard_from_remote_record): duplicate + * conduit/address-conduit.c (ecard_from_remote_record): duplicate the extra address lines +2003-08-22 Chris Toshok + + * backend/pas/pas-book.[ch]: switch from using the PASRequest + union and a central PASBackend dispatch function. just call the + pas_backend methods directly and expand the args out. + + * backend/pas/pas-backend.[ch]: same. + + * backend/pas/pas-backend-sync.[ch]: same. + + * backend/pas/pas-backend-vcf.c, backend/pas/pas-backend-file.c, + backend/pas/pas-backend-ldap.c: same, and get these all compiling + against the rest of the current pas/ebook code. + +2003-08-21 Chris Toshok + + * backend/ebook/test-ebook.c: track GError case. + + * backend/ebook/e-book.[ch]: GError-ify the api, and clean up some + cases where we weren't removing the current op. + + * backend/ebook/e-book-view-listener.c + (e_book_view_listener_convert_status): track change from + E_BOOK_VIEW_STATUS_* to E_BOOK_VIEW_ERROR_*. + + * backend/ebook/e-book-types.h: track change from E_BOOK_STATUS_* + to E_BOOK_ERROR_*, and some E_BOOK_VIEW_STATUS_* to + E_BOOK_VIEW_ERROR_*. + + * backend/ebook/e-book-listener.c + (e_book_listener_convert_status): track change from + E_BOOK_STATUS_* to E_BOOK_ERROR_*. + + * backend/ebook/e-book-query.c (e_book_query_any_field_contains): + new function. + (e_book_query_unref): handle the any_field_contains case. + (e_book_query_to_string): same. + + * backend/ebook/e-book-query.h: add prototype for + e_book_query_any_field_contains. + + * backend/ebook/e-card.c (e_card_load_uri): ifdef this out for + now. + + * backend/ebook/e-contact.[ch] (e_contact_get_const): new + function/prototype. + 2003-08-20 Gilbert Fang - * gui/widgets/e-addressbook-util.c + * gui/widgets/e-addressbook-util.c (e_addressbook_send_card_list): use memcpy to assign CORBA_char_sequence instead of strcpy. (#46706) +2003-08-18 Ettore Perazzoli + + * gui/component/component-factory.c: Update OAFIIDs. + + * gui/widgets/e-addressbook-util.c (e_addressbook_transfer_cards): + Removed extern declaration for global_shell_client [yuck]. + (e_addressbook_transfer_cards): #if 0 the invocation for + evolution_shell_client_user_select_folder(), we need to + reimplement this component-side now. + + * gui/component/component-factory.c (factory): Call + addressbook_component_peek() here instead of + addressbook_component_init() [since the latter is no more]. + + * gui/component/addressbook.c (set_status_message): Don't create + the activity client for now. + + * gui/component/addressbook-config.c: Removed member shell from + struct AddressbookDialog. + (ldap_dialog_new): Do not take a shell arg anymore. + (ldap_config_control_new): Likewise. + (addressbook_config_control_new): No need to get the global shell + pointer here anymore. + + * gui/component/addressbook-component.c: Rewritten to support the + new ::Component interface. + * gui/component/addressbook-component.h: Likewise. + + * gui/component/GNOME_Evolution_Addressbook.server.in.in: Version + factory's OAFIID. Remove ShellComponent server, add Component + server. + 2003-08-12 Rodrigo Moya * backend/ebook/e-book.c (e_book_dispose): unref the @@ -70,6 +1658,487 @@ * printins/e-contact-print-style-editor.c (e_contact_print_stule_editor_destroy): Chain. Prevent double unref. +2003-08-07 Chris Toshok + + * backend/ebook/e-vcard.c (e_vcard_to_string_vcard_21): new, + unimplemented, function. + (e_vcard_to_string_vcard_30): move the 3.0 vcard export code here. + (e_vcard_to_string): call e_vcard_to_string_vcard_21 or + e_vcard_to_string_vcard_30 based on @format. + (e_vcard_attribute_remove_values): new function. + + * backend/ebook/e-vcard.h: add @format to e_vcard_to_string, and + add prototype for e_vcard_attribute_remove_values. also, add + prototype for e_vcard_decode_b_encoding. + +2003-08-07 Chris Toshok + + * backend/ebook/e-book-listener.c + (impl_BookListener_respond_open_book): remove the book arg. + + * backend/ebook/e-book-listener.h (struct _EBookListenerResponse): + remove the corba book. + + * backend/ebook/e-book-async.c (_get_book_view_dtor): free the + query string. + (e_book_async_get_book_view): dup the query string. + + * backend/ebook/e-book.h: change e_book_get_book_view and + e_book_get_contacts to take a const char * query string instead of + an EBookQuery. + + * backend/ebook/e-book.c (e_book_add_contact): pass + EVC_FORMAT_VCARD_30 to e_vcard_to_string. + (e_book_commit_contact): same. + (e_book_get_book_view): take a const char* query string instead of + an EBookQuery. + (e_book_get_contacts): same. + (e_book_response_open): track change - the Book is no longer + communicated back here. + (listener_cb): nuke. + (e_book_handle_response): track change to e_book_response_open. + (e_book_load_uri): rework this from using BookFactory::openBook to + BookFactory::getBook + Book::open. + (e_book_get_uri): new function, reimplement from old api. + (e_book_get_static_capabilities): same. + (e_book_check_static_capability): same. + (startup_mainloop): new function, run bonobo_main. + (e_book_activate): start up a thread with startup_mainloop as the + start func. + (e_book_new): call e_book_activate. + + * backend/idl/addressbook.idl: Add Book::open, remove the Book + from notifyBookOpened's args, and change BookFactory::openBook to + BookFactory::getBook. + + * backend/pas/pas-backend-file.c (pas_backend_file_load_uri): add + only_if_exists - stop using the "create-initial" special file. + + * backend/pas/pas-backend-vcf.c (pas_backend_vcf_load_uri): add + only_if_exists - stop using the "create-initial" special file. + + * backend/pas/pas-backend.c (pas_backend_load_uri): add + @only_if_exists, and pass it along to the virtual method. + (pas_backend_open): new function, lock the mutex so only one + PASBook can actually call load_uri. call load_uri with + pas_book_get_uri, and req->only_if_exists. + (pas_backend_handle_request): rename process_client_request to + this, and expose it publicly. Also add a case statement for + "Open". + (real_add_client): gut this function, we don't need to create the + book anymore, just add the client to the list and do the weak + ref/ORBit small stuff. + (pas_backend_add_client): track change to signature - BookListener + -> PASBook. + (pas_backend_init): init open_mutex. + (pas_backend_dispose): free open_mutex. + + * backend/pas/pas-backend.h (PASBackendClass): add @only_if_exists + to the load_uri virtual method, and change the add_client virtual + method to take a PASBook instead of a BookListener. add the same + args to _load_uri and add_client. Also, add prototypes for + pas_backend_handle_request and pas_backend_open. + + * backend/pas/pas-book-factory.c + (_pas_book_factory_send_open_book_response): nuke. + (pas_book_factory_launch_backend): just return NULL, don't call + _pas_book_factory_send_open_book_response, in the error case. + (start_backend): nuke + (impl_GNOME_Evolution_Addressbook_BookFactory_getBook): rename + _openBook to this. clean up the code a bit. Create the PASBook + here, and always track change to pas_backend_add_client's type (we + pass the book now, not the listener). + (pas_book_factory_class_init): openBook -> getBook. + + * backend/pas/pas-book.c + (impl_GNOME_Evolution_Addressbook_Book_open): new function, call + pas_backend_open. + (impl_GNOME_Evolution_Addressbook_Book_getVCard): get rid of the + signal crap, just call pas_backend_handle_request. + (impl_GNOME_Evolution_Addressbook_Book_getCardList): same. + (impl_GNOME_Evolution_Addressbook_Book_authenticateUser): same. + (impl_GNOME_Evolution_Addressbook_Book_addCard): same. + (impl_GNOME_Evolution_Addressbook_Book_removeCards): same. + (impl_GNOME_Evolution_Addressbook_Book_modifyCard): same. + (impl_GNOME_Evolution_Addressbook_Book_getChanges): same. + (impl_GNOME_Evolution_Addressbook_Book_getSupportedFields): same. + (impl_GNOME_Evolution_Addressbook_Book_getSupportedAuthMethods): + same. + (impl_GNOME_Evolution_Addressbook_Book_cancelOperation): same. + (pas_book_get_backend): aggregate some g_return_if_fail's. + (pas_book_get_listener): new function. + (pas_book_get_uri): new function. + (pas_book_respond_open): just call BookListener::notifyBookOpened. + (pas_book_construct): add @uri, and g_strdup it. + (pas_book_new): add @uri, and pass it to pas_book_construct. + (pas_book_class_init): remove the "request" signal stuff, and fill + in epv->open. + + * backend/pas/pas-book.h: add PASOpenRequest struct/enum entry. + Also, add @uri to the pas_book_new args, and add a prototype for + pas_book_get_uri. Also, remove the "request" signal. + +2003-08-07 Chris Toshok + + * backend/pas/pas-book-factory.c + (pas_book_factory_get_n_backends): lock map_mutex around hash + table work. + (pas_book_factory_dump_active_backends): same. + (backend_last_client_gone_cb): same. + (_pas_book_factory_send_open_book_response): track CallStatus idl + change. + (start_backend): simplify this greatly, since the factory is + tagged with HINT_PER_THREAD. + (impl_GNOME_Evolution_Addressbook_BookFactory_openBook): lock + around hash table. + (pas_book_factory_init): initialize map_mutex. + (pas_book_factory_dispose): free map_mutex. + +2003-08-06 Chris Toshok + + * backend/pas/pas-backend-file.c + (pas_backend_file_book_view_copy): nuke. + (pas_backend_file_book_view_free): same. + (view_destroy): same. + (pas_backend_file_changes): #if notyet + (do_create): e-card -> e-contact. + (pas_backend_file_process_create_card): remove view handling from + here. + (pas_backend_file_process_remove_cards): same. + (pas_backend_file_process_modify_card): convert to e-contact, and + remove view handling. + (pas_backend_file_get_book_view): nuke. + (pas_backend_file_process_get_supported_fields): e-card-simple -> + e-contact. + (pas_backend_file_upgrade_db): e-card -> e-contact. + (pas_backend_file_cancel_operation): implement, just return + CouldNotCancel. + (pas_backend_file_class_init): assign cancel_operation, and remove + get_book_view assignment. + (pas_backend_file_init): remove book_views assignment. + +2003-08-06 Chris Toshok + + * backend/pas/pas-backend-vcf.c (pas_backend_vcf_book_view_copy): + nuke. + (pas_backend_vcf_book_view_free): same. + (view_destroy): same. + (insert_contact): new function, insert the contact into our hash + table. + (load_file): reimplement without the e_card stuff. + (foreach_build_list): e_card -> e_contact. + (save_file): mostly reimplement in terms of e-contact. more error + case work needs doing. + (do_create): e-card -> e-contact. + (pas_backend_vcf_process_create_card): remove the view handling + from here. + (pas_backend_vcf_process_remove_cards): implement this, just + remove it from the hash table and set ourselves to dirty. + (pas_backend_vcf_process_modify_card): remove the view handling + from here. + (pas_backend_vcf_process_get_book_view): nuke. + (pas_backend_vcf_process_get_supported_fields): reimplement in + terms of e-contact. + (INITIAL_VCARD): add in a FN attribute, and remove the quoted + printable encoding. + (pas_backend_vcf_cancel_operation): implement, just always return + CouldNotCancel. + (pas_backend_vcf_class_init): fill in cancel_operation, and remove + get_book_view_sync. + (pas_backend_vcf_init): remove book_views handling. + + * backend/pas/pas-backend-vcf.h: update copyright. + +2003-08-06 Chris Toshok + + * backend/pas/pas-backend-sync.c (pas_backend_sync_remove_cards): + add out param @ids, so we can call pas_book_respond_remove + properly. + (_pas_backend_remove_cards): the other half of the change - pass + the ids on to pas_book_response_remove. + (pas_backend_sync_modify_card): add out param @old_vcard so we can + call pas_book_respond_modify properly. + (_pas_backend_modify_card): the other half of the change, pass the + old_vcard on to pas_book_respond_modify. + (pas_backend_sync_get_book_view): nuke. + (pas_backend_sync_get_changes): track change (book view -> GList) + (_pas_backend_is_threaded): nuke. + (_pas_backend_create_card): indent. + (_pas_backend_remove_cards): same. + (_pas_backend_modify_card): same. + (_pas_backend_get_card_list): same. + (_pas_backend_get_changes): same. + (_pas_backend_authenticate_user): same. + (_pas_backend_get_supported_fields): same. + (_pas_backend_get_supported_auth_methods): same. + (_pas_backend_get_book_view): nuke. + (pas_backend_sync_class_init): remove assignment to is_threaded + and get_book_view. + + * backend/pas/pas-backend-sync.h: add out-params @ids to + remove_cards_sync, @old_vcard to modify_card_sync. + get_changes_sync's out-param is a GList instead of a book view, + and remove get_book_view_sync. + + * backend/pas/pas-backend.c (pas_backend_get_book_view): nuke. + (pas_backend_is_threaded): nuke. + (pas_backend_start_threaded): nuke. + (pas_backend_init): initialize priv->views. + (pas_backend_dispose): free priv->views. + (pas_backend_get_book_views): new function, return priv->views. + + * backend/pas/pas-backend.h: remove the get_book_view virtual + method, and the pas_backend_get_book_view prototype. Also, track + the CallStatus change, and add a cancel_operation virtual method + and prototype, and add pas_backend_get_book_views function, so the + PASBook's can get ahold of the list. + + * backend/pas/pas-book-view.h: track collapsing of + Addressbook::BookListenerCallStatus and + Addressbook::BookView::CallStatus enums into + Addressbook::CallStatus. + + * backend/pas/pas-book-view.c: same. + + * backend/pas/pas-card-cursor.[ch]: nuke + + * backend/pas/pas-book.c: track collapsing of + Addressbook::BookListenerCallStatus and + Addressbook::BookView::CallStatus enums into + Addressbook::CallStatus. + (impl_GNOME_Evolution_Addressbook_Book_getBookView): implement + this all here, instead of farming it out to the backends. + (impl_GNOME_Evolution_Addressbook_Book_getChanges): track change + to signature. this is no longer a book view, it'll return an + actual list. + (impl_GNOME_Evolution_Addressbook_Book_cancelOperation): new + function, implement. + (pas_book_respond_create): iterate over the views, notifying them + if the new card matches their query. + (pas_book_respond_remove): iterate over the views, telling them to + delete the card matching the id. + (pas_book_respond_modify): iterate over the views, notifying them + if they need to change/add/remove that card. + (view_destroy): move this here from the backends. + (pas_book_respond_get_book_view): weak-ref the book view. + (pas_book_new): remove the is_threaded switch on POA hints, and + always use PER_REQUEST. + (pas_book_class_init): fill in cancelOperation. + + * backend/pas/pas-book.h: track collapsing of + Addressbook::BookListenerCallStatus and + Addressbook::BookView::CallStatus enums into + Addressbook::CallStatus. + +2003-08-01 Chris Toshok + + * backend/ebook/e-book-async.c: mostly finished. + +2003-08-01 Chris Toshok + + * backend/ebook/e-book-async.[ch]: new files, create async methods + similar to the old ebook api that use GThread/GAsyncQueue to + simulate the old async behavior. + +2003-07-29 Chris Toshok + + * backend/idl/addressbook.idl: collapse + Addressbook::BookListenerCallStatus and + Addressbook::BookView::CallStatus enums into + Addressbook::CallStatus. + +2003-07-29 Chris Toshok + + * backend/ebook/e-book-types.h: add EBookChangeType/EBookChange. + +2003-07-29 Chris Toshok + + * backend/ebook/e-book-view-listener.c: track collapsing of + Addressbook::BookListenerCallStatus and + Addressbook::BookView::CallStatus enums into + Addressbook::CallStatus. + + * backend/ebook/e-book-listener.c track collapsing of + Addressbook::BookListenerCallStatus and + Addressbook::BookView::CallStatus enums into + Addressbook::CallStatus. + (response_free): nuked + (e_book_listener_check_queue): nuked + (e_book_listener_queue_response): nuked + (e_book_listener_queue_progress): nuked + (e_book_listener_queue_get_view_response): nuked + (e_book_listener_queue_get_changes_response): nuked + (e_book_listener_queue_writable_status): nuked + (e_book_listener_queue_authentication_response): nuked + (e_book_listener_queue_get_supported_fields_response): nuked + (e_book_listener_queue_get_supported_auth_methods_response): nuked + (e_book_listener_dispose): nuked + + * backend/ebook/e-book-listener.h: remove prototypes for + check_pending and pop_response. + + * backend/ebook/e-book.c (e_book_get_changes): new function. + implement this as more of a getCardList type function, instead of + getBookView. + (e_book_response_get_changes): new function. + (e_book_free_change_list): new function. + + * backend/ebook/e-book.h: add prototype for + e_book_free_change_list. + +2003-07-23 Chris Toshok + + * backend/ebook/e-book.c (e_book_get_book_view): new function, + implement this. + (e_book_response_get_book_view): same. + (e_book_get_contacts): remove the op so we don't see BUSY after + this request. + (e_book_handle_response): unifdef a few things. + (e_book_unload_uri): fix the assertion about URI_NOT_LOADED, and + unifdef some code. + (e_book_dispose): fix a typo. + + * backend/ebook/e-book-view.c (e_book_view_handle_response): + rename _check_listener_queue to this. we don't need to pop the + response either, it's passed as an arg. + (e_book_view_construct): "response_queued" -> "response" + (e_book_view_start): new function, call BookView.start. + (e_book_view_dispose): track the signal id change. + + * backend/ebook/e-book-view.h: add prototype for + e_book_view_start. + + * backend/ebook/e-book-view-listener.c + (e_book_view_listener_check_queue): remove. + (e_book_view_listener_queue_response): just emit the signal. + (impl_BookViewListener_notify_card_added): spew. + (impl_BookViewListener_notify_card_changed): spew. + (impl_BookViewListener_notify_sequence_complete): spew. + (impl_BookViewListener_notify_progress): spew. + (e_book_view_listener_check_pending): remove + (e_book_view_listener_check_pop_response): remove + (e_book_view_listener_new): use the ALL_AT_IDLE poa policy. + (e_book_view_listener_init): remove the queue/timeout stuff. + (e_book_view_listener_dispose): remove the queue/timeout stuff. + + * backend/ebook/e-book-view-listener.h: remove _check_pending and + _pop_response. + +2003-07-23 Chris Toshok + + * backend/pas/pas-backend-file.c (do_summary_query): remove the + completion_search argument, and remove the aggregating stuff. + just call pas_book_view_notify_add_1. + (pas_backend_file_book_view_copy): remove card_sexp crap. + (pas_backend_file_book_view_free): same. + (get_length): remove + (get_nth): remove + (cursor_destroy): remove + (vcard_matches_search): remove + (ecard_matches_search): remove + (pas_backend_file_search_timeout): remove the aggregating stuff. + just call pas_book_view_notify_add_1. + (pas_backend_file_search): simplify this a bunch. + (do_create): use pas_book_view_vcard_matches. + (pas_backend_file_process_get_card_list): add some more error + checks. + (pas_backend_file_process_get_book_view): unifdef this, and + implement it. + (pas_backend_file_start_book_view): kick off the search. + (pas_backend_file_get_uri): remove. + (pas_backend_file_class_init): remove get_uri, add + start_book_view. + + * backend/pas/pas-backend-ldap.c (view_destroy): don't need to + unref the card_sexp, as the PASBookView owns it now. + (create_card_handler): use pas_book_view_vcard_matches. + (modify_card_modify_handler): same. + (ldap_get_view): initialize the view properly. + (pas_backend_ldap_get_uri): remove. + (pas_backend_ldap_class_init): remove the get_uri assignment. + + * backend/pas/pas-backend-sync.c (_pas_backend_get_card_list): + don't free this, it's freed in the pas_book code. + + * backend/pas/pas-backend-sync.h: make use of pas-types.h and + remove some typedefs. + + * backend/pas/pas-backend-summary.h: same. + + * backend/pas/pas-backend-card-sexp.h: same. + +2003-07-23 Chris Toshok + + * backend/pas/pas-book.c + (impl_GNOME_Evolution_Addressbook_Book_getBookView): spew. + (pas_book_respond_create): unifdef this. + (pas_book_respond_remove): same. + (pas_book_respond_modify): same. + (pas_book_respond_authenticate_user): same. + (pas_book_respond_get_supported_fields): unref the iterator. + (pas_book_respond_get_book_view): unifdef, and add spew. + + * backend/pas/pas-book.h: make use of pas-types.h and remove some + typedefs. + +2003-07-23 Chris Toshok + + * backend/pas/pas-types.h: new file, all the typedefs shared + between files here. + +2003-07-23 Chris Toshok + + * backend/pas/pas-book-view.c (send_pending_adds): abstract all + the aggregating code to the book view. backends just call + notify_card_added and the superclass does all the aggregating. + (pas_book_view_notify_change): if there are pending adds, send + them before we send the change. + (pas_book_view_notify_remove): same. + (pas_book_view_notify_add): the other part of the aggregating + code. + (pas_book_view_notify_complete): send pending adds if there are + any. + (impl_GNOME_Evolution_Addressbook_BookView_start): new function, + call pas_backend_start_book_view. + (pas_book_view_get_card_query): new function. + (pas_book_view_get_card_sexp): new function. + (pas_book_view_get_backend): new function. + + * backend/pas/pas-book-view.h: add a PASBackend arg to the + constructor, as well as the char* query and PASBackendCardSExp + form. also add accessors for card_query, card_sexp, and backend. + + * backend/idl/addressbook.idl + (GNOME::Evolution::Addressbook::BookView): add start() method. + (GNOME::Evolution::Addressbook::BookListener): remove the oneway + tag from notifyBookOpened, notifyViewRequested, and + notifyChangesRequested so the call doesn't return until the remote + object has gotten the method call. + + * backend/pas/pas-backend.c (pas_backend_load_uri): fill in the + uri slot if the load was successful. + (pas_backend_get_uri): return the uri, remove the virtual method + call. + (pas_backend_start_book_view): new function. + (process_client_request): ifdef out the threaded foo, since i'm + not certain it's at all necessary. + (real_add_client): remove the bonobo_object_unref of the book, + since it's immortal. + (pas_backend_dispose): free the uri. + + * backend/pas/pas-backend.h: remove the get_uri virtual method, + and add the start_book_view virtual method and + pas_backend_start_book_view prototype. + +2003-07-23 Chris Toshok + + * backend/pas/Makefile.am (libpasvcf_a_SOURCES): new. + (noinst_LIBRARIES): add libpasvcf.a + + * backend/pas/pas-backend-vcf.[ch]: new files, implement a vcard + file backend. the backend api still needs a little work, but it's + getting easier to write backends. + 2003-07-23 Chris Toshok * printing/e-contact-print.c (e_contact_print_response): deal with diff --git a/addressbook/Makefile.am b/addressbook/Makefile.am index d0d48e5076..7bbbce2434 100644 --- a/addressbook/Makefile.am +++ b/addressbook/Makefile.am @@ -3,7 +3,9 @@ CONDUIT_SUBDIR=conduit endif SUBDIRS = \ - backend printing gui tools $(CONDUIT_SUBDIR) + backend util printing gui $(CONDUIT_SUBDIR) EXTRA_DIST = \ ChangeLog.pre-1-4 + +# XXX tools \ No newline at end of file diff --git a/addressbook/backend/ebook/.cvsignore b/addressbook/backend/ebook/.cvsignore index e3e9c805bb..17250008f8 100644 --- a/addressbook/backend/ebook/.cvsignore +++ b/addressbook/backend/ebook/.cvsignore @@ -12,6 +12,7 @@ addressbook.h test-card test-client test-client-list +test-ebook load-pine-addressbook load-gnomecard-addressbook evolution-vcard-importer diff --git a/addressbook/backend/ebook/Makefile.am b/addressbook/backend/ebook/Makefile.am index 9d2b6d1b05..e83e3e1411 100644 --- a/addressbook/backend/ebook/Makefile.am +++ b/addressbook/backend/ebook/Makefile.am @@ -1,16 +1,7 @@ -noinst_PROGRAMS = test-card test-client test-client-list - -privlibexec_PROGRAMS = \ - evolution-vcard-importer \ - evolution-ldif-importer - -toolsdir = $(privlibexecdir)/ -tools_PROGRAMS = \ - load-pine-addressbook \ - load-gnomecard-addressbook - # CORBA stuff +SUBDIRS = . tests + CORBA_ADDRESSBOOK_SOURCE_H = \ addressbook.h CORBA_ADDRESSBOOK_SOURCE_C = \ @@ -38,13 +29,10 @@ INCLUDES = \ -DLIBDIR=\"$(libdir)\" \ -DG_LOG_DOMAIN=\"EBook\" \ -I$(top_srcdir) \ - -I$(top_srcdir)/camel \ -I$(top_srcdir)/addressbook/backend \ -I$(top_srcdir)/addressbook/ename \ -I$(top_builddir)/addressbook/backend \ -I$(top_builddir)/addressbook/ename \ - -I$(top_builddir)/shell \ - -I$(top_srcdir)/shell \ -DG_DISABLE_DEPRECATED \ -DLIBGNOME_DISABLE_DEPRECATED \ $(EVOLUTION_ADDRESSBOOK_CFLAGS) @@ -53,113 +41,39 @@ privlib_LTLIBRARIES = libebook.la libebook_la_SOURCES = \ $(CORBA_SOURCE) \ - e-book-listener.c \ + addressbook.h \ e-book-marshal.c \ + e-book-query.c \ e-book-view-listener.c \ e-book-view.c \ + e-book-listener.c \ e-book.c \ - e-book-util.c \ - e-card-cursor.c \ - e-card-simple.c \ - e-card.c \ - e-card-compare.c \ - e-destination.c + e-book-async.c \ + e-contact.c \ + e-vcard.c libebook_la_LIBADD = \ $(top_builddir)/libversit/libversit.la \ - $(top_builddir)/camel/libcamel.la \ $(top_builddir)/e-util/ename/libename.la \ $(top_builddir)/e-util/libeutil.la libebookincludedir = $(privincludedir)/ebook libebookinclude_HEADERS = \ - e-book-listener.h \ - e-book-types.h \ + e-book-query.h \ e-book-view-listener.h \ e-book-view.h \ + e-book-types.h \ + e-book-listener.h \ e-book.h \ - e-book-util.h \ - e-card-cursor.h \ - e-card-simple.h \ - e-card-types.h \ - e-card.h \ - e-card-compare.h \ - e-destination.h \ - addressbook.h - + e-contact.h \ + e-vcard.h MARSHAL_GENERATED = e-book-marshal.c e-book-marshal.h @EVO_MARSHAL_RULE@ -test_client_SOURCES = \ - test-client.c - -test_client_LDADD = \ - libebook.la \ - $(EVOLUTION_ADDRESSBOOK_LIBS) - -test_client_list_SOURCES = \ - test-client-list.c - -test_client_list_LDADD = \ - libebook.la \ - $(EVOLUTION_ADDRESSBOOK_LIBS) - -test_card_SOURCES = \ - test-card.c - -test_card_LDADD = \ - libebook.la \ - $(EVOLUTION_ADDRESSBOOK_LIBS) - -evolution_vcard_importer_SOURCES = \ - evolution-vcard-importer.c - -evolution_vcard_importer_LDADD = \ - libebook.la \ - $(EVOLUTION_ADDRESSBOOK_LIBS) \ - $(top_builddir)/shell/importer/libevolution-importer.la \ - $(DB3_LDADD) - -evolution_ldif_importer_SOURCES = \ - evolution-ldif-importer.c - -evolution_ldif_importer_LDADD = \ - libebook.la \ - $(EVOLUTION_ADDRESSBOOK_LIBS) \ - $(top_builddir)/shell/importer/libevolution-importer.la \ - $(DB3_LDADD) - -load_pine_addressbook_SOURCES = \ - load-pine-addressbook.c - -load_pine_addressbook_LDADD = \ - libebook.la \ - $(EVOLUTION_ADDRESSBOOK_LIBS) - -load_gnomecard_addressbook_SOURCES = \ - load-gnomecard-addressbook.c - -load_gnomecard_addressbook_LDADD = \ - libebook.la \ - $(EVOLUTION_ADDRESSBOOK_LIBS) - - -BUILT_SOURCES = $(CORBA_SOURCE) $(MARSHAL_GENERATED) $(server_DATA) +BUILT_SOURCES = $(CORBA_SOURCE) $(MARSHAL_GENERATED) CLEANFILES = $(BUILT_SOURCES) dist-hook: cd $(distdir); rm -f $(BUILT_SOURCES) - -server_in_files = GNOME_Evolution_Addressbook_VCard_Importer.server.in.in \ - GNOME_Evolution_Addressbook_LDIF_Importer.server.in.in - -server_DATA = $(server_in_files:.server.in.in=.server) -%.server.in: %.server.in.in - sed -e "s|\@LIBEXECDIR\@|$(privlibexecdir)|" $< > $@ - - -@INTLTOOL_SERVER_RULE@ - -EXTRA_DIST = $(server_in_files) $(server_DATA) e-book-marshal.list diff --git a/addressbook/backend/ebook/docs/rfc2739.txt b/addressbook/backend/ebook/docs/rfc2739.txt new file mode 100644 index 0000000000..5c1dbbcf77 --- /dev/null +++ b/addressbook/backend/ebook/docs/rfc2739.txt @@ -0,0 +1,899 @@ + + + + + + +Network Working Group T. Small +Request for Comments: 2739 XpertSite.Com +Category: Standards Track D. Hennessy + ISOCOR + F. Dawson + Lotus + January 2000 + + + Calendar Attributes for vCard and LDAP + + +Status of this Memo + + This document specifies an Internet standards track protocol for the + Internet community, and requests discussion and suggestions for + improvements. Please refer to the current edition of the "Internet + Official Protocol Standards" (STD 1) for the standardization state + and status of this protocol. Distribution of this memo is unlimited. + +Copyright Notice + + Copyright (C) The Internet Society (2000). All Rights Reserved. + +Abstract + + When scheduling a calendar entity, such as an event, it is a + prerequisite that an organizer has the calendar address of each + attendee that will be invited to the event. Additionally, access to + an attendee's current "busy time" provides an a priori indication of + whether the attendee will be free to participate in the event. + + In order to meet these challenges, a calendar user agent (CUA) needs + a mechanism to locate (URI) individual user's calendar and free/busy + time. + + This memo defines three mechanisms for obtaining a URI to a user's + calendar and free/busy time. These include: + + - Manual transfer of the information; + + - Personal data exchange using the vCard format; and + + - Directory lookup using the LDAP protocol. + + + + + + + +Small, et al. Standards Track [Page 1] + +RFC 2739 Locating a Calendar User January 2000 + + +Table of Contents + + 1 CALENDARING AND SCHEDULING URIS...................................3 + 1.1 FREE/BUSY URI (FBURL) .........................................3 + 1.2 CALENDAR ACCESS URI (CAPURI) ..................................4 + 1.3 CALENDAR URI (CALURI) .........................................4 + 1.4 DEFAULT URIS ..................................................4 + 2 DISTRIBUTION......................................................4 + 2.1 MANUAL TRANSFER ...............................................5 + 2.2 PERSONAL DATA EXCHANGE USING A VCARD ..........................5 + 2.3 VCARD SCHEMA EXTENSIONS .......................................5 + 2.3.1 FBURL Property IANA Registration ...........................6 + 2.3.2 CALADRURI Property IANA Registration .......................7 + 2.3.3 CAPURI Property IANA Registration ......................... 8 + 2.3.4 CALURI Property IANA Registration ......................... 8 + 2.4 DIRECTORY LOOKUP USING THE LDAP V3 PROTOCOL .................. 9 + 2.4.1 LDAP Schema Extensions .................................... 9 + 2.4.2 Notation ..................................................10 + 2.4.3 Object Definitions ........................................10 + 2.4.3.1 calEntry ..............................................10 + 2.4.4 Attribute Definitions .....................................10 + 2.4.4.1 calCalURI .............................................10 + 2.4.4.2 calFBURL ..............................................10 + 2.4.4.3 calCAPURI .............................................11 + 2.4.4.4 calCalAdrURI ..........................................11 + 2.4.4.5 calOtherCalURIs .......................................11 + 2.4.4.6 calOtherFBURLs ........................................11 + 2.4.4.7 calOtherCAPURIs .......................................12 + 2.4.4.8 calOtherCalAdrURIs ....................................12 + 3 IANA Considerations..............................................12 + 4 Security Considerations..........................................12 + 5 Acknowledgments..................................................13 + 6 Authors' Addresses...............................................13 + 7 Bibliography.....................................................15 + 8 Full Copyright Statement.........................................16 + + + + + + + + + + + + + + + + +Small, et al. Standards Track [Page 2] + +RFC 2739 Locating a Calendar User January 2000 + + +1 Calendaring and Scheduling URIs + + This memo defines four classes of URIs. URIs are more useful if it is + understood what the URIs point to. Here is a brief description: + +1.1 Free/Busy URI (FBURL) + + The free/busy URI is defined to be a transport independent location + where a client can obtain information about when a user is busy. At + the present time, this URI only points to busy time data. Future + revisions of this specification may provide for the extended + capability of publishing free time data. + + If a calendaring and scheduling client (i.e., CUA) were to retrieve + data from this location using FTP or HTTP, it would get back an + iCalendar object [4] containing one or more "VFREEBUSY" calendar + components. If a MIME transport is being used, the response will be + contained within a "text/calendar" MIME body part as specified in the + iCalendar specification [4]. For example: + + BEGIN:VCALENDAR + VERSION:2.0 + PRODID:-//hacksw/handcal//NONSGML v1.0//EN + METHOD:PUBLISH + BEGIN:VFREEBUSY + ATTENDEE:MAILTO:jane_doe@host1.com + DTSTART:19971013T050000Z + DTEND:19971124T050000Z + DTSTAMP:19970901T083000Z + FREEBUSY:19971015T133000Z/19971015T180000Z + FREEBUSY:19971015T190000Z/19971015T220000Z + FBURL:http://www.host.com/calendar/busy/jdoe.ifb + END:VFREEBUSY + END:VCALENDAR + + The amount of busy time data pointed to by the FBURL will generally + be pre-determined; for example one month of busy time data. As a + guideline, it is recommended that the previous six weeks of busy time + data be published at the location associated with the FBURL. If this + URI points to a file resource, it is recommended that the file + extension be "ifb" to distinguish it from an arbitrary iCalendar + object (e.g., with the "ics" file extension). + + + + + + + + + +Small, et al. Standards Track [Page 3] + +RFC 2739 Locating a Calendar User January 2000 + + +1.2 Calendar Access URI (CAPURI) + + The Calendar Access URI is defined to be a protocol independent + location from which a calendaring and scheduling client (i.e., CUA) + can communicate with a user's entire calendar. + + The semantics for using this URI as an access protocol locator are + yet to be defined by the IETF CALSCH Working Group. This will be + addressed in the "Calendar Access Protocol" specification. + +1.3 Calendar URI (CALURI) + + The Calendar URI is defined to be a protocol independent location + from which a calendaring and scheduling client (i.e. CUA) can + retrieve an entire copy of a user's calendar. Retrieving data from + this URI obtains a published "snapshot" of the user's calendar. + + HTTP URI -- If the URI is an HTTP URI, then the content returned with + a GET should be a "text/calendar" MIME body part containing one or + more iCalendar object. + + FTP URI -- If the URI is an FTP URI, then the resource pointed to + should be a file with an "ics" file extension containing one or more + iCalendar objects. + +1.4 Default URIs + + There are many cases where a user may have more than one calendar. In + these cases, a user may have multiple URIs, each URI pointing to a + calendar or free/busy data. + + To make the case of multiple calendars simpler for clients, the + concept of the "default" calendar is introduced. A "default" calendar + is one that the user has designated as the calendar that other users + should look at when accessing the user's calendar, or retrieving the + user's free/busy time. + + The default calendar may, in fact, include rolled-up information from + all the user's other calendars. The other calendars may only exist + for organizational purposes. + +2 Distribution + + These four URIs provide valuable pointers to calendaring and + scheduling data that other users need in order to know when to + schedule meetings, etc. There are several possibilities on how users + can communicate these URIs to other users. The following section + outlines how these URIs can be distributed to other users. + + + +Small, et al. Standards Track [Page 4] + +RFC 2739 Locating a Calendar User January 2000 + + +2.1 Manual Transfer + + The simplest way to obtain these URIs is for a user to communicate + the URIs using some out-of-band mechanism such as verbally, or in an + e-mail message, or by printing these URIs on a paper business card. + + When using this mechanism, the user obtains these URIs using an out- + of-band mechanism and then enters these URIs into their calendaring + software manually. + +2.2 Personal Data Exchange Using A vCard + + A more sophisticated way to obtain these URIs is for users to publish + vCards containing these URIs. The vCard object can be transferred + between one another. Since many e-mail clients allow a user to + automatically include a vCard with every message that the user sends, + this provides a simple, transparent way for a user to distribute + their calendaring and scheduling URIs. + + On the receiving end, an e-mail client that provides an integrated + vCard database can provide a way to lookup calendaring URIs for users + whose vCards are stored locally. + +2.3 vCard Schema Extensions + + Since the vCard [3] specification doesn't specify how to encode + calendaring URIs in a vCard, this section is provided as an extension + to vCard which specifies how to encode calendaring URIs within a + vCard. + + Inside a vCard object, four new properties are defined: "CALURI", + "CAPURI", "CALADRURI", and "FBURL", as defined above. + + Any vCard can have one or more of these properties, each representing + a calendar or free/busy time that is associated with the user. + + One of these properties can be designated as the "default" by adding + the "PREF" parameter. + + + + + + + + + + + + + +Small, et al. Standards Track [Page 5] + +RFC 2739 Locating a Calendar User January 2000 + + + Here is a simple example of a vCard containing a "FBURL" and a + "CALURI". + + BEGIN:VCARD + VERSION:3.0 + N:Dun;Alec + FN:Alec Dun + ORG:Microsoft Corporation + ADR;WORK;POSTAL;PARCEL:;;One Microsoft Way; + Redmond;WA;98052-6399;USA + TEL;WORK;MSG:+1-206-936-4544 + TEL;WORK;FAX:+1-206-936-7329 + EMAIL;INTERNET:user@host1.com + CALADRURI;PREF:mailto:user@host1.com + CALURI;PREF:http://cal.host1.com/user/cal.ics + FBURL;PREF:http://cal.host1.com/user/fb.ifb + CALURI:http://cal.company.com/projectA/pjtA.ics + FBURL:http://cal.company.com/projectA/pjtAfb.ifb + END:VCARD + +2.3.1 FBURL Property IANA Registration + + To: ietf-mime-directory@imc.org + + Subject: Registration of FBURL type for text/directory MIME type + vCard profile. + + Type name: FBURL + + Type purpose: To specify the URI for a user's busy time in a vCard + object. + + Type encoding: 8bit + + Type value: A single URI value. + + Type special notes: Where multiple FBURL properties are specified, + the default FBURL property is indicated with the PREF parameter. The + FTP or HTTP type of URI points to an iCalendar object associated with + a snapshot of the last six weeks of the user's busy time data. If the + iCalendar object is represented as a file or document, it's file type + should be "ifb". + + Intended usage: Refer to section 1.1. + + + + + + + +Small, et al. Standards Track [Page 6] + +RFC 2739 Locating a Calendar User January 2000 + + + Type examples: + + FBURL;PREF:http://www.host1.com/busy/janedoe + FBURL:FTP://ftp.host.com/busy/project-a.ifb + +2.3.2 CALADRURI Property IANA Registration + + To: ietf-mime-directory@imc.org + + Subject: Registration of CALADRURI type for application/directory + MIME type vCard profile. + + Type name: CALADRURI + + Type purpose: To specify the location to which an event request + should be sent for the user. + + Type encoding: 8bit + + Type value: A single URI value. + + Type special notes: Where multiple CALADRURI properties are + specified, the default CALADRURI property is indicated with the PREF + parameter. + + Intended usage: Refer to section 1.2. + + Type examples: + + CALADRURI;PREF:mailto:janedoe@host.com + + + + + + + + + + + + + + + + + + + + + +Small, et al. Standards Track [Page 7] + +RFC 2739 Locating a Calendar User January 2000 + + +2.3.3 CAPURI Property IANA Registration + + To: ietf-mime-directory@imc.org + + Subject: Registration of CAPURI type for application/directory MIME + type vCard profile. + + Type name: CAPURI + + Type purpose: To specify a protocol independent location from which a + calendaring and scheduling client (i.e., CUA) can communicate with a + user's entire calendar. + + Type encoding: 8bit + + Type value: A single URI value. + + Type special notes: Where multiple CAPURI properties are specified, + the default CAPURI property is indicated with the PREF parameter. + + Intended usage: Refer to section 1.3. + +2.3.4 CALURI Property IANA Registration + + To: ietf-mime-directory@imc.org + + Subject: Registration of CALURI type for text/directory MIME type + vCard profile. + + Type name: CALURI + + Type purpose: To specify the URI for a user's calendar in a vCard + object. + + Type encoding: 8bit + + Type value type: A single URI value. + + Type special notes: Where multiple CALURI properties are specified, + the default CALURI property is indicated with the PREF parameter. The + property should contain a URI pointing to an iCalendar object + associated with a snapshot of the user's calendar store. If the + iCalendar object is represented as a file or document, it's file type + should be "ics". + + Intended usage: Refer to section 1.4. + + + + + +Small, et al. Standards Track [Page 8] + +RFC 2739 Locating a Calendar User January 2000 + + + Type examples: + + CALURI;PREF:http://cal.host1.com/calA + CALURI:ftp://ftp.host1.com/calA.ics + +2.4 Directory Lookup Using The LDAP v3 Protocol + + Another way to obtain these URIs is to look them up in a directory + using the LDAP protocol [1]. + + If a user's URIs can be found using directory lookup (i.e., searching + for one of the LDAP schema extensions defined below), they should, in + general, be considered "more up-to-date" than URIs in any vCards that + are stored locally. + +2.4.1 LDAP Schema Extensions + + In order to encode the calendaring URIs in the directory, the + following are defined: + + - One object class: + + - calEntry + + - Eight attributes: + + - calCalURI + + - calFBURL + + - calCAPURI + + - calCalAdrURI + + - calOtherCalURIs + + - calOtherFBURLs + + - calOtherCAPURIs + + - calOtherCalAdrURIs + + The calCalURI contains the URI to a snapshot of the user's entire + default calendar. The calFBURL contains the URI to the user's default + busy time data. The calCAPURI represents contains a URI that can be + used to communicate with the user's calendar. The calCalAdrURI + contains a URI that points to the location to which event requests + should be sent for that user. + + + +Small, et al. Standards Track [Page 9] + +RFC 2739 Locating a Calendar User January 2000 + + + The calOtherCalURIs is a multi-valued property containing URIs to + snapshots of other calendars that the user may have. The + calOtherFBURLs is a multi-valued property containing URIs to other + free/busy data that the user may have. The calOtherCAPURIs attribute + is a multi-valued property containing URIs to other calendars that + the user may have. The calOtherCalAdrURIs attribute is a multi-valued + property containing URIs to other locations that a user may want + event requests sent to. + + There is no predetermined order to the values in either multi-valued + property. + +2.4.2 Notation + + The notation used in this memo is the same as that used in [2]. + +2.4.3 Object Definitions + +2.4.3.1 calEntry + + The Calendar Entry is a class derived from "TOP" [2], which contains + the four calendaring attributes. + + (1.2.840.113556.1.5.87 + NAME 'calEntry' + TOP + AUXILIARY + MAY (calCalURI calFBURL calOtherCalURIs calOtherFBURLs calCAPURI + calOtherCAPURLs) + ) + +2.4.4 Attribute Definitions + +2.4.4.1 calCalURI + + (1.2.840.113556.1.4.478 + NAME 'calCalURI' + EQUALITY caseIgnoreMatch + SUBSTRING caseIgnoreMatch + SYNTAX 'IA5String' + USAGE userApplications + ) + +2.4.4.2 calFBURL + + (1.2.840.113556.1.4.479 + NAME 'calFBURL' + EQUALITY caseIgnoreMatch + + + +Small, et al. Standards Track [Page 10] + +RFC 2739 Locating a Calendar User January 2000 + + + SUBSTRING caseIgnoreMatch + SYNTAX 'IA5String' + USAGE userApplications + ) + +2.4.4.3 calCAPURI + + (1.2.840.113556.1.4.480 + NAME 'calCAPURI' + EQUALITY caseIgnoreMatch + SUBSTRING caseIgnoreMatch + SYNTAX 'IA5String' + USAGE userApplications + ) + +2.4.4.4 calCalAdrURI + + (1.2.840.113556.1.4.481 + NAME 'calCalAdrURI' + EQUALITY caseIgnoreMatch + SUBSTRING caseIgnoreMatch + SYNTAX 'IA5String' + USAGE userApplications + ) + +2.4.4.5 calOtherCalURIs + + (1.2.840.113556.1.4.482 + NAME 'calOtherCalURIs' + EQUALITY caseIgnoreMatch + SUBSTRING caseIgnoreMatch + SYNTAX 'IA5String' + MULTI-VALUE + USAGE userApplications + ) + +2.4.4.6 calOtherFBURLs + + (1.2.840.113556.1.4.483 + NAME 'calOtherFBURLs' + EQUALITY caseIgnoreMatch + SUBSTRING caseIgnoreMatch + SYNTAX 'IA5String' + MULTI-VALUE + USAGE userApplications + ) + + + + + +Small, et al. Standards Track [Page 11] + +RFC 2739 Locating a Calendar User January 2000 + + +2.4.4.7 calOtherCAPURIs + + (1.2.840.113556.1.4.484 + NAME 'calOtherCAPURIs' + EQUALITY caseIgnoreMatch + SUBSTRING caseIgnoreMatch + SYNTAX 'IA5String' + MULTI-VALUE + USAGE userApplications + ) + +2.4.4.8 calOtherCalAdrURIs + + (1.2.840.113556.1.4.485 + NAME 'calOtherCalAdrURIs' + EQUALITY caseIgnoreMatch + SUBSTRING caseIgnoreMatch + SYNTAX 'IA5String' + MULTI-VALUE + USAGE userApplications + ) + +3 IANA Considerations + + This memo defines IANA registered extensions to the attributes + defined by LDAP [1] and vCard [3]. + + IANA registration proposals for vCard are to be emailed to the + registration agent for the "text/directory" MIME content-type, + using the format defined in + [3]. + +4 Security Considerations + + Standard vCard and LDAP security rules and support apply for the + extensions described in this document, and there are no special + security issues for these extensions. + + Please note, though, that LDAP servers may permit anonymous clients + to refresh entries which they did not create. Servers are also + permitted to control a refresh access to an entry by requiring + clients to bind before issuing a RefreshRequest. This will have + implications on the server performance and scalability. + + Please also note, though, that vCard objects may have been created by + an entity other than that represented by the vCard. Recipients should + be certain of the source that generated the vCard. + + + + +Small, et al. Standards Track [Page 12] + +RFC 2739 Locating a Calendar User January 2000 + + + Also, care should be taken in making use of information obtained from + directory servers that has been supplied by client, as it may now be + out of date. In many networks, for example, IP addresses are + automatically assigned when a host connects to the network, and may + be reassigned if that host later disconnects. An IP address obtained + from the directory may no longer be assigned to the host that placed + the address in the directory. This issue is not specific to LDAP or + dynamic directories. + +5 Acknowledgments + + The authors wish to acknowledge the work of Alec Dun, who acted as an + author for the early drafts of this memo. In addition, this document + received input from the various participants in the IETF CALSCH + Working Group discussions. + +6 Authors' Addresses + + The following address information is provided in a vCard v3.0 [3], + Electronic Business Card, format. + + BEGIN:VCARD + VERSION:3.0 + N:Small;Tony + FN:Tony Small + ORG:XpertSite.Com + ADR;TYPE=WORK,POSTAL,PARCEL:;;4700 42nd Ave. SW, Suite 440; + Seattle;WA;98116;USA + TEL;TYPE=WORK,MSG:+1-206-937-9972 + TEL;TYPE=WORK,FAX:+1-206-936-7329 + EMAIL;TYPE=INTERNET:tony@xpertsite.com + CALADRURI:MAILTO:tony@xpertsite.com + END:VCARD + + BEGIN:VCARD + VERSION:3.0 + N:Hennessy;Denis + FN:Denis Hennessy + ORG:ISOCOR + ADR;TYPE=WORK,POSTAL,PARCEL:;;42-47 Lower Mount St; + Dublin 2;Ireland + TEL;TYPE=WORK,MSG:+353-1-676-0366 + TEL;TYPE=WORK,FAX:+353-1-676-0856 + EMAIL;TYPE=INTERNET:denis.hennessy@isocor.com + CALADRURI:MAILTO:denis.hennessy@isocor.com + END:VCARD + + + + + +Small, et al. Standards Track [Page 13] + +RFC 2739 Locating a Calendar User January 2000 + + + BEGIN:VCARD + VERSION:3.0 + N:Dawson;Frank + FN:Frank Dawson + ORG:Lotus Development Corporation + ADR;TYPE=WORK,POSTAL,PARCEL:;;6544 Battleford Drive; + Raleigh;NC;27613-3502;USA + TEL;TYPE=WORK,PREF:+1-617-693-8728 + TEL;TYPE=WORK,MSG:+1-919-676-9515 + TEL;TYPE=FAX:+1-617-693-8728 + EMAIL;TYPE=INTERNET,PREF:Frank_Dawson@Lotus.com + EMAIL;TYPE=INTERNET:fdawson@earthlink.net + CALADRURI;TYPE=PREF:MAILTO:Frank_Dawson@Lotus.com + CALADRURI:MAILTO:fdawson@earthlink.net + URL:http://home.earthlink.net/~fdawson + END:VCARD + + This memo is a result of the work of the Internet Engineering Task + Force Calendaring and scheduling Working Group. The chairman of that + working group is: + + BEGIN:VCARD + VERSION:3.0 + N:Egen;Pat + FN:Pat Egen + ORG:Engan Consulting + ADR;TYPE=WORK:;;803 Creek Overlook;Chattanooga;TN;37415;USA + TEL;TYPE=WORK,VOICE:423.875.2652 + TEL;TYPE=WORK,FAX:423.875.2017 + EMAIL:pregen@egenconsulting.com + URL:http://www.egenconsulting.com + CALADRURI:MAILTO:pregen@egenconsulting.com + END:VCARD + + + + + + + + + + + + + + + + + + +Small, et al. Standards Track [Page 14] + +RFC 2739 Locating a Calendar User January 2000 + + +7 Bibliography + + [1] Wahl, M., Howes, T. and S. Kille, "Lightweight Directory Access + Protocol (v3)", RFC 2251, December 1997. + + [2] Wahl, M., Coulbeck, A., Howes, T. and S. Kille, "Lightweight + Directory Access Protocol (v3): Attribute Syntax Definitions", + RFC 2252, December 1997. + + [3] Dawson, F. and T. Howes, "vCard MIME Directory Profile", RFC + 2426, September 1998. + + [4] Dawson, F. and D. Stenerson, "Internet Calendaring and Scheduling + Core Object Specification (iCalendar)", RFC 2445, November 1997. + + [5] Dawson, F. and S. Mansour, "iCalendar Message-Based + Interopability Protocal (iMIP)", RFC 2447, November 1997. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +Small, et al. Standards Track [Page 15] + +RFC 2739 Locating a Calendar User January 2000 + + +8 Full Copyright Statement + + Copyright (C) The Internet Society (2000). All Rights Reserved. + + This document and translations of it may be copied and furnished to + others, and derivative works that comment on or otherwise explain it + or assist in its implementation may be prepared, copied, published + and distributed, in whole or in part, without restriction of any + kind, provided that the above copyright notice and this paragraph are + included on all such copies and derivative works. However, this + document itself may not be modified in any way, such as by removing + the copyright notice or references to the Internet Society or other + Internet organizations, except as needed for the purpose of + developing Internet standards in which case the procedures for + copyrights defined in the Internet Standards process must be + followed, or as required to translate it into languages other than + English. + + The limited permissions granted above are perpetual and will not be + revoked by the Internet Society or its successors or assigns. + + This document and the information contained herein is provided on an + "AS IS" basis and THE INTERNET SOCIETY AND THE INTERNET ENGINEERING + TASK FORCE DISCLAIMS ALL WARRANTIES, EXPRESS OR IMPLIED, INCLUDING + BUT NOT LIMITED TO ANY WARRANTY THAT THE USE OF THE INFORMATION + HEREIN WILL NOT INFRINGE ANY RIGHTS OR ANY IMPLIED WARRANTIES OF + MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. + +Acknowledgement + + Funding for the RFC Editor function is currently provided by the + Internet Society. + + + + + + + + + + + + + + + + + + + +Small, et al. Standards Track [Page 16] + diff --git a/addressbook/backend/ebook/e-book-async.c b/addressbook/backend/ebook/e-book-async.c new file mode 100644 index 0000000000..2ccc565eb9 --- /dev/null +++ b/addressbook/backend/ebook/e-book-async.c @@ -0,0 +1,1120 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ + +#include "ebook/e-book-async.h" + +static GThread *worker_thread; +static GAsyncQueue *to_worker_queue; +static GAsyncQueue *from_worker_queue; + +typedef struct _EBookMsg EBookMsg; + +typedef void (*EBookMsgHandler)(EBookMsg* msg); +typedef void (*EBookMsgDtor)(EBookMsg* msg); + +struct _EBookMsg { + EBookMsgHandler handler; + EBookMsgDtor dtor; +}; + +static gpointer +worker (gpointer data) +{ + while (TRUE) { + EBookMsg *msg = g_async_queue_pop (to_worker_queue); + msg->handler (msg); + msg->dtor (msg); + } + + return NULL; +} + +static gboolean +main_thread_check_for_response (gpointer data) +{ + EBookMsg *msg; + + while ((msg = g_async_queue_try_pop (from_worker_queue)) != NULL) { + msg->handler (msg); + msg->dtor (msg); + } + + return TRUE; +} + +static void +e_book_msg_init (EBookMsg *msg, EBookMsgHandler handler, EBookMsgDtor dtor) +{ + msg->handler = handler; + msg->dtor = dtor; +} + +static void +init_async() +{ + static gboolean init_done = FALSE; + if (!init_done) { + init_done = TRUE; + to_worker_queue = g_async_queue_new (); + from_worker_queue = g_async_queue_new (); + worker_thread = g_thread_create (worker, NULL, FALSE, NULL); + g_timeout_add (300, main_thread_check_for_response, NULL); + } +} + + + +typedef struct { + EBookMsg msg; + + EBook *book; + char *uri; + EBookCallback open_response; + gpointer closure; +} LoadUriMsg; + +typedef struct { + EBookMsg msg; + + EBook *book; + EBookStatus status; + EBookCallback open_response; + gpointer closure; +} LoadUriResponse; + +static void +_load_uri_response_handler (EBookMsg *msg) +{ + LoadUriResponse *resp = (LoadUriResponse*)msg; + + resp->open_response (resp->book, resp->status, resp->closure); +} + +static void +_load_uri_response_dtor (EBookMsg *msg) +{ + LoadUriResponse *resp = (LoadUriResponse*)msg; + + g_object_unref (resp->book); + g_free (resp); +} + +static void +_load_uri_handler (EBookMsg *msg) +{ + LoadUriMsg *uri_msg = (LoadUriMsg *)msg; + LoadUriResponse *response; + GError *error = NULL; + + response = g_new (LoadUriResponse, 1); + e_book_msg_init ((EBookMsg*)response, _load_uri_response_handler, _load_uri_response_dtor); + + response->status = E_BOOK_ERROR_OK; + if (!e_book_load_uri (uri_msg->book, uri_msg->uri, FALSE, &error)) { + response->status = error->code; + g_error_free (error); + } + + response->book = uri_msg->book; + response->open_response = uri_msg->open_response; + response->closure = uri_msg->closure; + + g_async_queue_push (from_worker_queue, response); +} + +static void +_load_uri_dtor (EBookMsg *msg) +{ + LoadUriMsg *uri_msg = (LoadUriMsg *)msg; + + g_free (uri_msg->uri); + g_free (uri_msg); +} + +void +e_book_async_load_uri (EBook *book, + const char *uri, + EBookCallback open_response, + gpointer closure) +{ + LoadUriMsg *msg; + + init_async (); + + msg = g_new (LoadUriMsg, 1); + e_book_msg_init ((EBookMsg*)msg, _load_uri_handler, _load_uri_dtor); + + msg->book = g_object_ref (book); + msg->uri = g_strdup (uri); + msg->open_response = open_response; + msg->closure = closure; + + g_async_queue_push (to_worker_queue, msg); +} + + +void +e_book_async_unload_uri (EBook *book) +{ + e_book_unload_uri (book, NULL); +} + + + + +typedef struct { + EBookMsg msg; + + EBookCallback open_response; + gpointer closure; +} DefaultBookMsg; + +typedef struct { + EBookMsg msg; + + EBook *book; + EBookStatus status; + EBookCallback open_response; + gpointer closure; +} DefaultBookResponse; + +static void +_default_book_response_handler (EBookMsg *msg) +{ + LoadUriResponse *resp = (LoadUriResponse*)msg; + + resp->open_response (resp->book, resp->status, resp->closure); +} + +static void +_default_book_response_dtor (EBookMsg *msg) +{ + LoadUriResponse *resp = (LoadUriResponse*)msg; + + g_object_unref (resp->book); + g_free (resp); +} + +static void +_default_book_handler (EBookMsg *msg) +{ + DefaultBookMsg *dfb_msg = (DefaultBookMsg *)msg; + DefaultBookResponse *response; + GError *error = NULL; + + response = g_new (DefaultBookResponse, 1); + e_book_msg_init ((EBookMsg*)response, _default_book_response_handler, _default_book_response_dtor); + + response->status = E_BOOK_ERROR_OK; + if (!e_book_get_default_addressbook (&response->book, &error)) { + response->status = error->code; + g_error_free (error); + } + + response->open_response = dfb_msg->open_response; + response->closure = dfb_msg->closure; + + g_async_queue_push (from_worker_queue, response); +} + +static void +_default_book_dtor (EBookMsg *msg) +{ + DefaultBookMsg *dfb_msg = (DefaultBookMsg *)msg; + + g_free (dfb_msg); +} + +void +e_book_async_get_default_addressbook (EBookCallback open_response, + gpointer closure) +{ + DefaultBookMsg *msg; + + init_async (); + + msg = g_new (DefaultBookMsg, 1); + e_book_msg_init ((EBookMsg*)msg, _default_book_handler, _default_book_dtor); + + msg->open_response = open_response; + msg->closure = closure; + + g_async_queue_push (to_worker_queue, msg); +} + + + +typedef struct { + EBookMsg msg; + + EBook *book; + EBookFieldsCallback cb; + gpointer closure; +} GetFieldsMsg; + +typedef struct { + EBookMsg msg; + + EBook *book; + EBookStatus status; + GList *fields; + EBookFieldsCallback cb; + gpointer closure; +} GetFieldsResponse; + +static void +_get_fields_response_handler (EBookMsg *msg) +{ + GetFieldsResponse *resp = (GetFieldsResponse*)msg; + GList *l; + EList *fields = e_list_new ((EListCopyFunc) g_strdup, + (EListFreeFunc) g_free, + NULL); + + for (l = resp->fields; l; l = l->next) + e_list_append (fields, l->data); + + if (resp->cb) + resp->cb (resp->book, resp->status, fields, resp->closure); + + g_object_unref (fields); +} + +static void +_get_fields_response_dtor (EBookMsg *msg) +{ + GetFieldsResponse *resp = (GetFieldsResponse*)msg; + + g_list_foreach (resp->fields, (GFunc)g_free, NULL); + g_list_free (resp->fields); + g_object_unref (resp->book); + g_free (resp); +} + +static void +_get_fields_handler (EBookMsg *msg) +{ + GetFieldsMsg *fields_msg = (GetFieldsMsg *)msg; + GetFieldsResponse *response; + GError *error = NULL; + + response = g_new (GetFieldsResponse, 1); + e_book_msg_init ((EBookMsg*)response, _get_fields_response_handler, _get_fields_response_dtor); + + response->status = E_BOOK_ERROR_OK; + if (!e_book_get_supported_fields (fields_msg->book, &response->fields, &error)) { + response->status = error->code; + g_error_free (error); + } + response->book = fields_msg->book; + response->cb = fields_msg->cb; + response->closure = fields_msg->closure; + + g_async_queue_push (from_worker_queue, response); +} + +guint +e_book_async_get_supported_fields (EBook *book, + EBookFieldsCallback cb, + gpointer closure) +{ + GetFieldsMsg *msg; + + init_async (); + + msg = g_new (GetFieldsMsg, 1); + e_book_msg_init ((EBookMsg*)msg, _get_fields_handler, (EBookMsgDtor)g_free); + + msg->book = g_object_ref (book); + msg->cb = cb; + msg->closure = closure; + + g_async_queue_push (to_worker_queue, msg); + + return 0; +} + + + +typedef struct { + EBookMsg msg; + + EBook *book; + EBookAuthMethodsCallback cb; + gpointer closure; +} GetMethodsMsg; + +typedef struct { + EBookMsg msg; + + EBook *book; + EBookStatus status; + GList *methods; + EBookAuthMethodsCallback cb; + gpointer closure; +} GetMethodsResponse; + +static void +_get_methods_response_handler (EBookMsg *msg) +{ + GetMethodsResponse *resp = (GetMethodsResponse*)msg; + GList *l; + EList *methods = e_list_new ((EListCopyFunc) g_strdup, + (EListFreeFunc) g_free, + NULL); + + for (l = resp->methods; l; l = l->next) + e_list_append (methods, l->data); + + if (resp->cb) + resp->cb (resp->book, resp->status, methods, resp->closure); + + g_object_unref (methods); +} + +static void +_get_methods_response_dtor (EBookMsg *msg) +{ + GetMethodsResponse *resp = (GetMethodsResponse*)msg; + + g_list_foreach (resp->methods, (GFunc)g_free, NULL); + g_list_free (resp->methods); + g_object_unref (resp->book); + g_free (resp); +} + +static void +_get_methods_handler (EBookMsg *msg) +{ + GetMethodsMsg *methods_msg = (GetMethodsMsg *)msg; + GetMethodsResponse *response; + GError *error = NULL; + + response = g_new (GetMethodsResponse, 1); + e_book_msg_init ((EBookMsg*)response, _get_methods_response_handler, _get_methods_response_dtor); + + response->status = E_BOOK_ERROR_OK; + if (!e_book_get_supported_auth_methods (methods_msg->book, &response->methods, &error)) { + response->status = error->code; + g_error_free (error); + } + + response->book = methods_msg->book; + response->cb = methods_msg->cb; + response->closure = methods_msg->closure; + + g_async_queue_push (from_worker_queue, response); +} + +guint +e_book_async_get_supported_auth_methods (EBook *book, + EBookAuthMethodsCallback cb, + gpointer closure) +{ + GetMethodsMsg *msg; + + init_async (); + + msg = g_new (GetMethodsMsg, 1); + e_book_msg_init ((EBookMsg*)msg, _get_methods_handler, (EBookMsgDtor)g_free); + + msg->book = g_object_ref (book); + msg->cb = cb; + msg->closure = closure; + + g_async_queue_push (to_worker_queue, msg); + + return 0; +} + + + +typedef struct { + EBookMsg msg; + + EBook *book; + char *user; + char *passwd; + char *auth_method; + EBookCallback cb; + gpointer closure; +} AuthUserMsg; + +typedef struct { + EBookMsg msg; + + EBook *book; + EBookStatus status; + EBookCallback cb; + gpointer closure; +} AuthUserResponse; + +static void +_auth_user_response_handler (EBookMsg *msg) +{ + AuthUserResponse *resp = (AuthUserResponse*)msg; + + if (resp->cb) + resp->cb (resp->book, resp->status, resp->closure); +} + +static void +_auth_user_response_dtor (EBookMsg *msg) +{ + AuthUserResponse *resp = (AuthUserResponse*)msg; + + g_object_unref (resp->book); + g_free (resp); +} + +static void +_auth_user_handler (EBookMsg *msg) +{ + AuthUserMsg *auth_msg = (AuthUserMsg *)msg; + AuthUserResponse *response; + GError *error = NULL; + + response = g_new (AuthUserResponse, 1); + e_book_msg_init ((EBookMsg*)response, _auth_user_response_handler, _auth_user_response_dtor); + + response->status = E_BOOK_ERROR_OK; + if (!e_book_authenticate_user (auth_msg->book, auth_msg->user, auth_msg->passwd, auth_msg->auth_method, &error)) { + response->status = error->code; + g_error_free (error); + } + response->book = auth_msg->book; + response->cb = auth_msg->cb; + response->closure = auth_msg->closure; + + g_async_queue_push (from_worker_queue, response); +} + +static void +_auth_user_dtor (EBookMsg *msg) +{ + AuthUserMsg *auth_msg = (AuthUserMsg *)msg; + + g_free (auth_msg->user); + g_free (auth_msg->passwd); + g_free (auth_msg->auth_method); + + g_free (auth_msg); +} + +/* User authentication. */ +void +e_book_async_authenticate_user (EBook *book, + const char *user, + const char *passwd, + const char *auth_method, + EBookCallback cb, + gpointer closure) +{ + AuthUserMsg *msg; + + init_async (); + + msg = g_new (AuthUserMsg, 1); + e_book_msg_init ((EBookMsg*)msg, _auth_user_handler, _auth_user_dtor); + + msg->book = g_object_ref (book); + msg->user = g_strdup (user); + msg->passwd = g_strdup (passwd); + msg->auth_method = g_strdup (auth_method); + msg->cb = cb; + msg->closure = closure; + + g_async_queue_push (to_worker_queue, msg); +} + + + +typedef struct { + EBookMsg msg; + + EBook *book; + char *id; + EBookContactCallback cb; + gpointer closure; +} GetContactMsg; + +typedef struct { + EBookMsg msg; + + EBook *book; + EContact *contact; + EBookStatus status; + EBookContactCallback cb; + gpointer closure; +} GetContactResponse; + +static void +_get_contact_response_handler (EBookMsg *msg) +{ + GetContactResponse *resp = (GetContactResponse*)msg; + + if (resp->cb) + resp->cb (resp->book, resp->status, resp->contact, resp->closure); +} + +static void +_get_contact_response_dtor (EBookMsg *msg) +{ + GetContactResponse *resp = (GetContactResponse*)msg; + + g_object_unref (resp->contact); + g_object_unref (resp->book); + g_free (resp); +} + +static void +_get_contact_handler (EBookMsg *msg) +{ + GetContactMsg *get_contact_msg = (GetContactMsg *)msg; + GetContactResponse *response; + GError *error = NULL; + + response = g_new (GetContactResponse, 1); + e_book_msg_init ((EBookMsg*)response, _get_contact_response_handler, _get_contact_response_dtor); + + response->status = E_BOOK_ERROR_OK; + if (!e_book_get_contact (get_contact_msg->book, get_contact_msg->id, &response->contact, &error)) { + response->status = error->code; + g_error_free (error); + } + response->book = get_contact_msg->book; + response->cb = get_contact_msg->cb; + response->closure = get_contact_msg->closure; + + g_async_queue_push (from_worker_queue, response); +} + +static void +_get_contact_dtor (EBookMsg *msg) +{ + GetContactMsg *get_contact_msg = (GetContactMsg *)msg; + + g_free (get_contact_msg->id); + g_free (get_contact_msg); +} + +/* Fetching contacts. */ +guint +e_book_async_get_contact (EBook *book, + const char *id, + EBookContactCallback cb, + gpointer closure) +{ + GetContactMsg *msg; + + init_async (); + + msg = g_new (GetContactMsg, 1); + e_book_msg_init ((EBookMsg*)msg, _get_contact_handler, _get_contact_dtor); + + msg->book = g_object_ref (book); + msg->id = g_strdup (id); + msg->cb = cb; + msg->closure = closure; + + g_async_queue_push (to_worker_queue, msg); + + return 0; +} + + + +/* Deleting cards. */ +gboolean +e_book_async_remove_contact (EBook *book, + EContact *contact, + EBookCallback cb, + gpointer closure) +{ + const char *id = e_contact_get_const (contact, E_CONTACT_UID); + + return e_book_async_remove_contact_by_id (book, id, cb, closure); +} + +gboolean +e_book_async_remove_contact_by_id (EBook *book, + const char *id, + EBookCallback cb, + gpointer closure) +{ + GList *list = g_list_append (NULL, g_strdup (id)); + + return e_book_async_remove_contacts (book, list, cb, closure); +} + + +typedef struct { + EBookMsg msg; + + EBook *book; + GList *id_list; + EBookCallback cb; + gpointer closure; +} RemoveContactsMsg; + +typedef struct { + EBookMsg msg; + + EBook *book; + EBookStatus status; + EBookCallback cb; + gpointer closure; +} RemoveContactsResponse; + +static void +_remove_contacts_response_handler (EBookMsg *msg) +{ + RemoveContactsResponse *resp = (RemoveContactsResponse*)msg; + + if (resp->cb) + resp->cb (resp->book, resp->status, resp->closure); +} + +static void +_remove_contacts_response_dtor (EBookMsg *msg) +{ + RemoveContactsResponse *resp = (RemoveContactsResponse*)msg; + + g_object_unref (resp->book); + g_free (resp); +} + +static void +_remove_contacts_handler (EBookMsg *msg) +{ + RemoveContactsMsg *remove_contacts_msg = (RemoveContactsMsg *)msg; + RemoveContactsResponse *response; + GError *error = NULL; + + response = g_new (RemoveContactsResponse, 1); + e_book_msg_init ((EBookMsg*)response, _remove_contacts_response_handler, _remove_contacts_response_dtor); + + response->status = E_BOOK_ERROR_OK; + if (!e_book_remove_contacts (remove_contacts_msg->book, remove_contacts_msg->id_list, &error)) { + response->status = error->code; + g_error_free (error); + } + response->book = remove_contacts_msg->book; + response->cb = remove_contacts_msg->cb; + response->closure = remove_contacts_msg->closure; + + g_async_queue_push (from_worker_queue, response); +} + +static void +_remove_contacts_dtor (EBookMsg *msg) +{ + RemoveContactsMsg *remove_contacts_msg = (RemoveContactsMsg *)msg; + + g_list_foreach (remove_contacts_msg->id_list, (GFunc)g_free, NULL); + g_list_free (remove_contacts_msg->id_list); + g_free (remove_contacts_msg); +} + +gboolean +e_book_async_remove_contacts (EBook *book, + GList *id_list, + EBookCallback cb, + gpointer closure) +{ + RemoveContactsMsg *msg; + GList *l; + init_async (); + + msg = g_new (RemoveContactsMsg, 1); + e_book_msg_init ((EBookMsg*)msg, _remove_contacts_handler, _remove_contacts_dtor); + + msg->book = g_object_ref (book); + msg->id_list = g_list_copy (id_list); + for (l = msg->id_list; l; l = l->next) + l->data = g_strdup (l->data); + msg->cb = cb; + msg->closure = closure; + + g_async_queue_push (to_worker_queue, msg); + + return 0; +} + + + +/* Adding contacts. */ +typedef struct { + EBookMsg msg; + + EBook *book; + EContact *contact; + EBookIdCallback cb; + gpointer closure; +} AddContactMsg; + +typedef struct { + EBookMsg msg; + + EBook *book; + char *id; + EBookStatus status; + EBookIdCallback cb; + gpointer closure; +} AddContactResponse; + +static void +_add_contact_response_handler (EBookMsg *msg) +{ + AddContactResponse *resp = (AddContactResponse*)msg; + + if (resp->cb) + resp->cb (resp->book, resp->status, resp->id, resp->closure); +} + +static void +_add_contact_response_dtor (EBookMsg *msg) +{ + AddContactResponse *resp = (AddContactResponse*)msg; + + g_object_unref (resp->book); + g_free (resp->id); + g_free (resp); +} + +static void +_add_contact_handler (EBookMsg *msg) +{ + AddContactMsg *add_contact_msg = (AddContactMsg *)msg; + AddContactResponse *response; + GError *error = NULL; + + response = g_new (AddContactResponse, 1); + e_book_msg_init ((EBookMsg*)response, _add_contact_response_handler, _add_contact_response_dtor); + + response->status = E_BOOK_ERROR_OK; + if (!e_book_add_contact (add_contact_msg->book, add_contact_msg->contact, &error)) { + response->status = error->code; + response->id = NULL; + g_error_free (error); + } + else { + response->id = e_contact_get (add_contact_msg->contact, E_CONTACT_UID); + } + response->book = add_contact_msg->book; + response->cb = add_contact_msg->cb; + response->closure = add_contact_msg->closure; + + g_async_queue_push (from_worker_queue, response); +} + +static void +_add_contact_dtor (EBookMsg *msg) +{ + AddContactMsg *add_contact_msg = (AddContactMsg *)msg; + + g_object_unref (add_contact_msg->contact); + g_free (add_contact_msg); +} + +gboolean +e_book_async_add_contact (EBook *book, + EContact *contact, + EBookIdCallback cb, + gpointer closure) +{ + AddContactMsg *msg; + + init_async (); + + msg = g_new (AddContactMsg, 1); + e_book_msg_init ((EBookMsg*)msg, _add_contact_handler, _add_contact_dtor); + + msg->book = g_object_ref (book); + msg->contact = g_object_ref (contact); /* XXX maybe we should _duplicate it here instead */ + msg->cb = cb; + msg->closure = closure; + + g_async_queue_push (to_worker_queue, msg); + + return TRUE; +} + + + +/* Modifying cards. */ +typedef struct { + EBookMsg msg; + + EBook *book; + EContact *contact; + EBookCallback cb; + gpointer closure; +} CommitContactMsg; + +typedef struct { + EBookMsg msg; + + EBook *book; + EBookStatus status; + EBookCallback cb; + gpointer closure; +} CommitContactResponse; + +static void +_commit_contact_response_handler (EBookMsg *msg) +{ + CommitContactResponse *resp = (CommitContactResponse*)msg; + + if (resp->cb) + resp->cb (resp->book, resp->status, resp->closure); +} + +static void +_commit_contact_response_dtor (EBookMsg *msg) +{ + CommitContactResponse *resp = (CommitContactResponse*)msg; + + g_object_unref (resp->book); + g_free (resp); +} + +static void +_commit_contact_handler (EBookMsg *msg) +{ + CommitContactMsg *commit_contact_msg = (CommitContactMsg *)msg; + CommitContactResponse *response; + GError *error = NULL; + + response = g_new (CommitContactResponse, 1); + e_book_msg_init ((EBookMsg*)response, _commit_contact_response_handler, _commit_contact_response_dtor); + + response->status = E_BOOK_ERROR_OK; + if (!e_book_commit_contact (commit_contact_msg->book, commit_contact_msg->contact, &error)) { + response->status = error->code; + g_error_free (error); + } + response->book = commit_contact_msg->book; + response->cb = commit_contact_msg->cb; + response->closure = commit_contact_msg->closure; + + g_async_queue_push (from_worker_queue, response); +} + +static void +_commit_contact_dtor (EBookMsg *msg) +{ + CommitContactMsg *commit_contact_msg = (CommitContactMsg *)msg; + + g_object_unref (commit_contact_msg->contact); + g_free (commit_contact_msg); +} + + +gboolean +e_book_async_commit_contact (EBook *book, + EContact *contact, + EBookCallback cb, + gpointer closure) +{ + CommitContactMsg *msg; + + init_async (); + + msg = g_new (CommitContactMsg, 1); + e_book_msg_init ((EBookMsg*)msg, _commit_contact_handler, _commit_contact_dtor); + + msg->book = g_object_ref (book); + msg->contact = g_object_ref (contact); /* XXX maybe we should _duplicate it here instead */ + msg->cb = cb; + msg->closure = closure; + + g_async_queue_push (to_worker_queue, msg); + + return TRUE; +} + + + +typedef struct { + EBookMsg msg; + + EBook *book; + EBookQuery *query; + EBookBookViewCallback cb; + gpointer closure; +} GetBookViewMsg; + +typedef struct { + EBookMsg msg; + + EBook *book; + EBookStatus status; + EBookView *book_view; + EBookBookViewCallback cb; + gpointer closure; +} GetBookViewResponse; + +static void +_get_book_view_response_handler (EBookMsg *msg) +{ + GetBookViewResponse *resp = (GetBookViewResponse*)msg; + + if (resp->cb) + resp->cb (resp->book, resp->status, resp->book_view, resp->closure); +} + +static void +_get_book_view_response_dtor (EBookMsg *msg) +{ + GetBookViewResponse *resp = (GetBookViewResponse*)msg; + + g_object_unref (resp->book); + g_free (resp); +} + +static void +_get_book_view_handler (EBookMsg *msg) +{ + GetBookViewMsg *view_msg = (GetBookViewMsg *)msg; + GetBookViewResponse *response; + GError *error = NULL; + + response = g_new (GetBookViewResponse, 1); + e_book_msg_init ((EBookMsg*)response, _get_book_view_response_handler, _get_book_view_response_dtor); + + response->status = E_BOOK_ERROR_OK; + if (!e_book_get_book_view (view_msg->book, view_msg->query, NULL, -1, &response->book_view, &error)) { + response->status = error->code; + g_error_free (error); + } + response->book = view_msg->book; + response->cb = view_msg->cb; + response->closure = view_msg->closure; + + g_async_queue_push (from_worker_queue, response); +} + +static void +_get_book_view_dtor (EBookMsg *msg) +{ + GetBookViewMsg *view_msg = (GetBookViewMsg *)msg; + + e_book_query_unref (view_msg->query); + g_free (view_msg); +} + +guint +e_book_async_get_book_view (EBook *book, + const gchar *query, + EBookBookViewCallback cb, + gpointer closure) +{ + GetBookViewMsg *msg; + + init_async (); + + msg = g_new (GetBookViewMsg, 1); + e_book_msg_init ((EBookMsg*)msg, _get_book_view_handler, _get_book_view_dtor); + + msg->book = g_object_ref (book); + msg->query = e_book_query_from_string (query); + msg->cb = cb; + msg->closure = closure; + + g_async_queue_push (to_worker_queue, msg); + + return 0; +} + + + +typedef struct { + EBookMsg msg; + + EBook *book; + EBookQuery *query; + EBookContactsCallback cb; + gpointer closure; +} GetContactsMsg; + +typedef struct { + EBookMsg msg; + + EBook *book; + EBookStatus status; + GList *contacts; + EBookContactsCallback cb; + gpointer closure; +} GetContactsResponse; + +static void +_get_contacts_response_handler (EBookMsg *msg) +{ + GetContactsResponse *resp = (GetContactsResponse*)msg; + + if (resp->cb) + resp->cb (resp->book, resp->status, resp->contacts, resp->closure); +} + +static void +_get_contacts_response_dtor (EBookMsg *msg) +{ + GetContactsResponse *resp = (GetContactsResponse*)msg; + + g_object_unref (resp->book); + g_free (resp); +} + +static void +_get_contacts_handler (EBookMsg *msg) +{ + GetContactsMsg *view_msg = (GetContactsMsg *)msg; + GetContactsResponse *response; + GError *error = NULL; + + response = g_new (GetContactsResponse, 1); + e_book_msg_init ((EBookMsg*)response, _get_contacts_response_handler, _get_contacts_response_dtor); + + response->status = E_BOOK_ERROR_OK; + if (!e_book_get_contacts (view_msg->book, view_msg->query, &response->contacts, &error)) { + response->status = error->code; + g_error_free (error); + } + response->book = view_msg->book; + response->cb = view_msg->cb; + response->closure = view_msg->closure; + + g_async_queue_push (from_worker_queue, response); +} + +static void +_get_contacts_dtor (EBookMsg *msg) +{ + GetContactsMsg *view_msg = (GetContactsMsg *)msg; + + e_book_query_unref (view_msg->query); + g_free (view_msg); +} + +guint +e_book_async_get_contacts (EBook *book, + const gchar *query, + EBookContactsCallback cb, + gpointer closure) +{ + GetContactsMsg *msg; + + init_async (); + + msg = g_new (GetContactsMsg, 1); + e_book_msg_init ((EBookMsg*)msg, _get_contacts_handler, _get_contacts_dtor); + + msg->book = g_object_ref (book); + msg->query = e_book_query_from_string (query); + msg->cb = cb; + msg->closure = closure; + + g_async_queue_push (to_worker_queue, msg); + + return 0; +} diff --git a/addressbook/backend/ebook/e-book-async.h b/addressbook/backend/ebook/e-book-async.h new file mode 100644 index 0000000000..097f3cff61 --- /dev/null +++ b/addressbook/backend/ebook/e-book-async.h @@ -0,0 +1,107 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ +/* + * The Evolution addressbook client object. + * + * Author: + * Chris Toshok (toshok@ximian.com) + * + * Copyright (C) 2003, Ximian, Inc. + */ + +#ifndef __E_BOOK_ASYNC_H__ +#define __E_BOOK_ASYNC_H__ + +#include +#include + +#include +#include +#include + +G_BEGIN_DECLS + +/* Callbacks for asynchronous functions. */ +typedef void (*EBookCallback) (EBook *book, EBookStatus status, gpointer closure); +typedef void (*EBookOpenProgressCallback) (EBook *book, + const char *status_message, + short percent, + gpointer closure); +typedef void (*EBookIdCallback) (EBook *book, EBookStatus status, const char *id, gpointer closure); +typedef void (*EBookContactCallback) (EBook *book, EBookStatus status, EContact *contact, gpointer closure); +typedef void (*EBookContactsCallback) (EBook *book, EBookStatus status, GList *contacts, gpointer closure); +typedef void (*EBookBookViewCallback) (EBook *book, EBookStatus status, EBookView *book_view, gpointer closure); +typedef void (*EBookFieldsCallback) (EBook *book, EBookStatus status, EList *fields, gpointer closure); +typedef void (*EBookAuthMethodsCallback) (EBook *book, EBookStatus status, EList *auth_methods, gpointer closure); + +void e_book_async_load_uri (EBook *book, + const char *uri, + EBookCallback open_response, + gpointer closure); + +void e_book_async_get_default_addressbook (EBookCallback open_response, + gpointer closure); + +void e_book_async_unload_uri (EBook *book); + +guint e_book_async_get_supported_fields (EBook *book, + EBookFieldsCallback cb, + gpointer closure); + +guint e_book_async_get_supported_auth_methods (EBook *book, + EBookAuthMethodsCallback cb, + gpointer closure); + +/* User authentication. */ +void e_book_async_authenticate_user (EBook *book, + const char *user, + const char *passwd, + const char *auth_method, + EBookCallback cb, + gpointer closure); + +/* Fetching cards. */ +guint e_book_async_get_contact (EBook *book, + const char *id, + EBookContactCallback cb, + gpointer closure); + +guint e_book_async_get_contacts (EBook *book, + const char *query, + EBookContactsCallback cb, + gpointer closure); + +/* Deleting cards. */ +gboolean e_book_async_remove_contact (EBook *book, + EContact *contact, + EBookCallback cb, + gpointer closure); +gboolean e_book_async_remove_contact_by_id (EBook *book, + const char *id, + EBookCallback cb, + gpointer closure); + +gboolean e_book_async_remove_contacts (EBook *book, + GList *id_list, + EBookCallback cb, + gpointer closure); + +/* Adding cards. */ +gboolean e_book_async_add_contact (EBook *book, + EContact *contact, + EBookIdCallback cb, + gpointer closure); + +/* Modifying cards. */ +gboolean e_book_async_commit_contact (EBook *book, + EContact *contact, + EBookCallback cb, + gpointer closure); + +guint e_book_async_get_book_view (EBook *book, + const gchar *query, /* XXX this needs to change to an EBookQuery */ + EBookBookViewCallback cb, + gpointer closure); + +G_END_DECLS + +#endif /* ! __E_BOOK_H__ */ diff --git a/addressbook/backend/ebook/e-book-listener.c b/addressbook/backend/ebook/e-book-listener.c index 9d6d876045..0bb5193376 100644 --- a/addressbook/backend/ebook/e-book-listener.c +++ b/addressbook/backend/ebook/e-book-listener.c @@ -11,13 +11,14 @@ #include #include +#include "e-contact.h" #include "e-book-listener.h" #include "e-book-marshal.h" -static EBookStatus e_book_listener_convert_status (GNOME_Evolution_Addressbook_BookListener_CallStatus status); +static EBookStatus e_book_listener_convert_status (GNOME_Evolution_Addressbook_CallStatus status); enum { - RESPONSES_QUEUED, + RESPONSE, LAST_SIGNAL }; @@ -26,569 +27,267 @@ static guint e_book_listener_signals [LAST_SIGNAL]; static BonoboObjectClass *parent_class; struct _EBookListenerPrivate { - GList *response_queue; - gint timeout_id; - - guint timeout_lock : 1; guint stopped : 1; }; -static void -response_free (EBookListenerResponse *resp) -{ - if (resp == NULL) - return; - - g_free (resp->msg); - g_free (resp->id); - - if (resp->book != CORBA_OBJECT_NIL) { - CORBA_Environment ev; - - CORBA_exception_init (&ev); - - bonobo_object_release_unref (resp->book, &ev); - - if (ev._major != CORBA_NO_EXCEPTION) { - g_warning ("e_book_listener_destroy: " - "Exception destroying book " - "in response queue!\n"); - } - - CORBA_exception_free (&ev); - } - - if (resp->cursor != CORBA_OBJECT_NIL) { - CORBA_Environment ev; - - CORBA_exception_init (&ev); - - bonobo_object_release_unref (resp->cursor, &ev); - - if (ev._major != CORBA_NO_EXCEPTION) { - g_warning ("e_book_listener_destroy: " - "Exception destroying cursor " - "in response queue!\n"); - } - - CORBA_exception_free (&ev); - } - - if (resp->book_view != CORBA_OBJECT_NIL) { - CORBA_Environment ev; - - CORBA_exception_init (&ev); - - bonobo_object_release_unref (resp->book_view, &ev); - - if (ev._major != CORBA_NO_EXCEPTION) { - g_warning ("e_book_listener_destroy: " - "Exception destroying book_view " - "in response queue!\n"); - } - - CORBA_exception_free (&ev); - } - - g_free (resp); -} - -static gboolean -e_book_listener_check_queue (EBookListener *listener) -{ - if (listener->priv->timeout_lock) - return TRUE; - - listener->priv->timeout_lock = TRUE; - - if (listener->priv->response_queue != NULL && !listener->priv->stopped) { - g_signal_emit (listener, e_book_listener_signals [RESPONSES_QUEUED], 0); - } - - if (listener->priv->response_queue == NULL || listener->priv->stopped) { - listener->priv->timeout_id = 0; - listener->priv->timeout_lock = FALSE; - bonobo_object_unref (BONOBO_OBJECT (listener)); /* release the timeout's reference */ - return FALSE; - } - - listener->priv->timeout_lock = FALSE; - return TRUE; -} - -static void -e_book_listener_queue_response (EBookListener *listener, - EBookListenerResponse *response) +static EBookStatus +e_book_listener_convert_status (const GNOME_Evolution_Addressbook_CallStatus status) { - if (response == NULL) - return; - - if (listener->priv->stopped) { - response_free (response); - return; - } - - listener->priv->response_queue = g_list_append (listener->priv->response_queue, response); - - if (listener->priv->timeout_id == 0) { - - /* 20 == an arbitrary small integer */ - listener->priv->timeout_id = g_timeout_add (20, (GSourceFunc) e_book_listener_check_queue, listener); - - /* Hold a reference on behalf of the timeout */ - bonobo_object_ref (BONOBO_OBJECT (listener)); - + switch (status) { + case GNOME_Evolution_Addressbook_Success: + return E_BOOK_ERROR_OK; + case GNOME_Evolution_Addressbook_RepositoryOffline: + return E_BOOK_ERROR_REPOSITORY_OFFLINE; + case GNOME_Evolution_Addressbook_PermissionDenied: + return E_BOOK_ERROR_PERMISSION_DENIED; + case GNOME_Evolution_Addressbook_ContactNotFound: + return E_BOOK_ERROR_CONTACT_NOT_FOUND; + case GNOME_Evolution_Addressbook_ContactIdAlreadyExists: + return E_BOOK_ERROR_CONTACT_ID_ALREADY_EXISTS; + case GNOME_Evolution_Addressbook_AuthenticationFailed: + return E_BOOK_ERROR_AUTHENTICATION_FAILED; + case GNOME_Evolution_Addressbook_AuthenticationRequired: + return E_BOOK_ERROR_AUTHENTICATION_REQUIRED; + case GNOME_Evolution_Addressbook_TLSNotAvailable: + return E_BOOK_ERROR_TLS_NOT_AVAILABLE; + case GNOME_Evolution_Addressbook_NoSuchBook: + return E_BOOK_ERROR_NO_SUCH_BOOK; + case GNOME_Evolution_Addressbook_OtherError: + default: + return E_BOOK_ERROR_OTHER_ERROR; } } -/* Add, Remove, Modify */ -static void -e_book_listener_queue_generic_response (EBookListener *listener, - EBookListenerOperation op, - EBookStatus status) -{ - EBookListenerResponse *resp; - - if (listener->priv->stopped) - return; - - resp = g_new0 (EBookListenerResponse, 1); - - resp->op = op; - resp->status = status; - - e_book_listener_queue_response (listener, resp); -} - -static void -e_book_listener_queue_open_response (EBookListener *listener, - EBookStatus status, - GNOME_Evolution_Addressbook_Book book) -{ - EBookListenerResponse *resp; - - if (listener->priv->stopped) - return; - - resp = g_new0 (EBookListenerResponse, 1); - - resp->op = OpenBookResponse; - resp->status = status; - resp->book = book; - - e_book_listener_queue_response (listener, resp); -} - -static void -e_book_listener_queue_open_progress (EBookListener *listener, - const char *msg, - short percent) -{ - EBookListenerResponse *resp; - - if (listener->priv->stopped) - return; - - resp = g_new0 (EBookListenerResponse, 1); - - resp->op = OpenProgressEvent; - resp->msg = g_strdup (msg); - resp->percent = percent; - - e_book_listener_queue_response (listener, resp); -} - - -static void -e_book_listener_queue_create_card_response (EBookListener *listener, - EBookStatus status, - const char *id) -{ - EBookListenerResponse *resp; - - if (listener->priv->stopped) - return; - - resp = g_new0 (EBookListenerResponse, 1); - - resp->op = CreateCardResponse; - resp->status = status; - resp->id = g_strdup (id); - - e_book_listener_queue_response (listener, resp); -} - -static void -e_book_listener_queue_get_vcard_response (EBookListener *listener, - EBookStatus status, - const char *vcard) -{ - EBookListenerResponse *resp; - - if (listener->priv->stopped) - return; - - resp = g_new0 (EBookListenerResponse, 1); - - resp->op = GetCardResponse; - resp->status = status; - resp->vcard = g_strdup (vcard); - - e_book_listener_queue_response (listener, resp); -} - -static void -e_book_listener_queue_get_cursor_response (EBookListener *listener, - EBookStatus status, - GNOME_Evolution_Addressbook_CardCursor cursor) -{ - EBookListenerResponse *resp; - - if (listener->priv->stopped) - return; - - resp = g_new0 (EBookListenerResponse, 1); - - resp->op = GetCursorResponse; - resp->status = status; - resp->cursor = cursor; - - e_book_listener_queue_response (listener, resp); -} - -static void -e_book_listener_queue_get_view_response (EBookListener *listener, - EBookStatus status, - GNOME_Evolution_Addressbook_BookView book_view) -{ - EBookListenerResponse *resp; - - if (listener->priv->stopped) - return; - - resp = g_new0 (EBookListenerResponse, 1); - - resp->op = GetBookViewResponse; - resp->status = status; - resp->book_view = book_view; - - e_book_listener_queue_response (listener, resp); -} - static void -e_book_listener_queue_get_changes_response (EBookListener *listener, - EBookStatus status, - GNOME_Evolution_Addressbook_BookView book_view) +impl_BookListener_respond_create_contact (PortableServer_Servant servant, + const GNOME_Evolution_Addressbook_CallStatus status, + const CORBA_char* id, + CORBA_Environment *ev) { - EBookListenerResponse *resp; - - if (listener->priv->stopped) - return; - - resp = g_new0 (EBookListenerResponse, 1); - - resp->op = GetChangesResponse; - resp->status = status; - resp->book_view = book_view; - - e_book_listener_queue_response (listener, resp); -} - -static void -e_book_listener_queue_link_status (EBookListener *listener, - gboolean connected) -{ - EBookListenerResponse *resp; - - if (listener->priv->stopped) - return; + EBookListener *listener = E_BOOK_LISTENER (bonobo_object (servant)); + EBookListenerResponse response; - resp = g_new0 (EBookListenerResponse, 1); + response.op = CreateContactResponse; + response.status = e_book_listener_convert_status (status); + response.id = g_strdup (id); - resp->op = LinkStatusEvent; - resp->connected = connected; + g_signal_emit (listener, e_book_listener_signals [RESPONSE], 0, &response); - e_book_listener_queue_response (listener, resp); + g_free (response.id); } static void -e_book_listener_queue_writable_status (EBookListener *listener, - gboolean writable) +impl_BookListener_respond_remove_contacts (PortableServer_Servant servant, + const GNOME_Evolution_Addressbook_CallStatus status, + CORBA_Environment *ev) { - EBookListenerResponse *resp; - - if (listener->priv->stopped) - return; - - resp = g_new0 (EBookListenerResponse, 1); + EBookListener *listener = E_BOOK_LISTENER (bonobo_object (servant)); + EBookListenerResponse response; - resp->op = WritableStatusEvent; - resp->writable = writable; + response.op = RemoveContactResponse; + response.status = e_book_listener_convert_status (status); - e_book_listener_queue_response (listener, resp); + g_signal_emit (listener, e_book_listener_signals [RESPONSE], 0, &response); } static void -e_book_listener_queue_authentication_response (EBookListener *listener, - EBookStatus status) +impl_BookListener_respond_modify_contact (PortableServer_Servant servant, + const GNOME_Evolution_Addressbook_CallStatus status, + CORBA_Environment *ev) { - EBookListenerResponse *resp; - - if (listener->priv->stopped) - return; - - resp = g_new0 (EBookListenerResponse, 1); + EBookListener *listener = E_BOOK_LISTENER (bonobo_object (servant)); + EBookListenerResponse response; - resp->op = AuthenticationResponse; - resp->status = status; + response.op = ModifyContactResponse; + response.status = e_book_listener_convert_status (status); - e_book_listener_queue_response (listener, resp); + g_signal_emit (listener, e_book_listener_signals [RESPONSE], 0, &response); } static void -e_book_listener_queue_get_supported_fields_response (EBookListener *listener, - EBookStatus status, - const GNOME_Evolution_Addressbook_stringlist *fields) +impl_BookListener_respond_get_contact (PortableServer_Servant servant, + const GNOME_Evolution_Addressbook_CallStatus status, + const CORBA_char* card, + CORBA_Environment *ev) { - EBookListenerResponse *resp; - int i; - - if (listener->priv->stopped) - return; - - resp = g_new0 (EBookListenerResponse, 1); + EBookListener *listener = E_BOOK_LISTENER (bonobo_object (servant)); + EBookListenerResponse response; - resp->op = GetSupportedFieldsResponse; - resp->status = status; - resp->list = e_list_new ((EListCopyFunc)g_strdup, (EListFreeFunc)g_free, NULL); + response.op = GetContactResponse; + response.status = e_book_listener_convert_status (status); + response.vcard = g_strdup (card); - for (i = 0; i < fields->_length; i ++) { - e_list_append (resp->list, fields->_buffer[i]); - } + g_signal_emit (listener, e_book_listener_signals [RESPONSE], 0, &response); - e_book_listener_queue_response (listener, resp); + g_free (response.vcard); } static void -e_book_listener_queue_get_supported_auth_methods_response (EBookListener *listener, - EBookStatus status, - const GNOME_Evolution_Addressbook_stringlist *auth_methods) +impl_BookListener_respond_get_contact_list (PortableServer_Servant servant, + const GNOME_Evolution_Addressbook_CallStatus status, + const GNOME_Evolution_Addressbook_stringlist *cards, + CORBA_Environment *ev) { - EBookListenerResponse *resp; + EBookListener *listener = E_BOOK_LISTENER (bonobo_object (servant)); + EBookListenerResponse response; int i; if (listener->priv->stopped) return; - resp = g_new0 (EBookListenerResponse, 1); + response.op = GetContactListResponse; + response.status = e_book_listener_convert_status (status); + response.list = NULL; - resp->op = GetSupportedAuthMethodsResponse; - resp->status = status; - resp->list = e_list_new ((EListCopyFunc)g_strdup, (EListFreeFunc)g_free, NULL); - - for (i = 0; i < auth_methods->_length; i ++) { - e_list_append (resp->list, auth_methods->_buffer[i]); + for (i = 0; i < cards->_length; i ++) { + response.list = g_list_prepend (response.list, e_contact_new_from_vcard (cards->_buffer[i])); } - e_book_listener_queue_response (listener, resp); -} - -static void -impl_BookListener_respond_create_card (PortableServer_Servant servant, - const GNOME_Evolution_Addressbook_BookListener_CallStatus status, - const CORBA_char* id, - CORBA_Environment *ev) -{ - EBookListener *listener = E_BOOK_LISTENER (bonobo_object (servant)); - - e_book_listener_queue_create_card_response ( - listener, - e_book_listener_convert_status (status), - id); -} - -static void -impl_BookListener_respond_remove_cards (PortableServer_Servant servant, - const GNOME_Evolution_Addressbook_BookListener_CallStatus status, - CORBA_Environment *ev) -{ - EBookListener *listener = E_BOOK_LISTENER (bonobo_object (servant)); - - e_book_listener_queue_generic_response ( - listener, RemoveCardResponse, - e_book_listener_convert_status (status)); -} - -static void -impl_BookListener_respond_modify_card (PortableServer_Servant servant, - const GNOME_Evolution_Addressbook_BookListener_CallStatus status, - CORBA_Environment *ev) -{ - EBookListener *listener = E_BOOK_LISTENER (bonobo_object (servant)); - - e_book_listener_queue_generic_response ( - listener, ModifyCardResponse, - e_book_listener_convert_status (status)); -} - -static void -impl_BookListener_respond_get_vcard (PortableServer_Servant servant, - const GNOME_Evolution_Addressbook_BookListener_CallStatus status, - const CORBA_char* card, - CORBA_Environment *ev) -{ - EBookListener *listener = E_BOOK_LISTENER (bonobo_object (servant)); - - e_book_listener_queue_get_vcard_response ( - listener, - e_book_listener_convert_status (status), - g_strdup (card)); -} - -static void -impl_BookListener_respond_get_cursor (PortableServer_Servant servant, - const GNOME_Evolution_Addressbook_BookListener_CallStatus status, - const GNOME_Evolution_Addressbook_CardCursor cursor, - CORBA_Environment *ev) -{ - EBookListener *listener = E_BOOK_LISTENER (bonobo_object (servant)); - GNOME_Evolution_Addressbook_CardCursor cursor_copy; - - cursor_copy = bonobo_object_dup_ref (cursor, ev); + g_signal_emit (listener, e_book_listener_signals [RESPONSE], 0, &response); - if (ev->_major != CORBA_NO_EXCEPTION) { - g_warning ("EBookListener: Exception while duplicating CardCursor!\n"); - return; - } - - e_book_listener_queue_get_cursor_response ( - listener, - e_book_listener_convert_status (status), - cursor_copy); + /* XXX free response.list? */ } static void impl_BookListener_respond_get_view (PortableServer_Servant servant, - const GNOME_Evolution_Addressbook_BookListener_CallStatus status, + const GNOME_Evolution_Addressbook_CallStatus status, const GNOME_Evolution_Addressbook_BookView book_view, CORBA_Environment *ev) { - EBookListener *listener = E_BOOK_LISTENER (bonobo_object (servant)); - GNOME_Evolution_Addressbook_BookView book_view_copy; + EBookListener *listener = E_BOOK_LISTENER (bonobo_object (servant)); + EBookListenerResponse response; - book_view_copy = bonobo_object_dup_ref (book_view, ev); + printf ("impl_BookListener_respond_get_view\n"); - if (ev->_major != CORBA_NO_EXCEPTION) { - g_warning ("EBookListener: Exception while duplicating BookView.\n"); + if (listener->priv->stopped) return; - } - e_book_listener_queue_get_view_response ( - listener, - e_book_listener_convert_status (status), - book_view_copy); + response.op = GetBookViewResponse; + response.status = e_book_listener_convert_status (status); + response.book_view = bonobo_object_dup_ref (book_view, ev); + + g_signal_emit (listener, e_book_listener_signals [RESPONSE], 0, &response); } static void impl_BookListener_respond_get_changes (PortableServer_Servant servant, - const GNOME_Evolution_Addressbook_BookListener_CallStatus status, - const GNOME_Evolution_Addressbook_BookView book_view, + const GNOME_Evolution_Addressbook_CallStatus status, + const GNOME_Evolution_Addressbook_BookChangeList *changes, CORBA_Environment *ev) { EBookListener *listener = E_BOOK_LISTENER (bonobo_object (servant)); - GNOME_Evolution_Addressbook_BookView book_view_copy; + EBookListenerResponse response; + int i; - book_view_copy = bonobo_object_dup_ref (book_view, ev); + response.op = GetChangesResponse; + response.status = e_book_listener_convert_status (status); + response.list = NULL; + + for (i = 0; i < changes->_length; i ++) { + EBookChange *change = g_new (EBookChange, 1); + GNOME_Evolution_Addressbook_BookChangeItem corba_change = changes->_buffer[i]; + + switch (corba_change._d) { + case GNOME_Evolution_Addressbook_ContactAdded: + change->change_type = E_BOOK_CHANGE_CARD_ADDED; + change->vcard = g_strdup (corba_change._u.add_vcard); + break; + case GNOME_Evolution_Addressbook_ContactDeleted: + change->change_type = E_BOOK_CHANGE_CARD_DELETED; + change->id = g_strdup (corba_change._u.del_id); + break; + case GNOME_Evolution_Addressbook_ContactModified: + change->change_type = E_BOOK_CHANGE_CARD_MODIFIED; + change->vcard = g_strdup (corba_change._u.mod_vcard); + break; + } - if (ev->_major != CORBA_NO_EXCEPTION) { - g_warning ("EBookListener: Exception while duplicating BookView.\n"); - return; + response.list = g_list_prepend (response.list, change); } - e_book_listener_queue_get_changes_response ( - listener, - e_book_listener_convert_status (status), - book_view_copy); + g_signal_emit (listener, e_book_listener_signals [RESPONSE], 0, &response); } static void impl_BookListener_respond_open_book (PortableServer_Servant servant, - const GNOME_Evolution_Addressbook_BookListener_CallStatus status, - const GNOME_Evolution_Addressbook_Book book, + const GNOME_Evolution_Addressbook_CallStatus status, CORBA_Environment *ev) { - EBookListener *listener = E_BOOK_LISTENER (bonobo_object (servant)); - GNOME_Evolution_Addressbook_Book book_copy; - - book_copy = bonobo_object_dup_ref (book, ev); + EBookListener *listener = E_BOOK_LISTENER (bonobo_object (servant)); + EBookListenerResponse response; - if (ev->_major != CORBA_NO_EXCEPTION) { - g_warning ("EBookListener: Exception while duplicating Book!\n"); - return; - } + response.op = OpenBookResponse; + response.status = e_book_listener_convert_status (status); - e_book_listener_queue_open_response ( - listener, - e_book_listener_convert_status (status), - book_copy); + g_signal_emit (listener, e_book_listener_signals [RESPONSE], 0, &response); } static void -impl_BookListener_report_open_book_progress (PortableServer_Servant servant, - const CORBA_char *status_message, - const CORBA_short percent, - CORBA_Environment *ev) +impl_BookListener_respond_remove_book (PortableServer_Servant servant, + const GNOME_Evolution_Addressbook_CallStatus status, + CORBA_Environment *ev) { EBookListener *listener = E_BOOK_LISTENER (bonobo_object (servant)); + EBookListenerResponse response; - e_book_listener_queue_open_progress ( - listener, status_message, percent); + response.op = RemoveBookResponse; + response.status = e_book_listener_convert_status (status); + + g_signal_emit (listener, e_book_listener_signals [RESPONSE], 0, &response); } static void impl_BookListener_respond_authentication_result (PortableServer_Servant servant, - const GNOME_Evolution_Addressbook_BookListener_CallStatus status, + const GNOME_Evolution_Addressbook_CallStatus status, CORBA_Environment *ev) { EBookListener *listener = E_BOOK_LISTENER (bonobo_object (servant)); + EBookListenerResponse response; + + response.op = AuthenticationResponse; + response.status = e_book_listener_convert_status (status); - e_book_listener_queue_authentication_response ( - listener, status); + g_signal_emit (listener, e_book_listener_signals [RESPONSE], 0, &response); } static void -impl_BookListener_response_get_supported_fields (PortableServer_Servant servant, - const GNOME_Evolution_Addressbook_BookListener_CallStatus status, - const GNOME_Evolution_Addressbook_stringlist *fields, - CORBA_Environment *ev) +impl_BookListener_respond_get_supported_fields (PortableServer_Servant servant, + const GNOME_Evolution_Addressbook_CallStatus status, + const GNOME_Evolution_Addressbook_stringlist *fields, + CORBA_Environment *ev) { EBookListener *listener = E_BOOK_LISTENER (bonobo_object (servant)); + EBookListenerResponse response; + int i; - e_book_listener_queue_get_supported_fields_response ( - listener, status, fields); -} + response.op = GetSupportedFieldsResponse; + response.status = e_book_listener_convert_status (status); + response.list = NULL; -static void -impl_BookListener_response_get_supported_auth_methods (PortableServer_Servant servant, - const GNOME_Evolution_Addressbook_BookListener_CallStatus status, - const GNOME_Evolution_Addressbook_stringlist *auth_methods, - CORBA_Environment *ev) -{ - EBookListener *listener = E_BOOK_LISTENER (bonobo_object (servant)); + for (i = 0; i < fields->_length; i ++) + response.list = g_list_prepend (response.list, g_strdup (fields->_buffer[i])); - e_book_listener_queue_get_supported_auth_methods_response ( - listener, status, auth_methods); + g_signal_emit (listener, e_book_listener_signals [RESPONSE], 0, &response); } static void -impl_BookListener_report_connection_status (PortableServer_Servant servant, - const CORBA_boolean connected, - CORBA_Environment *ev) +impl_BookListener_respond_get_supported_auth_methods (PortableServer_Servant servant, + const GNOME_Evolution_Addressbook_CallStatus status, + const GNOME_Evolution_Addressbook_stringlist *auth_methods, + CORBA_Environment *ev) { EBookListener *listener = E_BOOK_LISTENER (bonobo_object (servant)); + EBookListenerResponse response; + int i; + + response.op = GetSupportedAuthMethodsResponse; + response.status = e_book_listener_convert_status (status); + response.list = NULL; - e_book_listener_queue_link_status ( - listener, connected); + for (i = 0; i < auth_methods->_length; i ++) + response.list = g_list_prepend (response.list, g_strdup (auth_methods->_buffer[i])); + + g_signal_emit (listener, e_book_listener_signals [RESPONSE], 0, &response); } static void @@ -597,89 +296,20 @@ impl_BookListener_report_writable (PortableServer_Servant servant, CORBA_Environment *ev) { EBookListener *listener = E_BOOK_LISTENER (bonobo_object (servant)); + EBookListenerResponse response; - e_book_listener_queue_writable_status (listener, writable); -} + response.op = WritableStatusEvent; + response.writable = writable; -/** - * e_book_listener_check_pending: - * @listener: the #EBookListener - * - * Returns: the number of items on the response queue, - * or -1 if the @listener is isn't an #EBookListener. - */ -int -e_book_listener_check_pending (EBookListener *listener) -{ - g_return_val_if_fail (listener != NULL, -1); - g_return_val_if_fail (E_IS_BOOK_LISTENER (listener), -1); - - return g_list_length (listener->priv->response_queue); + g_signal_emit (listener, e_book_listener_signals [RESPONSE], 0, &response); } -/** - * e_book_listener_pop_response: - * @listener: the #EBookListener for which a request is to be popped - * - * Returns: an #EBookListenerResponse if there are responses on the - * queue to be returned; %NULL if there aren't, or if the @listener - * isn't an EBookListener. - */ -EBookListenerResponse * -e_book_listener_pop_response (EBookListener *listener) -{ - EBookListenerResponse *resp; - GList *popped; - - g_return_val_if_fail (listener != NULL, NULL); - g_return_val_if_fail (E_IS_BOOK_LISTENER (listener), NULL); - - if (listener->priv->response_queue == NULL) - return NULL; - - resp = listener->priv->response_queue->data; - - popped = listener->priv->response_queue; - listener->priv->response_queue = - g_list_remove_link (listener->priv->response_queue, - listener->priv->response_queue); - g_list_free_1 (popped); - - return resp; -} - -static EBookStatus -e_book_listener_convert_status (const GNOME_Evolution_Addressbook_BookListener_CallStatus status) +static void +impl_BookListener_respond_progress (PortableServer_Servant servant, + const CORBA_char * message, + const CORBA_short percent, + CORBA_Environment *ev) { - switch (status) { - case GNOME_Evolution_Addressbook_BookListener_Success: - return E_BOOK_STATUS_SUCCESS; - case GNOME_Evolution_Addressbook_BookListener_RepositoryOffline: - return E_BOOK_STATUS_REPOSITORY_OFFLINE; - case GNOME_Evolution_Addressbook_BookListener_PermissionDenied: - return E_BOOK_STATUS_PERMISSION_DENIED; - case GNOME_Evolution_Addressbook_BookListener_CardNotFound: - return E_BOOK_STATUS_CARD_NOT_FOUND; - case GNOME_Evolution_Addressbook_BookListener_CardIdAlreadyExists: - return E_BOOK_STATUS_CARD_ID_ALREADY_EXISTS; - case GNOME_Evolution_Addressbook_BookListener_ProtocolNotSupported: - return E_BOOK_STATUS_PROTOCOL_NOT_SUPPORTED; - case GNOME_Evolution_Addressbook_BookListener_AuthenticationFailed: - return E_BOOK_STATUS_AUTHENTICATION_FAILED; - case GNOME_Evolution_Addressbook_BookListener_AuthenticationRequired: - return E_BOOK_STATUS_AUTHENTICATION_REQUIRED; - case GNOME_Evolution_Addressbook_BookListener_TLSNotAvailable: - return E_BOOK_STATUS_TLS_NOT_AVAILABLE; - case GNOME_Evolution_Addressbook_BookListener_NoSuchBook: - return E_BOOK_STATUS_NO_SUCH_BOOK; - case GNOME_Evolution_Addressbook_BookListener_OtherError: - return E_BOOK_STATUS_OTHER_ERROR; - default: - g_warning ("e_book_listener_convert_status: Unknown status " - "from card server: %d\n", (int) status); - return E_BOOK_STATUS_UNKNOWN; - - } } static void @@ -701,7 +331,9 @@ e_book_listener_new () { EBookListener *listener; - listener = g_object_new (E_TYPE_BOOK_LISTENER, NULL); + listener = g_object_new (E_TYPE_BOOK_LISTENER, + "poa", bonobo_poa_get_threaded (ORBIT_THREAD_HINT_ALL_AT_IDLE, NULL), + NULL); e_book_listener_construct (listener); @@ -722,38 +354,6 @@ e_book_listener_stop (EBookListener *listener) listener->priv->stopped = TRUE; } -static void -e_book_listener_dispose (GObject *object) -{ - EBookListener *listener = E_BOOK_LISTENER (object); - - if (listener->priv) { - GList *l; - - /* Remove our response queue handler: In theory, this - can never happen since we always hold a reference - to the listener while the timeout is running. */ - if (listener->priv->timeout_id) { - g_source_remove (listener->priv->timeout_id); - } - - /* Clean up anything still sitting in response_queue */ - for (l = listener->priv->response_queue; l != NULL; l = l->next) { - EBookListenerResponse *resp = l->data; - - response_free (resp); - } - g_list_free (listener->priv->response_queue); - - g_free (listener->priv); - - listener->priv = NULL; - } - - if (G_OBJECT_CLASS (parent_class)->dispose) - G_OBJECT_CLASS (parent_class)->dispose (object); -} - static void e_book_listener_class_init (EBookListenerClass *klass) { @@ -762,31 +362,30 @@ e_book_listener_class_init (EBookListenerClass *klass) parent_class = g_type_class_ref (BONOBO_TYPE_OBJECT); - e_book_listener_signals [RESPONSES_QUEUED] = - g_signal_new ("responses_queued", + e_book_listener_signals [RESPONSE] = + g_signal_new ("response", G_OBJECT_CLASS_TYPE (object_class), G_SIGNAL_RUN_LAST, - G_STRUCT_OFFSET (EBookListenerClass, responses_queued), + G_STRUCT_OFFSET (EBookListenerClass, response), NULL, NULL, - e_book_marshal_NONE__NONE, - G_TYPE_NONE, 0); - - object_class->dispose = e_book_listener_dispose; + e_book_marshal_NONE__POINTER, + G_TYPE_NONE, 1, + G_TYPE_POINTER); epv = &klass->epv; - epv->notifyOpenBookProgress = impl_BookListener_report_open_book_progress; + epv->notifyProgress = impl_BookListener_respond_progress; epv->notifyBookOpened = impl_BookListener_respond_open_book; - epv->notifyCardCreated = impl_BookListener_respond_create_card; - epv->notifyCardsRemoved = impl_BookListener_respond_remove_cards; - epv->notifyCardModified = impl_BookListener_respond_modify_card; + epv->notifyBookRemoved = impl_BookListener_respond_remove_book; + epv->notifyContactCreated = impl_BookListener_respond_create_contact; + epv->notifyContactsRemoved = impl_BookListener_respond_remove_contacts; + epv->notifyContactModified = impl_BookListener_respond_modify_contact; epv->notifyAuthenticationResult = impl_BookListener_respond_authentication_result; - epv->notifySupportedFields = impl_BookListener_response_get_supported_fields; - epv->notifySupportedAuthMethods = impl_BookListener_response_get_supported_auth_methods; - epv->notifyCardRequested = impl_BookListener_respond_get_vcard; - epv->notifyCursorRequested = impl_BookListener_respond_get_cursor; + epv->notifySupportedFields = impl_BookListener_respond_get_supported_fields; + epv->notifySupportedAuthMethods = impl_BookListener_respond_get_supported_auth_methods; + epv->notifyContactRequested = impl_BookListener_respond_get_contact; + epv->notifyContactListRequested = impl_BookListener_respond_get_contact_list; epv->notifyViewRequested = impl_BookListener_respond_get_view; epv->notifyChangesRequested = impl_BookListener_respond_get_changes; - epv->notifyConnectionStatus = impl_BookListener_report_connection_status; epv->notifyWritable = impl_BookListener_report_writable; } diff --git a/addressbook/backend/ebook/e-book-listener.h b/addressbook/backend/ebook/e-book-listener.h index 1b02dd4bb6..4d1f0c0231 100644 --- a/addressbook/backend/ebook/e-book-listener.h +++ b/addressbook/backend/ebook/e-book-listener.h @@ -15,7 +15,6 @@ #include #include #include -#include #define E_TYPE_BOOK_LISTENER (e_book_listener_get_type ()) #define E_BOOK_LISTENER(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), E_TYPE_BOOK_LISTENER, EBookListener)) @@ -29,6 +28,7 @@ G_BEGIN_DECLS typedef struct _EBookListener EBookListener; typedef struct _EBookListenerClass EBookListenerClass; typedef struct _EBookListenerPrivate EBookListenerPrivate; +typedef struct _EBookListenerResponse EBookListenerResponse; struct _EBookListener { BonoboObject parent; @@ -39,20 +39,30 @@ struct _EBookListenerClass { BonoboObjectClass parent; POA_GNOME_Evolution_Addressbook_BookListener__epv epv; + /* * Signals */ - void (*responses_queued) (void); + + void (*response) (EBookListener *listener, EBookListenerResponse *response); + + /* Padding for future expansion */ + void (*_ebook_reserved0) (void); + void (*_ebook_reserved1) (void); + void (*_ebook_reserved2) (void); + void (*_ebook_reserved3) (void); + void (*_ebook_reserved4) (void); }; typedef enum { /* Async responses */ OpenBookResponse, - CreateCardResponse, - RemoveCardResponse, - ModifyCardResponse, - GetCardResponse, - GetCursorResponse, + RemoveBookResponse, + CreateContactResponse, + RemoveContactResponse, + ModifyContactResponse, + GetContactResponse, + GetContactListResponse, GetBookViewResponse, GetChangesResponse, AuthenticationResponse, @@ -62,28 +72,22 @@ typedef enum { /* Async events */ LinkStatusEvent, WritableStatusEvent, - OpenProgressEvent, + ProgressEvent, } EBookListenerOperation; -typedef struct { +struct _EBookListenerResponse { EBookListenerOperation op; /* For most Response notifications */ EBookStatus status; - /* For OpenBookResponse */ - GNOME_Evolution_Addressbook_Book book; - - /* For GetCursorResponse */ - GNOME_Evolution_Addressbook_CardCursor cursor; - /* For GetBookViewReponse */ GNOME_Evolution_Addressbook_BookView book_view; /* For GetSupportedFields/GetSupportedAuthMethods */ - EList *list; + GList *list; - /* For OpenProgressEvent */ + /* For ProgressEvent */ char *msg; short percent; @@ -96,12 +100,10 @@ typedef struct { /* For Card[Added|Removed|Modified]Event */ char *id; char *vcard; -} EBookListenerResponse; +}; EBookListener *e_book_listener_new (void); -int e_book_listener_check_pending (EBookListener *listener); -EBookListenerResponse *e_book_listener_pop_response (EBookListener *listener); GType e_book_listener_get_type (void); void e_book_listener_stop (EBookListener *listener); diff --git a/addressbook/backend/ebook/e-book-query.c b/addressbook/backend/ebook/e-book-query.c new file mode 100644 index 0000000000..16e325303c --- /dev/null +++ b/addressbook/backend/ebook/e-book-query.c @@ -0,0 +1,524 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ + +#include + +#include "e-book-query.h" +#include + +#include +#include + +typedef enum { + E_BOOK_QUERY_TYPE_AND, + E_BOOK_QUERY_TYPE_OR, + E_BOOK_QUERY_TYPE_NOT, + E_BOOK_QUERY_TYPE_FIELD_EXISTS, + E_BOOK_QUERY_TYPE_FIELD_TEST, + E_BOOK_QUERY_TYPE_ANY_FIELD_CONTAINS +} EBookQueryType; + +struct EBookQuery { + EBookQueryType type; + int ref_count; + + union { + struct { + guint nqs; + EBookQuery **qs; + } andor; + + struct { + EBookQuery *q; + } not; + + struct { + EBookQueryTest test; + EContactField field; + char *value; + } field_test; + + struct { + EContactField field; + } exist; + + struct { + char *value; + } any_field_contains; + } query; +}; + +static EBookQuery * +conjoin (EBookQueryType type, int nqs, EBookQuery **qs, gboolean unref) +{ + EBookQuery *ret = g_new0 (EBookQuery, 1); + int i; + + ret->type = type; + ret->query.andor.nqs = nqs; + ret->query.andor.qs = g_new (EBookQuery *, nqs); + for (i = 0; i < nqs; i++) { + ret->query.andor.qs[i] = qs[i]; + if (!unref) + e_book_query_ref (qs[i]); + } + + return ret; +} + +EBookQuery * +e_book_query_and (int nqs, EBookQuery **qs, gboolean unref) +{ + return conjoin (E_BOOK_QUERY_TYPE_AND, nqs, qs, unref); +} + +EBookQuery * +e_book_query_or (int nqs, EBookQuery **qs, gboolean unref) +{ + return conjoin (E_BOOK_QUERY_TYPE_OR, nqs, qs, unref); +} + +static EBookQuery * +conjoinv (EBookQueryType type, EBookQuery *q, va_list ap) +{ + EBookQuery *ret = g_new0 (EBookQuery, 1); + GPtrArray *qs; + + qs = g_ptr_array_new (); + while (q) { + g_ptr_array_add (qs, q); + q = va_arg (ap, EBookQuery *); + } + va_end (ap); + + ret->type = type; + ret->query.andor.nqs = qs->len; + ret->query.andor.qs = (EBookQuery **)qs->pdata; + g_ptr_array_free (qs, FALSE); + + return ret; +} + +EBookQuery * +e_book_query_andv (EBookQuery *q, ...) +{ + va_list ap; + + va_start (ap, q); + return conjoinv (E_BOOK_QUERY_TYPE_AND, q, ap); +} + +EBookQuery * +e_book_query_orv (EBookQuery *q, ...) +{ + va_list ap; + + va_start (ap, q); + return conjoinv (E_BOOK_QUERY_TYPE_OR, q, ap); +} + +EBookQuery * +e_book_query_not (EBookQuery *q, gboolean unref) +{ + EBookQuery *ret = g_new0 (EBookQuery, 1); + + ret->type = E_BOOK_QUERY_TYPE_NOT; + ret->query.not.q = q; + if (!unref) + e_book_query_ref (q); + + return ret; +} + +EBookQuery * +e_book_query_field_test (EContactField field, + EBookQueryTest test, + const char *value) +{ + EBookQuery *ret = g_new0 (EBookQuery, 1); + + ret->type = E_BOOK_QUERY_TYPE_FIELD_TEST; + ret->query.field_test.field = field; + ret->query.field_test.test = test; + ret->query.field_test.value = g_strdup (value); + + return ret; +} + +EBookQuery * +e_book_query_field_exists (EContactField field) +{ + EBookQuery *ret = g_new0 (EBookQuery, 1); + + ret->type = E_BOOK_QUERY_TYPE_FIELD_EXISTS; + ret->query.exist.field = field; + + return ret; +} + +EBookQuery * +e_book_query_any_field_contains (const char *value) +{ + EBookQuery *ret = g_new0 (EBookQuery, 1); + + ret->type = E_BOOK_QUERY_TYPE_ANY_FIELD_CONTAINS; + ret->query.any_field_contains.value = g_strdup (value); + + return ret; +} + +void +e_book_query_unref (EBookQuery *q) +{ + int i; + + if (q->ref_count--) + return; + + switch (q->type) { + case E_BOOK_QUERY_TYPE_AND: + case E_BOOK_QUERY_TYPE_OR: + for (i = 0; i < q->query.andor.nqs; i++) + e_book_query_unref (q->query.andor.qs[i]); + g_free (q->query.andor.qs); + break; + + case E_BOOK_QUERY_TYPE_NOT: + e_book_query_unref (q->query.not.q); + break; + + case E_BOOK_QUERY_TYPE_FIELD_TEST: + g_free (q->query.field_test.value); + break; + + case E_BOOK_QUERY_TYPE_ANY_FIELD_CONTAINS: + g_free (q->query.any_field_contains.value); + break; + + default: + break; + } + + g_free (q); +} + +void +e_book_query_ref (EBookQuery *q) +{ + q->ref_count++; +} + +static ESExpResult * +func_and(struct _ESExp *f, int argc, struct _ESExpResult **argv, void *data) +{ + GList **list = data; + ESExpResult *r; + EBookQuery **qs; + + if (argc > 0) { + int i; + + qs = g_new0(EBookQuery*, argc); + + for (i = 0; i < argc; i ++) { + GList *list_head = *list; + if (!list_head) + break; + qs[i] = list_head->data; + *list = g_list_remove_link(*list, list_head); + g_list_free_1(list_head); + } + + *list = g_list_prepend(*list, + e_book_query_and (argc, qs, TRUE)); + + g_free (qs); + } + + r = e_sexp_result_new(f, ESEXP_RES_BOOL); + r->value.bool = FALSE; + + return r; +} + +static ESExpResult * +func_or(struct _ESExp *f, int argc, struct _ESExpResult **argv, void *data) +{ + GList **list = data; + ESExpResult *r; + EBookQuery **qs; + + if (argc > 0) { + int i; + + qs = g_new0(EBookQuery*, argc); + + for (i = 0; i < argc; i ++) { + GList *list_head = *list; + if (!list_head) + break; + qs[i] = list_head->data; + *list = g_list_remove_link(*list, list_head); + g_list_free_1(list_head); + } + + *list = g_list_prepend(*list, + e_book_query_or (argc, qs, TRUE)); + + g_free (qs); + } + + r = e_sexp_result_new(f, ESEXP_RES_BOOL); + r->value.bool = FALSE; + + return r; +} + +static ESExpResult * +func_not(struct _ESExp *f, int argc, struct _ESExpResult **argv, void *data) +{ + GList **list = data; + ESExpResult *r; + + /* just replace the head of the list with the NOT of it. */ + if (argc > 0) { + EBookQuery *term = (*list)->data; + (*list)->data = e_book_query_not (term, TRUE); + } + + r = e_sexp_result_new(f, ESEXP_RES_BOOL); + r->value.bool = FALSE; + + return r; +} + +static ESExpResult * +func_contains(struct _ESExp *f, int argc, struct _ESExpResult **argv, void *data) +{ + GList **list = data; + ESExpResult *r; + + if (argc == 2 + && argv[0]->type == ESEXP_RES_STRING + && argv[1]->type == ESEXP_RES_STRING) { + char *propname = argv[0]->value.string; + char *str = argv[1]->value.string; + + if (!strcmp (propname, "x-evolution-any-field")) { + *list = g_list_prepend (*list, e_book_query_any_field_contains (str)); + } + else { + EContactField field = e_contact_field_id (propname); + + if (field) + *list = g_list_prepend (*list, e_book_query_field_test (field, + E_BOOK_QUERY_CONTAINS, + str)); + } + } + + r = e_sexp_result_new(f, ESEXP_RES_BOOL); + r->value.bool = FALSE; + + return r; +} + +static ESExpResult * +func_is(struct _ESExp *f, int argc, struct _ESExpResult **argv, void *data) +{ + GList **list = data; + ESExpResult *r; + + if (argc == 2 + && argv[0]->type == ESEXP_RES_STRING + && argv[1]->type == ESEXP_RES_STRING) { + char *propname = argv[0]->value.string; + char *str = argv[1]->value.string; + EContactField field = e_contact_field_id (propname); + + if (field) + *list = g_list_prepend (*list, e_book_query_field_test (field, + E_BOOK_QUERY_IS, + str)); + } + + r = e_sexp_result_new(f, ESEXP_RES_BOOL); + r->value.bool = FALSE; + + return r; +} + +static ESExpResult * +func_beginswith(struct _ESExp *f, int argc, struct _ESExpResult **argv, void *data) +{ + GList **list = data; + ESExpResult *r; + + if (argc == 2 + && argv[0]->type == ESEXP_RES_STRING + && argv[1]->type == ESEXP_RES_STRING) { + char *propname = argv[0]->value.string; + char *str = argv[1]->value.string; + EContactField field = e_contact_field_id (propname); + + if (field) + *list = g_list_prepend (*list, e_book_query_field_test (field, + E_BOOK_QUERY_BEGINS_WITH, + str)); + } + + r = e_sexp_result_new(f, ESEXP_RES_BOOL); + r->value.bool = FALSE; + + return r; +} + +static ESExpResult * +func_endswith(struct _ESExp *f, int argc, struct _ESExpResult **argv, void *data) +{ + GList **list = data; + ESExpResult *r; + + if (argc == 2 + && argv[0]->type == ESEXP_RES_STRING + && argv[1]->type == ESEXP_RES_STRING) { + char *propname = argv[0]->value.string; + char *str = argv[1]->value.string; + EContactField field = e_contact_field_id (propname); + + if (field) + *list = g_list_prepend (*list, e_book_query_field_test (field, + E_BOOK_QUERY_ENDS_WITH, + str)); + } + + r = e_sexp_result_new(f, ESEXP_RES_BOOL); + r->value.bool = FALSE; + + return r; +} + +/* 'builtin' functions */ +static struct { + char *name; + ESExpFunc *func; + int type; /* set to 1 if a function can perform shortcut evaluation, or + doesn't execute everything, 0 otherwise */ +} symbols[] = { + { "and", func_and, 0 }, + { "or", func_or, 0 }, + { "not", func_not, 0 }, + { "contains", func_contains, 0 }, + { "is", func_is, 0 }, + { "beginswith", func_beginswith, 0 }, + { "endswith", func_endswith, 0 }, +}; + +EBookQuery* +e_book_query_from_string (const char *query_string) +{ + ESExp *sexp; + ESExpResult *r; + EBookQuery *retval; + GList *list = NULL; + int i; + + sexp = e_sexp_new(); + + for(i=0;inext) { + g_warning ("conversion to EBookQuery"); + retval = NULL; + g_list_foreach (list, (GFunc)e_book_query_unref, NULL); + } + else { + retval = list->data; + } + } + else { + g_warning ("conversion to EBookQuery failed"); + retval = NULL; + } + + g_list_free (list); + return retval; +} + +char* +e_book_query_to_string (EBookQuery *q) +{ + GString *str = g_string_new ("("); + int i; + char *s = NULL; + + switch (q->type) { + case E_BOOK_QUERY_TYPE_AND: + g_string_append (str, "and "); + for (i = 0; i < q->query.andor.nqs; i ++) { + s = e_book_query_to_string (q->query.andor.qs[i]); + g_string_append (str, s); + g_free (s); + g_string_append_c (str, ' '); + } + break; + case E_BOOK_QUERY_TYPE_OR: + g_string_append (str, "or "); + for (i = 0; i < q->query.andor.nqs; i ++) { + s = e_book_query_to_string (q->query.andor.qs[i]); + g_string_append (str, s); + g_free (s); + g_string_append_c (str, ' '); + } + break; + case E_BOOK_QUERY_TYPE_NOT: + s = e_book_query_to_string (q->query.not.q); + g_string_append_printf (str, "not %s", s); + g_free (s); + break; + case E_BOOK_QUERY_TYPE_FIELD_EXISTS: + g_string_append_printf (str, "exists \"%s\"", e_contact_field_name (q->query.exist.field)); + break; + case E_BOOK_QUERY_TYPE_FIELD_TEST: + switch (q->query.field_test.test) { + case E_BOOK_QUERY_IS: s = "is"; break; + case E_BOOK_QUERY_CONTAINS: s = "contains"; break; + case E_BOOK_QUERY_BEGINS_WITH: s = "beginswith"; break; + case E_BOOK_QUERY_ENDS_WITH: s = "endswith"; break; + default: + g_assert_not_reached(); + break; + } + + /* XXX need to escape q->query.field_test.value */ + g_string_append_printf (str, "%s \"%s\" \"%s\"", + s, + e_contact_field_name (q->query.field_test.field), + q->query.field_test.value); + break; + case E_BOOK_QUERY_TYPE_ANY_FIELD_CONTAINS: + g_string_append_printf (str, "contains \"x-evolution-any-field\" \"%s\"", q->query.any_field_contains.value); + break; + } + + + g_string_append (str, ")"); + + return g_string_free (str, FALSE); +} diff --git a/addressbook/backend/ebook/e-book-query.h b/addressbook/backend/ebook/e-book-query.h new file mode 100644 index 0000000000..e36887f6f2 --- /dev/null +++ b/addressbook/backend/ebook/e-book-query.h @@ -0,0 +1,49 @@ + +#ifndef __E_BOOK_QUERY_H__ +#define __E_BOOK_QUERY_H__ + +#include + +G_BEGIN_DECLS + +typedef struct EBookQuery EBookQuery; + +typedef enum { + E_BOOK_QUERY_IS, + E_BOOK_QUERY_CONTAINS, + E_BOOK_QUERY_BEGINS_WITH, + E_BOOK_QUERY_ENDS_WITH, + +#if notyet + E_BOOK_QUERY_LT, + E_BOOK_QUERY_LE, + E_BOOK_QUERY_GT, + E_BOOK_QUERY_GE, + E_BOOK_QUERY_EQ, +#endif +} EBookQueryTest; + +EBookQuery* e_book_query_from_string (const char *sexp); +char* e_book_query_to_string (EBookQuery *q); + +void e_book_query_ref (EBookQuery *q); +void e_book_query_unref (EBookQuery *q); + +EBookQuery* e_book_query_and (int nqs, EBookQuery **qs, gboolean unref); +EBookQuery* e_book_query_andv (EBookQuery *q, ...); +EBookQuery* e_book_query_or (int nqs, EBookQuery **qs, gboolean unref); +EBookQuery* e_book_query_orv (EBookQuery *q, ...); + +EBookQuery* e_book_query_not (EBookQuery *qs, gboolean unref); + +EBookQuery* e_book_query_field_exists (EContactField field); +EBookQuery* e_book_query_field_test (EContactField field, + EBookQueryTest test, + const char *value); + +/* a special any field contains query */ +EBookQuery* e_book_query_any_field_contains (const char *value); + +G_END_DECLS + +#endif /* __E_BOOK_QUERY_H__ */ diff --git a/addressbook/backend/ebook/e-book-types.h b/addressbook/backend/ebook/e-book-types.h index b1900e77ed..4ca69bd516 100644 --- a/addressbook/backend/ebook/e-book-types.h +++ b/addressbook/backend/ebook/e-book-types.h @@ -16,37 +16,52 @@ G_BEGIN_DECLS +#define E_BOOK_ERROR e_book_error_quark() + +GQuark e_book_error_quark (void) G_GNUC_CONST; + typedef enum { - E_BOOK_STATUS_SUCCESS, - E_BOOK_STATUS_UNKNOWN, - E_BOOK_STATUS_REPOSITORY_OFFLINE, - E_BOOK_STATUS_PERMISSION_DENIED, - E_BOOK_STATUS_CARD_NOT_FOUND, - E_BOOK_STATUS_CARD_ID_ALREADY_EXISTS, - E_BOOK_STATUS_PROTOCOL_NOT_SUPPORTED, - E_BOOK_STATUS_CANCELLED, - E_BOOK_STATUS_AUTHENTICATION_FAILED, - E_BOOK_STATUS_AUTHENTICATION_REQUIRED, - E_BOOK_STATUS_TLS_NOT_AVAILABLE, - E_BOOK_STATUS_NO_SUCH_BOOK, - E_BOOK_STATUS_OTHER_ERROR + E_BOOK_ERROR_OK, + E_BOOK_ERROR_INVALID_ARG, + E_BOOK_ERROR_BUSY, + E_BOOK_ERROR_REPOSITORY_OFFLINE, + E_BOOK_ERROR_NO_SUCH_BOOK, + E_BOOK_ERROR_URI_NOT_LOADED, + E_BOOK_ERROR_URI_ALREADY_LOADED, + E_BOOK_ERROR_PERMISSION_DENIED, + E_BOOK_ERROR_CONTACT_NOT_FOUND, + E_BOOK_ERROR_CONTACT_ID_ALREADY_EXISTS, + E_BOOK_ERROR_PROTOCOL_NOT_SUPPORTED, + E_BOOK_ERROR_CANCELLED, + E_BOOK_ERROR_COULD_NOT_CANCEL, + E_BOOK_ERROR_AUTHENTICATION_FAILED, + E_BOOK_ERROR_AUTHENTICATION_REQUIRED, + E_BOOK_ERROR_TLS_NOT_AVAILABLE, + E_BOOK_ERROR_CORBA_EXCEPTION, + E_BOOK_ERROR_OTHER_ERROR } EBookStatus; + typedef enum { - E_BOOK_VIEW_STATUS_SUCCESS, + E_BOOK_VIEW_STATUS_OK, E_BOOK_VIEW_STATUS_TIME_LIMIT_EXCEEDED, E_BOOK_VIEW_STATUS_SIZE_LIMIT_EXCEEDED, - E_BOOK_VIEW_STATUS_INVALID_QUERY, - E_BOOK_VIEW_STATUS_QUERY_REFUSED, - E_BOOK_VIEW_STATUS_OTHER_ERROR, - E_BOOK_VIEW_STATUS_UNKNOWN + E_BOOK_VIEW_ERROR_INVALID_QUERY, + E_BOOK_VIEW_ERROR_QUERY_REFUSED, + E_BOOK_VIEW_ERROR_OTHER_ERROR } EBookViewStatus; typedef enum { - E_BOOK_SIMPLE_QUERY_STATUS_SUCCESS, - E_BOOK_SIMPLE_QUERY_STATUS_CANCELLED, - E_BOOK_SIMPLE_QUERY_STATUS_OTHER_ERROR -} EBookSimpleQueryStatus; + E_BOOK_CHANGE_CARD_ADDED, + E_BOOK_CHANGE_CARD_DELETED, + E_BOOK_CHANGE_CARD_MODIFIED +} EBookChangeType; + +typedef struct { + EBookChangeType change_type; + char *vcard; /* used in the ADDED/MODIFIED case */ + char *id; /* used in the DELETED case */ +} EBookChange; G_END_DECLS diff --git a/addressbook/backend/ebook/e-book-util.c b/addressbook/backend/ebook/e-book-util.c deleted file mode 100644 index cc00d045f4..0000000000 --- a/addressbook/backend/ebook/e-book-util.c +++ /dev/null @@ -1,808 +0,0 @@ -/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ - -/* - * e-book-util.c - * - * Copyright (C) 2001 Ximian, Inc. - * - * Developed by Jon Trowbridge - */ - -/* - * This program is free software; you can redistribute it and/or - * modify it under the terms of version 2 of the GNU General Public - * License as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - * USA. - */ - -#include -#include "e-book-util.h" - -#include -#include -#include -#include -#include "e-card-compare.h" - -typedef struct _CommonBookInfo CommonBookInfo; -struct _CommonBookInfo { - EBookCommonCallback cb; - gpointer closure; -}; - -char * -e_book_expand_uri (const char *uri) -{ - if (!strncmp (uri, "file:", 5)) { - int length = strlen (uri); - int offset = 5; - - if (!strncmp (uri, "file://", 7)) - offset = 7; - - if (length < 3 || strcmp (uri + length - 3, ".db")) { - /* we assume it's a dir and glom addressbook.db onto the end. */ - - char *ret_val; - char *file_name; - - file_name = g_build_filename(uri + offset, "addressbook.db", NULL); - ret_val = g_strdup_printf("file://%s", file_name); - g_free(file_name); - return ret_val; - } - } - - return g_strdup (uri); -} - -static void -got_uri_book_cb (EBook *book, EBookStatus status, gpointer closure) -{ - CommonBookInfo *info = (CommonBookInfo *) closure; - - if (status == E_BOOK_STATUS_SUCCESS) { - info->cb (book, info->closure); - } else { - if (book) - g_object_unref (book); - info->cb (NULL, info->closure); - } - g_free (info); -} - -void -e_book_load_address_book_by_uri (EBook *book, const char *uri, EBookCallback open_response, gpointer closure) -{ - char *real_uri; - - g_return_if_fail (book != NULL); - g_return_if_fail (E_IS_BOOK (book)); - g_return_if_fail (open_response != NULL); - - real_uri = e_book_expand_uri (uri); - - e_book_load_uri (book, real_uri, open_response, closure); - - g_free (real_uri); -} - -void -e_book_use_address_book_by_uri (const char *uri, EBookCommonCallback cb, gpointer closure) -{ - EBook *book; - CommonBookInfo *info; - - g_return_if_fail (cb != NULL); - - info = g_new0 (CommonBookInfo, 1); - info->cb = cb; - info->closure = closure; - - book = e_book_new (); - e_book_load_address_book_by_uri (book, uri, got_uri_book_cb, info); -} - -EConfigListener * -e_book_get_config_database () -{ - static EConfigListener *config_db; - - if (config_db == NULL) - config_db = e_config_listener_new (); - - return config_db; -} - -static EBook *common_default_book = NULL; - -static void -got_default_book_cb (EBook *book, EBookStatus status, gpointer closure) -{ - CommonBookInfo *info = (CommonBookInfo *) closure; - - if (status == E_BOOK_STATUS_SUCCESS) { - - /* We try not to leak in a race condition where the - default book got loaded twice. */ - - if (common_default_book) { - g_object_unref (book); - book = common_default_book; - } - - info->cb (book, info->closure); - - if (common_default_book == NULL) { - common_default_book = book; - } - - } else { - if (book) - g_object_unref (book); - info->cb (NULL, info->closure); - - } - g_free (info); -} - -void -e_book_use_default_book (EBookCommonCallback cb, gpointer closure) -{ - EBook *book; - CommonBookInfo *info; - - g_return_if_fail (cb != NULL); - - if (common_default_book != NULL) { - cb (common_default_book, closure); - return; - } - - info = g_new0 (CommonBookInfo, 1); - info->cb = cb; - info->closure = closure; - - book = e_book_new (); - e_book_load_default_book (book, got_default_book_cb, info); -} - -static char *default_book_uri; - -static char* -get_local_book_uri (void) -{ - char *filename; - char *uri; - - filename = g_build_filename (g_get_home_dir(), - "evolution/local/Contacts/addressbook.db", - NULL); - uri = g_strdup_printf ("file://%s", filename); - - g_free (filename); - - return uri; -} - -static void -set_default_book_uri_local (void) -{ - g_free (default_book_uri); - - default_book_uri = get_local_book_uri (); -} - -static void -set_default_book_uri (char *val) -{ - if (default_book_uri) - g_free (default_book_uri); - - if (val) { - default_book_uri = e_book_expand_uri (val); - g_free (val); - } - else { - set_default_book_uri_local (); - } -} - -#define DEFAULT_CONTACTS_URI_PATH "/apps/evolution/shell/default_folders/contacts_uri" -static void -default_folder_listener (EConfigListener *cl, const char *key, gpointer data) -{ - char *val; - - if (strcmp (key, DEFAULT_CONTACTS_URI_PATH)) - return; - - val = e_config_listener_get_string (cl, DEFAULT_CONTACTS_URI_PATH); - - set_default_book_uri (val); -} - -static void -set_default_book_uri_from_config_db (void) -{ - char *val; - EConfigListener* config_db; - - config_db = e_book_get_config_database (); - val = e_config_listener_get_string_with_default (config_db, DEFAULT_CONTACTS_URI_PATH, NULL, NULL); - - g_signal_connect (config_db, - "key_changed", - G_CALLBACK (default_folder_listener), NULL); - - set_default_book_uri (val); -} - -typedef struct { - gpointer closure; - EBookCallback open_response; -} DefaultBookClosure; - -static void -e_book_default_book_open (EBook *book, EBookStatus status, gpointer closure) -{ - DefaultBookClosure *default_book_closure = closure; - gpointer user_closure = default_book_closure->closure; - EBookCallback user_response = default_book_closure->open_response; - - g_free (default_book_closure); - - /* If there's a transient error, report it to the caller, but - * if the old default folder has disappeared, fall back to the - * local contacts folder instead, except when the default - * folder is also the local folder. - */ - if (status == E_BOOK_STATUS_PROTOCOL_NOT_SUPPORTED || - status == E_BOOK_STATUS_NO_SUCH_BOOK) { - char *local_uri = get_local_book_uri(); - if (strcmp (local_uri, default_book_uri)) { - set_default_book_uri_local (); - e_book_load_default_book (book, user_response, user_closure); - } - else - user_response (book, status, user_closure); - g_free (local_uri); - } else { - user_response (book, status, user_closure); - } -} - -void -e_book_load_default_book (EBook *book, EBookCallback open_response, gpointer closure) -{ - const char *uri; - DefaultBookClosure *default_book_closure; - - g_return_if_fail (book != NULL); - g_return_if_fail (E_IS_BOOK (book)); - g_return_if_fail (open_response != NULL); - - uri = e_book_get_default_book_uri (); - - default_book_closure = g_new (DefaultBookClosure, 1); - - default_book_closure->closure = closure; - default_book_closure->open_response = open_response; - - e_book_load_uri (book, uri, - e_book_default_book_open, default_book_closure); - -} - -const char * -e_book_get_default_book_uri () -{ - if (!default_book_uri) - set_default_book_uri_from_config_db (); - - return default_book_uri; -} - -/* - * - * Simple Query Stuff - * - */ - -typedef struct _SimpleQueryInfo SimpleQueryInfo; -struct _SimpleQueryInfo { - guint tag; - EBook *book; - gchar *query; - EBookSimpleQueryCallback cb; - gpointer closure; - EBookView *view; - guint add_tag; - guint seq_complete_tag; - GList *cards; - gboolean cancelled; -}; - -static void -book_add_simple_query (EBook *book, SimpleQueryInfo *info) -{ - GList *pending = g_object_get_data (G_OBJECT(book), "sq_pending"); - pending = g_list_prepend (pending, info); - g_object_set_data (G_OBJECT (book), "sq_pending", pending); -} - -static SimpleQueryInfo * -book_lookup_simple_query (EBook *book, guint tag) -{ - GList *pending = g_object_get_data (G_OBJECT (book), "sq_pending"); - while (pending) { - SimpleQueryInfo *sq = pending->data; - if (sq->tag == tag) - return sq; - pending = g_list_next (pending); - } - return NULL; -} - -static void -book_remove_simple_query (EBook *book, SimpleQueryInfo *info) -{ - GList *pending = g_object_get_data (G_OBJECT (book), "sq_pending"); - GList *i; - - for (i=pending; i != NULL; i = g_list_next (i)) { - if (i->data == info) { - pending = g_list_remove_link (pending, i); - g_list_free_1 (i); - break; - } - } - g_object_set_data (G_OBJECT (book), "sq_pending", pending); -} - -static guint -book_issue_tag (EBook *book) -{ - gpointer ptr = g_object_get_data (G_OBJECT (book), "sq_tag"); - guint tag = GPOINTER_TO_UINT (ptr); - if (tag == 0) - tag = 1; - g_object_set_data (G_OBJECT (book), "sq_tag", GUINT_TO_POINTER (tag+1)); - return tag; -} - -static SimpleQueryInfo * -simple_query_new (EBook *book, const char *query, EBookSimpleQueryCallback cb, gpointer closure) -{ - SimpleQueryInfo *sq = g_new0 (SimpleQueryInfo, 1); - - sq->tag = book_issue_tag (book); - sq->book = book; - g_object_ref (book); - sq->query = g_strdup (query); - sq->cb = cb; - sq->closure = closure; - sq->cancelled = FALSE; - - /* Automatically add ourselves to the EBook's pending list. */ - book_add_simple_query (book, sq); - - return sq; -} - -static void -simple_query_disconnect (SimpleQueryInfo *sq) -{ - if (sq->add_tag) { - g_signal_handler_disconnect (sq->view, sq->add_tag); - sq->add_tag = 0; - } - - if (sq->seq_complete_tag) { - g_signal_handler_disconnect (sq->view, sq->seq_complete_tag); - sq->seq_complete_tag = 0; - } - - if (sq->view) { - g_object_unref (sq->view); - sq->view = NULL; - } -} - -static void -simple_query_free (SimpleQueryInfo *sq) -{ - simple_query_disconnect (sq); - - /* Remove ourselves from the EBook's pending list. */ - book_remove_simple_query (sq->book, sq); - - g_free (sq->query); - - if (sq->book) - g_object_unref (sq->book); - - g_list_foreach (sq->cards, (GFunc) g_object_unref, NULL); - g_list_free (sq->cards); - - g_free (sq); -} - -static void -simple_query_card_added_cb (EBookView *view, const GList *cards, gpointer closure) -{ - SimpleQueryInfo *sq = closure; - - if (sq->cancelled) - return; - - sq->cards = g_list_concat (sq->cards, g_list_copy ((GList *) cards)); - g_list_foreach ((GList *) cards, (GFunc) g_object_ref, NULL); -} - -static void -simple_query_sequence_complete_cb (EBookView *view, EBookViewStatus status, gpointer closure) -{ - SimpleQueryInfo *sq = closure; - - /* Disconnect signals, so that we don't pick up any changes to the book that occur - in our callback */ - simple_query_disconnect (sq); - if (! sq->cancelled) - sq->cb (sq->book, E_BOOK_SIMPLE_QUERY_STATUS_SUCCESS, sq->cards, sq->closure); - simple_query_free (sq); -} - -static void -simple_query_book_view_cb (EBook *book, EBookStatus status, EBookView *book_view, gpointer closure) -{ - SimpleQueryInfo *sq = closure; - - if (sq->cancelled) { - simple_query_free (sq); - return; - } - - if (status != E_BOOK_STATUS_SUCCESS) { - simple_query_disconnect (sq); - sq->cb (sq->book, E_BOOK_SIMPLE_QUERY_STATUS_OTHER_ERROR, NULL, sq->closure); - simple_query_free (sq); - return; - } - - sq->view = book_view; - g_object_ref (book_view); - - sq->add_tag = g_signal_connect (sq->view, "card_added", - G_CALLBACK (simple_query_card_added_cb), sq); - sq->seq_complete_tag = g_signal_connect (sq->view, "sequence_complete", - G_CALLBACK (simple_query_sequence_complete_cb), sq); -} - -guint -e_book_simple_query (EBook *book, const char *query, EBookSimpleQueryCallback cb, gpointer closure) -{ - SimpleQueryInfo *sq; - - g_return_val_if_fail (book && E_IS_BOOK (book), 0); - g_return_val_if_fail (query, 0); - g_return_val_if_fail (cb, 0); - - sq = simple_query_new (book, query, cb, closure); - e_book_get_book_view (book, (gchar *) query, simple_query_book_view_cb, sq); - - return sq->tag; -} - -void -e_book_simple_query_cancel (EBook *book, guint tag) -{ - SimpleQueryInfo *sq; - - g_return_if_fail (book && E_IS_BOOK (book)); - - sq = book_lookup_simple_query (book, tag); - - if (sq) { - sq->cancelled = TRUE; - sq->cb (sq->book, E_BOOK_SIMPLE_QUERY_STATUS_CANCELLED, NULL, sq->closure); - } else { - g_warning ("Simple query tag %d is unknown", tag); - } -} - -/* - * - * Specialized Queries - * - */ - -typedef struct _NameEmailQueryInfo NameEmailQueryInfo; -struct _NameEmailQueryInfo { - gchar *name; - gchar *email; - EBookSimpleQueryCallback cb; - gpointer closure; -}; - -static void -name_email_query_info_free (NameEmailQueryInfo *info) -{ - if (info) { - g_free (info->name); - g_free (info->email); - g_free (info); - } -} - -static void -name_and_email_cb (EBook *book, EBookSimpleQueryStatus status, const GList *cards, gpointer closure) -{ - NameEmailQueryInfo *info = closure; - GList *filtered_cards = NULL; - - while (cards) { - ECard *card = E_CARD (cards->data); - if ((info->name == NULL || e_card_compare_name_to_string (card, info->name) >= E_CARD_MATCH_VAGUE) - && (info->email == NULL || e_card_email_match_string (card, info->email))) { - filtered_cards = g_list_append (filtered_cards, card); - } - cards = g_list_next (cards); - } - - info->cb (book, status, filtered_cards, info->closure); - - g_list_free (filtered_cards); - - name_email_query_info_free (info); -} - -guint -e_book_name_and_email_query (EBook *book, - const gchar *name, - const gchar *email, - EBookSimpleQueryCallback cb, - gpointer closure) -{ - NameEmailQueryInfo *info; - gchar *email_query=NULL, *name_query=NULL, *query; - guint tag; - - g_return_val_if_fail (book && E_IS_BOOK (book), 0); - g_return_val_if_fail (cb != NULL, 0); - - if (name && !*name) - name = NULL; - if (email && !*email) - email = NULL; - - if (name == NULL && email == NULL) - return 0; - - /* Build our e-mail query. - * We only query against the username part of the address, to avoid not matching - * fred@foo.com and fred@mail.foo.com. While their may be namespace collisions - * in the usernames of everyone out there, it shouldn't be that bad. (Famous last words.) - */ - if (email) { - const gchar *t = email; - while (*t && *t != '@') - ++t; - if (*t == '@') { - email_query = g_strdup_printf ("(beginswith \"email\" \"%.*s@\")", t-email, email); - - } else { - email_query = g_strdup_printf ("(beginswith \"email\" \"%s\")", email); - } - } - - /* Build our name query. - * We only do name-query stuff if we don't have an e-mail address. Our basic assumption - * is that the username part of the email is good enough to keep the amount of stuff returned - * in the query relatively small. - */ - if (name && !email) { - gchar *name_cpy = g_strdup (name), *qjoined; - gchar **namev; - gint i, count=0; - - g_strstrip (name_cpy); - namev = g_strsplit (name_cpy, " ", 0); - for (i=0; namev[i]; ++i) { - if (*namev[i]) { - char *str = namev[i]; - - namev[i] = g_strdup_printf ("(contains \"file_as\" \"%s\")", namev[i]); - ++count; - - g_free (str); - } - } - - qjoined = g_strjoinv (" ", namev); - if (count > 1) { - name_query = g_strdup_printf ("(or %s)", qjoined); - } else { - name_query = qjoined; - qjoined = NULL; - } - - g_free (name_cpy); - g_strfreev (namev); - g_free (qjoined); - } - - /* Assemble our e-mail & name queries */ - if (email_query && name_query) { - query = g_strdup_printf ("(and %s %s)", email_query, name_query); - } else if (email_query) { - query = email_query; - email_query = NULL; - } else if (name_query) { - query = name_query; - name_query = NULL; - } else - return 0; - - info = g_new0 (NameEmailQueryInfo, 1); - info->name = g_strdup (name); - info->email = g_strdup (email); - info->cb = cb; - info->closure = closure; - - tag = e_book_simple_query (book, query, name_and_email_cb, info); - - g_free (email_query); - g_free (name_query); - g_free (query); - - return tag; -} - -/* - * Simple nickname query - */ - -typedef struct _NicknameQueryInfo NicknameQueryInfo; -struct _NicknameQueryInfo { - gchar *nickname; - EBookSimpleQueryCallback cb; - gpointer closure; -}; - -static void -nickname_cb (EBook *book, EBookSimpleQueryStatus status, const GList *cards, gpointer closure) -{ - NicknameQueryInfo *info = closure; - - if (info->cb) - info->cb (book, status, cards, info->closure); - - g_free (info->nickname); - g_free (info); -} - -guint -e_book_nickname_query (EBook *book, - const char *nickname, - EBookSimpleQueryCallback cb, - gpointer closure) -{ - NicknameQueryInfo *info; - gchar *query; - guint retval; - - g_return_val_if_fail (E_IS_BOOK (book), 0); - g_return_val_if_fail (nickname != NULL, 0); - - /* The empty-string case shouldn't generate a warning. */ - if (! *nickname) - return 0; - - info = g_new0 (NicknameQueryInfo, 1); - info->nickname = g_strdup (nickname); - info->cb = cb; - info->closure = closure; - - query = g_strdup_printf ("(is \"nickname\" \"%s\")", info->nickname); - - retval = e_book_simple_query (book, query, nickname_cb, info); - - g_free (query); - - return retval; -} - -/* - * Convenience routine to check for addresses in the local address book. - */ - -typedef struct _HaveAddressInfo HaveAddressInfo; -struct _HaveAddressInfo { - gchar *email; - EBookHaveAddressCallback cb; - gpointer closure; -}; - -static void -have_address_query_cb (EBook *book, EBookSimpleQueryStatus status, const GList *cards, gpointer closure) -{ - HaveAddressInfo *info = (HaveAddressInfo *) closure; - - info->cb (book, - info->email, - cards && (status == E_BOOK_SIMPLE_QUERY_STATUS_SUCCESS) ? E_CARD (cards->data) : NULL, - info->closure); - - g_free (info->email); - g_free (info); -} - -static void -have_address_book_open_cb (EBook *book, gpointer closure) -{ - HaveAddressInfo *info = (HaveAddressInfo *) closure; - - if (book) { - - e_book_name_and_email_query (book, NULL, info->email, have_address_query_cb, info); - - } else { - - info->cb (NULL, info->email, NULL, info->closure); - - g_free (info->email); - g_free (info); - - } -} - -void -e_book_query_address_default (const gchar *email, - EBookHaveAddressCallback cb, - gpointer closure) -{ - HaveAddressInfo *info; - - g_return_if_fail (email != NULL); - g_return_if_fail (cb != NULL); - - info = g_new0 (HaveAddressInfo, 1); - info->email = g_strdup (email); - info->cb = cb; - info->closure = closure; - - e_book_use_default_book (have_address_book_open_cb, info); -} - -/* bad place for this i know. */ -int -e_utf8_casefold_collate_len (const gchar *str1, const gchar *str2, int len) -{ - gchar *s1 = g_utf8_casefold(str1, len); - gchar *s2 = g_utf8_casefold(str2, len); - int rv; - - rv = g_utf8_collate (s1, s2); - - g_free (s1); - g_free (s2); - - return rv; -} - -int -e_utf8_casefold_collate (const gchar *str1, const gchar *str2) -{ - return e_utf8_casefold_collate_len (str1, str2, -1); -} - diff --git a/addressbook/backend/ebook/e-book-util.h b/addressbook/backend/ebook/e-book-util.h deleted file mode 100644 index 39eb135332..0000000000 --- a/addressbook/backend/ebook/e-book-util.h +++ /dev/null @@ -1,94 +0,0 @@ -/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ - -/* - * e-book-util.h - * - * Copyright (C) 2001 Ximian, Inc. - * - * Developed by Jon Trowbridge - */ - -/* - * This program is free software; you can redistribute it and/or - * modify it under the terms of version 2 of the GNU General Public - * License as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - * USA. - */ - -#ifndef __E_BOOK_UTIL_H__ -#define __E_BOOK_UTIL_H__ - -#include "e-book.h" -#include "e-util/e-config-listener.h" -#include -#include - -G_BEGIN_DECLS - -/* Callbacks for asynchronous functions. */ -typedef void (*EBookCommonCallback) (EBook *book, gpointer closure); -typedef void (*EBookSimpleQueryCallback) (EBook *book, EBookSimpleQueryStatus status, const GList *cards, gpointer closure); -typedef void (*EBookHaveAddressCallback) (EBook *book, const gchar *addr, ECard *card, gpointer closure); - -/* expand file:///foo/foo/ to file:///foo/foo/addressbook.db */ -char *e_book_expand_uri (const char *uri); - -void e_book_load_address_book_by_uri (EBook *book, - const char *uri, - EBookCallback open_response, - gpointer closure); -void e_book_use_address_book_by_uri (const char *uri, - EBookCommonCallback cb, - gpointer closure); - -void e_book_use_default_book (EBookCommonCallback cb, - gpointer closure); -void e_book_load_default_book (EBook *book, - EBookCallback open_response, - gpointer closure); -const char *e_book_get_default_book_uri (void); - -/* config database interface. */ -EConfigListener *e_book_get_config_database (void); - -/* Simple Query Interface. */ -guint e_book_simple_query (EBook *book, - const char *query, - EBookSimpleQueryCallback cb, - gpointer closure); -void e_book_simple_query_cancel (EBook *book, - guint tag); - -/* Specialized Name/Email Queries */ -guint e_book_name_and_email_query (EBook *book, - const char *name, - const char *email, - EBookSimpleQueryCallback cb, - gpointer closure); -guint e_book_nickname_query (EBook *book, - const char *nickname, - EBookSimpleQueryCallback cb, - gpointer closure); - -/* Returns the ECard associated to email in the callback, - or NULL if no match is found in the default address book. */ -void e_book_query_address_default (const gchar *email, - EBookHaveAddressCallback cb, - gpointer closure); - -int e_utf8_casefold_collate_len (const gchar *str1, const gchar *str2, int len); -int e_utf8_casefold_collate (const gchar *str1, const gchar *str2); - -G_END_DECLS - -#endif /* __E_BOOK_UTIL_H__ */ - diff --git a/addressbook/backend/ebook/e-book-view-listener.c b/addressbook/backend/ebook/e-book-view-listener.c index 668c442a9a..3ab2ff2708 100644 --- a/addressbook/backend/ebook/e-book-view-listener.c +++ b/addressbook/backend/ebook/e-book-view-listener.c @@ -13,13 +13,13 @@ #include #include "e-book-view-listener.h" #include "e-book-view.h" -#include "e-card.h" +#include "e-contact.h" #include "e-book-marshal.h" -static EBookViewStatus e_book_view_listener_convert_status (GNOME_Evolution_Addressbook_BookViewListener_CallStatus status); +static EBookViewStatus e_book_view_listener_convert_status (GNOME_Evolution_Addressbook_CallStatus status); enum { - RESPONSES_QUEUED, + RESPONSE, LAST_SIGNAL }; @@ -28,36 +28,9 @@ static guint e_book_view_listener_signals [LAST_SIGNAL]; static BonoboObjectClass *parent_class; struct _EBookViewListenerPrivate { - GList *response_queue; - gint timeout_id; - - guint timeout_lock : 1; guint stopped : 1; }; -static gboolean -e_book_view_listener_check_queue (EBookViewListener *listener) -{ - if (listener->priv->timeout_lock) - return TRUE; - - listener->priv->timeout_lock = TRUE; - - if (listener->priv->response_queue != NULL && !listener->priv->stopped) { - g_signal_emit (listener, e_book_view_listener_signals [RESPONSES_QUEUED], 0); - } - - if (listener->priv->response_queue == NULL || listener->priv->stopped) { - listener->priv->timeout_id = 0; - listener->priv->timeout_lock = FALSE; - bonobo_object_unref (BONOBO_OBJECT (listener)); - return FALSE; - } - - listener->priv->timeout_lock = FALSE; - return TRUE; -} - static void e_book_view_listener_queue_response (EBookViewListener *listener, EBookViewListenerResponse *response) @@ -69,45 +42,14 @@ e_book_view_listener_queue_response (EBookViewListener *listener, /* Free response and return */ g_list_foreach (response->ids, (GFunc)g_free, NULL); g_list_free (response->ids); - g_list_foreach (response->cards, (GFunc) g_object_unref, NULL); - g_list_free (response->cards); + g_list_foreach (response->contacts, (GFunc) g_object_unref, NULL); + g_list_free (response->contacts); g_free (response->message); g_free (response); return; } - /* a slight optimization for huge ldap queries. if there's an - existing Add response on the end of the queue, and we're an - Add response, we just glom the two lists of cards - together */ - if (response->op == CardAddedEvent) { - GList *last = g_list_last (listener->priv->response_queue); - EBookViewListenerResponse *last_resp = NULL; - - if (last) last_resp = last->data; - - if (last_resp && last_resp->op == CardAddedEvent ) { - response->cards = g_list_concat (last_resp->cards, response->cards); - g_free (response); - /* there should already be a timeout since the - queue isn't empty, so we'll just return - here */ - return; - } - else - listener->priv->response_queue = g_list_append (last, response); - } - else - listener->priv->response_queue = g_list_append (listener->priv->response_queue, response); - - if (listener->priv->timeout_id == 0) { - - /* Here, 20 == an arbitrary small number */ - listener->priv->timeout_id = g_timeout_add (20, (GSourceFunc) e_book_view_listener_check_queue, listener); - - /* Hold a reference to the listener on behalf of the timeout */ - bonobo_object_ref (BONOBO_OBJECT (listener)); - } + g_signal_emit (listener, e_book_view_listener_signals [RESPONSE], 0, response); } /* Add, Remove, Modify */ @@ -125,9 +67,6 @@ e_book_view_listener_queue_status_event (EBookViewListener *listener, resp->op = op; resp->status = status; - resp->ids = NULL; - resp->cards = NULL; - resp->message = NULL; e_book_view_listener_queue_response (listener, resp); } @@ -136,7 +75,7 @@ e_book_view_listener_queue_status_event (EBookViewListener *listener, static void e_book_view_listener_queue_idlist_event (EBookViewListener *listener, EBookViewListenerOperation op, - const GNOME_Evolution_Addressbook_CardIdList *ids) + const GNOME_Evolution_Addressbook_ContactIdList *ids) { EBookViewListenerResponse *resp; int i; @@ -147,10 +86,7 @@ e_book_view_listener_queue_idlist_event (EBookViewListener *listener, resp = g_new0 (EBookViewListenerResponse, 1); resp->op = op; - resp->status = E_BOOK_VIEW_STATUS_SUCCESS; - resp->ids = NULL; - resp->cards = NULL; - resp->message = NULL; + resp->status = E_BOOK_VIEW_STATUS_OK; for (i = 0; i < ids->_length; i ++) { resp->ids = g_list_prepend (resp->ids, g_strdup (ids->_buffer[i])); @@ -163,7 +99,7 @@ e_book_view_listener_queue_idlist_event (EBookViewListener *listener, static void e_book_view_listener_queue_sequence_event (EBookViewListener *listener, EBookViewListenerOperation op, - const GNOME_Evolution_Addressbook_VCardList *cards) + const GNOME_Evolution_Addressbook_VCardList *vcards) { EBookViewListenerResponse *resp; int i; @@ -174,13 +110,10 @@ e_book_view_listener_queue_sequence_event (EBookViewListener *listener, resp = g_new0 (EBookViewListenerResponse, 1); resp->op = op; - resp->status = E_BOOK_VIEW_STATUS_SUCCESS; - resp->ids = NULL; - resp->cards = NULL; - resp->message = NULL; + resp->status = E_BOOK_VIEW_STATUS_OK; - for ( i = 0; i < cards->_length; i++ ) { - resp->cards = g_list_append(resp->cards, e_card_new(cards->_buffer[i])); + for ( i = 0; i < vcards->_length; i++ ) { + resp->contacts = g_list_append(resp->contacts, e_contact_new_from_vcard (vcards->_buffer[i])); } e_book_view_listener_queue_response (listener, resp); @@ -200,135 +133,93 @@ e_book_view_listener_queue_message_event (EBookViewListener *listener, resp = g_new0 (EBookViewListenerResponse, 1); resp->op = op; - resp->status = E_BOOK_VIEW_STATUS_SUCCESS; - resp->ids = NULL; - resp->cards = NULL; + resp->status = E_BOOK_VIEW_STATUS_OK; resp->message = g_strdup(message); e_book_view_listener_queue_response (listener, resp); } static void -impl_BookViewListener_notify_card_added (PortableServer_Servant servant, - const GNOME_Evolution_Addressbook_VCardList *cards, - CORBA_Environment *ev) +impl_BookViewListener_notify_contacts_added (PortableServer_Servant servant, + const GNOME_Evolution_Addressbook_VCardList *vcards, + CORBA_Environment *ev) { EBookViewListener *listener = E_BOOK_VIEW_LISTENER (bonobo_object (servant)); + printf ("impl_BookViewListener_notify_contacts_added\n"); + e_book_view_listener_queue_sequence_event ( - listener, CardAddedEvent, cards); + listener, ContactsAddedEvent, vcards); } static void -impl_BookViewListener_notify_cards_removed (PortableServer_Servant servant, - const GNOME_Evolution_Addressbook_CardIdList *ids, - CORBA_Environment *ev) +impl_BookViewListener_notify_contacts_removed (PortableServer_Servant servant, + const GNOME_Evolution_Addressbook_ContactIdList *ids, + CORBA_Environment *ev) { EBookViewListener *listener = E_BOOK_VIEW_LISTENER (bonobo_object (servant)); - e_book_view_listener_queue_idlist_event (listener, CardsRemovedEvent, ids); + printf ("impl_BookViewListener_notify_contacts_removed\n"); + + e_book_view_listener_queue_idlist_event (listener, ContactsRemovedEvent, ids); } static void -impl_BookViewListener_notify_card_changed (PortableServer_Servant servant, - const GNOME_Evolution_Addressbook_VCardList *cards, - CORBA_Environment *ev) +impl_BookViewListener_notify_contacts_changed (PortableServer_Servant servant, + const GNOME_Evolution_Addressbook_VCardList *vcards, + CORBA_Environment *ev) { EBookViewListener *listener = E_BOOK_VIEW_LISTENER (bonobo_object (servant)); + printf ("impl_BookViewListener_notify_contacts_changed\n"); + e_book_view_listener_queue_sequence_event ( - listener, CardModifiedEvent, cards); + listener, ContactsModifiedEvent, vcards); } static void impl_BookViewListener_notify_sequence_complete (PortableServer_Servant servant, - const GNOME_Evolution_Addressbook_BookViewListener_CallStatus status, + const GNOME_Evolution_Addressbook_CallStatus status, CORBA_Environment *ev) { EBookViewListener *listener = E_BOOK_VIEW_LISTENER (bonobo_object (servant)); + printf ("impl_BookViewListener_notify_sequence_complete\n"); + e_book_view_listener_queue_status_event (listener, SequenceCompleteEvent, e_book_view_listener_convert_status (status)); } static void -impl_BookViewListener_notify_status_message (PortableServer_Servant servant, - const char *message, - CORBA_Environment *ev) +impl_BookViewListener_notify_progress (PortableServer_Servant servant, + const char *message, + const CORBA_short percent, + CORBA_Environment *ev) { EBookViewListener *listener = E_BOOK_VIEW_LISTENER (bonobo_object (servant)); - e_book_view_listener_queue_message_event (listener, StatusMessageEvent, message); -} + printf ("impl_BookViewListener_notify_progress\n"); -/** - * e_book_view_listener_check_pending: - * @listener: the #EBookViewListener - * - * Returns: the number of items on the response queue, - * or -1 if the @listener is isn't an #EBookViewListener. - */ -int -e_book_view_listener_check_pending (EBookViewListener *listener) -{ - g_return_val_if_fail (listener != NULL, -1); - g_return_val_if_fail (E_IS_BOOK_VIEW_LISTENER (listener), -1); - - return g_list_length (listener->priv->response_queue); -} - -/** - * e_book_view_listener_pop_response: - * @listener: the #EBookViewListener for which a request is to be popped - * - * Returns: an #EBookViewListenerResponse if there are responses on the - * queue to be returned; %NULL if there aren't, or if the @listener - * isn't an EBookViewListener. - */ -EBookViewListenerResponse * -e_book_view_listener_pop_response (EBookViewListener *listener) -{ - EBookViewListenerResponse *resp; - GList *popped; - - g_return_val_if_fail (listener != NULL, NULL); - g_return_val_if_fail (E_IS_BOOK_VIEW_LISTENER (listener), NULL); - - if (listener->priv->response_queue == NULL) - return NULL; - - resp = listener->priv->response_queue->data; - - popped = listener->priv->response_queue; - listener->priv->response_queue = - g_list_remove_link (listener->priv->response_queue, - listener->priv->response_queue); - g_list_free_1 (popped); - - return resp; + e_book_view_listener_queue_message_event (listener, StatusMessageEvent, message); } static EBookViewStatus -e_book_view_listener_convert_status (const GNOME_Evolution_Addressbook_BookViewListener_CallStatus status) +e_book_view_listener_convert_status (const GNOME_Evolution_Addressbook_CallStatus status) { switch (status) { - case GNOME_Evolution_Addressbook_BookViewListener_Success: - return E_BOOK_VIEW_STATUS_SUCCESS; - case GNOME_Evolution_Addressbook_BookViewListener_SearchTimeLimitExceeded: + case GNOME_Evolution_Addressbook_Success: + return E_BOOK_VIEW_STATUS_OK; + case GNOME_Evolution_Addressbook_SearchTimeLimitExceeded: return E_BOOK_VIEW_STATUS_TIME_LIMIT_EXCEEDED; - case GNOME_Evolution_Addressbook_BookViewListener_SearchSizeLimitExceeded: + case GNOME_Evolution_Addressbook_SearchSizeLimitExceeded: return E_BOOK_VIEW_STATUS_SIZE_LIMIT_EXCEEDED; - case GNOME_Evolution_Addressbook_BookViewListener_InvalidQuery: - return E_BOOK_VIEW_STATUS_INVALID_QUERY; - case GNOME_Evolution_Addressbook_BookViewListener_QueryRefused: - return E_BOOK_VIEW_STATUS_QUERY_REFUSED; - case GNOME_Evolution_Addressbook_BookViewListener_OtherError: - return E_BOOK_VIEW_STATUS_OTHER_ERROR; + case GNOME_Evolution_Addressbook_InvalidQuery: + return E_BOOK_VIEW_ERROR_INVALID_QUERY; + case GNOME_Evolution_Addressbook_QueryRefused: + return E_BOOK_VIEW_ERROR_QUERY_REFUSED; + case GNOME_Evolution_Addressbook_OtherError: default: - g_warning ("e_book_view_listener_convert_status: Unknown status " - "from card server: %d\n", (int) status); - return E_BOOK_VIEW_STATUS_UNKNOWN; - + return E_BOOK_VIEW_ERROR_OTHER_ERROR; } } @@ -351,7 +242,9 @@ e_book_view_listener_new () { EBookViewListener *listener; - listener = g_object_new (E_TYPE_BOOK_VIEW_LISTENER, NULL); + listener = g_object_new (E_TYPE_BOOK_VIEW_LISTENER, + "poa", bonobo_poa_get_threaded (ORBIT_THREAD_HINT_ALL_AT_IDLE, NULL), + NULL); e_book_view_listener_construct (listener); @@ -362,9 +255,6 @@ static void e_book_view_listener_init (EBookViewListener *listener) { listener->priv = g_new0 (EBookViewListenerPrivate, 1); - listener->priv->response_queue = NULL; - listener->priv->timeout_id = 0; - listener->priv->timeout_lock = FALSE; listener->priv->stopped = FALSE; } @@ -381,32 +271,6 @@ e_book_view_listener_dispose (GObject *object) EBookViewListener *listener = E_BOOK_VIEW_LISTENER (object); if (listener->priv) { - GList *l; - /* Remove our response queue handler: In theory, this - can never happen since we always hold a reference - to the listener while the timeout is running. */ - if (listener->priv->timeout_id) { - g_source_remove (listener->priv->timeout_id); - } - - /* Clear out the queue */ - for (l = listener->priv->response_queue; l != NULL; l = l->next) { - EBookViewListenerResponse *resp = l->data; - - g_list_foreach (resp->ids, (GFunc)g_free, NULL); - g_list_free (resp->ids); - - g_list_foreach(resp->cards, (GFunc) g_object_unref, NULL); - g_list_free(resp->cards); - resp->cards = NULL; - - g_free (resp->message); - resp->message = NULL; - - g_free (resp); - } - g_list_free (listener->priv->response_queue); - g_free (listener->priv); listener->priv = NULL; } @@ -423,23 +287,24 @@ e_book_view_listener_class_init (EBookViewListenerClass *klass) parent_class = g_type_class_ref (BONOBO_TYPE_OBJECT); - e_book_view_listener_signals [RESPONSES_QUEUED] = - g_signal_new ("responses_queued", + e_book_view_listener_signals [RESPONSE] = + g_signal_new ("response", G_OBJECT_CLASS_TYPE (object_class), G_SIGNAL_RUN_LAST, - G_STRUCT_OFFSET (EBookViewListenerClass, responses_queued), + G_STRUCT_OFFSET (EBookViewListenerClass, response), NULL, NULL, - e_book_marshal_NONE__NONE, - G_TYPE_NONE, 0); + e_book_marshal_NONE__POINTER, + G_TYPE_NONE, + 1, G_TYPE_POINTER); object_class->dispose = e_book_view_listener_dispose; epv = &klass->epv; - epv->notifyCardChanged = impl_BookViewListener_notify_card_changed; - epv->notifyCardsRemoved = impl_BookViewListener_notify_cards_removed; - epv->notifyCardAdded = impl_BookViewListener_notify_card_added; + epv->notifyContactsChanged = impl_BookViewListener_notify_contacts_changed; + epv->notifyContactsRemoved = impl_BookViewListener_notify_contacts_removed; + epv->notifyContactsAdded = impl_BookViewListener_notify_contacts_added; epv->notifySequenceComplete = impl_BookViewListener_notify_sequence_complete; - epv->notifyStatusMessage = impl_BookViewListener_notify_status_message; + epv->notifyProgress = impl_BookViewListener_notify_progress; } BONOBO_TYPE_FUNC_FULL ( diff --git a/addressbook/backend/ebook/e-book-view-listener.h b/addressbook/backend/ebook/e-book-view-listener.h index fd1c1395a7..a68f25c337 100644 --- a/addressbook/backend/ebook/e-book-view-listener.h +++ b/addressbook/backend/ebook/e-book-view-listener.h @@ -29,6 +29,8 @@ typedef struct _EBookViewListener EBookViewListener; typedef struct _EBookViewListenerClass EBookViewListenerClass; typedef struct _EBookViewListenerPrivate EBookViewListenerPrivate; +typedef struct _EBookViewListenerResponse EBookViewListenerResponse; + struct _EBookViewListener { BonoboObject parent; EBookViewListenerPrivate *priv; @@ -42,38 +44,44 @@ struct _EBookViewListenerClass { /* * Signals */ - void (*responses_queued) (void); + void (*response) (EBookViewListener *listener, EBookViewListenerResponse *response); + + + /* Padding for future expansion */ + void (*_ebook_reserved0) (void); + void (*_ebook_reserved1) (void); + void (*_ebook_reserved2) (void); + void (*_ebook_reserved3) (void); + void (*_ebook_reserved4) (void); }; typedef enum { /* Async events */ - CardAddedEvent, - CardsRemovedEvent, - CardModifiedEvent, + ContactsAddedEvent, + ContactsRemovedEvent, + ContactsModifiedEvent, SequenceCompleteEvent, StatusMessageEvent, } EBookViewListenerOperation; -typedef struct { +struct _EBookViewListenerResponse { EBookViewListenerOperation op; /* For SequenceComplete */ EBookViewStatus status; - /* For CardsRemovedEvent */ + /* For ContactsRemovedEvent */ GList *ids; - /* For Card[Added|Modified]Event */ - GList *cards; /* Of type ECard. */ + /* For Contact[sAdded|Modified]Event */ + GList *contacts; /* Of type EContact. */ /* For StatusMessageEvent */ char *message; -} EBookViewListenerResponse; +}; EBookViewListener *e_book_view_listener_new (void); -int e_book_view_listener_check_pending (EBookViewListener *listener); -EBookViewListenerResponse *e_book_view_listener_pop_response (EBookViewListener *listener); GType e_book_view_listener_get_type (void); void e_book_view_listener_stop (EBookViewListener *listener); diff --git a/addressbook/backend/ebook/e-book-view.c b/addressbook/backend/ebook/e-book-view.c index e1f4b1623c..e8468e35de 100644 --- a/addressbook/backend/ebook/e-book-view.c +++ b/addressbook/backend/ebook/e-book-view.c @@ -11,7 +11,6 @@ #include #include "addressbook.h" -#include "e-card-cursor.h" #include "e-book-view-listener.h" #include "e-book-view.h" #include "e-book.h" @@ -26,13 +25,13 @@ struct _EBookViewPrivate { EBookViewListener *listener; - int responses_queued_id; + int response_id; }; enum { - CARD_CHANGED, - CARD_REMOVED, - CARD_ADDED, + CONTACTS_CHANGED, + CONTACTS_REMOVED, + CONTACTS_ADDED, SEQUENCE_COMPLETE, STATUS_MESSAGE, LAST_SIGNAL @@ -40,48 +39,33 @@ enum { static guint e_book_view_signals [LAST_SIGNAL]; -static void -add_book_iterator (gpointer data, gpointer closure) -{ - ECard *card = E_CARD (data); - EBook *book = E_BOOK (closure); - - e_card_set_book (card, book); -} - static void e_book_view_do_added_event (EBookView *book_view, EBookViewListenerResponse *resp) { - if (book_view->priv->book) - g_list_foreach (resp->cards, add_book_iterator, book_view->priv->book); - - g_signal_emit (book_view, e_book_view_signals [CARD_ADDED], 0, - resp->cards); + g_signal_emit (book_view, e_book_view_signals [CONTACTS_ADDED], 0, + resp->contacts); - g_list_foreach (resp->cards, (GFunc) g_object_unref, NULL); - g_list_free (resp->cards); + g_list_foreach (resp->contacts, (GFunc) g_object_unref, NULL); + g_list_free (resp->contacts); } static void e_book_view_do_modified_event (EBookView *book_view, EBookViewListenerResponse *resp) { - if (book_view->priv->book) - g_list_foreach (resp->cards, add_book_iterator, book_view->priv->book); + g_signal_emit (book_view, e_book_view_signals [CONTACTS_CHANGED], 0, + resp->contacts); - g_signal_emit (book_view, e_book_view_signals [CARD_CHANGED], 0, - resp->cards); - - g_list_foreach (resp->cards, (GFunc) g_object_unref, NULL); - g_list_free (resp->cards); + g_list_foreach (resp->contacts, (GFunc) g_object_unref, NULL); + g_list_free (resp->contacts); } static void e_book_view_do_removed_event (EBookView *book_view, EBookViewListenerResponse *resp) { - g_signal_emit (book_view, e_book_view_signals [CARD_REMOVED], 0, + g_signal_emit (book_view, e_book_view_signals [CONTACTS_REMOVED], 0, resp->ids); g_list_foreach (resp->ids, (GFunc) g_free, NULL); @@ -106,27 +90,20 @@ e_book_view_do_status_message_event (EBookView *book_view, } -/* - * Reading notices out of the EBookViewListener's queue. - */ static void -e_book_view_check_listener_queue (EBookViewListener *listener, EBookView *book_view) +e_book_view_handle_response (EBookViewListener *listener, EBookViewListenerResponse *resp, EBookView *book_view) { - EBookViewListenerResponse *resp; - - resp = e_book_view_listener_pop_response (listener); - if (resp == NULL) return; switch (resp->op) { - case CardAddedEvent: + case ContactsAddedEvent: e_book_view_do_added_event (book_view, resp); break; - case CardModifiedEvent: + case ContactsModifiedEvent: e_book_view_do_modified_event (book_view, resp); break; - case CardsRemovedEvent: + case ContactsRemovedEvent: e_book_view_do_removed_event (book_view, resp); break; case SequenceCompleteEvent: @@ -171,8 +148,8 @@ e_book_view_construct (EBookView *book_view, GNOME_Evolution_Addressbook_BookVie * Create our local BookListener interface. */ book_view->priv->listener = listener; - book_view->priv->responses_queued_id = g_signal_connect (book_view->priv->listener, "responses_queued", - G_CALLBACK (e_book_view_check_listener_queue), book_view); + book_view->priv->response_id = g_signal_connect (book_view->priv->listener, "response", + G_CALLBACK (e_book_view_handle_response), book_view); bonobo_object_ref(BONOBO_OBJECT(book_view->priv->listener)); @@ -208,6 +185,22 @@ e_book_view_set_book (EBookView *book_view, EBook *book) g_object_ref (book); } +void +e_book_view_start (EBookView *book_view) +{ + CORBA_Environment ev; + + g_return_if_fail (book_view && E_IS_BOOK_VIEW (book_view)); + + CORBA_exception_init (&ev); + + GNOME_Evolution_Addressbook_BookView_start (book_view->priv->corba_book_view, &ev); + + if (ev._major != CORBA_NO_EXCEPTION) { + g_warning ("corba exception._major = %d\n", ev._major); + } +} + void e_book_view_stop (EBookView *book_view) { @@ -223,7 +216,7 @@ e_book_view_init (EBookView *book_view) book_view->priv->book = NULL; book_view->priv->corba_book_view = CORBA_OBJECT_NIL; book_view->priv->listener = NULL; - book_view->priv->responses_queued_id = 0; + book_view->priv->response_id = 0; } static void @@ -250,9 +243,9 @@ e_book_view_dispose (GObject *object) } if (book_view->priv->listener) { - if (book_view->priv->responses_queued_id) + if (book_view->priv->response_id) g_signal_handler_disconnect(book_view->priv->listener, - book_view->priv->responses_queued_id); + book_view->priv->response_id); e_book_view_listener_stop (book_view->priv->listener); bonobo_object_unref (BONOBO_OBJECT(book_view->priv->listener)); } @@ -271,31 +264,31 @@ e_book_view_class_init (EBookViewClass *klass) parent_class = g_type_class_ref (G_TYPE_OBJECT); - e_book_view_signals [CARD_CHANGED] = - g_signal_new ("card_changed", + e_book_view_signals [CONTACTS_CHANGED] = + g_signal_new ("contacts_changed", G_OBJECT_CLASS_TYPE (object_class), G_SIGNAL_RUN_LAST, - G_STRUCT_OFFSET (EBookViewClass, card_changed), + G_STRUCT_OFFSET (EBookViewClass, contacts_changed), NULL, NULL, e_book_marshal_NONE__POINTER, G_TYPE_NONE, 1, G_TYPE_POINTER); - e_book_view_signals [CARD_ADDED] = - g_signal_new ("card_added", + e_book_view_signals [CONTACTS_ADDED] = + g_signal_new ("contacts_added", G_OBJECT_CLASS_TYPE (object_class), G_SIGNAL_RUN_LAST, - G_STRUCT_OFFSET (EBookViewClass, card_added), + G_STRUCT_OFFSET (EBookViewClass, contacts_added), NULL, NULL, e_book_marshal_NONE__POINTER, G_TYPE_NONE, 1, G_TYPE_POINTER); - e_book_view_signals [CARD_REMOVED] = - g_signal_new ("card_removed", + e_book_view_signals [CONTACTS_REMOVED] = + g_signal_new ("contacts_removed", G_OBJECT_CLASS_TYPE (object_class), G_SIGNAL_RUN_LAST, - G_STRUCT_OFFSET (EBookViewClass, card_removed), + G_STRUCT_OFFSET (EBookViewClass, contacts_removed), NULL, NULL, e_book_marshal_NONE__POINTER, G_TYPE_NONE, 1, diff --git a/addressbook/backend/ebook/e-book-view.h b/addressbook/backend/ebook/e-book-view.h index bd7a97d1d5..5b9768315b 100644 --- a/addressbook/backend/ebook/e-book-view.h +++ b/addressbook/backend/ebook/e-book-view.h @@ -13,7 +13,6 @@ #include #include -#include #include #define E_TYPE_BOOK_VIEW (e_book_view_get_type ()) @@ -42,11 +41,18 @@ struct _EBookViewClass { /* * Signals. */ - void (* card_changed) (EBookView *book_view, const GList *cards); - void (* card_removed) (EBookView *book_view, const GList *ids); - void (* card_added) (EBookView *book_view, const GList *cards); + void (* contacts_changed) (EBookView *book_view, const GList *contacts); + void (* contacts_removed) (EBookView *book_view, const GList *ids); + void (* contacts_added) (EBookView *book_view, const GList *contacts); void (* sequence_complete) (EBookView *book_view, EBookViewStatus status); void (* status_message) (EBookView *book_view, const char *message); + + /* Padding for future expansion */ + void (*_ebook_reserved0) (void); + void (*_ebook_reserved1) (void); + void (*_ebook_reserved2) (void); + void (*_ebook_reserved3) (void); + void (*_ebook_reserved4) (void); }; /* Creating a new addressbook. */ @@ -56,6 +62,7 @@ GType e_book_view_get_type (void); void e_book_view_set_book (EBookView *book_view, struct _EBook *book); +void e_book_view_start (EBookView *book_view); void e_book_view_stop (EBookView *book_view); G_END_DECLS diff --git a/addressbook/backend/ebook/e-book.c b/addressbook/backend/ebook/e-book.c index 08a0aac995..3883cd4b15 100644 --- a/addressbook/backend/ebook/e-book.c +++ b/addressbook/backend/ebook/e-book.c @@ -1,34 +1,86 @@ /* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ -/* - * The Evolution addressbook client object. - * - * Author: - * Nat Friedman (nat@ximian.com) - * - * Copyright 1999, 2000, Ximian, Inc. - */ #include -#include -#include + +#include + #include -#include -#include "addressbook.h" -#include "e-card-cursor.h" -#include "e-book-listener.h" #include "e-book.h" +#include "e-vcard.h" + +#include + +#include +#include + +#include + #include "e-book-marshal.h" +#include "e-book-listener.h" +#include "addressbook.h" #include "e-util/e-component-listener.h" +#include "e-util/e-msgport.h" static GObjectClass *parent_class; #define CARDSERVER_OAF_ID "OAFIID:GNOME_Evolution_Wombat_ServerFactory" +#define e_return_error_if_fail(expr,error_code) G_STMT_START{ \ + if G_LIKELY(expr) { } else \ + { \ + g_log (G_LOG_DOMAIN, \ + G_LOG_LEVEL_CRITICAL, \ + "file %s: line %d (%s): assertion `%s' failed", \ + __FILE__, \ + __LINE__, \ + __PRETTY_FUNCTION__, \ + #expr); \ + g_set_error (error, E_BOOK_ERROR, (error_code), \ + "file %s: line %d (%s): assertion `%s' failed", \ + __FILE__, \ + __LINE__, \ + __PRETTY_FUNCTION__, \ + #expr); \ + return FALSE; \ + }; }G_STMT_END + +/* XXX we need a better error message here */ +#define E_BOOK_CHECK_STATUS(status,error) G_STMT_START{ \ + if ((status) == E_BOOK_ERROR_OK) { \ + return TRUE; \ + } \ + else { \ + g_set_error ((error), E_BOOK_ERROR, (status), "EBookStatus returned %d", (status)); \ + return FALSE; \ + } }G_STMT_END + +enum { + OPEN_PROGRESS, + WRITABLE_STATUS, + BACKEND_DIED, + LAST_SIGNAL +}; + +static guint e_book_signals [LAST_SIGNAL]; + +typedef struct { + EMutex *mutex; + pthread_cond_t cond; + EBookStatus status; + + char *id; + GList *list; + EContact *contact; + + EBookView *view; + EBookViewListener *listener; +} EBookOp; + typedef enum { - URINotLoaded, - URILoading, - URILoaded + E_BOOK_URI_NOT_LOADED, + E_BOOK_URI_LOADING, + E_BOOK_URI_LOADED } EBookLoadState; struct _EBookPrivate { @@ -39,21 +91,20 @@ struct _EBookPrivate { char *cap; gboolean cap_queried; - EBookListener *listener; + /* cached writable status */ + gboolean writable; + + EBookListener *listener; EComponentListener *comp_listener; GNOME_Evolution_Addressbook_Book corba_book; EBookLoadState load_state; - /* - * The operation queue. New operations are appended to the - * end of the queue. When responses come back from the PAS, - * the op structures are popped off the front of the queue. - */ - GList *pending_ops; - guint op_tag; + EBookOp *current_op; + + EMutex *mutex; gchar *uri; @@ -61,1526 +112,1844 @@ struct _EBookPrivate { gulong died_signal; }; -enum { - OPEN_PROGRESS, - WRITABLE_STATUS, - LINK_STATUS, - BACKEND_DIED, - LAST_SIGNAL -}; - -static guint e_book_signals [LAST_SIGNAL]; + +/* Error quark */ +GQuark +e_book_error_quark (void) +{ + static GQuark q = 0; + if (q == 0) + q = g_quark_from_static_string ("e-book-error-quark"); -typedef struct { - guint tag; - gboolean active; - gpointer cb; - gpointer closure; - EBookViewListener *listener; -} EBookOp; + return q; +} -/* - * Local response queue management. - */ + -static void -e_book_op_free (EBookOp *op) -{ - if (op->listener) { - bonobo_object_unref (BONOBO_OBJECT (op->listener)); - op->listener = NULL; - } - g_free (op); -} +/* EBookOp calls */ -static guint -e_book_queue_op (EBook *book, - gpointer cb, - gpointer closure, - EBookViewListener *listener) +static EBookOp* +e_book_new_op (EBook *book) { - EBookOp *op; + EBookOp *op = g_new0 (EBookOp, 1); - op = g_new0 (EBookOp, 1); - op->tag = book->priv->op_tag++; - op->active = TRUE; - op->cb = cb; - op->closure = closure; - op->listener = listener; + op->mutex = e_mutex_new (E_MUTEX_SIMPLE); + pthread_cond_init (&op->cond, 0); - if (op->listener) - bonobo_object_ref (BONOBO_OBJECT (op->listener)); + book->priv->current_op = op; - book->priv->pending_ops = - g_list_append (book->priv->pending_ops, op); + return op; +} - return op->tag; +static EBookOp* +e_book_get_op (EBook *book) +{ + if (!book->priv->current_op) { + g_warning ("unexpected response"); + return NULL; + } + + return book->priv->current_op; } -/* - * Local response queue management. - */ static void -e_book_unqueue_op (EBook *book) +e_book_op_free (EBookOp *op) { - EBookOp *op; - GList *removed; + /* XXX more stuff here */ + pthread_cond_destroy (&op->cond); + e_mutex_destroy (op->mutex); + g_free (op); +} - removed = g_list_last (book->priv->pending_ops); +static void +e_book_op_remove (EBook *book, + EBookOp *op) +{ + if (book->priv->current_op != op) + g_warning ("cannot remove op, it's not current"); - if (removed) { - book->priv->pending_ops = g_list_remove_link (book->priv->pending_ops, - removed); - op = removed->data; - e_book_op_free (op); - g_list_free_1 (removed); - book->priv->op_tag--; - } + book->priv->current_op = NULL; } -static EBookOp * -e_book_pop_op (EBook *book) +static void +e_book_clear_op (EBook *book, + EBookOp *op) { - GList *popped; - EBookOp *op; + e_book_op_remove (book, op); + e_mutex_unlock (op->mutex); + e_book_op_free (op); +} - if (book->priv->pending_ops == NULL) - return NULL; + - op = book->priv->pending_ops->data; +/** + * e_book_add_card: + * @book: an #EBook + * @contact: an #EContact + * + * adds @contact to @book. + * + * Return value: a #EBookStatus value. + **/ +gboolean +e_book_add_contact (EBook *book, + EContact *contact, + GError **error) +{ + EBookOp *our_op; + EBookStatus status; + CORBA_Environment ev; + char *vcard_str; - popped = book->priv->pending_ops; - book->priv->pending_ops = - g_list_remove_link (book->priv->pending_ops, - book->priv->pending_ops); + printf ("e_book_add_contact\n"); - g_list_free_1 (popped); + e_return_error_if_fail (book && E_IS_BOOK (book), E_BOOK_ERROR_INVALID_ARG); + e_return_error_if_fail (contact && E_IS_CONTACT (contact), E_BOOK_ERROR_INVALID_ARG); - return op; -} + e_mutex_lock (book->priv->mutex); -static gboolean -e_book_cancel_op (EBook *book, guint tag) -{ - GList *iter; - gboolean cancelled = FALSE; + if (book->priv->load_state != E_BOOK_URI_LOADED) { + e_mutex_unlock (book->priv->mutex); + g_set_error (error, E_BOOK_ERROR, E_BOOK_ERROR_URI_NOT_LOADED, + _("e_book_add_contact called on book before e_book_load_uri")); + return FALSE; + } - for (iter = book->priv->pending_ops; iter != NULL && !cancelled; iter = g_list_next (iter)) { - EBookOp *op = iter->data; - if (op->tag == tag) { - op->active = FALSE; - cancelled = TRUE; - } + if (book->priv->current_op != NULL) { + e_mutex_unlock (book->priv->mutex); + g_set_error (error, E_BOOK_ERROR, E_BOOK_ERROR_BUSY, + _("book busy")); + return FALSE; } - - return cancelled; -} -static void -e_book_do_response_create_card (EBook *book, - EBookListenerResponse *resp) -{ - EBookOp *op; + vcard_str = e_vcard_to_string (E_VCARD (contact), EVC_FORMAT_VCARD_30); - op = e_book_pop_op (book); + our_op = e_book_new_op (book); - if (op == NULL) { - g_warning ("e_book_do_response_create_card: Cannot find operation " - "in local op queue!\n"); - return; - } + e_mutex_lock (our_op->mutex); - if (op->cb) - ((EBookIdCallback) op->cb) (book, resp->status, resp->id, op->closure); - g_free (resp->id); - e_book_op_free (op); -} + e_mutex_unlock (book->priv->mutex); -static void -e_book_do_response_generic (EBook *book, - EBookListenerResponse *resp) -{ - EBookOp *op; + CORBA_exception_init (&ev); - op = e_book_pop_op (book); + /* will eventually end up calling e_book_response_add_contact */ + GNOME_Evolution_Addressbook_Book_addContact (book->priv->corba_book, + (const GNOME_Evolution_Addressbook_VCard) vcard_str, &ev); - if (op == NULL) { - g_warning ("e_book_do_response_generic: Cannot find operation " - "in local op queue!\n"); + g_free (vcard_str); + + if (ev._major != CORBA_NO_EXCEPTION) { + + e_book_clear_op (book, our_op); + + CORBA_exception_free (&ev); + + g_set_error (error, E_BOOK_ERROR, E_BOOK_ERROR_CORBA_EXCEPTION, + _("Corba exception making Book::addContact call")); + return FALSE; } - if (op->cb) - ((EBookCallback) op->cb) (book, resp->status, op->closure); + CORBA_exception_free (&ev); + + /* wait for something to happen (both cancellation and a + successful response will notity us via our cv */ + e_mutex_cond_wait (&our_op->cond, our_op->mutex); - e_book_op_free (op); + status = our_op->status; + e_contact_set (contact, E_CONTACT_UID, our_op->id); + g_free (our_op->id); + + e_book_clear_op (book, our_op); + + E_BOOK_CHECK_STATUS (status, error); } static void -e_book_do_response_get_vcard (EBook *book, - EBookListenerResponse *resp) +e_book_response_add_contact (EBook *book, + EBookStatus status, + char *id) { EBookOp *op; - ECard *card; - op = e_book_pop_op (book); + printf ("e_book_response_add_contact\n"); + + op = e_book_get_op (book); if (op == NULL) { - g_warning ("e_book_do_response_get_vcard: Cannot find operation " - "in local op queue!\n"); - return; + g_warning ("e_book_response_add_contact: Cannot find operation "); + return; } - if (resp->vcard != NULL) { - card = e_card_new(resp->vcard); + e_mutex_lock (op->mutex); - if (card != NULL) { - e_card_set_book (card, book); - if (op->cb) { - if (op->active) - ((EBookCardCallback) op->cb) (book, resp->status, card, op->closure); - else - ((EBookCardCallback) op->cb) (book, E_BOOK_STATUS_CANCELLED, NULL, op->closure); - } + op->status = status; + op->id = g_strdup (id); - g_object_unref(card); - } else { - ((EBookCursorCallback) op->cb) (book, resp->status, NULL, op->closure); - } - } else { - ((EBookCardCallback) op->cb) (book, resp->status, NULL, op->closure); - } + pthread_cond_signal (&op->cond); - g_free (resp->vcard); - e_book_op_free (op); + e_mutex_unlock (op->mutex); } -static void -e_book_do_response_get_cursor (EBook *book, - EBookListenerResponse *resp) + + +/** + * e_book_commit_contact: + * @book: an #EBook + * @contact: an #EContact + * + * applies the changes made to @contact to the stored version in + * @book. + * + * Return value: a #EBookStatus value. + **/ +gboolean +e_book_commit_contact (EBook *book, + EContact *contact, + GError **error) { + EBookOp *our_op; + EBookStatus status; CORBA_Environment ev; - EBookOp *op; - ECardCursor *cursor; + char *vcard_str; - op = e_book_pop_op (book); + e_return_error_if_fail (book && E_IS_BOOK (book), E_BOOK_ERROR_INVALID_ARG); + e_return_error_if_fail (contact && E_IS_CONTACT (contact), E_BOOK_ERROR_INVALID_ARG); - if (op == NULL) { - g_warning ("e_book_do_response_get_cursor: Cannot find operation " - "in local op queue!\n"); - return; + e_mutex_lock (book->priv->mutex); + + if (book->priv->load_state != E_BOOK_URI_LOADED) { + e_mutex_unlock (book->priv->mutex); + g_set_error (error, E_BOOK_ERROR, E_BOOK_ERROR_URI_NOT_LOADED, + _("e_book_commit_contact called on book before e_book_load_uri")); + return FALSE; } - cursor = e_card_cursor_new(resp->cursor); + if (book->priv->current_op != NULL) { + e_mutex_unlock (book->priv->mutex); + g_set_error (error, E_BOOK_ERROR, E_BOOK_ERROR_BUSY, + _("book busy")); + return FALSE; + } - if (cursor != NULL) { - if (op->cb) { - if (op->active) - ((EBookCursorCallback) op->cb) (book, resp->status, cursor, op->closure); - else - ((EBookCursorCallback) op->cb) (book, E_BOOK_STATUS_CANCELLED, NULL, op->closure); - } + vcard_str = e_vcard_to_string (E_VCARD (contact), EVC_FORMAT_VCARD_30); - /* - * Release the remote GNOME_Evolution_Addressbook_Book in the PAS. - */ - CORBA_exception_init (&ev); + our_op = e_book_new_op (book); - bonobo_object_release_unref (resp->cursor, &ev); + e_mutex_lock (our_op->mutex); - if (ev._major != CORBA_NO_EXCEPTION) { - g_warning ("e_book_do_response_get_cursor: Exception releasing " - "remote GNOME_Evolution_Addressbook_CardCursor interface!\n"); - } + e_mutex_unlock (book->priv->mutex); - CORBA_exception_free (&ev); + CORBA_exception_init (&ev); - g_object_unref(cursor); - } else { - ((EBookCursorCallback) op->cb) (book, E_BOOK_STATUS_CANCELLED, NULL, op->closure); - } - - e_book_op_free (op); -} + /* will eventually end up calling _e_book_response_generic */ + GNOME_Evolution_Addressbook_Book_modifyContact (book->priv->corba_book, + (const GNOME_Evolution_Addressbook_VCard) vcard_str, &ev); -static void -e_book_do_response_get_view (EBook *book, - EBookListenerResponse *resp) -{ - CORBA_Environment ev; - EBookOp *op; - EBookView *book_view; + g_free (vcard_str); + + if (ev._major != CORBA_NO_EXCEPTION) { - op = e_book_pop_op (book); + e_book_clear_op (book, our_op); - if (op == NULL) { - g_warning ("e_book_do_response_get_view: Cannot find operation " - "in local op queue!\n"); - return; + CORBA_exception_free (&ev); + + g_set_error (error, E_BOOK_ERROR, E_BOOK_ERROR_CORBA_EXCEPTION, + _("Corba exception making Book::modifyContact call")); + return FALSE; } - - book_view = e_book_view_new (resp->book_view, op->listener); - - if (book_view != NULL) { - e_book_view_set_book (book_view, book); - - /* Only execute the callback if the operation is still flagged as active (i.e. hasn't - been cancelled. This is mildly wasteful since we unnecessaryily create the - book_view, etc... but I'm leery of tinkering with the CORBA magic. */ - if (op->cb) { - if (op->active) - ((EBookBookViewCallback) op->cb) (book, resp->status, book_view, op->closure); - else - ((EBookBookViewCallback) op->cb) (book, E_BOOK_STATUS_CANCELLED, NULL, op->closure); - } - - /* - * Release the remote GNOME_Evolution_Addressbook_Book in the PAS. - */ - CORBA_exception_init (&ev); - bonobo_object_release_unref (resp->book_view, &ev); + CORBA_exception_free (&ev); - if (ev._major != CORBA_NO_EXCEPTION) { - g_warning ("e_book_do_response_get_view: Exception releasing " - "remote GNOME_Evolution_Addressbook_BookView interface!\n"); - } + /* wait for something to happen (both cancellation and a + successful response will notity us via our cv */ + e_mutex_cond_wait (&our_op->cond, our_op->mutex); - CORBA_exception_free (&ev); + status = our_op->status; + e_contact_set (contact, E_CONTACT_UID, our_op->id); + g_free (our_op->id); - g_object_unref(book_view); - } else { - e_book_view_listener_stop (op->listener); - ((EBookBookViewCallback) op->cb) (book, E_BOOK_STATUS_CANCELLED, NULL, op->closure); - } + /* remove the op from the book's hash of operations */ + e_book_clear_op (book, our_op); - e_book_op_free (op); + E_BOOK_CHECK_STATUS (status, error); } -static void -e_book_do_response_get_changes (EBook *book, - EBookListenerResponse *resp) + +/** + * e_book_get_supported_fields: + * @book: an #EBook + * @fields: a #GList + * + * queries @book for the list of fields it supports. mostly for use + * by the contact editor so it knows what fields to sensitize. + * + * Return value: a #EBookStatus value. + **/ +gboolean +e_book_get_supported_fields (EBook *book, + GList **fields, + GError **error) { + EBookOp *our_op; + EBookStatus status; CORBA_Environment ev; - EBookOp *op; - EBookView *book_view; - op = e_book_pop_op (book); + e_return_error_if_fail (book && E_IS_BOOK (book), E_BOOK_ERROR_INVALID_ARG); + e_return_error_if_fail (fields, E_BOOK_ERROR_INVALID_ARG); - if (op == NULL) { - g_warning ("e_book_do_response_get_changes: Cannot find operation " - "in local op queue!\n"); - return; + e_mutex_lock (book->priv->mutex); + + if (book->priv->load_state != E_BOOK_URI_LOADED) { + e_mutex_unlock (book->priv->mutex); + g_set_error (error, E_BOOK_ERROR, E_BOOK_ERROR_URI_NOT_LOADED, + _("e_book_get_supported_fields on book before e_book_load_uri")); + return FALSE; } - book_view = e_book_view_new (resp->book_view, op->listener); + if (book->priv->current_op != NULL) { + e_mutex_unlock (book->priv->mutex); + g_set_error (error, E_BOOK_ERROR, E_BOOK_ERROR_BUSY, + _("book busy")); + } - if (book_view != NULL) { - e_book_view_set_book (book_view, book); - - if (op->cb) { - if (op->active) - ((EBookBookViewCallback) op->cb) (book, resp->status, book_view, op->closure); - else - ((EBookBookViewCallback) op->cb) (book, E_BOOK_STATUS_CANCELLED, NULL, op->closure); - } + our_op = e_book_new_op (book); - /* - * Release the remote GNOME_Evolution_Addressbook_BookView in the PAS. - */ - CORBA_exception_init (&ev); + e_mutex_lock (our_op->mutex); - bonobo_object_release_unref (resp->book_view, &ev); + e_mutex_unlock (book->priv->mutex); - if (ev._major != CORBA_NO_EXCEPTION) { - g_warning ("e_book_do_response_get_changes: Exception releasing " - "remote GNOME_Evolution_Addressbook_BookView interface!\n"); - } + CORBA_exception_init (&ev); + + /* will eventually end up calling + _e_book_response_get_supported_fields */ + GNOME_Evolution_Addressbook_Book_getSupportedFields(book->priv->corba_book, &ev); + + if (ev._major != CORBA_NO_EXCEPTION) { + + e_book_clear_op (book, our_op); CORBA_exception_free (&ev); - g_object_unref(book_view); - } else { - e_book_view_listener_stop (op->listener); - ((EBookBookViewCallback) op->cb) (book, E_BOOK_STATUS_CANCELLED, NULL, op->closure); + g_set_error (error, E_BOOK_ERROR, E_BOOK_ERROR_CORBA_EXCEPTION, + _("Corba exception making Book::getSupportedFields call")); + return FALSE; } - e_book_op_free (op); -} -static void -backend_died_cb (EComponentListener *cl, gpointer user_data) -{ - EBook *book = user_data; + CORBA_exception_free (&ev); - book->priv->load_state = URINotLoaded; - g_signal_emit (book, e_book_signals [BACKEND_DIED], 0); + /* wait for something to happen (both cancellation and a + successful response will notity us via our cv */ + e_mutex_cond_wait (&our_op->cond, our_op->mutex); + + status = our_op->status; + *fields = our_op->list; + + e_book_clear_op (book, our_op); + + E_BOOK_CHECK_STATUS (status, error); } static void -e_book_do_response_open (EBook *book, - EBookListenerResponse *resp) +e_book_response_get_supported_fields (EBook *book, + EBookStatus status, + GList *fields) { EBookOp *op; - if (resp->status == E_BOOK_STATUS_SUCCESS) { - book->priv->corba_book = resp->book; - book->priv->load_state = URILoaded; - - book->priv->comp_listener = e_component_listener_new (book->priv->corba_book); - book->priv->died_signal = g_signal_connect (book->priv->comp_listener, "component_died", - G_CALLBACK (backend_died_cb), book); - } - - op = e_book_pop_op (book); + op = e_book_get_op (book); if (op == NULL) { - g_warning ("e_book_do_response_open: Cannot find operation " - "in local op queue!\n"); - return; + g_warning ("e_book_response_get_supported_fields: Cannot find operation "); + return; } - if (op->cb) - ((EBookCallback) op->cb) (book, resp->status, op->closure); - e_book_op_free (op); -} + e_mutex_lock (op->mutex); -static void -e_book_do_progress_event (EBook *book, - EBookListenerResponse *resp) -{ - g_signal_emit (book, e_book_signals [OPEN_PROGRESS], 0, - resp->msg, resp->percent); + op->status = status; + op->list = fields; - g_free (resp->msg); -} + pthread_cond_signal (&op->cond); -static void -e_book_do_link_event (EBook *book, - EBookListenerResponse *resp) -{ - g_signal_emit (book, e_book_signals [LINK_STATUS], 0, - resp->connected); + e_mutex_unlock (op->mutex); } -static void -e_book_do_writable_event (EBook *book, - EBookListenerResponse *resp) + +/** + * e_book_get_supported_auth_methods: + * @book: an #EBook + * @auth_methods: a #GList + * + * queries @book for the list of authentication methods it supports. + * + * Return value: a #EBookStatus value. + **/ +gboolean +e_book_get_supported_auth_methods (EBook *book, + GList **auth_methods, + GError **error) { - g_signal_emit (book, e_book_signals [WRITABLE_STATUS], 0, - resp->writable); -} + EBookOp *our_op; + EBookStatus status; + CORBA_Environment ev; -static void -e_book_do_response_get_supported_fields (EBook *book, - EBookListenerResponse *resp) -{ - EBookOp *op; + e_return_error_if_fail (book && E_IS_BOOK (book), E_BOOK_ERROR_INVALID_ARG); + e_return_error_if_fail (auth_methods, E_BOOK_ERROR_INVALID_ARG); - op = e_book_pop_op (book); + e_mutex_lock (book->priv->mutex); - if (op == NULL) { - g_warning ("e_book_do_response_get_supported_fields: Cannot find operation " - "in local op queue!\n"); - return; + if (book->priv->load_state != E_BOOK_URI_LOADED) { + e_mutex_unlock (book->priv->mutex); + g_set_error (error, E_BOOK_ERROR, E_BOOK_ERROR_URI_NOT_LOADED, + _("e_book_get_supported_auth_methods on book before e_book_load_uri")); + return FALSE; } - if (op->cb) { - if (op->active) - ((EBookFieldsCallback) op->cb) (book, resp->status, resp->list, op->closure); - else - ((EBookFieldsCallback) op->cb) (book, E_BOOK_STATUS_CANCELLED, NULL, op->closure); + if (book->priv->current_op != NULL) { + e_mutex_unlock (book->priv->mutex); + g_set_error (error, E_BOOK_ERROR, E_BOOK_ERROR_BUSY, + _("book busy")); + return FALSE; } - g_object_unref(resp->list); + our_op = e_book_new_op (book); - e_book_op_free (op); + e_mutex_lock (our_op->mutex); + + e_mutex_unlock (book->priv->mutex); + + CORBA_exception_init (&ev); + + /* will eventually end up calling + e_book_response_get_supported_fields */ + GNOME_Evolution_Addressbook_Book_getSupportedAuthMethods(book->priv->corba_book, &ev); + + if (ev._major != CORBA_NO_EXCEPTION) { + + e_book_clear_op (book, our_op); + + CORBA_exception_free (&ev); + + g_set_error (error, E_BOOK_ERROR, E_BOOK_ERROR_CORBA_EXCEPTION, + _("Corba exception making Book::getSupportedAuthMethods call")); + return FALSE; + } + + + CORBA_exception_free (&ev); + + /* wait for something to happen (both cancellation and a + successful response will notity us via our cv */ + e_mutex_cond_wait (&our_op->cond, our_op->mutex); + + status = our_op->status; + *auth_methods = our_op->list; + + e_book_clear_op (book, our_op); + + E_BOOK_CHECK_STATUS (status, error); } static void -e_book_do_response_get_supported_auth_methods (EBook *book, - EBookListenerResponse *resp) +e_book_response_get_supported_auth_methods (EBook *book, + EBookStatus status, + GList *auth_methods) { EBookOp *op; - op = e_book_pop_op (book); + op = e_book_get_op (book); if (op == NULL) { - g_warning ("e_book_do_response_get_supported_auth_methods: Cannot find operation " - "in local op queue!\n"); - return; - } - - if (op->cb) { - if (op->active) - ((EBookAuthMethodsCallback) op->cb) (book, resp->status, resp->list, op->closure); - else - ((EBookAuthMethodsCallback) op->cb) (book, E_BOOK_STATUS_CANCELLED, NULL, op->closure); + g_warning ("e_book_response_get_supported_auth_methods: Cannot find operation "); + return; } - g_object_unref(resp->list); + e_mutex_lock (op->mutex); - e_book_op_free (op); -} + op->status = status; + op->list = auth_methods; -/* - * Reading notices out of the EBookListener's queue. - */ -static void -e_book_check_listener_queue (EBookListener *listener, EBook *book) -{ - EBookListenerResponse *resp; + pthread_cond_signal (&op->cond); - resp = e_book_listener_pop_response (listener); + e_mutex_unlock (op->mutex); +} - if (resp == NULL) - return; - - switch (resp->op) { - case CreateCardResponse: - e_book_do_response_create_card (book, resp); - break; - case RemoveCardResponse: - case ModifyCardResponse: - case AuthenticationResponse: - e_book_do_response_generic (book, resp); - break; - case GetCardResponse: - e_book_do_response_get_vcard (book, resp); - break; - case GetCursorResponse: - e_book_do_response_get_cursor (book, resp); - break; - case GetBookViewResponse: - e_book_do_response_get_view(book, resp); - break; - case GetChangesResponse: - e_book_do_response_get_changes(book, resp); - break; - case OpenBookResponse: - e_book_do_response_open (book, resp); - break; - case GetSupportedFieldsResponse: - e_book_do_response_get_supported_fields (book, resp); - break; - case GetSupportedAuthMethodsResponse: - e_book_do_response_get_supported_auth_methods (book, resp); - break; - - case OpenProgressEvent: - e_book_do_progress_event (book, resp); - break; - case LinkStatusEvent: - e_book_do_link_event (book, resp); - break; - case WritableStatusEvent: - e_book_do_writable_event (book, resp); - break; - default: - g_error ("EBook: Unknown operation %d in listener queue!\n", - resp->op); - } - - g_free (resp); -} + /** - * e_book_load_uri: - */ + * e_book_authenticate_user: + * @book: an #EBook + * @user: a string + * @passwd: a string + * @auth_method: a string + * + * authenticates @user with @passwd, using the auth method + * @auth_method. @auth_method must be one of the authentication + * methods returned using e_book_get_supported_auth_methods. + * + * Return value: a #EBookStatus value. + **/ +gboolean +e_book_authenticate_user (EBook *book, + const char *user, + const char *passwd, + const char *auth_method, + GError **error) +{ + EBookOp *our_op; + EBookStatus status; + CORBA_Environment ev; -typedef struct { - char *uri; - EBookCallback open_response; - gpointer closure; -} EBookLoadURIData; + e_return_error_if_fail (book && E_IS_BOOK (book), E_BOOK_ERROR_INVALID_ARG); + e_return_error_if_fail (user, E_BOOK_ERROR_INVALID_ARG); + e_return_error_if_fail (passwd, E_BOOK_ERROR_INVALID_ARG); + e_return_error_if_fail (auth_method, E_BOOK_ERROR_INVALID_ARG); -static void e_book_load_uri_from_factory (EBook *book, - GNOME_Evolution_Addressbook_BookFactory factory, - EBookLoadURIData *load_uri_data); + e_mutex_lock (book->priv->mutex); -static void -e_book_load_uri_step (EBook *book, EBookStatus status, EBookLoadURIData *data) -{ - /* iterate to the next possible CardFactory, or fail - if it's the last one */ - book->priv->iter = book->priv->iter->next; - if (book->priv->iter) { - GNOME_Evolution_Addressbook_BookFactory factory = book->priv->iter->data; - e_book_load_uri_from_factory (book, factory, data); + if (book->priv->load_state != E_BOOK_URI_LOADED) { + e_mutex_unlock (book->priv->mutex); + g_set_error (error, E_BOOK_ERROR, E_BOOK_ERROR_URI_NOT_LOADED, + _("e_book_authenticate_user on book before e_book_load_uri")); + return FALSE; } - else { - EBookCallback cb = data->open_response; - gpointer closure = data->closure; - - /* reset the load_state to NotLoaded so people can - attempt another load_uri on the book. */ - book->priv->load_state = URINotLoaded; - g_free (data); - - cb (book, status, closure); + if (book->priv->current_op != NULL) { + e_mutex_unlock (book->priv->mutex); + g_set_error (error, E_BOOK_ERROR, E_BOOK_ERROR_BUSY, + _("book busy")); + return FALSE; } -} - -static void -e_book_load_uri_open_cb (EBook *book, EBookStatus status, EBookLoadURIData *data) -{ - if (status == E_BOOK_STATUS_SUCCESS) { - EBookCallback cb = data->open_response; - gpointer closure = data->closure; - g_free (data); + our_op = e_book_new_op (book); - cb (book, status, closure); - } - else { - e_book_load_uri_step (book, status, data); - } -} + e_mutex_lock (our_op->mutex); -static void -e_book_load_uri_from_factory (EBook *book, - GNOME_Evolution_Addressbook_BookFactory factory, - EBookLoadURIData *load_uri_data) -{ - CORBA_Environment ev; + e_mutex_unlock (book->priv->mutex); CORBA_exception_init (&ev); - e_book_queue_op (book, e_book_load_uri_open_cb, load_uri_data, NULL); - - GNOME_Evolution_Addressbook_BookFactory_openBook ( - factory, book->priv->uri, - bonobo_object_corba_objref (BONOBO_OBJECT (book->priv->listener)), - &ev); + /* will eventually end up calling + e_book_response_generic */ + GNOME_Evolution_Addressbook_Book_authenticateUser (book->priv->corba_book, + user, passwd, + auth_method, + &ev); if (ev._major != CORBA_NO_EXCEPTION) { - g_warning ("e_book_load_uri: CORBA exception while opening addressbook!\n"); - e_book_unqueue_op (book); + + e_book_clear_op (book, our_op); + CORBA_exception_free (&ev); - e_book_load_uri_step (book, E_BOOK_STATUS_OTHER_ERROR, load_uri_data); + + g_set_error (error, E_BOOK_ERROR, E_BOOK_ERROR_CORBA_EXCEPTION, + _("Corba exception making Book::authenticateUser call")); + return FALSE; } CORBA_exception_free (&ev); + /* wait for something to happen (both cancellation and a + successful response will notity us via our cv */ + e_mutex_cond_wait (&our_op->cond, our_op->mutex); + + status = our_op->status; + + e_book_clear_op (book, our_op); + + E_BOOK_CHECK_STATUS (status, error); } + -static gboolean -activate_factories_for_uri (EBook *book, const char *uri) +/** + * e_book_get_contact: + * @book: an #EBook + * @id: a string + * @contact: an #EContact + * + * Fills in @contact with the contents of the vcard in @book + * corresponding to @id. + * + * Return value: a #EBookStatus value. + **/ +gboolean +e_book_get_contact (EBook *book, + const char *id, + EContact **contact, + GError **error) { + EBookOp *our_op; + EBookStatus status; CORBA_Environment ev; - Bonobo_ServerInfoList *info_list = NULL; - int i; - char *protocol, *query, *colon; - gboolean retval = FALSE; - colon = strchr (uri, ':'); - if (!colon) { - g_warning ("e_book_load_uri: Unable to determine protocol in the URI\n"); + e_return_error_if_fail (book && E_IS_BOOK (book), E_BOOK_ERROR_INVALID_ARG); + e_return_error_if_fail (id, E_BOOK_ERROR_INVALID_ARG); + e_return_error_if_fail (contact, E_BOOK_ERROR_INVALID_ARG); + + e_mutex_lock (book->priv->mutex); + + if (book->priv->load_state != E_BOOK_URI_LOADED) { + e_mutex_unlock (book->priv->mutex); + g_set_error (error, E_BOOK_ERROR, E_BOOK_ERROR_URI_NOT_LOADED, + _("e_book_get_contact on book before e_book_load_uri")); return FALSE; } - protocol = g_strndup (uri, colon-uri); - query = g_strdup_printf ("repo_ids.has ('IDL:GNOME/Evolution/BookFactory:1.0')" - " AND addressbook:supported_protocols.has ('%s')", protocol - ); + if (book->priv->current_op != NULL) { + e_mutex_unlock (book->priv->mutex); + g_set_error (error, E_BOOK_ERROR, E_BOOK_ERROR_BUSY, + _("book busy")); + return FALSE; + } + + our_op = e_book_new_op (book); + + e_mutex_lock (our_op->mutex); + + e_mutex_unlock (book->priv->mutex); CORBA_exception_init (&ev); - - info_list = bonobo_activation_query (query, NULL, &ev); + + /* will eventually end up calling e_book_response_generic */ + GNOME_Evolution_Addressbook_Book_getContact (book->priv->corba_book, + (const GNOME_Evolution_Addressbook_VCard) id, &ev); if (ev._major != CORBA_NO_EXCEPTION) { - g_warning ("Eeek! Cannot perform bonobo-activation query for book factories."); - CORBA_exception_free (&ev); - goto shutdown; - } - if (info_list->_length == 0) { - g_warning ("Can't find installed BookFactory that handles protocol '%s'.", protocol); + e_book_clear_op (book, our_op); + CORBA_exception_free (&ev); - goto shutdown; + + g_set_error (error, E_BOOK_ERROR, E_BOOK_ERROR_CORBA_EXCEPTION, + _("Corba exception making Book::getContact call")); + return FALSE; } CORBA_exception_free (&ev); - for (i = 0; i < info_list->_length; i ++) { - const Bonobo_ServerInfo *info; - GNOME_Evolution_Addressbook_BookFactory factory; + /* wait for something to happen (both cancellation and a + successful response will notity us via our cv */ + e_mutex_cond_wait (&our_op->cond, our_op->mutex); - info = info_list->_buffer + i; + status = our_op->status; + *contact = our_op->contact; - factory = bonobo_activation_activate_from_id (info->iid, 0, NULL, NULL); + e_book_clear_op (book, our_op); - if (factory == CORBA_OBJECT_NIL) - g_warning ("e_book_construct: Could not obtain a handle " - "to the Personal Addressbook Server with IID `%s'\n", info->iid); - else - book->priv->book_factories = g_list_append (book->priv->book_factories, - factory); - } + E_BOOK_CHECK_STATUS (status, error); +} + +static void +e_book_response_get_contact (EBook *book, + EBookStatus status, + EContact *contact) +{ + EBookOp *op; - if (!book->priv->book_factories) { - g_warning ("Couldn't activate any book factories."); - goto shutdown; + printf ("e_book_response_get_contact\n"); + + op = e_book_get_op (book); + + if (op == NULL) { + g_warning ("e_book_response_get_contact: Cannot find operation "); + return; } - retval = TRUE; + e_mutex_lock (op->mutex); - shutdown: - if (info_list) - CORBA_free (info_list); - g_free (query); - g_free (protocol); + op->status = status; + op->contact = contact; - return retval; + pthread_cond_signal (&op->cond); + + e_mutex_unlock (op->mutex); } -void -e_book_load_uri (EBook *book, - const char *uri, - EBookCallback open_response, - gpointer closure) + +/** + * e_book_remove_contact: + * @book: an #EBook + * @id: a string + * + * Removes the contact with id @id from @book. + * + * Return value: a #EBookStatus value. + **/ +gboolean +e_book_remove_contact (EBook *book, + const char *id, + GError **error) { - EBookLoadURIData *load_uri_data; - GNOME_Evolution_Addressbook_BookFactory factory; + GList *list; + gboolean rv; - g_return_if_fail (book != NULL); - g_return_if_fail (E_IS_BOOK (book)); - g_return_if_fail (uri != NULL); - g_return_if_fail (open_response != NULL); + e_return_error_if_fail (book && E_IS_BOOK (book), E_BOOK_ERROR_INVALID_ARG); + e_return_error_if_fail (id, E_BOOK_ERROR_INVALID_ARG); - if (book->priv->load_state != URINotLoaded) { - g_warning ("e_book_load_uri: Attempted to load a URI " - "on a book which already has a URI loaded!\n"); - open_response (book, E_BOOK_STATUS_OTHER_ERROR, closure); /* XXX need a new status code here */ - return; - } + e_mutex_lock (book->priv->mutex); - /* try to find a list of factories that can handle the protocol */ - if (!activate_factories_for_uri (book, uri)) { - open_response (book, E_BOOK_STATUS_PROTOCOL_NOT_SUPPORTED, closure); - return; + if (book->priv->load_state != E_BOOK_URI_LOADED) { + e_mutex_unlock (book->priv->mutex); + g_set_error (error, E_BOOK_ERROR, E_BOOK_ERROR_URI_NOT_LOADED, + _("e_book_remove_contact on book before e_book_load_uri")); + return FALSE; } - - g_free (book->priv->uri); - book->priv->uri = g_strdup (uri); - /* - * Create our local BookListener interface. - */ - book->priv->listener = e_book_listener_new (); - if (book->priv->listener == NULL) { - g_warning ("e_book_load_uri: Could not create EBookListener!\n"); - open_response (NULL, E_BOOK_STATUS_OTHER_ERROR, closure); /* XXX need a new status code here */ - return; + if (book->priv->current_op != NULL) { + e_mutex_unlock (book->priv->mutex); + g_set_error (error, E_BOOK_ERROR, E_BOOK_ERROR_BUSY, + _("book busy")); + return FALSE; } - book->priv->listener_signal = g_signal_connect (book->priv->listener, "responses_queued", - G_CALLBACK (e_book_check_listener_queue), book); - - load_uri_data = g_new (EBookLoadURIData, 1); - load_uri_data->open_response = open_response; - load_uri_data->closure = closure; + e_mutex_lock (book->priv->mutex); - /* initialize the iterator, and load from the first one*/ - book->priv->iter = book->priv->book_factories; + list = g_list_append (NULL, (char*)id); - factory = book->priv->iter->data; + rv = e_book_remove_contacts (book, list, error); - e_book_load_uri_from_factory (book, factory, load_uri_data); - - book->priv->load_state = URILoading; + return rv; } /** - * e_book_unload_uri: - */ -void -e_book_unload_uri (EBook *book) + * e_book_remove_contacts: + * @book: an #EBook + * @ids: an #GList of const char *id's + * + * Removes the contacts with ids from the list @ids from @book. This is + * always more efficient than calling e_book_remove_contact_by_id if you + * have more than one id to remove, as some backends can implement it + * as a batch request. + * + * Return value: a #EBookStatus value. + **/ +gboolean +e_book_remove_contacts (EBook *book, + GList *ids, + GError **error) { + GNOME_Evolution_Addressbook_ContactIdList idlist; CORBA_Environment ev; + GList *iter; + int num_ids, i; + EBookOp *our_op; + EBookStatus status; - g_return_if_fail (book != NULL); - g_return_if_fail (E_IS_BOOK (book)); + e_return_error_if_fail (book && E_IS_BOOK (book), E_BOOK_ERROR_INVALID_ARG); + e_return_error_if_fail (ids, E_BOOK_ERROR_INVALID_ARG); - /* - * FIXME: Make sure this works if the URI is still being - * loaded. - */ - if (book->priv->load_state != URILoaded) { - g_warning ("e_book_unload_uri: No URI is loaded!\n"); - return; + e_mutex_lock (book->priv->mutex); + + if (book->priv->load_state != E_BOOK_URI_LOADED) { + e_mutex_unlock (book->priv->mutex); + g_set_error (error, E_BOOK_ERROR, E_BOOK_ERROR_URI_NOT_LOADED, + _("e_book_remove_contacts on book before e_book_load_uri")); + return FALSE; } - /* - * Release the remote GNOME_Evolution_Addressbook_Book in the PAS. - */ + if (book->priv->current_op != NULL) { + e_mutex_unlock (book->priv->mutex); + g_set_error (error, E_BOOK_ERROR, E_BOOK_ERROR_BUSY, + _("book busy")); + return FALSE; + } + + our_op = e_book_new_op (book); + + e_mutex_lock (our_op->mutex); + + e_mutex_unlock (book->priv->mutex); + CORBA_exception_init (&ev); - bonobo_object_release_unref (book->priv->corba_book, &ev); + num_ids = g_list_length (ids); + idlist._buffer = CORBA_sequence_GNOME_Evolution_Addressbook_ContactId_allocbuf (num_ids); + idlist._maximum = num_ids; + idlist._length = num_ids; + + for (iter = ids, i = 0; iter; iter = iter->next) + idlist._buffer[i++] = CORBA_string_dup (iter->data); + + /* will eventually end up calling e_book_response_generic */ + GNOME_Evolution_Addressbook_Book_removeContacts (book->priv->corba_book, &idlist, &ev); + + CORBA_free(idlist._buffer); + if (ev._major != CORBA_NO_EXCEPTION) { - g_warning ("e_book_unload_uri: Exception releasing " - "remote book interface!\n"); - } + e_book_clear_op (book, our_op); + + CORBA_exception_free (&ev); + + g_set_error (error, E_BOOK_ERROR, E_BOOK_ERROR_CORBA_EXCEPTION, + _("Corba exception making Book::removeContacts call")); + return FALSE; + } + CORBA_exception_free (&ev); - e_book_listener_stop (book->priv->listener); - bonobo_object_unref (BONOBO_OBJECT (book->priv->listener)); + /* wait for something to happen (both cancellation and a + successful response will notity us via our cv */ + e_mutex_cond_wait (&our_op->cond, our_op->mutex); - book->priv->listener = NULL; - book->priv->load_state = URINotLoaded; -} + status = our_op->status; -const char * -e_book_get_uri (EBook *book) -{ - g_return_val_if_fail (book && E_IS_BOOK (book), NULL); + e_book_clear_op (book, our_op); - return book->priv->uri; + E_BOOK_CHECK_STATUS (status, error); } -char * -e_book_get_static_capabilities (EBook *book) + +/** + * e_book_get_book_view: + * @book: an #EBook + * @query: an #EBookQuery + * @requested_fields a #GList containing the names of fields to return, or NULL for all + * @max_results the maximum number of contacts to show (or 0 for all) + * + * need docs here.. + * + * Return value: a #EBookStatus value. + **/ +gboolean +e_book_get_book_view (EBook *book, + EBookQuery *query, + GList *requested_fields, + int max_results, + EBookView **book_view, + GError **error) { - if (!book->priv->cap_queried) { - CORBA_Environment ev; - char *temp; + GNOME_Evolution_Addressbook_stringlist stringlist; + CORBA_Environment ev; + EBookOp *our_op; + EBookStatus status; + int num_fields, i; + GList *iter; + char *query_string; - CORBA_exception_init (&ev); + e_return_error_if_fail (book && E_IS_BOOK (book), E_BOOK_ERROR_INVALID_ARG); + e_return_error_if_fail (query, E_BOOK_ERROR_INVALID_ARG); + e_return_error_if_fail (book_view, E_BOOK_ERROR_INVALID_ARG); - if (book->priv->load_state != URILoaded) { - g_warning ("e_book_unload_uri: No URI is loaded!\n"); - return g_strdup(""); - } + e_mutex_lock (book->priv->mutex); - temp = GNOME_Evolution_Addressbook_Book_getStaticCapabilities(book->priv->corba_book, &ev); + if (book->priv->load_state != E_BOOK_URI_LOADED) { + e_mutex_unlock (book->priv->mutex); + g_set_error (error, E_BOOK_ERROR, E_BOOK_ERROR_URI_NOT_LOADED, + _("e_book_get_book_view on book before e_book_load_uri")); + return FALSE; + } - if (ev._major != CORBA_NO_EXCEPTION) { - g_warning ("e_book_get_static_capabilities: Exception " - "during get_static_capabilities!\n"); - CORBA_exception_free (&ev); - return g_strdup(""); - } + if (book->priv->current_op != NULL) { + e_mutex_unlock (book->priv->mutex); + g_set_error (error, E_BOOK_ERROR, E_BOOK_ERROR_BUSY, + _("book busy")); + return FALSE; + } - book->priv->cap = g_strdup(temp); - book->priv->cap_queried = TRUE; + our_op = e_book_new_op (book); - CORBA_free(temp); + e_mutex_lock (our_op->mutex); + + e_mutex_unlock (book->priv->mutex); + + CORBA_exception_init (&ev); + + our_op->listener = e_book_view_listener_new(); + + num_fields = g_list_length (requested_fields); + + stringlist._buffer = CORBA_sequence_CORBA_string_allocbuf (num_fields); + stringlist._maximum = num_fields; + stringlist._length = num_fields; + + for (i = 0, iter = requested_fields; iter; iter = iter->next, i ++) { + stringlist._buffer[i] = CORBA_string_dup ((char*)iter->data); + } + + query_string = e_book_query_to_string (query); + + /* will eventually end up calling e_book_response_get_book_view */ + GNOME_Evolution_Addressbook_Book_getBookView (book->priv->corba_book, + bonobo_object_corba_objref(BONOBO_OBJECT(our_op->listener)), + query_string, + &stringlist, max_results, &ev); + + CORBA_free(stringlist._buffer); + g_free (query_string); + + if (ev._major != CORBA_NO_EXCEPTION) { + + e_book_clear_op (book, our_op); CORBA_exception_free (&ev); + + g_warning ("corba exception._major = %d\n", ev._major); + + g_set_error (error, E_BOOK_ERROR, E_BOOK_ERROR_CORBA_EXCEPTION, + _("Corba exception making Book::getBookView call")); + return FALSE; } + + CORBA_exception_free (&ev); + + /* wait for something to happen (both cancellation and a + successful response will notity us via our cv */ + e_mutex_cond_wait (&our_op->cond, our_op->mutex); - return g_strdup (book->priv->cap); + status = our_op->status; + *book_view = our_op->view; + + e_book_clear_op (book, our_op); + + E_BOOK_CHECK_STATUS (status, error); } -gboolean -e_book_check_static_capability (EBook *book, const char *cap) +static void +e_book_response_get_book_view (EBook *book, + EBookStatus status, + GNOME_Evolution_Addressbook_BookView corba_book_view) { - gboolean rv = FALSE; - char *caps = e_book_get_static_capabilities (book); - if (!caps) - return FALSE; - /* XXX this is an inexact test but it works for our use */ - if (strstr (caps, cap)) - rv = TRUE; + EBookOp *op; - g_free (caps); + printf ("e_book_response_get_book_view\n"); - return rv; + op = e_book_get_op (book); + + if (op == NULL) { + g_warning ("e_book_response_get_book_view: Cannot find operation "); + return; + } + + e_mutex_lock (op->mutex); + + op->status = status; + op->view = e_book_view_new (corba_book_view, op->listener); + + pthread_cond_signal (&op->cond); + + e_mutex_unlock (op->mutex); } -guint -e_book_get_supported_fields (EBook *book, - EBookFieldsCallback cb, - gpointer closure) + + +/** + * e_book_get_contacts: + * @book: an #EBook + * @query: an #EBookQuery + * + * need docs here.. + * + * Return value: a #EBookStatus value. + **/ +gboolean +e_book_get_contacts (EBook *book, + EBookQuery *query, + GList **contacts, + GError **error) { CORBA_Environment ev; - guint tag; + EBookOp *our_op; + EBookStatus status; + char *query_string; - CORBA_exception_init (&ev); + e_return_error_if_fail (book && E_IS_BOOK (book), E_BOOK_ERROR_INVALID_ARG); + e_return_error_if_fail (query, E_BOOK_ERROR_INVALID_ARG); + e_return_error_if_fail (contacts, E_BOOK_ERROR_INVALID_ARG); + + e_mutex_lock (book->priv->mutex); - if (book->priv->load_state != URILoaded) { - g_warning ("e_book_unload_uri: No URI is loaded!\n"); - return 0; + if (book->priv->load_state != E_BOOK_URI_LOADED) { + e_mutex_unlock (book->priv->mutex); + g_set_error (error, E_BOOK_ERROR, E_BOOK_ERROR_URI_NOT_LOADED, + _("e_book_get_contacts on book before e_book_load_uri")); + return FALSE; } - tag = e_book_queue_op (book, cb, closure, NULL); + if (book->priv->current_op != NULL) { + e_mutex_unlock (book->priv->mutex); + g_set_error (error, E_BOOK_ERROR, E_BOOK_ERROR_BUSY, + _("book busy")); + return FALSE; + } - GNOME_Evolution_Addressbook_Book_getSupportedFields(book->priv->corba_book, &ev); + our_op = e_book_new_op (book); + + e_mutex_lock (our_op->mutex); + + e_mutex_unlock (book->priv->mutex); + + CORBA_exception_init (&ev); + + query_string = e_book_query_to_string (query); + + /* will eventually end up calling e_book_response_get_contacts */ + GNOME_Evolution_Addressbook_Book_getContactList (book->priv->corba_book, query_string, &ev); + + g_free (query_string); if (ev._major != CORBA_NO_EXCEPTION) { - g_warning ("e_book_get_supported_fields: Exception " - "during get_supported_fields!\n"); + + e_book_clear_op (book, our_op); + CORBA_exception_free (&ev); - e_book_unqueue_op (book); - return 0; - } + g_warning ("corba exception._major = %d\n", ev._major); + + g_set_error (error, E_BOOK_ERROR, E_BOOK_ERROR_CORBA_EXCEPTION, + _("Corba exception making Book::getContactList call")); + return FALSE; + } + CORBA_exception_free (&ev); - return tag; + /* wait for something to happen (both cancellation and a + successful response will notity us via our cv */ + e_mutex_cond_wait (&our_op->cond, our_op->mutex); + + status = our_op->status; + *contacts = our_op->list; + + e_book_clear_op (book, our_op); + + E_BOOK_CHECK_STATUS (status, error); } -guint -e_book_get_supported_auth_methods (EBook *book, - EBookAuthMethodsCallback cb, - gpointer closure) +static void +e_book_response_get_contacts (EBook *book, + EBookStatus status, + GList *contact_list) +{ + + EBookOp *op; + + op = e_book_get_op (book); + + if (op == NULL) { + g_warning ("e_book_response_get_contacts: Cannot find operation "); + return; + } + + e_mutex_lock (op->mutex); + + op->status = status; + op->list = contact_list; + + pthread_cond_signal (&op->cond); + + e_mutex_unlock (op->mutex); +} + + +gboolean +e_book_get_changes (EBook *book, + char *changeid, + GList **changes, + GError **error) { CORBA_Environment ev; - guint tag; + EBookOp *our_op; + EBookStatus status; - CORBA_exception_init (&ev); + e_return_error_if_fail (book && E_IS_BOOK (book), E_BOOK_ERROR_INVALID_ARG); + e_return_error_if_fail (changeid, E_BOOK_ERROR_INVALID_ARG); + e_return_error_if_fail (changes, E_BOOK_ERROR_INVALID_ARG); + + e_mutex_lock (book->priv->mutex); - if (book->priv->load_state != URILoaded) { - g_warning ("e_book_unload_uri: No URI is loaded!\n"); - return 0; + if (book->priv->load_state != E_BOOK_URI_LOADED) { + e_mutex_unlock (book->priv->mutex); + g_set_error (error, E_BOOK_ERROR, E_BOOK_ERROR_URI_NOT_LOADED, + _("e_book_get_changes on book before e_book_load_uri")); + return FALSE; } - tag = e_book_queue_op (book, cb, closure, NULL); + if (book->priv->current_op != NULL) { + e_mutex_unlock (book->priv->mutex); + g_set_error (error, E_BOOK_ERROR, E_BOOK_ERROR_BUSY, + _("book busy")); + return FALSE; + } - GNOME_Evolution_Addressbook_Book_getSupportedAuthMethods(book->priv->corba_book, &ev); + our_op = e_book_new_op (book); + + e_mutex_lock (our_op->mutex); + + e_mutex_unlock (book->priv->mutex); + + CORBA_exception_init (&ev); + + /* will eventually end up calling e_book_response_get_changes */ + GNOME_Evolution_Addressbook_Book_getChanges (book->priv->corba_book, changeid, &ev); if (ev._major != CORBA_NO_EXCEPTION) { - g_warning ("e_book_get_supported_auth_methods: Exception " - "during get_supported_auth_methods!\n"); + + e_book_clear_op (book, our_op); + CORBA_exception_free (&ev); - e_book_unqueue_op (book); - return 0; - } + g_warning ("corba exception._major = %d\n", ev._major); + + g_set_error (error, E_BOOK_ERROR, E_BOOK_ERROR_CORBA_EXCEPTION, + _("Corba exception making Book::getChanges call")); + return FALSE; + } + CORBA_exception_free (&ev); - return tag; -} + /* wait for something to happen (both cancellation and a + successful response will notity us via our cv */ + e_mutex_cond_wait (&our_op->cond, our_op->mutex); -static gboolean -e_book_construct (EBook *book) -{ - g_return_val_if_fail (book != NULL, FALSE); - g_return_val_if_fail (E_IS_BOOK (book), FALSE); + status = our_op->status; + *changes = our_op->list; - book->priv->book_factories = NULL; + e_book_clear_op (book, our_op); - return TRUE; + E_BOOK_CHECK_STATUS (status, error); } -/** - * e_book_new: - */ -EBook * -e_book_new (void) +static void +e_book_response_get_changes (EBook *book, + EBookStatus status, + GList *change_list) { - EBook *book; - book = g_object_new (E_TYPE_BOOK, NULL); + EBookOp *op; - if (! e_book_construct (book)) { - g_object_unref (book); - return NULL; + op = e_book_get_op (book); + + if (op == NULL) { + g_warning ("e_book_response_get_contacts: Cannot find operation "); + return; } - return book; -} + e_mutex_lock (op->mutex); + + op->status = status; + op->list = change_list; -/* User authentication. */ + pthread_cond_signal (&op->cond); + + e_mutex_unlock (op->mutex); +} void -e_book_authenticate_user (EBook *book, - const char *user, - const char *passwd, - const char *auth_method, - EBookCallback cb, - gpointer closure) +e_book_free_change_list (GList *change_list) { - CORBA_Environment ev; - - g_return_if_fail (book != NULL); - g_return_if_fail (E_IS_BOOK (book)); + GList *l; + for (l = change_list; l; l = l->next) { + EBookChange *change = l->data; - if (book->priv->load_state != URILoaded) { - g_warning ("e_book_authenticate_user: No URI loaded!\n"); - return; + g_free (change->vcard); + g_free (change); } - CORBA_exception_init (&ev); + g_list_free (change_list); +} - e_book_queue_op (book, cb, closure, NULL); + - GNOME_Evolution_Addressbook_Book_authenticateUser (book->priv->corba_book, - user, - passwd, - auth_method, - &ev); +static void +e_book_response_generic (EBook *book, + EBookStatus status) +{ + EBookOp *op; - if (ev._major != CORBA_NO_EXCEPTION) { - g_warning ("e_book_authenticate_user: Exception authenticating user with the PAS!\n"); - CORBA_exception_free (&ev); - e_book_unqueue_op (book); - return; + op = e_book_get_op (book); + + if (op == NULL) { + g_warning ("e_book_response_generic: Cannot find operation "); + return; } - CORBA_exception_free (&ev); -} + e_mutex_lock (op->mutex); + + op->status = status; -/* Fetching cards */ + pthread_cond_signal (&op->cond); + + e_mutex_unlock (op->mutex); +} /** - * e_book_get_card: - */ -guint -e_book_get_card (EBook *book, - const char *id, - EBookCardCallback cb, - gpointer closure) + * e_book_cancel: + * @book: an #EBook + * + * Used to cancel an already running operation on @book. This + * function makes a synchronous CORBA to the backend telling it to + * cancel the operation. If the operation wasn't cancellable (either + * transiently or permanently) or had already comopleted on the wombat + * side, this function will return E_BOOK_STATUS_COULD_NOT_CANCEL, and + * the operation will continue uncancelled. If the operation could be + * cancelled, this function will return E_BOOK_ERROR_OK, and the + * blocked e_book function corresponding to current operation will + * return with a status of E_BOOK_STATUS_CANCELLED. + * + * Return value: a #EBookStatus value. + **/ +gboolean +e_book_cancel (EBook *book, + GError **error) { + EBookOp *op; + EBookStatus status; + gboolean rv; CORBA_Environment ev; - guint tag; - g_return_val_if_fail (book != NULL, 0); - g_return_val_if_fail (E_IS_BOOK (book), 0); + e_mutex_lock (book->priv->mutex); - if (book->priv->load_state != URILoaded) { - g_warning ("e_book_get_card: No URI loaded!\n"); - return 0; + if (book->priv->current_op == NULL) { + e_mutex_unlock (book->priv->mutex); + g_set_error (error, E_BOOK_ERROR, E_BOOK_ERROR_COULD_NOT_CANCEL, + _("e_book_cancel: there is no current operation")); + return FALSE; } - CORBA_exception_init (&ev); + op = book->priv->current_op; + + e_mutex_lock (op->mutex); - tag = e_book_queue_op (book, cb, closure, NULL); + e_mutex_unlock (book->priv->mutex); - GNOME_Evolution_Addressbook_Book_getVCard (book->priv->corba_book, (const GNOME_Evolution_Addressbook_VCard) id, &ev); + status = GNOME_Evolution_Addressbook_Book_cancelOperation(book->priv->corba_book, &ev); if (ev._major != CORBA_NO_EXCEPTION) { - g_warning ("e_book_get_card: Exception " - "getting card!\n"); + + e_mutex_unlock (op->mutex); + CORBA_exception_free (&ev); - e_book_unqueue_op (book); - return 0; + + g_set_error (error, E_BOOK_ERROR, E_BOOK_ERROR_CORBA_EXCEPTION, + _("Corba exception making Book::cancelOperation call")); + return FALSE; } CORBA_exception_free (&ev); - return tag; + if (status == E_BOOK_ERROR_OK) { + op->status = E_BOOK_ERROR_CANCELLED; + + pthread_cond_signal (&op->cond); + + rv = TRUE; + } + else { + g_set_error (error, E_BOOK_ERROR, E_BOOK_ERROR_COULD_NOT_CANCEL, + _("e_book_cancel: couldn't cancel")); + rv = FALSE; + } + + e_mutex_unlock (op->mutex); + + return rv; } -/* Deleting cards. */ +static void +e_book_response_open (EBook *book, + EBookStatus status) +{ + EBookOp *op; + + op = e_book_get_op (book); + + if (op == NULL) { + g_warning ("e_book_response_open: Cannot find operation "); + return; + } + + e_mutex_lock (op->mutex); + + op->status = status; + + pthread_cond_signal (&op->cond); + + e_mutex_unlock (op->mutex); +} + + -/** - * e_book_remove_card: - */ gboolean -e_book_remove_card (EBook *book, - ECard *card, - EBookCallback cb, - gpointer closure) +e_book_remove (EBook *book, + GError **error) { - const char *id; + CORBA_Environment ev; + EBookOp *our_op; + EBookStatus status; + + e_return_error_if_fail (book && E_IS_BOOK (book), E_BOOK_ERROR_INVALID_ARG); - g_return_val_if_fail (book != NULL, FALSE); - g_return_val_if_fail (E_IS_BOOK (book), FALSE); - g_return_val_if_fail (card != NULL, FALSE); - g_return_val_if_fail (E_IS_CARD (card), FALSE); + e_mutex_lock (book->priv->mutex); - if (book->priv->load_state != URILoaded) { - g_warning ("e_book_remove_card: No URI loaded!\n"); + if (book->priv->load_state != E_BOOK_URI_LOADED) { + e_mutex_unlock (book->priv->mutex); + g_set_error (error, E_BOOK_ERROR, E_BOOK_ERROR_URI_NOT_LOADED, + _("e_book_remove on book before e_book_load_uri")); return FALSE; } - id = e_card_get_id (card); - g_assert (id != NULL); + if (book->priv->current_op != NULL) { + e_mutex_unlock (book->priv->mutex); + g_set_error (error, E_BOOK_ERROR, E_BOOK_ERROR_BUSY, + _("book busy")); + return FALSE; + } - return e_book_remove_card_by_id (book, id, cb, closure); -} + our_op = e_book_new_op (book); -/** - * e_book_remove_card_by_id: - */ -gboolean -e_book_remove_card_by_id (EBook *book, - const char *id, - EBookCallback cb, - gpointer closure) + e_mutex_lock (our_op->mutex); -{ - GList *list = NULL; - gboolean rv; + e_mutex_unlock (book->priv->mutex); - list = g_list_prepend (list, (char*)id); - - rv = e_book_remove_cards (book, list, cb, closure); + CORBA_exception_init (&ev); - g_list_free (list); + /* will eventually end up calling e_book_response_remove */ + GNOME_Evolution_Addressbook_Book_remove (book->priv->corba_book, &ev); - return rv; + if (ev._major != CORBA_NO_EXCEPTION) { + + e_book_clear_op (book, our_op); + + CORBA_exception_free (&ev); + + g_set_error (error, E_BOOK_ERROR, E_BOOK_ERROR_CORBA_EXCEPTION, + _("Corba exception making Book::remove call")); + return FALSE; + } + + CORBA_exception_free (&ev); + + /* wait for something to happen (both cancellation and a + successful response will notity us via our cv */ + e_mutex_cond_wait (&our_op->cond, our_op->mutex); + + status = our_op->status; + + e_book_clear_op (book, our_op); + + E_BOOK_CHECK_STATUS (status, error); } -gboolean -e_book_remove_cards (EBook *book, - GList *ids, - EBookCallback cb, - gpointer closure) +static void +e_book_response_remove (EBook *book, + EBookStatus status) { - GNOME_Evolution_Addressbook_CardIdList idlist; - CORBA_Environment ev; - GList *l; - int num_ids, i; + EBookOp *op; - g_return_val_if_fail (book != NULL, FALSE); - g_return_val_if_fail (E_IS_BOOK (book), FALSE); - g_return_val_if_fail (ids != NULL, FALSE); + printf ("e_book_response_remove\n"); - if (book->priv->load_state != URILoaded) { - g_warning ("e_book_remove_card_by_id: No URI loaded!\n"); - return FALSE; + op = e_book_get_op (book); + + if (op == NULL) { + g_warning ("e_book_response_remove: Cannot find operation "); + return; } - CORBA_exception_init (&ev); + e_mutex_lock (op->mutex); - e_book_queue_op (book, cb, closure, NULL); + op->status = status; - num_ids = g_list_length (ids); - idlist._buffer = CORBA_sequence_GNOME_Evolution_Addressbook_CardId_allocbuf (num_ids); - idlist._maximum = num_ids; - idlist._length = num_ids; + pthread_cond_signal (&op->cond); + + e_mutex_unlock (op->mutex); +} + + - for (l = ids, i = 0; l; l=l->next, i ++) { - idlist._buffer[i] = CORBA_string_dup (l->data); +static void +e_book_handle_response (EBookListener *listener, EBookListenerResponse *resp, EBook *book) +{ + switch (resp->op) { + case CreateContactResponse: + e_book_response_add_contact (book, resp->status, resp->id); + break; + case RemoveContactResponse: + case ModifyContactResponse: + case AuthenticationResponse: + e_book_response_generic (book, resp->status); + break; + case GetContactResponse: { + EContact *contact = e_contact_new_from_vcard (resp->vcard); + e_book_response_get_contact (book, resp->status, contact); + break; } + case GetContactListResponse: + e_book_response_get_contacts (book, resp->status, resp->list); + break; + case GetBookViewResponse: + e_book_response_get_book_view(book, resp->status, resp->book_view); + break; + case GetChangesResponse: + e_book_response_get_changes(book, resp->status, resp->list); + break; + case OpenBookResponse: + e_book_response_open (book, resp->status); + break; + case RemoveBookResponse: + e_book_response_remove (book, resp->status); + break; + case GetSupportedFieldsResponse: + e_book_response_get_supported_fields (book, resp->status, resp->list); + break; + case GetSupportedAuthMethodsResponse: + e_book_response_get_supported_auth_methods (book, resp->status, resp->list); + break; + case WritableStatusEvent: + book->priv->writable = resp->writable; + g_signal_emit (book, e_book_signals [WRITABLE_STATUS], 0, resp->writable); + break; + default: + g_error ("EBook: Unknown response code %d!\n", + resp->op); + } +} + + + +gboolean +e_book_unload_uri (EBook *book, + GError **error) +{ + CORBA_Environment ev; - GNOME_Evolution_Addressbook_Book_removeCards (book->priv->corba_book, &idlist, &ev); + e_return_error_if_fail (book && E_IS_BOOK (book), E_BOOK_ERROR_INVALID_ARG); + e_return_error_if_fail (book->priv->load_state != E_BOOK_URI_NOT_LOADED, E_BOOK_ERROR_URI_NOT_LOADED); + /* Release the remote GNOME_Evolution_Addressbook_Book in the PAS. */ + CORBA_exception_init (&ev); + + bonobo_object_release_unref (book->priv->corba_book, &ev); if (ev._major != CORBA_NO_EXCEPTION) { - g_warning ("e_book_remove_card_by_id: CORBA exception " - "talking to PAS!\n"); - CORBA_exception_free (&ev); - e_book_unqueue_op (book); - return FALSE; + g_warning ("e_book_unload_uri: Exception releasing " + "remote book interface!\n"); } - + CORBA_exception_free (&ev); - CORBA_free(idlist._buffer); + e_book_listener_stop (book->priv->listener); + bonobo_object_unref (BONOBO_OBJECT (book->priv->listener)); + + book->priv->listener = NULL; + book->priv->load_state = E_BOOK_URI_NOT_LOADED; + g_free (book->priv->cap); + book->priv->cap = NULL; + book->priv->writable = FALSE; return TRUE; } - -/* Adding cards. */ + /** - * e_book_add_card: + * e_book_load_uri: */ -gboolean -e_book_add_card (EBook *book, - ECard *card, - EBookIdCallback cb, - gpointer closure) +static void +backend_died_cb (EComponentListener *cl, gpointer user_data) { - char *vcard; - gboolean retval; + EBook *book = user_data; + + book->priv->load_state = E_BOOK_URI_NOT_LOADED; + g_signal_emit (book, e_book_signals [BACKEND_DIED], 0); +} - g_return_val_if_fail (book != NULL, FALSE); - g_return_val_if_fail (E_IS_BOOK (book), FALSE); - g_return_val_if_fail (card != NULL, FALSE); - g_return_val_if_fail (E_IS_CARD (card), FALSE); +static GList * +activate_factories_for_uri (EBook *book, const char *uri) +{ + CORBA_Environment ev; + Bonobo_ServerInfoList *info_list = NULL; + int i; + char *protocol, *query, *colon; + GList *factories = NULL; - if (book->priv->load_state != URILoaded) { - g_warning ("e_book_add_card: No URI loaded!\n"); + colon = strchr (uri, ':'); + if (!colon) { + g_warning ("e_book_load_uri: Unable to determine protocol in the URI\n"); return FALSE; } - vcard = e_card_get_vcard_assume_utf8 (card); + protocol = g_strndup (uri, colon-uri); + query = g_strdup_printf ("repo_ids.has ('IDL:GNOME/Evolution/BookFactory:1.0')" + " AND addressbook:supported_protocols.has ('%s')", protocol + ); - if (vcard == NULL) { - g_warning ("e_book_add_card: Cannot convert card to VCard string!\n"); - return FALSE; + CORBA_exception_init (&ev); + + info_list = bonobo_activation_query (query, NULL, &ev); + + if (ev._major != CORBA_NO_EXCEPTION) { + g_warning ("Eeek! Cannot perform bonobo-activation query for book factories."); + CORBA_exception_free (&ev); + goto done; + return NULL; + } + + if (info_list->_length == 0) { + g_warning ("Can't find installed BookFactory that handles protocol '%s'.", protocol); + CORBA_exception_free (&ev); + goto done; } - retval = e_book_add_vcard (book, vcard, cb, closure); + CORBA_exception_free (&ev); + + for (i = 0; i < info_list->_length; i ++) { + const Bonobo_ServerInfo *info; + GNOME_Evolution_Addressbook_BookFactory factory; + + info = info_list->_buffer + i; + + factory = bonobo_activation_activate_from_id (info->iid, 0, NULL, NULL); - g_free (vcard); + if (factory == CORBA_OBJECT_NIL) + g_warning ("e_book_construct: Could not obtain a handle " + "to the Personal Addressbook Server with IID `%s'\n", info->iid); + else + factories = g_list_append (factories, factory); + } - e_card_set_book (card, book); + done: + if (info_list) + CORBA_free (info_list); + g_free (query); + g_free (protocol); - return retval; + return factories; } -/** - * e_book_add_vcard: - */ gboolean -e_book_add_vcard (EBook *book, - const char *vcard, - EBookIdCallback cb, - gpointer closure) +e_book_load_uri (EBook *book, + const char *uri, + gboolean only_if_exists, + GError **error) { - CORBA_Environment ev; + GList *factories; + GList *l; + gboolean rv = FALSE; + GNOME_Evolution_Addressbook_Book corba_book = CORBA_OBJECT_NIL; + + e_return_error_if_fail (book && E_IS_BOOK (book), E_BOOK_ERROR_INVALID_ARG); + e_return_error_if_fail (uri, E_BOOK_ERROR_INVALID_ARG); - g_return_val_if_fail (book != NULL, FALSE); - g_return_val_if_fail (E_IS_BOOK (book), FALSE); - g_return_val_if_fail (vcard != NULL, FALSE); + /* XXX this needs to happen while holding the book's lock i would think... */ + e_return_error_if_fail (book->priv->load_state == E_BOOK_URI_NOT_LOADED, E_BOOK_ERROR_URI_ALREADY_LOADED); - if (book->priv->load_state != URILoaded) { - g_warning ("e_book_add_vcard: No URI loaded!\n"); + /* try to find a list of factories that can handle the protocol */ + if (! (factories = activate_factories_for_uri (book, uri))) { + g_set_error (error, E_BOOK_ERROR, E_BOOK_ERROR_PROTOCOL_NOT_SUPPORTED, + _("e_book_load_uri: no factories available for uri `%s'"), uri); return FALSE; } - CORBA_exception_init (&ev); - - e_book_queue_op (book, (EBookCallback) cb, closure, NULL); - GNOME_Evolution_Addressbook_Book_addCard ( - book->priv->corba_book, (const GNOME_Evolution_Addressbook_VCard) vcard, &ev); + book->priv->load_state = E_BOOK_URI_LOADING; - if (ev._major != CORBA_NO_EXCEPTION) { - g_warning ("e_book_add_vcard: Exception adding card to PAS!\n"); - CORBA_exception_free (&ev); - e_book_unqueue_op (book); + /* + * Create our local BookListener interface. + */ + book->priv->listener = e_book_listener_new (); + if (book->priv->listener == NULL) { + g_warning ("e_book_load_uri: Could not create EBookListener!\n"); + g_set_error (error, E_BOOK_ERROR, E_BOOK_ERROR_OTHER_ERROR, + _("e_book_load_uri: Could not create EBookListener")); return FALSE; } + book->priv->listener_signal = g_signal_connect (book->priv->listener, "response", + G_CALLBACK (e_book_handle_response), book); - CORBA_exception_free (&ev); + g_free (book->priv->uri); + book->priv->uri = g_strdup (uri); - return TRUE; -} + for (l = factories; l; l = l->next) { + GNOME_Evolution_Addressbook_BookFactory factory = l->data; + EBookOp *our_op; + CORBA_Environment ev; + EBookStatus status; -/* Modifying cards. */ + our_op = e_book_new_op (book); -/** - * e_book_commit_card: - */ -gboolean -e_book_commit_card (EBook *book, - ECard *card, - EBookCallback cb, - gpointer closure) -{ - char *vcard; - gboolean retval; - - g_return_val_if_fail (book != NULL, FALSE); - g_return_val_if_fail (E_IS_BOOK (book), FALSE); - g_return_val_if_fail (card != NULL, FALSE); - g_return_val_if_fail (E_IS_CARD (card), FALSE); + e_mutex_lock (our_op->mutex); - if (book->priv->load_state != URILoaded) { - g_warning ("e_book_commit_card: No URI loaded!\n"); - return FALSE; - } + CORBA_exception_init (&ev); - vcard = e_card_get_vcard_assume_utf8 (card); + corba_book = GNOME_Evolution_Addressbook_BookFactory_getBook (factory, book->priv->uri, + bonobo_object_corba_objref (BONOBO_OBJECT (book->priv->listener)), + &ev); - if (vcard == NULL) { - g_warning ("e_book_commit_card: Error " - "getting VCard for card!\n"); - return FALSE; - } + if (ev._major != CORBA_NO_EXCEPTION) { - retval = e_book_commit_vcard (book, vcard, cb, closure); + e_book_clear_op (book, our_op); - g_free (vcard); + CORBA_exception_free (&ev); + continue; + } - e_card_set_book (card, book); + GNOME_Evolution_Addressbook_Book_open (corba_book, + only_if_exists, + &ev); - return retval; -} + if (ev._major != CORBA_NO_EXCEPTION) { + /* kill the listener so the book will die */ + g_signal_handler_disconnect (book->priv->listener, book->priv->listener_signal); + bonobo_object_unref (book->priv->listener); + book->priv->listener = NULL; -/** - * e_book_commit_vcard: - */ -gboolean -e_book_commit_vcard (EBook *book, - const char *vcard, - EBookCallback cb, - gpointer closure) -{ - CORBA_Environment ev; + e_book_clear_op (book, our_op); - g_return_val_if_fail (book != NULL, FALSE); - g_return_val_if_fail (E_IS_BOOK (book), FALSE); - g_return_val_if_fail (vcard != NULL, FALSE); + CORBA_exception_free (&ev); + continue; + } - if (book->priv->load_state != URILoaded) { - g_warning ("e_book_commit_vcard: No URI loaded!\n"); - return FALSE; - } + CORBA_exception_free (&ev); - CORBA_exception_init (&ev); + /* wait for something to happen (both cancellation and a + successful response will notity us via our cv */ + e_mutex_cond_wait (&our_op->cond, our_op->mutex); - e_book_queue_op (book, cb, closure, NULL); + status = our_op->status; - GNOME_Evolution_Addressbook_Book_modifyCard ( - book->priv->corba_book, (const GNOME_Evolution_Addressbook_VCard) vcard, &ev); + /* remove the op from the book's hash of operations */ + e_book_clear_op (book, our_op); - if (ev._major != CORBA_NO_EXCEPTION) { - g_warning ("e_book_commit_vcard: Exception " - "modifying card in PAS!\n"); - CORBA_exception_free (&ev); - e_book_unqueue_op (book); - return FALSE; + if (status == E_BOOK_ERROR_CANCELLED + || status == E_BOOK_ERROR_OK) { + rv = TRUE; + break; + } } - CORBA_exception_free (&ev); + /* free up the factories */ + for (l = factories; l; l = l->next) + CORBA_Object_release ((CORBA_Object)l->data, NULL); - return TRUE; + if (rv == TRUE) { + book->priv->corba_book = corba_book; + book->priv->load_state = E_BOOK_URI_LOADED; + book->priv->comp_listener = e_component_listener_new (book->priv->corba_book); + book->priv->died_signal = g_signal_connect (book->priv->comp_listener, "component_died", + G_CALLBACK (backend_died_cb), book); + return TRUE; + } + else { + g_set_error (error, E_BOOK_ERROR, E_BOOK_ERROR_PROTOCOL_NOT_SUPPORTED, + _("e_book_load_uri: no factories available for uri `%s'"), uri); + return FALSE; + } + + return rv; } -/** - * e_book_check_connection: - */ gboolean -e_book_check_connection (EBook *book) +e_book_load_local_addressbook (EBook *book, + GError **error) { - CORBA_Environment ev; - - g_return_val_if_fail (book != NULL, FALSE); - g_return_val_if_fail (E_IS_BOOK (book), FALSE); - - if (book->priv->load_state != URILoaded) { - g_warning ("e_book_check_connection: No URI loaded!\n"); - return FALSE; - } - - CORBA_exception_init (&ev); + char *filename; + char *uri; + gboolean rv; - GNOME_Evolution_Addressbook_Book_checkConnection (book->priv->corba_book, &ev); + filename = g_build_filename (g_get_home_dir(), + "evolution/local/Contacts", + NULL); + uri = g_strdup_printf ("file://%s", filename); - if (ev._major != CORBA_NO_EXCEPTION) { - g_warning ("e_book_check_connection: Exception " - "querying the PAS!\n"); - CORBA_exception_free (&ev); - return FALSE; - } + g_free (filename); - CORBA_exception_free (&ev); + rv = e_book_load_uri (book, uri, TRUE, error); + + g_free (uri); - return TRUE; + return rv; } -guint -e_book_get_cursor (EBook *book, - gchar *query, - EBookCursorCallback cb, - gpointer closure) +const char * +e_book_get_uri (EBook *book) { - CORBA_Environment ev; - 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_check_connection: No URI loaded!\n"); - return 0; - } - - CORBA_exception_init (&ev); + return book->priv->uri; +} - tag = e_book_queue_op (book, cb, closure, NULL); - - GNOME_Evolution_Addressbook_Book_getCursor (book->priv->corba_book, query, &ev); +const char * +e_book_get_static_capabilities (EBook *book, + GError **error) +{ + if (!book->priv->cap_queried) { + CORBA_Environment ev; + char *temp; - if (ev._major != CORBA_NO_EXCEPTION) { - g_warning ("e_book_get_all_cards: Exception " - "querying list of cards!\n"); - CORBA_exception_free (&ev); - e_book_unqueue_op (book); - return 0; - } - - CORBA_exception_free (&ev); + CORBA_exception_init (&ev); - return tag; -} + if (book->priv->load_state != E_BOOK_URI_LOADED) { + g_warning ("e_book_unload_uri: No URI is loaded!\n"); + return g_strdup(""); + } -guint -e_book_get_book_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); + temp = GNOME_Evolution_Addressbook_Book_getStaticCapabilities(book->priv->corba_book, &ev); - if (book->priv->load_state != URILoaded) { - g_warning ("e_book_get_book_view: No URI loaded!\n"); - return 0; - } + if (ev._major != CORBA_NO_EXCEPTION) { + g_warning ("e_book_get_static_capabilities: Exception " + "during get_static_capabilities!\n"); + CORBA_exception_free (&ev); + return g_strdup(""); + } - listener = e_book_view_listener_new(); - - CORBA_exception_init (&ev); + book->priv->cap = g_strdup(temp); + book->priv->cap_queried = TRUE; - tag = e_book_queue_op (book, cb, closure, listener); - - GNOME_Evolution_Addressbook_Book_getBookView (book->priv->corba_book, bonobo_object_corba_objref(BONOBO_OBJECT(listener)), query, &ev); + CORBA_free(temp); - if (ev._major != CORBA_NO_EXCEPTION) { - g_warning ("e_book_get_book_view: Exception " - "getting book_view!\n"); CORBA_exception_free (&ev); - e_book_unqueue_op (book); - return 0; } - - CORBA_exception_free (&ev); - return tag; + return book->priv->cap; } -guint -e_book_get_completion_view (EBook *book, - const gchar *query, - EBookBookViewCallback cb, - gpointer closure) +gboolean +e_book_check_static_capability (EBook *book, + const char *cap) { - 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); + const char *caps = e_book_get_static_capabilities (book, NULL); - if (book->priv->load_state != URILoaded) { - g_warning ("e_book_get_completion_view: No URI loaded!\n"); - return 0; - } + /* XXX this is an inexact test but it works for our use */ + if (caps && strstr (caps, cap)) + return TRUE; - listener = e_book_view_listener_new(); - - CORBA_exception_init (&ev); + return FALSE; +} - 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); +gboolean +e_book_is_writable (EBook *book) +{ + return book->priv->writable; +} - 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, - EBookBookViewCallback cb, - gpointer closure) +gboolean +e_book_get_self (EContact **contact, EBook **book, GError **error) { - 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); + GError *e = NULL; - if (book->priv->load_state != URILoaded) { - g_warning ("e_book_get_changes: No URI loaded!\n"); + if (!e_book_get_default_addressbook (book, &e)) { + g_propagate_error (error, e); return FALSE; } - listener = e_book_view_listener_new(); - - CORBA_exception_init (&ev); +#if notyet + EBook *b; + char *self_uri, *self_uid; - tag = e_book_queue_op (book, cb, closure, listener); - - GNOME_Evolution_Addressbook_Book_getChanges (book->priv->corba_book, bonobo_object_corba_objref(BONOBO_OBJECT(listener)), changeid, &ev); + /* XXX get the setting for the self book and self uid from gconf */ - if (ev._major != CORBA_NO_EXCEPTION) { - g_warning ("e_book_changes: Exception " - "getting changes!\n"); - CORBA_exception_free (&ev); - e_book_unqueue_op (book); - return 0; + b = e_book_new(); + if (! e_book_load_uri (b, self_uri, TRUE, error)) { + g_object_unref (b); + return FALSE; } - - CORBA_exception_free (&ev); - return tag; -} + if (! e_book_get_contact (b, self_uid, + contact, error)) { + g_object_unref (b); + return FALSE; + } -/** - * e_book_cancel - */ + if (book) + *book = b; + else + g_object_unref (b); + return TRUE; +#endif +} -void -e_book_cancel (EBook *book, guint tag) +gboolean +e_book_set_self (EBook *book, const char *id, GError **error) { - g_return_if_fail (book != NULL); - g_return_if_fail (E_IS_BOOK (book)); - g_return_if_fail (tag != 0); - - /* In an attempt to be useful, we take a bit of extra care in reporting - errors. This might come in handy someday. */ - if (tag >= book->priv->op_tag) - g_warning ("Attempt to cancel unassigned operation (%u)", tag); - else if (! e_book_cancel_op (book, tag)) - g_warning ("Attempt to cancel unknown operation (%u)", tag); } -/** - * e_book_get_name: - */ -char * -e_book_get_name (EBook *book) + + +gboolean +e_book_get_default_addressbook (EBook **book, GError **error) { - CORBA_Environment ev; - char *retval; - char *name; + /* XXX for now just load the local ~/evolution/local/Contacts */ + char *path, *uri; + gboolean rv; - g_return_val_if_fail (book != NULL, NULL); - g_return_val_if_fail (E_IS_BOOK (book), NULL); + *book = e_book_new (); - if (book->priv->load_state != URILoaded) { - g_warning ("e_book_get_name: No URI loaded!\n"); - return NULL; - } + path = g_build_filename (g_get_home_dir (), + "evolution/local/Contacts", + NULL); + uri = g_strdup_printf ("file://%s", path); + g_free (path); - CORBA_exception_init (&ev); + rv = e_book_load_uri (*book, uri, FALSE, error); - name = GNOME_Evolution_Addressbook_Book_getName (book->priv->corba_book, &ev); + g_free (uri); - if (ev._major != CORBA_NO_EXCEPTION) { - g_warning ("e_book_get_name: Exception getting name from PAS!\n"); - CORBA_exception_free (&ev); - return NULL; + if (!rv) { + g_object_unref (*book); + *book = NULL; } - CORBA_exception_free (&ev); + return rv; +#if notyet + EConfigListener *listener = e_config_listener_new (); + ESourceList *sources = ...; + ESource *default_source; + + default_source = e_source_list_peek_source_by_uid (sources, + "default_"); +#endif +} - if (name == NULL) { - g_warning ("e_book_get_name: Got NULL name from PAS!\n"); - return NULL; +#if notyet +ESourceList* +e_book_get_addressbooks (GError **error) +{ +} +#endif + + +static void* +startup_mainloop (void *arg) +{ + bonobo_main(); + return NULL; +} + +/* one-time start up for libebook */ +static void +e_book_activate() +{ + static GStaticMutex e_book_lock = G_STATIC_MUTEX_INIT; + static gboolean activated = FALSE; + + g_static_mutex_lock (&e_book_lock); + if (!activated) { + pthread_t ebook_mainloop_thread; + activated = TRUE; + pthread_create(&ebook_mainloop_thread, NULL, startup_mainloop, NULL); } + g_static_mutex_unlock (&e_book_lock); +} - retval = g_strdup (name); - CORBA_free (name); + - return retval; +EBook* +e_book_new (void) +{ + e_book_activate (); + return g_object_new (E_TYPE_BOOK, NULL); } + static void e_book_init (EBook *book) { book->priv = g_new0 (EBookPrivate, 1); - book->priv->load_state = URINotLoaded; - book->priv->op_tag = 1; + book->priv->load_state = E_BOOK_URI_NOT_LOADED; book->priv->uri = NULL; + book->priv->mutex = e_mutex_new (E_MUTEX_REC); } static void @@ -1598,8 +1967,8 @@ e_book_dispose (GObject *object) book->priv->comp_listener = NULL; } - if (book->priv->load_state == URILoaded) - e_book_unload_uri (book); + if (book->priv->load_state == E_BOOK_URI_LOADED) + e_book_unload_uri (book, NULL); CORBA_exception_init (&ev); @@ -1640,16 +2009,6 @@ e_book_class_init (EBookClass *klass) parent_class = g_type_class_ref (G_TYPE_OBJECT); - e_book_signals [LINK_STATUS] = - g_signal_new ("link_status", - G_OBJECT_CLASS_TYPE (object_class), - G_SIGNAL_RUN_LAST, - G_STRUCT_OFFSET (EBookClass, link_status), - NULL, NULL, - e_book_marshal_NONE__BOOL, - G_TYPE_NONE, 1, - G_TYPE_BOOLEAN); - e_book_signals [WRITABLE_STATUS] = g_signal_new ("writable_status", G_OBJECT_CLASS_TYPE (object_class), diff --git a/addressbook/backend/ebook/e-book.h b/addressbook/backend/ebook/e-book.h index d2c5a7bce4..1d2a4dc2d4 100644 --- a/addressbook/backend/ebook/e-book.h +++ b/addressbook/backend/ebook/e-book.h @@ -3,9 +3,9 @@ * The Evolution addressbook client object. * * Author: - * Nat Friedman (nat@ximian.com) + * Chris Toshok (toshok@ximian.com) * - * Copyright 1999, 2000, Ximian, Inc. + * Copyright (C) 1999-2003, Ximian, Inc. */ #ifndef __E_BOOK_H__ @@ -14,10 +14,13 @@ #include #include -#include -#include +#include +#include #include #include +#if notyet +#include +#endif #define E_TYPE_BOOK (e_book_get_type ()) #define E_BOOK(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), E_TYPE_BOOK, EBook)) @@ -43,127 +46,120 @@ struct _EBookClass { /* * Signals. */ - void (* open_progress) (EBook *book, const char *msg, short percent); - void (* link_status) (EBook *book, gboolean connected); void (* writable_status) (EBook *book, gboolean writable); void (* backend_died) (EBook *book); -}; -/* Callbacks for asynchronous functions. */ -typedef void (*EBookCallback) (EBook *book, EBookStatus status, gpointer closure); -typedef void (*EBookOpenProgressCallback) (EBook *book, - const char *status_message, - short percent, - gpointer closure); -typedef void (*EBookIdCallback) (EBook *book, EBookStatus status, const char *id, gpointer closure); -typedef void (*EBookCardCallback) (EBook *book, EBookStatus status, ECard *card, gpointer closure); -typedef void (*EBookCursorCallback) (EBook *book, EBookStatus status, ECardCursor *cursor, gpointer closure); -typedef void (*EBookBookViewCallback) (EBook *book, EBookStatus status, EBookView *book_view, gpointer closure); -typedef void (*EBookFieldsCallback) (EBook *book, EBookStatus status, EList *fields, gpointer closure); -typedef void (*EBookAuthMethodsCallback) (EBook *book, EBookStatus status, EList *auth_methods, gpointer closure); + /* Padding for future expansion */ + void (*_ebook_reserved0) (void); + void (*_ebook_reserved1) (void); + void (*_ebook_reserved2) (void); + void (*_ebook_reserved3) (void); + void (*_ebook_reserved4) (void); +}; /* Creating a new addressbook. */ -EBook *e_book_new (void); +EBook *e_book_new (void); + +/* loading arbitrary addressbooks */ +gboolean e_book_load_uri (EBook *book, + const char *uri, + gboolean only_if_exists, + GError **error); -void e_book_load_uri (EBook *book, - const char *uri, - EBookCallback open_response, - gpointer closure); -void e_book_unload_uri (EBook *book); +gboolean e_book_unload_uri (EBook *book, + GError **error); -const char *e_book_get_uri (EBook *book); +gboolean e_book_remove (EBook *book, + GError **error); -char *e_book_get_static_capabilities (EBook *book); -gboolean e_book_check_static_capability (EBook *book, const char *cap); +/* convenience function for loading the "local" contact folder */ +gboolean e_book_load_local_addressbook (EBook *book, + GError **error); -guint e_book_get_supported_fields (EBook *book, - EBookFieldsCallback cb, - gpointer closure); +gboolean e_book_get_supported_fields (EBook *book, + GList **fields, + GError **error); -guint e_book_get_supported_auth_methods (EBook *book, - EBookAuthMethodsCallback cb, - gpointer closure); +gboolean e_book_get_supported_auth_methods (EBook *book, + GList **auth_methods, + GError **error); /* User authentication. */ -void e_book_authenticate_user (EBook *book, - const char *user, - const char *passwd, - const char *auth_method, - EBookCallback cb, - gpointer closure); - -/* Fetching cards. */ -guint e_book_get_card (EBook *book, - const char *id, - EBookCardCallback cb, - gpointer closure); - -/* Deleting cards. */ -gboolean e_book_remove_card (EBook *book, - ECard *card, - EBookCallback cb, - gpointer closure); -gboolean e_book_remove_card_by_id (EBook *book, - const char *id, - EBookCallback cb, - gpointer closure); - -gboolean e_book_remove_cards (EBook *book, - GList *id_list, - EBookCallback cb, - gpointer closure); - -/* Adding cards. */ -gboolean e_book_add_card (EBook *book, - ECard *card, - EBookIdCallback cb, - gpointer closure); -gboolean e_book_add_vcard (EBook *book, - const char *vcard, - EBookIdCallback cb, - gpointer closure); - -/* Modifying cards. */ -gboolean e_book_commit_card (EBook *book, - ECard *card, - EBookCallback cb, - gpointer closure); -gboolean e_book_commit_vcard (EBook *book, - const char *vcard, - EBookCallback cb, - gpointer closure); - -/* Checking to see if we're connected to the card repository. */ -gboolean e_book_check_connection (EBook *book); -guint e_book_get_cursor (EBook *book, - char *query, - EBookCursorCallback cb, - gpointer closure); - -guint e_book_get_book_view (EBook *book, - const gchar *query, - 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, - gpointer closure); +gboolean e_book_authenticate_user (EBook *book, + const char *user, + const char *passwd, + const char *auth_method, + GError **error); + +/* Fetching contacts. */ +gboolean e_book_get_contact (EBook *book, + const char *id, + EContact **contact, + GError **error); + +/* Deleting contacts. */ +gboolean e_book_remove_contact (EBook *book, + const char *id, + GError **error); + +gboolean e_book_remove_contacts (EBook *book, + GList *id_list, + GError **error); + +/* Adding contacts. */ +gboolean e_book_add_contact (EBook *book, + EContact *contact, + GError **error); + +/* Modifying contacts. */ +gboolean e_book_commit_contact (EBook *book, + EContact *contact, + GError **error); + +/* Returns a live view of a query. */ +gboolean e_book_get_book_view (EBook *book, + EBookQuery *query, + GList *requested_fields, + int max_results, + EBookView **book_view, + GError **error); + +/* Returns a static snapshot of a query. */ +gboolean e_book_get_contacts (EBook *book, + EBookQuery *query, + GList **contacts, + GError **error); + +gboolean e_book_get_changes (EBook *book, + char *changeid, + GList **changes, + GError **error); + +void e_book_free_change_list (GList *change_list); + +const char *e_book_get_uri (EBook *book); + +const char *e_book_get_static_capabilities (EBook *book, + GError **error); +gboolean e_book_check_static_capability (EBook *book, + const char *cap); +gboolean e_book_is_writable (EBook *book); /* Cancel a pending operation. */ -void e_book_cancel (EBook *book, - guint tag); +gboolean e_book_cancel (EBook *book, + GError **error); +/* Identity */ +gboolean e_book_get_self (EContact **contact, EBook **book, GError **error); +gboolean e_book_set_self (EBook *book, const char *id, GError **error); -/* Getting the name of the repository. */ -char *e_book_get_name (EBook *book); +/* Addressbook Discovery */ +gboolean e_book_get_default_addressbook (EBook **book, GError **error); +#if notyet +gboolean e_book_get_addressbooks (ESourceList** addressbook_sources, GError **error); +#endif -GType e_book_get_type (void); +GType e_book_get_type (void); G_END_DECLS diff --git a/addressbook/backend/ebook/e-card-compare.c b/addressbook/backend/ebook/e-card-compare.c deleted file mode 100644 index 2413d987e5..0000000000 --- a/addressbook/backend/ebook/e-card-compare.c +++ /dev/null @@ -1,706 +0,0 @@ -/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ - -/* - * e-card-compare.c - * - * Copyright (C) 2001 Ximian, Inc. - * - * Developed by Jon Trowbridge - */ - -/* - * This program is free software; you can redistribute it and/or - * modify it under the terms of version 2 of the GNU General Public - * License as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - * USA. - */ - -#include -#include -#include -#include "e-book-util.h" -#include "e-card-compare.h" - -/* This is an "optimistic" combiner: the best of the two outcomes is - selected. */ -static ECardMatchType -combine_comparisons (ECardMatchType prev, - ECardMatchType new_info) -{ - if (new_info == E_CARD_MATCH_NOT_APPLICABLE) - return prev; - return (ECardMatchType) MAX ((gint) prev, (gint) new_info); -} - - -/*** Name comparisons ***/ - -/* This *so* doesn't belong here... at least not implemented in a - sucky way like this. But it can be fixed later. */ - -/* This is very Anglocentric. */ -static gchar *name_synonyms[][2] = { - { "jon", "john" }, /* Ah, the hacker's perogative */ - { "joseph", "joe" }, - { "robert", "bob" }, - { "gene", "jean" }, - { "jesse", "jessie" }, - { "ian", "iain" }, - { "richard", "dick" }, - { "william", "bill" }, - { "william", "will" }, - { "anthony", "tony" }, - { "michael", "mike" }, - { "eric", "erik" }, - { "elizabeth", "liz" }, - { "jeff", "geoff" }, - { "jeff", "geoffrey" }, - { "tom", "thomas" }, - { "dave", "david" }, - { "jim", "james" }, - { "abigal", "abby" }, - { "amanda", "amy" }, - { "amanda", "manda" }, - { "jennifer", "jenny" }, - { "christopher", "chris" }, - { "rebecca", "becca" }, - { "rebecca", "becky" }, - { "anderson", "andersen" }, - { "johnson", "johnsen" }, - /* We could go on and on... */ - /* We should add soundex here. */ - { NULL, NULL } -}; - -static gboolean -name_fragment_match (const gchar *a, const gchar *b, gboolean strict) -{ - gint len; - - if (!(a && b && *a && *b)) - return FALSE; - - /* If we are in 'strict' mode, b must match the beginning of a. - So "Robert", "Rob" would match, but "Robert", "Robbie" wouldn't. - - If strict is FALSE, it is sufficient for the strings to share - some leading characters. In this case, "Robert" and "Robbie" - would match, as would "Dave" and "Dan". */ - - if (strict) { - len = g_utf8_strlen (b, -1); - } else { - len = MIN (g_utf8_strlen (a, -1), g_utf8_strlen (b, -1)); - } - - return !e_utf8_casefold_collate_len (a, b, len); -} - -static gboolean -name_fragment_match_with_synonyms (const gchar *a, const gchar *b, gboolean strict) -{ - gint i; - - if (!(a && b && *a && *b)) - return FALSE; - - if (name_fragment_match (a, b, strict)) - return TRUE; - - /* Check for nicknames. Yes, the linear search blows. */ - for (i=0; name_synonyms[i][0]; ++i) { - - if (!e_utf8_casefold_collate (name_synonyms[i][0], a) - && !e_utf8_casefold_collate (name_synonyms[i][1], b)) - return TRUE; - - if (!e_utf8_casefold_collate (name_synonyms[i][0], b) - && !e_utf8_casefold_collate (name_synonyms[i][1], a)) - return TRUE; - } - - return FALSE; -} - -ECardMatchType -e_card_compare_name_to_string (ECard *card, const gchar *str) -{ - return e_card_compare_name_to_string_full (card, str, FALSE, NULL, NULL, NULL); -} - -ECardMatchType -e_card_compare_name_to_string_full (ECard *card, const gchar *str, gboolean allow_partial_matches, - gint *matched_parts_out, ECardMatchPart *first_matched_part_out, gint *matched_character_count_out) -{ - gchar **namev, **givenv = NULL, **addv = NULL, **familyv = NULL; - - gint matched_parts = E_CARD_MATCH_PART_NONE; - ECardMatchPart first_matched_part = E_CARD_MATCH_PART_NONE; - ECardMatchPart this_part_match = E_CARD_MATCH_PART_NOT_APPLICABLE; - ECardMatchType match_type; - - gint match_count = 0, matched_character_count = 0, fragment_count; - gint i, j; - gchar *str_cpy, *s; - - g_return_val_if_fail (E_IS_CARD (card), E_CARD_MATCH_NOT_APPLICABLE); - g_return_val_if_fail (card->name != NULL, E_CARD_MATCH_NOT_APPLICABLE); - g_return_val_if_fail (str != NULL, E_CARD_MATCH_NOT_APPLICABLE); - - str_cpy = s = g_strdup (str); - while (*s) { - if (*s == ',' || *s == '"') - *s = ' '; - ++s; - } - namev = g_strsplit (str_cpy, " ", 0); - g_free (str_cpy); - - if (card->name->given) - givenv = g_strsplit (card->name->given, " ", 0); - if (card->name->additional) - addv = g_strsplit (card->name->additional, " ", 0); - if (card->name->family) - familyv = g_strsplit (card->name->family, " ", 0); - - fragment_count = 0; - for (i = 0; givenv && givenv[i]; ++i) - ++fragment_count; - for (i = 0; addv && addv[i]; ++i) - ++fragment_count; - for (i = 0; familyv && familyv[i]; ++i) - ++fragment_count; - - for (i = 0; namev[i] && this_part_match != E_CARD_MATCH_PART_NONE; ++i) { - - if (*namev[i]) { - - this_part_match = E_CARD_MATCH_PART_NONE; - - /* When we are allowing partials, we are strict about the matches we allow. - Does this make sense? Not really, but it does the right thing for the purposes - of completion. */ - - if (givenv && this_part_match == E_CARD_MATCH_PART_NONE) { - for (j = 0; givenv[j]; ++j) { - if (name_fragment_match_with_synonyms (givenv[j], namev[i], allow_partial_matches)) { - - this_part_match = E_CARD_MATCH_PART_GIVEN_NAME; - - /* We remove a piece of a name once it has been matched against, so - that "john john" won't match "john doe". */ - g_free (givenv[j]); - givenv[j] = g_strdup (""); - break; - } - } - } - - if (addv && this_part_match == E_CARD_MATCH_PART_NONE) { - for (j = 0; addv[j]; ++j) { - if (name_fragment_match_with_synonyms (addv[j], namev[i], allow_partial_matches)) { - - this_part_match = E_CARD_MATCH_PART_ADDITIONAL_NAME; - - g_free (addv[j]); - addv[j] = g_strdup (""); - break; - } - } - } - - if (familyv && this_part_match == E_CARD_MATCH_PART_NONE) { - for (j = 0; familyv[j]; ++j) { - if (allow_partial_matches ? name_fragment_match_with_synonyms (familyv[j], namev[i], allow_partial_matches) - : !e_utf8_casefold_collate (familyv[j], namev[i])) { - - this_part_match = E_CARD_MATCH_PART_FAMILY_NAME; - - g_free (familyv[j]); - familyv[j] = g_strdup (""); - break; - } - } - } - - if (this_part_match != E_CARD_MATCH_PART_NONE) { - ++match_count; - matched_character_count += g_utf8_strlen (namev[i], -1); - matched_parts |= this_part_match; - if (first_matched_part == E_CARD_MATCH_PART_NONE) - first_matched_part = this_part_match; - } - } - } - - match_type = E_CARD_MATCH_NONE; - - if (this_part_match != E_CARD_MATCH_PART_NONE) { - - if (match_count > 0) - match_type = E_CARD_MATCH_VAGUE; - - if (fragment_count == match_count) { - - match_type = E_CARD_MATCH_EXACT; - - } else if (fragment_count == match_count + 1) { - - match_type = E_CARD_MATCH_PARTIAL; - - } - } - - if (matched_parts_out) - *matched_parts_out = matched_parts; - if (first_matched_part_out) - *first_matched_part_out = first_matched_part; - if (matched_character_count_out) - *matched_character_count_out = matched_character_count; - - g_strfreev (namev); - g_strfreev (givenv); - g_strfreev (addv); - g_strfreev (familyv); - - return match_type; -} - -ECardMatchType -e_card_compare_name (ECard *card1, ECard *card2) -{ - ECardName *a, *b; - gint matches=0, possible=0; - gboolean given_match = FALSE, additional_match = FALSE, family_match = FALSE; - - g_return_val_if_fail (E_IS_CARD (card1), E_CARD_MATCH_NOT_APPLICABLE); - g_return_val_if_fail (E_IS_CARD (card2), E_CARD_MATCH_NOT_APPLICABLE); - - a = card1->name; - b = card2->name; - - if (a == NULL || b == NULL) - return E_CARD_MATCH_NOT_APPLICABLE; - - if (a->given && b->given) { - ++possible; - if (name_fragment_match_with_synonyms (a->given, b->given, FALSE /* both inputs are complete */)) { - ++matches; - given_match = TRUE; - } - } - - if (a->additional && b->additional) { - ++possible; - if (name_fragment_match_with_synonyms (a->additional, b->additional, FALSE /* both inputs are complete */)) { - ++matches; - additional_match = TRUE; - } - } - - if (a->family && b->family) { - ++possible; - /* We don't allow "loose matching" (i.e. John vs. Jon) on family names */ - if (! e_utf8_casefold_collate (a->family, b->family)) { - ++matches; - family_match = TRUE; - } - } - - /* Now look at the # of matches and try to intelligently map - an E_CARD_MATCH_* type to it. Special consideration is given - to family-name matches. */ - - if (possible == 0) - return E_CARD_MATCH_NOT_APPLICABLE; - - if (possible == 1) - return family_match ? E_CARD_MATCH_VAGUE : E_CARD_MATCH_NONE; - - if (possible == matches) - return family_match ? E_CARD_MATCH_EXACT : E_CARD_MATCH_PARTIAL; - - if (possible == matches+1) - return family_match ? E_CARD_MATCH_VAGUE : E_CARD_MATCH_NONE; - - return E_CARD_MATCH_NONE; -} - - -/*** Nickname Comparisons ***/ - -ECardMatchType -e_card_compare_nickname (ECard *card1, ECard *card2) -{ - g_return_val_if_fail (card1 && E_IS_CARD (card1), E_CARD_MATCH_NOT_APPLICABLE); - g_return_val_if_fail (card2 && E_IS_CARD (card2), E_CARD_MATCH_NOT_APPLICABLE); - - return E_CARD_MATCH_NOT_APPLICABLE; -} - - - -/*** E-mail Comparisons ***/ - -static gboolean -match_email_username (const gchar *addr1, const gchar *addr2) -{ - gint c1, c2; - if (addr1 == NULL || addr2 == NULL) - return FALSE; - - while (*addr1 && *addr2 && *addr1 != '@' && *addr2 != '@') { - c1 = isupper (*addr1) ? tolower (*addr1) : *addr1; - c2 = isupper (*addr2) ? tolower (*addr2) : *addr2; - if (c1 != c2) - return FALSE; - ++addr1; - ++addr2; - } - - return *addr1 == *addr2; -} - -static gboolean -match_email_hostname (const gchar *addr1, const gchar *addr2) -{ - gint c1, c2; - gboolean seen_at1, seen_at2; - if (addr1 == NULL || addr2 == NULL) - return FALSE; - - /* Walk to the end of each string. */ - seen_at1 = FALSE; - if (*addr1) { - while (*addr1) { - if (*addr1 == '@') - seen_at1 = TRUE; - ++addr1; - } - --addr1; - } - - seen_at2 = FALSE; - if (*addr2) { - while (*addr2) { - if (*addr2 == '@') - seen_at2 = TRUE; - ++addr2; - } - --addr2; - } - - if (!seen_at1 && !seen_at2) - return TRUE; - if (!seen_at1 || !seen_at2) - return FALSE; - - while (*addr1 != '@' && *addr2 != '@') { - c1 = isupper (*addr1) ? tolower (*addr1) : *addr1; - c2 = isupper (*addr2) ? tolower (*addr2) : *addr2; - if (c1 != c2) - return FALSE; - --addr1; - --addr2; - } - - /* This will match bob@foo.ximian.com and bob@ximian.com */ - return *addr1 == '.' || *addr2 == '.'; -} - -static ECardMatchType -compare_email_addresses (const gchar *addr1, const gchar *addr2) -{ - if (addr1 == NULL || *addr1 == 0 || - addr2 == NULL || *addr2 == 0) - return E_CARD_MATCH_NOT_APPLICABLE; - - if (match_email_username (addr1, addr2)) - return match_email_hostname (addr1, addr2) ? E_CARD_MATCH_EXACT : E_CARD_MATCH_VAGUE; - - return E_CARD_MATCH_NONE; -} - -ECardMatchType -e_card_compare_email (ECard *card1, ECard *card2) -{ - EIterator *i1, *i2; - ECardMatchType match = E_CARD_MATCH_NOT_APPLICABLE; - - g_return_val_if_fail (card1 && E_IS_CARD (card1), E_CARD_MATCH_NOT_APPLICABLE); - g_return_val_if_fail (card2 && E_IS_CARD (card2), E_CARD_MATCH_NOT_APPLICABLE); - - if (card1->email == NULL || card2->email == NULL) - return E_CARD_MATCH_NOT_APPLICABLE; - - i1 = e_list_get_iterator (card1->email); - i2 = e_list_get_iterator (card2->email); - - /* Do pairwise-comparisons on all of the e-mail addresses. If - we find an exact match, there is no reason to keep - checking. */ - e_iterator_reset (i1); - while (e_iterator_is_valid (i1) && match != E_CARD_MATCH_EXACT) { - const gchar *addr1 = (const gchar *) e_iterator_get (i1); - - e_iterator_reset (i2); - while (e_iterator_is_valid (i2) && match != E_CARD_MATCH_EXACT) { - const gchar *addr2 = (const gchar *) e_iterator_get (i2); - - match = combine_comparisons (match, compare_email_addresses (addr1, addr2)); - - e_iterator_next (i2); - } - - e_iterator_next (i1); - } - - g_object_unref (i1); - g_object_unref (i2); - - return match; -} - -ECardMatchType -e_card_compare_address (ECard *card1, ECard *card2) -{ - g_return_val_if_fail (card1 && E_IS_CARD (card1), E_CARD_MATCH_NOT_APPLICABLE); - g_return_val_if_fail (card2 && E_IS_CARD (card2), E_CARD_MATCH_NOT_APPLICABLE); - - /* Unimplemented */ - - return E_CARD_MATCH_NOT_APPLICABLE; -} - -ECardMatchType -e_card_compare_telephone (ECard *card1, ECard *card2) -{ - g_return_val_if_fail (card1 && E_IS_CARD (card1), E_CARD_MATCH_NOT_APPLICABLE); - g_return_val_if_fail (card2 && E_IS_CARD (card2), E_CARD_MATCH_NOT_APPLICABLE); - - /* Unimplemented */ - - return E_CARD_MATCH_NOT_APPLICABLE; -} - -ECardMatchType -e_card_compare (ECard *card1, ECard *card2) -{ - ECardMatchType result; - - g_return_val_if_fail (card1 && E_IS_CARD (card1), E_CARD_MATCH_NOT_APPLICABLE); - g_return_val_if_fail (card2 && E_IS_CARD (card2), E_CARD_MATCH_NOT_APPLICABLE); - - result = E_CARD_MATCH_NONE; - result = combine_comparisons (result, e_card_compare_name (card1, card2)); - result = combine_comparisons (result, e_card_compare_nickname (card1, card2)); - result = combine_comparisons (result, e_card_compare_email (card1, card2)); - result = combine_comparisons (result, e_card_compare_address (card1, card2)); - result = combine_comparisons (result, e_card_compare_telephone (card1, card2)); - - return result; -} - -typedef struct _MatchSearchInfo MatchSearchInfo; -struct _MatchSearchInfo { - ECard *card; - GList *avoid; - ECardMatchQueryCallback cb; - gpointer closure; -}; - -static void -match_search_info_free (MatchSearchInfo *info) -{ - if (info) { - g_object_unref (info->card); - - /* This should already have been deallocated, but just in case... */ - if (info->avoid) { - g_list_foreach (info->avoid, (GFunc) g_object_unref, NULL); - g_list_free (info->avoid); - info->avoid = NULL; - } - - g_free (info); - } -} - -static void -simple_query_cb (EBook *book, EBookSimpleQueryStatus status, const GList *cards, gpointer closure) -{ - MatchSearchInfo *info = (MatchSearchInfo *) closure; - ECardMatchType best_match = E_CARD_MATCH_NONE; - ECard *best_card = NULL; - GList *remaining_cards = NULL; - const GList *i; - - if (status != E_BOOK_SIMPLE_QUERY_STATUS_SUCCESS) { - info->cb (info->card, NULL, E_CARD_MATCH_NONE, info->closure); - match_search_info_free (info); - return; - } - - /* remove the cards we're to avoid from the list, if they're present */ - for (i = cards; i != NULL; i = g_list_next (i)) { - ECard *this_card = E_CARD (i->data); - GList *iterator; - gboolean avoid = FALSE; - for (iterator = info->avoid; iterator; iterator = iterator->next) { - if (!strcmp (e_card_get_id (iterator->data), e_card_get_id (this_card))) { - avoid = TRUE; - break; - } - } - if (!avoid) - remaining_cards = g_list_prepend (remaining_cards, this_card); - } - - remaining_cards = g_list_reverse (remaining_cards); - - for (i = remaining_cards; i != NULL; i = g_list_next (i)) { - ECard *this_card = E_CARD (i->data); - ECardMatchType this_match = e_card_compare (info->card, this_card); - if ((gint)this_match > (gint)best_match) { - best_match = this_match; - best_card = this_card; - } - } - - g_list_free (remaining_cards); - - info->cb (info->card, best_card, best_match, info->closure); - match_search_info_free (info); -} - -#define MAX_QUERY_PARTS 10 -static void -use_common_book_cb (EBook *book, gpointer closure) -{ - MatchSearchInfo *info = (MatchSearchInfo *) closure; - ECard *card = info->card; - gchar *query_parts[MAX_QUERY_PARTS]; - gint p=0; - gchar *query, *qj; - int i; - - if (book == NULL) { - info->cb (info->card, NULL, E_CARD_MATCH_NONE, info->closure); - match_search_info_free (info); - return; - } - -#if 0 - if (card->nickname && *card->nickname) - query_parts[p++] = g_strdup_printf ("(beginswith \"nickname\" \"%s\")", card->nickname); -#endif - - if (card->name->given && strlen (card->name->given) > 1) - query_parts[p++] = g_strdup_printf ("(contains \"full_name\" \"%s\")", card->name->given); - - if (card->name->additional && strlen (card->name->additional) > 1) - query_parts[p++] = g_strdup_printf ("(contains \"full_name\" \"%s\")", card->name->additional); - - if (card->name->family && strlen (card->name->family) > 1) - query_parts[p++] = g_strdup_printf ("(contains \"full_name\" \"%s\")", card->name->family); - - - if (card->email) { - EIterator *iter = e_list_get_iterator (card->email); - while (e_iterator_is_valid (iter) && p < MAX_QUERY_PARTS) { - gchar *addr = g_strdup (e_iterator_get (iter)); - if (addr && *addr) { - gchar *s = addr; - while (*s) { - if (*s == '@') { - *s = '\0'; - break; - } - ++s; - } - query_parts[p++] = g_strdup_printf ("(beginswith \"email\" \"%s\")", addr); - g_free (addr); - } - e_iterator_next (iter); - } - } - - - - /* Build up our full query from the parts. */ - query_parts[p] = NULL; - qj = g_strjoinv (" ", query_parts); - for(i = 0; query_parts[i] != NULL; i++) - g_free(query_parts[i]); - if (p > 0) { - query = g_strdup_printf ("(or %s)", qj); - g_free (qj); - } else { - query = qj; - } - - e_book_simple_query (book, query, simple_query_cb, info); - - g_free (query); -} - -void -e_card_locate_match (ECard *card, ECardMatchQueryCallback cb, gpointer closure) -{ - MatchSearchInfo *info; - - g_return_if_fail (card && E_IS_CARD (card)); - g_return_if_fail (cb != NULL); - - info = g_new (MatchSearchInfo, 1); - info->card = card; - g_object_ref (card); - info->cb = cb; - info->closure = closure; - info->avoid = NULL; - - e_book_use_default_book (use_common_book_cb, info); -} - -/** - * e_card_locate_match_full: - * @book: The book to look in. If this is NULL, use the default - * addressbook. - * @card: The card to compare to. - * @avoid: A list of cards to not match. These will not show up in the search. - * @cb: The function to call. - * @closure: The closure to add to the call. - * - * Look for the best match and return it using the ECardMatchQueryCallback. - **/ -void -e_card_locate_match_full (EBook *book, ECard *card, GList *avoid, ECardMatchQueryCallback cb, gpointer closure) -{ - MatchSearchInfo *info; - - g_return_if_fail (card && E_IS_CARD (card)); - g_return_if_fail (cb != NULL); - - info = g_new (MatchSearchInfo, 1); - info->card = card; - g_object_ref (card); - info->cb = cb; - info->closure = closure; - info->avoid = g_list_copy (avoid); - g_list_foreach (info->avoid, (GFunc) g_object_ref, NULL); - - if (book) - use_common_book_cb (book, info); - else - e_book_use_default_book (use_common_book_cb, info); -} - diff --git a/addressbook/backend/ebook/e-card-compare.h b/addressbook/backend/ebook/e-card-compare.h deleted file mode 100644 index 07ccb54e89..0000000000 --- a/addressbook/backend/ebook/e-card-compare.h +++ /dev/null @@ -1,72 +0,0 @@ -/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ - -/* - * e-card-compare.h - * - * Copyright (C) 2001 Ximian, Inc. - * - * Developed by Jon Trowbridge - */ - -/* - * This program is free software; you can redistribute it and/or - * modify it under the terms of version 2 of the GNU General Public - * License as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - * USA. - */ - -#ifndef __E_CARD_COMPARE_H__ -#define __E_CARD_COMPARE_H__ - -#include "e-book.h" -#include "e-card.h" - -typedef enum { - E_CARD_MATCH_NOT_APPLICABLE = 0, - E_CARD_MATCH_NONE = 1, - E_CARD_MATCH_VAGUE = 2, - E_CARD_MATCH_PARTIAL = 3, - E_CARD_MATCH_EXACT = 4 -} ECardMatchType; - -typedef enum { - E_CARD_MATCH_PART_NOT_APPLICABLE = -1, - E_CARD_MATCH_PART_NONE = 0, - E_CARD_MATCH_PART_GIVEN_NAME = 1<<0, - E_CARD_MATCH_PART_ADDITIONAL_NAME = 1<<2, - E_CARD_MATCH_PART_FAMILY_NAME = 1<<3 -} ECardMatchPart; - -typedef void (*ECardMatchQueryCallback) (ECard *card, ECard *match, ECardMatchType type, gpointer closure); - -ECardMatchType e_card_compare_name_to_string (ECard *card, const gchar *str); - -ECardMatchType e_card_compare_name_to_string_full (ECard *card, const gchar *str, - gboolean allow_partial_matches, - gint *matched_parts, ECardMatchPart *first_matched_part, - gint *matched_character_count); - -ECardMatchType e_card_compare_name (ECard *card1, ECard *card2); -ECardMatchType e_card_compare_nickname (ECard *card1, ECard *card2); -ECardMatchType e_card_compare_email (ECard *card1, ECard *card2); -ECardMatchType e_card_compare_address (ECard *card1, ECard *card2); -ECardMatchType e_card_compare_telephone (ECard *card1, ECard *card2); - -ECardMatchType e_card_compare (ECard *card1, ECard *card2); - -void e_card_locate_match (ECard *card, ECardMatchQueryCallback cb, gpointer closure); -void e_card_locate_match_full (EBook *book, ECard *card, GList *avoid, ECardMatchQueryCallback cb, gpointer closure); - - - -#endif /* __E_CARD_COMPARE_H__ */ - diff --git a/addressbook/backend/ebook/e-card-cursor.c b/addressbook/backend/ebook/e-card-cursor.c deleted file mode 100644 index 0aa9c8c1e0..0000000000 --- a/addressbook/backend/ebook/e-card-cursor.c +++ /dev/null @@ -1,239 +0,0 @@ -/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ -/* - * e-card-cursor.c: Implements card cursors. - * - * Author: - * Christopher James Lahey -#include "addressbook.h" -#include "e-card-cursor.h" - -struct _ECardCursorPrivate { - GNOME_Evolution_Addressbook_CardCursor corba_cursor; -}; - -/* - * A pointer to our parent object class - */ -static GObjectClass *parent_class; - -/* - * Implemented GObject::dispose - */ -static void -e_card_cursor_dispose (GObject *object) -{ - ECardCursor *cursor = E_CARD_CURSOR (object); - - if (cursor->priv) { - CORBA_Environment ev; - - CORBA_exception_init (&ev); - - GNOME_Evolution_Addressbook_CardCursor_unref( cursor->priv->corba_cursor, &ev ); - - if (ev._major != CORBA_NO_EXCEPTION) { - g_warning("e_card_cursor_destroy: Exception unreffing " - "corba cursor.\n"); - CORBA_exception_free (&ev); - CORBA_exception_init (&ev); - } - - CORBA_Object_release (cursor->priv->corba_cursor, &ev); - - if (ev._major != CORBA_NO_EXCEPTION) { - g_warning("e_card_cursor_destroy: Exception releasing " - "corba cursor.\n"); - } - - CORBA_exception_free (&ev); - - g_free ( cursor->priv ); - cursor->priv = NULL; - } - - if (G_OBJECT_CLASS (parent_class)->dispose) - G_OBJECT_CLASS (parent_class)->dispose (object); -} - -/** - * e_card_cursor_get_length: - * @cursor: the #ECardCursor whose length is being queried - * - * Returns: the number of items the cursor references, or -1 there's - * an error. - */ -long -e_card_cursor_get_length (ECardCursor *cursor) -{ - if ( cursor->priv->corba_cursor != CORBA_OBJECT_NIL ) { - CORBA_Environment ev; - long ret_val; - - CORBA_exception_init (&ev); - - ret_val = GNOME_Evolution_Addressbook_CardCursor_count (cursor->priv->corba_cursor, &ev); - - if (ev._major != CORBA_NO_EXCEPTION) { - g_warning("e_card_cursor_get_length: Exception during " - "get_length corba call.\n"); - ret_val = -1; - } - - CORBA_exception_free (&ev); - - return ret_val; - } - else - return -1; -} - -/** - * e_card_cursor_get_nth: - * @cursor: an #ECardCursor object - * @n: the index of the item requested - * - * Gets an #ECard based on an index. - * - * Returns: a new #ECard on success, or %NULL on failure. - */ -ECard * -e_card_cursor_get_nth (ECardCursor *cursor, - const long n) -{ - if ( cursor->priv->corba_cursor != CORBA_OBJECT_NIL ) { - CORBA_Environment en; - CORBA_char *vcard; - ECard *card; - - CORBA_exception_init (&en); - - vcard = GNOME_Evolution_Addressbook_CardCursor_getNth(cursor->priv->corba_cursor, n, &en); - - if (en._major != CORBA_NO_EXCEPTION) { - g_warning("e_card_cursor_get_nth: Exception during " - "get_nth corba call.\n"); - } - - CORBA_exception_free (&en); - - card = e_card_new (vcard); - - CORBA_free(vcard); - - return card; - } - else - return e_card_new(""); -} - -static void -e_card_cursor_class_init (ECardCursorClass *klass) -{ - GObjectClass *object_class = (GObjectClass *) klass; - - parent_class = g_type_class_ref (G_TYPE_OBJECT); - - object_class->dispose = e_card_cursor_dispose; -} - -static void -e_card_cursor_init (ECardCursor *cursor) -{ - cursor->priv = g_new(ECardCursorPrivate, 1); - cursor->priv->corba_cursor = CORBA_OBJECT_NIL; -} - -GType -e_card_cursor_get_type (void) -{ - static GType type = 0; - - if (!type){ - static const GTypeInfo info = { - sizeof (ECardCursorClass), - NULL, /* base_init */ - NULL, /* base_finalize */ - (GClassInitFunc) e_card_cursor_class_init, - NULL, /* class_finalize */ - NULL, /* class_data */ - sizeof (ECardCursor), - 0, /* n_preallocs */ - (GInstanceInitFunc) e_card_cursor_init, - }; - - type = g_type_register_static (G_TYPE_OBJECT, "ECardCursor", &info, 0); - } - - return type; -} - -/** - * e_card_cursor_construct: - * @cursor: an #ECardCursor object - * @corba_cursor: an #GNOME_Evolution_Addressbook_CardCursor - * - * Wraps an #GNOME_Evolution_Addressbook_CardCursor object inside the #ECardCursor - * @cursor object. - * - * Returns: a new #ECardCursor on success, or %NULL on failure. - */ -ECardCursor * -e_card_cursor_construct (ECardCursor *cursor, - GNOME_Evolution_Addressbook_CardCursor corba_cursor) -{ - CORBA_Environment ev; - g_return_val_if_fail (cursor != NULL, NULL); - g_return_val_if_fail (E_IS_CARD_CURSOR (cursor), NULL); - g_return_val_if_fail (corba_cursor != CORBA_OBJECT_NIL, NULL); - - CORBA_exception_init (&ev); - - /* - * Initialize cursor - */ - cursor->priv->corba_cursor = CORBA_Object_duplicate(corba_cursor, &ev); - - if (ev._major != CORBA_NO_EXCEPTION) { - g_warning("e_card_cursor_construct: Exception duplicating " - "corba cursor.\n"); - CORBA_exception_free (&ev); - CORBA_exception_init (&ev); - } - - GNOME_Evolution_Addressbook_CardCursor_ref(cursor->priv->corba_cursor, &ev); - - if (ev._major != CORBA_NO_EXCEPTION) { - g_warning("e_card_cursor_construct: Exception reffing " - "corba cursor.\n"); - } - - CORBA_exception_free (&ev); - - /* - * Success: return the GType we were given - */ - return cursor; -} - -/** - * e_card_cursor_new: - * @cursor: the #GNOME_Evolution_Addressbook_CardCursor to be wrapped - * - * Creates a new #ECardCursor, which wraps an #GNOME_Evolution_Addressbook_CardCursor - * object. - * - * Returns: a new #ECardCursor on success, or %NULL on failure. - */ -ECardCursor * -e_card_cursor_new (GNOME_Evolution_Addressbook_CardCursor corba_cursor) -{ - ECardCursor *cursor; - - cursor = g_object_new (E_TYPE_CARD_CURSOR, NULL); - - return e_card_cursor_construct (cursor, - corba_cursor); -} diff --git a/addressbook/backend/ebook/e-card-cursor.h b/addressbook/backend/ebook/e-card-cursor.h deleted file mode 100644 index b8da39f023..0000000000 --- a/addressbook/backend/ebook/e-card-cursor.h +++ /dev/null @@ -1,53 +0,0 @@ -/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ -/* - * - * Author: - * Nat Friedman (nat@ximian.com) - * - * Copyright 2000, Ximian, Inc. - */ - -#ifndef __E_CARD_CURSOR_H__ -#define __E_CARD_CURSOR_H__ - -#include -#include -#include -#include - -#define E_TYPE_CARD_CURSOR (e_card_cursor_get_type ()) -#define E_CARD_CURSOR(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), E_TYPE_CARD_CURSOR, ECardCursor)) -#define E_CARD_CURSOR_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), E_TYPE_CARD_CURSOR, ECardCursorClass)) -#define E_IS_CARD_CURSOR(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), E_TYPE_CARD_CURSOR)) -#define E_IS_CARD_CURSOR_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), E_TYPE_CARD_CURSOR)) -#define E_CARD_CURSOR_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), E_TYPE_CARD_CURSOR, ECardCursorClass)) - -G_BEGIN_DECLS - -typedef struct _ECardCursor ECardCursor; -typedef struct _ECardCursorPrivate ECardCursorPrivate; -typedef struct _ECardCursorClass ECardCursorClass; - -struct _ECardCursor { - GObject parent; - ECardCursorPrivate *priv; -}; - -struct _ECardCursorClass { - GObjectClass parent; -}; - -/* Creating a new addressbook. */ -ECardCursor *e_card_cursor_new (GNOME_Evolution_Addressbook_CardCursor corba_cursor); -ECardCursor *e_card_cursor_construct (ECardCursor *cursor, - GNOME_Evolution_Addressbook_CardCursor corba_cursor); - -GType e_card_cursor_get_type (void); - -/* Fetching cards. */ -long e_card_cursor_get_length (ECardCursor *cursor); -ECard *e_card_cursor_get_nth (ECardCursor *cursor, - const long nth); -G_END_DECLS - -#endif /* ! __E_CARD_CURSOR_H__ */ diff --git a/addressbook/backend/ebook/e-card-pairs.h b/addressbook/backend/ebook/e-card-pairs.h deleted file mode 100644 index f82f948ebb..0000000000 --- a/addressbook/backend/ebook/e-card-pairs.h +++ /dev/null @@ -1,118 +0,0 @@ -/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ -/* GnomeCard - a graphical contact manager. - * - * pairs.h: This file is part of GnomeCard. - * - * Copyright (C) 1999 The Free Software Foundation - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of version 2 of the GNU General Public - * License as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public - * License along with this program; if not, write to the - * Free Software Foundation, Inc., 59 Temple Place - Suite 330, - * Boston, MA 02111-1307, USA. - */ - -#ifndef __E_CARD_PAIRS_H__ -#define __E_CARD_PAIRS_H__ - -#include -#include - - -#if 0 -struct pair -{ - char *str; - ECardPropertyType i ; -}; - -struct pair prop_lookup[] = { - { VCFullNameProp, PROP_FNAME }, - { VCNameProp, PROP_NAME }, - { VCPhotoProp, PROP_PHOTO }, - { VCBirthDateProp, PROP_BDAY }, - { VCAdrProp, PROP_DELADDR }, - { VCDeliveryLabelProp, PROP_DELLABEL }, - { VCTelephoneProp, PROP_PHONE }, - { VCEmailAddressProp, PROP_EMAIL }, - { VCMailerProp, PROP_MAILER }, - { VCTimeZoneProp, PROP_TIMEZN }, - { VCGeoProp, PROP_GEOPOS }, - { VCTitleProp, PROP_TITLE }, - { VCBusinessRoleProp, PROP_ROLE }, - { VCLogoProp, PROP_LOGO }, - { VCAgentProp, PROP_AGENT }, - { VCOrgProp, PROP_ORG }, - { VCCategoriesProp, PROP_CATEGORIES }, - { VCCommentProp, PROP_COMMENT }, - { VCLastRevisedProp, PROP_REV }, - { VCPronunciationProp, PROP_SOUND }, - { VCURLProp, PROP_URL }, - { VCUniqueStringProp, PROP_UID }, - { VCVersionProp, PROP_VERSION }, - { VCPublicKeyProp, PROP_KEY }, - { VCValueProp, PROP_VALUE }, - { VCEncodingProp, PROP_ENCODING }, - { VCQuotedPrintableProp, PROP_QUOTED_PRINTABLE }, - { VC8bitProp, PROP_8BIT }, - { VCBase64Prop, PROP_BASE64 }, - { VCLanguageProp, PROP_LANG }, - { VCCharSetProp, PROP_CHARSET }, - { NULL, PROP_NONE} }; - -struct pair photo_pairs[] = { - { VCGIFProp, PHOTO_GIF }, - { VCCGMProp, PHOTO_CGM }, - { VCWMFProp, PHOTO_WMF }, - { VCBMPProp, PHOTO_BMP }, - { VCMETProp, PHOTO_MET }, - { VCPMBProp, PHOTO_PMB }, - { VCDIBProp, PHOTO_DIB }, - { VCPICTProp, PHOTO_PICT }, - { VCTIFFProp, PHOTO_TIFF }, - { VCPDFProp, PHOTO_PDF }, - { VCPSProp, PHOTO_PS }, - { VCJPEGProp, PHOTO_JPEG }, - { VCMPEGProp, PHOTO_MPEG }, - { VCMPEG2Prop, PHOTO_MPEG2 }, - { VCAVIProp, PHOTO_AVI }, - { VCQuickTimeProp, PHOTO_QTIME }, - { NULL, 0 } }; - -struct pair email_pairs[] = { - { VCAOLProp, EMAIL_AOL }, - { VCAppleLinkProp, EMAIL_APPLE_LINK }, - { VCATTMailProp, EMAIL_ATT }, - { VCCISProp, EMAIL_CIS }, - { VCEWorldProp, EMAIL_EWORLD }, - { VCInternetProp, EMAIL_INET }, - { VCIBMMailProp, EMAIL_IBM }, - { VCMCIMailProp, EMAIL_MCI }, - { VCPowerShareProp, EMAIL_POWERSHARE }, - { VCProdigyProp, EMAIL_PRODIGY }, - { VCTLXProp, EMAIL_TLX }, - { VCX400Prop, EMAIL_X400 }, - { NULL, 0 } }; - -struct pair sound_pairs[] = { - { VCAIFFProp, SOUND_AIFF }, - { VCPCMProp, SOUND_PCM }, - { VCWAVEProp, SOUND_WAVE }, - { NULL, 0 } }; - -struct pair key_pairs[] = { - { VCX509Prop, KEY_X509 }, - { VCPGPProp, KEY_PGP }, - { NULL, 0 } }; - - -#endif -#endif /* ! __E_CARD_PAIRS_H__ */ diff --git a/addressbook/backend/ebook/e-card-simple.c b/addressbook/backend/ebook/e-card-simple.c deleted file mode 100644 index b9e32762fe..0000000000 --- a/addressbook/backend/ebook/e-card-simple.c +++ /dev/null @@ -1,1344 +0,0 @@ -/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ -/* - * Authors: - * Chris Lahey - * Arturo Espinosa (arturo@nuclecu.unam.mx) - * Nat Friedman (nat@ximian.com) - * - * Copyright (C) 2000 Ximian, Inc. - * Copyright (C) 1999 The Free Software Foundation - */ - -#include -#include -#include -#include -#include -#include - -#include -#include "e-card-simple.h" - -/* Object property IDs */ -enum { - PROP_0, - PROP_CARD, -}; - -static GObjectClass *parent_class; - -typedef enum _ECardSimpleInternalType ECardSimpleInternalType; -typedef struct _ECardSimpleFieldData ECardSimpleFieldData; - -enum _ECardSimpleInternalType { - E_CARD_SIMPLE_INTERNAL_TYPE_STRING, - E_CARD_SIMPLE_INTERNAL_TYPE_DATE, - E_CARD_SIMPLE_INTERNAL_TYPE_ADDRESS, - E_CARD_SIMPLE_INTERNAL_TYPE_PHONE, - E_CARD_SIMPLE_INTERNAL_TYPE_EMAIL, - E_CARD_SIMPLE_INTERNAL_TYPE_SPECIAL, - E_CARD_SIMPLE_INTERNAL_TYPE_BOOL, -}; - -struct _ECardSimpleFieldData { - ECardSimpleField field; - char *ecard_field; - char *name; - char *short_name; - int list_type_index; - ECardSimpleInternalType type; -}; - -/* This order must match the order in the .h. */ - -/* the ecard_field data below should only be used for TYPE_STRING, - TYPE_DATE, and TYPE_SPECIAL fields. that is, it's only valid for - e-cards for those types. it is used as a unique name for fields - for the get_supported functionality. */ -static ECardSimpleFieldData field_data[] = -{ - { E_CARD_SIMPLE_FIELD_FILE_AS, "file_as", N_("File As"), "", 0, E_CARD_SIMPLE_INTERNAL_TYPE_STRING }, - { E_CARD_SIMPLE_FIELD_FULL_NAME, "full_name", N_("Name"), N_("Name"), 0, E_CARD_SIMPLE_INTERNAL_TYPE_STRING }, - { E_CARD_SIMPLE_FIELD_EMAIL, "email", N_("Email"), N_("Email"), E_CARD_SIMPLE_EMAIL_ID_EMAIL, E_CARD_SIMPLE_INTERNAL_TYPE_EMAIL }, - { E_CARD_SIMPLE_FIELD_PHONE_PRIMARY, "primary_phone", N_("Primary"), N_("Prim"), E_CARD_SIMPLE_PHONE_ID_PRIMARY, E_CARD_SIMPLE_INTERNAL_TYPE_PHONE }, - { E_CARD_SIMPLE_FIELD_PHONE_ASSISTANT, "assistant_phone", N_("Assistant"), N_("Assistant"),E_CARD_SIMPLE_PHONE_ID_ASSISTANT, E_CARD_SIMPLE_INTERNAL_TYPE_PHONE }, - { E_CARD_SIMPLE_FIELD_PHONE_BUSINESS, "business_phone", N_("Business"), N_("Bus"), E_CARD_SIMPLE_PHONE_ID_BUSINESS, E_CARD_SIMPLE_INTERNAL_TYPE_PHONE }, - { E_CARD_SIMPLE_FIELD_PHONE_CALLBACK, "callback_phone", N_("Callback"), N_("Callback"), E_CARD_SIMPLE_PHONE_ID_CALLBACK, E_CARD_SIMPLE_INTERNAL_TYPE_PHONE }, - { E_CARD_SIMPLE_FIELD_PHONE_COMPANY, "company_phone", N_("Company"), N_("Comp"), E_CARD_SIMPLE_PHONE_ID_COMPANY, E_CARD_SIMPLE_INTERNAL_TYPE_PHONE }, - { E_CARD_SIMPLE_FIELD_PHONE_HOME, "home_phone", N_("Home"), N_("Home"), E_CARD_SIMPLE_PHONE_ID_HOME, E_CARD_SIMPLE_INTERNAL_TYPE_PHONE }, - { E_CARD_SIMPLE_FIELD_ORG, "org", N_("Organization"), N_("Org"), 0, E_CARD_SIMPLE_INTERNAL_TYPE_STRING }, - { E_CARD_SIMPLE_FIELD_ADDRESS_BUSINESS, "business_address",N_("Business"), N_("Bus"), E_CARD_SIMPLE_ADDRESS_ID_BUSINESS, E_CARD_SIMPLE_INTERNAL_TYPE_ADDRESS }, - { E_CARD_SIMPLE_FIELD_ADDRESS_HOME, "home_address", N_("Home"), N_("Home"), E_CARD_SIMPLE_ADDRESS_ID_HOME, E_CARD_SIMPLE_INTERNAL_TYPE_ADDRESS }, - { E_CARD_SIMPLE_FIELD_PHONE_MOBILE, "mobile_phone", N_("Mobile"), N_("Mobile"), E_CARD_SIMPLE_PHONE_ID_MOBILE, E_CARD_SIMPLE_INTERNAL_TYPE_PHONE }, - { E_CARD_SIMPLE_FIELD_PHONE_CAR, "car_phone", N_("Car"), N_("Car"), E_CARD_SIMPLE_PHONE_ID_CAR, E_CARD_SIMPLE_INTERNAL_TYPE_PHONE }, - { E_CARD_SIMPLE_FIELD_PHONE_BUSINESS_FAX, "business_fax", N_("Business Fax"), N_("Bus Fax"), E_CARD_SIMPLE_PHONE_ID_BUSINESS_FAX, E_CARD_SIMPLE_INTERNAL_TYPE_PHONE }, - { E_CARD_SIMPLE_FIELD_PHONE_HOME_FAX, "home_fax", N_("Home Fax"), N_("Home Fax"), E_CARD_SIMPLE_PHONE_ID_HOME_FAX, E_CARD_SIMPLE_INTERNAL_TYPE_PHONE }, - { E_CARD_SIMPLE_FIELD_PHONE_BUSINESS_2, "business_phone_2",N_("Business 2"), N_("Bus 2"), E_CARD_SIMPLE_PHONE_ID_BUSINESS_2, E_CARD_SIMPLE_INTERNAL_TYPE_PHONE }, - { E_CARD_SIMPLE_FIELD_PHONE_HOME_2, "home_phone_2", N_("Home 2"), N_("Home 2"), E_CARD_SIMPLE_PHONE_ID_HOME_2, E_CARD_SIMPLE_INTERNAL_TYPE_PHONE }, - { E_CARD_SIMPLE_FIELD_PHONE_ISDN, "isdn", N_("ISDN"), N_("ISDN"), E_CARD_SIMPLE_PHONE_ID_ISDN, E_CARD_SIMPLE_INTERNAL_TYPE_PHONE }, - { E_CARD_SIMPLE_FIELD_PHONE_OTHER, "other_phone", N_("Other"), N_("Other"), E_CARD_SIMPLE_PHONE_ID_OTHER, E_CARD_SIMPLE_INTERNAL_TYPE_PHONE }, - { E_CARD_SIMPLE_FIELD_PHONE_OTHER_FAX, "other_fax", N_("Other Fax"), N_("Other Fax"), E_CARD_SIMPLE_PHONE_ID_OTHER_FAX, E_CARD_SIMPLE_INTERNAL_TYPE_PHONE }, - { E_CARD_SIMPLE_FIELD_PHONE_PAGER, "pager", N_("Pager"), N_("Pager"), E_CARD_SIMPLE_PHONE_ID_PAGER, E_CARD_SIMPLE_INTERNAL_TYPE_PHONE }, - { E_CARD_SIMPLE_FIELD_PHONE_RADIO, "radio", N_("Radio"), N_("Radio"), E_CARD_SIMPLE_PHONE_ID_RADIO, E_CARD_SIMPLE_INTERNAL_TYPE_PHONE }, - { E_CARD_SIMPLE_FIELD_PHONE_TELEX, "telex", N_("Telex"), N_("Telex"), E_CARD_SIMPLE_PHONE_ID_TELEX, E_CARD_SIMPLE_INTERNAL_TYPE_PHONE }, - { E_CARD_SIMPLE_FIELD_PHONE_TTYTDD, "tty", N_("TTY"), N_("TTY"), E_CARD_SIMPLE_PHONE_ID_TTYTDD, E_CARD_SIMPLE_INTERNAL_TYPE_PHONE }, - { E_CARD_SIMPLE_FIELD_ADDRESS_OTHER, "other_address", N_("Other"), N_("Other"), E_CARD_SIMPLE_ADDRESS_ID_OTHER, E_CARD_SIMPLE_INTERNAL_TYPE_ADDRESS }, - { E_CARD_SIMPLE_FIELD_EMAIL_2, "email_2", N_("Email 2"), N_("Email 2"), E_CARD_SIMPLE_EMAIL_ID_EMAIL_2, E_CARD_SIMPLE_INTERNAL_TYPE_EMAIL }, - { E_CARD_SIMPLE_FIELD_EMAIL_3, "email_3", N_("Email 3"), N_("Email 3"), E_CARD_SIMPLE_EMAIL_ID_EMAIL_3, E_CARD_SIMPLE_INTERNAL_TYPE_EMAIL }, - { E_CARD_SIMPLE_FIELD_URL, "url", N_("Web Site"), N_("Url"), 0, E_CARD_SIMPLE_INTERNAL_TYPE_STRING }, - { E_CARD_SIMPLE_FIELD_ORG_UNIT, "org_unit", N_("Department"), N_("Dep"), 0, E_CARD_SIMPLE_INTERNAL_TYPE_STRING }, - { E_CARD_SIMPLE_FIELD_OFFICE, "office", N_("Office"), N_("Off"), 0, E_CARD_SIMPLE_INTERNAL_TYPE_STRING }, - { E_CARD_SIMPLE_FIELD_TITLE, "title", N_("Title"), N_("Title"), 0, E_CARD_SIMPLE_INTERNAL_TYPE_STRING }, - { E_CARD_SIMPLE_FIELD_ROLE, "role", N_("Profession"), N_("Prof"), 0, E_CARD_SIMPLE_INTERNAL_TYPE_STRING }, - { E_CARD_SIMPLE_FIELD_MANAGER, "manager", N_("Manager"), N_("Man"), 0, E_CARD_SIMPLE_INTERNAL_TYPE_STRING }, - { E_CARD_SIMPLE_FIELD_ASSISTANT, "assistant", N_("Assistant"), N_("Ass"), 0, E_CARD_SIMPLE_INTERNAL_TYPE_STRING }, - { E_CARD_SIMPLE_FIELD_NICKNAME, "nickname", N_("Nickname"), N_("Nick"), 0, E_CARD_SIMPLE_INTERNAL_TYPE_STRING }, - { E_CARD_SIMPLE_FIELD_SPOUSE, "spouse", N_("Spouse"), N_("Spouse"), 0, E_CARD_SIMPLE_INTERNAL_TYPE_STRING }, - { E_CARD_SIMPLE_FIELD_NOTE, "note", N_("Note"), N_("Note"), 0, E_CARD_SIMPLE_INTERNAL_TYPE_STRING }, - { E_CARD_SIMPLE_FIELD_CALURI, "caluri", N_("Calendar URI"), N_("CALUri"), 0, E_CARD_SIMPLE_INTERNAL_TYPE_STRING }, - { E_CARD_SIMPLE_FIELD_FBURL, "fburl", N_("Free-busy URL"), N_("FBUrl"), 0, E_CARD_SIMPLE_INTERNAL_TYPE_STRING }, - { E_CARD_SIMPLE_FIELD_ICSCALENDAR, "icscalendar", N_("Default server calendar"), N_("icsCalendar"), 0, E_CARD_SIMPLE_INTERNAL_TYPE_STRING }, - { E_CARD_SIMPLE_FIELD_ANNIVERSARY, "anniversary", N_("Anniversary"), N_("Anniv"), 0, E_CARD_SIMPLE_INTERNAL_TYPE_DATE }, - { E_CARD_SIMPLE_FIELD_BIRTH_DATE, "birth_date", N_("Birth Date"), "", 0, E_CARD_SIMPLE_INTERNAL_TYPE_DATE }, - { E_CARD_SIMPLE_FIELD_MAILER, "mailer", "", "", 0, E_CARD_SIMPLE_INTERNAL_TYPE_STRING }, - { E_CARD_SIMPLE_FIELD_NAME_OR_ORG, "nameororg", "", "", 0, E_CARD_SIMPLE_INTERNAL_TYPE_SPECIAL }, - { E_CARD_SIMPLE_FIELD_CATEGORIES, "categories", N_("Categories"), N_("Categories"), 0, E_CARD_SIMPLE_INTERNAL_TYPE_STRING }, - { E_CARD_SIMPLE_FIELD_FAMILY_NAME, "family_name", N_("Family Name"), N_("Family Name"), 0, E_CARD_SIMPLE_INTERNAL_TYPE_SPECIAL }, - { E_CARD_SIMPLE_FIELD_GIVEN_NAME, "given_name", "Given Name", "Given Name", 0, E_CARD_SIMPLE_INTERNAL_TYPE_SPECIAL }, - { E_CARD_SIMPLE_FIELD_ADDITIONAL_NAME, "additional_name", "Additional Name", "Additional Name", 0, E_CARD_SIMPLE_INTERNAL_TYPE_SPECIAL }, - { E_CARD_SIMPLE_FIELD_NAME_SUFFIX, "name_suffix", "Name Suffix", "Name Suffix", 0, E_CARD_SIMPLE_INTERNAL_TYPE_SPECIAL }, - { E_CARD_SIMPLE_FIELD_WANTS_HTML, "wants_html", "Wants HTML", "Wants HTML", 0, E_CARD_SIMPLE_INTERNAL_TYPE_BOOL }, - { E_CARD_SIMPLE_FIELD_IS_LIST, "list", "Is List", "Is List", 0, E_CARD_SIMPLE_INTERNAL_TYPE_BOOL }, -}; -static int field_data_count = sizeof (field_data) / sizeof (field_data[0]); - -static void e_card_simple_init (ECardSimple *simple); -static void e_card_simple_class_init (ECardSimpleClass *klass); - -static void e_card_simple_dispose (GObject *object); -static void e_card_simple_set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec); -static void e_card_simple_get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec); - -static void fill_in_info(ECardSimple *simple); - -ECardPhoneFlags phone_correspondences[] = { - E_CARD_PHONE_ASSISTANT, /* E_CARD_SIMPLE_PHONE_ID_ASSISTANT, */ - E_CARD_PHONE_WORK | E_CARD_PHONE_VOICE, /* E_CARD_SIMPLE_PHONE_ID_BUSINESS, */ - E_CARD_PHONE_WORK | E_CARD_PHONE_VOICE, /* E_CARD_SIMPLE_PHONE_ID_BUSINESS_2, */ - E_CARD_PHONE_WORK | E_CARD_PHONE_FAX, /* E_CARD_SIMPLE_PHONE_ID_BUSINESS_FAX, */ - E_CARD_PHONE_CALLBACK, /* E_CARD_SIMPLE_PHONE_ID_CALLBACK, */ - E_CARD_PHONE_CAR, /* E_CARD_SIMPLE_PHONE_ID_CAR, */ - E_CARD_PHONE_WORK, /* E_CARD_SIMPLE_PHONE_ID_COMPANY, */ - E_CARD_PHONE_HOME, /* E_CARD_SIMPLE_PHONE_ID_HOME, */ - E_CARD_PHONE_HOME, /* E_CARD_SIMPLE_PHONE_ID_HOME_2, */ - E_CARD_PHONE_HOME | E_CARD_PHONE_FAX, /* E_CARD_SIMPLE_PHONE_ID_HOME_FAX, */ - E_CARD_PHONE_ISDN, /* E_CARD_SIMPLE_PHONE_ID_ISDN, */ - E_CARD_PHONE_CELL, /* E_CARD_SIMPLE_PHONE_ID_MOBILE, */ - E_CARD_PHONE_VOICE, /* E_CARD_SIMPLE_PHONE_ID_OTHER, */ - E_CARD_PHONE_FAX, /* E_CARD_SIMPLE_PHONE_ID_OTHER_FAX, */ - E_CARD_PHONE_PAGER, /* E_CARD_SIMPLE_PHONE_ID_PAGER, */ - E_CARD_PHONE_PREF, /* E_CARD_SIMPLE_PHONE_ID_PRIMARY, */ - E_CARD_PHONE_RADIO, /* E_CARD_SIMPLE_PHONE_ID_RADIO, */ - E_CARD_PHONE_TELEX, /* E_CARD_SIMPLE_PHONE_ID_TELEX, */ - E_CARD_PHONE_TTYTDD, /* E_CARD_SIMPLE_PHONE_ID_TTYTDD, */ -}; - -char *phone_names[] = { - NULL, /* E_CARD_SIMPLE_PHONE_ID_ASSISTANT, */ - "Business", - "Business 2", - "Business Fax", - NULL, /* E_CARD_SIMPLE_PHONE_ID_CALLBACK, */ - "Car", - NULL, /* E_CARD_SIMPLE_PHONE_ID_COMPANY, */ - "Home", - "Home 2", - "Home Fax", - "ISDN", - "Mobile", - "Other", - NULL, /* E_CARD_SIMPLE_PHONE_ID_OTHER_FAX, */ - "Pager", - "Primary", - NULL, /* E_CARD_SIMPLE_PHONE_ID_RADIO, */ - NULL, /* E_CARD_SIMPLE_PHONE_ID_TELEX, */ - NULL, /* E_CARD_SIMPLE_PHONE_ID_TTYTDD, */ -}; - -char *phone_short_names[] = { - NULL, /* E_CARD_SIMPLE_PHONE_ID_ASSISTANT, */ - "Bus", - "Bus 2", - "Bus Fax", - NULL, /* E_CARD_SIMPLE_PHONE_ID_CALLBACK, */ - "Car", - NULL, /* E_CARD_SIMPLE_PHONE_ID_COMPANY, */ - "Home", - "Home 2", - "Home Fax", - "ISDN", - "Mob", - "Other", - NULL, /* E_CARD_SIMPLE_PHONE_ID_OTHER_FAX, */ - "Pag", - "Prim", - NULL, /* E_CARD_SIMPLE_PHONE_ID_RADIO, */ - NULL, /* E_CARD_SIMPLE_PHONE_ID_TELEX, */ - NULL, /* E_CARD_SIMPLE_PHONE_ID_TTYTDD, */ -}; - -ECardAddressFlags addr_correspondences[] = { - E_CARD_ADDR_WORK, /* E_CARD_SIMPLE_ADDRESS_ID_BUSINESS, */ - E_CARD_ADDR_HOME, /* E_CARD_SIMPLE_ADDRESS_ID_HOME, */ - E_CARD_ADDR_POSTAL, /* E_CARD_SIMPLE_ADDRESS_ID_OTHER, */ -}; - -char *address_names[] = { - "Business", - "Home", - "Other", -}; - -/** - * e_card_simple_get_type: - * @void: - * - * Registers the &ECardSimple class if necessary, and returns the type ID - * associated to it. - * - * Return value: The type ID of the &ECardSimple class. - **/ -GType -e_card_simple_get_type (void) -{ - static GType simple_type = 0; - - if (!simple_type) { - static const GTypeInfo simple_info = { - sizeof (ECardSimpleClass), - NULL, /* base_init */ - NULL, /* base_finalize */ - (GClassInitFunc) e_card_simple_class_init, - NULL, /* class_finalize */ - NULL, /* class_data */ - sizeof (ECardSimple), - 0, /* n_preallocs */ - (GInstanceInitFunc) e_card_simple_init, - }; - - simple_type = g_type_register_static (G_TYPE_OBJECT, "ECardSimple", &simple_info, 0); - } - - return simple_type; -} - -/** - * e_card_simple_new: - * @VCard: a string in vCard format - * - * Returns: a new #ECardSimple that wraps the @VCard. - */ -ECardSimple * -e_card_simple_new (ECard *card) -{ - ECardSimple *simple = g_object_new (E_TYPE_CARD_SIMPLE, NULL); - g_object_set(simple, - "card", card, - NULL); - return simple; -} - -ECardSimple * -e_card_simple_duplicate(ECardSimple *simple) -{ - ECard *card = simple->card ? e_card_duplicate (simple->card) : e_card_new (""); - ECardSimple *new_simple = e_card_simple_new(card); - return new_simple; -} - -/** - * e_card_simple_get_id: - * @simple: an #ECardSimple - * - * Returns: a string representing the id of the simple, which is unique - * within its book. - */ -const char * -e_card_simple_get_id (ECardSimple *simple) -{ - if (simple->card) - return e_card_get_id(simple->card); - else - return ""; -} - -/** - * e_card_simple_get_id: - * @simple: an #ECardSimple - * @id: a id in string format - * - * Sets the identifier of a simple, which should be unique within its - * book. - */ -void -e_card_simple_set_id (ECardSimple *simple, const char *id) -{ - if ( simple->card ) - e_card_set_id(simple->card, id); -} - -/** - * e_card_simple_get_vcard: - * @simple: an #ECardSimple - * - * Returns: a string in vcard format, which is wrapped by the @simple. - */ -char * -e_card_simple_get_vcard (ECardSimple *simple) -{ - if (simple->card) - return e_card_get_vcard(simple->card); - else - return g_strdup(""); -} - -/** - * e_card_simple_get_vcard_assume_utf8: - * @simple: an #ECardSimple - * - * Returns: a string in vcard format, which is wrapped by the @simple. - */ -char * -e_card_simple_get_vcard_assume_utf8 (ECardSimple *simple) -{ - if (simple->card) - return e_card_get_vcard_assume_utf8(simple->card); - else - return g_strdup(""); -} - -static void -e_card_simple_class_init (ECardSimpleClass *klass) -{ - GObjectClass *object_class; - - object_class = G_OBJECT_CLASS(klass); - - parent_class = g_type_class_ref (G_TYPE_OBJECT); - - object_class->dispose = e_card_simple_dispose; - object_class->get_property = e_card_simple_get_property; - object_class->set_property = e_card_simple_set_property; - - g_object_class_install_property (object_class, PROP_CARD, - g_param_spec_object ("card", - _("ECard"), - /*_( */"XXX blurb" /*)*/, - E_TYPE_CARD, - G_PARAM_READWRITE)); -} - -/* - * ECardSimple lifecycle management and vcard loading/saving. - */ - -static void -e_card_simple_dispose (GObject *object) -{ - ECardSimple *simple; - int i; - - simple = E_CARD_SIMPLE (object); - - if (simple->card) { - g_object_unref(simple->card); - simple->card = NULL; - } - if (simple->temp_fields) { - g_list_foreach(simple->temp_fields, (GFunc) g_free, NULL); - g_list_free(simple->temp_fields); - simple->temp_fields = NULL; - } - - for(i = 0; i < E_CARD_SIMPLE_PHONE_ID_LAST; i++) { - if (simple->phone[i]) { - e_card_phone_unref (simple->phone[i]); - simple->phone[i] = NULL; - } - } - for(i = 0; i < E_CARD_SIMPLE_EMAIL_ID_LAST; i++) { - if (simple->email[i]) { - g_free(simple->email[i]); - simple->email[i] = NULL; - } - } - for(i = 0; i < E_CARD_SIMPLE_ADDRESS_ID_LAST; i++) { - if (simple->address[i]) { - e_card_address_label_unref(simple->address[i]); - simple->address[i] = NULL; - } - } - for(i = 0; i < E_CARD_SIMPLE_ADDRESS_ID_LAST; i++) { - if (simple->delivery[i]) { - e_card_delivery_address_unref(simple->delivery[i]); - simple->delivery[i] = NULL; - } - } - - if (G_OBJECT_CLASS (parent_class)->dispose) - G_OBJECT_CLASS (parent_class)->dispose (object); -} - - -/* Set_arg handler for the simple */ -static void -e_card_simple_set_property (GObject *object, - guint prop_id, - const GValue *value, - GParamSpec *pspec) -{ - ECardSimple *simple; - - simple = E_CARD_SIMPLE (object); - - switch (prop_id) { - case PROP_CARD: - if (simple->card) - g_object_unref(simple->card); - g_list_foreach(simple->temp_fields, (GFunc) g_free, NULL); - g_list_free(simple->temp_fields); - simple->temp_fields = NULL; - if (g_value_get_object (value)) - simple->card = E_CARD(g_value_get_object (value)); - else - simple->card = NULL; - if(simple->card) - g_object_ref(simple->card); - fill_in_info(simple); - break; - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); - break; - } -} - -/* Get_arg handler for the simple */ -static void -e_card_simple_get_property (GObject *object, - guint prop_id, - GValue *value, - GParamSpec *pspec) -{ - ECardSimple *simple; - - simple = E_CARD_SIMPLE (object); - - switch (prop_id) { - case PROP_CARD: - e_card_simple_sync_card(simple); - g_value_set_object (value, simple->card); - break; - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); - break; - } -} - - -/** - * e_card_simple_init: - */ -static void -e_card_simple_init (ECardSimple *simple) -{ - int i; - simple->card = NULL; - for(i = 0; i < E_CARD_SIMPLE_PHONE_ID_LAST; i++) - simple->phone[i] = NULL; - for(i = 0; i < E_CARD_SIMPLE_EMAIL_ID_LAST; i++) - simple->email[i] = NULL; - for(i = 0; i < E_CARD_SIMPLE_ADDRESS_ID_LAST; i++) - simple->address[i] = NULL; - simple->temp_fields = NULL; - - simple->changed = TRUE; -} - -static void -fill_in_info(ECardSimple *simple) -{ - ECard *card = simple->card; - if (card) { - EList *address_list; - EList *phone_list; - EList *email_list; - EList *delivery_list; - const ECardPhone *phone; - const char *email; - const ECardAddrLabel *address; - const ECardDeliveryAddress *delivery; - int i; - - EIterator *iterator; - - g_object_get(card, - "address_label", &address_list, - "address", &delivery_list, - "phone", &phone_list, - "email", &email_list, - NULL); - for (i = 0; i < E_CARD_SIMPLE_PHONE_ID_LAST; i++) { - e_card_phone_unref(simple->phone[i]); - simple->phone[i] = NULL; - } - for (iterator = e_list_get_iterator(phone_list); e_iterator_is_valid(iterator); e_iterator_next(iterator)) { - gboolean found = FALSE; - phone = e_iterator_get(iterator); - for (i = 0; i < E_CARD_SIMPLE_PHONE_ID_LAST; i ++) { - if ((phone->flags == phone_correspondences[i]) && (simple->phone[i] == NULL)) { - simple->phone[i] = e_card_phone_ref(phone); - found = TRUE; - break; - } - } - if (found) - continue; - for (i = 0; i < E_CARD_SIMPLE_PHONE_ID_LAST; i ++) { - if (((phone->flags & phone_correspondences[i]) == phone_correspondences[i]) && (simple->phone[i] == NULL)) { - simple->phone[i] = e_card_phone_ref(phone); - break; - } - } - } - g_object_unref(iterator); - - for (i = 0; i < E_CARD_SIMPLE_EMAIL_ID_LAST; i++) { - g_free(simple->email[i]); - simple->email[i] = NULL; - } - for (iterator = e_list_get_iterator(email_list); e_iterator_is_valid(iterator); e_iterator_next(iterator)) { - email = e_iterator_get(iterator); - for (i = 0; i < E_CARD_SIMPLE_EMAIL_ID_LAST; i ++) { - if ((simple->email[i] == NULL)) { - simple->email[i] = g_strdup(email); - break; - } - } - } - g_object_unref(iterator); - - for (i = 0; i < E_CARD_SIMPLE_ADDRESS_ID_LAST; i++) { - e_card_address_label_unref(simple->address[i]); - simple->address[i] = NULL; - } - for (iterator = e_list_get_iterator(address_list); e_iterator_is_valid(iterator); e_iterator_next(iterator)) { - address = e_iterator_get(iterator); - for (i = 0; i < E_CARD_SIMPLE_ADDRESS_ID_LAST; i ++) { - if (((address->flags & addr_correspondences[i]) == addr_correspondences[i]) && (simple->address[i] == NULL)) { - simple->address[i] = e_card_address_label_ref(address); - break; - } - } - } - g_object_unref(iterator); - - for (i = 0; i < E_CARD_SIMPLE_ADDRESS_ID_LAST; i++) { - e_card_delivery_address_unref(simple->delivery[i]); - simple->delivery[i] = NULL; - } - for (iterator = e_list_get_iterator(delivery_list); e_iterator_is_valid(iterator); e_iterator_next(iterator)) { - delivery = e_iterator_get(iterator); - for (i = 0; i < E_CARD_SIMPLE_ADDRESS_ID_LAST; i ++) { - if (((delivery->flags & addr_correspondences[i]) == addr_correspondences[i]) && (simple->delivery[i] == NULL)) { - simple->delivery[i] = e_card_delivery_address_ref(delivery); - break; - } - } - } - g_object_unref(iterator); - - g_object_unref(phone_list); - g_object_unref(email_list); - g_object_unref(address_list); - g_object_unref(delivery_list); - e_card_free_empty_lists (card); - } -} - -void -e_card_simple_sync_card(ECardSimple *simple) -{ - ECard *card = simple->card; - if (card && simple->changed) { - EList *address_list; - EList *phone_list; - EList *email_list; - EList *delivery_list; - const ECardPhone *phone; - const ECardAddrLabel *address; - const ECardDeliveryAddress *delivery; - const char *email; - int i; - - EIterator *iterator; - - g_object_get(card, - "address_label", &address_list, - "address", &delivery_list, - "phone", &phone_list, - "email", &email_list, - NULL); - - for (iterator = e_list_get_iterator(phone_list); e_iterator_is_valid(iterator); e_iterator_next(iterator) ) { - int i; - gboolean found = FALSE; - phone = e_iterator_get(iterator); - for (i = 0; i < E_CARD_SIMPLE_PHONE_ID_LAST; i ++) { - if (phone->flags == phone_correspondences[i]) { - if (simple->phone[i]) { - simple->phone[i]->flags = phone_correspondences[i]; - if (simple->phone[i]->number && *simple->phone[i]->number) { - e_iterator_set(iterator, simple->phone[i]); - } else { - e_iterator_delete(iterator); - } - e_card_phone_unref(simple->phone[i]); - simple->phone[i] = NULL; - found = TRUE; - break; - } - } - } - if (found) - continue; - for (i = 0; i < E_CARD_SIMPLE_PHONE_ID_LAST; i ++) { - if ((phone->flags & phone_correspondences[i]) == phone_correspondences[i]) { - if (simple->phone[i]) { - simple->phone[i]->flags = phone_correspondences[i]; - if (simple->phone[i]->number && *simple->phone[i]->number) { - e_iterator_set(iterator, simple->phone[i]); - } else { - e_iterator_delete(iterator); - } - e_card_phone_unref(simple->phone[i]); - simple->phone[i] = NULL; - break; - } - } - } - } - g_object_unref(iterator); - for (i = 0; i < E_CARD_SIMPLE_PHONE_ID_LAST; i ++) { - if (simple->phone[i]) { - simple->phone[i]->flags = phone_correspondences[i]; - e_list_append(phone_list, simple->phone[i]); - e_card_phone_unref(simple->phone[i]); - simple->phone[i] = NULL; - } - } - - for (iterator = e_list_get_iterator(email_list); e_iterator_is_valid(iterator); e_iterator_next(iterator) ) { - int i; - email = e_iterator_get(iterator); - for (i = 0; i < E_CARD_SIMPLE_EMAIL_ID_LAST; i ++) { - if (simple->email[i]) { - if (*simple->email[i]) { - e_iterator_set(iterator, simple->email[i]); - } else { - e_iterator_delete(iterator); - } - g_free(simple->email[i]); - simple->email[i] = NULL; - break; - } - } - } - g_object_unref(iterator); - for (i = 0; i < E_CARD_SIMPLE_EMAIL_ID_LAST; i ++) { - if (simple->email[i]) { - e_list_append(email_list, simple->email[i]); - g_free(simple->email[i]); - simple->email[i] = NULL; - } - } - - for (iterator = e_list_get_iterator(address_list); e_iterator_is_valid(iterator); e_iterator_next(iterator) ) { - int i; - address = e_iterator_get(iterator); - for (i = 0; i < E_CARD_SIMPLE_ADDRESS_ID_LAST; i ++) { - if ((address->flags & addr_correspondences[i]) == addr_correspondences[i]) { - if (simple->address[i]) { - simple->address[i]->flags &= ~E_CARD_ADDR_MASK; - simple->address[i]->flags |= addr_correspondences[i]; - if (simple->address[i]->data && *simple->address[i]->data) { - e_iterator_set(iterator, simple->address[i]); - } else { - e_iterator_delete(iterator); - } - e_card_address_label_unref(simple->address[i]); - simple->address[i] = NULL; - break; - } - } - } - } - g_object_unref(iterator); - for (i = 0; i < E_CARD_SIMPLE_ADDRESS_ID_LAST; i ++) { - if (simple->address[i]) { - simple->address[i]->flags &= ~E_CARD_ADDR_MASK; - simple->address[i]->flags |= addr_correspondences[i]; - e_list_append(address_list, simple->address[i]); - e_card_address_label_unref(simple->address[i]); - simple->address[i] = NULL; - } - } - - for (iterator = e_list_get_iterator(delivery_list); e_iterator_is_valid(iterator); e_iterator_next(iterator) ) { - int i; - delivery = e_iterator_get(iterator); - for (i = 0; i < E_CARD_SIMPLE_ADDRESS_ID_LAST; i ++) { - if ((delivery->flags & addr_correspondences[i]) == addr_correspondences[i]) { - if (simple->delivery[i]) { - simple->delivery[i]->flags &= ~E_CARD_ADDR_MASK; - simple->delivery[i]->flags |= addr_correspondences[i]; - if (!e_card_delivery_address_is_empty(simple->delivery[i])) { - e_iterator_set(iterator, simple->delivery[i]); - } else { - e_iterator_delete(iterator); - } - e_card_delivery_address_unref(simple->delivery[i]); - simple->delivery[i] = NULL; - break; - } - } - } - } - g_object_unref(iterator); - for (i = 0; i < E_CARD_SIMPLE_ADDRESS_ID_LAST; i ++) { - if (simple->delivery[i]) { - simple->delivery[i]->flags &= ~E_CARD_ADDR_MASK; - simple->delivery[i]->flags |= addr_correspondences[i]; - e_list_append(delivery_list, simple->delivery[i]); - e_card_delivery_address_unref(simple->delivery[i]); - simple->delivery[i] = NULL; - } - } - fill_in_info(simple); - - g_object_unref(phone_list); - g_object_unref(email_list); - g_object_unref(address_list); - g_object_unref(delivery_list); - e_card_free_empty_lists (card); - } - - simple->changed = FALSE; -} - -const ECardPhone *e_card_simple_get_phone (ECardSimple *simple, - ECardSimplePhoneId id) -{ - return simple->phone[id]; -} - -const char *e_card_simple_get_email (ECardSimple *simple, - ECardSimpleEmailId id) -{ - return simple->email[id]; -} - -const ECardAddrLabel *e_card_simple_get_address (ECardSimple *simple, - ECardSimpleAddressId id) -{ - return simple->address[id]; -} - -const ECardDeliveryAddress *e_card_simple_get_delivery_address (ECardSimple *simple, - ECardSimpleAddressId id) -{ - return simple->delivery[id]; -} - -void e_card_simple_set_phone (ECardSimple *simple, - ECardSimplePhoneId id, - const ECardPhone *phone) -{ - e_card_phone_unref(simple->phone[id]); - simple->phone[id] = e_card_phone_ref(phone); - simple->changed = TRUE; -} - -void e_card_simple_set_email (ECardSimple *simple, - ECardSimpleEmailId id, - const char *email) -{ - g_free(simple->email[id]); - simple->email[id] = g_strdup(email); - simple->changed = TRUE; -} - -void -e_card_simple_set_address (ECardSimple *simple, ECardSimpleAddressId id, const ECardAddrLabel *address) -{ - e_card_address_label_unref(simple->address[id]); - simple->address[id] = e_card_address_label_ref(address); - e_card_delivery_address_unref(simple->delivery[id]); - simple->delivery[id] = e_card_delivery_address_from_label(simple->address[id]); - simple->changed = TRUE; -} - -void e_card_simple_set_delivery_address (ECardSimple *simple, - ECardSimpleAddressId id, - const ECardDeliveryAddress *delivery) -{ - e_card_delivery_address_unref(simple->delivery[id]); - simple->delivery[id] = e_card_delivery_address_ref(delivery); - e_card_address_label_unref(simple->address[id]); - simple->address[id] = e_card_delivery_address_to_label(simple->delivery[id]); - simple->changed = TRUE; -} - -const char *e_card_simple_get_const (ECardSimple *simple, - ECardSimpleField field) -{ - char *ret_val = e_card_simple_get(simple, field); - if (ret_val) - simple->temp_fields = g_list_prepend(simple->temp_fields, ret_val); - return ret_val; -} - -char *e_card_simple_get (ECardSimple *simple, - ECardSimpleField field) -{ - ECardSimpleInternalType type = field_data[field].type; - const ECardAddrLabel *addr; - const ECardPhone *phone; - char *string; - ECardDate *date; - ECardName *name; - switch(type) { - case E_CARD_SIMPLE_INTERNAL_TYPE_STRING: - if (simple->card) { - g_object_get(simple->card, - field_data[field].ecard_field, &string, - NULL); - return string; - } else - return NULL; - case E_CARD_SIMPLE_INTERNAL_TYPE_DATE: - if (simple->card) { - g_object_get(simple->card, - field_data[field].ecard_field, &date, - NULL); - if (date != NULL) { - char buf[26]; - struct tm then; - then.tm_year = date->year; - then.tm_mon = date->month - 1; - then.tm_mday = date->day; - then.tm_hour = 12; - then.tm_min = 0; - then.tm_sec = 0; - e_strftime_fix_am_pm (buf, 26, _("%x"), &then); - return g_strdup (buf); - } else { - return NULL; - } - } else - return NULL; - case E_CARD_SIMPLE_INTERNAL_TYPE_ADDRESS: - addr = e_card_simple_get_address(simple, - field_data[field].list_type_index); - if (addr) - return g_strdup(addr->data); - else - return NULL; - case E_CARD_SIMPLE_INTERNAL_TYPE_PHONE: - phone = e_card_simple_get_phone(simple, - field_data[field].list_type_index); - if (phone) - return g_strdup(phone->number); - else - return NULL; - case E_CARD_SIMPLE_INTERNAL_TYPE_EMAIL: - string = e_card_simple_get_email(simple, - field_data[field].list_type_index); - return g_strdup(string); - case E_CARD_SIMPLE_INTERNAL_TYPE_BOOL: - if (simple->card) { - gboolean boole; - g_object_get (simple->card, - field_data[field].ecard_field, &boole, - NULL); - if (boole) - return g_strdup("true"); - else - return NULL; - } else { - return NULL; - } - case E_CARD_SIMPLE_INTERNAL_TYPE_SPECIAL: - switch (field) { - case E_CARD_SIMPLE_FIELD_NAME_OR_ORG: - if (simple->card) { - gboolean is_list; - - g_object_get(simple->card, - "file_as", &string, - NULL); - if (string && *string) - return string -; else - g_free (string); - - g_object_get(simple->card, - "full_name", &string, - NULL); - if (string && *string) - return g_strdup(string); - else - g_free (string); - - g_object_get(simple->card, - "org", &string, - NULL); - if (string && *string) - return g_strdup(string); - else - g_free (string); - - is_list = e_card_evolution_list (simple->card); - if (is_list) - string = _("Unnamed List"); - else - string = e_card_simple_get_email(simple, - E_CARD_SIMPLE_EMAIL_ID_EMAIL); - return g_strdup(string); - } else - return NULL; - case E_CARD_SIMPLE_FIELD_FAMILY_NAME: - if (simple->card) { - g_object_get (simple->card, - "name", &name, - NULL); - return g_strdup (name->family); - } else - return NULL; - case E_CARD_SIMPLE_FIELD_GIVEN_NAME: - if (simple->card) { - g_object_get (simple->card, - "name", &name, - NULL); - return g_strdup (name->given); - } else - return NULL; - case E_CARD_SIMPLE_FIELD_ADDITIONAL_NAME: - if (simple->card) { - g_object_get (simple->card, - "name", &name, - NULL); - return g_strdup (name->additional); - } else - return NULL; - case E_CARD_SIMPLE_FIELD_NAME_SUFFIX: - if (simple->card) { - g_object_get (simple->card, - "name", &name, - NULL); - return g_strdup (name->suffix); - } else - return NULL; - default: - return NULL; - } - default: - return NULL; - } -} - -static char * -name_to_style(const ECardName *name, char *company, int style) -{ - char *string; - char *strings[4], **stringptr; - char *substring; - switch (style) { - case 0: - stringptr = strings; - if (name->family && *name->family) - *(stringptr++) = name->family; - if (name->given && *name->given) - *(stringptr++) = name->given; - *stringptr = NULL; - string = g_strjoinv(", ", strings); - break; - case 1: - stringptr = strings; - if (name->given && *name->given) - *(stringptr++) = name->given; - if (name->family && *name->family) - *(stringptr++) = name->family; - *stringptr = NULL; - string = g_strjoinv(" ", strings); - break; - case 2: - string = g_strdup(company); - break; - case 3: /* Fall Through */ - case 4: - stringptr = strings; - if (name->family && *name->family) - *(stringptr++) = name->family; - if (name->given && *name->given) - *(stringptr++) = name->given; - *stringptr = NULL; - substring = g_strjoinv(", ", strings); - if (!(company && *company)) - company = ""; - if (style == 3) - string = g_strdup_printf("%s (%s)", substring, company); - else - string = g_strdup_printf("%s (%s)", company, substring); - g_free(substring); - break; - default: - string = g_strdup(""); - } - return string; -} - -static int -file_as_get_style (ECardSimple *simple) -{ - char *filestring = e_card_simple_get(simple, E_CARD_SIMPLE_FIELD_FILE_AS); - char *trystring; - char *company = e_card_simple_get(simple, E_CARD_SIMPLE_FIELD_ORG); - ECardName *name = NULL; - int i; - int style; - style = 0; - if (!company) - company = g_strdup(""); - if (filestring) { - g_object_get (simple->card, - "name", &name, - NULL); - - if (!name) { - goto end; - } - - style = -1; - - for (i = 0; i < 5; i++) { - trystring = name_to_style(name, company, i); - if (!strcmp(trystring, filestring)) { - g_free(trystring); - style = i; - goto end; - } - g_free(trystring); - } - } - end: - - g_free(filestring); - g_free(company); - - return style; -} - -static void -file_as_set_style(ECardSimple *simple, int style) -{ - if (style != -1) { - char *string; - char *company = e_card_simple_get(simple, E_CARD_SIMPLE_FIELD_ORG); - ECardName *name; - - if (!company) - company = g_strdup(""); - g_object_get (simple->card, - "name", &name, - NULL); - if (name) { - string = name_to_style(name, company, style); - e_card_simple_set(simple, E_CARD_SIMPLE_FIELD_FILE_AS, string); - g_free(string); - } - g_free(company); - } -} - -void e_card_simple_set (ECardSimple *simple, - ECardSimpleField field, - const char *data) -{ - ECardSimpleInternalType type = field_data[field].type; - ECardAddrLabel *address; - ECardPhone *phone; - int style; - simple->changed = TRUE; - switch (field) { - case E_CARD_SIMPLE_FIELD_FULL_NAME: - case E_CARD_SIMPLE_FIELD_ORG: - style = file_as_get_style(simple); - g_object_set(simple->card, - field_data[field].ecard_field, data, - NULL); - file_as_set_style(simple, style); - break; - default: - switch(type) { - case E_CARD_SIMPLE_INTERNAL_TYPE_STRING: - g_object_set(simple->card, - field_data[field].ecard_field, data, - NULL); - break; - case E_CARD_SIMPLE_INTERNAL_TYPE_DATE: - break; /* FIXME!!!! */ - case E_CARD_SIMPLE_INTERNAL_TYPE_ADDRESS: - address = e_card_address_label_new(); - address->data = g_strdup (data); - e_card_simple_set_address(simple, - field_data[field].list_type_index, - address); - e_card_address_label_unref(address); - break; - case E_CARD_SIMPLE_INTERNAL_TYPE_PHONE: - phone = e_card_phone_new(); - phone->number = g_strdup (data); - e_card_simple_set_phone(simple, - field_data[field].list_type_index, - phone); - e_card_phone_unref(phone); - break; - case E_CARD_SIMPLE_INTERNAL_TYPE_EMAIL: - e_card_simple_set_email(simple, - field_data[field].list_type_index, - data); - break; - case E_CARD_SIMPLE_INTERNAL_TYPE_SPECIAL: - break; - case E_CARD_SIMPLE_INTERNAL_TYPE_BOOL: - if (simple->card) { - gboolean boole = TRUE; - if (data == NULL) - boole = FALSE; - else if (!strcasecmp (data, "false")) - boole = FALSE; - g_object_set (simple->card, - field_data[field].ecard_field, boole, - NULL); - } - break; - } - break; - } -} - -ECardSimpleType e_card_simple_type (ECardSimple *simple, - ECardSimpleField field) -{ - ECardSimpleInternalType type = field_data[field].type; - switch(type) { - case E_CARD_SIMPLE_INTERNAL_TYPE_STRING: - case E_CARD_SIMPLE_INTERNAL_TYPE_ADDRESS: - case E_CARD_SIMPLE_INTERNAL_TYPE_PHONE: - case E_CARD_SIMPLE_INTERNAL_TYPE_EMAIL: - default: - return E_CARD_SIMPLE_TYPE_STRING; - - case E_CARD_SIMPLE_INTERNAL_TYPE_BOOL: - return E_CARD_SIMPLE_TYPE_BOOL; - - case E_CARD_SIMPLE_INTERNAL_TYPE_DATE: - return E_CARD_SIMPLE_TYPE_DATE; - - case E_CARD_SIMPLE_INTERNAL_TYPE_SPECIAL: - return E_CARD_SIMPLE_TYPE_STRING; - } -} - -const char *e_card_simple_get_ecard_field (ECardSimple *simple, - ECardSimpleField field) -{ - return field_data[field].ecard_field; -} - -const char *e_card_simple_get_name (ECardSimple *simple, - ECardSimpleField field) -{ - return _(field_data[field].name); -} - -gboolean -e_card_simple_get_allow_newlines (ECardSimple *simple, - ECardSimpleField field) -{ - ECardSimpleInternalType type = field_data[field].type; - switch(type) { - case E_CARD_SIMPLE_INTERNAL_TYPE_STRING: - case E_CARD_SIMPLE_INTERNAL_TYPE_PHONE: - case E_CARD_SIMPLE_INTERNAL_TYPE_EMAIL: - case E_CARD_SIMPLE_INTERNAL_TYPE_BOOL: - case E_CARD_SIMPLE_INTERNAL_TYPE_DATE: - case E_CARD_SIMPLE_INTERNAL_TYPE_SPECIAL: - default: - switch (field) { - case E_CARD_SIMPLE_FIELD_NOTE: - return TRUE; - default: - return FALSE; - } - - case E_CARD_SIMPLE_INTERNAL_TYPE_ADDRESS: - return TRUE; - } -} - -const char *e_card_simple_get_short_name (ECardSimple *simple, - ECardSimpleField field) -{ - return _(field_data[field].short_name); -} - -void e_card_simple_arbitrary_foreach (ECardSimple *simple, - ECardSimpleArbitraryCallback *callback, - gpointer closure) -{ - if (simple->card) { - EList *list; - EIterator *iterator; - g_object_get(simple->card, - "arbitrary", &list, - NULL); - for (iterator = e_list_get_iterator(list); e_iterator_is_valid(iterator); e_iterator_next(iterator)) { - const ECardArbitrary *arbitrary = e_iterator_get(iterator); - if (callback) - (*callback) (arbitrary, closure); - } - - g_object_unref (list); - e_card_free_empty_lists (simple->card); - } -} - -const ECardArbitrary *e_card_simple_get_arbitrary (ECardSimple *simple, - const char *key) -{ - if (simple->card) { - EList *list; - EIterator *iterator; - g_object_get(simple->card, - "arbitrary", &list, - NULL); - for (iterator = e_list_get_iterator(list); e_iterator_is_valid(iterator); e_iterator_next(iterator)) { - const ECardArbitrary *arbitrary = e_iterator_get(iterator); - if (!strcasecmp(arbitrary->key, key)) - return arbitrary; - } - - g_object_unref (list); - e_card_free_empty_lists (simple->card); - } - return NULL; -} - -/* Any of these except key can be NULL */ -void e_card_simple_set_arbitrary (ECardSimple *simple, - const char *key, - const char *type, - const char *value) -{ - if (simple->card) { - ECardArbitrary *new_arb; - EList *list; - EIterator *iterator; - - simple->changed = TRUE; - g_object_get(simple->card, - "arbitrary", &list, - NULL); - for (iterator = e_list_get_iterator(list); e_iterator_is_valid(iterator); e_iterator_next(iterator)) { - const ECardArbitrary *arbitrary = e_iterator_get(iterator); - if (!strcasecmp(arbitrary->key, key)) { - new_arb = e_card_arbitrary_new(); - new_arb->key = g_strdup(key); - new_arb->type = g_strdup(type); - new_arb->value = g_strdup(value); - e_iterator_set(iterator, new_arb); - e_card_arbitrary_unref(new_arb); - return; - } - } - new_arb = e_card_arbitrary_new(); - new_arb->key = g_strdup(key); - new_arb->type = g_strdup(type); - new_arb->value = g_strdup(value); - e_list_append(list, new_arb); - g_object_unref(list); - e_card_arbitrary_unref(new_arb); - } -} - -void -e_card_simple_set_name (ECardSimple *simple, ECardName *name) -{ - int style; - style = file_as_get_style(simple); - g_object_set (simple->card, - "name", name, - NULL); - file_as_set_style(simple, style); -} - -/* These map between the individual list types and ECardSimpleField */ -ECardSimpleField -e_card_simple_map_phone_to_field (ECardSimplePhoneId phone_id) -{ - int i; - - g_return_val_if_fail (phone_id < E_CARD_SIMPLE_PHONE_ID_LAST, 0); - - for (i = 0; i < field_data_count; i ++) - if (field_data[i].list_type_index == phone_id - && field_data[i].type == E_CARD_SIMPLE_INTERNAL_TYPE_PHONE) - return i; - - g_warning ("couldn't find phone id %d, returning 0 (which is almost assuredly incorrect)\n", phone_id); - - return 0; -} - -ECardSimpleField -e_card_simple_map_email_to_field (ECardSimpleEmailId email_id) -{ - int i; - - g_return_val_if_fail (email_id < E_CARD_SIMPLE_EMAIL_ID_LAST, 0); - - for (i = 0; i < field_data_count; i ++) - if (field_data[i].list_type_index == email_id - && field_data[i].type == E_CARD_SIMPLE_INTERNAL_TYPE_EMAIL) - return i; - - g_warning ("couldn't find email id %d, returning 0 (which is almost assuredly incorrect)\n", email_id); - return 0; -} - -ECardSimpleField -e_card_simple_map_address_to_field (ECardSimpleAddressId address_id) -{ - int i; - - g_return_val_if_fail (address_id < E_CARD_SIMPLE_ADDRESS_ID_LAST, 0); - - for (i = 0; i < field_data_count; i ++) - if (field_data[i].list_type_index == address_id - && field_data[i].type == E_CARD_SIMPLE_INTERNAL_TYPE_ADDRESS) - return i; - - g_warning ("couldn't find address id %d, returning 0 (which is almost assuredly incorrect)\n", address_id); - return 0; -} diff --git a/addressbook/backend/ebook/e-card-simple.h b/addressbook/backend/ebook/e-card-simple.h deleted file mode 100644 index 868d4e1573..0000000000 --- a/addressbook/backend/ebook/e-card-simple.h +++ /dev/null @@ -1,234 +0,0 @@ -/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ -/* - * Authors: - * Chris Lahey - * Arturo Espinosa - * Nat Friedman (nat@ximian.com) - * - * Copyright (C) 2000 Ximian, Inc. - * Copyright (C) 1999 The Free Software Foundation - */ - -#ifndef __E_CARD_SIMPLE_H__ -#define __E_CARD_SIMPLE_H__ - -#include -#include -#include -#include -#include -#include - -#define E_TYPE_CARD_SIMPLE (e_card_simple_get_type ()) -#define E_CARD_SIMPLE(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), E_TYPE_CARD_SIMPLE, ECardSimple)) -#define E_CARD_SIMPLE_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), E_TYPE_CARD_SIMPLE, ECardSimpleClass)) -#define E_IS_CARD_SIMPLE(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), E_TYPE_CARD_SIMPLE)) -#define E_IS_CARD_SIMPLE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), E_TYPE_CARD_SIMPLE)) -#define E_CARD_SIMPLE_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), E_TYPE_CARD_SIMPLE, ECardSimpleClass)) - -typedef enum _ECardSimplePhoneId ECardSimplePhoneId; -typedef enum _ECardSimpleEmailId ECardSimpleEmailId; -typedef enum _ECardSimpleAddressId ECardSimpleAddressId; -typedef enum _ECardSimpleType ECardSimpleType; -typedef enum _ECardSimpleField ECardSimpleField; - -enum _ECardSimplePhoneId { - E_CARD_SIMPLE_PHONE_ID_ASSISTANT, - E_CARD_SIMPLE_PHONE_ID_BUSINESS, - E_CARD_SIMPLE_PHONE_ID_BUSINESS_2, - E_CARD_SIMPLE_PHONE_ID_BUSINESS_FAX, - E_CARD_SIMPLE_PHONE_ID_CALLBACK, - E_CARD_SIMPLE_PHONE_ID_CAR, - E_CARD_SIMPLE_PHONE_ID_COMPANY, - E_CARD_SIMPLE_PHONE_ID_HOME, - E_CARD_SIMPLE_PHONE_ID_HOME_2, - E_CARD_SIMPLE_PHONE_ID_HOME_FAX, - E_CARD_SIMPLE_PHONE_ID_ISDN, - E_CARD_SIMPLE_PHONE_ID_MOBILE, - E_CARD_SIMPLE_PHONE_ID_OTHER, - E_CARD_SIMPLE_PHONE_ID_OTHER_FAX, - E_CARD_SIMPLE_PHONE_ID_PAGER, - E_CARD_SIMPLE_PHONE_ID_PRIMARY, - E_CARD_SIMPLE_PHONE_ID_RADIO, - E_CARD_SIMPLE_PHONE_ID_TELEX, - E_CARD_SIMPLE_PHONE_ID_TTYTDD, - E_CARD_SIMPLE_PHONE_ID_LAST -}; - -/* We need HOME and WORK email addresses here. */ -enum _ECardSimpleEmailId { - E_CARD_SIMPLE_EMAIL_ID_EMAIL, - E_CARD_SIMPLE_EMAIL_ID_EMAIL_2, - E_CARD_SIMPLE_EMAIL_ID_EMAIL_3, - E_CARD_SIMPLE_EMAIL_ID_LAST -}; - -/* Should this include (BILLING/SHIPPING)? */ -enum _ECardSimpleAddressId { - E_CARD_SIMPLE_ADDRESS_ID_BUSINESS, - E_CARD_SIMPLE_ADDRESS_ID_HOME, - E_CARD_SIMPLE_ADDRESS_ID_OTHER, - E_CARD_SIMPLE_ADDRESS_ID_LAST -}; - -enum _ECardSimpleType { - E_CARD_SIMPLE_TYPE_STRING, - E_CARD_SIMPLE_TYPE_DATE, - E_CARD_SIMPLE_TYPE_BOOL, -}; - -enum _ECardSimpleField { - E_CARD_SIMPLE_FIELD_FILE_AS, - E_CARD_SIMPLE_FIELD_FULL_NAME, - E_CARD_SIMPLE_FIELD_EMAIL, - E_CARD_SIMPLE_FIELD_PHONE_PRIMARY, - E_CARD_SIMPLE_FIELD_PHONE_ASSISTANT, - E_CARD_SIMPLE_FIELD_PHONE_BUSINESS, - E_CARD_SIMPLE_FIELD_PHONE_CALLBACK, - E_CARD_SIMPLE_FIELD_PHONE_COMPANY, - E_CARD_SIMPLE_FIELD_PHONE_HOME, - E_CARD_SIMPLE_FIELD_ORG, - E_CARD_SIMPLE_FIELD_ADDRESS_BUSINESS, - E_CARD_SIMPLE_FIELD_ADDRESS_HOME, - E_CARD_SIMPLE_FIELD_PHONE_MOBILE, - E_CARD_SIMPLE_FIELD_PHONE_CAR, - E_CARD_SIMPLE_FIELD_PHONE_BUSINESS_FAX, - E_CARD_SIMPLE_FIELD_PHONE_HOME_FAX, - E_CARD_SIMPLE_FIELD_PHONE_BUSINESS_2, - E_CARD_SIMPLE_FIELD_PHONE_HOME_2, - E_CARD_SIMPLE_FIELD_PHONE_ISDN, - E_CARD_SIMPLE_FIELD_PHONE_OTHER, - E_CARD_SIMPLE_FIELD_PHONE_OTHER_FAX, - E_CARD_SIMPLE_FIELD_PHONE_PAGER, - E_CARD_SIMPLE_FIELD_PHONE_RADIO, - E_CARD_SIMPLE_FIELD_PHONE_TELEX, - E_CARD_SIMPLE_FIELD_PHONE_TTYTDD, - E_CARD_SIMPLE_FIELD_ADDRESS_OTHER, - E_CARD_SIMPLE_FIELD_EMAIL_2, - E_CARD_SIMPLE_FIELD_EMAIL_3, - E_CARD_SIMPLE_FIELD_URL, - E_CARD_SIMPLE_FIELD_ORG_UNIT, - E_CARD_SIMPLE_FIELD_OFFICE, - E_CARD_SIMPLE_FIELD_TITLE, - E_CARD_SIMPLE_FIELD_ROLE, - E_CARD_SIMPLE_FIELD_MANAGER, - E_CARD_SIMPLE_FIELD_ASSISTANT, - E_CARD_SIMPLE_FIELD_NICKNAME, - E_CARD_SIMPLE_FIELD_SPOUSE, - E_CARD_SIMPLE_FIELD_NOTE, - E_CARD_SIMPLE_FIELD_CALURI, - E_CARD_SIMPLE_FIELD_FBURL, - E_CARD_SIMPLE_FIELD_ICSCALENDAR, - /* If you add after icscalendar, make sure to move LAST_SIMPLE_STRING */ - E_CARD_SIMPLE_FIELD_LAST_SIMPLE_STRING = E_CARD_SIMPLE_FIELD_ICSCALENDAR, - E_CARD_SIMPLE_FIELD_ANNIVERSARY, - E_CARD_SIMPLE_FIELD_BIRTH_DATE, - E_CARD_SIMPLE_FIELD_MAILER, - E_CARD_SIMPLE_FIELD_NAME_OR_ORG, - E_CARD_SIMPLE_FIELD_CATEGORIES, - E_CARD_SIMPLE_FIELD_FAMILY_NAME, - E_CARD_SIMPLE_FIELD_GIVEN_NAME, - E_CARD_SIMPLE_FIELD_ADDITIONAL_NAME, - E_CARD_SIMPLE_FIELD_NAME_SUFFIX, - E_CARD_SIMPLE_FIELD_WANTS_HTML, - E_CARD_SIMPLE_FIELD_IS_LIST, - E_CARD_SIMPLE_FIELD_LAST -}; - -typedef struct _ECardSimple ECardSimple; -typedef struct _ECardSimpleClass ECardSimpleClass; - -struct _ECardSimple { - GObject object; - ECard *card; - - GList *temp_fields; - - ECardPhone *phone[E_CARD_SIMPLE_PHONE_ID_LAST]; - char *email[E_CARD_SIMPLE_EMAIL_ID_LAST]; - ECardAddrLabel *address[E_CARD_SIMPLE_ADDRESS_ID_LAST]; - ECardDeliveryAddress *delivery[E_CARD_SIMPLE_ADDRESS_ID_LAST]; - - gboolean changed; -}; - -struct _ECardSimpleClass { - GObjectClass parent_class; -}; - -typedef void (*ECardSimpleArbitraryCallback) (const ECardArbitrary *arbitrary, gpointer closure); -ECardSimple *e_card_simple_new (ECard *card); -const char *e_card_simple_get_id (ECardSimple *simple); -void e_card_simple_set_id (ECardSimple *simple, - const gchar *character); -char *e_card_simple_get_vcard (ECardSimple *simple); -char *e_card_simple_get_vcard_assume_utf8 (ECardSimple *simple); -ECardSimple *e_card_simple_duplicate (ECardSimple *simple); -char *e_card_simple_get (ECardSimple *simple, - ECardSimpleField field); -const char *e_card_simple_get_const (ECardSimple *simple, - ECardSimpleField field); -void e_card_simple_set (ECardSimple *simple, - ECardSimpleField field, - const char *data); -ECardSimpleType e_card_simple_type (ECardSimple *simple, - ECardSimpleField field); - -const char *e_card_simple_get_ecard_field (ECardSimple *simple, - ECardSimpleField field); -const char *e_card_simple_get_name (ECardSimple *simple, - ECardSimpleField field); -const char *e_card_simple_get_short_name (ECardSimple *simple, - ECardSimpleField field); -gboolean e_card_simple_get_allow_newlines (ECardSimple *simple, - ECardSimpleField field); - - -/* Use these only if building lists of specific types. It should be - * easier to use the above if you consider a phone field to be the - * same as any other field. - */ -const ECardPhone *e_card_simple_get_phone (ECardSimple *simple, - ECardSimplePhoneId id); -const char *e_card_simple_get_email (ECardSimple *simple, - ECardSimpleEmailId id); -const ECardAddrLabel *e_card_simple_get_address (ECardSimple *simple, - ECardSimpleAddressId id); -const ECardDeliveryAddress *e_card_simple_get_delivery_address (ECardSimple *simple, - ECardSimpleAddressId id); -void e_card_simple_set_phone (ECardSimple *simple, - ECardSimplePhoneId id, - const ECardPhone *phone); -void e_card_simple_set_email (ECardSimple *simple, - ECardSimpleEmailId id, - const char *email); -void e_card_simple_set_address (ECardSimple *simple, - ECardSimpleAddressId id, - const ECardAddrLabel *address); -void e_card_simple_set_delivery_address (ECardSimple *simple, - ECardSimpleAddressId id, - const ECardDeliveryAddress *delivery); -void e_card_simple_arbitrary_foreach (ECardSimple *simple, - ECardSimpleArbitraryCallback *callback, - gpointer closure); -const ECardArbitrary *e_card_simple_get_arbitrary (ECardSimple *simple, - const char *key); -/* Any of these except key can be NULL */ -void e_card_simple_set_arbitrary (ECardSimple *simple, - const char *key, - const char *type, - const char *value); -void e_card_simple_set_name (ECardSimple *simple, - ECardName *name); -void e_card_simple_sync_card (ECardSimple *simple); - -/* These map between the individual list types and ECardSimpleField */ -ECardSimpleField e_card_simple_map_phone_to_field (ECardSimplePhoneId phone_id); -ECardSimpleField e_card_simple_map_email_to_field (ECardSimpleEmailId email_id); -ECardSimpleField e_card_simple_map_address_to_field (ECardSimpleAddressId address_id); - -GType e_card_simple_get_type (void); - -#endif /* ! __E_CARD_SIMPLE_H__ */ - - diff --git a/addressbook/backend/ebook/e-card-types.h b/addressbook/backend/ebook/e-card-types.h deleted file mode 100644 index 8d35c54924..0000000000 --- a/addressbook/backend/ebook/e-card-types.h +++ /dev/null @@ -1,101 +0,0 @@ -/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ -/* - * Authors: - * Arturo Espinosa - * Nat Friedman (nat@ximian.com) - * - * Copyright (C) 2000 Ximian, Inc. - * Copyright (C) 1999 The Free Software Foundation - */ - -#ifndef __E_CARD_TYPES_H__ -#define __E_CARD_TYPES_H__ - -/* IDENTIFICATION PROPERTIES */ - -typedef struct { - gint ref_count; - char *prefix; /* Mr. */ - char *given; /* John */ - char *additional; /* Quinlan */ - char *family; /* Public */ - char *suffix; /* Esq. */ -} ECardName; - -typedef struct { - int year; - int month; - int day; -} ECardDate; - -/* TELECOMMUNICATIONS ADDRESSING PROPERTIES */ - -typedef enum { - E_CARD_PHONE_PREF = 1 << 0, - E_CARD_PHONE_WORK = 1 << 1, - E_CARD_PHONE_HOME = 1 << 2, - E_CARD_PHONE_VOICE = 1 << 3, - E_CARD_PHONE_FAX = 1 << 4, - E_CARD_PHONE_MSG = 1 << 5, - E_CARD_PHONE_CELL = 1 << 6, - E_CARD_PHONE_PAGER = 1 << 7, - E_CARD_PHONE_BBS = 1 << 8, - E_CARD_PHONE_MODEM = 1 << 9, - E_CARD_PHONE_CAR = 1 << 10, - E_CARD_PHONE_ISDN = 1 << 11, - E_CARD_PHONE_VIDEO = 1 << 12, - E_CARD_PHONE_ASSISTANT = 1 << 13, - E_CARD_PHONE_CALLBACK = 1 << 14, - E_CARD_PHONE_RADIO = 1 << 15, - E_CARD_PHONE_TELEX = 1 << 16, - E_CARD_PHONE_TTYTDD = 1 << 17, -} ECardPhoneFlags; - -typedef struct { - gint ref_count; - ECardPhoneFlags flags; - char *number; -} ECardPhone; - -/* DELIVERY ADDRESSING PROPERTIES */ - -typedef enum { - E_CARD_ADDR_HOME = 1 << 0, - E_CARD_ADDR_WORK = 1 << 1, - E_CARD_ADDR_POSTAL = 1 << 2, - E_CARD_ADDR_MASK = 7, - E_CARD_ADDR_PARCEL = 1 << 3, - E_CARD_ADDR_DOM = 1 << 4, - E_CARD_ADDR_INTL = 1 << 5, - E_CARD_ADDR_DEFAULT = 1 << 6 -} ECardAddressFlags; - -typedef struct { - gint ref_count; - ECardAddressFlags flags; - - char *po; - char *ext; - char *street; - char *city; - char *region; - char *code; - char *country; -} ECardDeliveryAddress; - -typedef struct { - gint ref_count; - ECardAddressFlags flags; - char *data; -} ECardAddrLabel; - -/* ARBITRARY PROPERTIES */ - -typedef struct { - gint ref_count; - char *key; - char *type; - char *value; -} ECardArbitrary; - -#endif /* __E_CARD_TYPES_H__ */ diff --git a/addressbook/backend/ebook/e-card.c b/addressbook/backend/ebook/e-card.c deleted file mode 100644 index 1b3bbfba88..0000000000 --- a/addressbook/backend/ebook/e-card.c +++ /dev/null @@ -1,2807 +0,0 @@ -/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ -/* - * Authors: - * Arturo Espinosa (arturo@nuclecu.unam.mx) - * Nat Friedman (nat@ximian.com) - * - * Copyright (C) 2000 Ximian, Inc. - * Copyright (C) 1999 The Free Software Foundation - */ - -#include - -#include "e-card.h" - -#include - -#include -#include -#include -#include -#include -#include - -#include -#include - -#include -#include "e-util/ename/e-name-western.h" -#include "e-util/ename/e-address-western.h" -#include "e-book.h" - -#define is_a_prop_of(obj,prop) (isAPropertyOf ((obj),(prop))) -#define str_val(obj) (the_str = (vObjectValueType (obj))? fakeCString (vObjectUStringZValue (obj)) : calloc (1, 1)) -#define has(obj,prop) (vo = isAPropertyOf ((obj), (prop))) - -#define XEV_WANTS_HTML "X-MOZILLA-HTML" -#define XEV_ARBITRARY "X-EVOLUTION-ARBITRARY" -#define XEV_LIST "X-EVOLUTION-LIST" -#define XEV_LIST_SHOW_ADDRESSES "X-EVOLUTION-LIST-SHOW_ADDRESSES" -#define XEV_RELATED_CONTACTS "X-EVOLUTION-RELATED_CONTACTS" - -/* Object property IDs */ -enum { - PROP_0, - PROP_FILE_AS, - PROP_FULL_NAME, - PROP_NAME, - PROP_ADDRESS, - PROP_ADDRESS_LABEL, - PROP_PHONE, - PROP_EMAIL, - PROP_BIRTH_DATE, - PROP_URL, - PROP_ORG, - PROP_ORG_UNIT, - PROP_OFFICE, - PROP_TITLE, - PROP_ROLE, - PROP_MANAGER, - PROP_ASSISTANT, - PROP_NICKNAME, - PROP_SPOUSE, - PROP_ANNIVERSARY, - PROP_MAILER, - PROP_CALURI, - PROP_FBURL, - PROP_ICSCALENDAR, - PROP_NOTE, - PROP_RELATED_CONTACTS, - PROP_CATEGORIES, - PROP_CATEGORY_LIST, - PROP_WANTS_HTML, - PROP_WANTS_HTML_SET, - PROP_EVOLUTION_LIST, - PROP_EVOLUTION_LIST_SHOW_ADDRESSES, - PROP_ARBITRARY, - PROP_ID, - PROP_LAST_USE, - PROP_USE_SCORE, -}; - -static GObjectClass *parent_class; - -static void parse(ECard *card, VObject *vobj, const char *default_charset); -static void e_card_init (ECard *card); -static void e_card_class_init (ECardClass *klass); - -static void e_card_dispose (GObject *object); -static void e_card_set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec); -static void e_card_get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec); - -static void assign_string(VObject *vobj, const char *default_charset, char **string); - -char *e_v_object_get_child_value(VObject *vobj, char *name, const char *default_charset); - -static void parse_bday(ECard *card, VObject *object, const char *default_charset); -static void parse_full_name(ECard *card, VObject *object, const char *default_charset); -static void parse_file_as(ECard *card, VObject *object, const char *default_charset); -static void parse_name(ECard *card, VObject *object, const char *default_charset); -static void parse_email(ECard *card, VObject *object, const char *default_charset); -static void parse_phone(ECard *card, VObject *object, const char *default_charset); -static void parse_address(ECard *card, VObject *object, const char *default_charset); -static void parse_address_label(ECard *card, VObject *object, const char *default_charset); -static void parse_url(ECard *card, VObject *object, const char *default_charset); -static void parse_org(ECard *card, VObject *object, const char *default_charset); -static void parse_office(ECard *card, VObject *object, const char *default_charset); -static void parse_title(ECard *card, VObject *object, const char *default_charset); -static void parse_role(ECard *card, VObject *object, const char *default_charset); -static void parse_manager(ECard *card, VObject *object, const char *default_charset); -static void parse_assistant(ECard *card, VObject *object, const char *default_charset); -static void parse_nickname(ECard *card, VObject *object, const char *default_charset); -static void parse_spouse(ECard *card, VObject *object, const char *default_charset); -static void parse_anniversary(ECard *card, VObject *object, const char *default_charset); -static void parse_mailer(ECard *card, VObject *object, const char *default_charset); -static void parse_caluri(ECard *card, VObject *object, const char *default_charset); -static void parse_fburl(ECard *card, VObject *object, const char *default_charset); -static void parse_icscalendar(ECard *card, VObject *object, const char *default_charset); -static void parse_note(ECard *card, VObject *object, const char *default_charset); -static void parse_related_contacts(ECard *card, VObject *object, const char *default_charset); -static void parse_categories(ECard *card, VObject *object, const char *default_charset); -static void parse_wants_html(ECard *card, VObject *object, const char *default_charset); -static void parse_list(ECard *card, VObject *object, const char *default_charset); -static void parse_list_show_addresses(ECard *card, VObject *object, const char *default_charset); -static void parse_arbitrary(ECard *card, VObject *object, const char *default_charset); -static void parse_id(ECard *card, VObject *object, const char *default_charset); -static void parse_last_use(ECard *card, VObject *object, const char *default_charset); -static void parse_use_score(ECard *card, VObject *object, const char *default_charset); - -static ECardPhoneFlags get_phone_flags (VObject *vobj); -static void set_phone_flags (VObject *vobj, ECardPhoneFlags flags); -static ECardAddressFlags get_address_flags (VObject *vobj); -static void set_address_flags (VObject *vobj, ECardAddressFlags flags); - -typedef void (* ParsePropertyFunc) (ECard *card, VObject *object, const char *default_charset); - -struct { - char *key; - ParsePropertyFunc function; -} attribute_jump_array[] = -{ - { VCFullNameProp, parse_full_name }, - { "X-EVOLUTION-FILE-AS", parse_file_as }, - { VCNameProp, parse_name }, - { VCBirthDateProp, parse_bday }, - { VCEmailAddressProp, parse_email }, - { VCTelephoneProp, parse_phone }, - { VCAdrProp, parse_address }, - { VCDeliveryLabelProp, parse_address_label }, - { VCURLProp, parse_url }, - { VCOrgProp, parse_org }, - { "X-EVOLUTION-OFFICE", parse_office }, - { VCTitleProp, parse_title }, - { VCBusinessRoleProp, parse_role }, - { "X-EVOLUTION-MANAGER", parse_manager }, - { "X-EVOLUTION-ASSISTANT", parse_assistant }, - { "NICKNAME", parse_nickname }, - { "X-EVOLUTION-SPOUSE", parse_spouse }, - { "X-EVOLUTION-ANNIVERSARY", parse_anniversary }, - { VCMailerProp, parse_mailer }, - { "CALURI", parse_caluri }, - { "FBURL", parse_fburl }, - { "ICSCALENDAR", parse_icscalendar }, - { VCNoteProp, parse_note }, - { XEV_RELATED_CONTACTS, parse_related_contacts }, - { "CATEGORIES", parse_categories }, - { XEV_WANTS_HTML, parse_wants_html }, - { XEV_ARBITRARY, parse_arbitrary }, - { VCUniqueStringProp, parse_id }, - { "X-EVOLUTION-LAST-USE", parse_last_use }, - { "X-EVOLUTION-USE-SCORE", parse_use_score }, - { XEV_LIST, parse_list }, - { XEV_LIST_SHOW_ADDRESSES, parse_list_show_addresses }, - { VCUniqueStringProp, parse_id } -}; - -/** - * e_card_get_type: - * @void: - * - * Registers the &ECard class if necessary, and returns the type ID - * associated to it. - * - * Return value: The type ID of the &ECard class. - **/ -GType -e_card_get_type (void) -{ - static GType card_type = 0; - - if (!card_type) { - static const GTypeInfo card_info = { - sizeof (ECardClass), - NULL, /* base_init */ - NULL, /* base_finalize */ - (GClassInitFunc) e_card_class_init, - NULL, /* class_finalize */ - NULL, /* class_data */ - sizeof (ECard), - 0, /* n_preallocs */ - (GInstanceInitFunc) e_card_init, - }; - - card_type = g_type_register_static (G_TYPE_OBJECT, "ECard", &card_info, 0); - } - - return card_type; -} - -ECard * -e_card_new_with_default_charset (const char *vcard, const char *default_charset) -{ - ECard *card = g_object_new (E_TYPE_CARD, NULL); - VObject *vobj = Parse_MIME(vcard, strlen(vcard)); - while(vobj) { - VObject *next; - parse(card, vobj, default_charset); - next = nextVObjectInList(vobj); - cleanVObject(vobj); - vobj = next; - } - if (card->name == NULL) - card->name = e_card_name_new(); - if (card->file_as == NULL) - card->file_as = g_strdup(""); - if (card->fname == NULL) - card->fname = g_strdup(""); - return card; -} - -/** - * e_card_new: - * @vcard: a string in vCard format - * - * Returns: a new #ECard that wraps the @vcard. - */ -ECard * -e_card_new (const char *vcard) -{ - return e_card_new_with_default_charset (vcard, "UTF-8"); -} - -ECard * -e_card_duplicate(ECard *card) -{ - char *vcard = e_card_get_vcard_assume_utf8(card); - ECard *new_card = e_card_new(vcard); - g_free (vcard); - - if (card->book) { - new_card->book = card->book; - g_object_ref (new_card->book); - } - - return new_card; -} - -static void -e_card_get_today (GDate *dt) -{ - time_t now; - struct tm *now_tm; - if (dt == NULL) - return; - - time (&now); - now_tm = localtime (&now); - - g_date_set_dmy (dt, now_tm->tm_mday, now_tm->tm_mon + 1, now_tm->tm_year + 1900); -} - -float -e_card_get_use_score(ECard *card) -{ - GDate today, last_use; - gint days_since_last_use; - - g_return_val_if_fail (card != NULL && E_IS_CARD (card), 0); - - if (card->last_use == NULL) - return 0.0; - - e_card_get_today (&today); - g_date_set_dmy (&last_use, card->last_use->day, card->last_use->month, card->last_use->year); - - days_since_last_use = g_date_get_julian (&today) - g_date_get_julian (&last_use); - - /* Apply a seven-day "grace period" to the use score decay. */ - days_since_last_use -= 7; - if (days_since_last_use < 0) - days_since_last_use = 0; - - return MAX (card->raw_use_score, 0) * exp (- days_since_last_use / 30.0); -} - -void -e_card_touch(ECard *card) -{ - GDate today; - double use_score; - - g_return_if_fail (card != NULL && E_IS_CARD (card)); - - e_card_get_today (&today); - use_score = e_card_get_use_score (card); - - if (card->last_use == NULL) - card->last_use = g_new (ECardDate, 1); - - card->last_use->day = g_date_get_day (&today); - card->last_use->month = g_date_get_month (&today); - card->last_use->year = g_date_get_year (&today); - - card->raw_use_score = use_score + 1.0; -} - -/** - * e_card_get_id: - * @card: an #ECard - * - * Returns: a string representing the id of the card, which is unique - * within its book. - */ -const char * -e_card_get_id (ECard *card) -{ - g_return_val_if_fail (card && E_IS_CARD (card), NULL); - - return card->id ? card->id : ""; -} - -/** - * e_card_get_id: - * @card: an #ECard - * @id: a id in string format - * - * Sets the identifier of a card, which should be unique within its - * book. - */ -void -e_card_set_id (ECard *card, const char *id) -{ - g_return_if_fail (card && E_IS_CARD (card)); - - if ( card->id ) - g_free(card->id); - card->id = g_strdup(id ? id : ""); -} - -EBook * -e_card_get_book (ECard *card) -{ - g_return_val_if_fail (card && E_IS_CARD (card), NULL); - - return card->book; -} - -void -e_card_set_book (ECard *card, EBook *book) -{ - g_return_if_fail (card && E_IS_CARD (card)); - - if (card->book) - g_object_unref (card->book); - card->book = book; - if (card->book) - g_object_ref (card->book); -} - -gchar * -e_card_date_to_string (ECardDate *dt) -{ - if (dt) - return g_strdup_printf ("%04d-%02d-%02d", - CLAMP(dt->year, 1000, 9999), - CLAMP(dt->month, 1, 12), - CLAMP(dt->day, 1, 31)); - else - return NULL; -} - -static VObject * -addPropValueUTF8(VObject *o, const char *p, const char *v) -{ - VObject *prop = addPropValue (o, p, v); - for (; *v; v++) { - if ((*v) & 0x80) { - addPropValue (prop, "CHARSET", "UTF-8"); - addProp(prop, VCQuotedPrintableProp); - - return prop; - } - if (*v == '\n') { - addProp(prop, VCQuotedPrintableProp); - for (; *v; v++) { - if ((*v) & 0x80) { - addPropValue (prop, "CHARSET", "UTF-8"); - return prop; - } - } - return prop; - } - } - return prop; -} - -static VObject * -addPropValueQP(VObject *o, const char *p, const char *v) -{ - VObject *prop = addPropValue (o, p, v); - for (; *v; v++) { - if (*v == '\n') { - addProp(prop, VCQuotedPrintableProp); - break; - } - } - return prop; -} - -static void -addPropValueSets (VObject *o, const char *p, const char *v, gboolean assumeUTF8, gboolean *is_ascii, gboolean *has_return) -{ - addPropValue (o, p, v); - if (*has_return && (assumeUTF8 || !*is_ascii)) - return; - if (*has_return) { - for (; *v; v++) { - if (*v & 0x80) { - *is_ascii = FALSE; - return; - } - } - return; - } - if (assumeUTF8 || !*is_ascii) { - for (; *v; v++) { - if (*v == '\n') { - *has_return = TRUE; - return; - } - } - return; - } - for (; *v; v++) { - if (*v & 0x80) { - *is_ascii = FALSE; - for (; *v; v++) { - if (*v == '\n') { - *has_return = TRUE; - return; - } - } - return; - } - if (*v == '\n') { - *has_return = TRUE; - for (; *v; v++) { - if (*v & 0x80) { - *is_ascii = FALSE; - return; - } - } - return; - } - } - return; -} - -#define ADD_PROP_VALUE(o, p, v) (assumeUTF8 ? (addPropValueQP ((o), (p), (v))) : addPropValueUTF8 ((o), (p), (v))) -#define ADD_PROP_VALUE_SET_IS_ASCII(o, p, v) (addPropValueSets ((o), (p), (v), assumeUTF8, &is_ascii, &has_return)) - - -static VObject * -e_card_get_vobject (const ECard *card, gboolean assumeUTF8) -{ - VObject *vobj; - - vobj = newVObject (VCCardProp); - - ADD_PROP_VALUE(vobj, VCVersionProp, "2.1"); - - if (card->file_as && *card->file_as) - ADD_PROP_VALUE(vobj, "X-EVOLUTION-FILE-AS", card->file_as); - else if (card->file_as) - addProp(vobj, "X-EVOLUTION-FILE_AS"); - - if (card->fname && *card->fname) - ADD_PROP_VALUE(vobj, VCFullNameProp, card->fname); - else if (card->fname) - addProp(vobj, VCFullNameProp); - - if ( card->name && (card->name->prefix || card->name->given || card->name->additional || card->name->family || card->name->suffix) ) { - VObject *nameprop; - gboolean is_ascii = TRUE; - gboolean has_return = FALSE; - nameprop = addProp(vobj, VCNameProp); - if ( card->name->prefix ) - ADD_PROP_VALUE_SET_IS_ASCII(nameprop, VCNamePrefixesProp, card->name->prefix); - if ( card->name->given ) - ADD_PROP_VALUE_SET_IS_ASCII(nameprop, VCGivenNameProp, card->name->given); - if ( card->name->additional ) - ADD_PROP_VALUE_SET_IS_ASCII(nameprop, VCAdditionalNamesProp, card->name->additional); - if ( card->name->family ) - ADD_PROP_VALUE_SET_IS_ASCII(nameprop, VCFamilyNameProp, card->name->family); - if ( card->name->suffix ) - ADD_PROP_VALUE_SET_IS_ASCII(nameprop, VCNameSuffixesProp, card->name->suffix); - if (has_return) - addProp(nameprop, VCQuotedPrintableProp); - if (!(is_ascii || assumeUTF8)) - addPropValue (nameprop, "CHARSET", "UTF-8"); - } - else if (card->name) - addProp(vobj, VCNameProp); - - - if ( card->address ) { - EIterator *iterator = e_list_get_iterator(card->address); - for ( ; e_iterator_is_valid(iterator) ;e_iterator_next(iterator) ) { - VObject *addressprop; - ECardDeliveryAddress *address = (ECardDeliveryAddress *) e_iterator_get(iterator); - gboolean is_ascii = TRUE; - gboolean has_return = FALSE; - - addressprop = addProp(vobj, VCAdrProp); - - set_address_flags (addressprop, address->flags); - if (address->po) - ADD_PROP_VALUE_SET_IS_ASCII(addressprop, VCPostalBoxProp, address->po); - if (address->ext) - ADD_PROP_VALUE_SET_IS_ASCII(addressprop, VCExtAddressProp, address->ext); - if (address->street) - ADD_PROP_VALUE_SET_IS_ASCII(addressprop, VCStreetAddressProp, address->street); - if (address->city) - ADD_PROP_VALUE_SET_IS_ASCII(addressprop, VCCityProp, address->city); - if (address->region) - ADD_PROP_VALUE_SET_IS_ASCII(addressprop, VCRegionProp, address->region); - if (address->code) - ADD_PROP_VALUE_SET_IS_ASCII(addressprop, VCPostalCodeProp, address->code); - if (address->country) - ADD_PROP_VALUE_SET_IS_ASCII(addressprop, VCCountryNameProp, address->country); - - if (has_return) - addProp(addressprop, VCQuotedPrintableProp); - if (!(is_ascii || assumeUTF8)) - addPropValue (addressprop, "CHARSET", "UTF-8"); - } - g_object_unref(iterator); - } - - if ( card->address_label ) { - EIterator *iterator = e_list_get_iterator(card->address_label); - for ( ; e_iterator_is_valid(iterator) ;e_iterator_next(iterator) ) { - VObject *labelprop; - ECardAddrLabel *address_label = (ECardAddrLabel *) e_iterator_get(iterator); - if (address_label->data) - labelprop = ADD_PROP_VALUE(vobj, VCDeliveryLabelProp, address_label->data); - else - labelprop = addProp(vobj, VCDeliveryLabelProp); - - set_address_flags (labelprop, address_label->flags); - } - g_object_unref(iterator); - } - - if ( card->phone ) { - EIterator *iterator = e_list_get_iterator(card->phone); - for ( ; e_iterator_is_valid(iterator) ;e_iterator_next(iterator) ) { - VObject *phoneprop; - ECardPhone *phone = (ECardPhone *) e_iterator_get(iterator); - phoneprop = ADD_PROP_VALUE(vobj, VCTelephoneProp, phone->number); - - set_phone_flags (phoneprop, phone->flags); - } - g_object_unref(iterator); - } - - if ( card->email ) { - EIterator *iterator = e_list_get_iterator(card->email); - for ( ; e_iterator_is_valid(iterator) ;e_iterator_next(iterator) ) { - VObject *emailprop; - emailprop = ADD_PROP_VALUE(vobj, VCEmailAddressProp, (char *) e_iterator_get(iterator)); - addProp (emailprop, VCInternetProp); - } - g_object_unref(iterator); - } - - if ( card->bday ) { - char *value; - value = e_card_date_to_string (card->bday); - ADD_PROP_VALUE(vobj, VCBirthDateProp, value); - g_free(value); - } - - if (card->url) - ADD_PROP_VALUE(vobj, VCURLProp, card->url); - - if (card->org || card->org_unit) { - VObject *orgprop; - gboolean is_ascii = TRUE; - gboolean has_return = FALSE; - orgprop = addProp(vobj, VCOrgProp); - - if (card->org) - ADD_PROP_VALUE_SET_IS_ASCII(orgprop, VCOrgNameProp, card->org); - if (card->org_unit) - ADD_PROP_VALUE_SET_IS_ASCII(orgprop, VCOrgUnitProp, card->org_unit); - - if (has_return) - addProp(orgprop, VCQuotedPrintableProp); - if (!(is_ascii || assumeUTF8)) - addPropValue (orgprop, "CHARSET", "UTF-8"); - } - - if (card->office) - ADD_PROP_VALUE(vobj, "X-EVOLUTION-OFFICE", card->office); - - if (card->title) - ADD_PROP_VALUE(vobj, VCTitleProp, card->title); - - if (card->role) - ADD_PROP_VALUE(vobj, VCBusinessRoleProp, card->role); - - if (card->manager) - ADD_PROP_VALUE(vobj, "X-EVOLUTION-MANAGER", card->manager); - - if (card->assistant) - ADD_PROP_VALUE(vobj, "X-EVOLUTION-ASSISTANT", card->assistant); - - if (card->nickname) - ADD_PROP_VALUE(vobj, "NICKNAME", card->nickname); - - if (card->spouse) - ADD_PROP_VALUE(vobj, "X-EVOLUTION-SPOUSE", card->spouse); - - if ( card->anniversary ) { - char *value; - value = e_card_date_to_string (card->anniversary); - ADD_PROP_VALUE(vobj, "X-EVOLUTION-ANNIVERSARY", value); - g_free(value); - } - - if (card->mailer) { - ADD_PROP_VALUE(vobj, VCMailerProp, card->mailer); - } - - if (card->caluri) - addPropValueQP(vobj, "CALURI", card->caluri); - - if (card->fburl) - ADD_PROP_VALUE(vobj, "FBURL", card->fburl); - - if (card->icscalendar) - ADD_PROP_VALUE(vobj, "ICSCALENDAR", card->icscalendar); - - if (card->note) { - VObject *noteprop; - - noteprop = ADD_PROP_VALUE(vobj, VCNoteProp, card->note); - } - - if (card->last_use) { - char *value; - value = e_card_date_to_string (card->last_use); - ADD_PROP_VALUE (vobj, "X-EVOLUTION-LAST-USE", value); - g_free (value); - } - - if (card->raw_use_score > 0) { - char *value; - value = g_strdup_printf ("%f", card->raw_use_score); - ADD_PROP_VALUE (vobj, "X-EVOLUTION-USE-SCORE", value); - g_free (value); - } - - if (card->related_contacts && *card->related_contacts) { - ADD_PROP_VALUE(vobj, XEV_RELATED_CONTACTS, card->related_contacts); - } - - if (card->categories) { - EIterator *iterator; - int length = 0; - char *string; - char *stringptr; - for (iterator = e_list_get_iterator(card->categories); e_iterator_is_valid(iterator); e_iterator_next(iterator)) { - length += strlen(e_iterator_get(iterator)) + 1; - } - string = g_new(char, length + 1); - stringptr = string; - *stringptr = 0; - for (e_iterator_reset(iterator); e_iterator_is_valid(iterator); e_iterator_next(iterator)) { - strcpy(stringptr, e_iterator_get(iterator)); - stringptr += strlen(stringptr); - *stringptr = ','; - stringptr++; - *stringptr = 0; - } - if (stringptr > string) { - stringptr --; - *stringptr = 0; - } - ADD_PROP_VALUE (vobj, "CATEGORIES", string); - g_free(string); - } - - if (card->wants_html_set) { - ADD_PROP_VALUE (vobj, XEV_WANTS_HTML, card->wants_html ? "TRUE" : "FALSE"); - } - - if (card->list) { - ADD_PROP_VALUE (vobj, XEV_LIST, "TRUE"); - ADD_PROP_VALUE (vobj, XEV_LIST_SHOW_ADDRESSES, card->list_show_addresses ? "TRUE" : "FALSE"); - } - - if (card->arbitrary) { - EIterator *iterator; - for (iterator = e_list_get_iterator(card->arbitrary); e_iterator_is_valid(iterator); e_iterator_next(iterator)) { - const ECardArbitrary *arbitrary = e_iterator_get(iterator); - VObject *arb_object; - if (arbitrary->value) { - arb_object = ADD_PROP_VALUE (vobj, XEV_ARBITRARY, arbitrary->value); - } else { - arb_object = addProp (vobj, XEV_ARBITRARY); - } - if (arbitrary->type) { - ADD_PROP_VALUE (arb_object, "TYPE", arbitrary->type); - } - if (arbitrary->key) { - addProp (arb_object, arbitrary->key); - } - } - } - - addPropValueQP (vobj, VCUniqueStringProp, (card->id ? card->id : "")); - - return vobj; -} - -/** - * e_card_get_vcard: - * @card: an #ECard - * - * Returns: a string in vCard format, which is wrapped by the @card. - */ -char * -e_card_get_vcard (ECard *card) -{ - VObject *vobj; - char *temp, *ret_val; - - vobj = e_card_get_vobject (card, FALSE); - temp = writeMemVObject(NULL, NULL, vobj); - ret_val = g_strdup(temp); - free(temp); - cleanVObject(vobj); - return ret_val; -} - -char * -e_card_get_vcard_assume_utf8 (ECard *card) -{ - VObject *vobj; - char *temp, *ret_val; - - vobj = e_card_get_vobject (card, TRUE); - temp = writeMemVObject(NULL, NULL, vobj); - ret_val = g_strdup(temp); - free(temp); - cleanVObject(vobj); - return ret_val; -} - -/** - * e_card_list_get_vcard: - * @list: a list of #ECards - * - * Returns: a string in vCard format. - */ -char * -e_card_list_get_vcard (const GList *list) -{ - VObject *vobj; - - char *temp, *ret_val; - - vobj = NULL; - - for (; list; list = list->next) { - VObject *tempvobj; - ECard *card = list->data; - - tempvobj = e_card_get_vobject (card, FALSE); - addList (&vobj, tempvobj); - } - temp = writeMemVObjects(NULL, NULL, vobj); - ret_val = g_strdup(temp); - free(temp); - cleanVObjects(vobj); - return ret_val; -} - -static void -parse_file_as(ECard *card, VObject *vobj, const char *default_charset) -{ - if ( card->file_as ) - g_free(card->file_as); - assign_string(vobj, default_charset, &(card->file_as)); -} - -static void -parse_name(ECard *card, VObject *vobj, const char *default_charset) -{ - e_card_name_unref(card->name); - - card->name = e_card_name_new(); - - card->name->family = e_v_object_get_child_value (vobj, VCFamilyNameProp, default_charset); - card->name->given = e_v_object_get_child_value (vobj, VCGivenNameProp, default_charset); - card->name->additional = e_v_object_get_child_value (vobj, VCAdditionalNamesProp, default_charset); - card->name->prefix = e_v_object_get_child_value (vobj, VCNamePrefixesProp, default_charset); - card->name->suffix = e_v_object_get_child_value (vobj, VCNameSuffixesProp, default_charset); -} - -static void -parse_full_name(ECard *card, VObject *vobj, const char *default_charset) -{ - if ( card->fname ) - g_free(card->fname); - assign_string(vobj, default_charset, &(card->fname)); -} - -static void -parse_email(ECard *card, VObject *vobj, const char *default_charset) -{ - char *next_email; - EList *list; - - assign_string(vobj, default_charset, &next_email); - g_object_get(card, - "email", &list, - NULL); - e_list_append(list, next_email); - g_free (next_email); - g_object_unref(list); -} - -/* Deal with charset */ -static void -parse_bday(ECard *card, VObject *vobj, const char *default_charset) -{ - if ( vObjectValueType (vobj) ) { - char *str = fakeCString (vObjectUStringZValue (vobj)); - if ( card->bday ) - g_free(card->bday); - card->bday = g_new(ECardDate, 1); - *(card->bday) = e_card_date_from_string(str); - free(str); - } -} - -static void -parse_phone(ECard *card, VObject *vobj, const char *default_charset) -{ - ECardPhone *next_phone = e_card_phone_new (); - EList *list; - - assign_string(vobj, default_charset, &(next_phone->number)); - next_phone->flags = get_phone_flags(vobj); - - g_object_get(card, - "phone", &list, - NULL); - e_list_append(list, next_phone); - e_card_phone_unref (next_phone); - g_object_unref(list); -} - -static void -parse_address(ECard *card, VObject *vobj, const char *default_charset) -{ - ECardDeliveryAddress *next_addr = e_card_delivery_address_new (); - EList *list; - - next_addr->flags = get_address_flags (vobj); - next_addr->po = e_v_object_get_child_value (vobj, VCPostalBoxProp, default_charset); - next_addr->ext = e_v_object_get_child_value (vobj, VCExtAddressProp, default_charset); - next_addr->street = e_v_object_get_child_value (vobj, VCStreetAddressProp, default_charset); - next_addr->city = e_v_object_get_child_value (vobj, VCCityProp, default_charset); - next_addr->region = e_v_object_get_child_value (vobj, VCRegionProp, default_charset); - next_addr->code = e_v_object_get_child_value (vobj, VCPostalCodeProp, default_charset); - next_addr->country = e_v_object_get_child_value (vobj, VCCountryNameProp, default_charset); - - g_object_get(card, - "address", &list, - NULL); - e_list_append(list, next_addr); - e_card_delivery_address_unref (next_addr); - g_object_unref(list); -} - -static void -parse_address_label(ECard *card, VObject *vobj, const char *default_charset) -{ - ECardAddrLabel *next_addr = e_card_address_label_new (); - EList *list; - - next_addr->flags = get_address_flags (vobj); - assign_string(vobj, default_charset, &next_addr->data); - - g_object_get(card, - "address_label", &list, - NULL); - e_list_append(list, next_addr); - e_card_address_label_unref (next_addr); - g_object_unref(list); -} - -static void -parse_url(ECard *card, VObject *vobj, const char *default_charset) -{ - if (card->url) - g_free(card->url); - assign_string(vobj, default_charset, &(card->url)); -} - -static void -parse_org(ECard *card, VObject *vobj, const char *default_charset) -{ - char *temp; - - temp = e_v_object_get_child_value(vobj, VCOrgNameProp, default_charset); - g_free(card->org); - card->org = temp; - - temp = e_v_object_get_child_value(vobj, VCOrgUnitProp, default_charset); - g_free(card->org_unit); - card->org_unit = temp; -} - -static void -parse_office(ECard *card, VObject *vobj, const char *default_charset) -{ - if ( card->office ) - g_free(card->office); - assign_string(vobj, default_charset, &(card->office)); -} - -static void -parse_title(ECard *card, VObject *vobj, const char *default_charset) -{ - if ( card->title ) - g_free(card->title); - assign_string(vobj, default_charset, &(card->title)); -} - -static void -parse_role(ECard *card, VObject *vobj, const char *default_charset) -{ - if (card->role) - g_free(card->role); - assign_string(vobj, default_charset, &(card->role)); -} - -static void -parse_manager(ECard *card, VObject *vobj, const char *default_charset) -{ - if ( card->manager ) - g_free(card->manager); - assign_string(vobj, default_charset, &(card->manager)); -} - -static void -parse_assistant(ECard *card, VObject *vobj, const char *default_charset) -{ - if ( card->assistant ) - g_free(card->assistant); - assign_string(vobj, default_charset, &(card->assistant)); -} - -static void -parse_nickname(ECard *card, VObject *vobj, const char *default_charset) -{ - if (card->nickname) - g_free(card->nickname); - assign_string(vobj, default_charset, &(card->nickname)); -} - -static void -parse_spouse(ECard *card, VObject *vobj, const char *default_charset) -{ - if ( card->spouse ) - g_free(card->spouse); - assign_string(vobj, default_charset, &(card->spouse)); -} - -/* Deal with charset */ -static void -parse_anniversary(ECard *card, VObject *vobj, const char *default_charset) -{ - if ( vObjectValueType (vobj) ) { - char *str = fakeCString (vObjectUStringZValue (vobj)); - if (card->anniversary) - g_free(card->anniversary); - card->anniversary = g_new(ECardDate, 1); - *(card->anniversary) = e_card_date_from_string(str); - free(str); - } -} - -static void -parse_mailer(ECard *card, VObject *vobj, const char *default_charset) -{ - if ( card->mailer ) - g_free(card->mailer); - assign_string(vobj, default_charset, &(card->mailer)); -} - -static void -parse_caluri(ECard *card, VObject *vobj, const char *default_charset) -{ - g_free(card->caluri); - assign_string(vobj, default_charset, &(card->caluri)); -} - -static void -parse_fburl(ECard *card, VObject *vobj, const char *default_charset) -{ - g_free(card->fburl); - assign_string(vobj, default_charset, &(card->fburl)); -} - -static void -parse_icscalendar(ECard *card, VObject *vobj, const char *default_charset) -{ - g_free(card->icscalendar); - assign_string(vobj, default_charset, &(card->icscalendar)); -} - -static void -parse_note(ECard *card, VObject *vobj, const char *default_charset) -{ - g_free(card->note); - assign_string(vobj, default_charset, &(card->note)); -} - -static void -parse_related_contacts(ECard *card, VObject *vobj, const char *default_charset) -{ - g_free(card->related_contacts); - assign_string(vobj, default_charset, &(card->related_contacts)); -} - -static void -add_list_unique(ECard *card, EList *list, char *string) -{ - char *temp = e_strdup_strip(string); - EIterator *iterator; - - if (!*temp) { - g_free(temp); - return; - } - for ( iterator = e_list_get_iterator(list); e_iterator_is_valid(iterator); e_iterator_next(iterator)) { - if (!strcmp(e_iterator_get(iterator), temp)) { - break; - } - } - if (!e_iterator_is_valid(iterator)) { - e_list_append(list, temp); - } - g_free(temp); - g_object_unref(iterator); -} - -static void -do_parse_categories(ECard *card, char *str) -{ - int length = strlen(str); - char *copy = g_new(char, length + 1); - int i, j; - EList *list; - g_object_get(card, - "category_list", &list, - NULL); - for (i = 0, j = 0; str[i]; i++, j++) { - switch (str[i]) { - case '\\': - i++; - if (str[i]) { - copy[j] = str[i]; - } else - i--; - break; - case ',': - copy[j] = 0; - add_list_unique(card, list, copy); - j = -1; - break; - default: - copy[j] = str[i]; - break; - } - } - copy[j] = 0; - add_list_unique(card, list, copy); - g_object_unref(list); - g_free(copy); -} - -/* Deal with charset */ -static void -parse_categories(ECard *card, VObject *vobj, const char *default_charset) -{ - if ( vObjectValueType (vobj) ) { - char *str = fakeCString (vObjectUStringZValue (vobj)); - do_parse_categories(card, str); - free(str); - } -} - -/* Deal with charset */ -static void -parse_wants_html(ECard *card, VObject *vobj, const char *default_charset) -{ - if ( vObjectValueType (vobj) ) { - char *str = fakeCString (vObjectUStringZValue (vobj)); - if (!strcasecmp(str, "true")) { - card->wants_html = TRUE; - card->wants_html_set = TRUE; - } - if (!strcasecmp(str, "false")) { - card->wants_html = FALSE; - card->wants_html_set = TRUE; - } - free(str); - } -} - -/* Deal with charset */ -static void -parse_list(ECard *card, VObject *vobj, const char *default_charset) -{ - if ( vObjectValueType (vobj) ) { - char *str = fakeCString (vObjectUStringZValue (vobj)); - if (!strcasecmp(str, "true")) { - card->list = TRUE; - } - if (!strcasecmp(str, "false")) { - card->list = FALSE; - } - free(str); - } -} - -/* Deal with charset */ -static void -parse_list_show_addresses(ECard *card, VObject *vobj, const char *default_charset) -{ - if ( vObjectValueType (vobj) ) { - char *str = fakeCString (vObjectUStringZValue (vobj)); - if (!strcasecmp(str, "true")) { - card->list_show_addresses = TRUE; - } - if (!strcasecmp(str, "false")) { - card->list_show_addresses = FALSE; - } - free(str); - } -} - -typedef union ValueItem { - const char *strs; - const wchar_t *ustrs; - unsigned int i; - unsigned long l; - void *any; - VObject *vobj; -} ValueItem; - -struct VObject { - VObject *next; - const char *id; - VObject *prop; - unsigned short valType; - ValueItem val; -}; - -static void -parse_arbitrary(ECard *card, VObject *vobj, const char *default_charset) -{ - ECardArbitrary *arbitrary = e_card_arbitrary_new(); - VObjectIterator iterator; - EList *list; - for ( initPropIterator (&iterator, vobj); moreIteration(&iterator); ) { - VObject *temp = nextVObject(&iterator); - const char *name = vObjectName(temp); - if (name && !strcmp(name, "TYPE")) { - g_free(arbitrary->type); - assign_string(temp, default_charset, &(arbitrary->type)); - } else { - g_free(arbitrary->key); - arbitrary->key = g_strdup(name); - } - } - - assign_string(vobj, default_charset, &(arbitrary->value)); - - g_object_get(card, - "arbitrary", &list, - NULL); - e_list_append(list, arbitrary); - e_card_arbitrary_unref(arbitrary); - g_object_unref(list); -} - -static void -parse_id(ECard *card, VObject *vobj, const char *default_charset) -{ - g_free(card->id); - assign_string(vobj, default_charset, &(card->id)); -} - -/* Deal with charset */ -static void -parse_last_use(ECard *card, VObject *vobj, const char *default_charset) -{ - if ( vObjectValueType (vobj) ) { - char *str = fakeCString (vObjectUStringZValue (vobj)); - g_free(card->last_use); - card->last_use = g_new(ECardDate, 1); - *(card->last_use) = e_card_date_from_string(str); - free(str); - } -} - -/* Deal with charset */ -static void -parse_use_score(ECard *card, VObject *vobj, const char *default_charset) -{ - card->raw_use_score = 0; - - if ( vObjectValueType (vobj) ) { - char *str = fakeCString (vObjectUStringZValue (vobj)); - card->raw_use_score = MAX(0, atof (str)); - free (str); - } -} - -static void -parse_attribute(ECard *card, VObject *vobj, const char *default_charset) -{ - ParsePropertyFunc function = g_hash_table_lookup(E_CARD_GET_CLASS(card)->attribute_jump_table, vObjectName(vobj)); - if ( function ) - function(card, vobj, default_charset); -} - -static void -parse(ECard *card, VObject *vobj, const char *default_charset) -{ - VObjectIterator iterator; - initPropIterator(&iterator, vobj); - while(moreIteration (&iterator)) { - parse_attribute(card, nextVObject(&iterator), default_charset); - } - if (!card->fname) { - card->fname = g_strdup(""); - } - if (!card->name) { - card->name = e_card_name_from_string(card->fname); - } - if (!card->file_as) { - ECardName *name = card->name; - char *strings[3], **stringptr; - char *string; - stringptr = strings; - if (name->family && *name->family) - *(stringptr++) = name->family; - if (name->given && *name->given) - *(stringptr++) = name->given; - *stringptr = NULL; - string = g_strjoinv(", ", strings); - card->file_as = string; - } -} - -static void -e_card_class_init (ECardClass *klass) -{ - int i; - GObjectClass *object_class; - - object_class = G_OBJECT_CLASS(klass); - - parent_class = g_type_class_ref (G_TYPE_OBJECT); - - klass->attribute_jump_table = g_hash_table_new(g_str_hash, g_str_equal); - - for ( i = 0; i < sizeof(attribute_jump_array) / sizeof(attribute_jump_array[0]); i++ ) { - g_hash_table_insert(klass->attribute_jump_table, attribute_jump_array[i].key, attribute_jump_array[i].function); - } - - object_class->dispose = e_card_dispose; - object_class->get_property = e_card_get_property; - object_class->set_property = e_card_set_property; - - g_object_class_install_property (object_class, PROP_FILE_AS, - g_param_spec_string ("file_as", - _("File As"), - /*_( */"XXX blurb" /*)*/, - NULL, - G_PARAM_READWRITE)); - - g_object_class_install_property (object_class, PROP_FULL_NAME, - g_param_spec_string ("full_name", - _("Full Name"), - /*_( */"XXX blurb" /*)*/, - NULL, - G_PARAM_READWRITE)); - - g_object_class_install_property (object_class, PROP_NAME, - g_param_spec_pointer ("name", - _("Name"), - /*_( */"XXX blurb" /*)*/, - G_PARAM_READWRITE)); - - g_object_class_install_property (object_class, PROP_ADDRESS, - g_param_spec_object ("address", - _("Address"), - /*_( */"XXX blurb" /*)*/, - E_TYPE_LIST, - G_PARAM_READABLE)); - - g_object_class_install_property (object_class, PROP_ADDRESS_LABEL, - g_param_spec_object ("address_label", - _("Address Label"), - /*_( */"XXX blurb" /*)*/, - E_TYPE_LIST, - G_PARAM_READABLE)); - - g_object_class_install_property (object_class, PROP_PHONE, - g_param_spec_object ("phone", - _("Phone"), - /*_( */"XXX blurb" /*)*/, - E_TYPE_LIST, - G_PARAM_READABLE)); - - g_object_class_install_property (object_class, PROP_EMAIL, - g_param_spec_object ("email", - _("Email"), - /*_( */"XXX blurb" /*)*/, - E_TYPE_LIST, - G_PARAM_READABLE)); - - g_object_class_install_property (object_class, PROP_BIRTH_DATE, - g_param_spec_pointer ("birth_date", - _("Birth date"), - /*_( */"XXX blurb" /*)*/, - G_PARAM_READWRITE)); - - g_object_class_install_property (object_class, PROP_URL, - g_param_spec_string ("url", - _("URL"), - /*_( */"XXX blurb" /*)*/, - NULL, - G_PARAM_READWRITE)); - - g_object_class_install_property (object_class, PROP_ORG, - g_param_spec_string ("org", - _("Organization"), - /*_( */"XXX blurb" /*)*/, - NULL, - G_PARAM_READWRITE)); - - g_object_class_install_property (object_class, PROP_ORG_UNIT, - g_param_spec_string ("org_unit", - _("Organizational Unit"), - /*_( */"XXX blurb" /*)*/, - NULL, - G_PARAM_READWRITE)); - - g_object_class_install_property (object_class, PROP_OFFICE, - g_param_spec_string ("office", - _("Office"), - /*_( */"XXX blurb" /*)*/, - NULL, - G_PARAM_READWRITE)); - - g_object_class_install_property (object_class, PROP_TITLE, - g_param_spec_string ("title", - _("Title"), - /*_( */"XXX blurb" /*)*/, - NULL, - G_PARAM_READWRITE)); - - g_object_class_install_property (object_class, PROP_ROLE, - g_param_spec_string ("role", - _("Role"), - /*_( */"XXX blurb" /*)*/, - NULL, - G_PARAM_READWRITE)); - - g_object_class_install_property (object_class, PROP_MANAGER, - g_param_spec_string ("manager", - _("Manager"), - /*_( */"XXX blurb" /*)*/, - NULL, - G_PARAM_READWRITE)); - - g_object_class_install_property (object_class, PROP_ASSISTANT, - g_param_spec_string ("assistant", - _("Assistant"), - /*_( */"XXX blurb" /*)*/, - NULL, - G_PARAM_READWRITE)); - - g_object_class_install_property (object_class, PROP_NICKNAME, - g_param_spec_string ("nickname", - _("Nickname"), - /*_( */"XXX blurb" /*)*/, - NULL, - G_PARAM_READWRITE)); - - g_object_class_install_property (object_class, PROP_SPOUSE, - g_param_spec_string ("spouse", - _("Spouse"), - /*_( */"XXX blurb" /*)*/, - NULL, - G_PARAM_READWRITE)); - - g_object_class_install_property (object_class, PROP_ANNIVERSARY, - g_param_spec_pointer ("anniversary", - _("Anniversary"), - /*_( */"XXX blurb" /*)*/, - G_PARAM_READWRITE)); - - g_object_class_install_property (object_class, PROP_MAILER, - g_param_spec_string ("mailer", - _("Mailer"), - /*_( */"XXX blurb" /*)*/, - NULL, - G_PARAM_READWRITE)); - - g_object_class_install_property (object_class, PROP_CALURI, - g_param_spec_string ("caluri", - _("Calendar URI"), - /*_( */"XXX blurb" /*)*/, - NULL, - G_PARAM_READWRITE)); - - g_object_class_install_property (object_class, PROP_FBURL, - g_param_spec_string ("fburl", - _("Free/Busy URL"), - /*_( */"XXX blurb" /*)*/, - NULL, - G_PARAM_READWRITE)); - - g_object_class_install_property (object_class, PROP_ICSCALENDAR, - g_param_spec_string ("icscalendar", - _("ICS Calendar"), - /*_( */"XXX blurb" /*)*/, - NULL, - G_PARAM_READWRITE)); - - g_object_class_install_property (object_class, PROP_NOTE, - g_param_spec_string ("note", - _("Note"), - /*_( */"XXX blurb" /*)*/, - NULL, - G_PARAM_READWRITE)); - - g_object_class_install_property (object_class, PROP_RELATED_CONTACTS, - g_param_spec_string ("related_contacts", - _("Related Contacts"), - /*_( */"XXX blurb" /*)*/, - NULL, - G_PARAM_READWRITE)); - - g_object_class_install_property (object_class, PROP_CATEGORIES, - g_param_spec_string ("categories", - _("Categories"), - /*_( */"XXX blurb" /*)*/, - NULL, - G_PARAM_READWRITE)); - - g_object_class_install_property (object_class, PROP_CATEGORY_LIST, - g_param_spec_object ("category list", - _("Category List"), - /*_( */"XXX blurb" /*)*/, - E_TYPE_LIST, - G_PARAM_READWRITE)); - - g_object_class_install_property (object_class, PROP_WANTS_HTML, - g_param_spec_boolean ("wants_html", - _("Wants HTML"), - /*_( */"XXX blurb" /*)*/, - FALSE, - G_PARAM_READWRITE)); - - g_object_class_install_property (object_class, PROP_WANTS_HTML_SET, - g_param_spec_boolean ("wants_html_set", - _("Wants HTML set"), - /*_( */"XXX blurb" /*)*/, - FALSE, - G_PARAM_READABLE)); - - g_object_class_install_property (object_class, PROP_EVOLUTION_LIST, - g_param_spec_boolean ("list", - _("List"), - /*_( */"XXX blurb" /*)*/, - FALSE, - G_PARAM_READWRITE)); - - g_object_class_install_property (object_class, PROP_EVOLUTION_LIST_SHOW_ADDRESSES, - g_param_spec_boolean ("list_show_addresses", - _("List Show Addresses"), - /*_( */"XXX blurb" /*)*/, - FALSE, - G_PARAM_READWRITE)); - - g_object_class_install_property (object_class, PROP_ARBITRARY, - g_param_spec_object ("arbitrary", - _("Arbitrary"), - /*_( */"XXX blurb" /*)*/, - E_TYPE_LIST, - G_PARAM_READWRITE)); - - g_object_class_install_property (object_class, PROP_ID, - g_param_spec_string ("id", - _("ID"), - /*_( */"XXX blurb" /*)*/, - NULL, - G_PARAM_READWRITE)); - - g_object_class_install_property (object_class, PROP_LAST_USE, - g_param_spec_pointer ("last_use", - _("Last Use"), - /*_( */"XXX blurb" /*)*/, - G_PARAM_READWRITE)); - - g_object_class_install_property (object_class, PROP_USE_SCORE, - /* XXX at some point we - should remove - LAX_VALIDATION and figure - out some hard min & max - scores. */ - g_param_spec_float ("use_score", - _("Use Score"), - /*_( */"XXX blurb" /*)*/, - 0.0, - 0.0, - 0.0, - G_PARAM_READWRITE | G_PARAM_LAX_VALIDATION)); -} - -ECardPhone * -e_card_phone_new (void) -{ - ECardPhone *newphone = g_new(ECardPhone, 1); - - newphone->ref_count = 1; - newphone->number = NULL; - newphone->flags = 0; - - return newphone; -} - -void -e_card_phone_unref (ECardPhone *phone) -{ - if (phone) { - phone->ref_count --; - if (phone->ref_count == 0) { - g_free(phone->number); - g_free(phone); - } - } -} - -ECardPhone * -e_card_phone_ref (const ECardPhone *phone) -{ - ECardPhone *phone_mutable = (ECardPhone *) phone; - if (phone_mutable) - phone_mutable->ref_count ++; - return phone_mutable; -} - -ECardPhone * -e_card_phone_copy (const ECardPhone *phone) -{ - if ( phone ) { - ECardPhone *phone_copy = e_card_phone_new(); - phone_copy->number = g_strdup(phone->number); - phone_copy->flags = phone->flags; - return phone_copy; - } else - return NULL; -} - -ECardDeliveryAddress * -e_card_delivery_address_new (void) -{ - ECardDeliveryAddress *newaddr = g_new(ECardDeliveryAddress, 1); - - newaddr->ref_count = 1; - newaddr->po = NULL; - newaddr->ext = NULL; - newaddr->street = NULL; - newaddr->city = NULL; - newaddr->region = NULL; - newaddr->code = NULL; - newaddr->country = NULL; - newaddr->flags = 0; - - return newaddr; -} - -void -e_card_delivery_address_unref (ECardDeliveryAddress *addr) -{ - if ( addr ) { - addr->ref_count --; - if (addr->ref_count == 0) { - g_free(addr->po); - g_free(addr->ext); - g_free(addr->street); - g_free(addr->city); - g_free(addr->region); - g_free(addr->code); - g_free(addr->country); - g_free(addr); - } - } -} - -ECardDeliveryAddress * -e_card_delivery_address_ref (const ECardDeliveryAddress *addr) -{ - ECardDeliveryAddress *addr_mutable = (ECardDeliveryAddress *) addr; - if (addr_mutable) - addr_mutable->ref_count ++; - return addr_mutable; -} - -ECardDeliveryAddress * -e_card_delivery_address_copy (const ECardDeliveryAddress *addr) -{ - if ( addr ) { - ECardDeliveryAddress *addr_copy = e_card_delivery_address_new (); - addr_copy->po = g_strdup(addr->po ); - addr_copy->ext = g_strdup(addr->ext ); - addr_copy->street = g_strdup(addr->street ); - addr_copy->city = g_strdup(addr->city ); - addr_copy->region = g_strdup(addr->region ); - addr_copy->code = g_strdup(addr->code ); - addr_copy->country = g_strdup(addr->country); - addr_copy->flags = addr->flags; - return addr_copy; - } else - return NULL; -} - -gboolean -e_card_delivery_address_is_empty (const ECardDeliveryAddress *addr) -{ - return (((addr->po == NULL) || (*addr->po == 0)) && - ((addr->ext == NULL) || (*addr->ext == 0)) && - ((addr->street == NULL) || (*addr->street == 0)) && - ((addr->city == NULL) || (*addr->city == 0)) && - ((addr->region == NULL) || (*addr->region == 0)) && - ((addr->code == NULL) || (*addr->code == 0)) && - ((addr->country == NULL) || (*addr->country == 0))); -} - -ECardDeliveryAddress * -e_card_delivery_address_from_label(const ECardAddrLabel *label) -{ - ECardDeliveryAddress *addr = e_card_delivery_address_new (); - EAddressWestern *western = e_address_western_parse (label->data); - - addr->po = g_strdup (western->po_box ); - addr->ext = g_strdup (western->extended ); - addr->street = g_strdup (western->street ); - addr->city = g_strdup (western->locality ); - addr->region = g_strdup (western->region ); - addr->code = g_strdup (western->postal_code); - addr->country = g_strdup (western->country ); - addr->flags = label->flags; - - e_address_western_free(western); - - return addr; -} - -char * -e_card_delivery_address_to_string(const ECardDeliveryAddress *addr) -{ - char *strings[5], **stringptr = strings; - char *line1, *line22, *line2; - char *final; - if (addr->po && *addr->po) - *(stringptr++) = addr->po; - if (addr->street && *addr->street) - *(stringptr++) = addr->street; - *stringptr = NULL; - line1 = g_strjoinv(" ", strings); - stringptr = strings; - if (addr->region && *addr->region) - *(stringptr++) = addr->region; - if (addr->code && *addr->code) - *(stringptr++) = addr->code; - *stringptr = NULL; - line22 = g_strjoinv(" ", strings); - stringptr = strings; - if (addr->city && *addr->city) - *(stringptr++) = addr->city; - if (line22 && *line22) - *(stringptr++) = line22; - *stringptr = NULL; - line2 = g_strjoinv(", ", strings); - stringptr = strings; - if (line1 && *line1) - *(stringptr++) = line1; - if (addr->ext && *addr->ext) - *(stringptr++) = addr->ext; - if (line2 && *line2) - *(stringptr++) = line2; - if (addr->country && *addr->country) - *(stringptr++) = addr->country; - *stringptr = NULL; - final = g_strjoinv("\n", strings); - g_free(line1); - g_free(line22); - g_free(line2); - return final; -} - -ECardAddrLabel * -e_card_delivery_address_to_label (const ECardDeliveryAddress *addr) -{ - ECardAddrLabel *label; - label = e_card_address_label_new(); - label->flags = addr->flags; - label->data = e_card_delivery_address_to_string(addr); - - return label; -} - -ECardAddrLabel * -e_card_address_label_new (void) -{ - ECardAddrLabel *newaddr = g_new(ECardAddrLabel, 1); - - newaddr->ref_count = 1; - newaddr->data = NULL; - newaddr->flags = 0; - - return newaddr; -} - -void -e_card_address_label_unref (ECardAddrLabel *addr) -{ - if (addr) { - addr->ref_count --; - if (addr->ref_count == 0) { - g_free(addr->data); - g_free(addr); - } - } -} - -ECardAddrLabel * -e_card_address_label_ref (const ECardAddrLabel *addr) -{ - ECardAddrLabel *addr_mutable = (ECardAddrLabel *) addr; - if (addr_mutable) - addr_mutable->ref_count ++; - return addr_mutable; -} - -ECardAddrLabel * -e_card_address_label_copy (const ECardAddrLabel *addr) -{ - if ( addr ) { - ECardAddrLabel *addr_copy = e_card_address_label_new (); - addr_copy->data = g_strdup(addr->data); - addr_copy->flags = addr->flags; - return addr_copy; - } else - return NULL; -} - -ECardName *e_card_name_new(void) -{ - ECardName *newname = g_new(ECardName, 1); - - newname->ref_count = 1; - newname->prefix = NULL; - newname->given = NULL; - newname->additional = NULL; - newname->family = NULL; - newname->suffix = NULL; - - return newname; -} - -void -e_card_name_unref(ECardName *name) -{ - if (name) { - name->ref_count --; - if (name->ref_count == 0) { - g_free (name->prefix); - g_free (name->given); - g_free (name->additional); - g_free (name->family); - g_free (name->suffix); - g_free (name); - } - } -} - -ECardName * -e_card_name_ref(const ECardName *name) -{ - ECardName *name_mutable = (ECardName *) name; - if (name_mutable) - name_mutable->ref_count ++; - return name_mutable; -} - -ECardName * -e_card_name_copy(const ECardName *name) -{ - if (name) { - ECardName *newname = e_card_name_new (); - - newname->prefix = g_strdup(name->prefix); - newname->given = g_strdup(name->given); - newname->additional = g_strdup(name->additional); - newname->family = g_strdup(name->family); - newname->suffix = g_strdup(name->suffix); - - return newname; - } else - return NULL; -} - - -char * -e_card_name_to_string(const ECardName *name) -{ - char *strings[6], **stringptr = strings; - - g_return_val_if_fail (name != NULL, NULL); - - if (name->prefix && *name->prefix) - *(stringptr++) = name->prefix; - if (name->given && *name->given) - *(stringptr++) = name->given; - if (name->additional && *name->additional) - *(stringptr++) = name->additional; - if (name->family && *name->family) - *(stringptr++) = name->family; - if (name->suffix && *name->suffix) - *(stringptr++) = name->suffix; - *stringptr = NULL; - return g_strjoinv(" ", strings); -} - -ECardName * -e_card_name_from_string(const char *full_name) -{ - ECardName *name = e_card_name_new (); - ENameWestern *western = e_name_western_parse (full_name); - - name->prefix = g_strdup (western->prefix); - name->given = g_strdup (western->first ); - name->additional = g_strdup (western->middle); - name->family = g_strdup (western->last ); - name->suffix = g_strdup (western->suffix); - - e_name_western_free(western); - - return name; -} - -ECardArbitrary * -e_card_arbitrary_new(void) -{ - ECardArbitrary *arbitrary = g_new(ECardArbitrary, 1); - arbitrary->ref_count = 1; - arbitrary->key = NULL; - arbitrary->type = NULL; - arbitrary->value = NULL; - return arbitrary; -} - -void -e_card_arbitrary_unref(ECardArbitrary *arbitrary) -{ - if (arbitrary) { - arbitrary->ref_count --; - if (arbitrary->ref_count == 0) { - g_free(arbitrary->key); - g_free(arbitrary->type); - g_free(arbitrary->value); - g_free(arbitrary); - } - } -} - -ECardArbitrary * -e_card_arbitrary_copy(const ECardArbitrary *arbitrary) -{ - if (arbitrary) { - ECardArbitrary *arb_copy = e_card_arbitrary_new (); - arb_copy->key = g_strdup(arbitrary->key); - arb_copy->type = g_strdup(arbitrary->type); - arb_copy->value = g_strdup(arbitrary->value); - return arb_copy; - } else - return NULL; -} - -ECardArbitrary * -e_card_arbitrary_ref(const ECardArbitrary *arbitrary) -{ - ECardArbitrary *arbitrary_mutable = (ECardArbitrary *) arbitrary; - if (arbitrary_mutable) - arbitrary_mutable->ref_count ++; - return arbitrary_mutable; -} - -/* EMail matching */ -static gboolean -e_card_email_match_single_string (const gchar *a, const gchar *b) -{ - const gchar *xa = NULL, *xb = NULL; - gboolean match = TRUE; - - for (xa=a; *xa && *xa != '@'; ++xa); - for (xb=b; *xb && *xb != '@'; ++xb); - - if (xa-a != xb-b || *xa != *xb || g_ascii_strncasecmp (a, b, xa-a)) - return FALSE; - - if (*xa == '\0') - return TRUE; - - /* Find the end of the string, then walk through backwards comparing. - This is so that we'll match joe@foobar.com and joe@mail.foobar.com. - */ - while (*xa) - ++xa; - while (*xb) - ++xb; - - while (match && *xa != '@' && *xb != '@') { - match = (tolower (*xa) == tolower (*xb)); - --xa; - --xb; - } - - match = match && ((tolower (*xa) == tolower (*xb)) || (*xa == '.') || (*xb == '.')); - - return match; -} - -gboolean -e_card_email_match_string (const ECard *card, const gchar *str) -{ - EIterator *iter; - - g_return_val_if_fail (card && E_IS_CARD (card), FALSE); - g_return_val_if_fail (str != NULL, FALSE); - - if (!card->email) - return FALSE; - - iter = e_list_get_iterator (card->email); - for (e_iterator_reset (iter); e_iterator_is_valid (iter); e_iterator_next (iter)) { - if (e_card_email_match_single_string (e_iterator_get (iter), str)) - return TRUE; - } - g_object_unref (iter); - - return FALSE; -} - -gint -e_card_email_find_number (const ECard *card, const gchar *email) -{ - EIterator *iter; - gint count = 0; - - g_return_val_if_fail (E_IS_CARD (card), -1); - g_return_val_if_fail (email != NULL, -1); - - if (!card->email) - return -1; - - iter = e_list_get_iterator (card->email); - for (e_iterator_reset (iter); e_iterator_is_valid (iter); e_iterator_next (iter)) { - if (!g_ascii_strcasecmp (e_iterator_get (iter), email)) - goto finished; - ++count; - } - count = -1; - - finished: - g_object_unref (iter); - - return count; -} - -/* - * ECard lifecycle management and vCard loading/saving. - */ - -static void -e_card_dispose (GObject *object) -{ - ECard *card = E_CARD(object); - -#define FREE_IF(x) do { if ((x)) { g_free (x); x = NULL; } } while (0) -#define UNREF_IF(x) do { if ((x)) { g_object_unref (x); x = NULL; } } while (0) - - FREE_IF (card->id); - UNREF_IF (card->book); - FREE_IF(card->file_as); - FREE_IF(card->fname); - if (card->name) { - e_card_name_unref(card->name); - card->name = NULL; - } - FREE_IF(card->bday); - - FREE_IF(card->url); - FREE_IF(card->org); - FREE_IF(card->org_unit); - FREE_IF(card->office); - FREE_IF(card->title); - FREE_IF(card->role); - FREE_IF(card->manager); - FREE_IF(card->assistant); - FREE_IF(card->nickname); - FREE_IF(card->spouse); - FREE_IF(card->anniversary); - FREE_IF(card->caluri); - FREE_IF(card->fburl); - FREE_IF(card->icscalendar); - FREE_IF(card->last_use); - FREE_IF(card->note); - FREE_IF(card->related_contacts); - - UNREF_IF (card->categories); - UNREF_IF (card->email); - UNREF_IF (card->phone); - UNREF_IF (card->address); - UNREF_IF (card->address_label); - - if (G_OBJECT_CLASS (parent_class)->dispose) - G_OBJECT_CLASS (parent_class)->dispose (object); -} - - -/* Set_arg handler for the card */ -static void -e_card_set_property (GObject *object, - guint prop_id, - const GValue *value, - GParamSpec *pspec) -{ - ECard *card; - - card = E_CARD (object); - - switch (prop_id) { - case PROP_FILE_AS: - g_free(card->file_as); - card->file_as = g_strdup(g_value_get_string (value)); - if (card->file_as == NULL) - card->file_as = g_strdup(""); - break; - - case PROP_FULL_NAME: - g_free(card->fname); - card->fname = g_strdup(g_value_get_string (value)); - if (card->fname == NULL) - card->fname = g_strdup(""); - - e_card_name_unref (card->name); - card->name = e_card_name_from_string (card->fname); - break; - case PROP_NAME: - e_card_name_unref (card->name); - card->name = e_card_name_ref(g_value_get_pointer (value)); - if (card->name == NULL) - card->name = e_card_name_new(); - if (card->fname == NULL) { - card->fname = e_card_name_to_string(card->name); - } - if (card->file_as == NULL) { - ECardName *name = card->name; - char *strings[3], **stringptr; - char *string; - stringptr = strings; - if (name->family && *name->family) - *(stringptr++) = name->family; - if (name->given && *name->given) - *(stringptr++) = name->given; - *stringptr = NULL; - string = g_strjoinv(", ", strings); - card->file_as = string; - } - break; - case PROP_CATEGORIES: - if (card->categories) - g_object_unref(card->categories); - card->categories = NULL; - if (g_value_get_string (value)) - do_parse_categories(card, (char*)g_value_get_string (value)); - break; - case PROP_CATEGORY_LIST: - if (card->categories) - g_object_unref(card->categories); - card->categories = E_LIST(g_value_get_object(value)); - if (card->categories) - g_object_ref(card->categories); - break; - case PROP_BIRTH_DATE: - g_free(card->bday); - if (g_value_get_pointer (value)) { - card->bday = g_new (ECardDate, 1); - memcpy (card->bday, g_value_get_pointer (value), sizeof (ECardDate)); - } else { - card->bday = NULL; - } - break; - case PROP_URL: - g_free(card->url); - card->url = g_strdup(g_value_get_string(value)); - break; - case PROP_ORG: - g_free(card->org); - card->org = g_strdup(g_value_get_string(value)); - break; - case PROP_ORG_UNIT: - g_free(card->org_unit); - card->org_unit = g_strdup(g_value_get_string(value)); - break; - case PROP_OFFICE: - g_free(card->office); - card->office = g_strdup(g_value_get_string(value)); - break; - case PROP_TITLE: - g_free(card->title); - card->title = g_strdup(g_value_get_string(value)); - break; - case PROP_ROLE: - g_free(card->role); - card->role = g_strdup(g_value_get_string(value)); - break; - case PROP_MANAGER: - g_free(card->manager); - card->manager = g_strdup(g_value_get_string(value)); - break; - case PROP_ASSISTANT: - g_free(card->assistant); - card->assistant = g_strdup(g_value_get_string(value)); - break; - case PROP_NICKNAME: - g_free(card->nickname); - card->nickname = g_strdup(g_value_get_string(value)); - break; - case PROP_SPOUSE: - g_free(card->spouse); - card->spouse = g_strdup(g_value_get_string(value)); - break; - case PROP_ANNIVERSARY: - g_free(card->anniversary); - if (g_value_get_pointer (value)) { - card->anniversary = g_new (ECardDate, 1); - memcpy (card->anniversary, g_value_get_pointer (value), sizeof (ECardDate)); - } else { - card->anniversary = NULL; - } - break; - case PROP_MAILER: - g_free(card->mailer); - card->mailer = g_strdup(g_value_get_string(value)); - break; - case PROP_CALURI: - g_free(card->caluri); - card->caluri = g_strdup(g_value_get_string(value)); - break; - case PROP_FBURL: - g_free(card->fburl); - card->fburl = g_strdup(g_value_get_string(value)); - break; - case PROP_ICSCALENDAR: - g_free(card->icscalendar); - card->icscalendar = g_strdup(g_value_get_string(value)); - break; - case PROP_NOTE: - g_free (card->note); - card->note = g_strdup(g_value_get_string(value)); - break; - case PROP_RELATED_CONTACTS: - g_free (card->related_contacts); - card->related_contacts = g_strdup(g_value_get_string(value)); - break; - case PROP_WANTS_HTML: - card->wants_html = g_value_get_boolean (value); - card->wants_html_set = TRUE; - break; - case PROP_ARBITRARY: - if (card->arbitrary) - g_object_unref(card->arbitrary); - card->arbitrary = E_LIST(g_value_get_pointer(value)); - if (card->arbitrary) - g_object_ref(card->arbitrary); - break; - case PROP_ID: - g_free(card->id); - card->id = g_strdup(g_value_get_string(value)); - if (card->id == NULL) - card->id = g_strdup (""); - break; - case PROP_LAST_USE: - g_free(card->last_use); - if (g_value_get_pointer (value)) { - card->last_use = g_new (ECardDate, 1); - memcpy (card->last_use, g_value_get_pointer (value), sizeof (ECardDate)); - } else { - card->last_use = NULL; - } - break; - case PROP_USE_SCORE: - card->raw_use_score = g_value_get_float (value); - break; - case PROP_EVOLUTION_LIST: - card->list = g_value_get_boolean (value); - break; - case PROP_EVOLUTION_LIST_SHOW_ADDRESSES: - card->list_show_addresses = g_value_get_boolean (value); - break; - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); - break; - } -} - -/* Get_arg handler for the card */ -static void -e_card_get_property (GObject *object, - guint prop_id, - GValue *value, - GParamSpec *pspec) -{ - ECard *card; - - card = E_CARD (object); - - switch (prop_id) { - case PROP_FILE_AS: - g_value_set_string (value, card->file_as); - break; - case PROP_FULL_NAME: - g_value_set_string (value, card->fname); - break; - case PROP_NAME: - g_value_set_pointer (value, card->name); - break; - case PROP_ADDRESS: - if (!card->address) - card->address = e_list_new((EListCopyFunc) e_card_delivery_address_ref, - (EListFreeFunc) e_card_delivery_address_unref, - NULL); - g_value_set_object (value, card->address); - break; - case PROP_ADDRESS_LABEL: - if (!card->address_label) - card->address_label = e_list_new((EListCopyFunc) e_card_address_label_ref, - (EListFreeFunc) e_card_address_label_unref, - NULL); - g_value_set_object (value, card->address_label); - break; - case PROP_PHONE: - if (!card->phone) - card->phone = e_list_new((EListCopyFunc) e_card_phone_ref, - (EListFreeFunc) e_card_phone_unref, - NULL); - g_value_set_object (value, card->phone); - break; - case PROP_EMAIL: - if (!card->email) - card->email = e_list_new((EListCopyFunc) g_strdup, - (EListFreeFunc) g_free, - NULL); - g_value_set_object (value, card->email); - break; - case PROP_CATEGORIES: - { - int i; - char ** strs; - int length; - EIterator *iterator; - if (!card->categories) - card->categories = e_list_new((EListCopyFunc) g_strdup, - (EListFreeFunc) g_free, - NULL); - length = e_list_length(card->categories); - strs = g_new(char *, length + 1); - for (iterator = e_list_get_iterator(card->categories), i = 0; e_iterator_is_valid(iterator); e_iterator_next(iterator), i++) { - strs[i] = (char *)e_iterator_get(iterator); - } - strs[i] = 0; - g_value_set_string_take_ownership(value, g_strjoinv(", ", strs)); - g_free(strs); - } - break; - case PROP_CATEGORY_LIST: - if (!card->categories) - card->categories = e_list_new((EListCopyFunc) g_strdup, - (EListFreeFunc) g_free, - NULL); - g_value_set_object (value, card->categories); - break; - case PROP_BIRTH_DATE: - g_value_set_pointer (value, card->bday); - break; - case PROP_URL: - g_value_set_string (value, card->url); - break; - case PROP_ORG: - g_value_set_string (value, card->org); - break; - case PROP_ORG_UNIT: - g_value_set_string (value, card->org_unit); - break; - case PROP_OFFICE: - g_value_set_string (value, card->office); - break; - case PROP_TITLE: - g_value_set_string (value, card->title); - break; - case PROP_ROLE: - g_value_set_string (value, card->role); - break; - case PROP_MANAGER: - g_value_set_string (value, card->manager); - break; - case PROP_ASSISTANT: - g_value_set_string (value, card->assistant); - break; - case PROP_NICKNAME: - g_value_set_string (value, card->nickname); - break; - case PROP_SPOUSE: - g_value_set_string (value, card->spouse); - break; - case PROP_ANNIVERSARY: - g_value_set_pointer (value, card->anniversary); - break; - case PROP_MAILER: - g_value_set_string (value, card->mailer); - break; - case PROP_CALURI: - g_value_set_string (value, card->caluri); - break; - case PROP_FBURL: - g_value_set_string (value, card->fburl); - break; - case PROP_ICSCALENDAR: - g_value_set_string (value, card->icscalendar); - break; - case PROP_NOTE: - g_value_set_string (value, card->note); - break; - case PROP_RELATED_CONTACTS: - g_value_set_string (value, card->related_contacts); - break; - case PROP_WANTS_HTML: - g_value_set_boolean (value, card->wants_html); - break; - case PROP_WANTS_HTML_SET: - g_value_set_boolean (value, card->wants_html_set); - break; - case PROP_ARBITRARY: - if (!card->arbitrary) - card->arbitrary = e_list_new((EListCopyFunc) e_card_arbitrary_ref, - (EListFreeFunc) e_card_arbitrary_unref, - NULL); - - g_value_set_object (value, card->arbitrary); - break; - case PROP_ID: - g_value_set_string (value, card->id); - break; - case PROP_LAST_USE: - g_value_set_pointer (value, card->last_use); - break; - case PROP_USE_SCORE: - g_value_set_float (value, e_card_get_use_score (card)); - break; - case PROP_EVOLUTION_LIST: - g_value_set_boolean (value, card->list); - break; - case PROP_EVOLUTION_LIST_SHOW_ADDRESSES: - g_value_set_boolean (value, card->list_show_addresses); - break; - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); - break; - } -} - - -/** - * e_card_init: - */ -static void -e_card_init (ECard *card) -{ - card->id = g_strdup(""); - - card->file_as = NULL; - card->fname = NULL; - card->name = NULL; - card->bday = NULL; - card->email = NULL; - card->phone = NULL; - card->address = NULL; - card->address_label = NULL; - card->url = NULL; - card->org = NULL; - card->org_unit = NULL; - card->office = NULL; - card->title = NULL; - card->role = NULL; - card->manager = NULL; - card->assistant = NULL; - card->nickname = NULL; - card->spouse = NULL; - card->anniversary = NULL; - card->mailer = NULL; - card->caluri = NULL; - card->fburl = NULL; - card->icscalendar = NULL; - card->note = NULL; - card->related_contacts = NULL; - card->categories = NULL; - card->wants_html = FALSE; - card->wants_html_set = FALSE; - card->list = FALSE; - card->list_show_addresses = FALSE; - card->arbitrary = NULL; - card->last_use = NULL; - card->raw_use_score = 0; -} - -GList * -e_card_load_cards_from_file_with_default_charset(const char *filename, const char *default_charset) -{ - VObject *vobj = Parse_MIME_FromFileName((char *) filename); - GList *list = NULL; - while(vobj) { - VObject *next; - ECard *card = g_object_new (E_TYPE_CARD, NULL); - parse(card, vobj, default_charset); - next = nextVObjectInList(vobj); - cleanVObject(vobj); - vobj = next; - list = g_list_prepend(list, card); - } - list = g_list_reverse(list); - return list; -} - -GList * -e_card_load_cards_from_file(const char *filename) -{ - return e_card_load_cards_from_file_with_default_charset (filename, "UTF-8"); -} - -GList * -e_card_load_cards_from_string_with_default_charset(const char *str, const char *default_charset) -{ - VObject *vobj = Parse_MIME(str, strlen (str)); - GList *list = NULL; - while(vobj) { - VObject *next; - ECard *card = g_object_new (E_TYPE_CARD, NULL); - parse(card, vobj, default_charset); - next = nextVObjectInList(vobj); - cleanVObject(vobj); - vobj = next; - list = g_list_prepend(list, card); - } - list = g_list_reverse(list); - return list; -} - -GList * -e_card_load_cards_from_string(const char *str) -{ - return e_card_load_cards_from_string_with_default_charset (str, "UTF-8"); -} - -void -e_card_free_empty_lists (ECard *card) -{ - if (card->address && e_list_length (card->address) == 0) { - g_object_unref (card->address); - card->address = NULL; - } - - if (card->address_label && e_list_length (card->address_label) == 0) { - g_object_unref (card->address_label); - card->address_label = NULL; - } - - if (card->phone && e_list_length (card->phone) == 0) { - g_object_unref (card->phone); - card->phone = NULL; - } - - if (card->email && e_list_length (card->email) == 0) { - g_object_unref (card->email); - card->email = NULL; - } - - if (card->categories && e_list_length (card->categories) == 0) { - g_object_unref (card->categories); - card->categories = NULL; - } - - if (card->arbitrary && e_list_length (card->arbitrary) == 0) { - g_object_unref (card->arbitrary); - card->arbitrary = NULL; - } -} - -static void -assign_string(VObject *vobj, const char *default_charset, char **string) -{ - int type = vObjectValueType(vobj); - char *str; - const char *charset = default_charset; - char *charset_buf = NULL; - VObject *charset_obj; - - if ((charset_obj = isAPropertyOf (vobj, "CHARSET"))) { - switch (vObjectValueType (charset_obj)) { - case VCVT_STRINGZ: - charset = vObjectStringZValue(charset_obj); - break; - case VCVT_USTRINGZ: - charset_buf = fakeCString (vObjectUStringZValue (charset_obj)); - charset = charset_buf; - break; - } - } - - switch(type) { - case VCVT_STRINGZ: - if (strcmp (charset, "UTF-8")) - *string = e_utf8_from_charset_string (charset, vObjectStringZValue(vobj)); - else - *string = g_strdup(vObjectStringZValue(vobj)); - break; - case VCVT_USTRINGZ: - str = fakeCString (vObjectUStringZValue (vobj)); - if (strcmp (charset, "UTF-8")) - *string = e_utf8_from_charset_string (charset, str); - else - *string = g_strdup(str); - free(str); - break; - default: - *string = g_strdup(""); - break; - } - - if (charset_buf) { - free (charset_buf); - } -} - - -ECardDate -e_card_date_from_string (const char *str) -{ - ECardDate date; - int length; - - date.year = 0; - date.month = 0; - date.day = 0; - - length = strlen(str); - - if (length == 10 ) { - date.year = str[0] * 1000 + str[1] * 100 + str[2] * 10 + str[3] - '0' * 1111; - date.month = str[5] * 10 + str[6] - '0' * 11; - date.day = str[8] * 10 + str[9] - '0' * 11; - } else if ( length == 8 ) { - date.year = str[0] * 1000 + str[1] * 100 + str[2] * 10 + str[3] - '0' * 1111; - date.month = str[4] * 10 + str[5] - '0' * 11; - date.day = str[6] * 10 + str[7] - '0' * 11; - } - - return date; -} - -char * -e_v_object_get_child_value(VObject *vobj, char *name, const char *default_charset) -{ - char *ret_val; - VObjectIterator iterator; - char *charset_buf = NULL; - VObject *charset_obj; - - if ((charset_obj = isAPropertyOf (vobj, "CHARSET"))) { - switch (vObjectValueType (charset_obj)) { - case VCVT_STRINGZ: - default_charset = vObjectStringZValue(charset_obj); - break; - case VCVT_USTRINGZ: - charset_buf = fakeCString (vObjectUStringZValue (charset_obj)); - default_charset = charset_buf; - break; - } - } - - initPropIterator(&iterator, vobj); - while(moreIteration (&iterator)) { - VObject *attribute = nextVObject(&iterator); - const char *id = vObjectName(attribute); - if ( ! strcmp(id, name) ) { - assign_string(attribute, default_charset, &ret_val); - return ret_val; - } - } - if (charset_buf) - free (charset_buf); - - return NULL; -} - -static struct { - char *id; - ECardPhoneFlags flag; -} phone_pairs[] = { - { VCPreferredProp, E_CARD_PHONE_PREF }, - { VCWorkProp, E_CARD_PHONE_WORK }, - { VCHomeProp, E_CARD_PHONE_HOME }, - { VCVoiceProp, E_CARD_PHONE_VOICE }, - { VCFaxProp, E_CARD_PHONE_FAX }, - { VCMessageProp, E_CARD_PHONE_MSG }, - { VCCellularProp, E_CARD_PHONE_CELL }, - { VCPagerProp, E_CARD_PHONE_PAGER }, - { VCBBSProp, E_CARD_PHONE_BBS }, - { VCModemProp, E_CARD_PHONE_MODEM }, - { VCCarProp, E_CARD_PHONE_CAR }, - { VCISDNProp, E_CARD_PHONE_ISDN }, - { VCVideoProp, E_CARD_PHONE_VIDEO }, - { "X-EVOLUTION-ASSISTANT", E_CARD_PHONE_ASSISTANT }, - { "X-EVOLUTION-CALLBACK", E_CARD_PHONE_CALLBACK }, - { "X-EVOLUTION-RADIO", E_CARD_PHONE_RADIO }, - { "X-EVOLUTION-TELEX", E_CARD_PHONE_TELEX }, - { "X-EVOLUTION-TTYTDD", E_CARD_PHONE_TTYTDD }, -}; - -static ECardPhoneFlags -get_phone_flags (VObject *vobj) -{ - ECardPhoneFlags ret = 0; - int i; - - for (i = 0; i < sizeof(phone_pairs) / sizeof(phone_pairs[0]); i++) { - if (isAPropertyOf (vobj, phone_pairs[i].id)) { - ret |= phone_pairs[i].flag; - } - } - - return ret; -} - -static void -set_phone_flags (VObject *vobj, ECardPhoneFlags flags) -{ - int i; - - for (i = 0; i < sizeof(phone_pairs) / sizeof(phone_pairs[0]); i++) { - if (flags & phone_pairs[i].flag) { - addProp (vobj, phone_pairs[i].id); - } - } -} - -static struct { - char *id; - ECardAddressFlags flag; -} addr_pairs[] = { - { VCDomesticProp, E_CARD_ADDR_DOM }, - { VCInternationalProp, E_CARD_ADDR_INTL }, - { VCPostalProp, E_CARD_ADDR_POSTAL }, - { VCParcelProp, E_CARD_ADDR_PARCEL }, - { VCHomeProp, E_CARD_ADDR_HOME }, - { VCWorkProp, E_CARD_ADDR_WORK }, - { "PREF", E_CARD_ADDR_DEFAULT }, -}; - -static ECardAddressFlags -get_address_flags (VObject *vobj) -{ - ECardAddressFlags ret = 0; - int i; - - for (i = 0; i < sizeof(addr_pairs) / sizeof(addr_pairs[0]); i++) { - if (isAPropertyOf (vobj, addr_pairs[i].id)) { - ret |= addr_pairs[i].flag; - } - } - - return ret; -} - -static void -set_address_flags (VObject *vobj, ECardAddressFlags flags) -{ - int i; - - for (i = 0; i < sizeof(addr_pairs) / sizeof(addr_pairs[0]); i++) { - if (flags & addr_pairs[i].flag) { - addProp (vobj, addr_pairs[i].id); - } - } -} - -gboolean -e_card_evolution_list (ECard *card) -{ - g_return_val_if_fail (card && E_IS_CARD (card), FALSE); - return card->list; -} - -gboolean -e_card_evolution_list_show_addresses (ECard *card) -{ - g_return_val_if_fail (card && E_IS_CARD (card), FALSE); - return card->list_show_addresses; -} - -typedef struct _CardLoadData CardLoadData; -struct _CardLoadData { - gchar *card_id; - ECardCallback cb; - gpointer closure; -}; - -static void -get_card_cb (EBook *book, EBookStatus status, ECard *card, gpointer closure) -{ - CardLoadData *data = (CardLoadData *) closure; - - if (data->cb != NULL) { - if (status == E_BOOK_STATUS_SUCCESS) - data->cb (card, data->closure); - else - data->cb (NULL, data->closure); - } - - g_free (data->card_id); - g_free (data); -} - -static void -card_load_cb (EBook *book, EBookStatus status, gpointer closure) -{ - CardLoadData *data = (CardLoadData *) closure; - - if (status == E_BOOK_STATUS_SUCCESS) - e_book_get_card (book, data->card_id, get_card_cb, closure); - else { - data->cb (NULL, data->closure); - g_free (data->card_id); - g_free (data); - } -} - -void -e_card_load_uri (const gchar *book_uri, const gchar *uid, ECardCallback cb, gpointer closure) -{ - CardLoadData *data; - EBook *book; - - data = g_new (CardLoadData, 1); - data->card_id = g_strdup (uid); - data->cb = cb; - data->closure = closure; - - book = e_book_new (); - e_book_load_uri (book, book_uri, card_load_cb, data); -} diff --git a/addressbook/backend/ebook/e-card.h b/addressbook/backend/ebook/e-card.h deleted file mode 100644 index 8819966d5b..0000000000 --- a/addressbook/backend/ebook/e-card.h +++ /dev/null @@ -1,209 +0,0 @@ -/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ -/* - * Authors: - * Chris Lahey - * Arturo Espinosa - * Nat Friedman (nat@ximian.com) - * - * Copyright (C) 2000 Ximian, Inc. - * Copyright (C) 1999 The Free Software Foundation - */ - -#ifndef __E_CARD_H__ -#define __E_CARD_H__ - -#include -#include -#include -#include -#include - -#define E_TYPE_CARD (e_card_get_type ()) -#define E_CARD(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), E_TYPE_CARD, ECard)) -#define E_CARD_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), E_TYPE_CARD, ECardClass)) -#define E_IS_CARD(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), E_TYPE_CARD)) -#define E_IS_CARD_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), E_TYPE_CARD)) -#define E_CARD_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), E_TYPE_CARD, ECardClass)) - -typedef struct _ECard ECard; -typedef struct _ECardClass ECardClass; - -struct _EBook; /* Forward reference */ - -struct _ECard { - GObject object; - char *id; - - struct _EBook *book; /* The EBook this card is from. */ - - char *file_as; /* The File As field. */ - char *fname; /* The full name. */ - ECardName *name; /* The structured name. */ - EList *address; /* Delivery addresses (ECardDeliveryAddress *) */ - EList *address_label; /* Delivery address labels - * (ECardAddrLabel *) */ - - EList *phone; /* Phone numbers (ECardPhone *) */ - EList *email; /* Email addresses (char *) */ - char *url; /* The person's web page. */ - - ECardDate *bday; /* The person's birthday. */ - - char *note; - - - char *org; /* The person's organization. */ - char *org_unit; /* The person's organization unit. */ - char *office; /* The person's office. */ - char *role; /* The person's role w/in his org */ - char *title; /* The person's title w/in his org */ - - char *manager; - char *assistant; - - char *nickname; /* The person's nickname */ - - char *spouse; /* The person's spouse. */ - ECardDate *anniversary; /* The person's anniversary. */ - - char *mailer; /* Mailer */ - - char *caluri; /* Calendar URI */ - char *fburl; /* Free Busy URL */ - char *icscalendar; /* Default server calendar */ - - gint timezone; /* number of minutes from UTC as an int */ - - ECardDate *last_use; - float raw_use_score; - - char *related_contacts; /* EDestinationV (serialized) of related contacts. */ - - EList *categories; /* Categories. */ - - EList *arbitrary; /* Arbitrary fields. */ - - - - guint32 wants_html : 1; /* Wants html mail. */ - guint32 wants_html_set : 1; /* Wants html mail. */ - guint32 list : 1; /* If the card corresponds to a contact list */ - guint32 list_show_addresses : 1; /* Whether to show the addresses - in the To: or Bcc: field */ - -#if 0 - ECardPhoto *logo; /* This person's org's logo. */ - - ECardPhoto *photo; /* A photo of the person. */ - - ECard *agent; /* A person who sereves as this - guy's agent/secretary/etc. */ - - ECardSound *sound; - - ECardKey *key; /* The person's public key. */ - ECardTimeZone *timezn; /* The person's time zone. */ - ECardGeoPos *geopos; /* The person's long/lat. */ - - ECardRev *rev; /* The time this card was last - modified. */ - - EList xtension; -#endif -}; - -struct _ECardClass { - GObjectClass parent_class; - GHashTable *attribute_jump_table; -}; - - -/* Simple functions */ -ECard *e_card_new (const char *vcard); /* Assumes utf8 */ -ECard *e_card_new_with_default_charset (const char *vcard, - const char *default_charset); -const char *e_card_get_id (ECard *card); -void e_card_set_id (ECard *card, - const char *character); - -struct _EBook *e_card_get_book (ECard *card); -void e_card_set_book (ECard *card, - struct _EBook *book); -char *e_card_get_vcard (ECard *card); -char *e_card_get_vcard_assume_utf8 (ECard *card); -char *e_card_list_get_vcard (const GList *list); -ECard *e_card_duplicate (ECard *card); -float e_card_get_use_score (ECard *card); -void e_card_touch (ECard *card); - -/* Evolution List convenience functions */ -/* used for encoding uids in email addresses */ -gboolean e_card_evolution_list (ECard *card); -gboolean e_card_evolution_list_show_addresses (ECard *card); - -/* ECardPhone manipulation */ -ECardPhone *e_card_phone_new (void); -ECardPhone *e_card_phone_copy (const ECardPhone *phone); -ECardPhone *e_card_phone_ref (const ECardPhone *phone); -void e_card_phone_unref (ECardPhone *phone); - -/* ECardDeliveryAddress manipulation */ -ECardDeliveryAddress *e_card_delivery_address_new (void); -ECardDeliveryAddress *e_card_delivery_address_copy (const ECardDeliveryAddress *addr); -ECardDeliveryAddress *e_card_delivery_address_ref (const ECardDeliveryAddress *addr); -void e_card_delivery_address_unref (ECardDeliveryAddress *addr); -gboolean e_card_delivery_address_is_empty (const ECardDeliveryAddress *addr); -char *e_card_delivery_address_to_string (const ECardDeliveryAddress *addr); -ECardDeliveryAddress *e_card_delivery_address_from_label (const ECardAddrLabel *label); -ECardAddrLabel *e_card_delivery_address_to_label (const ECardDeliveryAddress *addr); - -/* ECardAddrLabel manipulation */ -ECardAddrLabel *e_card_address_label_new (void); -ECardAddrLabel *e_card_address_label_copy (const ECardAddrLabel *addr); -ECardAddrLabel *e_card_address_label_ref (const ECardAddrLabel *addr); -void e_card_address_label_unref (ECardAddrLabel *addr); - -/* ECardName manipulation */ -ECardName *e_card_name_new (void); -ECardName *e_card_name_copy (const ECardName *name); -ECardName *e_card_name_ref (const ECardName *name); -void e_card_name_unref (ECardName *name); -char *e_card_name_to_string (const ECardName *name); -ECardName *e_card_name_from_string (const char *full_name); - -/* ECardDate */ -ECardDate e_card_date_from_string (const gchar *str); -gchar *e_card_date_to_string (ECardDate *dt); - -/* ECardArbitrary manipulation */ -ECardArbitrary *e_card_arbitrary_new (void); -ECardArbitrary *e_card_arbitrary_copy (const ECardArbitrary *arbitrary); -ECardArbitrary *e_card_arbitrary_ref (const ECardArbitrary *arbitrary); -void e_card_arbitrary_unref (ECardArbitrary *arbitrary); - -/* ECard email manipulation */ -gboolean e_card_email_match_string (const ECard *card, - const gchar *str); -gint e_card_email_find_number (const ECard *card, - const gchar *email); - -/* Specialized functionality */ -GList *e_card_load_cards_from_file (const char *filename); -GList *e_card_load_cards_from_file_with_default_charset (const char *filename, - const char *default_charset); -GList *e_card_load_cards_from_string (const char *str); -GList *e_card_load_cards_from_string_with_default_charset (const char *str, - const char *default_charset); -void e_card_free_empty_lists (ECard *card); - -/* Getting ECards via their URIs */ -typedef void (*ECardCallback) (ECard *card, gpointer closure); -void e_card_load_uri (const gchar *book_uri, - const gchar *uid, - ECardCallback cb, - gpointer closure); - - -GType e_card_get_type (void); - -#endif /* ! __E_CARD_H__ */ diff --git a/addressbook/backend/ebook/e-contact.c b/addressbook/backend/ebook/e-contact.c new file mode 100644 index 0000000000..ce92b31f71 --- /dev/null +++ b/addressbook/backend/ebook/e-contact.c @@ -0,0 +1,1288 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ +/* e-contact.c + * + * Copyright (C) 2003 Ximian, Inc. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of version 2 of the GNU General Public + * License as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public + * License along with this program; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + * + * Author: Chris Toshok (toshok@ximian.com) + */ + +#include +#include +#include +#include +#include +#include +#include "e-contact.h" +#include "e-book.h" +#include "e-util/ename/e-name-western.h" + +struct _EContactPrivate { +}; + +#define E_CONTACT_FIELD_TYPE_STRING 0x00000001 /* used for simple single valued attributes */ +/*E_CONTACT_FIELD_TYPE_FLOAT*/ +#define E_CONTACT_FIELD_TYPE_LIST 0x00000002 /* used for multivalued single attributes - the elements are of type char* */ +#define E_CONTACT_FIELD_TYPE_MULTI 0x00000004 /* used for multivalued attributes - the elements are of type EVCardAttribute */ +#define E_CONTACT_FIELD_TYPE_STRUCT 0x00000008 /* used for structured types (N and ADR properties, in particular) */ +#define E_CONTACT_FIELD_TYPE_BOOLEAN 0x00000010 /* used for boolean types (WANTS_HTML) */ + +#define E_CONTACT_FIELD_TYPE_SYNTHETIC 0x10000000 /* used when there isn't a corresponding vcard field (such as email_1) */ +#define E_CONTACT_FIELD_TYPE_LIST_ELEM 0x20000000 /* used when a synthetic attribute is a numbered list element */ +#define E_CONTACT_FIELD_TYPE_MULTI_ELEM 0x40000000 /* used when we're looking for the nth attribute where more than 1 can be present in the vcard */ +#define E_CONTACT_FIELD_TYPE_ATTR_TYPE 0x80000000 /* used when a synthetic attribute is flagged with a TYPE= that we'll be looking for */ + +typedef struct { + guint32 t; + + EContactField field_id; + const char *vcard_field_name; + const char *field_name; /* non translated */ + const char *pretty_name; /* translated */ + + gboolean read_only; + + int list_elem; + const char *attr_type1; + const char *attr_type2; + + void* (*struct_getter)(EContact *contact, EVCardAttribute *attribute); + void (*struct_setter)(EContact *contact, EVCardAttribute *attribute, void *data); + +} EContactFieldInfo; + +static void* photo_getter (EContact *contact, EVCardAttribute *attr); +static void photo_setter (EContact *contact, EVCardAttribute *attr, void *data); +static void* fn_getter (EContact *contact, EVCardAttribute *attr); +static void fn_setter (EContact *contact, EVCardAttribute *attr, void *data); +static void* n_getter (EContact *contact, EVCardAttribute *attr); +static void n_setter (EContact *contact, EVCardAttribute *attr, void *data); +static void* adr_getter (EContact *contact, EVCardAttribute *attr); +static void adr_setter (EContact *contact, EVCardAttribute *attr, void *data); +static void* date_getter (EContact *contact, EVCardAttribute *attr); +static void date_setter (EContact *contact, EVCardAttribute *attr, void *data); + +#define STRING_FIELD(id,vc,n,pn,ro) { E_CONTACT_FIELD_TYPE_STRING, (id), (vc), (n), (pn), (ro) } +#define BOOLEAN_FIELD(id,vc,n,pn,ro) { E_CONTACT_FIELD_TYPE_BOOLEAN, (id), (vc), (n), (pn), (ro) } +#define LIST_FIELD(id,vc,n,pn,ro) { E_CONTACT_FIELD_TYPE_LIST, (id), (vc), (n), (pn), (ro) } +#define MULTI_LIST_FIELD(id,vc,n,pn,ro) { E_CONTACT_FIELD_TYPE_MULTI, (id), (vc), (n), (pn), (ro) } +#define STRUCT_FIELD(id,vc,n,pn,ro,get,set) { E_CONTACT_FIELD_TYPE_STRUCT, (id), (vc), (n), (pn), (ro), -1, NULL, NULL, (get), (set) } +#define LIST_ELEM_STR_FIELD(id,vc,n,pn,ro,nm) { E_CONTACT_FIELD_TYPE_LIST_ELEM | E_CONTACT_FIELD_TYPE_SYNTHETIC | E_CONTACT_FIELD_TYPE_STRING, (id), (vc), (n), (pn), (ro), (nm) } +#define MULTI_ELEM_STR_FIELD(id,vc,n,pn,ro,nm) { E_CONTACT_FIELD_TYPE_MULTI_ELEM | E_CONTACT_FIELD_TYPE_SYNTHETIC | E_CONTACT_FIELD_TYPE_STRING, (id), (vc), (n), (pn), (ro), (nm) } +#define ATTR_TYPE_STR_FIELD(id,vc,n,pn,ro,at1,nth) { E_CONTACT_FIELD_TYPE_ATTR_TYPE | E_CONTACT_FIELD_TYPE_SYNTHETIC | E_CONTACT_FIELD_TYPE_STRING, (id), (vc), (n), (pn), (ro), (nth), (at1), NULL } +#define ATTR2_TYPE_STR_FIELD(id,vc,n,pn,ro,at1,at2,nth) { E_CONTACT_FIELD_TYPE_ATTR_TYPE | E_CONTACT_FIELD_TYPE_SYNTHETIC | E_CONTACT_FIELD_TYPE_STRING, (id), (vc), (n), (pn), (ro), (nth), (at1), (at2) } +#define ATTR_TYPE_STRUCT_FIELD(id,vc,n,pn,ro,at,get,set) { E_CONTACT_FIELD_TYPE_ATTR_TYPE | E_CONTACT_FIELD_TYPE_SYNTHETIC | E_CONTACT_FIELD_TYPE_STRUCT, (id), (vc), (n), (pn), (ro), 0, (at), NULL, (get), (set) } + +static EContactFieldInfo field_info[] = { + STRING_FIELD (E_CONTACT_UID, EVC_UID, "id", N_("Unique ID"), FALSE), + STRING_FIELD (E_CONTACT_FILE_AS, EVC_X_FILE_AS, "file_as", N_("File As"), FALSE), + + /* Name fields */ + /* FN isn't really a structured field - we use a getter/setter + so we can set the N property (since evo 1.4 works fine with + vcards that don't even have a N attribute. *sigh*) */ + STRUCT_FIELD (E_CONTACT_FULL_NAME, EVC_FN, "full_name", N_("Full Name"), FALSE, fn_getter, fn_setter), + STRUCT_FIELD (E_CONTACT_NAME, EVC_N, "name", N_("Name"), FALSE, n_getter, n_setter), + LIST_ELEM_STR_FIELD (E_CONTACT_GIVEN_NAME, EVC_N, "given_name", N_("Given Name"), FALSE, 1), + LIST_ELEM_STR_FIELD (E_CONTACT_FAMILY_NAME, EVC_N, "family_name", N_("Family Name"), FALSE, 0), + STRING_FIELD (E_CONTACT_NICKNAME, EVC_NICKNAME, "nickname", N_("Nickname"), FALSE), + + /* Address fields */ + MULTI_LIST_FIELD (E_CONTACT_ADDRESS, EVC_ADR, "address", N_("Address List"), FALSE), + ATTR_TYPE_STRUCT_FIELD (E_CONTACT_ADDRESS_HOME, EVC_ADR, "address_home", N_("Home Address"), FALSE, "HOME", adr_getter, adr_setter), + ATTR_TYPE_STRUCT_FIELD (E_CONTACT_ADDRESS_WORK, EVC_ADR, "address_work", N_("Work Address"), FALSE, "WORK", adr_getter, adr_setter), + ATTR_TYPE_STRUCT_FIELD (E_CONTACT_ADDRESS_OTHER, EVC_ADR, "address_other", N_("Other Address"), FALSE, "OTHER", adr_getter, adr_setter), + + ATTR_TYPE_STR_FIELD (E_CONTACT_ADDRESS_LABEL_HOME, EVC_LABEL, "address_label_home", N_("Home Address Label"), FALSE, "HOME", 0), + ATTR_TYPE_STR_FIELD (E_CONTACT_ADDRESS_LABEL_WORK, EVC_LABEL, "address_label_work", N_("Work Address Label"), FALSE, "WORK", 0), + ATTR_TYPE_STR_FIELD (E_CONTACT_ADDRESS_LABEL_OTHER, EVC_LABEL, "address_label_other", N_("Other Address Label"), FALSE, "OTHER", 0), + + ATTR_TYPE_STR_FIELD (E_CONTACT_PHONE_ASSISTANT, EVC_TEL, "assistant_phone", N_("Assistant Phone"), FALSE, "X-EVOLUTION-ASSISTANT", 0), + ATTR2_TYPE_STR_FIELD (E_CONTACT_PHONE_BUSINESS, EVC_TEL, "business_phone", N_("Business Phone"), FALSE, "WORK", "VOICE", 0), + ATTR2_TYPE_STR_FIELD (E_CONTACT_PHONE_BUSINESS_2, EVC_TEL, "business_phone_2", N_("Business Phone 2"), FALSE, "WORK", "VOICE", 1), + ATTR2_TYPE_STR_FIELD (E_CONTACT_PHONE_BUSINESS_FAX, EVC_TEL, "business_fax", N_("Business Fax"), FALSE, "WORK", "FAX", 0), + ATTR_TYPE_STR_FIELD (E_CONTACT_PHONE_CALLBACK, EVC_TEL, "callback_phone", N_("Callback Phone"), FALSE, "X-EVOLUTION-CALLBACK", 0), + ATTR_TYPE_STR_FIELD (E_CONTACT_PHONE_CAR, EVC_TEL, "car_phone", N_("Car Phone"), FALSE, "CAR", 0), + ATTR2_TYPE_STR_FIELD (E_CONTACT_PHONE_COMPANY, EVC_TEL, "company_phone", N_("Company Phone"), FALSE, "WORK", "VOICE", 2), + ATTR2_TYPE_STR_FIELD (E_CONTACT_PHONE_HOME, EVC_TEL, "home_phone", N_("Home Phone"), FALSE, "HOME", "VOICE", 0), + ATTR2_TYPE_STR_FIELD (E_CONTACT_PHONE_HOME_2, EVC_TEL, "home_phone_2", N_("Home Phone 2"), FALSE, "HOME", "VOICE", 1), + ATTR2_TYPE_STR_FIELD (E_CONTACT_PHONE_HOME_FAX, EVC_TEL, "home_fax", N_("Home Fax"), FALSE, "HOME", "FAX", 0), + ATTR_TYPE_STR_FIELD (E_CONTACT_PHONE_ISDN, EVC_TEL, "isdn_phone", N_("ISDN"), FALSE, "ISDN", 0), + ATTR_TYPE_STR_FIELD (E_CONTACT_PHONE_MOBILE, EVC_TEL, "mobile_phone", N_("Mobile Phone"), FALSE, "CELL", 0), + ATTR_TYPE_STR_FIELD (E_CONTACT_PHONE_OTHER, EVC_TEL, "other_phone", N_("Other Phone"), FALSE, "VOICE", 0), /* XXX */ + ATTR_TYPE_STR_FIELD (E_CONTACT_PHONE_OTHER_FAX, EVC_TEL, "other_fax", N_("Other Fax"), FALSE, "FAX", 0), /* XXX */ + ATTR_TYPE_STR_FIELD (E_CONTACT_PHONE_PAGER, EVC_TEL, "pager", N_("Pager"), FALSE, "PAGER", 0), + ATTR_TYPE_STR_FIELD (E_CONTACT_PHONE_PRIMARY, EVC_TEL, "primary_phone", N_("Primary Phone"), FALSE, "PREF", 0), + ATTR_TYPE_STR_FIELD (E_CONTACT_PHONE_RADIO, EVC_TEL, "radio", N_("Radio"), FALSE, "X-EVOLUTION-RADIO", 0), + ATTR_TYPE_STR_FIELD (E_CONTACT_PHONE_TELEX, EVC_TEL, "telex", N_("Telex"), FALSE, "X-EVOLUTION-TELEX", 0), + ATTR_TYPE_STR_FIELD (E_CONTACT_PHONE_TTYTDD, EVC_TEL, "tty", N_("TTY"), FALSE, "X-EVOLUTION-TTYTDD", 0), + + /* Email fields */ + MULTI_LIST_FIELD (E_CONTACT_EMAIL, EVC_EMAIL, "email", N_("Email List"), FALSE), + MULTI_ELEM_STR_FIELD (E_CONTACT_EMAIL_1, EVC_EMAIL, "email_1", N_("Email 1"), FALSE, 0), + MULTI_ELEM_STR_FIELD (E_CONTACT_EMAIL_2, EVC_EMAIL, "email_2", N_("Email 2"), FALSE, 1), + MULTI_ELEM_STR_FIELD (E_CONTACT_EMAIL_3, EVC_EMAIL, "email_3", N_("Email 3"), FALSE, 2), + STRING_FIELD (E_CONTACT_MAILER, EVC_MAILER, "mailer", N_("Mailer"), FALSE), + BOOLEAN_FIELD (E_CONTACT_WANTS_HTML, EVC_X_WANTS_HTML, "wants_html", N_("Wants HTML Mail"), FALSE), + + /* Instant messaging fields */ + LIST_FIELD (E_CONTACT_IM_AIM, EVC_X_AIM, "im_aim", N_("AIM Screen Name List"), FALSE), + LIST_FIELD (E_CONTACT_IM_JABBER, EVC_X_JABBER, "im_jabber", N_("Jabber Id List"), FALSE), + LIST_FIELD (E_CONTACT_IM_YAHOO, EVC_X_YAHOO, "im_yahoo", N_("Yahoo! Screen Name List"), FALSE), + LIST_FIELD (E_CONTACT_IM_MSN, EVC_X_MSN, "im_msn", N_("MSN Screen Name List"), FALSE), + LIST_FIELD (E_CONTACT_IM_ICQ, EVC_X_ICQ, "im_icq", N_("ICQ Id List"), FALSE), + + /* Organizational fields */ + LIST_ELEM_STR_FIELD (E_CONTACT_ORG, EVC_ORG, "org", N_("Organization"), FALSE, 0), + LIST_ELEM_STR_FIELD (E_CONTACT_ORG_UNIT, EVC_ORG, "org_unit", N_("Organizational Unit"), FALSE, 1), + LIST_ELEM_STR_FIELD (E_CONTACT_OFFICE, EVC_ORG, "office", N_("Office"), FALSE, 2), + + STRING_FIELD (E_CONTACT_TITLE, EVC_TITLE, "title", N_("Title"), FALSE), + STRING_FIELD (E_CONTACT_ROLE, EVC_ROLE, "role", N_("Role"), FALSE), + STRING_FIELD (E_CONTACT_MANAGER, EVC_X_MANAGER, "manager", N_("Manager"), FALSE), + STRING_FIELD (E_CONTACT_ASSISTANT, EVC_X_ASSISTANT, "assistant", N_("Assistant"), FALSE), + + /* Web fields */ + STRING_FIELD (E_CONTACT_HOMEPAGE_URL, EVC_URL, "homepage_url", N_("Homepage URL"), FALSE), + STRING_FIELD (E_CONTACT_BLOG_URL, EVC_X_BLOG_URL, "blog_url", N_("Weblog URL"), FALSE), + + /* Photo/Logo */ + STRUCT_FIELD (E_CONTACT_PHOTO, EVC_PHOTO, "photo", N_("Photo"), FALSE, photo_getter, photo_setter), + STRUCT_FIELD (E_CONTACT_LOGO, EVC_LOGO, "logo", N_("Logo"), FALSE, photo_getter, photo_setter), + + /* Contact categories */ +#if notyet + LIST_FIELD (E_CONTACT_CATEGORY_LIST, EVC_CATEGORIES, "category_list", N_("Category List"), FALSE), + SYNTH_STR_FIELD (E_CONTACT_CATEGORIES, "categories", N_("Categories"), FALSE), +#else + STRING_FIELD (E_CONTACT_CATEGORIES, EVC_CATEGORIES, "categories", N_("Categories"), FALSE), +#endif + + /* Collaboration fields */ + STRING_FIELD (E_CONTACT_CALENDAR_URI, EVC_CALURI, "caluri", N_("Calendar URI"), FALSE), + STRING_FIELD (E_CONTACT_FREEBUSY_URL, EVC_FBURL, "fburl", N_("Free/Busy URL"), FALSE), + STRING_FIELD (E_CONTACT_ICS_CALENDAR, EVC_ICSCALENDAR, "icscalendar", N_("ICS Calendar"), FALSE), + + /* Misc fields */ + STRING_FIELD (E_CONTACT_SPOUSE, EVC_X_SPOUSE, "spouse", N_("Spouse's Name"), FALSE), + STRING_FIELD (E_CONTACT_NOTE, EVC_NOTE, "note", N_("Note"), FALSE), + + STRUCT_FIELD (E_CONTACT_BIRTH_DATE, EVC_BDAY, "birth_date", N_("Birth Date"), FALSE, date_getter, date_setter), + STRUCT_FIELD (E_CONTACT_ANNIVERSARY, EVC_BDAY, "anniversary", N_("Anniversary"), FALSE, date_getter, date_setter), + + BOOLEAN_FIELD (E_CONTACT_IS_LIST, EVC_X_LIST, "list", N_("List"), FALSE), + BOOLEAN_FIELD (E_CONTACT_LIST_SHOW_ADDRESSES, EVC_X_LIST_SHOW_ADDRESSES, "list_show_addresses", N_("List Show Addresses"), FALSE) +}; + +#undef LIST_ELEM_STR_FIELD +#undef STRING_FIELD +#undef SYNTH_STR_FIELD +#undef LIST_FIELD +#undef STRUCT_FIELD + +static GObjectClass *parent_class; + +static void e_contact_set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec); +static void e_contact_get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec); + +static void +e_contact_dispose (GObject *object) +{ + EContact *ec = E_CONTACT (object); + + if (!ec->priv) + return; + + /* XXX free instance specific stuff */ + + g_free (ec->priv); + ec->priv = NULL; + + if (G_OBJECT_CLASS (parent_class)->dispose) + G_OBJECT_CLASS (parent_class)->dispose (object); +} + +static void +e_contact_class_init (EContactClass *klass) +{ + GObjectClass *object_class; + int i; + + object_class = G_OBJECT_CLASS(klass); + + parent_class = g_type_class_ref (E_TYPE_VCARD); + + object_class->dispose = e_contact_dispose; + object_class->set_property = e_contact_set_property; + object_class->get_property = e_contact_get_property; + + for (i = 0; i < G_N_ELEMENTS (field_info); i ++) { + GParamSpec *pspec = NULL; + if (field_info[i].t & E_CONTACT_FIELD_TYPE_STRING) + pspec = g_param_spec_string (field_info[i].field_name, + _(field_info[i].pretty_name), + "" /* XXX blurb */, + NULL, + field_info[i].read_only ? G_PARAM_READABLE : G_PARAM_READWRITE); + else if (field_info[i].t & E_CONTACT_FIELD_TYPE_BOOLEAN) + pspec = g_param_spec_boolean (field_info[i].field_name, + _(field_info[i].pretty_name), + "" /* XXX blurb */, + FALSE, + field_info[i].read_only ? G_PARAM_READABLE : G_PARAM_READWRITE); + else + pspec = g_param_spec_pointer (field_info[i].field_name, + _(field_info[i].pretty_name), + "" /* XXX blurb */, + field_info[i].read_only ? G_PARAM_READABLE : G_PARAM_READWRITE); + + g_object_class_install_property (object_class, field_info[i].field_id, + pspec); + } +} + +static void +e_contact_init (EContact *ec) +{ + ec->priv = g_new0 (EContactPrivate, 1); +} + +GType +e_contact_get_type (void) +{ + static GType contact_type = 0; + + if (!contact_type) { + static const GTypeInfo contact_info = { + sizeof (EContactClass), + NULL, /* base_init */ + NULL, /* base_finalize */ + (GClassInitFunc) e_contact_class_init, + NULL, /* class_finalize */ + NULL, /* class_data */ + sizeof (EContact), + 0, /* n_preallocs */ + (GInstanceInitFunc) e_contact_init, + }; + + contact_type = g_type_register_static (E_TYPE_VCARD, "EContact", &contact_info, 0); + } + + return contact_type; +} + +static EVCardAttribute* +e_contact_get_first_attr (EContact *contact, const char *attr_name) +{ + GList *attrs, *l; + + attrs = e_vcard_get_attributes (E_VCARD (contact)); + + for (l = attrs; l; l = l->next) { + EVCardAttribute *attr = l->data; + const char *name, *group; + + group = e_vcard_attribute_get_group (attr); + name = e_vcard_attribute_get_name (attr); + + /* all the attributes we care about should be in group "" */ + if ((!group || !*group) && !strcasecmp (name, attr_name)) + return attr; + } + + return NULL; +} + + + +static void* +photo_getter (EContact *contact, EVCardAttribute *attr) +{ + if (attr) { + GList *values = e_vcard_attribute_get_values_decoded (attr); + + if (values && values->data) { + GString *s = values->data; + EContactPhoto *photo = g_new (EContactPhoto, 1); + + photo->length = s->len; + photo->data = g_malloc (photo->length); + memcpy (photo->data, s->str, photo->length); + + return photo; + } + } + + return NULL; +} + +static void +photo_setter (EContact *contact, EVCardAttribute *attr, void *data) +{ + EContactPhoto *photo = data; + const char *mime_type; + char *image_type = "X-EVOLUTION-UNKNOWN"; + + e_vcard_attribute_add_param_with_value (attr, + e_vcard_attribute_param_new (EVC_ENCODING), + "b"); + + mime_type = gnome_vfs_get_mime_type_for_data (photo->data, photo->length); + if (!strcmp (mime_type, "image/gif")) + image_type = "GIF"; + else if (!strcmp (mime_type, "image/jpeg")) + image_type = "JPEG"; + else if (!strcmp (mime_type, "image/png")) + image_type = "PNG"; + else if (!strcmp (mime_type, "image/tiff")) + image_type = "TIFF"; + /* i have no idea what these last 2 are.. :) */ + else if (!strcmp (mime_type, "image/ief")) + image_type = "IEF"; + else if (!strcmp (mime_type, "image/cgm")) + image_type = "CGM"; + + e_vcard_attribute_add_param_with_value (attr, + e_vcard_attribute_param_new (EVC_TYPE), + image_type); + + printf ("adding photo of type `%s' of length %d\n", image_type, photo->length); + e_vcard_attribute_add_value_decoded (attr, photo->data, photo->length); +} + + +static void* +fn_getter (EContact *contact, EVCardAttribute *attr) +{ + if (attr) { + GList *p = e_vcard_attribute_get_values (attr); + + return g_strdup (p && p->data ? p->data : ""); + } + else + return NULL; +} + +static void +fn_setter (EContact *contact, EVCardAttribute *attr, void *data) +{ + e_vcard_attribute_add_value (attr, (char*)data); + + attr = e_contact_get_first_attr (contact, EVC_N); + if (!attr) { + EContactName *name = e_contact_name_from_string ((char*)data); + + attr = e_vcard_attribute_new (NULL, EVC_N); + e_vcard_add_attribute (E_VCARD (contact), attr); + + /* call the setter directly */ + n_setter (contact, attr, name); + + e_contact_name_free (name); + } +} + + + +static void* +n_getter (EContact *contact, EVCardAttribute *attr) +{ + EContactName *name = g_new0 (EContactName, 1); + if (attr) { + GList *p = e_vcard_attribute_get_values (attr); + + name->family = g_strdup (p && p->data ? p->data : ""); if (p) p = p->next; + name->given = g_strdup (p && p->data ? p->data : ""); if (p) p = p->next; + name->additional = g_strdup (p && p->data ? p->data : ""); if (p) p = p->next; + name->prefixes = g_strdup (p && p->data ? p->data : ""); if (p) p = p->next; + name->suffixes = g_strdup (p && p->data ? p->data : ""); + } + + return name; +} + +static void +n_setter (EContact *contact, EVCardAttribute *attr, void *data) +{ + EContactName *name = data; + + e_vcard_attribute_add_value (attr, name->family); + e_vcard_attribute_add_value (attr, name->given); + e_vcard_attribute_add_value (attr, name->additional); + e_vcard_attribute_add_value (attr, name->prefixes); + e_vcard_attribute_add_value (attr, name->suffixes); + + /* now find the attribute for FileAs. if it's not present, fill it in */ + attr = e_contact_get_first_attr (contact, EVC_X_FILE_AS); + if (!attr) { + char *strings[3], **stringptr; + char *string; + attr = e_vcard_attribute_new (NULL, EVC_X_FILE_AS); + e_vcard_add_attribute (E_VCARD (contact), attr); + + stringptr = strings; + if (name->family && *name->family) + *(stringptr++) = name->family; + if (name->given && *name->given) + *(stringptr++) = name->given; + *stringptr = NULL; + string = g_strjoinv(", ", strings); + + e_vcard_attribute_add_value (attr, string); + g_free (string); + } + +} + + + +static void* +adr_getter (EContact *contact, EVCardAttribute *attr) +{ + if (attr) { + GList *p = e_vcard_attribute_get_values (attr); + EContactAddress *addr = g_new (EContactAddress, 1); + + addr->po = g_strdup (p && p->data ? p->data : ""); if (p) p = p->next; + addr->ext = g_strdup (p && p->data ? p->data : ""); if (p) p = p->next; + addr->street = g_strdup (p && p->data ? p->data : ""); if (p) p = p->next; + addr->locality = g_strdup (p && p->data ? p->data : ""); if (p) p = p->next; + addr->region = g_strdup (p && p->data ? p->data : ""); if (p) p = p->next; + addr->code = g_strdup (p && p->data ? p->data : ""); if (p) p = p->next; + addr->country = g_strdup (p && p->data ? p->data : ""); if (p) p = p->next; + + return addr; + } + + return NULL; +} + +static void +adr_setter (EContact *contact, EVCardAttribute *attr, void *data) +{ + /* XXX */ + g_assert_not_reached (); +} + + + +static void* +date_getter (EContact *contact, EVCardAttribute *attr) +{ + if (attr) { + GList *p = e_vcard_attribute_get_values (attr); + EContactDate *date = e_contact_date_from_string (p && p->data ? (char*)p->data : ""); + + return date; + } + + return NULL; +} + +static void +date_setter (EContact *contact, EVCardAttribute *attr, void *data) +{ + EContactDate *date = data; + char *str = e_contact_date_to_string (date); + + e_vcard_attribute_add_value (attr, str); + g_free (str); +} + + + +/* Set_arg handler for the contact */ +static void +e_contact_set_property (GObject *object, + guint prop_id, + const GValue *value, + GParamSpec *pspec) +{ + EContact *contact = E_CONTACT (object); + int i; + EContactFieldInfo *info = NULL; + + if (prop_id < 1 || prop_id >= E_CONTACT_FIELD_LAST) { + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + return; + } + + + for (i = 0; i < G_N_ELEMENTS (field_info); i++) { + if (field_info[i].field_id == prop_id) { + info = &field_info[i]; + break; + } + } + + if (!info) { + g_warning ("unknown field %d", prop_id); + return; + } + + if (info->t & E_CONTACT_FIELD_TYPE_MULTI) { + GList *new_values = g_value_get_pointer (value); + GList *l; + + /* first we remove all attributes of the type we're + adding, then add new ones based on the values that + are passed in */ + e_vcard_remove_attributes (E_VCARD (contact), NULL, info->vcard_field_name); + + for (l = new_values; l; l = l->next) + e_vcard_add_attribute_with_value (E_VCARD (contact), + e_vcard_attribute_new (NULL, info->vcard_field_name), + (char*)l->data); + } + else if (info->t & E_CONTACT_FIELD_TYPE_SYNTHETIC) { + if (info->t & E_CONTACT_FIELD_TYPE_MULTI_ELEM) { + /* XXX this is kinda broken - we don't insert + insert padding elements if, e.g. the user + sets email 3 when email 1 and 2 don't + exist. But, if we *did* pad the lists we'd + end up with empty items in the vcard. I + dunno which is worse. */ + EVCardAttribute *attr = NULL; + gboolean found = FALSE; + int num_left = info->list_elem; + GList *attrs = e_vcard_get_attributes (E_VCARD (contact)); + GList *l; + + for (l = attrs; l; l = l->next) { + const char *name, *group; + + attr = l->data; + group = e_vcard_attribute_get_group (attr); + name = e_vcard_attribute_get_name (attr); + + /* all the attributes we care about should be in group "" */ + if ((!group || !*group) && !strcasecmp (name, info->vcard_field_name)) { + if (num_left-- == 0) { + found = TRUE; + break; + } + } + } + + if (found) { + /* we found it, overwrite it */ + e_vcard_attribute_remove_values (attr); + } + else { + /* we didn't find it - add a new attribute */ + attr = e_vcard_attribute_new (NULL, info->vcard_field_name); + e_vcard_add_attribute (E_VCARD (contact), attr); + } + + e_vcard_attribute_add_value (attr, g_value_get_string (value)); + } + else if (info->t & E_CONTACT_FIELD_TYPE_ATTR_TYPE) { + /* XXX this is kinda broken - we don't insert + insert padding elements if, e.g. the user + sets email 3 when email 1 and 2 don't + exist. But, if we *did* pad the lists we'd + end up with empty items in the vcard. I + dunno which is worse. */ + EVCardAttribute *attr = NULL; + gboolean found = FALSE; + int num_left = info->list_elem; + GList *attrs = e_vcard_get_attributes (E_VCARD (contact)); + GList *l; + const char *sval = g_value_get_string (value); + + for (l = attrs; l && !found; l = l->next) { + const char *name, *group; + gboolean found_needed1, found_needed2; + + if (!info->attr_type1) + found_needed1 = TRUE; + else + found_needed1 = FALSE; + + if (!info->attr_type2) + found_needed2 = TRUE; + else + found_needed2 = FALSE; + + attr = l->data; + group = e_vcard_attribute_get_group (attr); + name = e_vcard_attribute_get_name (attr); + + /* all the attributes we care about should be in group "" */ + if ((!group || !*group) && !strcasecmp (name, info->vcard_field_name)) { + GList *params; + + for (params = e_vcard_attribute_get_params (attr); params; params = params->next) { + EVCardAttributeParam *param = params->data; + const char *name = e_vcard_attribute_param_get_name (param); + + if (!strcasecmp (name, EVC_TYPE)) { + GList *values = e_vcard_attribute_param_get_values (param); + if (values && values->data) { + if (!found_needed1 && !strcasecmp ((char*)values->data, info->attr_type1)) + found_needed1 = TRUE; + else if (!found_needed2 && !strcasecmp ((char*)values->data, info->attr_type2)) + found_needed2 = TRUE; + } + } + + if (found_needed1 && found_needed2) { + if (num_left-- == 0) { + found = TRUE; + break; + } + } + } + } + } + + if (found) { + /* we found it, overwrite it */ + e_vcard_attribute_remove_values (attr); + } + else { + /* we didn't find it - add a new attribute */ + attr = e_vcard_attribute_new (NULL, info->vcard_field_name); + e_vcard_add_attribute (E_VCARD (contact), attr); + if (info->attr_type1) + e_vcard_attribute_add_param_with_value (attr, e_vcard_attribute_param_new (EVC_TYPE), + info->attr_type1); + if (info->attr_type2) + e_vcard_attribute_add_param_with_value (attr, e_vcard_attribute_param_new (EVC_TYPE), + info->attr_type2); + } + + if (sval && *sval) + e_vcard_attribute_add_value (attr, sval); + else + e_vcard_remove_attribute (E_VCARD (contact), attr); + } + else if (info->t & E_CONTACT_FIELD_TYPE_LIST_ELEM) { + EVCardAttribute *attr = e_contact_get_first_attr (contact, info->vcard_field_name); + GList *values; + GList *p; + const char *sval = g_value_get_string (value); + + if (!attr) { + if (!sval || !*sval) + return; + + printf ("adding new %s\n", info->vcard_field_name); + + attr = e_vcard_attribute_new (NULL, info->vcard_field_name); + e_vcard_add_attribute (E_VCARD (contact), attr); + } + + values = e_vcard_attribute_get_values (attr); + p = g_list_nth (values, info->list_elem); + + if (p) { + g_free (p->data); + p->data = g_strdup (g_value_get_string (value)); + } + else { + /* there weren't enough elements in the list, pad it */ + int count = info->list_elem - g_list_length (values); + + while (count--) + e_vcard_attribute_add_value (attr, ""); + + e_vcard_attribute_add_value (attr, g_value_get_string (value)); + } + + } + } + else if (info->t & E_CONTACT_FIELD_TYPE_BOOLEAN) { + EVCardAttribute *attr; + + /* first we search for an attribute we can overwrite */ + attr = e_contact_get_first_attr (contact, info->vcard_field_name); + if (attr) { + printf ("setting %s to `%s'\n", info->vcard_field_name, g_value_get_string (value)); + e_vcard_attribute_remove_values (attr); + e_vcard_attribute_add_value (attr, g_value_get_boolean (value) ? "TRUE" : "FALSE"); + } + else { + /* and if we don't find one we create a new attribute */ + e_vcard_add_attribute_with_value (E_VCARD (contact), + e_vcard_attribute_new (NULL, info->vcard_field_name), + g_value_get_boolean (value) ? "TRUE" : "FALSE"); + } + } + else if (info->t & E_CONTACT_FIELD_TYPE_STRING) { + EVCardAttribute *attr; + const char *sval = g_value_get_string (value); + + /* first we search for an attribute we can overwrite */ + attr = e_contact_get_first_attr (contact, info->vcard_field_name); + if (attr) { + printf ("setting %s to `%s'\n", info->vcard_field_name, sval); + e_vcard_attribute_remove_values (attr); + if (sval) + e_vcard_attribute_add_value (attr, sval); + } + else if (sval) { + /* and if we don't find one we create a new attribute */ + e_vcard_add_attribute_with_value (E_VCARD (contact), + e_vcard_attribute_new (NULL, info->vcard_field_name), + g_value_get_string (value)); + } + } + else if (info->t & E_CONTACT_FIELD_TYPE_STRUCT) { + EVCardAttribute *attr = e_contact_get_first_attr (contact, info->vcard_field_name); + void *data = g_value_get_pointer (value); + + if (attr) { + printf ("overwriting existing %s\n", info->vcard_field_name); + /* remove all existing values and parameters. + the setter will add the correct ones */ + e_vcard_attribute_remove_values (attr); + e_vcard_attribute_remove_params (attr); + } + else { + printf ("adding new %s\n", info->vcard_field_name); + attr = e_vcard_attribute_new (NULL, info->vcard_field_name); + + e_vcard_add_attribute (E_VCARD (contact), attr); + } + + info->struct_setter (contact, attr, data); + } + else { + g_warning ("unhandled attribute `%s'", info->vcard_field_name); + } +} + +static GList * +e_contact_get_email_list (EContact *contact) +{ + GList *rv = NULL; + GList *attrs, *l; + + attrs = e_vcard_get_attributes (E_VCARD (contact)); + + for (l = attrs; l; l = l->next) { + EVCardAttribute *attr = l->data; + const char *name, *group; + + group = e_vcard_attribute_get_group (attr); + name = e_vcard_attribute_get_name (attr); + + /* all the attributes we care about should be in group "" */ + if ((!group || !*group) && !strcasecmp (name, EVC_EMAIL)) { + GList *v = e_vcard_attribute_get_values (attr); + + rv = g_list_append (rv, v ? g_strdup (v->data) : NULL); + } + } + + return rv; +} + +static EVCardAttribute * +e_contact_find_attribute_with_types (EContact *contact, const char *attr_name, const char *type_needed1, const char *type_needed2, int nth) +{ + GList *l, *attrs; + gboolean found_needed1, found_needed2; + + attrs = e_vcard_get_attributes (E_VCARD (contact)); + + for (l = attrs; l; l = l->next) { + EVCardAttribute *attr = l->data; + const char *name, *group; + + if (!type_needed1) + found_needed1 = TRUE; + else + found_needed1 = FALSE; + + if (!type_needed2) + found_needed2 = TRUE; + else + found_needed2 = FALSE; + + group = e_vcard_attribute_get_group (attr); + name = e_vcard_attribute_get_name (attr); + + /* all the attributes we care about should be in group "" */ + if ((!group || !*group) && !strcasecmp (name, attr_name)) { + GList *params; + + for (params = e_vcard_attribute_get_params (attr); params; params = params->next) { + EVCardAttributeParam *param = params->data; + const char *name = e_vcard_attribute_param_get_name (param); + + if (!strcasecmp (name, EVC_TYPE)) { + GList *values = e_vcard_attribute_param_get_values (param); + if (values && values->data) { + if (!found_needed1 && !strcasecmp ((char*)values->data, type_needed1)) + found_needed1 = TRUE; + else if (!found_needed2 && !strcasecmp ((char*)values->data, type_needed2)) + found_needed2 = TRUE; + } + } + + if (found_needed1 && found_needed2) { + if (nth-- == 0) + return attr; + else + break; + } + } + } + } + + return NULL; +} + +static void +e_contact_get_property (GObject *object, + guint prop_id, + GValue *value, + GParamSpec *pspec) +{ + EContact *contact = E_CONTACT (object); + int i; + EContactFieldInfo *info = NULL; + + if (prop_id < 1 || prop_id >= E_CONTACT_FIELD_LAST) { + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + return; + } + + for (i = 0; i < G_N_ELEMENTS (field_info); i++) { + if (field_info[i].field_id == prop_id) { + info = &field_info[i]; + break; + } + } + + if (!info) { + g_warning ("unknown field %d", prop_id); + return; + } + else if (info->t & E_CONTACT_FIELD_TYPE_BOOLEAN) { + EVCardAttribute *attr = e_contact_get_first_attr (contact, info->vcard_field_name); + gboolean rv = FALSE; + + if (attr) { + GList *v = e_vcard_attribute_get_values (attr); + rv = v && v->data && !strcasecmp ((char*)v->data, "true"); + } + + g_value_set_boolean (value, rv); + } + else if (info->t & E_CONTACT_FIELD_TYPE_LIST) { + EVCardAttribute *attr = e_contact_get_first_attr (contact, info->vcard_field_name); + + if (attr) + g_value_set_pointer (value, e_vcard_attribute_get_values (attr)); + } + else if (info->t & E_CONTACT_FIELD_TYPE_LIST_ELEM) { + if (info->t & E_CONTACT_FIELD_TYPE_STRING) { + GList *attrs, *l; + + attrs = e_vcard_get_attributes (E_VCARD (contact)); + + for (l = attrs; l; l = l->next) { + EVCardAttribute *attr = l->data; + const char *name, *group; + + group = e_vcard_attribute_get_group (attr); + name = e_vcard_attribute_get_name (attr); + + /* all the attributes we care about should be in group "" */ + if ((!group || !*group) && !strcasecmp (name, info->vcard_field_name)) { + GList *v; + int count; + + v = e_vcard_attribute_get_values (attr); + count = info->list_elem; + + v = g_list_nth (v, info->list_elem); + + g_value_set_string (value, v ? v->data : NULL); + } + } + } + } + else if (info->t & E_CONTACT_FIELD_TYPE_MULTI_ELEM) { + if (info->t & E_CONTACT_FIELD_TYPE_STRING) { + GList *attrs, *l; + + attrs = e_vcard_get_attributes (E_VCARD (contact)); + + for (l = attrs; l; l = l->next) { + EVCardAttribute *attr = l->data; + const char *name, *group; + + group = e_vcard_attribute_get_group (attr); + name = e_vcard_attribute_get_name (attr); + + /* all the attributes we care about should be in group "" */ + if ((!group || !*group) && !strcasecmp (name, info->vcard_field_name)) { + GList *v; + int count; + + v = e_vcard_attribute_get_values (attr); + count = info->list_elem; + + v = g_list_nth (v, info->list_elem); + + g_value_set_string (value, v ? v->data : NULL); + } + } + } + } + else if (info->t & E_CONTACT_FIELD_TYPE_ATTR_TYPE) { + EVCardAttribute *attr = e_contact_find_attribute_with_types (contact, info->vcard_field_name, info->attr_type1, info->attr_type2, info->list_elem); + + if (info->t & E_CONTACT_FIELD_TYPE_STRING) { + if (attr) { + GList *p = e_vcard_attribute_get_values (attr); + char *rv = p->data; + + g_value_set_string (value, rv); + } + else { + g_value_set_string (value, NULL); + } + } + else { /* struct */ + gpointer rv = info->struct_getter (contact, attr); + + g_value_set_pointer (value, rv); + } + + } + else if (info->t & E_CONTACT_FIELD_TYPE_STRUCT) { + EVCardAttribute *attr = e_contact_get_first_attr (contact, info->vcard_field_name); + void *rv = NULL; + + if (attr) + rv = info->struct_getter (contact, attr); + + g_value_set_pointer (value, rv); + } + + else if (info->t & E_CONTACT_FIELD_TYPE_SYNTHETIC) { + switch (info->field_id) { + default: + g_warning ("unhandled synthetic field 0x%02x", info->field_id); + } + } + else { + GList *attrs, *l; + GList *rv = NULL; /* used for multi attribute lists */ + + attrs = e_vcard_get_attributes (E_VCARD (contact)); + + for (l = attrs; l; l = l->next) { + EVCardAttribute *attr = l->data; + const char *name, *group; + + group = e_vcard_attribute_get_group (attr); + name = e_vcard_attribute_get_name (attr); + + /* all the attributes we care about should be in group "" */ + if ((!group || !*group) && !strcasecmp (name, info->vcard_field_name)) { + GList *v; + v = e_vcard_attribute_get_values (attr); + + if (info->t & E_CONTACT_FIELD_TYPE_STRING) { + g_value_set_string (value, v ? v->data : NULL); + } + else { + rv = g_list_append (rv, v ? g_strdup (v->data) : NULL); + + g_value_set_pointer (value, rv); + } + } + } + } +} + + + +EContact* +e_contact_new (void) +{ + return e_contact_new_from_vcard (""); +} + +EContact* +e_contact_new_from_vcard (const char *vcard) +{ + EContact *contact = g_object_new (E_TYPE_CONTACT, NULL); + + e_vcard_construct (E_VCARD (contact), vcard); + + return contact; +} + +EContact* +e_contact_duplicate (EContact *contact) +{ + char *vcard = e_vcard_to_string (E_VCARD (contact), EVC_FORMAT_VCARD_30); + EContact *c = e_contact_new_from_vcard (vcard); + + g_free (vcard); + + return c; +} + +const char * +e_contact_field_name (EContactField field_id) +{ + int i; + + g_return_val_if_fail (field_id >= 1 && field_id <= E_CONTACT_FIELD_LAST, ""); + + for (i = 0; i < G_N_ELEMENTS (field_info); i ++) { + if (field_id == field_info[i].field_id) + return field_info[i].field_name; + } + + g_warning ("unknown field id %d", field_id); + return ""; +} + +const char * +e_contact_pretty_name (EContactField field_id) +{ + int i; + + g_return_val_if_fail (field_id >= 1 && field_id <= E_CONTACT_FIELD_LAST, ""); + + for (i = 0; i < G_N_ELEMENTS (field_info); i ++) { + if (field_id == field_info[i].field_id) + return _(field_info[i].pretty_name); + } + + g_warning ("unknown field id %d", field_id); + return ""; +} + +EContactField +e_contact_field_id (const char *field_name) +{ + int i; + + for (i = 0; i < G_N_ELEMENTS (field_info); i ++) { + if (!strcmp (field_info[i].field_name, field_name)) + return field_info[i].field_id; + } + + g_warning ("unknown field name `%s'", field_name); + return 0; +} + +gpointer +e_contact_get (EContact *contact, EContactField field_id) +{ + gpointer value; + + g_return_val_if_fail (contact && E_IS_CONTACT (contact), NULL); + g_return_val_if_fail (field_id >= 1 && field_id <= E_CONTACT_FIELD_LAST, NULL); + + g_object_get (contact, + e_contact_field_name (field_id), &value, + NULL); + + return value; +} + +/* XXX this won't work for structure/list types... */ +static void +free_const_data (gpointer data, GObject *where_object_was) +{ + g_free (data); +} + +const gpointer +e_contact_get_const (EContact *contact, EContactField field_id) +{ + gpointer value; + + g_return_val_if_fail (E_IS_CONTACT (contact), NULL); + g_return_val_if_fail (field_id >= 1 && field_id <= E_CONTACT_FIELD_LAST, NULL); + + value = e_contact_get (contact, field_id); + + g_object_weak_ref (G_OBJECT (contact), free_const_data, value); + + return value; +} + +void +e_contact_set (EContact *contact, EContactField field_id, gpointer value) +{ + printf ("e_contact_set (%p, %d, %p)\n", contact, field_id, value); + + g_return_if_fail (contact && E_IS_CONTACT (contact)); + g_return_if_fail (field_id >= 1 && field_id <= E_CONTACT_FIELD_LAST); + + g_object_set (contact, + e_contact_field_name (field_id), value, + NULL); +} + +EContactName* +e_contact_name_new () +{ + return g_new0 (EContactName, 1); +} + +char * +e_contact_name_to_string(const EContactName *name) +{ + char *strings[6], **stringptr = strings; + + g_return_val_if_fail (name != NULL, NULL); + + if (name->prefixes && *name->prefixes) + *(stringptr++) = name->prefixes; + if (name->given && *name->given) + *(stringptr++) = name->given; + if (name->additional && *name->additional) + *(stringptr++) = name->additional; + if (name->family && *name->family) + *(stringptr++) = name->family; + if (name->suffixes && *name->suffixes) + *(stringptr++) = name->suffixes; + *stringptr = NULL; + return g_strjoinv(" ", strings); +} + +EContactName* +e_contact_name_from_string (const char *name_str) +{ + EContactName *name = e_contact_name_new(); + ENameWestern *western = e_name_western_parse (name_str); + + name->prefixes = g_strdup (western->prefix); + name->given = g_strdup (western->first ); + name->additional = g_strdup (western->middle); + name->family = g_strdup (western->last ); + name->suffixes = g_strdup (western->suffix); + + e_name_western_free(western); + + return name; +} + +EContactName* +e_contact_name_copy (EContactName *n) +{ + EContactName *name = e_contact_name_new(); + + name->prefixes = g_strdup (n->prefixes); + name->given = g_strdup (n->given); + name->additional = g_strdup (n->additional); + name->family = g_strdup (n->family); + name->suffixes = g_strdup (n->suffixes); + + return name; +} + +void +e_contact_name_free (EContactName *name) +{ + if (!name) + return; + + g_free (name->family); + g_free (name->given); + g_free (name->additional); + g_free (name->prefixes); + g_free (name->suffixes); + + g_free (name); +} + +EContactDate* +e_contact_date_new (void) +{ + return g_new0 (EContactDate, 1); +} + +EContactDate* +e_contact_date_from_string (const char *str) +{ + EContactDate* date = e_contact_date_new(); + int length; + + length = strlen(str); + + if (length == 10 ) { + date->year = str[0] * 1000 + str[1] * 100 + str[2] * 10 + str[3] - '0' * 1111; + date->month = str[5] * 10 + str[6] - '0' * 11; + date->day = str[8] * 10 + str[9] - '0' * 11; + } else if ( length == 8 ) { + date->year = str[0] * 1000 + str[1] * 100 + str[2] * 10 + str[3] - '0' * 1111; + date->month = str[4] * 10 + str[5] - '0' * 11; + date->day = str[6] * 10 + str[7] - '0' * 11; + } + + return date; +} + +char * +e_contact_date_to_string (EContactDate *dt) +{ + if (dt) + return g_strdup_printf ("%04d-%02d-%02d", + CLAMP(dt->year, 1000, 9999), + CLAMP(dt->month, 1, 12), + CLAMP(dt->day, 1, 31)); + else + return NULL; +} + +void +e_contact_date_free (EContactDate *dt) +{ + g_free (dt); +} + + +void +e_contact_photo_free (EContactPhoto *photo) +{ + if (!photo) + return; + + g_free (photo->data); + g_free (photo); +} + +void +e_contact_address_free (EContactAddress *address) +{ + if (!address) + return; + + g_free (address->address_format); + g_free (address->po); + g_free (address->ext); + g_free (address->street); + g_free (address->locality); + g_free (address->region); + g_free (address->code); + g_free (address->country); + + g_free (address); +} diff --git a/addressbook/backend/ebook/e-contact.h b/addressbook/backend/ebook/e-contact.h new file mode 100644 index 0000000000..8de02caa5f --- /dev/null +++ b/addressbook/backend/ebook/e-contact.h @@ -0,0 +1,227 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ +/* + * Authors: + * Chris Toshok + * + * Copyright (C) 2003 Ximian, Inc. + */ + +#ifndef __E_CONTACT_H__ +#define __E_CONTACT_H__ + +#include +#include +#include +#include + +#define E_TYPE_CONTACT (e_contact_get_type ()) +#define E_CONTACT(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), E_TYPE_CONTACT, EContact)) +#define E_CONTACT_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), E_TYPE_CONTACT, EContactClass)) +#define E_IS_CONTACT(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), E_TYPE_CONTACT)) +#define E_IS_CONTACT_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), E_TYPE_CONTACT)) +#define E_CONTACT_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), E_TYPE_CONTACT, EContactClass)) + +typedef struct _EContact EContact; +typedef struct _EContactClass EContactClass; +typedef struct _EContactPrivate EContactPrivate; + +typedef enum { + + E_CONTACT_UID = 1, /* string field */ + E_CONTACT_FILE_AS, /* string field */ + + /* Name fields */ + E_CONTACT_FULL_NAME, /* string field */ + E_CONTACT_GIVEN_NAME, /* synthetic string field */ + E_CONTACT_FAMILY_NAME, /* synthetic string field */ + E_CONTACT_NICKNAME, /* string field */ + + /* Email fields */ + E_CONTACT_EMAIL_1, /* synthetic string field */ + E_CONTACT_EMAIL_2, /* synthetic string field */ + E_CONTACT_EMAIL_3, /* synthetic string field */ + + E_CONTACT_MAILER, /* string field */ + + /* Address Labels */ + E_CONTACT_ADDRESS_LABEL_HOME, /* synthetic string field */ + E_CONTACT_ADDRESS_LABEL_WORK, /* synthetic string field */ + E_CONTACT_ADDRESS_LABEL_OTHER, /* synthetic string field */ + + /* Phone fields */ + E_CONTACT_PHONE_ASSISTANT, + E_CONTACT_PHONE_BUSINESS, + E_CONTACT_PHONE_BUSINESS_2, + E_CONTACT_PHONE_BUSINESS_FAX, + E_CONTACT_PHONE_CALLBACK, + E_CONTACT_PHONE_CAR, + E_CONTACT_PHONE_COMPANY, + E_CONTACT_PHONE_HOME, + E_CONTACT_PHONE_HOME_2, + E_CONTACT_PHONE_HOME_FAX, + E_CONTACT_PHONE_ISDN, + E_CONTACT_PHONE_MOBILE, + E_CONTACT_PHONE_OTHER, + E_CONTACT_PHONE_OTHER_FAX, + E_CONTACT_PHONE_PAGER, + E_CONTACT_PHONE_PRIMARY, + E_CONTACT_PHONE_RADIO, + E_CONTACT_PHONE_TELEX, + E_CONTACT_PHONE_TTYTDD, + + /* Organizational fields */ + E_CONTACT_ORG, /* string field */ + E_CONTACT_ORG_UNIT, /* string field */ + E_CONTACT_OFFICE, /* string field */ + E_CONTACT_TITLE, /* string field */ + E_CONTACT_ROLE, /* string field */ + E_CONTACT_MANAGER, /* string field */ + E_CONTACT_ASSISTANT, /* string field */ + + /* Web fields */ + E_CONTACT_HOMEPAGE_URL, /* string field */ + E_CONTACT_BLOG_URL, /* string field */ + + /* Contact categories */ + E_CONTACT_CATEGORIES, /* string field */ + + /* Collaboration fields */ + E_CONTACT_CALENDAR_URI, /* string field */ + E_CONTACT_FREEBUSY_URL, /* string field */ + E_CONTACT_ICS_CALENDAR, /* string field */ + + /* misc fields */ + E_CONTACT_SPOUSE, /* string field */ + E_CONTACT_NOTE, /* string field */ + + /* fields used for describing contact lists. a contact list + is just a contact with _IS_LIST set to true. the members + are listed in the _EMAIL field. */ + E_CONTACT_IS_LIST, /* boolean field */ + E_CONTACT_LIST_SHOW_ADDRESSES, /* boolean field */ + + /* Instant Messaging fields */ + E_CONTACT_IM_AIM, /* Multi-valued */ + E_CONTACT_IM_JABBER, /* Multi-valued */ + E_CONTACT_IM_YAHOO, /* Multi-valued */ + E_CONTACT_IM_MSN, /* Multi-valued */ + E_CONTACT_IM_ICQ, /* Multi-valued */ + + /* Address fields */ + E_CONTACT_ADDRESS, /* Multi-valued structured (EContactAddress) */ + E_CONTACT_ADDRESS_HOME, /* synthetic structured field (EContactAddress) */ + E_CONTACT_ADDRESS_WORK, /* synthetic structured field (EContactAddress) */ + E_CONTACT_ADDRESS_OTHER, /* synthetic structured field (EContactAddress) */ + + E_CONTACT_CATEGORY_LIST, /* multi-valued */ + + /* Photo/Logo */ + E_CONTACT_PHOTO, /* structured field (EContactPhoto) */ + E_CONTACT_LOGO, /* structured field (EContactPhoto) */ + + E_CONTACT_NAME, /* structured field (EContactName) */ + E_CONTACT_EMAIL, /* Multi-valued */ + + E_CONTACT_WANTS_HTML, /* boolean field */ + + E_CONTACT_BIRTH_DATE, /* structured field (EContactDate) */ + E_CONTACT_ANNIVERSARY, /* structured field (EContactDate) */ + + E_CONTACT_FIELD_LAST, + + /* useful constants */ + E_CONTACT_LAST_SIMPLE_STRING = E_CONTACT_NOTE, + E_CONTACT_FIRST_PHONE_ID = E_CONTACT_PHONE_ASSISTANT, + E_CONTACT_LAST_PHONE_ID = E_CONTACT_PHONE_TTYTDD, + E_CONTACT_FIRST_EMAIL_ID = E_CONTACT_EMAIL_1, + E_CONTACT_LAST_EMAIL_ID = E_CONTACT_EMAIL_3, + E_CONTACT_FIRST_ADDRESS_ID = E_CONTACT_ADDRESS_HOME, + E_CONTACT_LAST_ADDRESS_ID = E_CONTACT_ADDRESS_OTHER, + E_CONTACT_FIRST_LABEL_ID = E_CONTACT_ADDRESS_LABEL_HOME, + E_CONTACT_LAST_LABEL_ID = E_CONTACT_ADDRESS_LABEL_OTHER + +} EContactField; + +typedef struct { + char *family; + char *given; + char *additional; + char *prefixes; + char *suffixes; +} EContactName; + +typedef struct { + int length; + char *data; +} EContactPhoto; + +typedef struct { + char *address_format; /* the two letter country code that + determines the format/meaning of the + following fields */ + char *po; + char *ext; + char *street; + char *locality; + char *region; + char *code; + char *country; +} EContactAddress; + +typedef struct { + int year; + int month; + int day; +} EContactDate; + +struct _EContact { + EVCard parent; + + EContactPrivate *priv; +}; + +struct _EContactClass { + EVCardClass parent_class; + + /* Padding for future expansion */ + void (*_ebook_reserved0) (void); + void (*_ebook_reserved1) (void); + void (*_ebook_reserved2) (void); + void (*_ebook_reserved3) (void); + void (*_ebook_reserved4) (void); +}; + +GType e_contact_get_type (void); + +EContact* e_contact_new (void); +EContact* e_contact_new_from_vcard (const char *vcard); + +EContact* e_contact_duplicate (EContact *contact); + +gpointer e_contact_get (EContact *contact, EContactField field_id); +const gpointer e_contact_get_const (EContact *contact, EContactField field_id); +void e_contact_set (EContact *contact, EContactField field_id, gpointer value); + +/* misc functions for structured values */ +EContactDate *e_contact_date_new (void); +EContactDate *e_contact_date_from_string (const char *str); +char *e_contact_date_to_string (EContactDate *dt); + +EContactName *e_contact_name_new (void); +char *e_contact_name_to_string (const EContactName *name); +EContactName *e_contact_name_from_string (const char *name_str); +EContactName *e_contact_name_copy (EContactName *name); + + +/* destructors for structured values */ +void e_contact_date_free (EContactDate *date); +void e_contact_name_free (EContactName *name); +void e_contact_photo_free (EContactPhoto *photo); +void e_contact_address_free (EContactAddress *address); + + +const char* e_contact_field_name (EContactField field_id); +const char* e_contact_pretty_name (EContactField field_id); +EContactField e_contact_field_id (const char *field_name); + +#endif /* __E_CONTACT_H__ */ diff --git a/addressbook/backend/ebook/e-destination.h b/addressbook/backend/ebook/e-destination.h deleted file mode 100644 index acd6af1bc4..0000000000 --- a/addressbook/backend/ebook/e-destination.h +++ /dev/null @@ -1,140 +0,0 @@ -/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ - -/* - * e-destination.h - * - * Copyright (C) 2001 Ximian, Inc. - * - * Developed by Jon Trowbridge - */ - -/* - * This program is free software; you can redistribute it and/or - * modify it under the terms of version 2 of the GNU General Public - * License as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - * USA. - */ - -#ifndef __E_DESTINATION_H__ -#define __E_DESTINATION_H__ - -#include -#include -#include -#include -#include - -#define E_TYPE_DESTINATION (e_destination_get_type ()) -#define E_DESTINATION(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), E_TYPE_DESTINATION, EDestination)) -#define E_DESTINATION_CLASS(k) (G_TYPE_CHECK_CLASS_CAST ((k), E_TYPE_DESTINATION, EDestinationClass)) -#define E_IS_DESTINATION(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), E_TYPE_DESTINATION)) -#define E_IS_DESTINATION_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), E_TYPE_DESTINATION)) -#define E_DESTINATION_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), E_TYPE_DESTINATION, EDestinationClass)) - -typedef struct _EDestination EDestination; -typedef struct _EDestinationClass EDestinationClass; - -typedef void (*EDestinationCardCallback) (EDestination *dest, ECard *card, gpointer closure); - -struct _EDestinationPrivate; - -struct _EDestination { - GObject object; - - struct _EDestinationPrivate *priv; -}; - -struct _EDestinationClass { - GObjectClass parent_class; - - void (*changed) (EDestination *dest); - void (*cardified) (EDestination *dest); -}; - -GType e_destination_get_type (void); - - -EDestination *e_destination_new (void); -void e_destination_changed (EDestination *); -EDestination *e_destination_copy (const EDestination *); -void e_destination_clear (EDestination *); - -gboolean e_destination_is_empty (const EDestination *); -gboolean e_destination_is_valid (const EDestination *); -gboolean e_destination_equal (const EDestination *a, const EDestination *b); - -void e_destination_set_card (EDestination *, ECard *card, gint email_num); -void e_destination_set_book_uri (EDestination *, const gchar *uri); -void e_destination_set_card_uid (EDestination *, const gchar *uid, gint email_num); - -void e_destination_set_name (EDestination *, const gchar *name); -void e_destination_set_email (EDestination *, const gchar *email); - -void e_destination_set_html_mail_pref (EDestination *, gboolean); - -gboolean e_destination_contains_card (const EDestination *); -gboolean e_destination_from_card (const EDestination *); - -gboolean e_destination_is_auto_recipient (const EDestination *); -void e_destination_set_auto_recipient (EDestination *, gboolean value); - -void e_destination_use_card (EDestination *, EDestinationCardCallback cb, gpointer closure); - -ECard *e_destination_get_card (const EDestination *); -const gchar *e_destination_get_book_uri (const EDestination *); -const gchar *e_destination_get_card_uid (const EDestination *); -gint e_destination_get_email_num (const EDestination *); - -const gchar *e_destination_get_name (const EDestination *); /* "Jane Smith" */ -const gchar *e_destination_get_email (const EDestination *); /* "jane@assbarn.com" */ -const gchar *e_destination_get_address (const EDestination *);; /* "Jane Smith " (or a comma-sep set of such for a list) */ - -void e_destination_set_raw (EDestination *, const gchar *free_form_string); -const gchar *e_destination_get_textrep (const EDestination *, gboolean include_email); /* "Jane Smith" or "jane@assbarn.com" */ - -gboolean e_destination_is_evolution_list (const EDestination *); -gboolean e_destination_list_show_addresses (const EDestination *); - -/* If true, they want HTML mail. */ -gboolean e_destination_get_html_mail_pref (const EDestination *); - -gboolean e_destination_allow_cardification (const EDestination *); -void e_destination_set_allow_cardification (EDestination *, gboolean); -void e_destination_cardify (EDestination *, EBook *); -void e_destination_cardify_delayed (EDestination *, EBook *, gint delay); /* delay < 0: "default" */ -void e_destination_cancel_cardify (EDestination *); -gboolean e_destination_uncardify (EDestination *); - -gboolean e_destination_revert (EDestination *); - -gchar *e_destination_get_address_textv (EDestination **); - -xmlNodePtr e_destination_xml_encode (const EDestination *dest); -gboolean e_destination_xml_decode (EDestination *dest, xmlNodePtr node); - -gchar *e_destination_export (const EDestination *); -EDestination *e_destination_import (const gchar *str); - -gchar *e_destination_exportv (EDestination **); -EDestination **e_destination_importv (const gchar *str); - -EDestination **e_destination_list_to_vector_sized (GList *, int n); -EDestination **e_destination_list_to_vector (GList *); - -void e_destination_freev (EDestination **); - -void e_destination_touch (EDestination *); -void e_destination_touchv (EDestination **); - - -#endif /* __E_DESTINATION_H__ */ - diff --git a/addressbook/backend/ebook/e-vcard.c b/addressbook/backend/ebook/e-vcard.c index 62ebda9349..7ea1d9da84 100644 --- a/addressbook/backend/ebook/e-vcard.c +++ b/addressbook/backend/ebook/e-vcard.c @@ -1,5 +1,5 @@ /* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ -/* evcard.h +/* e-vcard.c * * Copyright (C) 2003 Ximian, Inc. * @@ -22,11 +22,18 @@ #include #include +#include #include #include "e-vcard.h" #define CRLF "\r\n" +typedef enum { + EVC_ENCODING_RAW, /* no encoding */ + EVC_ENCODING_BASE64, /* base64 */ + EVC_ENCODING_QP /* quoted-printable */ +} EVCardEncoding; + struct _EVCardPrivate { GList *attributes; }; @@ -36,6 +43,9 @@ struct _EVCardAttribute { char *name; GList *params; /* EVCardParam */ GList *values; + GList *decoded_values; + EVCardEncoding encoding; + gboolean encoding_set; }; struct _EVCardAttributeParam { @@ -45,6 +55,12 @@ struct _EVCardAttributeParam { static GObjectClass *parent_class; +static void _evc_base64_init(void); +static size_t _evc_base64_encode_step(unsigned char *in, size_t len, gboolean break_lines, unsigned char *out, int *state, int *save); +static size_t _evc_base64_decode_step(unsigned char *in, size_t len, unsigned char *out, int *state, unsigned int *save); +size_t _evc_base64_decode_simple (char *data, size_t len); +char *_evc_base64_encode_simple (const char *data, size_t len); + static void e_vcard_dispose (GObject *object) { @@ -73,6 +89,8 @@ e_vcard_class_init (EVCardClass *klass) parent_class = g_type_class_ref (G_TYPE_OBJECT); object_class->dispose = e_vcard_dispose; + + _evc_base64_init(); } static void @@ -229,9 +247,9 @@ read_attribute_value (EVCardAttribute *attr, char **p, gboolean quoted_printable g_warning ("invalid escape, passing it through"); str = g_string_append_c (str, '\\'); str = g_string_append_unichar (str, g_utf8_get_char(lp)); - lp = g_utf8_next_char(lp); break; } + lp = g_utf8_next_char(lp); } else if (*lp == ';') { e_vcard_attribute_add_value (attr, g_string_free (str, FALSE)); @@ -480,14 +498,16 @@ parse (EVCard *evc, const char *str) *end = '\0'; } +#if DEBUG_FOLDING printf ("BEFORE FOLDING:\n"); printf (str); - +#endif buf = fold_lines (buf); +#if DEBUG_FOLDING printf ("\n\nAFTER FOLDING:\n"); printf (buf); - +#endif p = buf; attr = read_attribute (&p); @@ -508,6 +528,8 @@ parse (EVCard *evc, const char *str) if (!attr || attr->group || g_ascii_strcasecmp (attr->name, "end")) { g_warning ("vcard ended without END:VCARD\n"); } + + g_free (buf); } static char* @@ -517,7 +539,7 @@ escape_string (const char *s) const char *p; /* Escape a string as described in RFC2426, section 5 */ - for (p = s; *p; p++) { + for (p = s; p && *p; p++) { switch (*p) { case '\n': str = g_string_append (str, "\\n"); @@ -579,24 +601,42 @@ unescape_string (const char *s) } #endif +void +e_vcard_construct (EVCard *evc, const char *str) +{ + if (*str) + parse (evc, str); +} + EVCard * e_vcard_new () { - return g_object_new (E_TYPE_VCARD, NULL); + return e_vcard_new_from_string (""); } EVCard * e_vcard_new_from_string (const char *str) { - EVCard *evc = e_vcard_new (); + EVCard *evc; - parse (evc, str); + g_return_val_if_fail (str, NULL); + + evc = g_object_new (E_TYPE_VCARD, NULL); + + e_vcard_construct (evc, str); return evc; } -char* -e_vcard_to_string (EVCard *evc) +static char* +e_vcard_to_string_vcard_21 (EVCard *evc) +{ + g_warning ("need to implement e_vcard_to_string_vcard_21"); + return g_strdup (""); +} + +static char* +e_vcard_to_string_vcard_30 (EVCard *evc) { GList *l; GList *v; @@ -680,6 +720,20 @@ e_vcard_to_string (EVCard *evc) return g_string_free (str, FALSE); } +char* +e_vcard_to_string (EVCard *evc, EVCardFormat format) +{ + switch (format) { + case EVC_FORMAT_VCARD_21: + return e_vcard_to_string_vcard_21 (evc); + case EVC_FORMAT_VCARD_30: + return e_vcard_to_string_vcard_30 (evc); + default: + g_warning ("invalid format specifier passed to e_vcard_to_string"); + return g_strdup (""); + } +} + void e_vcard_dump_structure (EVCard *evc) { @@ -732,24 +786,62 @@ e_vcard_attribute_new (const char *attr_group, const char *attr_name) void e_vcard_attribute_free (EVCardAttribute *attr) { - GList *p; - g_free (attr->group); g_free (attr->name); - g_list_foreach (attr->values, (GFunc)g_free, NULL); - g_list_free (attr->values); + e_vcard_attribute_remove_values (attr); + + e_vcard_attribute_remove_params (attr); + + g_free (attr); +} + +EVCardAttribute* +e_vcard_attribute_copy (EVCardAttribute *attr) +{ + EVCardAttribute *a = e_vcard_attribute_new (e_vcard_attribute_get_group (attr), + e_vcard_attribute_get_name (attr)); + GList *p; + + for (p = attr->values; p; p = p->next) + e_vcard_attribute_add_value (a, p->data); + + for (p = attr->params; p; p = p->next) + e_vcard_attribute_add_param (a, e_vcard_attribute_param_copy (p->data)); + + return a; +} + +void +e_vcard_remove_attributes (EVCard *evc, const char *attr_group, const char *attr_name) +{ + GList *attr; + + attr = evc->priv->attributes; + while (attr) { + GList *next_attr; + EVCardAttribute *a = attr->data; + + next_attr = attr->next; + + if (((!attr_group && !a->group) || !g_ascii_strcasecmp (attr_group, a->group)) && + ((!attr_name && !a->name) || !g_ascii_strcasecmp (attr_name, a->name))) { + + /* matches, remove/delete the attribute */ + evc->priv->attributes = g_list_remove_link (evc->priv->attributes, attr); - for (p = attr->params; p; p = p->next) { - EVCardAttributeParam *param = p->data; + e_vcard_attribute_free (a); + } - g_free (param->name); - g_list_foreach (param->values, (GFunc)g_free, NULL); - g_list_free (param->values); - g_free (param); + attr = next_attr; } +} - g_free (attr); +void +e_vcard_remove_attribute (EVCard *evc, EVCardAttribute *attr) +{ + evc->priv->attributes = g_list_remove (evc->priv->attributes, attr); + e_vcard_attribute_free (attr); } void @@ -790,6 +882,33 @@ e_vcard_attribute_add_value (EVCardAttribute *attr, const char *value) attr->values = g_list_append (attr->values, g_strdup (value)); } +void +e_vcard_attribute_add_value_decoded (EVCardAttribute *attr, const char *value, int len) +{ + switch (attr->encoding) { + case EVC_ENCODING_RAW: + g_warning ("can't add_value_decoded with an attribute using RAW encoding. you must set the ENCODING parameter first"); + break; + case EVC_ENCODING_BASE64: { + char *b64_data = _evc_base64_encode_simple (value, len); + GString *decoded = g_string_new_len (value, len); + + /* make sure the decoded list is up to date */ + e_vcard_attribute_get_values_decoded (attr); + + printf ("base64 encoded value: %s\n", b64_data); + printf ("original length: %d\n", len); + + attr->values = g_list_append (attr->values, b64_data); + attr->decoded_values = g_list_append (attr->decoded_values, decoded); + break; + } + case EVC_ENCODING_QP: + g_warning ("need to implement quoted printable decoding"); + break; + } +} + void e_vcard_attribute_add_values (EVCardAttribute *attr, ...) @@ -806,6 +925,21 @@ e_vcard_attribute_add_values (EVCardAttribute *attr, va_end (ap); } +void +e_vcard_attribute_remove_values (EVCardAttribute *attr) +{ + g_list_foreach (attr->values, (GFunc)g_free, NULL); + g_list_free (attr->values); + attr->values = NULL; +} + +void +e_vcard_attribute_remove_params (EVCardAttribute *attr) +{ + g_list_foreach (attr->params, (GFunc)e_vcard_attribute_param_free, NULL); + g_list_free (attr->params); + attr->params = NULL; +} EVCardAttributeParam* e_vcard_attribute_param_new (const char *name) @@ -820,16 +954,55 @@ void e_vcard_attribute_param_free (EVCardAttributeParam *param) { g_free (param->name); - g_list_foreach (param->values, (GFunc)g_free, NULL); - g_list_free (param->values); + + e_vcard_attribute_param_remove_values (param); + g_free (param); } +EVCardAttributeParam* +e_vcard_attribute_param_copy (EVCardAttributeParam *param) +{ + EVCardAttributeParam *p = e_vcard_attribute_param_new (e_vcard_attribute_param_get_name (param)); + GList *l; + + for (l = param->values; l; l = l->next) { + e_vcard_attribute_param_add_value (p, l->data); + } + + return p; +} + void e_vcard_attribute_add_param (EVCardAttribute *attr, EVCardAttributeParam *param) { attr->params = g_list_append (attr->params, param); + + /* we handle our special encoding stuff here */ + + if (!g_ascii_strcasecmp (param->name, EVC_ENCODING)) { + if (attr->encoding_set) { + g_warning ("ENCODING specified twice"); + return; + } + + if (param->values && param->values->data) { + if (!g_ascii_strcasecmp ((char*)param->values->data, "b")) + attr->encoding = EVC_ENCODING_BASE64; + else if (!g_ascii_strcasecmp ((char*)param->values->data, EVC_QUOTEDPRINTABLE)) + attr->encoding = EVC_ENCODING_QP; + else { + g_warning ("Unknown value `%s' for ENCODING parameter. values will be treated as raw", + (char*)param->values->data); + } + + attr->encoding_set = TRUE; + } + else { + g_warning ("ENCODING parameter added with no value"); + } + } } void @@ -882,6 +1055,14 @@ e_vcard_attribute_add_param_with_values (EVCardAttribute *attr, e_vcard_attribute_add_param (attr, param); } +void +e_vcard_attribute_param_remove_values (EVCardAttributeParam *param) +{ + g_list_foreach (param->values, (GFunc)g_free, NULL); + g_list_free (param->values); + param->values = NULL; +} + GList* e_vcard_get_attributes (EVCard *evcard) { @@ -906,6 +1087,33 @@ e_vcard_attribute_get_values (EVCardAttribute *attr) return attr->values; } +GList* +e_vcard_attribute_get_values_decoded (EVCardAttribute *attr) +{ + if (!attr->decoded_values) { + GList *l; + switch (attr->encoding) { + case EVC_ENCODING_RAW: + for (l = attr->values; l; l = l->next) + attr->decoded_values = g_list_append (attr->decoded_values, g_string_new ((char*)l->data)); + break; + case EVC_ENCODING_BASE64: + for (l = attr->values; l; l = l->next) { + char *decoded = g_strdup ((char*)l->data); + int len = _evc_base64_decode_simple (decoded, strlen (decoded)); + attr->decoded_values = g_list_append (attr->decoded_values, g_string_new_len (decoded, len)); + g_free (decoded); + } + break; + case EVC_ENCODING_QP: + g_warning ("need to implement quoted printable decoding"); + break; + } + } + + return attr->decoded_values; +} + GList* e_vcard_attribute_get_params (EVCardAttribute *attr) { @@ -923,3 +1131,237 @@ e_vcard_attribute_param_get_values (EVCardAttributeParam *param) { return param->values; } + + + +/* encoding/decoding stuff ripped from camel-mime-utils.c */ + +static char *_evc_base64_alphabet = +"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; + +static unsigned char _evc_base64_rank[256]; + +static void +_evc_base64_init(void) +{ + int i; + + memset(_evc_base64_rank, 0xff, sizeof(_evc_base64_rank)); + for (i=0;i<64;i++) { + _evc_base64_rank[(unsigned int)_evc_base64_alphabet[i]] = i; + } + _evc_base64_rank['='] = 0; +} + +/* call this when finished encoding everything, to + flush off the last little bit */ +static size_t +_evc_base64_encode_close(unsigned char *in, size_t inlen, gboolean break_lines, unsigned char *out, int *state, int *save) +{ + int c1, c2; + unsigned char *outptr = out; + + if (inlen>0) + outptr += _evc_base64_encode_step(in, inlen, break_lines, outptr, state, save); + + c1 = ((unsigned char *)save)[1]; + c2 = ((unsigned char *)save)[2]; + +#if 0 + d(printf("mode = %d\nc1 = %c\nc2 = %c\n", + (int)((char *)save)[0], + (int)((char *)save)[1], + (int)((char *)save)[2])); +#endif + + switch (((char *)save)[0]) { + case 2: + outptr[2] = _evc_base64_alphabet[ ( (c2 &0x0f) << 2 ) ]; + g_assert(outptr[2] != 0); + goto skip; + case 1: + outptr[2] = '='; + skip: + outptr[0] = _evc_base64_alphabet[ c1 >> 2 ]; + outptr[1] = _evc_base64_alphabet[ c2 >> 4 | ( (c1&0x3) << 4 )]; + outptr[3] = '='; + outptr += 4; + break; + } + if (break_lines) + *outptr++ = '\n'; + + *save = 0; + *state = 0; + + return outptr-out; +} + +/* + performs an 'encode step', only encodes blocks of 3 characters to the + output at a time, saves left-over state in state and save (initialise to + 0 on first invocation). +*/ +static size_t +_evc_base64_encode_step(unsigned char *in, size_t len, gboolean break_lines, unsigned char *out, int *state, int *save) +{ + register unsigned char *inptr, *outptr; + + if (len<=0) + return 0; + + inptr = in; + outptr = out; + +#if 0 + d(printf("we have %d chars, and %d saved chars\n", len, ((char *)save)[0])); +#endif + + if (len + ((char *)save)[0] > 2) { + unsigned char *inend = in+len-2; + register int c1, c2, c3; + register int already; + + already = *state; + + switch (((char *)save)[0]) { + case 1: c1 = ((unsigned char *)save)[1]; goto skip1; + case 2: c1 = ((unsigned char *)save)[1]; + c2 = ((unsigned char *)save)[2]; goto skip2; + } + + /* yes, we jump into the loop, no i'm not going to change it, it's beautiful! */ + while (inptr < inend) { + c1 = *inptr++; + skip1: + c2 = *inptr++; + skip2: + c3 = *inptr++; + *outptr++ = _evc_base64_alphabet[ c1 >> 2 ]; + *outptr++ = _evc_base64_alphabet[ c2 >> 4 | ( (c1&0x3) << 4 ) ]; + *outptr++ = _evc_base64_alphabet[ ( (c2 &0x0f) << 2 ) | (c3 >> 6) ]; + *outptr++ = _evc_base64_alphabet[ c3 & 0x3f ]; + /* this is a bit ugly ... */ + if (break_lines && (++already)>=19) { + *outptr++='\n'; + already = 0; + } + } + + ((char *)save)[0] = 0; + len = 2-(inptr-inend); + *state = already; + } + +#if 0 + d(printf("state = %d, len = %d\n", + (int)((char *)save)[0], + len)); +#endif + + if (len>0) { + register char *saveout; + + /* points to the slot for the next char to save */ + saveout = & (((char *)save)[1]) + ((char *)save)[0]; + + /* len can only be 0 1 or 2 */ + switch(len) { + case 2: *saveout++ = *inptr++; + case 1: *saveout++ = *inptr++; + } + ((char *)save)[0]+=len; + } + +#if 0 + d(printf("mode = %d\nc1 = %c\nc2 = %c\n", + (int)((char *)save)[0], + (int)((char *)save)[1], + (int)((char *)save)[2])); +#endif + + return outptr-out; +} + + +/** + * base64_decode_step: decode a chunk of base64 encoded data + * @in: input stream + * @len: max length of data to decode + * @out: output stream + * @state: holds the number of bits that are stored in @save + * @save: leftover bits that have not yet been decoded + * + * Decodes a chunk of base64 encoded data + **/ +static size_t +_evc_base64_decode_step(unsigned char *in, size_t len, unsigned char *out, int *state, unsigned int *save) +{ + register unsigned char *inptr, *outptr; + unsigned char *inend, c; + register unsigned int v; + int i; + + inend = in+len; + outptr = out; + + /* convert 4 base64 bytes to 3 normal bytes */ + v=*save; + i=*state; + inptr = in; + while (inptr>16; + *outptr++ = v>>8; + *outptr++ = v; + i=0; + } + } + } + + *save = v; + *state = i; + + /* quick scan back for '=' on the end somewhere */ + /* fortunately we can drop 1 output char for each trailing = (upto 2) */ + i=2; + while (inptr>in && i) { + inptr--; + if (_evc_base64_rank[*inptr] != 0xff) { + if (*inptr == '=' && outptr>out) + outptr--; + i--; + } + } + + /* if i!= 0 then there is a truncation error! */ + return outptr-out; +} + +char * +_evc_base64_encode_simple (const char *data, size_t len) +{ + unsigned char *out; + int state = 0, outlen; + unsigned int save = 0; + + out = g_malloc (len * 4 / 3 + 5); + outlen = _evc_base64_encode_close ((unsigned char *)data, len, FALSE, + out, &state, &save); + out[outlen] = '\0'; + return (char *)out; +} + +size_t +_evc_base64_decode_simple (char *data, size_t len) +{ + int state = 0; + unsigned int save = 0; + + return _evc_base64_decode_step ((unsigned char *)data, len, + (unsigned char *)data, &state, &save); +} diff --git a/addressbook/backend/ebook/e-vcard.h b/addressbook/backend/ebook/e-vcard.h index 69e0a3e10b..cedc2b4c70 100644 --- a/addressbook/backend/ebook/e-vcard.h +++ b/addressbook/backend/ebook/e-vcard.h @@ -26,18 +26,56 @@ #include #include -#define EVC_FN "FN" -#define EVC_ORG "ORG" -#define EVC_URL "URL" -#define EVC_VERSION "VERSION" -#define EVC_REV "REV" -#define EVC_PRODID "PRODID" -#define EVC_TYPE "TYPE" -#define EVC_ADR "ADR" -#define EVC_TEL "TEL" - -#define EVC_ENCODING "ENCODING" +#define EVC_ADR "ADR" +#define EVC_BDAY "BDAY" +#define EVC_CALURI "CALURI" +#define EVC_CATEGORIES "CATEGORIES" +#define EVC_EMAIL "EMAIL" +#define EVC_ENCODING "ENCODING" +#define EVC_FBURL "FBURL" +#define EVC_FN "FN" +#define EVC_ICSCALENDAR "ICSCALENDAR" /* XXX should this be X-EVOLUTION-ICSCALENDAR? */ +#define EVC_LABEL "LABEL" +#define EVC_LOGO "LOGO" +#define EVC_MAILER "MAILER" +#define EVC_NICKNAME "NICKNAME" +#define EVC_N "N" +#define EVC_NOTE "NOTE" +#define EVC_ORG "ORG" +#define EVC_PHOTO "PHOTO" +#define EVC_PRODID "PRODID" #define EVC_QUOTEDPRINTABLE "QUOTED-PRINTABLE" +#define EVC_REV "REV" +#define EVC_ROLE "ROLE" +#define EVC_TEL "TEL" +#define EVC_TITLE "TITLE" +#define EVC_TYPE "TYPE" +#define EVC_UID "UID" +#define EVC_URL "URL" +#define EVC_VALUE "VALUE" +#define EVC_VERSION "VERSION" + +#define EVC_X_AIM "X-AIM" +#define EVC_X_ANNIVERSARY "X-EVOLUTION-ANNIVERSARY" +#define EVC_X_ASSISTANT "X-EVOLUTION-ASSISTANT" +#define EVC_X_BIRTHDAY "X-EVOLUTION-BIRTHDAY" +#define EVC_X_BLOG_URL "X-EVOLUTION-BLOG-URL" +#define EVC_X_FILE_AS "X-EVOLUTION-FILE-AS" +#define EVC_X_ICQ "X-ICQ" +#define EVC_X_JABBER "X-JABBER" +#define EVC_X_LIST_SHOW_ADDRESSES "X-EVOLUTION-LIST-SHOW_ADDRESSES" +#define EVC_X_LIST "X-EVOLUTION-LIST" +#define EVC_X_MANAGER "X-EVOLUTION-MANAGER" +#define EVC_X_MSN "X-MSN" +#define EVC_X_SPOUSE "X-EVOLUTION-SPOUSE" +#define EVC_X_WANTS_HTML "X-MOZILLA-HTML" +#define EVC_X_WANTS_HTML "X-MOZILLA-HTML" +#define EVC_X_YAHOO "X-YAHOO" + +typedef enum { + EVC_FORMAT_VCARD_21, + EVC_FORMAT_VCARD_30 +} EVCardFormat; #define E_TYPE_VCARD (e_vcard_get_type ()) #define E_VCARD(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), E_TYPE_VCARD, EVCard)) @@ -60,28 +98,46 @@ struct _EVCard { struct _EVCardClass { GObjectClass parent_class; + + /* Padding for future expansion */ + void (*_ebook_reserved0) (void); + void (*_ebook_reserved1) (void); + void (*_ebook_reserved2) (void); + void (*_ebook_reserved3) (void); + void (*_ebook_reserved4) (void); }; GType e_vcard_get_type (void); + +void e_vcard_construct (EVCard *evc, const char *str); EVCard* e_vcard_new (void); EVCard* e_vcard_new_from_string (const char *str); -char* e_vcard_to_string (EVCard *evcard); + +char* e_vcard_to_string (EVCard *evc, EVCardFormat format); + /* mostly for debugging */ void e_vcard_dump_structure (EVCard *evc); /* attributes */ -EVCardAttribute *e_vcard_attribute_new (const char *attr_group, const char *attr_name); -void e_vcard_attribute_free (EVCardAttribute *attr); -void e_vcard_add_attribute (EVCard *evcard, EVCardAttribute *attr); -void e_vcard_add_attribute_with_value (EVCard *evcard, EVCardAttribute *attr, const char *value); -void e_vcard_add_attribute_with_values (EVCard *evcard, EVCardAttribute *attr, ...); -void e_vcard_attribute_add_value (EVCardAttribute *attr, const char *value); -void e_vcard_attribute_add_values (EVCardAttribute *attr, ...); +EVCardAttribute *e_vcard_attribute_new (const char *attr_group, const char *attr_name); +void e_vcard_attribute_free (EVCardAttribute *attr); +EVCardAttribute *e_vcard_attribute_copy (EVCardAttribute *attr); +void e_vcard_remove_attributes (EVCard *evcard, const char *attr_group, const char *attr_name); +void e_vcard_remove_attribute (EVCard *evcard, EVCardAttribute *attr); +void e_vcard_add_attribute (EVCard *evcard, EVCardAttribute *attr); +void e_vcard_add_attribute_with_value (EVCard *evcard, EVCardAttribute *attr, const char *value); +void e_vcard_add_attribute_with_values (EVCard *evcard, EVCardAttribute *attr, ...); +void e_vcard_attribute_add_value (EVCardAttribute *attr, const char *value); +void e_vcard_attribute_add_value_decoded (EVCardAttribute *attr, const char *value, int len); +void e_vcard_attribute_add_values (EVCardAttribute *attr, ...); +void e_vcard_attribute_remove_values (EVCardAttribute *attr); +void e_vcard_attribute_remove_params (EVCardAttribute *attr); /* attribute parameters */ EVCardAttributeParam* e_vcard_attribute_param_new (const char *param_name); void e_vcard_attribute_param_free (EVCardAttributeParam *param); +EVCardAttributeParam* e_vcard_attribute_param_copy (EVCardAttributeParam *param); void e_vcard_attribute_add_param (EVCardAttribute *attr, EVCardAttributeParam *param); void e_vcard_attribute_add_param_with_value (EVCardAttribute *attr, EVCardAttributeParam *param, const char *value); @@ -92,17 +148,18 @@ void e_vcard_attribute_param_add_value (EVCardAttributePa const char *value); void e_vcard_attribute_param_add_values (EVCardAttributeParam *param, ...); +void e_vcard_attribute_param_remove_values (EVCardAttributeParam *param); /* EVCard* accessors. nothing returned from these functions should be freed by the caller. */ GList* e_vcard_get_attributes (EVCard *evcard); const char* e_vcard_attribute_get_group (EVCardAttribute *attr); const char* e_vcard_attribute_get_name (EVCardAttribute *attr); -GList* e_vcard_attribute_get_values (EVCardAttribute *attr); +GList* e_vcard_attribute_get_values (EVCardAttribute *attr); /* GList elements are of type char* */ +GList* e_vcard_attribute_get_values_decoded (EVCardAttribute *attr); /* GList elements are of type GString* */ GList* e_vcard_attribute_get_params (EVCardAttribute *attr); const char* e_vcard_attribute_param_get_name (EVCardAttributeParam *param); GList* e_vcard_attribute_param_get_values (EVCardAttributeParam *param); - #endif /* _EVCARD_H */ diff --git a/addressbook/backend/ebook/test-client-list.c b/addressbook/backend/ebook/test-client-list.c deleted file mode 100644 index 6fa3d6b094..0000000000 --- a/addressbook/backend/ebook/test-client-list.c +++ /dev/null @@ -1,65 +0,0 @@ -/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ -#include - -#include -#include -#include -#include - -#include "e-book.h" - -static void -init_bonobo (int *argc, char **argv) -{ - if (bonobo_init (argc, argv) == FALSE) - g_error (_("Could not initialize Bonobo")); -} - -static void -get_cursor_cb (EBook *book, EBookStatus status, ECardCursor *cursor, gpointer closure) -{ - long length = e_card_cursor_get_length(cursor); - long i; - - printf ("Length: %d\n", (int) length); - for ( i = 0; i < length; i++ ) { - ECard *card = e_card_cursor_get_nth(cursor, i); - char *vcard = e_card_get_vcard_assume_utf8(card); - printf("[%s]\n", vcard); - g_free(vcard); - g_object_unref(card); - } -} - -static void -book_open_cb (EBook *book, EBookStatus status, gpointer closure) -{ - printf ("Book opened.\n"); - e_book_get_cursor(book, "", get_cursor_cb, NULL); -} - -static gboolean -ebook_create (gpointer data) -{ - EBook *book; - - book = e_book_new (); - - e_book_load_uri (book, "file:/tmp/test.db", book_open_cb, NULL); - - return FALSE; -} - -int -main (int argc, char **argv) -{ - gnome_program_init("test-client-list", "0.0", LIBGNOME_MODULE, argc, argv, NULL); - - init_bonobo (&argc, argv); - - g_idle_add (ebook_create, NULL); - - bonobo_main (); - - return 0; -} diff --git a/addressbook/backend/ebook/test-client.c b/addressbook/backend/ebook/test-client.c deleted file mode 100644 index 63461fb671..0000000000 --- a/addressbook/backend/ebook/test-client.c +++ /dev/null @@ -1,191 +0,0 @@ -/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ -#include -#include -#include -#include -#include -#include -#include - -#include "e-book.h" -#include "e-book-util.h" - -#define TEST_VCARD \ -"BEGIN:VCARD\r\n" \ -"FN:Nat\r\n" \ -"N:Friedman;Nat;D;Mr.\r\n" \ -"BDAY:1977-08-06\r\n" \ -"TEL;WORK:617 679 1984\r\n" \ -"TEL;CELL:123 456 7890\r\n" \ -"EMAIL;INTERNET:nat@nat.org\r\n" \ -"EMAIL;INTERNET:nat@ximian.com\r\n" \ -"ADR;WORK;POSTAL:P.O. Box 101;;;Any Town;CA;91921-1234;\r\n" \ -"END:VCARD\r\n" \ -"\r\n" - -static CORBA_Environment ev; -static char *cardstr; - -static void -init_bonobo (int *argc, char **argv) -{ - if (bonobo_init (argc, argv) == FALSE) - g_error (_("Could not initialize Bonobo")); -} - -static void -get_cursor_cb (EBook *book, EBookStatus status, ECardCursor *cursor, gpointer closure) -{ - long length = e_card_cursor_get_length(cursor); - long i; - - /* we just added a card, so the length should be >1 */ - printf ("\n%s: %s(): Number of cards is %ld\n", - __FILE__, G_GNUC_FUNCTION, length); - if (length < 1) - printf ("*** Why isn't this above zero?? ***\n\n"); - - for ( i = 0; i < length; i++ ) { - ECard *card = e_card_cursor_get_nth(cursor, i); - char *vcard = e_card_get_vcard_assume_utf8(card); - printf("Get all cards callback: [%s]\n", vcard); - g_free(vcard); - g_object_unref(card); - } - - g_object_unref (book); - exit(0); -} - -static void -get_card_cb (EBook *book, EBookStatus status, ECard *card, gpointer closure) -{ - char *vcard; - - vcard = e_card_get_vcard_assume_utf8(card); - printf ("Card added: [%s]\n", vcard); - g_free(vcard); - - printf ("Getting cards..\n"); - e_book_get_cursor(book, "(contains \"x-evolution-any-field\" \"\")", get_cursor_cb, NULL); - printf ("Done getting all cards.\n"); -} - -static void -add_card_cb (EBook *book, EBookStatus status, const gchar *id, gpointer closure) -{ - GTimer *timer; - - printf ("Status: %d\n", status); - - printf ("Id: %s\n", id); - - timer = g_timer_new (); - g_timer_start (timer); - e_book_get_card (book, id, get_card_cb, closure); - g_timer_stop (timer); - printf ("%g\n", g_timer_elapsed (timer, NULL)); -} - -static void -get_fields_cb (EBook *book, EBookStatus status, EList *fields, gpointer closure) -{ - if (fields) { - EIterator *iter = e_list_get_iterator (fields); - - printf ("Supported fields:\n"); - - for (; e_iterator_is_valid (iter); e_iterator_next (iter)) { - printf (" %s\n", (char*)e_iterator_get (iter)); - } - - g_object_unref(fields); - } - else { - printf ("No supported fields?\n"); - } - - e_book_add_vcard(book, cardstr, add_card_cb, NULL); -} - - -static void -auth_user_cb (EBook *book, EBookStatus status, gpointer closure) -{ - printf ("user authenticated\n"); - e_book_get_supported_fields (book, get_fields_cb, closure); -} - -static void -book_open_cb (EBook *book, EBookStatus status, gpointer closure) -{ - e_book_authenticate_user (book, "username", "password", "auth_method", auth_user_cb, NULL); -} - -static gboolean -ebook_create (gpointer data) -{ - EBook *book; - - book = e_book_new (); - - if (!book) { - printf ("%s: %s(): Couldn't create EBook, bailing.\n", - __FILE__, - G_GNUC_FUNCTION); - return FALSE; - } - - - e_book_load_default_book (book, book_open_cb, NULL); - - return FALSE; -} - -static char * -read_file (char *name) -{ - int len; - char buff[65536]; - char line[1024]; - FILE *f; - - f = fopen (name, "r"); - if (f == NULL) - g_error ("Unable to open %s!\n", name); - - len = 0; - while (fgets (line, sizeof (line), f) != NULL) { - strcpy (buff + len, line); - len += strlen (line); - } - - fclose (f); - - return g_strdup (buff); -} - - -int -main (int argc, char **argv) -{ - - CORBA_exception_init (&ev); - - gnome_program_init("test-client", "0.0", LIBGNOME_MODULE, argc, argv, NULL); - - init_bonobo (&argc, argv); - - cardstr = NULL; - if (argc == 2) - cardstr = read_file (argv [1]); - - if (cardstr == NULL) - cardstr = TEST_VCARD; - - g_idle_add (ebook_create, NULL); - - bonobo_main (); - - return 0; -} diff --git a/addressbook/backend/ebook/tests/Makefile.am b/addressbook/backend/ebook/tests/Makefile.am index f17f979485..444d692e22 100644 --- a/addressbook/backend/ebook/tests/Makefile.am +++ b/addressbook/backend/ebook/tests/Makefile.am @@ -1 +1 @@ -SUBDIRS=vcard \ No newline at end of file +SUBDIRS=vcard ebook diff --git a/addressbook/backend/ebook/tests/ebook/.cvsignore b/addressbook/backend/ebook/tests/ebook/.cvsignore new file mode 100644 index 0000000000..8dbec11b01 --- /dev/null +++ b/addressbook/backend/ebook/tests/ebook/.cvsignore @@ -0,0 +1,7 @@ +Makefile +Makefile.in +test-date +test-ebook +test-changes +test-photo +test-string diff --git a/addressbook/backend/ebook/tests/ebook/Makefile.am b/addressbook/backend/ebook/tests/ebook/Makefile.am new file mode 100644 index 0000000000..7147690482 --- /dev/null +++ b/addressbook/backend/ebook/tests/ebook/Makefile.am @@ -0,0 +1,12 @@ + +TEST_LIBS=$(top_builddir)/addressbook/backend/ebook/libebook.la + +INCLUDES=-I$(srcdir)/../../.. @EVOLUTION_ADDRESSBOOK_CFLAGS@ + +noinst_PROGRAMS= test-changes test-date test-ebook test-photo test-string + +test_date_LDFLAGS=$(TEST_LIBS) +test_ebook_LDFLAGS=$(TEST_LIBS) +test_changes_LDFLAGS=$(TEST_LIBS) +test_photo_LDFLAGS=$(TEST_LIBS) +test_string_LDFLAGS=$(TEST_LIBS) diff --git a/addressbook/backend/ebook/tests/ebook/test-changes.c b/addressbook/backend/ebook/tests/ebook/test-changes.c new file mode 100644 index 0000000000..0c91f30cf4 --- /dev/null +++ b/addressbook/backend/ebook/tests/ebook/test-changes.c @@ -0,0 +1,89 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ + +#include "ebook/e-book.h" +#include +#include +#include + +#define NEW_VCARD "BEGIN:VCARD\n\ +X-EVOLUTION-FILE-AS:Toshok, Chris\n\ +FN:Chris Toshok\n\ +EMAIL;INTERNET:toshok@ximian.com\n\ +ORG:Ximian, Inc.;\n\ +END:VCARD" + +static char file_template[]="file:///tmp/change-test-XXXXXX"; + +int +main (int argc, char **argv) +{ + EBook *book; + gboolean status; + EContact *contact; + GList *changes; + GError *error = NULL; + EBookChange *change; + + gnome_program_init("test-changes", "0.0", LIBGNOME_MODULE, argc, argv, NULL); + + if (bonobo_init (&argc, argv) == FALSE) + g_error ("Could not initialize Bonobo"); + + mktemp (file_template); + + /* create a temp addressbook in /tmp */ + book = e_book_new (); + + printf ("loading addressbook\n"); + if (!e_book_load_uri (book, file_template, FALSE, &error)) { + printf ("failed to open addressbook: `%s': %s\n", file_template, error->message); + exit(0); + } + + /* get an initial change set */ + if (!e_book_get_changes (book, "changeidtest", &changes, &error)) { + printf ("failed to get changes: %s\n", error->message); + exit(0); + } + + /* make a change to the book */ + contact = e_contact_new_from_vcard (NEW_VCARD); + if (!e_book_add_contact (book, contact, &error)) { + printf ("failed to add new contact: %s\n", error->message); + exit(0); + } + + /* get another change set */ + if (!e_book_get_changes (book, "changeidtest", &changes, &error)) { + printf ("failed to get second set of changes: %s\n", error->message); + exit(0); + } + + /* make sure that 1 change has occurred */ + if (g_list_length (changes) != 1) { + printf ("got back %d changes, was expecting 1\n", g_list_length (changes)); + exit(0); + } + + change = changes->data; + if (change->change_type != E_BOOK_CHANGE_CARD_ADDED) { + printf ("was expecting a CARD_ADDED change, but didn't get it.\n"); + exit(0); + } + + printf ("got changed vcard back: %s\n", change->vcard); + + e_book_free_change_list (changes); + + + if (!e_book_remove (book, &error)) { + printf ("failed to remove book; %s\n", error->message); + exit(0); + } + + g_object_unref (book); + + bonobo_main_quit(); + + return 0; +} diff --git a/addressbook/backend/ebook/tests/ebook/test-date.c b/addressbook/backend/ebook/tests/ebook/test-date.c new file mode 100644 index 0000000000..afe37cf224 --- /dev/null +++ b/addressbook/backend/ebook/tests/ebook/test-date.c @@ -0,0 +1,36 @@ + +#include "ebook/e-book.h" +#include +#include +#include + +int +main (int argc, char **argv) +{ + EContact *contact; + EContactDate date, *dp; + + gnome_program_init("test-string", "0.0", LIBGNOME_MODULE, argc, argv, NULL); + + if (bonobo_init (&argc, argv) == FALSE) + g_error ("Could not initialize Bonobo"); + + contact = e_contact_new (); + + date.year = 1999; + date.month = 3; + date.day = 3; + + e_contact_set (contact, E_CONTACT_BIRTH_DATE, &date); + + printf ("vcard = \n%s\n", e_vcard_to_string (E_VCARD (contact), EVC_FORMAT_VCARD_30)); + + dp = e_contact_get (contact, E_CONTACT_BIRTH_DATE); + + if (dp->year != date.year + || dp->month != date.month + || dp->day != date.day) + printf ("failed\n"); + else + printf ("passed\n"); +} diff --git a/addressbook/backend/ebook/tests/ebook/test-ebook.c b/addressbook/backend/ebook/tests/ebook/test-ebook.c new file mode 100644 index 0000000000..d78d9f3b6a --- /dev/null +++ b/addressbook/backend/ebook/tests/ebook/test-ebook.c @@ -0,0 +1,110 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ + +#include "ebook/e-book.h" +#include +#include +#include + +static void +print_email (EContact *contact) +{ + char *file_as = e_contact_get (contact, E_CONTACT_FILE_AS); + GList *emails, *e; + + printf ("Contact: %s\n", file_as); + printf ("Email addresses:\n"); + emails = e_contact_get (contact, E_CONTACT_EMAIL); + for (e = emails; e; e = e->next) { + EVCardAttribute *attr = e->data; + GList *values = e_vcard_attribute_get_values (attr); + printf ("\t%s\n", values && values->data ? (char*)values->data : ""); + e_vcard_attribute_free (attr); + } + g_list_free (emails); + + g_free (file_as); + + printf ("\n"); +} + +static void +print_all_emails (EBook *book) +{ + EBookQuery *query; + gboolean status; + GList *cards, *c; + + query = e_book_query_field_exists (E_CONTACT_FULL_NAME); + + status = e_book_get_contacts (book, query, &cards, NULL); + + e_book_query_unref (query); + + if (status == FALSE) { + printf ("error %d getting card list\n", status); + exit(0); + } + + for (c = cards; c; c = c->next) { + EContact *contact = E_CONTACT (c->data); + + print_email (contact); + + g_object_unref (contact); + } + g_list_free (cards); +} + +static void +print_one_email (EBook *book) +{ + EContact *contact; + GError *error = NULL; + + if (!e_book_get_contact (book, "pas-id-0002023", &contact, &error)) { + printf ("error %d getting card: %s\n", error->code, error->message); + g_clear_error (&error); + return; + } + + print_email (contact); + + g_object_unref (contact); +} + +int +main (int argc, char **argv) +{ + EBook *book; + gboolean status; + + gnome_program_init("test-ebook", "0.0", LIBGNOME_MODULE, argc, argv, NULL); + + if (bonobo_init (&argc, argv) == FALSE) + g_error ("Could not initialize Bonobo"); + + /* + ** the actual ebook foo + */ + + book = e_book_new (); + + printf ("loading addressbook\n"); + status = e_book_load_local_addressbook (book, NULL); + if (status == FALSE) { + printf ("failed to open local addressbook\n"); + exit(0); + } + + printf ("printing one contact\n"); + print_one_email (book); + + printf ("printing all contacts\n"); + print_all_emails (book); + + g_object_unref (book); + + bonobo_main_quit(); + + return 0; +} diff --git a/addressbook/backend/ebook/tests/ebook/test-photo.c b/addressbook/backend/ebook/tests/ebook/test-photo.c new file mode 100644 index 0000000000..cbd6817b37 --- /dev/null +++ b/addressbook/backend/ebook/tests/ebook/test-photo.c @@ -0,0 +1,59 @@ + +#include "ebook/e-book.h" +#include +#include +#include + +const char *photo_data = "/9j/4AAQSkZJRgABAQEARwBHAAD//gAXQ3JlYXRlZCB3aXRo\ +IFRoZSBHSU1Q/9sAQwAIBgYHBgUIBwcHCQkICgwUDQwLCwwZEhMPFB0aHx4dGhwcICQuJyAiLC\ +McHCg3KSwwMTQ0NB8nOT04MjwuMzQy/9sAQwEJCQkMCwwYDQ0YMiEcITIyMjIyMjIyMjIyMjIy\ +MjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIy/8AAEQgAMgAyAwEiAAIRAQMRAf\ +/EABsAAQACAwEBAAAAAAAAAAAAAAAHCAQFBgID/8QAMBAAAgEDAQYEBQQDAAAAAAAAAQIDAAQR\ +BQYSEyExQQdhcYEiI0JRkRQVMqFiguH/xAAaAQADAQEBAQAAAAAAAAAAAAAABAUCBgED/8QAIx\ +EAAgICAQQCAwAAAAAAAAAAAAECAwQRQRITITEUYQUiUf/aAAwDAQACEQMRAD8An+sHUtWtNKjV\ +rmQ7754cajLvjrgfbzPIdzWdVfds9pJb3XdQkMrcFZGj+HqY0bdVV9Tz/wBia+N9vbjvkaxMb5\ +E9N6SJB1HxLEEjJaWsUjD6QzSMPXdGB7E1zV74t63HINy1s4F7CWCTn77wrA0TY86jY3N1qsUk\ +6wxBxBDvYjLHkoUH4j3JP/a0V3s1CvF/QM9tKpw0THeU+TLkj8VLnmzT8y0n9FujBx5bioba/r\ +ZLWx3iPZ7RzLp95GtnqRGVTezHNjruH7/4n+67iqpq7Qi3uYWMMsNynfnE6sM8/Lr6VamFi0KM\ +epUE1Sx7XZHbI+fjxos1H0z3SlKYEjzISI2I64OKqsyu8sck2QYrmPjBvpIYg598Vauoh8VtlY\ +7JW2isoBwpPl6hGByZTyD+o6E+h7UtlVOcPHA/+PyI1Wal6Zp7vaC/06wnTTLtEeUDiKwzu4H8\ +vI9AM9Tiuctkng1Nnk1G5cOoYifB4nI/jB7VjWuoT21qPmwXUCHKlphHKvqG5N6g0/cLi/Rg88\ +FhbkbxlaUSu3kqpnn6kDzqGqbNdPB0XyK4/svZr9RVntL50GePdcKEDqzhVBx7sKtPpayppNos\ +xzKIlDHzxUFeG2zo2n2kivWhK6PpHwwoTnfk65J7kZyT9z5VYADAwKuYtfRA5zPv7tnjgUpSmR\ +EV8bq1hvbWW1uY1khlUo6MMhgeor7UoAje18FtmLe9eeQT3EXPcglkJRPbv71EWu7Dajp2o3MG\ +mlRCkjKQ30jPUe1WlrlNW0RptTleNB84DnjkD0P9VlxT4Nqck9pmn8JuFp2zo0cgCWFi2e7555\ +/NSHXLadso2m3sU0NxlV65HM+VdTW3rgwvsUpSvAFKUoAUxSlAClKUAKUpQB//2Q=="; + + +int +main (int argc, char **argv) +{ + EContact *contact; + EContactPhoto *photo, *new_photo; + + gnome_program_init("test-photo", "0.0", LIBGNOME_MODULE, argc, argv, NULL); + + if (bonobo_init (&argc, argv) == FALSE) + g_error ("Could not initialize Bonobo"); + + contact = e_contact_new (); + + photo = g_new (EContactPhoto, 1); + photo->data = g_strdup (photo_data); + photo->length = _evc_base64_decode_simple (photo->data, strlen (photo_data)); + + /* set the photo */ + e_contact_set (contact, E_CONTACT_PHOTO, photo); + + /* then get the photo */ + new_photo = e_contact_get (contact, E_CONTACT_PHOTO); + + /* and compare */ + if (new_photo->length != photo->length) + g_error ("photo lengths differ"); + + if (memcmp (new_photo->data, photo->data, photo->length)) + g_error ("photo data differs"); + + printf ("photo test passed\n"); +} diff --git a/addressbook/backend/ebook/tests/ebook/test-string.c b/addressbook/backend/ebook/tests/ebook/test-string.c new file mode 100644 index 0000000000..b7cdbb3720 --- /dev/null +++ b/addressbook/backend/ebook/tests/ebook/test-string.c @@ -0,0 +1,27 @@ + +#include "ebook/e-book.h" +#include +#include +#include + +#define TEST_ID "test-uid" + +int +main (int argc, char **argv) +{ + EContact *contact; + + gnome_program_init("test-string", "0.0", LIBGNOME_MODULE, argc, argv, NULL); + + if (bonobo_init (&argc, argv) == FALSE) + g_error ("Could not initialize Bonobo"); + + contact = e_contact_new (); + + e_contact_set (contact, E_CONTACT_UID, TEST_ID); + + if (!strcmp (e_contact_get_const (contact, E_CONTACT_UID), TEST_ID)) + printf ("passed\n"); + else + printf ("failed\n"); +} diff --git a/addressbook/backend/ebook/tests/vcard/Makefile.am b/addressbook/backend/ebook/tests/vcard/Makefile.am index ae16780095..7e57329e1d 100644 --- a/addressbook/backend/ebook/tests/vcard/Makefile.am +++ b/addressbook/backend/ebook/tests/vcard/Makefile.am @@ -1,6 +1,8 @@ -CFLAGS=-I$(srcdir)/../.. `pkg-config --cflags gobject-2.0` +TEST_LIBS=$(top_builddir)/addressbook/backend/ebook/libebook.la + +INCLUDES=-I$(srcdir)/../../.. @EVOLUTION_ADDRESSBOOK_CFLAGS@ noinst_PROGRAMS=dump-vcard -dump_vcard_LDFLAGS=$(top_builddir)/addressbook/backend/ebook/libevcard.la `pkg-config --libs gobject-2.0` +dump_vcard_LDFLAGS=$(TEST_LIBS) diff --git a/addressbook/backend/ebook/tests/vcard/dump-vcard.c b/addressbook/backend/ebook/tests/vcard/dump-vcard.c index 52dbf8a957..907a00efa7 100644 --- a/addressbook/backend/ebook/tests/vcard/dump-vcard.c +++ b/addressbook/backend/ebook/tests/vcard/dump-vcard.c @@ -1,7 +1,7 @@ /* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ #include -#include "e-vcard.h" +#include "ebook/e-vcard.h" FILE *fp; diff --git a/addressbook/backend/idl/addressbook.idl b/addressbook/backend/idl/addressbook.idl index c9ce728a15..1ad3a62dd9 100644 --- a/addressbook/backend/idl/addressbook.idl +++ b/addressbook/backend/idl/addressbook.idl @@ -12,98 +12,120 @@ module GNOME { module Evolution { module Addressbook { - typedef string CardId; + typedef string ContactId; typedef string VCard; typedef sequence VCardList; - typedef sequence CardIdList; + typedef sequence ContactIdList; typedef sequence stringlist; - interface CardCursor : Bonobo::Unknown { - long count (); - string getNth (in long n); + enum BookChangeType { + ContactAdded, + ContactModified, + ContactDeleted + }; + + union BookChangeItem switch (BookChangeType) { + case ContactAdded: + VCard add_vcard; + case ContactModified: + VCard mod_vcard; + case ContactDeleted: + ContactId del_id; + }; + + typedef sequence BookChangeList; + + enum CallStatus { + Success, + RepositoryOffline, + PermissionDenied, + ContactNotFound, + ContactIdAlreadyExists, + AuthenticationFailed, + AuthenticationRequired, + UnsupportedField, + UnsupportedAuthenticationMethod, + TLSNotAvailable, + NoSuchBook, + BookRemoved, + + /* These can be returned for successful searches, but + indicate the result set was truncated */ + SearchSizeLimitExceeded, + SearchTimeLimitExceeded, + + InvalidQuery, + QueryRefused, + + CouldNotCancel, + + OtherError }; /* * A book view is a live view of a book. It's either a view - * of all the cards in the book or a view of a query. When - * created, it will get a series of signal_card_added calls + * of all the contacts in the book or a view of a query. When + * created, it will get a series of notifyContactsAdded calls * for all objects in the initial set. After that, it will * get added, removed, or changed signals whenever the book - * changes (if it affects the set of viewed cards.) + * changes (if it affects the set of viewed contacts.) */ interface BookViewListener : Bonobo::Unknown { - enum CallStatus { - Success, - /* These are still successful searches, but - the result set was truncated */ - SearchSizeLimitExceeded, - SearchTimeLimitExceeded, - - /* These are failures */ - InvalidQuery, - QueryRefused, - OtherError - }; - void notifyCardAdded (in VCardList cards); - void notifyCardsRemoved (in CardIdList ids); - void notifyCardChanged (in VCardList cards); - void notifySequenceComplete (in CallStatus status); - void notifyStatusMessage (in string message); + oneway void notifyContactsAdded (in VCardList vcards); + oneway void notifyContactsRemoved (in ContactIdList ids); + oneway void notifyContactsChanged (in VCardList vcards); + oneway void notifySequenceComplete (in CallStatus status); + oneway void notifyProgress (in string message, in short percent); }; interface BookView : Bonobo::Unknown { + oneway void start (); }; interface Book : Bonobo::Unknown { /* - * Fetching cards in the addresbook. + * Opening/creating addressbooks. */ - void getVCard (in CardId id); + oneway void open (in boolean only_if_exists); - void authenticateUser (in string user, in string passwd, - in string authMethod); + /* + * Removing addressbooks. + */ + oneway void remove (); /* - * Adding and deleting cards in the book. + * Fetching contacts in the addresbook. */ - void addCard (in VCard vcard); - void removeCards (in CardIdList Id); - + oneway void getContact (in ContactId id); + + oneway void authenticateUser (in string user, in string passwd, + in string authMethod); + /* - * Modifying cards in the addressbook. + * Adding and deleting contacts in the book. */ - void modifyCard (in VCard vcard); - + oneway void addContact (in VCard vcard); + oneway void removeContacts (in ContactIdList Id); + /* - * This function returns a cursor to the book - * listener. This is for people who want a snapshot - * of the addressbook. + * Modifying contacts in the addressbook. */ - void getCursor (in string query); + oneway void modifyContact (in VCard vcard); /* * These two functions return a book view to the book * listener. This is for people who want a live view * of the addressbook. */ - void getBookView (in BookViewListener listener, in string query); + oneway void getBookView (in BookViewListener listener, in string query, + in stringlist requested_fields, in long max_results); - void getChanges (in BookViewListener listener, in string change_id); + oneway void getChanges (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 (); + oneway void getContactList (in string query); - void getSupportedFields (); + oneway void getSupportedFields (); /* * This function returns a list of strings @@ -127,86 +149,40 @@ module Addressbook { * as it will be passed unchanged to the backend auth * function (eg. ldap_sasl_bind) */ - void getSupportedAuthMethods (); + oneway void getSupportedAuthMethods (); string getStaticCapabilities (); string getName (); + + /* cancels the currently running operation, whatever + it is. */ + CallStatus cancelOperation (); }; interface BookListener : Bonobo::Unknown { - enum CallStatus { - Success, - RepositoryOffline, - PermissionDenied, - CardNotFound, - CardIdAlreadyExists, - ProtocolNotSupported, - AuthenticationFailed, - AuthenticationRequired, - UnsupportedField, - UnsupportedAuthenticationMethod, - TLSNotAvailable, - NoSuchBook, - - OtherError - }; - - void notifyCardCreated (in CallStatus status, in CardId Id); - - void notifyCardsRemoved (in CallStatus status); - - void notifyCardModified (in CallStatus status); - - void notifyOpenBookProgress (in string status_message, in short percent); - - void notifyBookOpened (in CallStatus status, in Book book); - - void notifyCardRequested (in CallStatus status, in VCard card); - - void notifyCursorRequested (in CallStatus status, in CardCursor cursor); - - void notifyViewRequested (in CallStatus status, in BookView view); - - void notifyChangesRequested (in CallStatus status, in BookView view); - - void notifyAuthenticationResult (in CallStatus status); - - void notifySupportedFields (in CallStatus status, in stringlist fields); - - void notifySupportedAuthMethods (in CallStatus status, in stringlist fields); - - /** - * notifyConnectionStatus: - * - * Used to report changes in the connection to the - * contact repository. This is often a response to a - * call to check_connection() on the Book, but wombat - * is free to report the connection status without - * being asked. - */ - void notifyConnectionStatus (in boolean connected); - - /** - * notifyWritable: - * - * Used to report whether or not a backend can write - * to a given addressbook. All books default to - * read-only, so unless you receive a notification - * saying otherwise, treat the book as read-only. It - * is presumed that this notification will be sent - * early (just after a connection is opened, usually), - * but it may also be sent later, if/when the backend - * notices a change. - */ - void notifyWritable (in boolean writable); + oneway void notifyContactCreated (in CallStatus status, in ContactId Id); + oneway void notifyContactsRemoved (in CallStatus status); + oneway void notifyContactModified (in CallStatus status); + oneway void notifyProgress (in string status_message, in short precent); + oneway void notifyBookOpened (in CallStatus status); + oneway void notifyBookRemoved (in CallStatus status); + oneway void notifyViewRequested (in CallStatus status, in BookView view); + oneway void notifyChangesRequested (in CallStatus status, in BookChangeList changes); + oneway void notifyContactRequested (in CallStatus status, in VCard vcard); + oneway void notifyContactListRequested (in CallStatus status, in stringlist contacts); + oneway void notifySupportedFields (in CallStatus status, in stringlist fields); + oneway void notifyAuthenticationResult (in CallStatus status); + oneway void notifySupportedAuthMethods (in CallStatus status, in stringlist auth_methods); + + oneway void notifyWritable (in boolean writable); }; interface BookFactory : Bonobo::Unknown { exception ProtocolNotSupported {}; - void openBook (in string uri, in BookListener listener) + Book getBook (in string uri, in BookListener listener) raises (ProtocolNotSupported); }; }; diff --git a/addressbook/backend/pas/Makefile.am b/addressbook/backend/pas/Makefile.am index c618050ca2..b602a21512 100644 --- a/addressbook/backend/pas/Makefile.am +++ b/addressbook/backend/pas/Makefile.am @@ -42,7 +42,7 @@ ldapschemadir = $(privdatadir) ldapschema_DATA= $(LDAP_SCHEMA) privlib_LIBRARIES = libpas.a -noinst_LIBRARIES = libpasfile.a $(LDAP_BACKEND) +noinst_LIBRARIES = libpasfile.a libpasvcf.a $(LDAP_BACKEND) pasincludedir = $(privincludedir)/pas @@ -54,7 +54,8 @@ pasinclude_HEADERS = \ pas-backend-card-sexp.h \ pas-backend.h \ pas-backend-summary.h \ - pas-card-cursor.h + pas-backend-sync.h \ + pas-types.h libpas_a_SOURCES = \ $(pasinclude_HEADERS) \ @@ -66,13 +67,18 @@ libpas_a_SOURCES = \ pas-backend-file.c \ pas-backend.c \ pas-backend-summary.c \ - pas-card-cursor.c \ - pas-marshal.c + pas-backend-sync.c \ + pas-marshal.c \ + ximian-vcard.h libpasfile_a_SOURCES = \ pas-backend-file.c \ pas-backend-file.h +libpasvcf_a_SOURCES = \ + pas-backend-vcf.c \ + pas-backend-vcf.h + if ENABLE_LDAP libpasldap_a_SOURCES = \ $(LDAP_BACKEND_FILES) diff --git a/addressbook/backend/pas/pas-backend-card-sexp.c b/addressbook/backend/pas/pas-backend-card-sexp.c index e7b5d8a87d..1ccb4f2433 100644 --- a/addressbook/backend/pas/pas-backend-card-sexp.c +++ b/addressbook/backend/pas/pas-backend-card-sexp.c @@ -22,7 +22,6 @@ #include #include -#include #include static GObjectClass *parent_class; @@ -35,17 +34,17 @@ struct _PASBackendCardSExpPrivate { }; struct _SearchContext { - ECardSimple *card; + EContact *contact; }; static gboolean -compare_email (ECardSimple *card, const char *str, +compare_email (EContact *contact, const char *str, char *(*compare)(const char*, const char*)) { int i; - for (i = E_CARD_SIMPLE_EMAIL_ID_EMAIL; i < E_CARD_SIMPLE_EMAIL_ID_LAST; i ++) { - const char *email = e_card_simple_get_email (card, i); + for (i = E_CONTACT_EMAIL_1; i <= E_CONTACT_EMAIL_3; i ++) { + const char *email = e_contact_get_const (contact, i); if (email && compare(email, str)) return TRUE; @@ -55,32 +54,36 @@ compare_email (ECardSimple *card, const char *str, } static gboolean -compare_phone (ECardSimple *card, const char *str, +compare_phone (EContact *contact, const char *str, char *(*compare)(const char*, const char*)) { int i; + gboolean rv = FALSE; - for (i = E_CARD_SIMPLE_PHONE_ID_ASSISTANT; i < E_CARD_SIMPLE_PHONE_ID_LAST; i ++) { - const ECardPhone *phone = e_card_simple_get_phone (card, i); + for (i = E_CONTACT_FIRST_PHONE_ID; i <= E_CONTACT_LAST_PHONE_ID; i ++) { + char *phone = e_contact_get (contact, i); - if (phone && compare(phone->number, str)) - return TRUE; + rv = phone && compare(phone, str); + g_free (phone); + + if (rv) + break; } - return FALSE; + return rv; } static gboolean -compare_name (ECardSimple *card, const char *str, +compare_name (EContact *contact, const char *str, char *(*compare)(const char*, const char*)) { const char *name; - name = e_card_simple_get_const (card, E_CARD_SIMPLE_FIELD_FULL_NAME); + name = e_contact_get_const (contact, E_CONTACT_FULL_NAME); if (name && compare (name, str)) return TRUE; - name = e_card_simple_get_const (card, E_CARD_SIMPLE_FIELD_FAMILY_NAME); + name = e_contact_get_const (contact, E_CONTACT_FAMILY_NAME); if (name && compare (name, str)) return TRUE; @@ -88,7 +91,7 @@ compare_name (ECardSimple *card, const char *str, } static gboolean -compare_address (ECardSimple *card, const char *str, +compare_address (EContact *contact, const char *str, char *(*compare)(const char*, const char*)) { g_warning("address searching not implemented\n"); @@ -96,23 +99,17 @@ compare_address (ECardSimple *card, const char *str, } static gboolean -compare_category (ECardSimple *card, const char *str, +compare_category (EContact *contact, const char *str, char *(*compare)(const char*, const char*)) { - EList *categories; - EIterator *iterator; - ECard *ecard; + GList *categories; + GList *iterator; gboolean ret_val = FALSE; - g_object_get (card, - "card", &ecard, - NULL); - g_object_get (ecard, - "category_list", &categories, - NULL); + categories = e_contact_get (contact, E_CONTACT_CATEGORY_LIST); - for (iterator = e_list_get_iterator(categories); e_iterator_is_valid (iterator); e_iterator_next (iterator)) { - const char *category = e_iterator_get (iterator); + for (iterator = categories; iterator; iterator = iterator->next) { + const char *category = iterator->data; if (compare(category, str)) { ret_val = TRUE; @@ -120,83 +117,45 @@ compare_category (ECardSimple *card, const char *str, } } - g_object_unref (iterator); - e_card_free_empty_lists (ecard); - g_object_unref (categories); - g_object_unref (ecard); - return ret_val; -} - -static gboolean -compare_arbitrary (ECardSimple *card, const char *str, - char *(*compare)(const char*, const char*)) -{ - EList *list; - EIterator *iterator; - ECard *ecard; - gboolean ret_val = FALSE; - - g_object_get (card, - "card", &ecard, - NULL); - g_object_get (ecard, - "arbitrary", &list, - NULL); - - for (iterator = e_list_get_iterator(list); e_iterator_is_valid (iterator); e_iterator_next (iterator)) { - const ECardArbitrary *arbitrary = e_iterator_get (iterator); + g_list_foreach (categories, (GFunc)g_free, NULL); + g_list_free (categories); - if (compare(arbitrary->key, str)) { - ret_val = TRUE; - break; - } - } - - g_object_unref (iterator); - e_card_free_empty_lists (ecard); - g_object_unref (list); - g_object_unref (ecard); return ret_val; } static struct prop_info { - ECardSimpleField field_id; + EContactField field_id; const char *query_prop; - const char *ecard_prop; #define PROP_TYPE_NORMAL 0x01 #define PROP_TYPE_LIST 0x02 -#define PROP_TYPE_LISTITEM 0x03 -#define PROP_TYPE_ID 0x04 int prop_type; - gboolean (*list_compare)(ECardSimple *ecard, const char *str, + gboolean (*list_compare)(EContact *contact, const char *str, char *(*compare)(const char*, const char*)); } prop_info_table[] = { -#define NORMAL_PROP(f,q,e) {f, q, e, PROP_TYPE_NORMAL, NULL} -#define ID_PROP {0, "id", NULL, PROP_TYPE_ID, NULL} -#define LIST_PROP(q,e,c) {0, q, e, PROP_TYPE_LIST, c} - - /* query prop, ecard prop, type, list compare function */ - NORMAL_PROP ( E_CARD_SIMPLE_FIELD_FILE_AS, "file_as", "file_as" ), - LIST_PROP ( "full_name", "full_name", compare_name), /* not really a list, but we need to compare both full and surname */ - NORMAL_PROP ( E_CARD_SIMPLE_FIELD_URL, "url", "url" ), - NORMAL_PROP ( E_CARD_SIMPLE_FIELD_MAILER, "mailer", "mailer"), - NORMAL_PROP ( E_CARD_SIMPLE_FIELD_ORG, "org", "org"), - NORMAL_PROP ( E_CARD_SIMPLE_FIELD_ORG_UNIT, "org_unit", "org_unit"), - NORMAL_PROP ( E_CARD_SIMPLE_FIELD_OFFICE, "office", "office"), - NORMAL_PROP ( E_CARD_SIMPLE_FIELD_TITLE, "title", "title"), - NORMAL_PROP ( E_CARD_SIMPLE_FIELD_ROLE, "role", "role"), - NORMAL_PROP ( E_CARD_SIMPLE_FIELD_MANAGER, "manager", "manager"), - NORMAL_PROP ( E_CARD_SIMPLE_FIELD_ASSISTANT, "assistant", "assistant"), - NORMAL_PROP ( E_CARD_SIMPLE_FIELD_NICKNAME, "nickname", "nickname"), - NORMAL_PROP ( E_CARD_SIMPLE_FIELD_SPOUSE, "spouse", "spouse" ), - NORMAL_PROP ( E_CARD_SIMPLE_FIELD_NOTE, "note", "note"), - ID_PROP, - LIST_PROP ( "email", "email", compare_email ), - LIST_PROP ( "phone", "phone", compare_phone ), - LIST_PROP ( "address", "address", compare_address ), - LIST_PROP ( "category", "category", compare_category ), - LIST_PROP ( "arbitrary", "arbitrary", compare_arbitrary ) +#define NORMAL_PROP(f,q) {f, q, PROP_TYPE_NORMAL, NULL} +#define LIST_PROP(q,c) {0, q, PROP_TYPE_LIST, c} + + /* query prop, type, list compare function */ + NORMAL_PROP ( E_CONTACT_FILE_AS, "file_as" ), + LIST_PROP ( "full_name", compare_name), /* not really a list, but we need to compare both full and surname */ + NORMAL_PROP ( E_CONTACT_HOMEPAGE_URL, "url"), + NORMAL_PROP ( E_CONTACT_MAILER, "mailer"), + NORMAL_PROP ( E_CONTACT_ORG, "org"), + NORMAL_PROP ( E_CONTACT_ORG_UNIT, "org_unit"), + NORMAL_PROP ( E_CONTACT_OFFICE, "office"), + NORMAL_PROP ( E_CONTACT_TITLE, "title"), + NORMAL_PROP ( E_CONTACT_ROLE, "role"), + NORMAL_PROP ( E_CONTACT_MANAGER, "manager"), + NORMAL_PROP ( E_CONTACT_ASSISTANT, "assistant"), + NORMAL_PROP ( E_CONTACT_NICKNAME, "nickname"), + NORMAL_PROP ( E_CONTACT_SPOUSE, "spouse" ), + NORMAL_PROP ( E_CONTACT_NOTE, "note"), + NORMAL_PROP ( E_CONTACT_UID, "id"), + LIST_PROP ( "email", compare_email ), + LIST_PROP ( "phone", compare_phone ), + LIST_PROP ( "address", compare_address ), + LIST_PROP ( "category", compare_category ), }; static int num_prop_infos = sizeof(prop_info_table) / sizeof(prop_info_table[0]); @@ -225,28 +184,10 @@ entry_compare(SearchContext *ctx, struct _ESExp *f, info = &prop_info_table[i]; if (info->prop_type == PROP_TYPE_NORMAL) { - char *prop = NULL; - /* searches where the query's property - maps directly to an ecard property */ - - prop = e_card_simple_get (ctx->card, info->field_id); - - if (prop && compare(prop, argv[1]->value.string)) { - truth = TRUE; - } - if ((!prop) && compare("", argv[1]->value.string)) { - truth = TRUE; - } - g_free (prop); - } else if (info->prop_type == PROP_TYPE_LIST) { - /* the special searches that match any of the list elements */ - truth = info->list_compare (ctx->card, argv[1]->value.string, compare); - } else if (info->prop_type == PROP_TYPE_ID) { const char *prop = NULL; - /* searches where the query's property - maps directly to an ecard property */ + /* straight string property matches */ - prop = e_card_get_id (ctx->card->card); + prop = e_contact_get_const (ctx->contact, info->field_id); if (prop && compare(prop, argv[1]->value.string)) { truth = TRUE; @@ -255,6 +196,10 @@ entry_compare(SearchContext *ctx, struct _ESExp *f, truth = TRUE; } } + else if (info->prop_type == PROP_TYPE_LIST) { + /* the special searches that match any of the list elements */ + truth = info->list_compare (ctx->contact, argv[1]->value.string, compare); + } /* if we're looking at all fields and find a match, or if we're just looking at this one field, @@ -335,6 +280,51 @@ func_beginswith(struct _ESExp *f, int argc, struct _ESExpResult **argv, void *da return entry_compare (ctx, f, argc, argv, beginswith_helper); } +static ESExpResult * +func_exists(struct _ESExp *f, int argc, struct _ESExpResult **argv, void *data) +{ + SearchContext *ctx = data; + ESExpResult *r; + int truth = FALSE; + + if (argc == 1 + && argv[0]->type == ESEXP_RES_STRING) { + char *propname; + struct prop_info *info = NULL; + int i; + + propname = argv[0]->value.string; + + for (i = 0; i < num_prop_infos; i ++) { + if (!strcmp (prop_info_table[i].query_prop, propname)) { + info = &prop_info_table[i]; + + if (info->prop_type == PROP_TYPE_NORMAL) { + const char *prop = NULL; + /* searches where the query's property + maps directly to an ecard property */ + + prop = e_contact_get_const (ctx->contact, info->field_id); + + if (prop && *prop) + truth = TRUE; + } + else if (info->prop_type == PROP_TYPE_LIST) { + /* the special searches that match any of the list elements */ + truth = info->list_compare (ctx->contact, "", (char *(*)(const char*, const char*)) e_utf8_strstrcase); + } + + break; + } + } + + } + r = e_sexp_result_new(f, ESEXP_RES_BOOL); + r->value.bool = truth; + + return r; +} + /* 'builtin' functions */ static struct { char *name; @@ -346,25 +336,27 @@ static struct { { "is", func_is, 0 }, { "beginswith", func_beginswith, 0 }, { "endswith", func_endswith, 0 }, + { "exists", func_exists, 0 }, }; gboolean -pas_backend_card_sexp_match_ecard (PASBackendCardSExp *sexp, ECard *ecard) +pas_backend_card_sexp_match_contact (PASBackendCardSExp *sexp, EContact *contact) { ESExpResult *r; gboolean retval; - sexp->priv->search_context->card = e_card_simple_new (ecard); - - /* if it's not a valid vcard why is it in our db? :) */ - if (!sexp->priv->search_context->card) + if (!contact) { + g_warning ("null EContact passed to pas_backend_card_sexp_match_contact"); return FALSE; + } + + sexp->priv->search_context->contact = g_object_ref (contact); r = e_sexp_eval(sexp->priv->search_sexp); retval = (r && r->type == ESEXP_RES_BOOL && r->value.bool); - g_object_unref(sexp->priv->search_context->card); + g_object_unref(sexp->priv->search_context->contact); e_sexp_result_free(sexp->priv->search_sexp, r); @@ -374,14 +366,14 @@ pas_backend_card_sexp_match_ecard (PASBackendCardSExp *sexp, ECard *ecard) gboolean pas_backend_card_sexp_match_vcard (PASBackendCardSExp *sexp, const char *vcard) { - ECard *card; + EContact *contact; gboolean retval; - card = e_card_new ((char*)vcard); + contact = e_contact_new_from_vcard (vcard); - retval = pas_backend_card_sexp_match_ecard (sexp, card); + retval = pas_backend_card_sexp_match_contact (sexp, contact); - g_object_unref(card); + g_object_unref(contact); return retval; } @@ -404,7 +396,8 @@ pas_backend_card_sexp_new (const char *text) if (symbols[i].type == 1) { e_sexp_add_ifunction(sexp->priv->search_sexp, 0, symbols[i].name, (ESExpIFunc *)symbols[i].func, sexp->priv->search_context); - } else { + } + else { e_sexp_add_function(sexp->priv->search_sexp, 0, symbols[i].name, symbols[i].func, sexp->priv->search_context); } diff --git a/addressbook/backend/pas/pas-backend-card-sexp.h b/addressbook/backend/pas/pas-backend-card-sexp.h index eb7c7c6641..7efb697fb0 100644 --- a/addressbook/backend/pas/pas-backend-card-sexp.h +++ b/addressbook/backend/pas/pas-backend-card-sexp.h @@ -26,7 +26,8 @@ #include #include -#include +#include +#include #define PAS_TYPE_BACKEND_CARD_SEXP (pas_backend_card_sexp_get_type ()) #define PAS_BACKEND_CARD_SEXP(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), PAS_TYPE_BACKEND_CARD_SEXP, PASBackendCardSExp)) @@ -37,19 +38,19 @@ typedef struct _PASBackendCardSExpPrivate PASBackendCardSExpPrivate; -typedef struct { +struct _PASBackendCardSExp { GObject parent_object; PASBackendCardSExpPrivate *priv; -} PASBackendCardSExp; +}; -typedef struct { +struct _PASBackendCardSExpClass { GObjectClass parent_class; -} PASBackendCardSExpClass; +}; PASBackendCardSExp *pas_backend_card_sexp_new (const char *text); GType pas_backend_card_sexp_get_type (void); gboolean pas_backend_card_sexp_match_vcard (PASBackendCardSExp *sexp, const char *vcard); -gboolean pas_backend_card_sexp_match_ecard (PASBackendCardSExp *sexp, ECard *ecard); +gboolean pas_backend_card_sexp_match_contact (PASBackendCardSExp *sexp, EContact *contact); #endif /* __PAS_BACKEND_CARD_SEXP_H__ */ 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; diff --git a/addressbook/backend/pas/pas-backend-file.h b/addressbook/backend/pas/pas-backend-file.h index fd98d2cdd5..6e1a77b119 100644 --- a/addressbook/backend/pas/pas-backend-file.h +++ b/addressbook/backend/pas/pas-backend-file.h @@ -5,7 +5,7 @@ #ifndef __PAS_BACKEND_FILE_H__ #define __PAS_BACKEND_FILE_H__ -#include "pas-backend.h" +#include "pas-backend-sync.h" #define PAS_TYPE_BACKEND_FILE (pas_backend_file_get_type ()) #define PAS_BACKEND_FILE(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), PAS_TYPE_BACKEND_FILE, PASBackendFile)) @@ -17,12 +17,12 @@ typedef struct _PASBackendFilePrivate PASBackendFilePrivate; typedef struct { - PASBackend parent_object; + PASBackendSync parent_object; PASBackendFilePrivate *priv; } PASBackendFile; typedef struct { - PASBackendClass parent_class; + PASBackendSyncClass parent_class; } PASBackendFileClass; PASBackend *pas_backend_file_new (void); diff --git a/addressbook/backend/pas/pas-backend-ldap.c b/addressbook/backend/pas/pas-backend-ldap.c index 1e8677e559..9c44e9983f 100644 --- a/addressbook/backend/pas/pas-backend-ldap.c +++ b/addressbook/backend/pas/pas-backend-ldap.c @@ -34,13 +34,13 @@ #include #include -#include +#include #include #include "pas-backend-ldap.h" #include "pas-backend-card-sexp.h" #include "pas-book.h" -#include "pas-card-cursor.h" +#include "pas-book-view.h" #include @@ -59,14 +59,6 @@ typedef enum { /* timeout for ldap_result */ #define LDAP_RESULT_TIMEOUT_MILLIS 10 -/* smart grouping stuff */ -#define GROUPING_INITIAL_SIZE 1 -#define GROUPING_MAXIMUM_SIZE 200 - -/* the next two are in milliseconds */ -#define GROUPING_MINIMUM_WAIT 0 /* we never send updates faster than this, to avoid totally spamming the UI */ -#define GROUPING_MAXIMUM_WAIT 250 /* we always send updates (if there are pending cards) when we hit this */ - #define TV_TO_MILLIS(timeval) ((timeval).tv_sec * 1000 + (timeval).tv_usec / 1000) /* the objectClasses we need */ @@ -107,12 +99,10 @@ struct _PASBackendLDAPPrivate { was not built into openldap. */ PASBackendLDAPUseTLS use_tls; - EList *book_views; - LDAP *ldap; - EList *supported_fields; - EList *supported_auth_methods; + GList *supported_fields; + GList *supported_auth_methods; /* whether or not there's support for the objectclass we need to store all our additional fields */ @@ -138,7 +128,6 @@ struct _PASBackendLDAPBookView { PASBookView *book_view; PASBackendLDAPPrivate *blpriv; gchar *search; - PASBackendCardSExp *card_sexp; int limit; LDAPOp *search_op; @@ -160,122 +149,129 @@ static void ldap_op_add (LDAPOp *op, PASBackend *backend, PASBook *book, PASBookView *view, int id, LDAPOpHandler handler, LDAPOpDtor dtor); static void ldap_op_finished (LDAPOp *op); -static void ldap_search_op_timeout (LDAPOp *op, glong cur_millis); - static gboolean poll_ldap (PASBackendLDAP *bl); -static ECardSimple *build_card_from_entry (LDAP *ldap, LDAPMessage *e, GList **existing_objectclasses); +static EContact *build_contact_from_entry (LDAP *ldap, LDAPMessage *e, GList **existing_objectclasses); + +static void email_populate (EContact *contact, char **values); +struct berval** email_ber (EContact *contact); +static gboolean email_compare (EContact *contact1, EContact *contact2); -static void email_populate (ECardSimple *card, char **values); -struct berval** email_ber (ECardSimple *card); -static gboolean email_compare (ECardSimple *ecard1, ECardSimple *ecard2); +static void homephone_populate (EContact *contact, char **values); +struct berval** homephone_ber (EContact *contact); +static gboolean homephone_compare (EContact *contact1, EContact *contact2); -static void homephone_populate (ECardSimple *card, char **values); -struct berval** homephone_ber (ECardSimple *card); -static gboolean homephone_compare (ECardSimple *ecard1, ECardSimple *ecard2); +static void business_populate (EContact *contact, char **values); +struct berval** business_ber (EContact *contact); +static gboolean business_compare (EContact *contact1, EContact *contact2); -static void business_populate (ECardSimple *card, char **values); -struct berval** business_ber (ECardSimple *card); -static gboolean business_compare (ECardSimple *ecard1, ECardSimple *ecard2); +static void anniversary_populate (EContact *contact, char **values); +struct berval** anniversary_ber (EContact *contact); +static gboolean anniversary_compare (EContact *contact1, EContact *contact2); -static void anniversary_populate (ECardSimple *card, char **values); -struct berval** anniversary_ber (ECardSimple *card); -static gboolean anniversary_compare (ECardSimple *ecard1, ECardSimple *ecard2); +static void birthday_populate (EContact *contact, char **values); +struct berval** birthday_ber (EContact *contact); +static gboolean birthday_compare (EContact *contact1, EContact *contact2); -static void birthday_populate (ECardSimple *card, char **values); -struct berval** birthday_ber (ECardSimple *card); -static gboolean birthday_compare (ECardSimple *ecard1, ECardSimple *ecard2); +static void category_populate (EContact *contact, char **values); +struct berval** category_ber (EContact *contact); +static gboolean category_compare (EContact *contact1, EContact *contact2); -static void category_populate (ECardSimple *card, char **values); -struct berval** category_ber (ECardSimple *card); -static gboolean category_compare (ECardSimple *ecard1, ECardSimple *ecard2); +static void photo_populate (EContact *contact, struct berval **ber_values); struct prop_info { - ECardSimpleField field_id; - char *query_prop; + EContactField field_id; char *ldap_attr; #define PROP_TYPE_STRING 0x01 -#define PROP_TYPE_COMPLEX 0x02 -#define PROP_DN 0x04 -#define PROP_EVOLVE 0x08 +#define PROP_TYPE_COMPLEX 0x02 +#define PROP_TYPE_BINARY 0x04 +#define PROP_DN 0x08 +#define PROP_EVOLVE 0x10 +#define PROP_WRITE_ONLY 0x20 int prop_type; /* the remaining items are only used for the TYPE_COMPLEX props */ - /* used when reading from the ldap server populates ECard with the values in **values. */ - void (*populate_ecard_func)(ECardSimple *card, char **values); + /* used when reading from the ldap server populates EContact with the values in **values. */ + void (*populate_contact_func)(EContact *contact, char **values); /* used when writing to an ldap server. returns a NULL terminated array of berval*'s */ - struct berval** (*ber_func)(ECardSimple *card); + struct berval** (*ber_func)(EContact *contact); /* used to compare list attributes */ - gboolean (*compare_func)(ECardSimple *card1, ECardSimple *card2); + gboolean (*compare_func)(EContact *contact1, EContact *contact2); + + void (*binary_populate_contact_func)(EContact *contact, struct berval **ber_values); } prop_info[] = { -#define COMPLEX_PROP(fid,q,a,ctor,ber,cmp) {fid, q, a, PROP_TYPE_COMPLEX, ctor, ber, cmp} -#define E_COMPLEX_PROP(fid,q,a,ctor,ber,cmp) {fid, q, a, PROP_TYPE_COMPLEX | PROP_EVOLVE, ctor, ber, cmp} -#define STRING_PROP(fid,q,a) {fid, q, a, PROP_TYPE_STRING} -#define E_STRING_PROP(fid,q,a) {fid, q, a, PROP_TYPE_STRING | PROP_EVOLVE} +#define BINARY_PROP(fid,a,ctor,ber,cmp) {fid, a, PROP_TYPE_BINARY, NULL, ber, cmp, ctor} +#define COMPLEX_PROP(fid,a,ctor,ber,cmp) {fid, a, PROP_TYPE_COMPLEX, ctor, ber, cmp} +#define E_COMPLEX_PROP(fid,a,ctor,ber,cmp) {fid, a, PROP_TYPE_COMPLEX | PROP_EVOLVE, ctor, ber, cmp} +#define STRING_PROP(fid,a) {fid, a, PROP_TYPE_STRING} +#define WRITE_ONLY_STRING_PROP(fid,a) {fid, a, PROP_TYPE_STRING | PROP_WRITE_ONLY} +#define E_STRING_PROP(fid,a) {fid, a, PROP_TYPE_STRING | PROP_EVOLVE} /* name fields */ - STRING_PROP (E_CARD_SIMPLE_FIELD_FULL_NAME, "full_name", "cn" ), - STRING_PROP (E_CARD_SIMPLE_FIELD_FAMILY_NAME, "family_name", "sn" ), + STRING_PROP (E_CONTACT_FULL_NAME, "cn" ), + WRITE_ONLY_STRING_PROP (E_CONTACT_FAMILY_NAME, "sn" ), /* email addresses */ - COMPLEX_PROP (E_CARD_SIMPLE_FIELD_EMAIL, "email", "mail", email_populate, email_ber, email_compare), + COMPLEX_PROP (E_CONTACT_EMAIL, "mail", email_populate, email_ber, email_compare), /* phone numbers */ - E_STRING_PROP (E_CARD_SIMPLE_FIELD_PHONE_PRIMARY, "primary_phone", "primaryPhone"), - COMPLEX_PROP (E_CARD_SIMPLE_FIELD_PHONE_BUSINESS, "business_phone", "telephoneNumber", business_populate, business_ber, business_compare), - COMPLEX_PROP (E_CARD_SIMPLE_FIELD_PHONE_HOME, "home_phone", "homePhone", homephone_populate, homephone_ber, homephone_compare), - STRING_PROP (E_CARD_SIMPLE_FIELD_PHONE_MOBILE, "mobile_phone", "mobile"), - E_STRING_PROP (E_CARD_SIMPLE_FIELD_PHONE_CAR, "car_phone", "carPhone"), - STRING_PROP (E_CARD_SIMPLE_FIELD_PHONE_BUSINESS_FAX, "business_fax", "facsimileTelephoneNumber"), - E_STRING_PROP (E_CARD_SIMPLE_FIELD_PHONE_HOME_FAX, "home_fax", "homeFacsimileTelephoneNumber"), - E_STRING_PROP (E_CARD_SIMPLE_FIELD_PHONE_OTHER, "other_phone", "otherPhone"), - E_STRING_PROP (E_CARD_SIMPLE_FIELD_PHONE_OTHER_FAX, "other_fax", "otherFacsimileTelephoneNumber"), - STRING_PROP (E_CARD_SIMPLE_FIELD_PHONE_ISDN, "isdn", "internationaliSDNNumber"), - STRING_PROP (E_CARD_SIMPLE_FIELD_PHONE_PAGER, "pager", "pager"), - E_STRING_PROP (E_CARD_SIMPLE_FIELD_PHONE_RADIO, "radio", "radio"), - E_STRING_PROP (E_CARD_SIMPLE_FIELD_PHONE_TELEX, "telex", "telex"), - E_STRING_PROP (E_CARD_SIMPLE_FIELD_PHONE_ASSISTANT, "assistant_phone", "assistantPhone"), - E_STRING_PROP (E_CARD_SIMPLE_FIELD_PHONE_COMPANY, "company_phone", "companyPhone"), - E_STRING_PROP (E_CARD_SIMPLE_FIELD_PHONE_CALLBACK, "callback_phone", "callbackPhone"), - E_STRING_PROP (E_CARD_SIMPLE_FIELD_PHONE_TTYTDD, "tty", "tty"), + E_STRING_PROP (E_CONTACT_PHONE_PRIMARY, "primaryPhone"), + COMPLEX_PROP (E_CONTACT_PHONE_BUSINESS, "telephoneNumber", business_populate, business_ber, business_compare), + COMPLEX_PROP (E_CONTACT_PHONE_HOME, "homePhone", homephone_populate, homephone_ber, homephone_compare), + STRING_PROP (E_CONTACT_PHONE_MOBILE, "mobile"), + E_STRING_PROP (E_CONTACT_PHONE_CAR, "carPhone"), + STRING_PROP (E_CONTACT_PHONE_BUSINESS_FAX, "facsimileTelephoneNumber"), + E_STRING_PROP (E_CONTACT_PHONE_HOME_FAX, "homeFacsimileTelephoneNumber"), + E_STRING_PROP (E_CONTACT_PHONE_OTHER, "otherPhone"), + E_STRING_PROP (E_CONTACT_PHONE_OTHER_FAX, "otherFacsimileTelephoneNumber"), + STRING_PROP (E_CONTACT_PHONE_ISDN, "internationaliSDNNumber"), + STRING_PROP (E_CONTACT_PHONE_PAGER, "pager"), + E_STRING_PROP (E_CONTACT_PHONE_RADIO, "radio"), + E_STRING_PROP (E_CONTACT_PHONE_TELEX, "telex"), + E_STRING_PROP (E_CONTACT_PHONE_ASSISTANT, "assistantPhone"), + E_STRING_PROP (E_CONTACT_PHONE_COMPANY, "companyPhone"), + E_STRING_PROP (E_CONTACT_PHONE_CALLBACK, "callbackPhone"), + E_STRING_PROP (E_CONTACT_PHONE_TTYTDD, "tty"), /* org information */ - STRING_PROP (E_CARD_SIMPLE_FIELD_ORG, "org", "o"), - STRING_PROP (E_CARD_SIMPLE_FIELD_ORG_UNIT, "org_unit", "ou"), - STRING_PROP (E_CARD_SIMPLE_FIELD_OFFICE, "office", "roomNumber"), - STRING_PROP (E_CARD_SIMPLE_FIELD_TITLE, "title", "title"), - E_STRING_PROP (E_CARD_SIMPLE_FIELD_ROLE, "role", "businessRole"), - E_STRING_PROP (E_CARD_SIMPLE_FIELD_MANAGER, "manager", "managerName"), - E_STRING_PROP (E_CARD_SIMPLE_FIELD_ASSISTANT, "assistant", "assistantName"), + STRING_PROP (E_CONTACT_ORG, "o"), + STRING_PROP (E_CONTACT_ORG_UNIT, "ou"), + STRING_PROP (E_CONTACT_OFFICE, "roomNumber"), + STRING_PROP (E_CONTACT_TITLE, "title"), + E_STRING_PROP (E_CONTACT_ROLE, "businessRole"), + E_STRING_PROP (E_CONTACT_MANAGER, "managerName"), + E_STRING_PROP (E_CONTACT_ASSISTANT, "assistantName"), /* addresses */ - STRING_PROP (E_CARD_SIMPLE_FIELD_ADDRESS_BUSINESS, "business_address", "postalAddress"), - STRING_PROP (E_CARD_SIMPLE_FIELD_ADDRESS_HOME, "home_address", "homePostalAddress"), - E_STRING_PROP (E_CARD_SIMPLE_FIELD_ADDRESS_OTHER, "other_address", "otherPostalAddress"), + STRING_PROP (E_CONTACT_ADDRESS_LABEL_WORK, "postalAddress"), + STRING_PROP (E_CONTACT_ADDRESS_LABEL_HOME, "homePostalAddress"), + E_STRING_PROP (E_CONTACT_ADDRESS_LABEL_OTHER, "otherPostalAddress"), + + /* photos */ + BINARY_PROP (E_CONTACT_PHOTO, "jpegPhoto", photo_populate, NULL/*XXX*/, NULL/*XXX*/), /* misc fields */ - STRING_PROP (E_CARD_SIMPLE_FIELD_URL, "url", "labeledURI"), + STRING_PROP (E_CONTACT_HOMEPAGE_URL, "labeledURI"), /* map nickname to displayName */ - STRING_PROP (E_CARD_SIMPLE_FIELD_NICKNAME, "nickname", "displayName"), - E_STRING_PROP (E_CARD_SIMPLE_FIELD_SPOUSE, "spouse", "spouseName"), - E_STRING_PROP (E_CARD_SIMPLE_FIELD_NOTE, "note", "note"), - E_COMPLEX_PROP (E_CARD_SIMPLE_FIELD_ANNIVERSARY, "anniversary", "anniversary", anniversary_populate, anniversary_ber, anniversary_compare), - E_COMPLEX_PROP (E_CARD_SIMPLE_FIELD_BIRTH_DATE, "birth_date", "birthDate", birthday_populate, birthday_ber, birthday_compare), - E_STRING_PROP (E_CARD_SIMPLE_FIELD_MAILER, "mailer", "mailer"), - - E_STRING_PROP (E_CARD_SIMPLE_FIELD_FILE_AS, "file_as", "fileAs"), - E_COMPLEX_PROP (E_CARD_SIMPLE_FIELD_CATEGORIES, "categories", "category", category_populate, category_ber, category_compare), - - STRING_PROP (E_CARD_SIMPLE_FIELD_CALURI, "caluri", "calCalURI"), - STRING_PROP (E_CARD_SIMPLE_FIELD_FBURL, "fburl", "calFBURL"), - STRING_PROP (E_CARD_SIMPLE_FIELD_ICSCALENDAR, "icscalendar", "icsCalendar"), - -/* E_CARD_SIMPLE_FIELD_NAME_OR_ORG, */ - + STRING_PROP (E_CONTACT_NICKNAME, "displayName"), + E_STRING_PROP (E_CONTACT_SPOUSE, "spouseName"), + E_STRING_PROP (E_CONTACT_NOTE, "note"), + E_COMPLEX_PROP (E_CONTACT_ANNIVERSARY, "anniversary", anniversary_populate, anniversary_ber, anniversary_compare), + E_COMPLEX_PROP (E_CONTACT_BIRTH_DATE, "birthDate", birthday_populate, birthday_ber, birthday_compare), + E_STRING_PROP (E_CONTACT_MAILER, "mailer"), + + E_STRING_PROP (E_CONTACT_FILE_AS, "fileAs"), +#if notyet + E_COMPLEX_PROP (E_CONTACT_CATEGORIES, "category", category_populate, category_ber, category_compare), + + STRING_PROP (E_CONTACT_CALURI, "calCalURI"), + STRING_PROP (E_CONTACT_FBURL, "calFBURL"), + STRING_PROP (E_CONTACT_ICSCALENDAR, "icsCalendar"), +#endif #undef E_STRING_PROP #undef STRING_PROP @@ -285,6 +281,7 @@ struct prop_info { static int num_prop_infos = sizeof(prop_info) / sizeof(prop_info[0]); +#if 0 static void remove_view (int msgid, LDAPOp *op, PASBookView *view) { @@ -321,7 +318,6 @@ view_destroy(gpointer data, GObject *where_object_was) /* free up the view structure */ g_free (view->search); - g_object_unref (view->card_sexp); g_free (view); /* and remove it from our list */ @@ -349,6 +345,7 @@ view_destroy(gpointer data, GObject *where_object_was) g_object_unref (iter); } +#endif static void book_view_notify_status (PASBookView *view, const char *status) @@ -361,6 +358,7 @@ book_view_notify_status (PASBookView *view, const char *status) static PASBookView* find_book_view (PASBackendLDAP *bl) { +#if 0 EIterator *iter = e_list_get_iterator (bl->priv->book_views); PASBookView *rv = NULL; @@ -374,6 +372,7 @@ find_book_view (PASBackendLDAP *bl) g_object_unref (iter); return rv; +#endif } static void @@ -381,21 +380,21 @@ add_to_supported_fields (PASBackendLDAP *bl, char **attrs, GHashTable *attr_hash { int i; for (i = 0; attrs[i]; i ++) { - char *query_prop = g_hash_table_lookup (attr_hash, attrs[i]); + char *query_prop = g_hash_table_lookup (attr_hash, g_strdup (attrs[i])); if (query_prop) { - e_list_append (bl->priv->supported_fields, query_prop); + bl->priv->supported_fields = g_list_append (bl->priv->supported_fields, g_strdup (query_prop)); /* handle the list attributes here */ if (!strcmp (query_prop, "email")) { - e_list_append (bl->priv->supported_fields, "email_2"); - e_list_append (bl->priv->supported_fields, "email_3"); + bl->priv->supported_fields = g_list_append (bl->priv->supported_fields, g_strdup ("email_2")); + bl->priv->supported_fields = g_list_append (bl->priv->supported_fields, g_strdup ("email_3")); } else if (!strcmp (query_prop, "business_phone")) { - e_list_append (bl->priv->supported_fields, "business_phone_2"); + bl->priv->supported_fields = g_list_append (bl->priv->supported_fields, g_strdup ("business_phone_2")); } else if (!strcmp (query_prop, "home_phone")) { - e_list_append (bl->priv->supported_fields, "home_phone_2"); + bl->priv->supported_fields = g_list_append (bl->priv->supported_fields, g_strdup ("home_phone_2")); } } } @@ -408,7 +407,7 @@ add_oc_attributes_to_supported_fields (PASBackendLDAP *bl, LDAPObjectClass *oc) GHashTable *attr_hash = g_hash_table_new (g_str_hash, g_str_equal); for (i = 0; i < num_prop_infos; i ++) - g_hash_table_insert (attr_hash, prop_info[i].ldap_attr, prop_info[i].query_prop); + g_hash_table_insert (attr_hash, prop_info[i].ldap_attr, (char*)e_contact_field_name (prop_info[i].field_id)); if (oc->oc_at_oids_must) add_to_supported_fields (bl, oc->oc_at_oids_must, attr_hash); @@ -591,22 +590,21 @@ query_ldap_root_dse (PASBackendLDAP *bl) values = ldap_get_values (ldap, resp, "supportedSASLMechanisms"); if (values) { char *auth_method; - if (bl->priv->supported_auth_methods) - g_object_unref (bl->priv->supported_auth_methods); - bl->priv->supported_auth_methods = e_list_new ((EListCopyFunc)g_strdup, (EListFreeFunc)g_free, NULL); + if (bl->priv->supported_auth_methods) { + g_list_foreach (bl->priv->supported_auth_methods, (GFunc)g_free, NULL); + g_list_free (bl->priv->supported_auth_methods); + } + bl->priv->supported_auth_methods = NULL; auth_method = g_strdup_printf ("ldap/simple-binddn|%s", _("Using Distinguished Name (DN)")); - e_list_append (bl->priv->supported_auth_methods, auth_method); - g_free (auth_method); + bl->priv->supported_auth_methods = g_list_append (bl->priv->supported_auth_methods, auth_method); auth_method = g_strdup_printf ("ldap/simple-email|%s", _("Using Email Address")); - e_list_append (bl->priv->supported_auth_methods, auth_method); - g_free (auth_method); + bl->priv->supported_fields = g_list_append (bl->priv->supported_auth_methods, auth_method); for (i = 0; values[i]; i++) { auth_method = g_strdup_printf ("sasl/%s|%s", values[i], values[i]); - e_list_append (bl->priv->supported_auth_methods, auth_method); - g_free (auth_method); + bl->priv->supported_fields = g_list_append (bl->priv->supported_auth_methods, auth_method); g_message ("supported SASL mechanism: %s", values[i]); } ldap_value_free (values); @@ -633,7 +631,7 @@ query_ldap_root_dse (PASBackendLDAP *bl) return LDAP_SUCCESS; } -static GNOME_Evolution_Addressbook_BookListener_CallStatus +static GNOME_Evolution_Addressbook_CallStatus pas_backend_ldap_connect (PASBackendLDAP *bl) { PASBackendLDAPPrivate *blpriv = bl->priv; @@ -667,7 +665,7 @@ pas_backend_ldap_connect (PASBackendLDAP *bl) g_message ("TLS not available (fatal version), v3 protocol could not be established (ldap_error 0x%02x)", ldap_error); ldap_unbind (blpriv->ldap); blpriv->ldap = NULL; - return GNOME_Evolution_Addressbook_BookListener_TLSNotAvailable; + return GNOME_Evolution_Addressbook_TLSNotAvailable; } if (bl->priv->ldap_port == LDAPS_PORT && bl->priv->use_tls == PAS_BACKEND_LDAP_TLS_ALWAYS) { @@ -681,7 +679,7 @@ pas_backend_ldap_connect (PASBackendLDAP *bl) g_message ("TLS not available (fatal version), (ldap_error 0x%02x)", ldap_error); ldap_unbind (blpriv->ldap); blpriv->ldap = NULL; - return GNOME_Evolution_Addressbook_BookListener_TLSNotAvailable; + return GNOME_Evolution_Addressbook_TLSNotAvailable; } else { g_message ("TLS not available (ldap_error 0x%02x)", ldap_error); @@ -700,7 +698,7 @@ pas_backend_ldap_connect (PASBackendLDAP *bl) if (ldap_error == LDAP_SERVER_DOWN) { /* we only want this to be fatal if the server is down. */ g_warning ("failed to bind anonymously while connecting (ldap_error 0x%02x)", ldap_error); - return GNOME_Evolution_Addressbook_BookListener_RepositoryOffline; + return GNOME_Evolution_Addressbook_RepositoryOffline; } ldap_error = query_ldap_root_dse (bl); @@ -722,7 +720,7 @@ pas_backend_ldap_connect (PASBackendLDAP *bl) check_schema_support (bl); pas_backend_set_is_loaded (PAS_BACKEND (bl), TRUE); - return GNOME_Evolution_Addressbook_BookListener_Success; + return GNOME_Evolution_Addressbook_Success; } else g_warning ("Failed to perform root dse query anonymously, (ldap_error 0x%02x)", ldap_error); @@ -734,7 +732,7 @@ pas_backend_ldap_connect (PASBackendLDAP *bl) blpriv->ldap_port, blpriv->ldap_rootdn ? blpriv->ldap_rootdn : ""); blpriv->connected = FALSE; - return GNOME_Evolution_Addressbook_BookListener_RepositoryOffline; + return GNOME_Evolution_Addressbook_RepositoryOffline; } static gboolean @@ -742,14 +740,14 @@ pas_backend_ldap_reconnect (PASBackendLDAP *bl, PASBookView *book_view, int ldap { /* we need to reconnect if we were previously connected */ if (bl->priv->connected && ldap_status == LDAP_SERVER_DOWN) { - GNOME_Evolution_Addressbook_BookListener_CallStatus status; + GNOME_Evolution_Addressbook_CallStatus status; int ldap_error = LDAP_SUCCESS; book_view_notify_status (book_view, _("Reconnecting to LDAP server...")); status = pas_backend_ldap_connect (bl); - if (status != GNOME_Evolution_Addressbook_BookListener_Success) { + if (status != GNOME_Evolution_Addressbook_Success) { book_view_notify_status (book_view, ""); return FALSE; } @@ -836,27 +834,27 @@ static int ldap_error_to_response (int ldap_error) { if (ldap_error == LDAP_SUCCESS) - return GNOME_Evolution_Addressbook_BookListener_Success; + return GNOME_Evolution_Addressbook_Success; else if (LDAP_NAME_ERROR (ldap_error)) - return GNOME_Evolution_Addressbook_BookListener_CardNotFound; + return GNOME_Evolution_Addressbook_ContactNotFound; else if (ldap_error == LDAP_INSUFFICIENT_ACCESS) - return GNOME_Evolution_Addressbook_BookListener_PermissionDenied; + return GNOME_Evolution_Addressbook_PermissionDenied; else if (ldap_error == LDAP_SERVER_DOWN) - return GNOME_Evolution_Addressbook_BookListener_RepositoryOffline; + return GNOME_Evolution_Addressbook_RepositoryOffline; else if (ldap_error == LDAP_ALREADY_EXISTS) - return GNOME_Evolution_Addressbook_BookListener_CardIdAlreadyExists; + return GNOME_Evolution_Addressbook_ContactIdAlreadyExists; else - return GNOME_Evolution_Addressbook_BookListener_OtherError; + return GNOME_Evolution_Addressbook_OtherError; } static char * -create_dn_from_ecard (ECardSimple *card, const char *root_dn) +create_dn_from_contact (EContact *contact, const char *root_dn) { char *cn, *cn_part = NULL; char *dn; - cn = e_card_simple_get (card, E_CARD_SIMPLE_FIELD_FULL_NAME); + cn = e_contact_get (contact, E_CONTACT_FULL_NAME); if (cn) { if (strchr (cn, ',')) { /* need to escape commas */ @@ -921,7 +919,7 @@ free_mods (GPtrArray *mods) } static GPtrArray* -build_mods_from_ecards (PASBackendLDAP *bl, ECardSimple *current, ECardSimple *new, gboolean *new_dn_needed) +build_mods_from_contacts (PASBackendLDAP *bl, EContact *current, EContact *new, gboolean *new_dn_needed) { gboolean adding = (current == NULL); GPtrArray *result = g_ptr_array_new(); @@ -946,12 +944,12 @@ build_mods_from_ecards (PASBackendLDAP *bl, ECardSimple *current, ECardSimple *n if (prop_info[i].prop_type & PROP_EVOLVE && !bl->priv->evolutionPersonSupported) continue; - /* get the value for the new card, and compare it to - the value in the current card to see if we should + /* get the value for the new contact, and compare it to + the value in the current contact to see if we should update it -- if adding is TRUE, short circuit the check. */ if (prop_info[i].prop_type & PROP_TYPE_STRING) { - new_prop = e_card_simple_get (new, prop_info[i].field_id); + new_prop = e_contact_get (new, prop_info[i].field_id); new_prop_present = (new_prop != NULL); } else { @@ -962,7 +960,7 @@ build_mods_from_ecards (PASBackendLDAP *bl, ECardSimple *current, ECardSimple *n /* need to set INCLUDE to true if the field needs to show up in the ldap modify request */ if (adding) { - /* if we're creating a new card, include it if the + /* if we're creating a new contact, include it if the field is there at all */ if (prop_info[i].prop_type & PROP_TYPE_STRING) include = (new_prop_present && *new_prop); /* empty strings cause problems */ @@ -970,13 +968,13 @@ build_mods_from_ecards (PASBackendLDAP *bl, ECardSimple *current, ECardSimple *n include = new_prop_present; } else { - /* if we're modifying an existing card, + /* if we're modifying an existing contact, include it if the current field value is different than the new one, if it didn't exist previously, or if it's been removed. */ if (prop_info[i].prop_type & PROP_TYPE_STRING) { - current_prop = e_card_simple_get (current, prop_info[i].field_id); + current_prop = e_contact_get (current, prop_info[i].field_id); current_prop_present = (current_prop != NULL); if (new_prop && current_prop) @@ -1112,23 +1110,24 @@ add_objectclass_mod (PASBackendLDAP *bl, GPtrArray *mod_array, GList *existing_o typedef struct { LDAPOp op; char *dn; - ECardSimple *new_card; + EContact *new_contact; } LDAPCreateOp; static void -create_card_handler (LDAPOp *op, LDAPMessage *res) +create_contact_handler (LDAPOp *op, LDAPMessage *res) { LDAPCreateOp *create_op = (LDAPCreateOp*)op; PASBackendLDAP *bl = PAS_BACKEND_LDAP (op->backend); LDAP *ldap = bl->priv->ldap; + EContact *contact; int ldap_error; int response; if (LDAP_RES_ADD != ldap_msgtype (res)) { - g_warning ("incorrect msg type %d passed to create_card_handler", ldap_msgtype (res)); + g_warning ("incorrect msg type %d passed to create_contact_handler", ldap_msgtype (res)); pas_book_respond_create (op->book, - GNOME_Evolution_Addressbook_BookListener_OtherError, - create_op->dn); + GNOME_Evolution_Addressbook_OtherError, + NULL); ldap_op_finished (op); return; } @@ -1136,75 +1135,34 @@ create_card_handler (LDAPOp *op, LDAPMessage *res) ldap_parse_result (ldap, res, &ldap_error, NULL, NULL, NULL, NULL, 0); - if (ldap_error == LDAP_SUCCESS) { - /* the card was created, let's let the views know about it */ - EIterator *iter; - - iter = e_list_get_iterator (bl->priv->book_views); - while (e_iterator_is_valid (iter)) { - CORBA_Environment ev; - gboolean match; - PASBackendLDAPBookView *view = (PASBackendLDAPBookView*)e_iterator_get (iter); - char *new_vcard; - - CORBA_exception_init(&ev); - - bonobo_object_dup_ref(bonobo_object_corba_objref(BONOBO_OBJECT(view->book_view)), &ev); - - new_vcard = e_card_simple_get_vcard_assume_utf8 (create_op->new_card); - - match = pas_backend_card_sexp_match_vcard (view->card_sexp, - new_vcard); - if (match) { - pas_book_view_notify_add_1 (view->book_view, - new_vcard); - } - pas_book_view_notify_complete (view->book_view, GNOME_Evolution_Addressbook_BookViewListener_Success); - - g_free (new_vcard); - - bonobo_object_release_unref(bonobo_object_corba_objref(BONOBO_OBJECT(view->book_view)), &ev); - - e_iterator_next (iter); - } - g_object_unref (iter); - } - else { - ldap_perror (ldap, "create_card"); - } - - if (op->view) - pas_book_view_notify_complete (op->view, GNOME_Evolution_Addressbook_BookViewListener_Success); - /* and lastly respond */ response = ldap_error_to_response (ldap_error); pas_book_respond_create (op->book, response, - create_op->dn); + create_op->new_contact); ldap_op_finished (op); } static void -create_card_dtor (LDAPOp *op) +create_contact_dtor (LDAPOp *op) { LDAPCreateOp *create_op = (LDAPCreateOp*)op; g_free (create_op->dn); - g_object_unref (create_op->new_card); + g_object_unref (create_op->new_contact); g_free (create_op); } static void -pas_backend_ldap_process_create_card (PASBackend *backend, - PASBook *book, - PASCreateCardRequest *req) +pas_backend_ldap_process_create_contact (PASBackend *backend, + PASBook *book, + const char *vcard) { LDAPCreateOp *create_op = g_new (LDAPCreateOp, 1); PASBackendLDAP *bl = PAS_BACKEND_LDAP (backend); PASBookView *book_view; - int create_card_msgid; - ECard *new_ecard; + int create_contact_msgid; int response; int err; GPtrArray *mod_array; @@ -1213,18 +1171,17 @@ pas_backend_ldap_process_create_card (PASBackend *backend, book_view = find_book_view (bl); - printf ("vcard = %s\n", req->vcard); + printf ("vcard = %s\n", vcard); - new_ecard = e_card_new (req->vcard); - create_op->new_card = e_card_simple_new (new_ecard); + create_op->new_contact = e_contact_new_from_vcard (vcard); - create_op->dn = create_dn_from_ecard (create_op->new_card, bl->priv->ldap_rootdn); - e_card_simple_set_id (create_op->new_card, create_op->dn); /* for the notification code below */ + create_op->dn = create_dn_from_contact (create_op->new_contact, bl->priv->ldap_rootdn); + e_contact_set (create_op->new_contact, E_CONTACT_UID, create_op->dn); ldap = bl->priv->ldap; /* build our mods */ - mod_array = build_mods_from_ecards (bl, NULL, create_op->new_card, NULL); + mod_array = build_mods_from_contacts (bl, NULL, create_op->new_contact, NULL); #if 0 if (!mod_array) { @@ -1232,10 +1189,10 @@ pas_backend_ldap_process_create_card (PASBackend *backend, UnsupportedAttribute back */ pas_book_respond_create (book, GNOME_Evolution_Addressbook_BookListener_UnsupportedField, - create_op->dn); + NULL); g_free (create_op->dn); - g_object_unref (create_op->new_card); + g_object_unref (create_op->new_contact); g_free (create_op); return; } @@ -1288,10 +1245,10 @@ pas_backend_ldap_process_create_card (PASBackend *backend, ldap_mods = (LDAPMod**)mod_array->pdata; do { - book_view_notify_status (book_view, _("Adding card to LDAP server...")); + book_view_notify_status (book_view, _("Adding contact to LDAP server...")); err = ldap_add_ext (ldap, create_op->dn, ldap_mods, - NULL, NULL, &create_card_msgid); + NULL, NULL, &create_contact_msgid); } while (pas_backend_ldap_reconnect (bl, book_view, err)); @@ -1302,15 +1259,15 @@ pas_backend_ldap_process_create_card (PASBackend *backend, response = ldap_error_to_response (err); pas_book_respond_create (create_op->op.book, response, - create_op->dn); - create_card_dtor ((LDAPOp*)create_op); + NULL); + create_contact_dtor ((LDAPOp*)create_op); return; } else { g_print ("ldap_add_ext returned %d\n", err); ldap_op_add ((LDAPOp*)create_op, backend, book, - book_view, create_card_msgid, - create_card_handler, create_card_dtor); + book_view, create_contact_msgid, + create_contact_handler, create_contact_dtor); } } @@ -1321,16 +1278,18 @@ typedef struct { } LDAPRemoveOp; static void -remove_card_handler (LDAPOp *op, LDAPMessage *res) +remove_contact_handler (LDAPOp *op, LDAPMessage *res) { LDAPRemoveOp *remove_op = (LDAPRemoveOp*)op; PASBackendLDAP *bl = PAS_BACKEND_LDAP (op->backend); int ldap_error; + GList *ids = NULL; if (LDAP_RES_DELETE != ldap_msgtype (res)) { - g_warning ("incorrect msg type %d passed to remove_card_handler", ldap_msgtype (res)); - pas_book_respond_remove (op->book, - GNOME_Evolution_Addressbook_BookListener_OtherError); + g_warning ("incorrect msg type %d passed to remove_contact_handler", ldap_msgtype (res)); + pas_book_respond_remove_contacts (op->book, + GNOME_Evolution_Addressbook_OtherError, + NULL); ldap_op_finished (op); return; } @@ -1338,39 +1297,15 @@ remove_card_handler (LDAPOp *op, LDAPMessage *res) ldap_parse_result (bl->priv->ldap, res, &ldap_error, NULL, NULL, NULL, NULL, 0); - if (ldap_error == LDAP_SUCCESS) { - /* the card was removed, let's let the views know about it */ - EIterator *iter = e_list_get_iterator (bl->priv->book_views); - - while (e_iterator_is_valid (iter)) { - CORBA_Environment ev; - PASBackendLDAPBookView *view = (PASBackendLDAPBookView*)e_iterator_get (iter); - - CORBA_exception_init(&ev); - - bonobo_object_dup_ref(bonobo_object_corba_objref(BONOBO_OBJECT(view->book_view)), &ev); - - pas_book_view_notify_remove_1 (view->book_view, remove_op->id); - - bonobo_object_release_unref(bonobo_object_corba_objref(BONOBO_OBJECT(view->book_view)), &ev); - - e_iterator_next (iter); - } - g_object_unref (iter); - } - else { - ldap_perror (bl->priv->ldap, "remove_card"); - } - - pas_book_respond_remove (remove_op->op.book, - ldap_error_to_response (ldap_error)); - - if (op->view) - pas_book_view_notify_complete (op->view, GNOME_Evolution_Addressbook_BookViewListener_Success); + ids = g_list_append (ids, remove_op->id); + pas_book_respond_remove_contacts (remove_op->op.book, + ldap_error_to_response (ldap_error), + ids); + g_list_free (ids); } static void -remove_card_dtor (LDAPOp *op) +remove_contact_dtor (LDAPOp *op) { LDAPRemoveOp *remove_op = (LDAPRemoveOp*)op; @@ -1379,9 +1314,9 @@ remove_card_dtor (LDAPOp *op) } static void -pas_backend_ldap_process_remove_cards (PASBackend *backend, - PASBook *book, - PASRemoveCardsRequest *req) +pas_backend_ldap_process_remove_contacts (PASBackend *backend, + PASBook *book, + GList *ids) { LDAPRemoveOp *remove_op = g_new (LDAPRemoveOp, 1); PASBackendLDAP *bl = PAS_BACKEND_LDAP (backend); @@ -1396,10 +1331,10 @@ pas_backend_ldap_process_remove_cards (PASBackend *backend, ** capabilities, we should only get 1 length lists here, so ** the id we're deleting is the first and only id in the list. */ - remove_op->id = g_strdup (req->ids->data); + remove_op->id = g_strdup (ids->data); do { - book_view_notify_status (book_view, _("Removing card from LDAP server...")); + book_view_notify_status (book_view, _("Removing contact from LDAP server...")); ldap_error = ldap_delete_ext (bl->priv->ldap, remove_op->id, @@ -1407,16 +1342,17 @@ pas_backend_ldap_process_remove_cards (PASBackend *backend, } while (pas_backend_ldap_reconnect (bl, book_view, ldap_error)); if (ldap_error != LDAP_SUCCESS) { - pas_book_respond_remove (remove_op->op.book, - ldap_error_to_response (ldap_error)); - remove_card_dtor ((LDAPOp*)remove_op); + pas_book_respond_remove_contacts (remove_op->op.book, + ldap_error_to_response (ldap_error), + NULL); + remove_contact_dtor ((LDAPOp*)remove_op); return; } else { g_print ("ldap_delete_ext returned %d\n", ldap_error); ldap_op_add ((LDAPOp*)remove_op, backend, book, book_view, remove_msgid, - remove_card_handler, remove_card_dtor); + remove_contact_handler, remove_contact_dtor); } } @@ -1427,23 +1363,21 @@ pas_backend_ldap_process_remove_cards (PASBackend *backend, ** The modification request is actually composed of 2 separate ** requests. Since we need to get a list of theexisting objectclasses ** used by the ldap server for the entry, and since the UI only sends -** us the current card, we need to query the ldap server for the -** existing card. +** us the current contact, we need to query the ldap server for the +** existing contact. ** */ typedef struct { LDAPOp op; - const char *id; /* the id of the card we're modifying */ - char *current_vcard; /* current in the LDAP db */ - ECardSimple *current_card; - char *vcard; /* the VCard we want to store */ - ECardSimple *card; + const char *id; /* the id of the contact we're modifying */ + EContact *current_contact; + EContact *contact; GList *existing_objectclasses; } LDAPModifyOp; static void -modify_card_modify_handler (LDAPOp *op, LDAPMessage *res) +modify_contact_modify_handler (LDAPOp *op, LDAPMessage *res) { LDAPModifyOp *modify_op = (LDAPModifyOp*)op; PASBackendLDAP *bl = PAS_BACKEND_LDAP (op->backend); @@ -1451,9 +1385,10 @@ modify_card_modify_handler (LDAPOp *op, LDAPMessage *res) int ldap_error; if (LDAP_RES_MODIFY != ldap_msgtype (res)) { - g_warning ("incorrect msg type %d passed to modify_card_handler", ldap_msgtype (res)); + g_warning ("incorrect msg type %d passed to modify_contact_handler", ldap_msgtype (res)); pas_book_respond_modify (op->book, - GNOME_Evolution_Addressbook_BookListener_OtherError); + GNOME_Evolution_Addressbook_OtherError, + NULL); ldap_op_finished (op); return; } @@ -1461,48 +1396,15 @@ modify_card_modify_handler (LDAPOp *op, LDAPMessage *res) ldap_parse_result (ldap, res, &ldap_error, NULL, NULL, NULL, NULL, 0); - if (ldap_error == LDAP_SUCCESS) { - /* the card was modified, let's let the views know about it */ - EIterator *iter = e_list_get_iterator (bl->priv->book_views); - while (e_iterator_is_valid (iter)) { - CORBA_Environment ev; - gboolean old_match, new_match; - PASBackendLDAPBookView *view = (PASBackendLDAPBookView*)e_iterator_get (iter); - - CORBA_exception_init(&ev); - - bonobo_object_dup_ref(bonobo_object_corba_objref(BONOBO_OBJECT(view->book_view)), &ev); - - old_match = pas_backend_card_sexp_match_vcard (view->card_sexp, - modify_op->current_vcard); - new_match = pas_backend_card_sexp_match_vcard (view->card_sexp, - modify_op->vcard); - if (old_match && new_match) - pas_book_view_notify_change_1 (view->book_view, modify_op->vcard); - else if (new_match) - pas_book_view_notify_add_1 (view->book_view, modify_op->vcard); - else /* if (old_match) */ - pas_book_view_notify_remove_1 (view->book_view, e_card_simple_get_id (modify_op->card)); - pas_book_view_notify_complete (view->book_view, GNOME_Evolution_Addressbook_BookViewListener_Success); - - bonobo_object_release_unref(bonobo_object_corba_objref(BONOBO_OBJECT(view->book_view)), &ev); - - e_iterator_next (iter); - } - g_object_unref (iter); - } - else { - ldap_perror (ldap, "ldap_modify_s"); - } - /* and lastly respond */ pas_book_respond_modify (op->book, - ldap_error_to_response (ldap_error)); + ldap_error_to_response (ldap_error), + modify_op->contact); ldap_op_finished (op); } static void -modify_card_search_handler (LDAPOp *op, LDAPMessage *res) +modify_contact_search_handler (LDAPOp *op, LDAPMessage *res) { LDAPModifyOp *modify_op = (LDAPModifyOp*)op; PASBackendLDAP *bl = PAS_BACKEND_LDAP (op->backend); @@ -1520,14 +1422,14 @@ modify_card_search_handler (LDAPOp *op, LDAPMessage *res) if (!e) { g_warning ("uh, this shouldn't happen"); pas_book_respond_modify (op->book, - GNOME_Evolution_Addressbook_BookListener_OtherError); + GNOME_Evolution_Addressbook_OtherError, + NULL); ldap_op_finished (op); return; } - modify_op->current_card = build_card_from_entry (ldap, e, - &modify_op->existing_objectclasses); - modify_op->current_vcard = e_card_simple_get_vcard_assume_utf8 (modify_op->current_card); + modify_op->current_contact = build_contact_from_entry (ldap, e, + &modify_op->existing_objectclasses); } else if (msg_type == LDAP_RES_SEARCH_RESULT) { int ldap_error; @@ -1535,7 +1437,7 @@ modify_card_search_handler (LDAPOp *op, LDAPMessage *res) GPtrArray *mod_array; gboolean differences; gboolean need_new_dn; - int modify_card_msgid; + int modify_contact_msgid; /* grab the result code, and set up the actual modify if it was successful */ @@ -1545,13 +1447,14 @@ modify_card_search_handler (LDAPOp *op, LDAPMessage *res) if (ldap_error != LDAP_SUCCESS) { /* more here i'm sure */ pas_book_respond_modify (op->book, - ldap_error_to_response (ldap_error)); + ldap_error_to_response (ldap_error), + NULL); ldap_op_finished (op); return; } /* build our mods */ - mod_array = build_mods_from_ecards (bl, modify_op->current_card, modify_op->card, &need_new_dn); + mod_array = build_mods_from_contacts (bl, modify_op->current_contact, modify_op->contact, &need_new_dn); differences = mod_array->len > 0; if (differences) { @@ -1569,17 +1472,18 @@ modify_card_search_handler (LDAPOp *op, LDAPMessage *res) /* actually perform the ldap modify */ ldap_error = ldap_modify_ext (ldap, modify_op->id, ldap_mods, - NULL, NULL, &modify_card_msgid); + NULL, NULL, &modify_contact_msgid); if (ldap_error == LDAP_SUCCESS) { - op->handler = modify_card_modify_handler; + op->handler = modify_contact_modify_handler; ldap_op_change_id ((LDAPOp*)modify_op, - modify_card_msgid); + modify_contact_msgid); } else { g_warning ("ldap_modify_ext returned %d\n", ldap_error); pas_book_respond_modify (op->book, - ldap_error_to_response (ldap_error)); + ldap_error_to_response (ldap_error), + NULL); ldap_op_finished (op); return; } @@ -1591,84 +1495,80 @@ modify_card_search_handler (LDAPOp *op, LDAPMessage *res) else { g_warning ("unhandled result type %d returned", msg_type); pas_book_respond_modify (op->book, - GNOME_Evolution_Addressbook_BookListener_OtherError); + GNOME_Evolution_Addressbook_OtherError, + NULL); ldap_op_finished (op); } } static void -modify_card_dtor (LDAPOp *op) +modify_contact_dtor (LDAPOp *op) { LDAPModifyOp *modify_op = (LDAPModifyOp*)op; g_list_foreach (modify_op->existing_objectclasses, (GFunc)g_free, NULL); g_list_free (modify_op->existing_objectclasses); - g_free (modify_op->current_vcard); - if (modify_op->current_card) - g_object_unref (modify_op->current_card); - g_free (modify_op->vcard); - if (modify_op->card) - g_object_unref (modify_op->card); + if (modify_op->current_contact) + g_object_unref (modify_op->current_contact); + if (modify_op->contact) + g_object_unref (modify_op->contact); g_free (modify_op); } static void -pas_backend_ldap_process_modify_card (PASBackend *backend, - PASBook *book, - PASModifyCardRequest *req) +pas_backend_ldap_process_modify_contact (PASBackend *backend, + PASBook *book, + const char *vcard) { LDAPModifyOp *modify_op = g_new0 (LDAPModifyOp, 1); PASBackendLDAP *bl = PAS_BACKEND_LDAP (backend); - ECard *new_ecard; int ldap_error; LDAP *ldap; - int modify_card_msgid; + int modify_contact_msgid; PASBookView *book_view; book_view = find_book_view (bl); - modify_op->vcard = g_strdup (req->vcard); - new_ecard = e_card_new (modify_op->vcard); - modify_op->card = e_card_simple_new (new_ecard); - g_object_unref (new_ecard); - modify_op->id = e_card_simple_get_id(modify_op->card); + modify_op->contact = e_contact_new_from_vcard (vcard); + modify_op->id = e_contact_get_const (modify_op->contact, E_CONTACT_UID); ldap = bl->priv->ldap; - book_view_notify_status (book_view, _("Modifying card from LDAP server...")); + book_view_notify_status (book_view, _("Modifying contact from LDAP server...")); do { - book_view_notify_status (book_view, _("Modifying card from LDAP server...")); + book_view_notify_status (book_view, _("Modifying contact from LDAP server...")); ldap_error = ldap_search_ext (ldap, modify_op->id, LDAP_SCOPE_BASE, "(objectclass=*)", NULL, 0, NULL, NULL, NULL, /* XXX timeout */ - 1, &modify_card_msgid); + 1, &modify_contact_msgid); } while (pas_backend_ldap_reconnect (bl, book_view, ldap_error)); if (ldap_error == LDAP_SUCCESS) { ldap_op_add ((LDAPOp*)modify_op, backend, book, - book_view, modify_card_msgid, - modify_card_search_handler, modify_card_dtor); + book_view, modify_contact_msgid, + modify_contact_search_handler, modify_contact_dtor); } else { g_warning ("ldap_search_ext returned %d\n", ldap_error); pas_book_respond_modify (book, - GNOME_Evolution_Addressbook_BookListener_OtherError); - modify_card_dtor ((LDAPOp*)modify_op); + GNOME_Evolution_Addressbook_OtherError, + NULL); + modify_contact_dtor ((LDAPOp*)modify_op); } } typedef struct { LDAPOp op; -} LDAPGetVCardOp; +} LDAPGetContactOp; static void -get_vcard_handler (LDAPOp *op, LDAPMessage *res) +get_contact_handler (LDAPOp *op, LDAPMessage *res) { PASBackendLDAP *bl = PAS_BACKEND_LDAP (op->backend); int msg_type; @@ -1679,37 +1579,37 @@ get_vcard_handler (LDAPOp *op, LDAPMessage *res) msg_type = ldap_msgtype (res); if (msg_type == LDAP_RES_SEARCH_ENTRY) { LDAPMessage *e = ldap_first_entry(bl->priv->ldap, res); - ECardSimple *simple; + EContact *contact; char *vcard; if (!e) { g_warning ("uh, this shouldn't happen"); - pas_book_respond_get_vcard (op->book, - GNOME_Evolution_Addressbook_BookListener_OtherError, - ""); + pas_book_respond_get_contact (op->book, + GNOME_Evolution_Addressbook_OtherError, + ""); ldap_op_finished (op); return; } - simple = build_card_from_entry (bl->priv->ldap, e, NULL); - vcard = e_card_simple_get_vcard_assume_utf8 (simple); - pas_book_respond_get_vcard (op->book, - GNOME_Evolution_Addressbook_BookListener_Success, - vcard); + contact = build_contact_from_entry (bl->priv->ldap, e, NULL); + vcard = e_vcard_to_string (E_VCARD (contact), EVC_FORMAT_VCARD_30); + pas_book_respond_get_contact (op->book, + GNOME_Evolution_Addressbook_Success, + vcard); g_free (vcard); - g_object_unref (simple); + g_object_unref (contact); ldap_op_finished (op); } else if (msg_type == LDAP_RES_SEARCH_RESULT) { int ldap_error; ldap_parse_result (bl->priv->ldap, res, &ldap_error, NULL, NULL, NULL, NULL, 0); - pas_book_respond_get_vcard (op->book, ldap_error_to_response (ldap_error), ""); + pas_book_respond_get_contact (op->book, ldap_error_to_response (ldap_error), ""); ldap_op_finished (op); } else { g_warning ("unhandled result type %d returned", msg_type); - pas_book_respond_get_vcard (op->book, GNOME_Evolution_Addressbook_BookListener_OtherError, + pas_book_respond_get_contact (op->book, GNOME_Evolution_Addressbook_OtherError, ""); ldap_op_finished (op); } @@ -1717,254 +1617,75 @@ get_vcard_handler (LDAPOp *op, LDAPMessage *res) } static void -get_vcard_dtor (LDAPOp *op) +get_contact_dtor (LDAPOp *op) { - LDAPGetVCardOp *get_vcard_op = (LDAPGetVCardOp*)op; + LDAPGetContactOp *get_contact_op = (LDAPGetContactOp*)op; - g_free (get_vcard_op); + g_free (get_contact_op); } static void -pas_backend_ldap_process_get_vcard (PASBackend *backend, - PASBook *book, - PASGetVCardRequest *req) +pas_backend_ldap_process_get_contact (PASBackend *backend, + PASBook *book, + const char *id) { - LDAPGetVCardOp *get_vcard_op = g_new0 (LDAPGetVCardOp, 1); + LDAPGetContactOp *get_contact_op = g_new0 (LDAPGetContactOp, 1); PASBackendLDAP *bl = PAS_BACKEND_LDAP (backend); LDAP *ldap = bl->priv->ldap; - int get_vcard_msgid; + int get_contact_msgid; PASBookView *book_view; int ldap_error; book_view = find_book_view (bl); do { - ldap_error = ldap_search_ext (ldap, req->id, + ldap_error = ldap_search_ext (ldap, id, LDAP_SCOPE_BASE, "(objectclass=*)", NULL, 0, NULL, NULL, NULL, /* XXX timeout */ - 1, &get_vcard_msgid); + 1, &get_contact_msgid); } while (pas_backend_ldap_reconnect (bl, book_view, ldap_error)); if (ldap_error == LDAP_SUCCESS) { - ldap_op_add ((LDAPOp*)get_vcard_op, backend, book, - book_view, get_vcard_msgid, - get_vcard_handler, get_vcard_dtor); + ldap_op_add ((LDAPOp*)get_contact_op, backend, book, + book_view, get_contact_msgid, + get_contact_handler, get_contact_dtor); } else { - pas_book_respond_get_vcard (book, + pas_book_respond_get_contact (book, ldap_error_to_response (ldap_error), ""); - get_vcard_dtor ((LDAPOp*)get_vcard_op); + get_contact_dtor ((LDAPOp*)get_contact_op); } } -typedef struct { - LDAPOp op; - PASBackendLDAPCursorPrivate *cursor_data; - gboolean responded; /* if FALSE, we need to free cursor_data in the dtor */ -} LDAPGetCursorOp; - -static long -get_length(PASCardCursor *cursor, gpointer data) -{ - PASBackendLDAPCursorPrivate *cursor_data = (PASBackendLDAPCursorPrivate *) data; - - return cursor_data->num_elements; -} - -static char * -get_nth(PASCardCursor *cursor, long n, gpointer data) -{ - PASBackendLDAPCursorPrivate *cursor_data = (PASBackendLDAPCursorPrivate *) data; - - g_return_val_if_fail (n < cursor_data->num_elements, NULL); - - return (char*)g_list_nth (cursor_data->elements, n); -} - -static void -cursor_destroy(gpointer data, GObject *where_object_was) -{ - PASBackendLDAPCursorPrivate *cursor_data = (PASBackendLDAPCursorPrivate *) data; - if (cursor_data->book) { - CORBA_Environment ev; - GNOME_Evolution_Addressbook_Book corba_book; - - 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); - } - - /* free the ldap specific cursor information */ - g_list_foreach (cursor_data->elements, (GFunc)g_free, NULL); - g_list_free (cursor_data->elements); - - g_free(cursor_data); -} - -static void -get_cursor_handler (LDAPOp *op, LDAPMessage *res) -{ - LDAPGetCursorOp *cursor_op = (LDAPGetCursorOp*)op; - PASBackendLDAP *bl = PAS_BACKEND_LDAP (op->backend); - LDAP *ldap = bl->priv->ldap; - int msg_type; - - msg_type = ldap_msgtype (res); - if (msg_type == LDAP_RES_SEARCH_ENTRY) { - LDAPMessage *e; - - e = ldap_first_entry (ldap, res); - while (e) { - ECardSimple *simple; - - simple = build_card_from_entry (ldap, e, NULL); - if (simple) { - char *vcard = e_card_simple_get_vcard_assume_utf8 (simple); - cursor_op->cursor_data->num_elements ++; - cursor_op->cursor_data->elements = g_list_prepend (cursor_op->cursor_data->elements, - vcard); - g_object_unref (simple); - } - } - } - else if (msg_type == LDAP_RES_SEARCH_RESULT) { - PASCardCursor *cursor = CORBA_OBJECT_NIL; - int ldap_error; - ldap_parse_result (bl->priv->ldap, res, &ldap_error, - NULL, NULL, NULL, NULL, 0); - - if (ldap_error == LDAP_SUCCESS) { - cursor = pas_card_cursor_new(get_length, - get_nth, - cursor_op->cursor_data); - - g_object_weak_ref (G_OBJECT (cursor), cursor_destroy, cursor_op->cursor_data); - - cursor_op->responded = TRUE; - } - - pas_book_respond_get_cursor (cursor_op->cursor_data->book, - ldap_error_to_response (ldap_error), - cursor); - - ldap_op_finished (op); - } - else { - g_warning ("unhandled result type %d returned", msg_type); - pas_book_respond_get_cursor (op->book, - GNOME_Evolution_Addressbook_BookListener_OtherError, - CORBA_OBJECT_NIL); - ldap_op_finished (op); - } -} - -static void -get_cursor_dtor (LDAPOp *op) -{ - LDAPGetCursorOp *cursor_op = (LDAPGetCursorOp*)op; - - if (!cursor_op->responded) { - cursor_destroy (cursor_op->cursor_data, NULL); - } - - g_free (op); -} - -static void -pas_backend_ldap_process_get_cursor (PASBackend *backend, - PASBook *book, - PASGetCursorRequest *req) -{ - PASBackendLDAP *bl = PAS_BACKEND_LDAP (backend); - LDAP *ldap = bl->priv->ldap; - int ldap_error; - int get_cursor_msgid; - LDAPGetCursorOp *cursor_op; - PASBookView *book_view; - - book_view = find_book_view (bl); - - cursor_op = g_new0 (LDAPGetCursorOp, 1); - cursor_op->cursor_data = g_new0 (PASBackendLDAPCursorPrivate, 1); - - do { - ldap_error = ldap_search_ext (ldap, - bl->priv->ldap_rootdn, - bl->priv->ldap_scope, - "(objectclass=*)", - NULL, 0, - NULL, NULL, NULL, /* timeout */ - 0, &get_cursor_msgid); - } while (pas_backend_ldap_reconnect (bl, book_view, ldap_error)); - - if (ldap_error == LDAP_SUCCESS) { - CORBA_Environment ev; - GNOME_Evolution_Addressbook_Book corba_book; - - corba_book = bonobo_object_corba_objref(BONOBO_OBJECT(book)); - - CORBA_exception_init(&ev); - - GNOME_Evolution_Addressbook_Book_ref(corba_book, &ev); - - cursor_op->cursor_data->backend = backend; - cursor_op->cursor_data->book = book; - - if (ev._major != CORBA_NO_EXCEPTION) { - g_warning("pas_backend_ldap_process_get_cursor: Exception reffing " - "corba book.\n"); - } - - CORBA_exception_free(&ev); - - - ldap_op_add ((LDAPOp*)cursor_op, backend, book, - NULL, get_cursor_msgid, get_cursor_handler, get_cursor_dtor); - } - else { - pas_book_respond_get_cursor (book, - ldap_error_to_response (ldap_error), - CORBA_OBJECT_NIL); - get_cursor_dtor ((LDAPOp*)cursor_op); - } -} +static EContactField email_ids[3] = { + E_CONTACT_EMAIL_1, + E_CONTACT_EMAIL_2, + E_CONTACT_EMAIL_3 +}; - /* List property functions */ static void -email_populate(ECardSimple *card, char **values) +email_populate(EContact *contact, char **values) { int i; - - for (i = 0; values[i] && i < 3; i ++) { - e_card_simple_set_email (card, i, values[i]); - } + for (i = 0; values[i] && i < 3; i ++) + e_contact_set (contact, email_ids[i], values[i]); } struct berval** -email_ber(ECardSimple *card) +email_ber(EContact *contact) { struct berval** result; const char *emails[3]; - int i, j, num; + int i, j, num = 0; - num = 0; for (i = 0; i < 3; i ++) { - emails[i] = e_card_simple_get_email (card, E_CARD_SIMPLE_EMAIL_ID_EMAIL + i); + emails[i] = e_contact_get (contact, email_ids[i]); if (emails[i]) num++; } @@ -1991,15 +1712,15 @@ email_ber(ECardSimple *card) } static gboolean -email_compare (ECardSimple *ecard1, ECardSimple *ecard2) +email_compare (EContact *contact1, EContact *contact2) { const char *email1, *email2; int i; for (i = 0; i < 3; i ++) { gboolean equal; - email1 = e_card_simple_get_email (ecard1, E_CARD_SIMPLE_EMAIL_ID_EMAIL + i); - email2 = e_card_simple_get_email (ecard2, E_CARD_SIMPLE_EMAIL_ID_EMAIL + i); + email1 = e_contact_get_const (contact1, email_ids[i]); + email2 = e_contact_get_const (contact2, email_ids[i]); if (email1 && email2) equal = !strcmp (email1, email2); @@ -2014,26 +1735,26 @@ email_compare (ECardSimple *ecard1, ECardSimple *ecard2) } static void -homephone_populate(ECardSimple *card, char **values) +homephone_populate(EContact *contact, char **values) { if (values[0]) { - e_card_simple_set (card, E_CARD_SIMPLE_FIELD_PHONE_HOME, values[0]); + e_contact_set (contact, E_CONTACT_PHONE_HOME, values[0]); if (values[1]) - e_card_simple_set (card, E_CARD_SIMPLE_FIELD_PHONE_HOME_2, values[1]); + e_contact_set (contact, E_CONTACT_PHONE_HOME_2, values[1]); } } struct berval** -homephone_ber(ECardSimple *card) +homephone_ber(EContact *contact) { struct berval** result; const char *homephones[3]; int i, j, num; num = 0; - if ((homephones[0] = e_card_simple_get (card, E_CARD_SIMPLE_FIELD_PHONE_HOME))) + if ((homephones[0] = e_contact_get (contact, E_CONTACT_PHONE_HOME))) num++; - if ((homephones[1] = e_card_simple_get (card, E_CARD_SIMPLE_FIELD_PHONE_HOME_2))) + if ((homephones[1] = e_contact_get (contact, E_CONTACT_PHONE_HOME_2))) num++; if (num == 0) @@ -2058,16 +1779,16 @@ homephone_ber(ECardSimple *card) } static gboolean -homephone_compare (ECardSimple *ecard1, ECardSimple *ecard2) +homephone_compare (EContact *contact1, EContact *contact2) { - int phone_ids[2] = { E_CARD_SIMPLE_FIELD_PHONE_HOME, E_CARD_SIMPLE_FIELD_PHONE_HOME_2 }; + int phone_ids[2] = { E_CONTACT_PHONE_HOME, E_CONTACT_PHONE_HOME_2 }; const char *phone1, *phone2; int i; for (i = 0; i < 2; i ++) { gboolean equal; - phone1 = e_card_simple_get (ecard1, phone_ids[i]); - phone2 = e_card_simple_get (ecard2, phone_ids[i]); + phone1 = e_contact_get (contact1, phone_ids[i]); + phone2 = e_contact_get (contact2, phone_ids[i]); if (phone1 && phone2) equal = !strcmp (phone1, phone2); @@ -2082,26 +1803,26 @@ homephone_compare (ECardSimple *ecard1, ECardSimple *ecard2) } static void -business_populate(ECardSimple *card, char **values) +business_populate(EContact *contact, char **values) { if (values[0]) { - e_card_simple_set (card, E_CARD_SIMPLE_FIELD_PHONE_BUSINESS, values[0]); + e_contact_set (contact, E_CONTACT_PHONE_BUSINESS, values[0]); if (values[1]) - e_card_simple_set (card, E_CARD_SIMPLE_FIELD_PHONE_BUSINESS_2, values[1]); + e_contact_set (contact, E_CONTACT_PHONE_BUSINESS_2, values[1]); } } struct berval** -business_ber(ECardSimple *card) +business_ber(EContact *contact) { struct berval** result; const char *business_phones[3]; int i, j, num; num = 0; - if ((business_phones[0] = e_card_simple_get (card, E_CARD_SIMPLE_FIELD_PHONE_BUSINESS))) + if ((business_phones[0] = e_contact_get (contact, E_CONTACT_PHONE_BUSINESS))) num++; - if ((business_phones[1] = e_card_simple_get (card, E_CARD_SIMPLE_FIELD_PHONE_BUSINESS_2))) + if ((business_phones[1] = e_contact_get (contact, E_CONTACT_PHONE_BUSINESS_2))) num++; if (num == 0) @@ -2126,16 +1847,16 @@ business_ber(ECardSimple *card) } static gboolean -business_compare (ECardSimple *ecard1, ECardSimple *ecard2) +business_compare (EContact *contact1, EContact *contact2) { - int phone_ids[2] = { E_CARD_SIMPLE_FIELD_PHONE_BUSINESS, E_CARD_SIMPLE_FIELD_PHONE_BUSINESS_2 }; + int phone_ids[2] = { E_CONTACT_PHONE_BUSINESS, E_CONTACT_PHONE_BUSINESS_2 }; const char *phone1, *phone2; int i; for (i = 0; i < 2; i ++) { gboolean equal; - phone1 = e_card_simple_get (ecard1, phone_ids[i]); - phone2 = e_card_simple_get (ecard2, phone_ids[i]); + phone1 = e_contact_get (contact1, phone_ids[i]); + phone2 = e_contact_get (contact2, phone_ids[i]); if (phone1 && phone2) equal = !strcmp (phone1, phone2); @@ -2150,30 +1871,26 @@ business_compare (ECardSimple *ecard1, ECardSimple *ecard2) } static void -anniversary_populate (ECardSimple *card, char **values) +anniversary_populate (EContact *contact, char **values) { if (values[0]) { - ECardDate dt = e_card_date_from_string (values[0]); - g_object_set (card->card, - "anniversary", &dt, - NULL); + EContactDate *dt = e_contact_date_from_string (values[0]); + e_contact_set (contact, E_CONTACT_ANNIVERSARY, &dt); } } struct berval** -anniversary_ber (ECardSimple *card) +anniversary_ber (EContact *contact) { - ECardDate *dt; + EContactDate *dt; struct berval** result = NULL; - g_object_get (card->card, - "anniversary", &dt, - NULL); + dt = e_contact_get (contact, E_CONTACT_ANNIVERSARY); if (dt) { char *anniversary; - anniversary = e_card_date_to_string (dt); + anniversary = e_contact_date_to_string (dt); result = g_new (struct berval*, 2); result[0] = g_new (struct berval, 1); @@ -2181,29 +1898,31 @@ anniversary_ber (ECardSimple *card) result[0]->bv_len = strlen (anniversary); result[1] = NULL; + + e_contact_date_free (dt); } return result; } static gboolean -anniversary_compare (ECardSimple *ecard1, ECardSimple *ecard2) +anniversary_compare (EContact *contact1, EContact *contact2) { - ECardDate *dt; + EContactDate *dt; char *date1 = NULL, *date2 = NULL; gboolean equal; - g_object_get (ecard1->card, - "anniversary", &dt, - NULL); - if (dt) - date1 = e_card_date_to_string (dt); - - g_object_get (ecard2->card, - "anniversary", &dt, - NULL); - if (dt) - date2 = e_card_date_to_string (dt); + dt = e_contact_get (contact1, E_CONTACT_ANNIVERSARY); + if (dt) { + date1 = e_contact_date_to_string (dt); + e_contact_date_free (dt); + } + + dt = e_contact_get (contact2, E_CONTACT_ANNIVERSARY); + if (dt) { + date2 = e_contact_date_to_string (dt); + e_contact_date_free (dt); + } if (date1 && date2) equal = !strcmp (date1, date2); @@ -2217,30 +1936,26 @@ anniversary_compare (ECardSimple *ecard1, ECardSimple *ecard2) } static void -birthday_populate (ECardSimple *card, char **values) +birthday_populate (EContact *contact, char **values) { if (values[0]) { - ECardDate dt = e_card_date_from_string (values[0]); - g_object_set (card->card, - "birth_date", &dt, - NULL); + EContactDate *dt = e_contact_date_from_string (values[0]); + e_contact_set (contact, E_CONTACT_BIRTH_DATE, dt); + e_contact_date_free (dt); } } struct berval** -birthday_ber (ECardSimple *card) +birthday_ber (EContact *contact) { - ECardDate *dt; + EContactDate *dt; struct berval** result = NULL; - g_object_get (card->card, - "birth_date", &dt, - NULL); - + dt = e_contact_get (contact, E_CONTACT_BIRTH_DATE); if (dt) { char *birthday; - birthday = e_card_date_to_string (dt); + birthday = e_contact_date_to_string (dt); result = g_new (struct berval*, 2); result[0] = g_new (struct berval, 1); @@ -2248,29 +1963,31 @@ birthday_ber (ECardSimple *card) result[0]->bv_len = strlen (birthday); result[1] = NULL; + + e_contact_date_free (dt); } return result; } static gboolean -birthday_compare (ECardSimple *ecard1, ECardSimple *ecard2) +birthday_compare (EContact *contact1, EContact *contact2) { - ECardDate *dt; + EContactDate *dt; char *date1 = NULL, *date2 = NULL; gboolean equal; - g_object_get (ecard1->card, - "birth_date", &dt, - NULL); - if (dt) - date1 = e_card_date_to_string (dt); + dt = e_contact_get (contact1, E_CONTACT_BIRTH_DATE); + if (dt) { + date1 = e_contact_date_to_string (dt); + e_contact_date_free (dt); + } - g_object_get (ecard2->card, - "birth_date", &dt, - NULL); - if (dt) - date2 = e_card_date_to_string (dt); + dt = e_contact_get (contact2, E_CONTACT_BIRTH_DATE); + if (dt) { + date2 = e_contact_date_to_string (dt); + e_contact_date_free (dt); + } if (date1 && date2) equal = !strcmp (date1, date2); @@ -2284,10 +2001,11 @@ birthday_compare (ECardSimple *ecard1, ECardSimple *ecard2) } static void -category_populate (ECardSimple *card, char **values) +category_populate (EContact *contact, char **values) { +#if notyet int i; - ECard *ecard; + EContact *ecard; EList *categories; g_object_get (card, @@ -2309,15 +2027,17 @@ category_populate (ECardSimple *card, char **values) e_card_simple_sync_card (card); g_object_unref (ecard); +#endif } struct berval** -category_ber (ECardSimple *card) +category_ber (EContact *contact) { +#if notyet struct berval** result = NULL; EList *categories; EIterator *iterator; - ECard *ecard; + EContact *ecard; int i; g_object_get (card, @@ -2346,16 +2066,18 @@ category_ber (ECardSimple *card) g_object_unref (categories); g_object_unref (ecard); return result; +#endif } static gboolean -category_compare (ECardSimple *ecard1, ECardSimple *ecard2) +category_compare (EContact *contact1, EContact *contact2) { +#if notyet char *categories1, *categories2; gboolean equal; - categories1 = e_card_simple_get (ecard1, E_CARD_SIMPLE_FIELD_CATEGORIES); - categories2 = e_card_simple_get (ecard2, E_CARD_SIMPLE_FIELD_CATEGORIES); + categories1 = e_card_simple_get (ecard1, E_CONTACT_CATEGORIES); + categories2 = e_card_simple_get (ecard2, E_CONTACT_CATEGORIES); equal = !strcmp (categories1, categories2); @@ -2363,6 +2085,19 @@ category_compare (ECardSimple *ecard1, ECardSimple *ecard2) g_free (categories2); return equal; +#endif +} + +static void +photo_populate (EContact *contact, struct berval **ber_values) +{ + if (ber_values && ber_values[0]) { + EContactPhoto photo; + photo.data = ber_values[0]->bv_val; + photo.length = ber_values[0]->bv_len; + + e_contact_set (contact, E_CONTACT_PHOTO, &photo); + } } typedef struct { @@ -2670,6 +2405,58 @@ func_endswith(struct _ESExp *f, int argc, struct _ESExpResult **argv, void *data return r; } +static ESExpResult * +func_exists(struct _ESExp *f, int argc, struct _ESExpResult **argv, void *data) +{ + PASBackendLDAPSExpData *ldap_data = data; + ESExpResult *r; + + if (argc == 1 + && argv[0]->type == ESEXP_RES_STRING) { + char *propname = argv[0]->value.string; + + if (!strcmp (propname, "x-evolution-any-field")) { + int i; + int query_length; + char *big_query; + char *match_str; + + match_str = g_strdup("=*)"); + + query_length = 3; /* strlen ("(|") + strlen (")") */ + + for (i = 0; i < num_prop_infos; i ++) { + query_length += 1 /* strlen ("(") */ + strlen(prop_info[i].ldap_attr) + strlen (match_str); + } + + big_query = g_malloc0(query_length + 1); + strcat (big_query, "(|"); + for (i = 0; i < num_prop_infos; i ++) { + strcat (big_query, "("); + strcat (big_query, prop_info[i].ldap_attr); + strcat (big_query, match_str); + } + strcat (big_query, ")"); + + ldap_data->list = g_list_prepend(ldap_data->list, big_query); + + g_free (match_str); + } + else { + char *ldap_attr = query_prop_to_ldap(propname); + + if (ldap_attr) + ldap_data->list = g_list_prepend(ldap_data->list, + g_strdup_printf("(%s=*)", ldap_attr)); + } + } + + r = e_sexp_result_new(f, ESEXP_RES_BOOL); + r->value.bool = FALSE; + + return r; +} + /* 'builtin' functions */ static struct { char *name; @@ -2684,10 +2471,11 @@ static struct { { "is", func_is, 0 }, { "beginswith", func_beginswith, 0 }, { "endswith", func_endswith, 0 }, + { "exists", func_exists, 0 }, }; static gchar * -pas_backend_ldap_build_query (PASBackendLDAP *bl, gchar *query) +pas_backend_ldap_build_query (PASBackendLDAP *bl, const char *query) { ESExp *sexp; ESExpResult *r; @@ -2743,7 +2531,7 @@ query_prop_to_ldap(gchar *query_prop) int i; for (i = 0; i < num_prop_infos; i ++) - if (!strcmp (query_prop, prop_info[i].query_prop)) + if (!strcmp (query_prop, e_contact_field_name (prop_info[i].field_id))) return prop_info[i].ldap_attr; return NULL; @@ -2752,31 +2540,22 @@ query_prop_to_ldap(gchar *query_prop) typedef struct { LDAPOp op; - PASBackendLDAPBookView *view; - - /* grouping stuff */ - GList *pending_adds; /* the cards we're sending */ - int num_pending_adds; /* the number waiting to be sent */ - int target_pending_adds; /* the cutoff that forces a flush to the client, if it happens before the timeout */ - int num_sent_this_time; /* the number of cards we sent to the client before the most recent timeout */ - int num_sent_last_time; /* the number of cards we sent to the client before the previous timeout */ - glong grouping_time_start; - + PASBookView *view; + /* used by search_handler to only send the status messages once */ gboolean notified_receiving_results; } LDAPSearchOp; -static ECardSimple * -build_card_from_entry (LDAP *ldap, LDAPMessage *e, GList **existing_objectclasses) +static EContact * +build_contact_from_entry (LDAP *ldap, LDAPMessage *e, GList **existing_objectclasses) { - ECard *ecard = e_card_new (""); - ECardSimple *card = e_card_simple_new (ecard); + EContact *contact = e_contact_new (); char *dn; char *attr; BerElement *ber = NULL; dn = ldap_get_dn(ldap, e); - e_card_simple_set_id (card, dn); + e_contact_set (contact, E_CONTACT_UID, dn); ldap_memfree (dn); for (attr = ldap_first_attribute (ldap, e, &ber); attr; @@ -2799,24 +2578,41 @@ build_card_from_entry (LDAP *ldap, LDAPMessage *e, GList **existing_objectclasse break; } + printf ("attr = %s, ", attr); + printf ("info = %p\n", info); + if (info) { - values = ldap_get_values (ldap, e, attr); + if (info->prop_type & PROP_WRITE_ONLY) + continue; + + if (info->prop_type & PROP_TYPE_BINARY) { + struct berval **ber_values = ldap_get_values_len (ldap, e, attr); - if (values) { - if (info->prop_type & PROP_TYPE_STRING) { - /* if it's a normal property just set the string */ - if (values[0]) - e_card_simple_set (card, info->field_id, values[0]); + if (ber_values) { + info->binary_populate_contact_func (contact, ber_values); + ldap_value_free_len (ber_values); } - else if (info->prop_type & PROP_TYPE_COMPLEX) { - /* if it's a list call the ecard-populate function, - which calls g_object_set to set the property */ - info->populate_ecard_func(card, - values); + } + else { + values = ldap_get_values (ldap, e, attr); + + if (values) { + if (info->prop_type & PROP_TYPE_STRING) { + printf ("value = %s\n", values[0]); + /* if it's a normal property just set the string */ + if (values[0]) + e_contact_set (contact, info->field_id, values[0]); + } + else if (info->prop_type & PROP_TYPE_COMPLEX) { + /* if it's a list call the contact-populate function, + which calls g_object_set to set the property */ + info->populate_contact_func(contact, + values); + } + + ldap_value_free (values); } - - ldap_value_free (values); } } } @@ -2827,11 +2623,7 @@ build_card_from_entry (LDAP *ldap, LDAPMessage *e, GList **existing_objectclasse if (ber) ber_free (ber, 0); - e_card_simple_sync_card (card); - - g_object_unref (ecard); - - return card; + return contact; } static gboolean @@ -2840,10 +2632,7 @@ poll_ldap (PASBackendLDAP *bl) LDAP *ldap = bl->priv->ldap; int rc; LDAPMessage *res; - GTimeVal cur_time; - glong cur_millis; struct timeval timeout; - EIterator *iter; if (!bl->priv->active_ops) { g_warning ("poll_ldap being called for backend with no active operations"); @@ -2880,81 +2669,20 @@ poll_ldap (PASBackendLDAP *bl) } } - g_get_current_time (&cur_time); - cur_millis = TV_TO_MILLIS (cur_time); - - iter = e_list_get_iterator (bl->priv->book_views); - while (e_iterator_is_valid (iter)) { - PASBackendLDAPBookView *view = (PASBackendLDAPBookView *)e_iterator_get (iter); - if (view->search_op) { - bonobo_object_dup_ref(bonobo_object_corba_objref(BONOBO_OBJECT(view->book_view)), NULL); - - ldap_search_op_timeout (view->search_op, cur_millis); - - bonobo_object_release_unref(bonobo_object_corba_objref(BONOBO_OBJECT(view->book_view)), NULL); - } - e_iterator_next (iter); - } - g_object_unref (iter); - return TRUE; } -static void -send_pending_adds (LDAPSearchOp *search_op) -{ - search_op->num_sent_this_time += search_op->num_pending_adds; - pas_book_view_notify_add (search_op->op.view, search_op->pending_adds); - g_list_foreach (search_op->pending_adds, (GFunc)g_free, NULL); - g_list_free (search_op->pending_adds); - search_op->pending_adds = NULL; - search_op->num_pending_adds = 0; -} - -static void -ldap_search_op_timeout (LDAPOp *op, glong cur_millis) -{ - LDAPSearchOp *search_op = (LDAPSearchOp*)op; - - if (cur_millis - search_op->grouping_time_start > GROUPING_MINIMUM_WAIT) { - - if (search_op->num_pending_adds >= search_op->target_pending_adds) - send_pending_adds (search_op); - - if (cur_millis - search_op->grouping_time_start > GROUPING_MAXIMUM_WAIT) { - GTimeVal new_start; - - if (search_op->num_pending_adds) - send_pending_adds (search_op); - search_op->target_pending_adds = MIN (GROUPING_MAXIMUM_SIZE, - (search_op->num_sent_this_time + search_op->num_sent_last_time) / 2); - search_op->target_pending_adds = MAX (search_op->target_pending_adds, 1); - -#ifdef PERFORMANCE_SPEW - printf ("num sent this time %d, last time %d, target pending adds set to %d\n", - search_op->num_sent_this_time, - search_op->num_sent_last_time, - search_op->target_pending_adds); -#endif - g_get_current_time (&new_start); - search_op->grouping_time_start = TV_TO_MILLIS (new_start); - search_op->num_sent_last_time = search_op->num_sent_this_time; - search_op->num_sent_this_time = 0; - } - } -} - static void ldap_search_handler (LDAPOp *op, LDAPMessage *res) { LDAPSearchOp *search_op = (LDAPSearchOp*)op; - PASBackendLDAPBookView *view = search_op->view; + PASBookView *view = search_op->view; PASBackendLDAP *bl = PAS_BACKEND_LDAP (op->backend); LDAP *ldap = bl->priv->ldap; LDAPMessage *e; int msg_type; - bonobo_object_dup_ref(bonobo_object_corba_objref(BONOBO_OBJECT(view->book_view)), NULL); + bonobo_object_dup_ref(bonobo_object_corba_objref(BONOBO_OBJECT(view)), NULL); if (!search_op->notified_receiving_results) { search_op->notified_receiving_results = TRUE; @@ -2966,13 +2694,11 @@ ldap_search_handler (LDAPOp *op, LDAPMessage *res) e = ldap_first_entry(ldap, res); while (NULL != e) { - ECardSimple *card = build_card_from_entry (ldap, e, NULL); + EContact *contact = build_contact_from_entry (ldap, e, NULL); - search_op->pending_adds = g_list_append (search_op->pending_adds, - e_card_simple_get_vcard_assume_utf8 (card)); - search_op->num_pending_adds ++; + pas_book_view_notify_update (view, contact); - g_object_unref (card); + g_object_unref (contact); e = ldap_next_entry(ldap, e); } @@ -2985,31 +2711,25 @@ ldap_search_handler (LDAPOp *op, LDAPMessage *res) g_warning ("search returned %d\n", ldap_error); - /* the entry that marks the end of our search */ - if (search_op->num_pending_adds) - send_pending_adds (search_op); - if (ldap_error == LDAP_TIMELIMIT_EXCEEDED) - pas_book_view_notify_complete (search_op->op.view, GNOME_Evolution_Addressbook_BookViewListener_SearchTimeLimitExceeded); + pas_book_view_notify_complete (search_op->op.view, GNOME_Evolution_Addressbook_SearchTimeLimitExceeded); else if (ldap_error == LDAP_SIZELIMIT_EXCEEDED) - pas_book_view_notify_complete (search_op->op.view, GNOME_Evolution_Addressbook_BookViewListener_SearchSizeLimitExceeded); + pas_book_view_notify_complete (search_op->op.view, GNOME_Evolution_Addressbook_SearchSizeLimitExceeded); else if (ldap_error == LDAP_SUCCESS) - pas_book_view_notify_complete (search_op->op.view, GNOME_Evolution_Addressbook_BookViewListener_Success); + pas_book_view_notify_complete (search_op->op.view, GNOME_Evolution_Addressbook_Success); else - pas_book_view_notify_complete (search_op->op.view, GNOME_Evolution_Addressbook_BookViewListener_OtherError); + pas_book_view_notify_complete (search_op->op.view, GNOME_Evolution_Addressbook_OtherError); ldap_op_finished (op); } else { g_warning ("unhandled search result type %d returned", msg_type); - if (search_op->num_pending_adds) - send_pending_adds (search_op); - pas_book_view_notify_complete (search_op->op.view, GNOME_Evolution_Addressbook_BookViewListener_OtherError); + pas_book_view_notify_complete (search_op->op.view, GNOME_Evolution_Addressbook_OtherError); ldap_op_finished (op); } - bonobo_object_release_unref(bonobo_object_corba_objref(BONOBO_OBJECT(view->book_view)), NULL); + bonobo_object_release_unref(bonobo_object_corba_objref(BONOBO_OBJECT(view)), NULL); } static void @@ -3017,14 +2737,11 @@ ldap_search_dtor (LDAPOp *op) { LDAPSearchOp *search_op = (LDAPSearchOp*) op; +#if notyet /* unhook us from our PASBackendLDAPBookView */ if (search_op->view) search_op->view->search_op = NULL; - - g_list_foreach (search_op->pending_adds, (GFunc)g_free, NULL); - g_list_free (search_op->pending_adds); - search_op->pending_adds = NULL; - search_op->num_pending_adds = 0; +#endif g_free (search_op); } @@ -3032,22 +2749,21 @@ ldap_search_dtor (LDAPOp *op) static void pas_backend_ldap_search (PASBackendLDAP *bl, PASBook *book, - PASBackendLDAPBookView *view) + PASBookView *view) { char *ldap_query; - ldap_query = pas_backend_ldap_build_query(bl, view->search); + ldap_query = pas_backend_ldap_build_query (bl, pas_book_view_get_card_query (view)); if (ldap_query != NULL) { LDAP *ldap = bl->priv->ldap; int ldap_err; - GTimeVal search_start; int search_msgid; printf ("searching server using filter: %s\n", ldap_query); do { - book_view_notify_status (view->book_view, _("Searching...")); + book_view_notify_status (view, _("Searching...")); ldap_err = ldap_search_ext (ldap, bl->priv->ldap_rootdn, bl->priv->ldap_scope, @@ -3056,33 +2772,30 @@ pas_backend_ldap_search (PASBackendLDAP *bl, NULL, /* XXX */ NULL, /* XXX */ NULL, /* XXX timeout */ - view->limit, &search_msgid); - } while (pas_backend_ldap_reconnect (bl, view->book_view, ldap_err)); + 0 /* XXX we need this back in view->limit*/, &search_msgid); + } while (pas_backend_ldap_reconnect (bl, view, ldap_err)); g_free (ldap_query); if (ldap_err != LDAP_SUCCESS) { - book_view_notify_status (view->book_view, ldap_err2string(ldap_err)); + book_view_notify_status (view, ldap_err2string(ldap_err)); return; } else if (search_msgid == -1) { - book_view_notify_status (view->book_view, + book_view_notify_status (view, _("Error performing search")); return; } else { LDAPSearchOp *op = g_new0 (LDAPSearchOp, 1); - op->target_pending_adds = GROUPING_INITIAL_SIZE; - - g_get_current_time (&search_start); - op->grouping_time_start = TV_TO_MILLIS (search_start); - op->view = view; +#if notyet view->search_op = (LDAPOp*)op; +#endif - ldap_op_add ((LDAPOp*)op, PAS_BACKEND(bl), book, view->book_view, + ldap_op_add ((LDAPOp*)op, PAS_BACKEND(bl), book, view, search_msgid, ldap_search_handler, ldap_search_dtor); @@ -3090,106 +2803,49 @@ pas_backend_ldap_search (PASBackendLDAP *bl, return; } else { - pas_book_view_notify_complete (view->book_view, - GNOME_Evolution_Addressbook_BookViewListener_InvalidQuery); + pas_book_view_notify_complete (view, + GNOME_Evolution_Addressbook_InvalidQuery); return; } } static void -ldap_get_view (PASBackend *backend, - PASBook *book, - const char *search, - GNOME_Evolution_Addressbook_BookViewListener listener, - int limit) -{ - PASBackendLDAP *bl = PAS_BACKEND_LDAP (backend); - PASBookView *book_view; - PASBackendLDAPBookView *view; - - book_view = pas_book_view_new (listener); - - bonobo_object_ref(BONOBO_OBJECT(book)); - g_object_weak_ref (G_OBJECT (book_view), view_destroy, book); - - view = g_new0(PASBackendLDAPBookView, 1); - view->book_view = book_view; - view->search = g_strdup(search); - view->card_sexp = pas_backend_card_sexp_new (view->search); - view->blpriv = bl->priv; - view->limit = limit; - - e_list_append(bl->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); - - pas_backend_ldap_search (bl, book, view); - - bonobo_object_unref (BONOBO_OBJECT (book_view)); -} - -static void -pas_backend_ldap_process_get_book_view (PASBackend *backend, - PASBook *book, - PASGetBookViewRequest *req) -{ - PASBackendLDAP *bl = PAS_BACKEND_LDAP (backend); - - ldap_get_view (backend, book, req->search, req->listener, - bl->priv->ldap_limit); -} - -static void -pas_backend_ldap_process_get_completion_view (PASBackend *backend, - PASBook *book, - PASGetCompletionViewRequest *req) +pas_backend_ldap_process_start_book_view (PASBackend *backend, + PASBookView *view) { PASBackendLDAP *bl = PAS_BACKEND_LDAP (backend); - ldap_get_view (backend, book, req->search, req->listener, - MIN (bl->priv->ldap_limit, 100)); + pas_backend_ldap_search (bl, NULL /* XXX ugh */, view); } static void pas_backend_ldap_process_get_changes (PASBackend *backend, PASBook *book, - PASGetChangesRequest *req) + const char *change_id) { /* FIXME: implement */ } -static void -pas_backend_ldap_process_check_connection (PASBackend *backend, - PASBook *book, - PASCheckConnectionRequest *req) -{ - PASBackendLDAP *bl = PAS_BACKEND_LDAP (backend); - - pas_book_report_connection (book, bl->priv->connected); -} - #define LDAP_SIMPLE_PREFIX "ldap/simple-" #define SASL_PREFIX "sasl/" static void pas_backend_ldap_process_authenticate_user (PASBackend *backend, PASBook *book, - PASAuthenticateUserRequest *req) + const char *user, + const char *passwd, + const char *auth_method) { PASBackendLDAP *bl = PAS_BACKEND_LDAP (backend); int ldap_error; char *dn = NULL; - if (!strncasecmp (req->auth_method, LDAP_SIMPLE_PREFIX, strlen (LDAP_SIMPLE_PREFIX))) { + if (!strncasecmp (auth_method, LDAP_SIMPLE_PREFIX, strlen (LDAP_SIMPLE_PREFIX))) { - if (!strcmp (req->auth_method, "ldap/simple-email")) { + if (!strcmp (auth_method, "ldap/simple-email")) { LDAPMessage *res, *e; - char *query = g_strdup_printf ("(mail=%s)", req->user); + char *query = g_strdup_printf ("(mail=%s)", user); ldap_error = ldap_search_s (bl->priv->ldap, bl->priv->ldap_rootdn, @@ -3211,37 +2867,37 @@ pas_backend_ldap_process_authenticate_user (PASBackend *backend, } else { pas_book_respond_authenticate_user (book, - GNOME_Evolution_Addressbook_BookListener_PermissionDenied); + GNOME_Evolution_Addressbook_PermissionDenied); return; } } - else if (!strcmp (req->auth_method, "ldap/simple-binddn")) { - dn = g_strdup (req->user); + else if (!strcmp (auth_method, "ldap/simple-binddn")) { + dn = g_strdup (user); } /* now authenticate against the DN we were either supplied or queried for */ printf ("simple auth as %s\n", dn); ldap_error = ldap_simple_bind_s(bl->priv->ldap, dn, - req->passwd); + passwd); pas_book_respond_authenticate_user (book, ldap_error_to_response (ldap_error)); } #ifdef ENABLE_SASL_BINDS - else if (!strncasecmp (req->auth_method, SASL_PREFIX, strlen (SASL_PREFIX))) { - g_print ("sasl bind (mech = %s) as %s", req->auth_method + strlen (SASL_PREFIX), req->user); + else if (!strncasecmp (auth_method, SASL_PREFIX, strlen (SASL_PREFIX))) { + g_print ("sasl bind (mech = %s) as %s", auth_method + strlen (SASL_PREFIX), user); ldap_error = ldap_sasl_bind_s (bl->priv->ldap, NULL, - req->auth_method + strlen (SASL_PREFIX), - req->passwd, + auth_method + strlen (SASL_PREFIX), + passwd, NULL, NULL, NULL); if (ldap_error == LDAP_NOT_SUPPORTED) pas_book_respond_authenticate_user (book, - GNOME_Evolution_Addressbook_BookListener_UnsupportedAuthenticationMethod); + GNOME_Evolution_Addressbook_UnsupportedAuthenticationMethod); else pas_book_respond_authenticate_user (book, ldap_error_to_response (ldap_error)); @@ -3249,13 +2905,13 @@ pas_backend_ldap_process_authenticate_user (PASBackend *backend, #endif else { pas_book_respond_authenticate_user (book, - GNOME_Evolution_Addressbook_BookListener_UnsupportedAuthenticationMethod); + GNOME_Evolution_Addressbook_UnsupportedAuthenticationMethod); return; } if (ldap_error == LDAP_SUCCESS) { bl->priv->auth_dn = dn; - bl->priv->auth_passwd = g_strdup (req->passwd); + bl->priv->auth_passwd = g_strdup (passwd); pas_backend_set_is_writable (backend, TRUE); @@ -3281,33 +2937,32 @@ pas_backend_ldap_process_authenticate_user (PASBackend *backend, static void pas_backend_ldap_process_get_supported_fields (PASBackend *backend, - PASBook *book, - PASGetSupportedFieldsRequest *req) + PASBook *book) { PASBackendLDAP *bl = PAS_BACKEND_LDAP (backend); pas_book_respond_get_supported_fields (book, - GNOME_Evolution_Addressbook_BookListener_Success, + GNOME_Evolution_Addressbook_Success, bl->priv->supported_fields); } static void pas_backend_ldap_process_get_supported_auth_methods (PASBackend *backend, - PASBook *book, - PASGetSupportedAuthMethodsRequest *req) + PASBook *book) { PASBackendLDAP *bl = PAS_BACKEND_LDAP (backend); pas_book_respond_get_supported_auth_methods (book, - GNOME_Evolution_Addressbook_BookListener_Success, + GNOME_Evolution_Addressbook_Success, bl->priv->supported_auth_methods); } -static GNOME_Evolution_Addressbook_BookListener_CallStatus +static GNOME_Evolution_Addressbook_CallStatus pas_backend_ldap_load_uri (PASBackend *backend, - const char *uri) + const char *uri, + gboolean only_if_exists) { PASBackendLDAP *bl = PAS_BACKEND_LDAP (backend); LDAPURLDesc *lud; @@ -3383,17 +3038,7 @@ pas_backend_ldap_load_uri (PASBackend *backend, return pas_backend_ldap_connect (bl); } else - return GNOME_Evolution_Addressbook_BookListener_OtherError; -} - -/* Get_uri handler for the addressbook LDAP backend */ -static const char * -pas_backend_ldap_get_uri (PASBackend *backend) -{ - PASBackendLDAP *bl; - - bl = PAS_BACKEND_LDAP (backend); - return bl->priv->uri; + return GNOME_Evolution_Addressbook_OtherError; } static char* @@ -3459,13 +3104,15 @@ pas_backend_ldap_dispose (GObject *object) g_source_remove (bl->priv->poll_timeout); } - g_object_unref (bl->priv->book_views); - - if (bl->priv->supported_fields) - g_object_unref (bl->priv->supported_fields); + if (bl->priv->supported_fields) { + g_list_foreach (bl->priv->supported_fields, (GFunc)g_free, NULL); + g_list_free (bl->priv->supported_fields); + } - if (bl->priv->supported_auth_methods) - g_object_unref (bl->priv->supported_auth_methods); + if (bl->priv->supported_auth_methods) { + g_list_foreach (bl->priv->supported_auth_methods, (GFunc)g_free, NULL); + g_list_free (bl->priv->supported_auth_methods); + } g_free (bl->priv->uri); @@ -3492,17 +3139,13 @@ pas_backend_ldap_class_init (PASBackendLDAPClass *klass) /* Set the virtual methods. */ parent_class->load_uri = pas_backend_ldap_load_uri; - parent_class->get_uri = pas_backend_ldap_get_uri; parent_class->get_static_capabilities = pas_backend_ldap_get_static_capabilities; - parent_class->create_card = pas_backend_ldap_process_create_card; - parent_class->remove_cards = pas_backend_ldap_process_remove_cards; - parent_class->modify_card = pas_backend_ldap_process_modify_card; - parent_class->check_connection = pas_backend_ldap_process_check_connection; - parent_class->get_vcard = pas_backend_ldap_process_get_vcard; - parent_class->get_cursor = pas_backend_ldap_process_get_cursor; - parent_class->get_book_view = pas_backend_ldap_process_get_book_view; - parent_class->get_completion_view = pas_backend_ldap_process_get_completion_view; + parent_class->create_contact = pas_backend_ldap_process_create_contact; + parent_class->remove_contacts = pas_backend_ldap_process_remove_contacts; + parent_class->modify_contact = pas_backend_ldap_process_modify_contact; + parent_class->get_contact = pas_backend_ldap_process_get_contact; + parent_class->start_book_view = pas_backend_ldap_process_start_book_view; parent_class->get_changes = pas_backend_ldap_process_get_changes; parent_class->authenticate_user = pas_backend_ldap_process_authenticate_user; parent_class->get_supported_fields = pas_backend_ldap_process_get_supported_fields; @@ -3518,11 +3161,11 @@ pas_backend_ldap_init (PASBackendLDAP *backend) priv = g_new0 (PASBackendLDAPPrivate, 1); - priv->supported_fields = e_list_new ((EListCopyFunc)g_strdup, (EListFreeFunc)g_free, NULL); - priv->ldap_limit = 100; - priv->id_to_op = g_hash_table_new (g_int_hash, g_int_equal); - priv->poll_timeout = -1; - priv->book_views = e_list_new (NULL, NULL, NULL); + priv->supported_fields = NULL; + priv->supported_auth_methods = NULL; + priv->ldap_limit = 100; + priv->id_to_op = g_hash_table_new (g_int_hash, g_int_equal); + priv->poll_timeout = -1; backend->priv = priv; } diff --git a/addressbook/backend/pas/pas-backend-summary.c b/addressbook/backend/pas/pas-backend-summary.c index 6c2c9a45c8..15f12cebc1 100644 --- a/addressbook/backend/pas/pas-backend-summary.c +++ b/addressbook/backend/pas/pas-backend-summary.c @@ -33,7 +33,7 @@ #include -#include "ebook/e-card-simple.h" +#include "ebook/e-contact.h" #include "pas-backend-summary.h" #include "e-util/e-sexp.h" @@ -689,36 +689,29 @@ pas_backend_summary_save (PASBackendSummary *summary) } void -pas_backend_summary_add_card (PASBackendSummary *summary, const char *vcard) +pas_backend_summary_add_contact (PASBackendSummary *summary, EContact *contact) { - ECard *card; - ECardSimple *simple; PASBackendSummaryItem *new_item; - card = e_card_new ((char*)vcard); - simple = e_card_simple_new (card); - - new_item = g_new (PASBackendSummaryItem, 1); - - new_item->id = g_strdup (e_card_simple_get_id (simple)); - new_item->nickname = e_card_simple_get (simple, E_CARD_SIMPLE_FIELD_NICKNAME); - new_item->full_name = e_card_simple_get (simple, E_CARD_SIMPLE_FIELD_FULL_NAME); - new_item->given_name = e_card_simple_get (simple, E_CARD_SIMPLE_FIELD_GIVEN_NAME); - new_item->surname = e_card_simple_get (simple, E_CARD_SIMPLE_FIELD_FAMILY_NAME); - new_item->file_as = e_card_simple_get (simple, E_CARD_SIMPLE_FIELD_FILE_AS); - new_item->email_1 = e_card_simple_get (simple, E_CARD_SIMPLE_FIELD_EMAIL); - new_item->email_2 = e_card_simple_get (simple, E_CARD_SIMPLE_FIELD_EMAIL_2); - new_item->email_3 = e_card_simple_get (simple, E_CARD_SIMPLE_FIELD_EMAIL_3); - new_item->list = e_card_evolution_list (card); - new_item->list_show_addresses = e_card_evolution_list_show_addresses (card); - new_item->wants_html = card->wants_html; - new_item->wants_html_set = card->wants_html_set; + new_item = g_new0 (PASBackendSummaryItem, 1); + + new_item->id = e_contact_get (contact, E_CONTACT_UID); + new_item->nickname = e_contact_get (contact, E_CONTACT_NICKNAME); + new_item->full_name = e_contact_get (contact, E_CONTACT_FULL_NAME); + new_item->given_name = e_contact_get (contact, E_CONTACT_GIVEN_NAME); + new_item->surname = e_contact_get (contact, E_CONTACT_FAMILY_NAME); + new_item->file_as = e_contact_get (contact, E_CONTACT_FILE_AS); + new_item->email_1 = e_contact_get (contact, E_CONTACT_EMAIL_1); + new_item->email_2 = e_contact_get (contact, E_CONTACT_EMAIL_2); + new_item->email_3 = e_contact_get (contact, E_CONTACT_EMAIL_3); + new_item->list = GPOINTER_TO_INT (e_contact_get (contact, E_CONTACT_IS_LIST)); + new_item->list_show_addresses = GPOINTER_TO_INT (e_contact_get (contact, E_CONTACT_LIST_SHOW_ADDRESSES)); + new_item->wants_html = GPOINTER_TO_INT (e_contact_get (contact, E_CONTACT_WANTS_HTML)); g_ptr_array_add (summary->priv->items, new_item); g_hash_table_insert (summary->priv->id_to_item, new_item->id, new_item); - g_object_unref (simple); - g_object_unref (card); + g_object_unref (contact); #ifdef SUMMARY_STATS summary->priv->size += sizeof (PASBackendSummaryItem); @@ -736,7 +729,7 @@ pas_backend_summary_add_card (PASBackendSummary *summary, const char *vcard) } void -pas_backend_summary_remove_card (PASBackendSummary *summary, const char *id) +pas_backend_summary_remove_contact (PASBackendSummary *summary, const char *id) { PASBackendSummaryItem *item = g_hash_table_lookup (summary->priv->id_to_item, id); @@ -748,7 +741,7 @@ pas_backend_summary_remove_card (PASBackendSummary *summary, const char *id) return; } - g_warning ("pas_backend_summary_remove_card: unable to locate id `%s'", id); + g_warning ("pas_backend_summary_remove_contact: unable to locate id `%s'", id); } static gboolean @@ -1056,31 +1049,26 @@ 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); + EContact *contact = e_contact_new (); 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 (simple, E_CARD_SIMPLE_FIELD_FULL_NAME, item->full_name); - 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_contact_set (contact, E_CONTACT_UID, item->id); + e_contact_set (contact, E_CONTACT_FILE_AS, item->file_as); + e_contact_set (contact, E_CONTACT_GIVEN_NAME, item->given_name); + e_contact_set (contact, E_CONTACT_FAMILY_NAME, item->surname); + e_contact_set (contact, E_CONTACT_NICKNAME, item->nickname); + e_contact_set (contact, E_CONTACT_FULL_NAME, item->full_name); + e_contact_set (contact, E_CONTACT_EMAIL_1, item->email_1); + e_contact_set (contact, E_CONTACT_EMAIL_2, item->email_2); + e_contact_set (contact, E_CONTACT_EMAIL_3, item->email_3); - e_card_simple_sync_card (simple); + e_contact_set (contact, E_CONTACT_IS_LIST, GINT_TO_POINTER (item->list)); + e_contact_set (contact, E_CONTACT_LIST_SHOW_ADDRESSES, GINT_TO_POINTER (item->list_show_addresses)); + e_contact_set (contact, E_CONTACT_WANTS_HTML, GINT_TO_POINTER (item->wants_html)); - card->list = item->list; - card->wants_html = item->wants_html; - card->wants_html_set = item->wants_html_set; - card->list_show_addresses = item->list_show_addresses; + vcard = e_vcard_to_string (E_VCARD (contact), EVC_FORMAT_VCARD_30); - vcard = e_card_simple_get_vcard (simple); - - g_object_unref (simple); - g_object_unref (card); + g_object_unref (contact); return vcard; } diff --git a/addressbook/backend/pas/pas-backend-summary.h b/addressbook/backend/pas/pas-backend-summary.h index 54083855d5..bb07e0fb27 100644 --- a/addressbook/backend/pas/pas-backend-summary.h +++ b/addressbook/backend/pas/pas-backend-summary.h @@ -26,6 +26,8 @@ #include #include +#include +#include #define PAS_TYPE_BACKEND_SUMMARY (pas_backend_summary_get_type ()) #define PAS_BACKEND_SUMMARY(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), PAS_TYPE_BACKEND_SUMMARY, PASBackendSummary)) @@ -36,14 +38,14 @@ typedef struct _PASBackendSummaryPrivate PASBackendSummaryPrivate; -typedef struct { +struct _PASBackendSummary{ GObject parent_object; PASBackendSummaryPrivate *priv; -} PASBackendSummary; +}; -typedef struct { +struct _PASBackendSummaryClass{ GObjectClass parent_class; -} PASBackendSummaryClass; +}; PASBackendSummary* pas_backend_summary_new (const char *summary_path, int flush_timeout_millis); @@ -55,8 +57,8 @@ gboolean pas_backend_summary_load (PASBackendSummary *summ /* 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); -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_contact (PASBackendSummary *summary, EContact *contact); +void pas_backend_summary_remove_contact (PASBackendSummary *summary, const char *id); void pas_backend_summary_touch (PASBackendSummary *summary); diff --git a/addressbook/backend/pas/pas-backend-sync.c b/addressbook/backend/pas/pas-backend-sync.c new file mode 100644 index 0000000000..45063eddc6 --- /dev/null +++ b/addressbook/backend/pas/pas-backend-sync.c @@ -0,0 +1,395 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ +/* + * Author: + * Chris Toshok (toshok@ximian.com) + * + * Copyright (C) 2003, Ximian, Inc. + */ + +#include +#include "pas-backend-sync.h" +#include "pas-marshal.h" + +struct _PASBackendSyncPrivate { + int mumble; +}; + +static GObjectClass *parent_class; + +gboolean +pas_backend_sync_construct (PASBackendSync *backend) +{ + return TRUE; +} + +PASBackendSyncStatus +pas_backend_sync_create_contact (PASBackendSync *backend, + PASBook *book, + const char *vcard, + EContact **contact) +{ + g_return_val_if_fail (backend && PAS_IS_BACKEND_SYNC (backend), GNOME_Evolution_Addressbook_OtherError); + g_return_val_if_fail (book && PAS_IS_BOOK (book), GNOME_Evolution_Addressbook_OtherError); + g_return_val_if_fail (vcard, GNOME_Evolution_Addressbook_OtherError); + g_return_val_if_fail (contact, GNOME_Evolution_Addressbook_OtherError); + + g_assert (PAS_BACKEND_SYNC_GET_CLASS (backend)->create_contact_sync); + + return (* PAS_BACKEND_SYNC_GET_CLASS (backend)->create_contact_sync) (backend, book, vcard, contact); +} + +PASBackendSyncStatus +pas_backend_sync_remove (PASBackendSync *backend, + PASBook *book) +{ + g_return_val_if_fail (backend && PAS_IS_BACKEND_SYNC (backend), GNOME_Evolution_Addressbook_OtherError); + g_return_val_if_fail (book && PAS_IS_BOOK (book), GNOME_Evolution_Addressbook_OtherError); + + g_assert (PAS_BACKEND_SYNC_GET_CLASS (backend)->remove_sync); + + return (* PAS_BACKEND_SYNC_GET_CLASS (backend)->remove_sync) (backend, book); +} + +PASBackendSyncStatus +pas_backend_sync_remove_contacts (PASBackendSync *backend, + PASBook *book, + GList *id_list, + GList **removed_ids) +{ + g_return_val_if_fail (backend && PAS_IS_BACKEND_SYNC (backend), GNOME_Evolution_Addressbook_OtherError); + g_return_val_if_fail (book && PAS_IS_BOOK (book), GNOME_Evolution_Addressbook_OtherError); + g_return_val_if_fail (id_list, GNOME_Evolution_Addressbook_OtherError); + g_return_val_if_fail (removed_ids, GNOME_Evolution_Addressbook_OtherError); + + g_assert (PAS_BACKEND_SYNC_GET_CLASS (backend)->remove_contacts_sync); + + return (* PAS_BACKEND_SYNC_GET_CLASS (backend)->remove_contacts_sync) (backend, book, id_list, removed_ids); +} + +PASBackendSyncStatus +pas_backend_sync_modify_contact (PASBackendSync *backend, + PASBook *book, + const char *vcard, + EContact **contact) +{ + g_return_val_if_fail (backend && PAS_IS_BACKEND_SYNC (backend), GNOME_Evolution_Addressbook_OtherError); + g_return_val_if_fail (book && PAS_IS_BOOK (book), GNOME_Evolution_Addressbook_OtherError); + g_return_val_if_fail (vcard, GNOME_Evolution_Addressbook_OtherError); + g_return_val_if_fail (contact, GNOME_Evolution_Addressbook_OtherError); + + g_assert (PAS_BACKEND_SYNC_GET_CLASS (backend)->modify_contact_sync); + + return (* PAS_BACKEND_SYNC_GET_CLASS (backend)->modify_contact_sync) (backend, book, vcard, contact); +} + +PASBackendSyncStatus +pas_backend_sync_get_contact (PASBackendSync *backend, + PASBook *book, + const char *id, + char **vcard) +{ + g_return_val_if_fail (backend && PAS_IS_BACKEND_SYNC (backend), GNOME_Evolution_Addressbook_OtherError); + g_return_val_if_fail (book && PAS_IS_BOOK (book), GNOME_Evolution_Addressbook_OtherError); + g_return_val_if_fail (id, GNOME_Evolution_Addressbook_OtherError); + g_return_val_if_fail (vcard, GNOME_Evolution_Addressbook_OtherError); + + g_assert (PAS_BACKEND_SYNC_GET_CLASS (backend)->get_contact_sync); + + return (* PAS_BACKEND_SYNC_GET_CLASS (backend)->get_contact_sync) (backend, book, id, vcard); +} + +PASBackendSyncStatus +pas_backend_sync_get_contact_list (PASBackendSync *backend, + PASBook *book, + const char *query, + GList **contacts) +{ + g_return_val_if_fail (backend && PAS_IS_BACKEND_SYNC (backend), GNOME_Evolution_Addressbook_OtherError); + g_return_val_if_fail (book && PAS_IS_BOOK (book), GNOME_Evolution_Addressbook_OtherError); + g_return_val_if_fail (query, GNOME_Evolution_Addressbook_OtherError); + g_return_val_if_fail (contacts, GNOME_Evolution_Addressbook_OtherError); + + g_assert (PAS_BACKEND_SYNC_GET_CLASS (backend)->get_contact_list_sync); + + return (* PAS_BACKEND_SYNC_GET_CLASS (backend)->get_contact_list_sync) (backend, book, query, contacts); +} + +PASBackendSyncStatus +pas_backend_sync_get_changes (PASBackendSync *backend, + PASBook *book, + const char *change_id, + GList **changes) +{ + g_return_val_if_fail (backend && PAS_IS_BACKEND_SYNC (backend), GNOME_Evolution_Addressbook_OtherError); + g_return_val_if_fail (book && PAS_IS_BOOK (book), GNOME_Evolution_Addressbook_OtherError); + g_return_val_if_fail (change_id, GNOME_Evolution_Addressbook_OtherError); + g_return_val_if_fail (changes, GNOME_Evolution_Addressbook_OtherError); + + g_assert (PAS_BACKEND_SYNC_GET_CLASS (backend)->get_changes_sync); + + return (* PAS_BACKEND_SYNC_GET_CLASS (backend)->get_changes_sync) (backend, book, change_id, changes); +} + +PASBackendSyncStatus +pas_backend_sync_authenticate_user (PASBackendSync *backend, + PASBook *book, + const char *user, + const char *passwd, + const char *auth_method) +{ + g_return_val_if_fail (backend && PAS_IS_BACKEND_SYNC (backend), GNOME_Evolution_Addressbook_OtherError); + g_return_val_if_fail (book && PAS_IS_BOOK (book), GNOME_Evolution_Addressbook_OtherError); + g_return_val_if_fail (user && passwd && auth_method, GNOME_Evolution_Addressbook_OtherError); + + g_assert (PAS_BACKEND_SYNC_GET_CLASS (backend)->authenticate_user_sync); + + return (* PAS_BACKEND_SYNC_GET_CLASS (backend)->authenticate_user_sync) (backend, book, user, passwd, auth_method); +} + +PASBackendSyncStatus +pas_backend_sync_get_supported_fields (PASBackendSync *backend, + PASBook *book, + GList **fields) +{ + g_return_val_if_fail (backend && PAS_IS_BACKEND_SYNC (backend), GNOME_Evolution_Addressbook_OtherError); + g_return_val_if_fail (book && PAS_IS_BOOK (book), GNOME_Evolution_Addressbook_OtherError); + g_return_val_if_fail (fields, GNOME_Evolution_Addressbook_OtherError); + + g_assert (PAS_BACKEND_SYNC_GET_CLASS (backend)->get_supported_fields_sync); + + return (* PAS_BACKEND_SYNC_GET_CLASS (backend)->get_supported_fields_sync) (backend, book, fields); +} + +PASBackendSyncStatus +pas_backend_sync_get_supported_auth_methods (PASBackendSync *backend, + PASBook *book, + GList **methods) +{ + g_return_val_if_fail (backend && PAS_IS_BACKEND_SYNC (backend), GNOME_Evolution_Addressbook_OtherError); + g_return_val_if_fail (book && PAS_IS_BOOK (book), GNOME_Evolution_Addressbook_OtherError); + g_return_val_if_fail (methods, GNOME_Evolution_Addressbook_OtherError); + + g_assert (PAS_BACKEND_SYNC_GET_CLASS (backend)->get_supported_auth_methods_sync); + + return (* PAS_BACKEND_SYNC_GET_CLASS (backend)->get_supported_auth_methods_sync) (backend, book, methods); +} + +static void +_pas_backend_remove (PASBackend *backend, + PASBook *book) +{ + PASBackendSyncStatus status; + + status = pas_backend_sync_remove (PAS_BACKEND_SYNC (backend), book); + + pas_book_respond_remove (book, status); +} + +static void +_pas_backend_create_contact (PASBackend *backend, + PASBook *book, + const char *vcard) +{ + PASBackendSyncStatus status; + EContact *contact; + + status = pas_backend_sync_create_contact (PAS_BACKEND_SYNC (backend), book, vcard, &contact); + + pas_book_respond_create (book, status, contact); + + g_object_unref (contact); +} + +static void +_pas_backend_remove_contacts (PASBackend *backend, + PASBook *book, + GList *id_list) +{ + PASBackendSyncStatus status; + GList *ids = NULL; + + status = pas_backend_sync_remove_contacts (PAS_BACKEND_SYNC (backend), book, id_list, &ids); + + pas_book_respond_remove_contacts (book, status, ids); + + g_list_free (ids); +} + +static void +_pas_backend_modify_contact (PASBackend *backend, + PASBook *book, + const char *vcard) +{ + PASBackendSyncStatus status; + EContact *contact; + + status = pas_backend_sync_modify_contact (PAS_BACKEND_SYNC (backend), book, vcard, &contact); + + pas_book_respond_modify (book, status, contact); + + g_object_unref (contact); +} + +static void +_pas_backend_get_contact (PASBackend *backend, + PASBook *book, + const char *id) +{ + PASBackendSyncStatus status; + char *vcard; + + status = pas_backend_sync_get_contact (PAS_BACKEND_SYNC (backend), book, id, &vcard); + + pas_book_respond_get_contact (book, status, vcard); + + g_free (vcard); +} + +static void +_pas_backend_get_contact_list (PASBackend *backend, + PASBook *book, + const char *query) +{ + PASBackendSyncStatus status; + GList *cards = NULL; + + status = pas_backend_sync_get_contact_list (PAS_BACKEND_SYNC (backend), book, query, &cards); + + pas_book_respond_get_contact_list (book, status, cards); +} + +static void +_pas_backend_get_changes (PASBackend *backend, + PASBook *book, + const char *change_id) +{ + PASBackendSyncStatus status; + GList *changes = NULL; + + status = pas_backend_sync_get_changes (PAS_BACKEND_SYNC (backend), book, change_id, &changes); + + pas_book_respond_get_changes (book, status, changes); + + /* XXX free view? */ +} + +static void +_pas_backend_authenticate_user (PASBackend *backend, + PASBook *book, + const char *user, + const char *passwd, + const char *auth_method) +{ + PASBackendSyncStatus status; + + status = pas_backend_sync_authenticate_user (PAS_BACKEND_SYNC (backend), book, user, passwd, auth_method); + + pas_book_respond_authenticate_user (book, status); +} + +static void +_pas_backend_get_supported_fields (PASBackend *backend, + PASBook *book) +{ + PASBackendSyncStatus status; + GList *fields = NULL; + + status = pas_backend_sync_get_supported_fields (PAS_BACKEND_SYNC (backend), book, &fields); + + pas_book_respond_get_supported_fields (book, status, fields); + + g_list_foreach (fields, (GFunc)g_free, NULL); + g_list_free (fields); +} + +static void +_pas_backend_get_supported_auth_methods (PASBackend *backend, + PASBook *book) +{ + PASBackendSyncStatus status; + GList *methods = NULL; + + status = pas_backend_sync_get_supported_auth_methods (PAS_BACKEND_SYNC (backend), book, &methods); + + pas_book_respond_get_supported_auth_methods (book, status, methods); + + g_list_foreach (methods, (GFunc)g_free, NULL); + g_list_free (methods); +} + +static void +pas_backend_sync_init (PASBackendSync *backend) +{ + PASBackendSyncPrivate *priv; + + priv = g_new0 (PASBackendSyncPrivate, 1); + + backend->priv = priv; +} + +static void +pas_backend_sync_dispose (GObject *object) +{ + PASBackendSync *backend; + + backend = PAS_BACKEND_SYNC (object); + + if (backend->priv) { + g_free (backend->priv); + + backend->priv = NULL; + } + + G_OBJECT_CLASS (parent_class)->dispose (object); +} + +static void +pas_backend_sync_class_init (PASBackendSyncClass *klass) +{ + GObjectClass *object_class; + PASBackendClass *backend_class = PAS_BACKEND_CLASS (klass); + + parent_class = g_type_class_peek_parent (klass); + + object_class = (GObjectClass *) klass; + + backend_class->remove = _pas_backend_remove; + backend_class->create_contact = _pas_backend_create_contact; + backend_class->remove_contacts = _pas_backend_remove_contacts; + backend_class->modify_contact = _pas_backend_modify_contact; + backend_class->get_contact = _pas_backend_get_contact; + backend_class->get_contact_list = _pas_backend_get_contact_list; + backend_class->get_changes = _pas_backend_get_changes; + backend_class->authenticate_user = _pas_backend_authenticate_user; + backend_class->get_supported_fields = _pas_backend_get_supported_fields; + backend_class->get_supported_auth_methods = _pas_backend_get_supported_auth_methods; + + object_class->dispose = pas_backend_sync_dispose; +} + +/** + * pas_backend_get_type: + */ +GType +pas_backend_sync_get_type (void) +{ + static GType type = 0; + + if (! type) { + GTypeInfo info = { + sizeof (PASBackendSyncClass), + NULL, /* base_class_init */ + NULL, /* base_class_finalize */ + (GClassInitFunc) pas_backend_sync_class_init, + NULL, /* class_finalize */ + NULL, /* class_data */ + sizeof (PASBackendSync), + 0, /* n_preallocs */ + (GInstanceInitFunc) pas_backend_sync_init + }; + + type = g_type_register_static (PAS_TYPE_BACKEND, "PASBackendSync", &info, 0); + } + + return type; +} diff --git a/addressbook/backend/pas/pas-backend-sync.h b/addressbook/backend/pas/pas-backend-sync.h new file mode 100644 index 0000000000..2e176d9f5d --- /dev/null +++ b/addressbook/backend/pas/pas-backend-sync.h @@ -0,0 +1,81 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ +/* + */ + +#ifndef __PAS_BACKEND_SYNC_H__ +#define __PAS_BACKEND_SYNC_H__ + +#include +#include +#include +#include + +#define PAS_TYPE_BACKEND_SYNC (pas_backend_sync_get_type ()) +#define PAS_BACKEND_SYNC(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), PAS_TYPE_BACKEND_SYNC, PASBackendSync)) +#define PAS_BACKEND_SYNC_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), PAS_TYPE_BACKEND_SYNC, PASBackendSyncClass)) +#define PAS_IS_BACKEND_SYNC(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), PAS_TYPE_BACKEND_SYNC)) +#define PAS_IS_BACKEND_SYNC_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), PAS_TYPE_BACKEND_SYNC)) +#define PAS_BACKEND_SYNC_GET_CLASS(k) (G_TYPE_INSTANCE_GET_CLASS ((k), PAS_TYPE_BACKEND_SYNC, PASBackendSyncClass)) + +typedef struct _PASBackendSyncPrivate PASBackendSyncPrivate; + +typedef GNOME_Evolution_Addressbook_CallStatus PASBackendSyncStatus; + +struct _PASBackendSync { + PASBackend parent_object; + PASBackendSyncPrivate *priv; +}; + +struct _PASBackendSyncClass { + PASBackendClass parent_class; + + /* Virtual methods */ + PASBackendSyncStatus (*remove_sync) (PASBackendSync *backend, PASBook *book); + PASBackendSyncStatus (*create_contact_sync) (PASBackendSync *backend, PASBook *book, + const char *vcard, EContact **contact); + PASBackendSyncStatus (*remove_contacts_sync) (PASBackendSync *backend, PASBook *book, + GList *id_list, GList **removed_ids); + PASBackendSyncStatus (*modify_contact_sync) (PASBackendSync *backend, PASBook *book, + const char *vcard, EContact **contact); + PASBackendSyncStatus (*get_contact_sync) (PASBackendSync *backend, PASBook *book, + const char *id, char **vcard); + PASBackendSyncStatus (*get_contact_list_sync) (PASBackendSync *backend, PASBook *book, + const char *query, GList **contacts); + PASBackendSyncStatus (*get_changes_sync) (PASBackendSync *backend, PASBook *book, + const char *change_id, GList **changes); + PASBackendSyncStatus (*authenticate_user_sync) (PASBackendSync *backend, PASBook *book, + const char *user, + const char *passwd, + const char *auth_method); + PASBackendSyncStatus (*get_supported_fields_sync) (PASBackendSync *backend, PASBook *book, + GList **fields); + PASBackendSyncStatus (*get_supported_auth_methods_sync) (PASBackendSync *backend, PASBook *book, + GList **methods); + + /* Padding for future expansion */ + void (*_pas_reserved0) (void); + void (*_pas_reserved1) (void); + void (*_pas_reserved2) (void); + void (*_pas_reserved3) (void); + void (*_pas_reserved4) (void); + +}; + +typedef PASBackendSync * (*PASBackendSyncFactoryFn) (void); + +gboolean pas_backend_sync_construct (PASBackendSync *backend); + +GType pas_backend_sync_get_type (void); + +PASBackendSyncStatus pas_backend_sync_remove (PASBackendSync *backend, PASBook *book); +PASBackendSyncStatus pas_backend_sync_create_contact (PASBackendSync *backend, PASBook *book, const char *vcard, EContact **contact); +PASBackendSyncStatus pas_backend_sync_remove_contacts (PASBackendSync *backend, PASBook *book, GList *id_list, GList **removed_ids); +PASBackendSyncStatus pas_backend_sync_modify_contact (PASBackendSync *backend, PASBook *book, const char *vcard, EContact **contact); +PASBackendSyncStatus pas_backend_sync_get_contact (PASBackendSync *backend, PASBook *book, const char *id, char **vcard); +PASBackendSyncStatus pas_backend_sync_get_contact_list (PASBackendSync *backend, PASBook *book, const char *query, GList **contacts); +PASBackendSyncStatus pas_backend_sync_get_changes (PASBackendSync *backend, PASBook *book, const char *change_id, GList **changes); +PASBackendSyncStatus pas_backend_sync_authenticate_user (PASBackendSync *backend, PASBook *book, const char *user, const char *passwd, const char *auth_method); +PASBackendSyncStatus pas_backend_sync_get_supported_fields (PASBackendSync *backend, PASBook *book, GList **fields); +PASBackendSyncStatus pas_backend_sync_get_supported_auth_methods (PASBackendSync *backend, PASBook *book, GList **methods); + +#endif /* ! __PAS_BACKEND_SYNC_H__ */ diff --git a/addressbook/backend/pas/pas-backend-vcf.c b/addressbook/backend/pas/pas-backend-vcf.c new file mode 100644 index 0000000000..3765fd978e --- /dev/null +++ b/addressbook/backend/pas/pas-backend-vcf.c @@ -0,0 +1,632 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ +/* + * Author: + * Chris Toshok (toshok@ximian.com) + * + * Copyright (C) 2003, Ximian, Inc. + */ + +#include "config.h" +#include "pas-backend-vcf.h" +#include "pas-backend-card-sexp.h" +#include "pas-book.h" +#include "pas-book-view.h" + +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include +#include + +#define PAS_ID_PREFIX "pas-id-" +#define FILE_FLUSH_TIMEOUT 5000 + +static PASBackendSyncClass *pas_backend_vcf_parent_class; +typedef struct _PASBackendVCFBookView PASBackendVCFBookView; +typedef struct _PASBackendVCFSearchContext PASBackendVCFSearchContext; + +struct _PASBackendVCFPrivate { + char *uri; + char *filename; + GHashTable *contacts; + gboolean dirty; + int flush_timeout_tag; +}; + +static char * +pas_backend_vcf_create_unique_id () +{ + /* 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 + should be okay. */ + static guint c = 0; + return g_strdup_printf (PAS_ID_PREFIX "%08lX%08X", time(NULL), c++); +} + +typedef struct { + PASBackendVCF *bvcf; + PASBook *book; + PASBookView *view; +} VCFBackendSearchClosure; + +static void +free_search_closure (VCFBackendSearchClosure *closure) +{ + g_free (closure); +} + +static void +foreach_search_compare (char *id, char *vcard_string, VCFBackendSearchClosure *closure) +{ + EContact *contact; + + contact = e_contact_new_from_vcard (vcard_string); + pas_book_view_notify_update (closure->view, contact); + g_object_unref (contact); +} + +static gboolean +pas_backend_vcf_search_timeout (gpointer data) +{ + VCFBackendSearchClosure *closure = data; + + g_hash_table_foreach (closure->bvcf->priv->contacts, + (GHFunc)foreach_search_compare, + closure); + + pas_book_view_notify_complete (closure->view, GNOME_Evolution_Addressbook_Success); + + free_search_closure (closure); + + return FALSE; +} + + +static void +pas_backend_vcf_search (PASBackendVCF *bvcf, + PASBookView *book_view) +{ + const char *query = pas_book_view_get_card_query (book_view); + VCFBackendSearchClosure *closure = g_new0 (VCFBackendSearchClosure, 1); + + if ( ! strcmp (query, "(contains \"x-evolution-any-field\" \"\")")) + pas_book_view_notify_status_message (book_view, _("Loading...")); + else + pas_book_view_notify_status_message (book_view, _("Searching...")); + + closure->view = book_view; + closure->bvcf = bvcf; + + g_idle_add (pas_backend_vcf_search_timeout, closure); +} + +static void +insert_contact (PASBackendVCF *vcf, char *vcard) +{ + EContact *contact = e_contact_new_from_vcard (vcard); + char *id; + + id = e_contact_get (contact, E_CONTACT_UID); + if (id) + g_hash_table_insert (vcf->priv->contacts, + id, + e_vcard_to_string (E_VCARD (contact), EVC_FORMAT_VCARD_30)); +} + +static void +load_file (PASBackendVCF *vcf) +{ + FILE *fp; + GString *str; + char buf[1024]; + + fp = fopen (vcf->priv->filename, "r"); + if (!fp) { + g_warning ("failed to open `%s' for reading", vcf->priv->filename); + return; + } + + str = g_string_new (""); + + while (fgets (buf, sizeof (buf), fp)) { + if (!strcmp (buf, "\r\n")) { + /* if the string has accumulated some stuff, create a contact for it and start over */ + if (str->len) { + insert_contact (vcf, str->str); + g_string_assign (str, ""); + } + } + else { + g_string_append (str, buf); + } + } + if (str->len) { + insert_contact (vcf, str->str); + } + + g_string_free (str, TRUE); + + fclose (fp); +} + +static void +foreach_build_list (char *id, char *vcard_string, GList **list) +{ + *list = g_list_append (*list, e_contact_new_from_vcard (vcard_string)); +} + +static gboolean +save_file (PASBackendVCF *vcf) +{ + GList *contacts = NULL; + GList *l; + char *new_path; + int fd, rv; + + g_hash_table_foreach (vcf->priv->contacts, (GHFunc)foreach_build_list, &contacts); + + new_path = g_strdup_printf ("%s.new", vcf->priv->filename); + + fd = open (new_path, O_CREAT | O_TRUNC | O_WRONLY, 0666); + + for (l = contacts; l; l = l->next) { + EContact *contact = l->data; + char *vcard_str = e_vcard_to_string (E_VCARD (contact), EVC_FORMAT_VCARD_30); + int len = strlen (vcard_str); + + rv = write (fd, vcard_str, len); + g_free (vcard_str); + if (rv < len) { + /* XXX */ + g_warning ("write failed. we need to handle short writes\n"); + close (fd); + unlink (new_path); + return FALSE; + } + + rv = write (fd, "\r\n", 2); + if (rv < 2) { + /* XXX */ + g_warning ("write failed. we need to handle short writes\n"); + close (fd); + unlink (new_path); + return FALSE; + } + } + + if (0 > rename (new_path, vcf->priv->filename)) { + g_warning ("Failed to rename %s: %s\n", vcf->priv->filename, strerror(errno)); + unlink (new_path); + return FALSE; + } + + g_list_foreach (contacts, (GFunc)g_object_unref, NULL); + g_list_free (contacts); + g_free (new_path); + + vcf->priv->dirty = FALSE; + + return TRUE; +} + +static gboolean +vcf_flush_file (gpointer data) +{ + PASBackendVCF *bvcf = PAS_BACKEND_VCF (data); + + if (!bvcf->priv->dirty) { + bvcf->priv->flush_timeout_tag = 0; + return FALSE; + } + + if (!save_file (bvcf)) { + g_warning ("failed to flush the .vcf file to disk, will try again next timeout"); + return TRUE; + } + + bvcf->priv->flush_timeout_tag = 0; + return FALSE; +} + +static EContact * +do_create(PASBackendVCF *bvcf, + const char *vcard_req, + gboolean dirty_the_file) +{ + char *id; + EContact *contact; + char *vcard; + + id = pas_backend_vcf_create_unique_id (); + + 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); + + g_hash_table_insert (bvcf->priv->contacts, id, vcard); + + if (dirty_the_file) { + bvcf->priv->dirty = TRUE; + + if (!bvcf->priv->flush_timeout_tag) + bvcf->priv->flush_timeout_tag = g_timeout_add (FILE_FLUSH_TIMEOUT, + vcf_flush_file, bvcf); + } + + return contact; +} + +static PASBackendSyncStatus +pas_backend_vcf_process_create_contact (PASBackendSync *backend, + PASBook *book, + const char *vcard, + EContact **contact) +{ + PASBackendVCF *bvcf = PAS_BACKEND_VCF (backend); + + *contact = do_create(bvcf, vcard, TRUE); + if (*contact) { + return GNOME_Evolution_Addressbook_Success; + } + else { + /* XXX need a different call status for this case, i + think */ + return GNOME_Evolution_Addressbook_ContactNotFound; + } +} + +static PASBackendSyncStatus +pas_backend_vcf_process_remove_contacts (PASBackendSync *backend, + PASBook *book, + GList *id_list, + GList **ids) +{ + /* FIXME: make this handle bulk deletes like the file backend does */ + PASBackendVCF *bvcf = PAS_BACKEND_VCF (backend); + char *id = id_list->data; + + if (!g_hash_table_remove (bvcf->priv->contacts, id)) { + return GNOME_Evolution_Addressbook_ContactNotFound; + } + else { + bvcf->priv->dirty = TRUE; + if (!bvcf->priv->flush_timeout_tag) + bvcf->priv->flush_timeout_tag = g_timeout_add (FILE_FLUSH_TIMEOUT, + vcf_flush_file, bvcf); + + *ids = g_list_append (*ids, id); + + return GNOME_Evolution_Addressbook_Success; + } +} + +static PASBackendSyncStatus +pas_backend_vcf_process_modify_contact (PASBackendSync *backend, + PASBook *book, + const char *vcard, + EContact **contact) +{ + PASBackendVCF *bvcf = PAS_BACKEND_VCF (backend); + char *old_id, *old_vcard_string; + const char *id; + + /* create a new ecard from the request data */ + *contact = e_contact_new_from_vcard (vcard); + id = e_contact_get_const (*contact, E_CONTACT_UID); + + if (!g_hash_table_lookup_extended (bvcf->priv->contacts, id, (gpointer)&old_id, (gpointer)&old_vcard_string)) { + return GNOME_Evolution_Addressbook_ContactNotFound; + } + else { + g_hash_table_insert (bvcf->priv->contacts, old_id, g_strdup (vcard)); + + g_free (old_vcard_string); + + return GNOME_Evolution_Addressbook_Success; + } +} + +static PASBackendSyncStatus +pas_backend_vcf_process_get_contact (PASBackendSync *backend, + PASBook *book, + const char *id, + char **vcard) +{ + PASBackendVCF *bvcf = PAS_BACKEND_VCF (backend); + char *v; + + v = g_hash_table_lookup (bvcf->priv->contacts, id); + + if (v) { + *vcard = g_strdup (v); + return GNOME_Evolution_Addressbook_Success; + } else { + *vcard = g_strdup (""); + return GNOME_Evolution_Addressbook_ContactNotFound; + } +} + + +typedef struct { + PASBackendVCF *bvcf; + gboolean search_needed; + PASBackendCardSExp *card_sexp; + GList *list; +} GetContactListClosure; + +static void +foreach_get_contact_compare (char *id, char *vcard_string, GetContactListClosure *closure) +{ + if ((!closure->search_needed) || pas_backend_card_sexp_match_vcard (closure->card_sexp, vcard_string)) { + closure->list = g_list_append (closure->list, g_strdup (vcard_string)); + } +} + +static PASBackendSyncStatus +pas_backend_vcf_process_get_contact_list (PASBackendSync *backend, + PASBook *book, + const char *query, + GList **contacts) +{ + PASBackendVCF *bvcf = PAS_BACKEND_VCF (backend); + const char *search = query; + GetContactListClosure closure; + + closure.bvcf = bvcf; + closure.search_needed = strcmp (search, "(contains \"x-evolution-any-field\" \"\")"); + closure.card_sexp = pas_backend_card_sexp_new (search); + closure.list = NULL; + + g_hash_table_foreach (bvcf->priv->contacts, (GHFunc)foreach_get_contact_compare, &closure); + + g_object_unref (closure.card_sexp); + + *contacts = closure.list; + return GNOME_Evolution_Addressbook_Success; +} + +static void +pas_backend_vcf_start_book_view (PASBackend *backend, + PASBookView *book_view) +{ + pas_backend_vcf_search (PAS_BACKEND_VCF (backend), book_view); +} + +static char * +pas_backend_vcf_extract_path_from_uri (const char *uri) +{ + g_assert (strncasecmp (uri, "vcf://", 6) == 0); + + return g_strdup (uri + 6); +} + +static PASBackendSyncStatus +pas_backend_vcf_process_authenticate_user (PASBackendSync *backend, + PASBook *book, + const char *user, + const char *passwd, + const char *auth_method) +{ + return GNOME_Evolution_Addressbook_Success; +} + +static PASBackendSyncStatus +pas_backend_vcf_process_get_supported_fields (PASBackendSync *backend, + PASBook *book, + GList **fields_out) +{ + GList *fields = NULL; + int i; + + /* XXX we need a way to say "we support everything", since the + vcf backend does */ + for (i = 0; i < E_CONTACT_FIELD_LAST; i ++) + fields = g_list_append (fields, (char*)e_contact_field_name (i)); + + *fields_out = fields; + return GNOME_Evolution_Addressbook_Success; +} + +#include "ximian-vcard.h" + +static GNOME_Evolution_Addressbook_CallStatus +pas_backend_vcf_load_uri (PASBackend *backend, + const char *uri, + gboolean only_if_exists) +{ + PASBackendVCF *bvcf = PAS_BACKEND_VCF (backend); + char *filename; + gboolean writable = FALSE; + int fd; + + g_free(bvcf->priv->uri); + bvcf->priv->uri = g_strdup (uri); + + bvcf->priv->filename = filename = pas_backend_vcf_extract_path_from_uri (uri); + + fd = open (filename, O_RDWR); + + bvcf->priv->contacts = g_hash_table_new_full (g_str_hash, g_str_equal, + g_free, g_free); + + if (fd != -1) { + writable = TRUE; + } else { + fd = open (filename, O_RDONLY); + + if (fd == -1) { + fd = open (filename, O_CREAT, 0666); + + if (fd != -1 && !only_if_exists) { + EContact *contact; + + contact = do_create(bvcf, XIMIAN_VCARD, FALSE); + save_file (bvcf); + + /* XXX check errors here */ + g_object_unref (contact); + + writable = TRUE; + } + } + } + + if (fd == -1) { + g_warning ("Failed to open addressbook at uri `%s'", uri); + g_warning ("error == %s", strerror(errno)); + return GNOME_Evolution_Addressbook_OtherError; + } + + close (fd); /* XXX ugh */ + load_file (bvcf); + + pas_backend_set_is_loaded (backend, TRUE); + pas_backend_set_is_writable (backend, writable); + + return GNOME_Evolution_Addressbook_Success; +} + +static char * +pas_backend_vcf_get_static_capabilities (PASBackend *backend) +{ + return g_strdup("local,do-initial-query"); +} + +static GNOME_Evolution_Addressbook_CallStatus +pas_backend_vcf_cancel_operation (PASBackend *backend, PASBook *book) +{ + return GNOME_Evolution_Addressbook_CouldNotCancel; +} + +static gboolean +pas_backend_vcf_construct (PASBackendVCF *backend) +{ + g_assert (backend != NULL); + g_assert (PAS_IS_BACKEND_VCF (backend)); + + if (! pas_backend_construct (PAS_BACKEND (backend))) + return FALSE; + + return TRUE; +} + +/** + * pas_backend_vcf_new: + */ +PASBackend * +pas_backend_vcf_new (void) +{ + PASBackendVCF *backend; + + backend = g_object_new (PAS_TYPE_BACKEND_VCF, NULL); + + if (! pas_backend_vcf_construct (backend)) { + g_object_unref (backend); + + return NULL; + } + + return PAS_BACKEND (backend); +} + +static void +pas_backend_vcf_dispose (GObject *object) +{ + PASBackendVCF *bvcf; + + bvcf = PAS_BACKEND_VCF (object); + + if (bvcf->priv) { + + if (bvcf->priv->dirty) + save_file (bvcf); + + if (bvcf->priv->flush_timeout_tag) { + g_source_remove (bvcf->priv->flush_timeout_tag); + bvcf->priv->flush_timeout_tag = 0; + } + + g_free (bvcf->priv->uri); + g_free (bvcf->priv->filename); + + g_free (bvcf->priv); + bvcf->priv = NULL; + } + + G_OBJECT_CLASS (pas_backend_vcf_parent_class)->dispose (object); +} + +static void +pas_backend_vcf_class_init (PASBackendVCFClass *klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS (klass); + PASBackendSyncClass *sync_class; + PASBackendClass *backend_class; + + pas_backend_vcf_parent_class = g_type_class_peek_parent (klass); + + sync_class = PAS_BACKEND_SYNC_CLASS (klass); + backend_class = PAS_BACKEND_CLASS (klass); + + /* Set the virtual methods. */ + backend_class->load_uri = pas_backend_vcf_load_uri; + backend_class->get_static_capabilities = pas_backend_vcf_get_static_capabilities; + backend_class->start_book_view = pas_backend_vcf_start_book_view; + backend_class->cancel_operation = pas_backend_vcf_cancel_operation; + + sync_class->create_contact_sync = pas_backend_vcf_process_create_contact; + sync_class->remove_contacts_sync = pas_backend_vcf_process_remove_contacts; + sync_class->modify_contact_sync = pas_backend_vcf_process_modify_contact; + sync_class->get_contact_sync = pas_backend_vcf_process_get_contact; + sync_class->get_contact_list_sync = pas_backend_vcf_process_get_contact_list; + sync_class->authenticate_user_sync = pas_backend_vcf_process_authenticate_user; + sync_class->get_supported_fields_sync = pas_backend_vcf_process_get_supported_fields; + + object_class->dispose = pas_backend_vcf_dispose; +} + +static void +pas_backend_vcf_init (PASBackendVCF *backend) +{ + PASBackendVCFPrivate *priv; + + priv = g_new0 (PASBackendVCFPrivate, 1); + priv->uri = NULL; + + backend->priv = priv; +} + +/** + * pas_backend_vcf_get_type: + */ +GType +pas_backend_vcf_get_type (void) +{ + static GType type = 0; + + if (! type) { + GTypeInfo info = { + sizeof (PASBackendVCFClass), + NULL, /* base_class_init */ + NULL, /* base_class_finalize */ + (GClassInitFunc) pas_backend_vcf_class_init, + NULL, /* class_finalize */ + NULL, /* class_data */ + sizeof (PASBackendVCF), + 0, /* n_preallocs */ + (GInstanceInitFunc) pas_backend_vcf_init + }; + + type = g_type_register_static (PAS_TYPE_BACKEND_SYNC, "PASBackendVCF", &info, 0); + } + + return type; +} diff --git a/addressbook/backend/pas/pas-backend-vcf.h b/addressbook/backend/pas/pas-backend-vcf.h new file mode 100644 index 0000000000..81c872dcf1 --- /dev/null +++ b/addressbook/backend/pas/pas-backend-vcf.h @@ -0,0 +1,35 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ +/* + * Author: + * Chris Toshok (toshok@ximian.com) + * Copyright (C) 2003, Ximian, Inc. + */ + +#ifndef __PAS_BACKEND_VCF_H__ +#define __PAS_BACKEND_VCF_H__ + +#include "pas-backend-sync.h" + +#define PAS_TYPE_BACKEND_VCF (pas_backend_vcf_get_type ()) +#define PAS_BACKEND_VCF(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), PAS_TYPE_BACKEND_VCF, PASBackendVCF)) +#define PAS_BACKEND_VCF_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), PAS_BACKEND_TYPE, PASBackendVCFClass)) +#define PAS_IS_BACKEND_VCF(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), PAS_TYPE_BACKEND_VCF)) +#define PAS_IS_BACKEND_VCF_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), PAS_TYPE_BACKEND_VCF)) +#define PAS_BACKEND_VCF_GET_CLASS(k) (G_TYPE_INSTANCE_GET_CLASS ((obj), PAS_TYPE_BACKEND_VCF, PASBackendVCFClass)) + +typedef struct _PASBackendVCFPrivate PASBackendVCFPrivate; + +typedef struct { + PASBackendSync parent_object; + PASBackendVCFPrivate *priv; +} PASBackendVCF; + +typedef struct { + PASBackendSyncClass parent_class; +} PASBackendVCFClass; + +PASBackend *pas_backend_vcf_new (void); +GType pas_backend_vcf_get_type (void); + +#endif /* ! __PAS_BACKEND_VCF_H__ */ + diff --git a/addressbook/backend/pas/pas-backend.c b/addressbook/backend/pas/pas-backend.c index acc6ed2a2c..076565de07 100644 --- a/addressbook/backend/pas/pas-backend.c +++ b/addressbook/backend/pas/pas-backend.c @@ -7,12 +7,22 @@ */ #include +#include +#include "pas-book-view.h" #include "pas-backend.h" #include "pas-marshal.h" struct _PASBackendPrivate { + GMutex *open_mutex; + + GMutex *clients_mutex; GList *clients; - gboolean loaded, writable; + + char *uri; + gboolean loaded, writable, removed; + + GMutex *views_mutex; + EList *views; }; /* Signal IDs */ @@ -31,18 +41,25 @@ pas_backend_construct (PASBackend *backend) return TRUE; } -GNOME_Evolution_Addressbook_BookListener_CallStatus +GNOME_Evolution_Addressbook_CallStatus pas_backend_load_uri (PASBackend *backend, - const char *uri) + const char *uri, + gboolean only_if_exists) { - g_return_val_if_fail (backend != NULL, FALSE); - g_return_val_if_fail (PAS_IS_BACKEND (backend), FALSE); - g_return_val_if_fail (uri != NULL, FALSE); + GNOME_Evolution_Addressbook_CallStatus status; + + g_return_val_if_fail (backend && PAS_IS_BACKEND (backend), FALSE); + g_return_val_if_fail (uri, FALSE); g_return_val_if_fail (backend->priv->loaded == FALSE, FALSE); - g_assert (PAS_BACKEND_GET_CLASS (backend)->load_uri != NULL); + g_assert (PAS_BACKEND_GET_CLASS (backend)->load_uri); + + status = (* PAS_BACKEND_GET_CLASS (backend)->load_uri) (backend, uri, only_if_exists); + + if (status == GNOME_Evolution_Addressbook_Success) + backend->priv->uri = g_strdup (uri); - return (* PAS_BACKEND_GET_CLASS (backend)->load_uri) (backend, uri); + return status; } /** @@ -56,246 +73,198 @@ pas_backend_load_uri (PASBackend *backend, const char * pas_backend_get_uri (PASBackend *backend) { - g_return_val_if_fail (backend != NULL, NULL); - g_return_val_if_fail (PAS_IS_BACKEND (backend), NULL); + g_return_val_if_fail (backend && PAS_IS_BACKEND (backend), NULL); - g_assert (PAS_BACKEND_GET_CLASS (backend)->get_uri != NULL); - - return (* PAS_BACKEND_GET_CLASS (backend)->get_uri) (backend); + return backend->priv->uri; } - void -pas_backend_create_card (PASBackend *backend, - PASBook *book, - PASCreateCardRequest *req) +pas_backend_open (PASBackend *backend, + PASBook *book, + gboolean only_if_exists) { - g_return_if_fail (PAS_IS_BACKEND (backend)); - g_return_if_fail (PAS_IS_BOOK (book)); - g_return_if_fail (req != NULL && req->vcard != NULL); + g_return_if_fail (backend && PAS_IS_BACKEND (backend)); + g_return_if_fail (book && PAS_IS_BOOK (book)); + + g_mutex_lock (backend->priv->open_mutex); - g_assert (PAS_BACKEND_GET_CLASS (backend)->create_card != NULL); + if (backend->priv->loaded) { + pas_book_respond_open ( + book, GNOME_Evolution_Addressbook_Success); - (* PAS_BACKEND_GET_CLASS (backend)->create_card) (backend, book, req); + pas_book_report_writable (book, backend->priv->writable); + } else { + GNOME_Evolution_Addressbook_CallStatus status = + pas_backend_load_uri (backend, pas_book_get_uri (book), only_if_exists); + + pas_book_respond_open (book, status); + + if (status == GNOME_Evolution_Addressbook_Success) + pas_book_report_writable (book, backend->priv->writable); + } + + g_mutex_unlock (backend->priv->open_mutex); } void -pas_backend_remove_cards (PASBackend *backend, - PASBook *book, - PASRemoveCardsRequest *req) +pas_backend_remove (PASBackend *backend, + PASBook *book) { - g_return_if_fail (PAS_IS_BACKEND (backend)); - g_return_if_fail (PAS_IS_BOOK (book)); - g_return_if_fail (req != NULL && req->ids != NULL); + g_return_if_fail (backend && PAS_IS_BACKEND (backend)); + g_return_if_fail (book && PAS_IS_BOOK (book)); - g_assert (PAS_BACKEND_GET_CLASS (backend)->remove_cards != NULL); + g_assert (PAS_BACKEND_GET_CLASS (backend)->remove); - (* PAS_BACKEND_GET_CLASS (backend)->remove_cards) (backend, book, req); + (* PAS_BACKEND_GET_CLASS (backend)->remove) (backend, book); } void -pas_backend_modify_card (PASBackend *backend, - PASBook *book, - PASModifyCardRequest *req) +pas_backend_create_contact (PASBackend *backend, + PASBook *book, + const char *vcard) { - g_return_if_fail (PAS_IS_BACKEND (backend)); - g_return_if_fail (PAS_IS_BOOK (book)); - g_return_if_fail (req != NULL && req->vcard != NULL); + g_return_if_fail (backend && PAS_IS_BACKEND (backend)); + g_return_if_fail (book && PAS_IS_BOOK (book)); + g_return_if_fail (vcard); - g_assert (PAS_BACKEND_GET_CLASS (backend)->modify_card != NULL); + g_assert (PAS_BACKEND_GET_CLASS (backend)->create_contact); - (* PAS_BACKEND_GET_CLASS (backend)->modify_card) (backend, book, req); + (* PAS_BACKEND_GET_CLASS (backend)->create_contact) (backend, book, vcard); } void -pas_backend_check_connection (PASBackend *backend, - PASBook *book, - PASCheckConnectionRequest *req) +pas_backend_remove_contacts (PASBackend *backend, + PASBook *book, + GList *id_list) { - g_return_if_fail (PAS_IS_BACKEND (backend)); - g_return_if_fail (PAS_IS_BOOK (book)); - g_return_if_fail (req != NULL); + g_return_if_fail (backend && PAS_IS_BACKEND (backend)); + g_return_if_fail (book && PAS_IS_BOOK (book)); + g_return_if_fail (id_list); - g_assert (PAS_BACKEND_GET_CLASS (backend)->check_connection != NULL); + g_assert (PAS_BACKEND_GET_CLASS (backend)->remove_contacts); - (* PAS_BACKEND_GET_CLASS (backend)->check_connection) (backend, book, req); + (* PAS_BACKEND_GET_CLASS (backend)->remove_contacts) (backend, book, id_list); } void -pas_backend_get_vcard (PASBackend *backend, - PASBook *book, - PASGetVCardRequest *req) +pas_backend_modify_contact (PASBackend *backend, + PASBook *book, + const char *vcard) { - g_return_if_fail (PAS_IS_BACKEND (backend)); - g_return_if_fail (PAS_IS_BOOK (book)); - g_return_if_fail (req != NULL && req->id != NULL); + g_return_if_fail (backend && PAS_IS_BACKEND (backend)); + g_return_if_fail (book && PAS_IS_BOOK (book)); + g_return_if_fail (vcard); - g_assert (PAS_BACKEND_GET_CLASS (backend)->get_vcard != NULL); + g_assert (PAS_BACKEND_GET_CLASS (backend)->modify_contact); - (* PAS_BACKEND_GET_CLASS (backend)->get_vcard) (backend, book, req); + (* PAS_BACKEND_GET_CLASS (backend)->modify_contact) (backend, book, vcard); } void -pas_backend_get_cursor (PASBackend *backend, - PASBook *book, - PASGetCursorRequest *req) +pas_backend_get_contact (PASBackend *backend, + PASBook *book, + const char *id) { - g_return_if_fail (PAS_IS_BACKEND (backend)); - g_return_if_fail (PAS_IS_BOOK (book)); - g_return_if_fail (req != NULL && req->search != NULL); + g_return_if_fail (backend && PAS_IS_BACKEND (backend)); + g_return_if_fail (book && PAS_IS_BOOK (book)); + g_return_if_fail (id); - g_assert (PAS_BACKEND_GET_CLASS (backend)->get_cursor != NULL); + g_assert (PAS_BACKEND_GET_CLASS (backend)->get_contact); - (* PAS_BACKEND_GET_CLASS (backend)->get_cursor) (backend, book, req); + (* PAS_BACKEND_GET_CLASS (backend)->get_contact) (backend, book, id); } void -pas_backend_get_book_view (PASBackend *backend, - PASBook *book, - PASGetBookViewRequest *req) +pas_backend_get_contact_list (PASBackend *backend, + PASBook *book, + const char *query) { - g_return_if_fail (PAS_IS_BACKEND (backend)); - g_return_if_fail (PAS_IS_BOOK (book)); - g_return_if_fail (req != NULL && req->search != NULL && req->listener != CORBA_OBJECT_NIL); + g_return_if_fail (backend && PAS_IS_BACKEND (backend)); + g_return_if_fail (book && PAS_IS_BOOK (book)); + g_return_if_fail (query); - g_assert (PAS_BACKEND_GET_CLASS (backend)->get_book_view != NULL); + g_assert (PAS_BACKEND_GET_CLASS (backend)->get_contact_list); - (* PAS_BACKEND_GET_CLASS (backend)->get_book_view) (backend, book, req); + (* PAS_BACKEND_GET_CLASS (backend)->get_contact_list) (backend, book, query); } void -pas_backend_get_completion_view (PASBackend *backend, - PASBook *book, - PASGetCompletionViewRequest *req) +pas_backend_start_book_view (PASBackend *backend, + PASBookView *book_view) { - g_return_if_fail (PAS_IS_BACKEND (backend)); - g_return_if_fail (PAS_IS_BOOK (book)); - g_return_if_fail (req != NULL && req->search != NULL && req->listener != CORBA_OBJECT_NIL); + g_return_if_fail (backend && PAS_IS_BACKEND (backend)); + g_return_if_fail (book_view && PAS_IS_BOOK_VIEW (book_view)); - g_assert (PAS_BACKEND_GET_CLASS (backend)->get_completion_view != NULL); + g_assert (PAS_BACKEND_GET_CLASS (backend)->start_book_view); - (* PAS_BACKEND_GET_CLASS (backend)->get_completion_view) (backend, book, req); + (* PAS_BACKEND_GET_CLASS (backend)->start_book_view) (backend, book_view); } void pas_backend_get_changes (PASBackend *backend, PASBook *book, - PASGetChangesRequest *req) + const char *change_id) { - g_return_if_fail (PAS_IS_BACKEND (backend)); - g_return_if_fail (PAS_IS_BOOK (book)); - g_return_if_fail (req != NULL && req->change_id != NULL && req->listener != CORBA_OBJECT_NIL); + g_return_if_fail (backend && PAS_IS_BACKEND (backend)); + g_return_if_fail (book && PAS_IS_BOOK (book)); + g_return_if_fail (change_id); - g_assert (PAS_BACKEND_GET_CLASS (backend)->get_changes != NULL); + g_assert (PAS_BACKEND_GET_CLASS (backend)->get_changes); - (* PAS_BACKEND_GET_CLASS (backend)->get_changes) (backend, book, req); + (* PAS_BACKEND_GET_CLASS (backend)->get_changes) (backend, book, change_id); } void pas_backend_authenticate_user (PASBackend *backend, PASBook *book, - PASAuthenticateUserRequest *req) + const char *user, + const char *passwd, + const char *auth_method) { - g_return_if_fail (PAS_IS_BACKEND (backend)); - g_return_if_fail (PAS_IS_BOOK (book)); - g_return_if_fail (req != NULL); + g_return_if_fail (backend && PAS_IS_BACKEND (backend)); + g_return_if_fail (book && PAS_IS_BOOK (book)); + g_return_if_fail (user && passwd && auth_method); - g_assert (PAS_BACKEND_GET_CLASS (backend)->authenticate_user != NULL); + g_assert (PAS_BACKEND_GET_CLASS (backend)->authenticate_user); - (* PAS_BACKEND_GET_CLASS (backend)->authenticate_user) (backend, book, req); + (* PAS_BACKEND_GET_CLASS (backend)->authenticate_user) (backend, book, user, passwd, auth_method); } void pas_backend_get_supported_fields (PASBackend *backend, - PASBook *book, - PASGetSupportedFieldsRequest *req) + PASBook *book) + { - g_return_if_fail (PAS_IS_BACKEND (backend)); - g_return_if_fail (PAS_IS_BOOK (book)); - g_return_if_fail (req != NULL); + g_return_if_fail (backend && PAS_IS_BACKEND (backend)); + g_return_if_fail (book && PAS_IS_BOOK (book)); - g_assert (PAS_BACKEND_GET_CLASS (backend)->get_supported_fields != NULL); + g_assert (PAS_BACKEND_GET_CLASS (backend)->get_supported_fields); - (* PAS_BACKEND_GET_CLASS (backend)->get_supported_fields) (backend, book, req); + (* PAS_BACKEND_GET_CLASS (backend)->get_supported_fields) (backend, book); } void pas_backend_get_supported_auth_methods (PASBackend *backend, - PASBook *book, - PASGetSupportedAuthMethodsRequest *req) + PASBook *book) { - g_return_if_fail (PAS_IS_BACKEND (backend)); - g_return_if_fail (PAS_IS_BOOK (book)); - g_return_if_fail (req != NULL); + g_return_if_fail (backend && PAS_IS_BACKEND (backend)); + g_return_if_fail (book && PAS_IS_BOOK (book)); - g_assert (PAS_BACKEND_GET_CLASS (backend)->get_supported_auth_methods != NULL); + g_assert (PAS_BACKEND_GET_CLASS (backend)->get_supported_auth_methods); - (* PAS_BACKEND_GET_CLASS (backend)->get_supported_auth_methods) (backend, book, req); + (* PAS_BACKEND_GET_CLASS (backend)->get_supported_auth_methods) (backend, book); } -static void -process_client_requests (PASBook *book, gpointer user_data) +GNOME_Evolution_Addressbook_CallStatus +pas_backend_cancel_operation (PASBackend *backend, + PASBook *book) { - PASBackend *backend; - PASRequest *req; - - backend = PAS_BACKEND (user_data); - - req = pas_book_pop_request (book); - if (req == NULL) - return; - - switch (req->op) { - case CreateCard: - pas_backend_create_card (backend, book, &req->create); - break; - - case RemoveCards: - pas_backend_remove_cards (backend, book, &req->remove); - break; - - case ModifyCard: - pas_backend_modify_card (backend, book, &req->modify); - break; - - case CheckConnection: - pas_backend_check_connection (backend, book, &req->check_connection); - break; - - case GetVCard: - pas_backend_get_vcard (backend, book, &req->get_vcard); - break; - - case GetCursor: - pas_backend_get_cursor (backend, book, &req->get_cursor); - break; + g_return_val_if_fail (backend && PAS_IS_BACKEND (backend), GNOME_Evolution_Addressbook_OtherError); + g_return_val_if_fail (book && PAS_IS_BOOK (book), GNOME_Evolution_Addressbook_OtherError); - case GetBookView: - pas_backend_get_book_view (backend, book, &req->get_book_view); - break; + g_assert (PAS_BACKEND_GET_CLASS (backend)->cancel_operation); - case GetCompletionView: - pas_backend_get_completion_view (backend, book, &req->get_completion_view); - break; - - case GetChanges: - pas_backend_get_changes (backend, book, &req->get_changes); - break; - - case AuthenticateUser: - pas_backend_authenticate_user (backend, book, &req->auth_user); - break; - - case GetSupportedFields: - pas_backend_get_supported_fields (backend, book, &req->get_supported_fields); - break; - - case GetSupportedAuthMethods: - pas_backend_get_supported_auth_methods (backend, book, &req->get_supported_auth_methods); - break; - } - - pas_book_free_request (req); + return (* PAS_BACKEND_GET_CLASS (backend)->cancel_operation) (backend, book); } static void @@ -306,75 +275,83 @@ book_destroy_cb (gpointer data, GObject *where_book_was) pas_backend_remove_client (backend, (PASBook *)where_book_was); } +static void +listener_died_cb (gpointer cnx, gpointer user_data) +{ + PASBook *book = PAS_BOOK (user_data); + + pas_backend_remove_client (pas_book_get_backend (book), book); +} + static void last_client_gone (PASBackend *backend) { g_signal_emit (backend, pas_backend_signals[LAST_CLIENT_GONE], 0); } -static gboolean -add_client (PASBackend *backend, - GNOME_Evolution_Addressbook_BookListener listener) +EList* +pas_backend_get_book_views (PASBackend *backend) { - PASBook *book; - - book = pas_book_new (backend, listener); - if (!book) { - if (!backend->priv->clients) - last_client_gone (backend); - - return FALSE; - } - - g_object_weak_ref (G_OBJECT (book), book_destroy_cb, backend); - - g_signal_connect (book, "requests_queued", - G_CALLBACK (process_client_requests), backend); + g_return_val_if_fail (backend && PAS_IS_BACKEND (backend), FALSE); - backend->priv->clients = g_list_prepend (backend->priv->clients, book); - - if (backend->priv->loaded) { - pas_book_respond_open ( - book, GNOME_Evolution_Addressbook_BookListener_Success); - } else { - pas_book_respond_open ( - book, GNOME_Evolution_Addressbook_BookListener_OtherError); - } + return g_object_ref (backend->priv->views); +} - pas_book_report_writable (book, backend->priv->writable); +void +pas_backend_add_book_view (PASBackend *backend, + PASBookView *view) +{ + g_mutex_lock (backend->priv->views_mutex); - bonobo_object_unref (BONOBO_OBJECT (book)); + e_list_append (backend->priv->views, view); - return TRUE; + g_mutex_unlock (backend->priv->views_mutex); } /** * pas_backend_add_client: * @backend: An addressbook backend. - * @listener: Listener for notification to the client. + * @book: the corba object representing the client connection. * * Adds a client to an addressbook backend. * * Return value: TRUE on success, FALSE on failure to add the client. */ gboolean -pas_backend_add_client (PASBackend *backend, - GNOME_Evolution_Addressbook_BookListener listener) +pas_backend_add_client (PASBackend *backend, + PASBook *book) { - g_return_val_if_fail (PAS_IS_BACKEND (backend), FALSE); - g_return_val_if_fail (listener != CORBA_OBJECT_NIL, FALSE); + g_return_val_if_fail (backend && PAS_IS_BACKEND (backend), FALSE); + g_return_val_if_fail (book && PAS_IS_BOOK (book), FALSE); + + bonobo_object_set_immortal (BONOBO_OBJECT (book), TRUE); + + g_object_weak_ref (G_OBJECT (book), book_destroy_cb, backend); + + ORBit_small_listen_for_broken (pas_book_get_listener (book), G_CALLBACK (listener_died_cb), book); - g_assert (PAS_BACKEND_GET_CLASS (backend)->add_client != NULL); + g_mutex_lock (backend->priv->clients_mutex); + backend->priv->clients = g_list_prepend (backend->priv->clients, book); + g_mutex_unlock (backend->priv->clients_mutex); - return PAS_BACKEND_GET_CLASS (backend)->add_client (backend, listener); + return TRUE; } -static void -remove_client (PASBackend *backend, - PASBook *book) +void +pas_backend_remove_client (PASBackend *backend, + PASBook *book) { + /* XXX this needs a bit more thinking wrt the mutex - we + should be holding it when we check to see if clients is + NULL */ + + g_return_if_fail (backend && PAS_IS_BACKEND (backend)); + g_return_if_fail (book && PAS_IS_BOOK (book)); + /* Disconnect */ + g_mutex_lock (backend->priv->clients_mutex); backend->priv->clients = g_list_remove (backend->priv->clients, book); + g_mutex_unlock (backend->priv->clients_mutex); /* When all clients go away, notify the parent factory about it so that * it may decide whether to kill the backend or not. @@ -383,25 +360,12 @@ remove_client (PASBackend *backend, last_client_gone (backend); } -void -pas_backend_remove_client (PASBackend *backend, - PASBook *book) -{ - g_return_if_fail (PAS_IS_BACKEND (backend)); - g_return_if_fail (PAS_IS_BOOK (book)); - - g_assert (PAS_BACKEND_GET_CLASS (backend)->remove_client != NULL); - - PAS_BACKEND_GET_CLASS (backend)->remove_client (backend, book); -} - char * pas_backend_get_static_capabilities (PASBackend *backend) { - g_return_val_if_fail (backend != NULL, NULL); - g_return_val_if_fail (PAS_IS_BACKEND (backend), NULL); + g_return_val_if_fail (backend && PAS_IS_BACKEND (backend), NULL); - g_assert (PAS_BACKEND_GET_CLASS (backend)->get_static_capabilities != NULL); + g_assert (PAS_BACKEND_GET_CLASS (backend)->get_static_capabilities); return PAS_BACKEND_GET_CLASS (backend)->get_static_capabilities (backend); } @@ -409,7 +373,7 @@ pas_backend_get_static_capabilities (PASBackend *backend) gboolean pas_backend_is_loaded (PASBackend *backend) { - g_return_val_if_fail (PAS_IS_BACKEND (backend), FALSE); + g_return_val_if_fail (backend && PAS_IS_BACKEND (backend), FALSE); return backend->priv->loaded; } @@ -417,7 +381,7 @@ pas_backend_is_loaded (PASBackend *backend) void pas_backend_set_is_loaded (PASBackend *backend, gboolean is_loaded) { - g_return_if_fail (PAS_IS_BACKEND (backend)); + g_return_if_fail (backend && PAS_IS_BACKEND (backend)); backend->priv->loaded = is_loaded; } @@ -425,7 +389,7 @@ pas_backend_set_is_loaded (PASBackend *backend, gboolean is_loaded) gboolean pas_backend_is_writable (PASBackend *backend) { - g_return_val_if_fail (PAS_IS_BACKEND (backend), FALSE); + g_return_val_if_fail (backend && PAS_IS_BACKEND (backend), FALSE); return backend->priv->writable; } @@ -433,18 +397,175 @@ pas_backend_is_writable (PASBackend *backend) void pas_backend_set_is_writable (PASBackend *backend, gboolean is_writable) { - g_return_if_fail (PAS_IS_BACKEND (backend)); + g_return_if_fail (backend && PAS_IS_BACKEND (backend)); backend->priv->writable = is_writable; } +gboolean +pas_backend_is_removed (PASBackend *backend) +{ + g_return_val_if_fail (backend && PAS_IS_BACKEND (backend), FALSE); + + return backend->priv->removed; +} + +void +pas_backend_set_is_removed (PASBackend *backend, gboolean is_removed) +{ + g_return_if_fail (backend && PAS_IS_BACKEND (backend)); + + backend->priv->removed = is_removed; +} + + + +GNOME_Evolution_Addressbook_BookChangeItem* +pas_backend_change_add_new (const char *vcard) +{ + GNOME_Evolution_Addressbook_BookChangeItem* new_change = GNOME_Evolution_Addressbook_BookChangeItem__alloc(); + + new_change->_d = GNOME_Evolution_Addressbook_ContactAdded; + new_change->_u.add_vcard = CORBA_string_dup (vcard); + + return new_change; +} + +GNOME_Evolution_Addressbook_BookChangeItem* +pas_backend_change_modify_new (const char *vcard) +{ + GNOME_Evolution_Addressbook_BookChangeItem* new_change = GNOME_Evolution_Addressbook_BookChangeItem__alloc(); + + new_change->_d = GNOME_Evolution_Addressbook_ContactModified; + new_change->_u.mod_vcard = CORBA_string_dup (vcard); + + return new_change; +} + +GNOME_Evolution_Addressbook_BookChangeItem* +pas_backend_change_delete_new (const char *id) +{ + GNOME_Evolution_Addressbook_BookChangeItem* new_change = GNOME_Evolution_Addressbook_BookChangeItem__alloc(); + + new_change->_d = GNOME_Evolution_Addressbook_ContactDeleted; + new_change->_u.del_id = CORBA_string_dup (id); + + return new_change; +} + + + +static void +pas_backend_foreach_view (PASBackend *backend, + void (*callback) (PASBookView *, gpointer), + gpointer user_data) +{ + EList *views; + PASBookView *view; + EIterator *iter; + + views = pas_backend_get_book_views (backend); + iter = e_list_get_iterator (views); + + while (e_iterator_is_valid (iter)) { + view = (PASBookView*)e_iterator_get (iter); + + bonobo_object_ref (view); + callback (view, user_data); + bonobo_object_unref (view); + + e_iterator_next (iter); + } + + g_object_unref (iter); + g_object_unref (views); +} + + +static void +view_notify_update (PASBookView *view, gpointer contact) +{ + pas_book_view_notify_update (view, contact); +} + +/** + * pas_backend_notify_update: + * @backend: an addressbook backend + * @contact: a new or modified contact + * + * Notifies all of @backend's book views about the new or modified + * contacts @contact. + * + * pas_book_respond_create() and pas_book_respond_modify() call this + * function for you. You only need to call this from your backend if + * contacts are created or modified by another (non-PAS-using) client. + **/ +void +pas_backend_notify_update (PASBackend *backend, EContact *contact) +{ + pas_backend_foreach_view (backend, view_notify_update, contact); +} + + +static void +view_notify_remove (PASBookView *view, gpointer id) +{ + pas_book_view_notify_remove (view, id); +} + +/** + * pas_backend_notify_remove: + * @backend: an addressbook backend + * @id: a contact id + * + * Notifies all of @backend's book views that the contact with UID + * @id has been removed. + * + * pas_book_respond_remove_contacts() calls this function for you. You + * only need to call this from your backend if contacts are removed by + * another (non-PAS-using) client. + **/ +void +pas_backend_notify_remove (PASBackend *backend, const char *id) +{ + pas_backend_foreach_view (backend, view_notify_remove, (gpointer)id); +} + + +static void +view_notify_complete (PASBookView *view, gpointer unused) +{ + pas_book_view_notify_complete (view, GNOME_Evolution_Addressbook_Success); +} + +/** + * pas_backend_notify_complete: + * @backend: an addressbook backend + * + * Notifies all of @backend's book views that the current set of + * notifications is complete; use this after a series of + * pas_backend_notify_update() and pas_backend_notify_remove() calls. + **/ +void +pas_backend_notify_complete (PASBackend *backend) +{ + pas_backend_foreach_view (backend, view_notify_complete, NULL); +} + + + static void pas_backend_init (PASBackend *backend) { PASBackendPrivate *priv; priv = g_new0 (PASBackendPrivate, 1); + priv->uri = NULL; priv->clients = NULL; + priv->views = e_list_new((EListCopyFunc) g_object_ref, (EListFreeFunc) g_object_unref, NULL); + priv->open_mutex = g_mutex_new (); + priv->clients_mutex = g_mutex_new (); + priv->views_mutex = g_mutex_new (); backend->priv = priv; } @@ -458,8 +579,20 @@ pas_backend_dispose (GObject *object) if (backend->priv) { g_list_free (backend->priv->clients); - g_free (backend->priv); + if (backend->priv->uri) + g_free (backend->priv->uri); + + if (backend->priv->views) { + g_object_unref (backend->priv->views); + backend->priv->views = NULL; + } + + g_mutex_free (backend->priv->open_mutex); + g_mutex_free (backend->priv->clients_mutex); + g_mutex_free (backend->priv->views_mutex); + + g_free (backend->priv); backend->priv = NULL; } @@ -475,9 +608,6 @@ pas_backend_class_init (PASBackendClass *klass) object_class = (GObjectClass *) klass; - klass->add_client = add_client; - klass->remove_client = remove_client; - object_class->dispose = pas_backend_dispose; pas_backend_signals[LAST_CLIENT_GONE] = diff --git a/addressbook/backend/pas/pas-backend.h b/addressbook/backend/pas/pas-backend.h index b33518116e..41f6542213 100644 --- a/addressbook/backend/pas/pas-backend.h +++ b/addressbook/backend/pas/pas-backend.h @@ -25,6 +25,8 @@ #include #include #include +#include +#include #define PAS_TYPE_BACKEND (pas_backend_get_type ()) #define PAS_BACKEND(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), PAS_TYPE_BACKEND, PASBackend)) @@ -33,7 +35,6 @@ #define PAS_IS_BACKEND_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), PAS_TYPE_BACKEND)) #define PAS_BACKEND_GET_CLASS(k) (G_TYPE_INSTANCE_GET_CLASS ((k), PAS_TYPE_BACKEND, PASBackendClass)) -typedef struct _PASBackend PASBackend; typedef struct _PASBackendPrivate PASBackendPrivate; #include @@ -43,44 +44,49 @@ struct _PASBackend { PASBackendPrivate *priv; }; -typedef struct { +struct _PASBackendClass { GObjectClass parent_class; /* Virtual methods */ - GNOME_Evolution_Addressbook_BookListener_CallStatus (*load_uri) (PASBackend *backend, const char *uri); - const char *(* get_uri) (PASBackend *backend); - gboolean (*add_client) (PASBackend *backend, GNOME_Evolution_Addressbook_BookListener listener); - void (*remove_client) (PASBackend *backend, PASBook *book); + GNOME_Evolution_Addressbook_CallStatus (*load_uri) (PASBackend *backend, const char *uri, gboolean only_if_exists); + void (*remove) (PASBackend *backend, PASBook *book); char *(*get_static_capabilities) (PASBackend *backend); - void (*create_card) (PASBackend *backend, PASBook *book, PASCreateCardRequest *req); - void (*remove_cards) (PASBackend *backend, PASBook *book, PASRemoveCardsRequest *req); - void (*modify_card) (PASBackend *backend, PASBook *book, PASModifyCardRequest *req); - void (*check_connection) (PASBackend *backend, PASBook *book, PASCheckConnectionRequest *req); - void (*get_vcard) (PASBackend *backend, PASBook *book, PASGetVCardRequest *req); - void (*get_cursor) (PASBackend *backend, PASBook *book, PASGetCursorRequest *req); - void (*get_book_view) (PASBackend *backend, PASBook *book, PASGetBookViewRequest *req); - void (*get_completion_view) (PASBackend *backend, PASBook *book, PASGetCompletionViewRequest *req); - void (*get_changes) (PASBackend *backend, PASBook *book, PASGetChangesRequest *req); - void (*authenticate_user) (PASBackend *backend, PASBook *book, PASAuthenticateUserRequest *req); - void (*get_supported_fields) (PASBackend *backend, PASBook *book, PASGetSupportedFieldsRequest *req); - void (*get_supported_auth_methods) (PASBackend *backend, PASBook *book, PASGetSupportedAuthMethodsRequest *req); + void (*create_contact) (PASBackend *backend, PASBook *book, const char *vcard); + void (*remove_contacts) (PASBackend *backend, PASBook *book, GList *id_list); + void (*modify_contact) (PASBackend *backend, PASBook *book, const char *vcard); + void (*get_contact) (PASBackend *backend, PASBook *book, const char *id); + void (*get_contact_list) (PASBackend *backend, PASBook *book, const char *query); + void (*start_book_view) (PASBackend *backend, PASBookView *book_view); + void (*get_changes) (PASBackend *backend, PASBook *book, const char *change_id); + void (*authenticate_user) (PASBackend *backend, PASBook *book, const char *user, const char *passwd, const char *auth_method); + void (*get_supported_fields) (PASBackend *backend, PASBook *book); + void (*get_supported_auth_methods) (PASBackend *backend, PASBook *book); + GNOME_Evolution_Addressbook_CallStatus (*cancel_operation) (PASBackend *backend, PASBook *book); /* Notification signals */ void (* last_client_gone) (PASBackend *backend); -} PASBackendClass; + + /* Padding for future expansion */ + void (*_pas_reserved0) (void); + void (*_pas_reserved1) (void); + void (*_pas_reserved2) (void); + void (*_pas_reserved3) (void); + void (*_pas_reserved4) (void); +}; typedef PASBackend * (*PASBackendFactoryFn) (void); gboolean pas_backend_construct (PASBackend *backend); -GNOME_Evolution_Addressbook_BookListener_CallStatus +GNOME_Evolution_Addressbook_CallStatus pas_backend_load_uri (PASBackend *backend, - const char *uri); + const char *uri, + gboolean only_if_exists); const char *pas_backend_get_uri (PASBackend *backend); gboolean pas_backend_add_client (PASBackend *backend, - GNOME_Evolution_Addressbook_BookListener listener); + PASBook *book); void pas_backend_remove_client (PASBackend *backend, PASBook *book); char *pas_backend_get_static_capabilities (PASBackend *backend); @@ -89,42 +95,56 @@ gboolean pas_backend_is_loaded (PASBackend *backen gboolean pas_backend_is_writable (PASBackend *backend); -void pas_backend_create_card (PASBackend *backend, - PASBook *book, - PASCreateCardRequest *req); -void pas_backend_remove_cards (PASBackend *backend, - PASBook *book, - PASRemoveCardsRequest *req); -void pas_backend_modify_card (PASBackend *backend, +gboolean pas_backend_is_removed (PASBackend *backend); + +void pas_backend_open (PASBackend *backend, PASBook *book, - PASModifyCardRequest *req); -void pas_backend_check_connection (PASBackend *backend, + gboolean only_if_exists); +void pas_backend_remove (PASBackend *backend, + PASBook *book); +void pas_backend_create_contact (PASBackend *backend, PASBook *book, - PASCheckConnectionRequest *req); -void pas_backend_get_vcard (PASBackend *backend, + const char *vcard); +void pas_backend_remove_contacts (PASBackend *backend, PASBook *book, - PASGetVCardRequest *req); -void pas_backend_get_cursor (PASBackend *backend, + GList *id_list); +void pas_backend_modify_contact (PASBackend *backend, PASBook *book, - PASGetCursorRequest *req); -void pas_backend_get_book_view (PASBackend *backend, + const char *vcard); +void pas_backend_get_contact (PASBackend *backend, PASBook *book, - PASGetBookViewRequest *req); -void pas_backend_get_completion_view (PASBackend *backend, + const char *id); +void pas_backend_get_contact_list (PASBackend *backend, PASBook *book, - PASGetCompletionViewRequest *req); + const char *query); void pas_backend_get_changes (PASBackend *backend, PASBook *book, - PASGetChangesRequest *req); + const char *change_id); void pas_backend_authenticate_user (PASBackend *backend, PASBook *book, - PASAuthenticateUserRequest *req); + const char *user, + const char *passwd, + const char *auth_method); void pas_backend_get_supported_fields (PASBackend *backend, - PASBook *book, - PASGetSupportedFieldsRequest *req); + PASBook *book); void pas_backend_get_supported_auth_methods (PASBackend *backend, - PASBook *book, - PASGetSupportedAuthMethodsRequest *req); + PASBook *book); +GNOME_Evolution_Addressbook_CallStatus pas_backend_cancel_operation (PASBackend *backend, + PASBook *book); + +void pas_backend_start_book_view (PASBackend *backend, + PASBookView *view); + +void pas_backend_add_book_view (PASBackend *backend, + PASBookView *view); + +EList *pas_backend_get_book_views (PASBackend *backend); + +void pas_backend_notify_update (PASBackend *backend, + EContact *contact); +void pas_backend_notify_remove (PASBackend *backend, + const char *id); +void pas_backend_notify_complete (PASBackend *backend); GType pas_backend_get_type (void); @@ -135,6 +155,13 @@ void pas_backend_set_is_loaded (PASBackend *backen gboolean is_loaded); void pas_backend_set_is_writable (PASBackend *backend, gboolean is_writable); +void pas_backend_set_is_removed (PASBackend *backend, + gboolean is_removed); + +/* useful for implementing _get_changes in backends */ +GNOME_Evolution_Addressbook_BookChangeItem* pas_backend_change_add_new (const char *vcard); +GNOME_Evolution_Addressbook_BookChangeItem* pas_backend_change_modify_new (const char *vcard); +GNOME_Evolution_Addressbook_BookChangeItem* pas_backend_change_delete_new (const char *id); #endif /* ! __PAS_BACKEND_H__ */ diff --git a/addressbook/backend/pas/pas-book-factory.c b/addressbook/backend/pas/pas-book-factory.c index 2d6ed1e65b..34e97aa780 100644 --- a/addressbook/backend/pas/pas-book-factory.c +++ b/addressbook/backend/pas/pas-book-factory.c @@ -8,6 +8,7 @@ */ #include +#include #include #include "addressbook.h" @@ -15,21 +16,22 @@ #include "pas-marshal.h" #include #include +#include #define DEFAULT_PAS_BOOK_FACTORY_OAF_ID "OAFIID:GNOME_Evolution_Wombat_ServerFactory" static BonoboObjectClass *pas_book_factory_parent_class; typedef struct { - char *uri; - GNOME_Evolution_Addressbook_BookListener listener; + char *uri; + GNOME_Evolution_Addressbook_BookListener listener; } PASBookFactoryQueuedRequest; struct _PASBookFactoryPrivate { - gint idle_id; + GMutex *map_mutex; + GHashTable *backends; GHashTable *active_server_map; - GList *queued_requests; /* OAFIID of the factory */ char *iid; @@ -108,10 +110,16 @@ pas_book_factory_register_backend (PASBookFactory *factory, int pas_book_factory_get_n_backends (PASBookFactory *factory) { + int n_backends; + g_return_val_if_fail (factory != NULL, -1); g_return_val_if_fail (PAS_IS_BOOK_FACTORY (factory), -1); - return g_hash_table_size (factory->priv->active_server_map); + g_mutex_lock (factory->priv->map_mutex); + n_backends = g_hash_table_size (factory->priv->active_server_map); + g_mutex_unlock (factory->priv->map_mutex); + + return n_backends; } static void @@ -131,10 +139,11 @@ pas_book_factory_dump_active_backends (PASBookFactory *factory) { g_message ("Active PAS backends"); + g_mutex_lock (factory->priv->map_mutex); g_hash_table_foreach (factory->priv->active_server_map, dump_active_server_map_entry, NULL); - + g_mutex_unlock (factory->priv->map_mutex); } /* Callback used when a backend loses its last connected client */ @@ -154,6 +163,8 @@ backend_last_client_gone_cb (PASBackend *backend, gpointer data) gboolean result; char *orig_uri; + g_mutex_lock (factory->priv->map_mutex); + result = g_hash_table_lookup_extended (factory->priv->active_server_map, uri, &orig_key, NULL); g_assert (result != FALSE); @@ -165,13 +176,17 @@ backend_last_client_gone_cb (PASBackend *backend, gpointer data) g_object_unref (backend); - /* Notify upstream if there are no more backends */ + g_mutex_unlock (factory->priv->map_mutex); } - if (g_hash_table_size (factory->priv->active_server_map) == 0) + if (g_hash_table_size (factory->priv->active_server_map) == 0) { + /* Notify upstream if there are no more backends */ g_signal_emit (G_OBJECT (factory), factory_signals[LAST_BOOK_GONE], 0); + } } + + static PASBackendFactoryFn pas_book_factory_lookup_backend_factory (PASBookFactory *factory, const char *uri) @@ -203,52 +218,16 @@ pas_book_factory_lookup_backend_factory (PASBookFactory *factory, } static PASBackend * -pas_book_factory_launch_backend (PASBookFactory *factory, - GNOME_Evolution_Addressbook_BookListener listener, - const char *uri) +pas_book_factory_launch_backend (PASBookFactory *factory, + PASBackendFactoryFn backend_factory, + GNOME_Evolution_Addressbook_BookListener listener, + const char *uri) { - PASBackendFactoryFn backend_factory; PASBackend *backend; - backend_factory = pas_book_factory_lookup_backend_factory ( - factory, uri); - - if (!backend_factory) { - CORBA_Environment ev; - - CORBA_exception_init (&ev); - GNOME_Evolution_Addressbook_BookListener_notifyBookOpened ( - listener, - GNOME_Evolution_Addressbook_BookListener_ProtocolNotSupported, - CORBA_OBJECT_NIL, - &ev); - - if (ev._major != CORBA_NO_EXCEPTION) - g_message ("pas_book_factory_launch_backend(): could not notify " - "the listener"); - - CORBA_exception_free (&ev); - return NULL; - } - backend = (* backend_factory) (); - if (!backend) { - CORBA_Environment ev; - - CORBA_exception_init (&ev); - GNOME_Evolution_Addressbook_BookListener_notifyBookOpened ( - listener, - GNOME_Evolution_Addressbook_BookListener_OtherError, - CORBA_OBJECT_NIL, - &ev); - - if (ev._major != CORBA_NO_EXCEPTION) - g_message ("pas_book_factory_launch_backend(): could not notify " - "the listener"); - - CORBA_exception_free (&ev); + if (!backend) return NULL; - } g_hash_table_insert (factory->priv->active_server_map, g_strdup (uri), @@ -261,154 +240,63 @@ pas_book_factory_launch_backend (PASBookFactory *factory, return backend; } -static void -pas_book_factory_process_request (PASBookFactory *factory, - PASBookFactoryQueuedRequest *request) +static GNOME_Evolution_Addressbook_Book +impl_GNOME_Evolution_Addressbook_BookFactory_getBook (PortableServer_Servant servant, + const CORBA_char *uri, + const GNOME_Evolution_Addressbook_BookListener listener, + CORBA_Environment *ev) { + PASBookFactory *factory = PAS_BOOK_FACTORY (bonobo_object (servant)); PASBackend *backend; - char *uri; - GNOME_Evolution_Addressbook_BookListener listener; - CORBA_Environment ev; + PASBook *book; - uri = request->uri; - listener = request->listener; - g_free (request); + printf ("impl_GNOME_Evolution_Addressbook_BookFactory_getBook\n"); /* Look up the backend and create one if needed */ + g_mutex_lock (factory->priv->map_mutex); backend = g_hash_table_lookup (factory->priv->active_server_map, uri); if (!backend) { - GNOME_Evolution_Addressbook_BookListener_CallStatus status; - - backend = pas_book_factory_launch_backend (factory, listener, uri); - if (!backend) - goto out; + PASBackendFactoryFn backend_factory; - status = pas_backend_load_uri (backend, uri); - if (status != GNOME_Evolution_Addressbook_BookListener_Success) { - /* tell the listener that we failed to open the book */ - CORBA_exception_init (&ev); - - GNOME_Evolution_Addressbook_BookListener_notifyBookOpened ( - listener, status, - CORBA_OBJECT_NIL, - &ev); - - if (ev._major != CORBA_NO_EXCEPTION) { - g_warning ("pas_book_respond_open: Exception " - "responding to BookListener!\n"); - } + backend_factory = pas_book_factory_lookup_backend_factory (factory, uri); + + if (backend_factory == NULL) { + CORBA_exception_set (ev, CORBA_USER_EXCEPTION, + ex_GNOME_Evolution_Addressbook_BookFactory_ProtocolNotSupported, + NULL); - CORBA_exception_free (&ev); - - backend_last_client_gone_cb (backend, factory); + g_mutex_unlock (factory->priv->map_mutex); - goto out; + return CORBA_OBJECT_NIL; } - pas_backend_add_client (backend, listener); - - goto out; + backend = pas_book_factory_launch_backend (factory, backend_factory, listener, uri); } - pas_backend_add_client (backend, listener); + if (backend) { + GNOME_Evolution_Addressbook_BookListener listener_copy; - out: - g_free (uri); - - CORBA_exception_init (&ev); - CORBA_Object_release (listener, &ev); + listener_copy = bonobo_object_dup_ref (listener, NULL); - if (ev._major != CORBA_NO_EXCEPTION) - g_message ("pas_book_factory_process_request(): could not release the listener"); + g_mutex_unlock (factory->priv->map_mutex); - CORBA_exception_free (&ev); -} + book = pas_book_new (backend, uri, listener); -static gboolean -pas_book_factory_process_queue (PASBookFactory *factory) -{ - /* Process pending Book-creation requests. */ - if (factory->priv->queued_requests != NULL) { - PASBookFactoryQueuedRequest *request; - GList *l; + pas_backend_add_client (backend, book); - l = factory->priv->queued_requests; - request = l->data; - - pas_book_factory_process_request (factory, request); - - factory->priv->queued_requests = g_list_remove_link ( - factory->priv->queued_requests, l); - g_list_free_1 (l); - } - - if (factory->priv->queued_requests == NULL) { - - factory->priv->idle_id = 0; - return FALSE; - } - - return TRUE; -} - -static void -pas_book_factory_queue_request (PASBookFactory *factory, - const char *uri, - const GNOME_Evolution_Addressbook_BookListener listener) -{ - PASBookFactoryQueuedRequest *request; - GNOME_Evolution_Addressbook_BookListener listener_copy; - CORBA_Environment ev; - - CORBA_exception_init (&ev); - - listener_copy = CORBA_Object_duplicate (listener, &ev); - - if (ev._major != CORBA_NO_EXCEPTION) { - g_warning ("PASBookFactory: Could not duplicate BookListener!\n"); - CORBA_exception_free (&ev); - return; - } - - CORBA_exception_free (&ev); - - request = g_new0 (PASBookFactoryQueuedRequest, 1); - request->listener = listener_copy; - request->uri = g_strdup (uri); - - factory->priv->queued_requests = - g_list_prepend (factory->priv->queued_requests, request); - - if (! factory->priv->idle_id) { - factory->priv->idle_id = - g_idle_add ((GSourceFunc) pas_book_factory_process_queue, factory); + return bonobo_object_corba_objref (BONOBO_OBJECT (book)); } -} - -static void -impl_GNOME_Evolution_Addressbook_BookFactory_openBook (PortableServer_Servant servant, - const CORBA_char *uri, - const GNOME_Evolution_Addressbook_BookListener listener, - CORBA_Environment *ev) -{ - PASBookFactory *factory = PAS_BOOK_FACTORY (bonobo_object (servant)); - PASBackendFactoryFn backend_factory; - - backend_factory = pas_book_factory_lookup_backend_factory (factory, uri); - - if (backend_factory == NULL) { - GNOME_Evolution_Addressbook_BookListener_notifyBookOpened ( - listener, - GNOME_Evolution_Addressbook_BookListener_ProtocolNotSupported, - CORBA_OBJECT_NIL, - ev); - - return; + else { + /* probably need a more descriptive exception here */ + CORBA_exception_set (ev, CORBA_USER_EXCEPTION, + ex_GNOME_Evolution_Addressbook_BookFactory_ProtocolNotSupported, + NULL); + g_mutex_unlock (factory->priv->map_mutex); + + return CORBA_OBJECT_NIL; } - - pas_book_factory_queue_request (factory, uri, listener); } static void @@ -425,7 +313,9 @@ pas_book_factory_new (void) { PASBookFactory *factory; - factory = g_object_new (PAS_TYPE_BOOK_FACTORY, NULL); + factory = g_object_new (PAS_TYPE_BOOK_FACTORY, + "poa", bonobo_poa_get_threaded (ORBIT_THREAD_HINT_PER_REQUEST, NULL), + NULL); pas_book_factory_construct (factory); @@ -483,9 +373,9 @@ pas_book_factory_init (PASBookFactory *factory) { factory->priv = g_new0 (PASBookFactoryPrivate, 1); + factory->priv->map_mutex = g_mutex_new(); factory->priv->active_server_map = g_hash_table_new (g_str_hash, g_str_equal); factory->priv->backends = g_hash_table_new (g_str_hash, g_str_equal); - factory->priv->queued_requests = NULL; factory->priv->registered = FALSE; } @@ -518,22 +408,8 @@ pas_book_factory_dispose (GObject *object) if (factory->priv) { PASBookFactoryPrivate *priv = factory->priv; - GList *l; - for (l = priv->queued_requests; l != NULL; l = l->next) { - PASBookFactoryQueuedRequest *request = l->data; - CORBA_Environment ev; - - g_free (request->uri); - - CORBA_exception_init (&ev); - CORBA_Object_release (request->listener, &ev); - CORBA_exception_free (&ev); - - g_free (request); - } - g_list_free (priv->queued_requests); - priv->queued_requests = NULL; + g_mutex_free (priv->map_mutex); g_hash_table_foreach (priv->active_server_map, free_active_server_map_entry, @@ -585,7 +461,7 @@ pas_book_factory_class_init (PASBookFactoryClass *klass) epv = &klass->epv; - epv->openBook = impl_GNOME_Evolution_Addressbook_BookFactory_openBook; + epv->getBook = impl_GNOME_Evolution_Addressbook_BookFactory_getBook; } BONOBO_TYPE_FUNC_FULL ( diff --git a/addressbook/backend/pas/pas-book-view.c b/addressbook/backend/pas/pas-book-view.c index fce4173f0f..712997d258 100644 --- a/addressbook/backend/pas/pas-book-view.c +++ b/addressbook/backend/pas/pas-book-view.c @@ -6,158 +6,266 @@ */ #include +#include #include #include +#include "pas-backend.h" +#include "pas-backend-card-sexp.h" #include "pas-book-view.h" static BonoboObjectClass *pas_book_view_parent_class; struct _PASBookViewPrivate { GNOME_Evolution_Addressbook_BookViewListener listener; + +#define INITIAL_THRESHOLD 20 + GMutex *pending_mutex; + + CORBA_sequence_GNOME_Evolution_Addressbook_VCard adds; + int next_threshold; + int threshold_max; + + CORBA_sequence_GNOME_Evolution_Addressbook_VCard changes; + CORBA_sequence_GNOME_Evolution_Addressbook_ContactId removes; + + PASBackend *backend; + char *card_query; + PASBackendCardSExp *card_sexp; + GHashTable *ids; }; -/** - * pas_book_view_notify_change: - */ -void -pas_book_view_notify_change (PASBookView *book_view, - const GList *cards) +static void +send_pending_adds (PASBookView *book_view, gboolean reset) { CORBA_Environment ev; - gint i, length; - CORBA_sequence_GNOME_Evolution_Addressbook_VCard card_sequence; + CORBA_sequence_GNOME_Evolution_Addressbook_VCard *adds; + + adds = &book_view->priv->adds; + if (adds->_length == 0) + return; - length = g_list_length((GList *) cards); + CORBA_exception_init (&ev); - card_sequence._buffer = CORBA_sequence_GNOME_Evolution_Addressbook_VCard_allocbuf(length); - card_sequence._maximum = length; - card_sequence._length = length; + GNOME_Evolution_Addressbook_BookViewListener_notifyContactsAdded ( + book_view->priv->listener, adds, &ev); - for ( i = 0; cards; cards = g_list_next(cards), i++ ) { - card_sequence._buffer[i] = CORBA_string_dup((char *) cards->data); + if (ev._major != CORBA_NO_EXCEPTION) { + g_warning ("send_pending_adds: Exception signaling BookViewListener!\n"); } + CORBA_exception_free (&ev); + + CORBA_free (adds->_buffer); + adds->_buffer = NULL; + adds->_maximum = 0; + adds->_length = 0; + + if (reset) + book_view->priv->next_threshold = INITIAL_THRESHOLD; +} + +static void +send_pending_changes (PASBookView *book_view) +{ + CORBA_Environment ev; + CORBA_sequence_GNOME_Evolution_Addressbook_VCard *changes; + + changes = &book_view->priv->changes; + if (changes->_length == 0) + return; + CORBA_exception_init (&ev); - GNOME_Evolution_Addressbook_BookViewListener_notifyCardChanged ( - book_view->priv->listener, &card_sequence, &ev); + GNOME_Evolution_Addressbook_BookViewListener_notifyContactsChanged ( + book_view->priv->listener, changes, &ev); if (ev._major != CORBA_NO_EXCEPTION) { - g_warning ("pas_book_view_notify_change: Exception signaling BookViewListener!\n"); + g_warning ("send_pending_changes: Exception signaling BookViewListener!\n"); } CORBA_exception_free (&ev); - CORBA_free(card_sequence._buffer); + CORBA_free (changes->_buffer); + changes->_buffer = NULL; + changes->_maximum = 0; + changes->_length = 0; } -void -pas_book_view_notify_change_1 (PASBookView *book_view, - const char *card) +static void +send_pending_removes (PASBookView *book_view) { - GList *list = g_list_append(NULL, (char *) card); - pas_book_view_notify_change(book_view, list); - g_list_free(list); + CORBA_Environment ev; + CORBA_sequence_GNOME_Evolution_Addressbook_VCard *removes; + + removes = &book_view->priv->removes; + if (removes->_length == 0) + return; + + CORBA_exception_init (&ev); + + GNOME_Evolution_Addressbook_BookViewListener_notifyContactsRemoved ( + book_view->priv->listener, removes, &ev); + + if (ev._major != CORBA_NO_EXCEPTION) { + g_warning ("send_pending_removes: Exception signaling BookViewListener!\n"); + } + + CORBA_exception_free (&ev); + + CORBA_free (removes->_buffer); + removes->_buffer = NULL; + removes->_maximum = 0; + removes->_length = 0; } -/** - * pas_book_view_notify_remove: - */ -void -pas_book_view_notify_remove_1 (PASBookView *book_view, - const char *id) +#define MAKE_REALLOC(type) \ +static void \ +CORBA_sequence_ ## type ## _realloc (CORBA_sequence_ ## type *seq, \ + CORBA_unsigned_long new_max) \ +{ \ + type *new_buf; \ + \ + new_buf = CORBA_sequence_ ## type ## _allocbuf (new_max); \ + memcpy (new_buf, seq->_buffer, seq->_maximum * sizeof (type)); \ + CORBA_free (seq->_buffer); \ + seq->_buffer = new_buf; \ + seq->_maximum = new_max; \ +} + +MAKE_REALLOC (GNOME_Evolution_Addressbook_VCard) +MAKE_REALLOC (GNOME_Evolution_Addressbook_ContactId) + +static void +notify_change (PASBookView *book_view, const char *vcard) { - GList *ids = NULL; + CORBA_sequence_GNOME_Evolution_Addressbook_VCard *changes; + + send_pending_adds (book_view, TRUE); + send_pending_removes (book_view); - ids = g_list_prepend (ids, (char*)id); + changes = &book_view->priv->changes; - pas_book_view_notify_remove (book_view, ids); + if (changes->_length == changes->_maximum) { + CORBA_sequence_GNOME_Evolution_Addressbook_VCard_realloc ( + changes, 2 * (changes->_maximum + 1)); + } - g_list_free (ids); + changes->_buffer[changes->_length++] = CORBA_string_dup (vcard); } -void -pas_book_view_notify_remove (PASBookView *book_view, - const GList *ids) +static void +notify_remove (PASBookView *book_view, const char *id) { - GNOME_Evolution_Addressbook_CardIdList idlist; - CORBA_Environment ev; - const GList *l; - int num_ids, i; + CORBA_sequence_GNOME_Evolution_Addressbook_ContactId *removes; - CORBA_exception_init (&ev); + send_pending_adds (book_view, TRUE); + send_pending_changes (book_view); - num_ids = g_list_length ((GList*)ids); - idlist._buffer = CORBA_sequence_GNOME_Evolution_Addressbook_CardId_allocbuf (num_ids); - idlist._maximum = num_ids; - idlist._length = num_ids; + removes = &book_view->priv->removes; - for (l = ids, i = 0; l; l=l->next, i ++) { - idlist._buffer[i] = CORBA_string_dup (l->data); + if (removes->_length == removes->_maximum) { + CORBA_sequence_GNOME_Evolution_Addressbook_ContactId_realloc ( + removes, 2 * (removes->_maximum + 1)); } - GNOME_Evolution_Addressbook_BookViewListener_notifyCardsRemoved ( - book_view->priv->listener, &idlist, &ev); + removes->_buffer[removes->_length++] = CORBA_string_dup (id); + g_hash_table_remove (book_view->priv->ids, id); +} - if (ev._major != CORBA_NO_EXCEPTION) { - g_warning ("pas_book_view_notify_remove: Exception signaling BookViewListener!\n"); - } +static void +notify_add (PASBookView *book_view, const char *id, const char *vcard) +{ + CORBA_sequence_GNOME_Evolution_Addressbook_VCard *adds; + PASBookViewPrivate *priv = book_view->priv; - CORBA_free(idlist._buffer); + send_pending_changes (book_view); + send_pending_removes (book_view); - CORBA_exception_free (&ev); + adds = &priv->adds; + + if (adds->_length == adds->_maximum) { + send_pending_adds (book_view, FALSE); + + adds->_buffer = CORBA_sequence_GNOME_Evolution_Addressbook_VCard_allocbuf (priv->next_threshold); + adds->_maximum = priv->next_threshold; + + if (priv->next_threshold < priv->threshold_max) { + priv->next_threshold = MIN (2 * priv->next_threshold, + priv->threshold_max); + } + } + + adds->_buffer[adds->_length++] = CORBA_string_dup (vcard); + g_hash_table_insert (book_view->priv->ids, g_strdup (id), + GUINT_TO_POINTER (1)); } /** - * pas_book_view_notify_add: + * pas_book_view_notify_update: */ void -pas_book_view_notify_add (PASBookView *book_view, - const GList *cards) +pas_book_view_notify_update (PASBookView *book_view, + EContact *contact) { - CORBA_Environment ev; - gint i, length; - CORBA_sequence_GNOME_Evolution_Addressbook_VCard card_sequence; + gboolean currently_in_view, want_in_view; + const char *id; + char *vcard; - length = g_list_length((GList *)cards); + g_mutex_lock (book_view->priv->pending_mutex); - card_sequence._buffer = CORBA_sequence_GNOME_Evolution_Addressbook_VCard_allocbuf(length); - card_sequence._maximum = length; - card_sequence._length = length; + id = e_contact_get_const (contact, E_CONTACT_UID); - for ( i = 0; cards; cards = g_list_next(cards), i++ ) { - card_sequence._buffer[i] = CORBA_string_dup((char *) cards->data); - } + currently_in_view = + g_hash_table_lookup (book_view->priv->ids, id) != NULL; + want_in_view = pas_backend_card_sexp_match_contact ( + book_view->priv->card_sexp, contact); - CORBA_exception_init (&ev); + if (want_in_view) { + vcard = e_vcard_to_string (E_VCARD (contact), + EVC_FORMAT_VCARD_30); - GNOME_Evolution_Addressbook_BookViewListener_notifyCardAdded ( - book_view->priv->listener, &card_sequence, &ev); + if (currently_in_view) + notify_change (book_view, vcard); + else + notify_add (book_view, id, vcard); - if (ev._major != CORBA_NO_EXCEPTION) { - g_warning ("pas_book_view_notify_add: Exception signaling BookViewListener!\n"); + g_free (vcard); + } else { + if (currently_in_view) + pas_book_view_notify_remove (book_view, id); + /* else nothing; we're removing a card that wasn't there */ } - CORBA_exception_free (&ev); - - CORBA_free(card_sequence._buffer); + g_mutex_unlock (book_view->priv->pending_mutex); } +/** + * pas_book_view_notify_remove: + */ void -pas_book_view_notify_add_1 (PASBookView *book_view, - const char *card) +pas_book_view_notify_remove (PASBookView *book_view, + const char *id) { - GList *list = g_list_append(NULL, (char *) card); - pas_book_view_notify_add(book_view, list); - g_list_free(list); + g_mutex_lock (book_view->priv->pending_mutex); + notify_remove (book_view, id); + g_mutex_unlock (book_view->priv->pending_mutex); } + void pas_book_view_notify_complete (PASBookView *book_view, - GNOME_Evolution_Addressbook_BookViewListener_CallStatus status) + GNOME_Evolution_Addressbook_CallStatus status) { CORBA_Environment ev; + g_mutex_lock (book_view->priv->pending_mutex); + + send_pending_adds (book_view, TRUE); + send_pending_changes (book_view); + send_pending_removes (book_view); + + g_mutex_unlock (book_view->priv->pending_mutex); + CORBA_exception_init (&ev); GNOME_Evolution_Addressbook_BookViewListener_notifySequenceComplete ( @@ -178,8 +286,8 @@ pas_book_view_notify_status_message (PASBookView *book_view, CORBA_exception_init (&ev); - GNOME_Evolution_Addressbook_BookViewListener_notifyStatusMessage ( - book_view->priv->listener, message, &ev); + GNOME_Evolution_Addressbook_BookViewListener_notifyProgress ( + book_view->priv->listener, message, 0, &ev); if (ev._major != CORBA_NO_EXCEPTION) { g_warning ("pas_book_view_notify_status_message: Exception signaling BookViewListener!\n"); @@ -190,7 +298,10 @@ pas_book_view_notify_status_message (PASBookView *book_view, static void pas_book_view_construct (PASBookView *book_view, - GNOME_Evolution_Addressbook_BookViewListener listener) + PASBackend *backend, + GNOME_Evolution_Addressbook_BookViewListener listener, + const char *card_query, + PASBackendCardSExp *card_sexp) { PASBookViewPrivate *priv; CORBA_Environment ev; @@ -202,29 +313,70 @@ pas_book_view_construct (PASBookView *book_view, CORBA_exception_init (&ev); - bonobo_object_dup_ref (listener, &ev); + priv->listener = CORBA_Object_duplicate (listener, &ev); if (ev._major != CORBA_NO_EXCEPTION) { - g_warning("Unable to duplicate & ref listener object in pas-book-view.c\n"); + g_warning("Unable to duplicate listener object in pas-book-view.c\n"); CORBA_exception_free (&ev); return; } CORBA_exception_free (&ev); - priv->listener = listener; + priv->backend = backend; + priv->card_query = g_strdup (card_query); + priv->card_sexp = card_sexp; +} + +/** + * pas_book_view_new: + */ +static void +impl_GNOME_Evolution_Addressbook_BookView_start (PortableServer_Servant servant, + CORBA_Environment *ev) +{ + PASBookView *view = PAS_BOOK_VIEW (bonobo_object (servant)); + + pas_backend_start_book_view (pas_book_view_get_backend (view), view); +} + +/** + * pas_book_view_get_card_query + */ +const char* +pas_book_view_get_card_query (PASBookView *book_view) +{ + return book_view->priv->card_query; +} + +/** + * pas_book_view_get_card_sexp + */ +PASBackendCardSExp* +pas_book_view_get_card_sexp (PASBookView *book_view) +{ + return book_view->priv->card_sexp; +} + +PASBackend* +pas_book_view_get_backend (PASBookView *book_view) +{ + return book_view->priv->backend; } /** * pas_book_view_new: */ PASBookView * -pas_book_view_new (GNOME_Evolution_Addressbook_BookViewListener listener) +pas_book_view_new (PASBackend *backend, + GNOME_Evolution_Addressbook_BookViewListener listener, + const char *card_query, + PASBackendCardSExp *card_sexp) { PASBookView *book_view; book_view = g_object_new (PAS_TYPE_BOOK_VIEW, NULL); - pas_book_view_construct (book_view, listener); + pas_book_view_construct (book_view, backend, listener, card_query, card_sexp); return book_view; } @@ -237,6 +389,19 @@ pas_book_view_dispose (GObject *object) if (book_view->priv) { bonobo_object_release_unref (book_view->priv->listener, NULL); + if (book_view->priv->adds._buffer) + CORBA_free (book_view->priv->adds._buffer); + if (book_view->priv->changes._buffer) + CORBA_free (book_view->priv->changes._buffer); + if (book_view->priv->removes._buffer) + CORBA_free (book_view->priv->removes._buffer); + + g_free (book_view->priv->card_query); + g_object_unref (book_view->priv->card_sexp); + + g_mutex_free (book_view->priv->pending_mutex); + book_view->priv->pending_mutex = NULL; + g_free (book_view->priv); book_view->priv = NULL; } @@ -249,17 +414,30 @@ static void pas_book_view_class_init (PASBookViewClass *klass) { GObjectClass *object_class = G_OBJECT_CLASS (klass); + POA_GNOME_Evolution_Addressbook_BookView__epv *epv; pas_book_view_parent_class = g_type_class_peek_parent (klass); object_class->dispose = pas_book_view_dispose; + + epv = &klass->epv; + + epv->start = impl_GNOME_Evolution_Addressbook_BookView_start; + } static void pas_book_view_init (PASBookView *book_view) { - book_view->priv = g_new0 (PASBookViewPrivate, 1); - book_view->priv->listener = CORBA_OBJECT_NIL; + book_view->priv = g_new0 (PASBookViewPrivate, 1); + + book_view->priv->pending_mutex = g_mutex_new(); + + book_view->priv->next_threshold = INITIAL_THRESHOLD; + book_view->priv->threshold_max = 3000; + + book_view->priv->ids = g_hash_table_new_full (g_str_hash, g_str_equal, + g_free, NULL); } BONOBO_TYPE_FUNC_FULL ( diff --git a/addressbook/backend/pas/pas-book-view.h b/addressbook/backend/pas/pas-book-view.h index dd6c74c596..0cacab6bf0 100644 --- a/addressbook/backend/pas/pas-book-view.h +++ b/addressbook/backend/pas/pas-book-view.h @@ -16,6 +16,8 @@ #include #include #include +#include +#include #define PAS_TYPE_BOOK_VIEW (pas_book_view_get_type ()) #define PAS_BOOK_VIEW(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), PAS_TYPE_BOOK_VIEW, PASBookView)) @@ -24,8 +26,6 @@ #define PAS_IS_BOOK_VIEW_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), PAS_TYPE_BOOK_VIEW)) #define PAS_BOOK_VIEW_GET_CLASS(k) (G_TYPE_INSTANCE_GET_CLASS ((obj), PAS_TYPE_BOOK_VIEW, PASBookView)) -typedef struct _PASBookView PASBookView; -typedef struct _PASBookViewClass PASBookViewClass; typedef struct _PASBookViewPrivate PASBookViewPrivate; struct _PASBookView { @@ -40,25 +40,24 @@ struct _PASBookViewClass { }; -PASBookView *pas_book_view_new (GNOME_Evolution_Addressbook_BookViewListener listener); +PASBookView *pas_book_view_new (PASBackend *backend, + GNOME_Evolution_Addressbook_BookViewListener listener, + const char *card_query, + PASBackendCardSExp *card_sexp); -void pas_book_view_notify_change (PASBookView *book_view, - const GList *cards); -void pas_book_view_notify_change_1 (PASBookView *book_view, - const char *card); +const char* pas_book_view_get_card_query (PASBookView *book_view); +PASBackendCardSExp* pas_book_view_get_card_sexp (PASBookView *book_view); +PASBackend* pas_book_view_get_backend (PASBookView *book_view); + +void pas_book_view_notify_update (PASBookView *book_view, + EContact *contact); void pas_book_view_notify_remove (PASBookView *book_view, - const GList *ids); -void pas_book_view_notify_remove_1 (PASBookView *book_view, const char *id); -void pas_book_view_notify_add (PASBookView *book_view, - const GList *cards); -void pas_book_view_notify_add_1 (PASBookView *book_view, - const char *card); void pas_book_view_notify_complete (PASBookView *book_view, - GNOME_Evolution_Addressbook_BookViewListener_CallStatus); + GNOME_Evolution_Addressbook_CallStatus); void pas_book_view_notify_status_message (PASBookView *book_view, const char *message); -GType pas_book_view_get_type (void); +GType pas_book_view_get_type (void); #endif /* ! __PAS_BOOK_VIEW_H__ */ diff --git a/addressbook/backend/pas/pas-book.c b/addressbook/backend/pas/pas-book.c index dc626e59e1..7b6e0c9a2b 100644 --- a/addressbook/backend/pas/pas-book.c +++ b/addressbook/backend/pas/pas-book.c @@ -7,261 +7,68 @@ #include #include +#include #include "e-util/e-list.h" +#include "ebook/e-contact.h" +#include "pas-book-view.h" #include "pas-backend.h" +#include "pas-backend-card-sexp.h" #include "pas-marshal.h" static BonoboObjectClass *pas_book_parent_class; POA_GNOME_Evolution_Addressbook_Book__vepv pas_book_vepv; -enum { - REQUESTS_QUEUED, - LAST_SIGNAL -}; - -static guint pas_book_signals [LAST_SIGNAL]; - struct _PASBookPrivate { - PASBackend *backend; + PASBackend *backend; GNOME_Evolution_Addressbook_BookListener listener; - - GList *request_queue; - gint timeout_id; - - guint timeout_lock : 1; + char *uri; }; -static gboolean -pas_book_check_queue (PASBook *book) -{ - if (book->priv->timeout_lock) - return TRUE; - - book->priv->timeout_lock = TRUE; - - if (book->priv->request_queue != NULL) { - g_signal_emit (book, pas_book_signals [REQUESTS_QUEUED], 0); - } - - if (book->priv->request_queue == NULL) { - book->priv->timeout_id = 0; - book->priv->timeout_lock = FALSE; - bonobo_object_unref (BONOBO_OBJECT (book)); - return FALSE; - } - - book->priv->timeout_lock = FALSE; - - return TRUE; -} - -static void -pas_book_queue_request (PASBook *book, PASRequest *req) -{ - book->priv->request_queue = - g_list_append (book->priv->request_queue, req); - - if (book->priv->timeout_id == 0) { - bonobo_object_ref (BONOBO_OBJECT (book)); - book->priv->timeout_id = g_timeout_add (20, (GSourceFunc) pas_book_check_queue, book); - } -} - -static void -pas_book_queue_create_card (PASBook *book, const char *vcard) -{ - PASRequest *req; - - req = g_new0 (PASRequest, 1); - req->op = CreateCard; - req->create.vcard = g_strdup (vcard); - - pas_book_queue_request (book, req); -} - -static void -pas_book_queue_remove_cards (PASBook *book, - const GNOME_Evolution_Addressbook_CardIdList *ids) -{ - PASRequest *req; - int i; - - req = g_new0 (PASRequest, 1); - req->op = RemoveCards; - req->remove.ids = NULL; - - for (i = 0; i < ids->_length; i ++) { - req->remove.ids = g_list_append (req->remove.ids, g_strdup (ids->_buffer[i])); - } - - pas_book_queue_request (book, req); -} - -static void -pas_book_queue_modify_card (PASBook *book, const char *vcard) -{ - PASRequest *req; - - req = g_new0 (PASRequest, 1); - req->op = ModifyCard; - req->modify.vcard = g_strdup (vcard); - - pas_book_queue_request (book, req); -} - -static void -pas_book_queue_get_cursor (PASBook *book, const char *search) -{ - PASRequest *req; - - req = g_new0 (PASRequest, 1); - req->op = GetCursor; - req->get_cursor.search = g_strdup(search); - - pas_book_queue_request (book, req); -} - -static void -pas_book_queue_get_vcard (PASBook *book, const char *id) -{ - PASRequest *req; - - req = g_new0 (PASRequest, 1); - req->op = GetVCard; - req->get_vcard.id = g_strdup(id); - - pas_book_queue_request (book, req); -} - -static void -pas_book_queue_authenticate_user (PASBook *book, - const char *user, const char *passwd, const char *auth_method) -{ - PASRequest *req; - - req = g_new0 (PASRequest, 1); - req->op = AuthenticateUser; - req->auth_user.user = g_strdup(user); - req->auth_user.passwd = g_strdup(passwd); - req->auth_user.auth_method = g_strdup(auth_method); - - pas_book_queue_request (book, req); -} - -static void -pas_book_queue_get_supported_fields (PASBook *book) -{ - PASRequest *req; - - req = g_new0 (PASRequest, 1); - req->op = GetSupportedFields; - - pas_book_queue_request (book, req); -} - -static void -pas_book_queue_get_supported_auth_methods (PASBook *book) -{ - PASRequest *req; - - req = g_new0 (PASRequest, 1); - req->op = GetSupportedAuthMethods; - - pas_book_queue_request (book, req); -} - - static void -pas_book_queue_get_book_view (PASBook *book, const GNOME_Evolution_Addressbook_BookViewListener listener, const char *search) +impl_GNOME_Evolution_Addressbook_Book_open (PortableServer_Servant servant, + const CORBA_boolean only_if_exists, + CORBA_Environment *ev) { - PASRequest *req; - CORBA_Environment ev; - - req = g_new0 (PASRequest, 1); - req->op = GetBookView; - 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_book_view: Exception " - "duplicating BookViewListener!\n"); - } + PASBook *book = PAS_BOOK (bonobo_object (servant)); - CORBA_exception_free (&ev); + printf ("impl_GNOME_Evolution_Addressbook_Book_open\n"); - pas_book_queue_request (book, req); + pas_backend_open (pas_book_get_backend (book), book, only_if_exists); } static void -pas_book_queue_get_completion_view (PASBook *book, const GNOME_Evolution_Addressbook_BookViewListener listener, const char *search) +impl_GNOME_Evolution_Addressbook_Book_remove (PortableServer_Servant servant, + CORBA_Environment *ev) { - 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"); - } + PASBook *book = PAS_BOOK (bonobo_object (servant)); - CORBA_exception_free (&ev); + printf ("impl_GNOME_Evolution_Addressbook_Book_open\n"); - pas_book_queue_request (book, req); + pas_backend_remove (pas_book_get_backend (book), book); } static void -pas_book_queue_get_changes (PASBook *book, const GNOME_Evolution_Addressbook_BookViewListener listener, const char *change_id) -{ - PASRequest *req; - CORBA_Environment ev; - - req = g_new0 (PASRequest, 1); - req->op = GetChanges; - req->get_changes.change_id= g_strdup(change_id); - - CORBA_exception_init (&ev); - - req->get_changes.listener = bonobo_object_dup_ref(listener, &ev); - - if (ev._major != CORBA_NO_EXCEPTION) { - g_warning ("pas_book_queue_get_changes: Exception " - "duplicating BookViewListener!\n"); - } - - CORBA_exception_free (&ev); - - pas_book_queue_request (book, req); -} - -static void -pas_book_queue_check_connection (PASBook *book) +impl_GNOME_Evolution_Addressbook_Book_getContact (PortableServer_Servant servant, + const CORBA_char *id, + CORBA_Environment *ev) { - PASRequest *req; + PASBook *book = PAS_BOOK (bonobo_object (servant)); - req = g_new0 (PASRequest, 1); - req->op = CheckConnection; + printf ("impl_GNOME_Evolution_Addressbook_Book_getContact\n"); - pas_book_queue_request (book, req); + pas_backend_get_contact (pas_book_get_backend (book), book, id); } static void -impl_GNOME_Evolution_Addressbook_Book_getVCard (PortableServer_Servant servant, - const CORBA_char *id, - CORBA_Environment *ev) +impl_GNOME_Evolution_Addressbook_Book_getContactList (PortableServer_Servant servant, + const CORBA_char *query, + CORBA_Environment *ev) { PASBook *book = PAS_BOOK (bonobo_object (servant)); - pas_book_queue_get_vcard (book, id); + printf ("impl_GNOME_Evolution_Addressbook_Book_getContactList\n"); + + pas_backend_get_contact_list (pas_book_get_backend (book), book, query); } static void @@ -273,90 +80,97 @@ impl_GNOME_Evolution_Addressbook_Book_authenticateUser (PortableServer_Servant s { PASBook *book = PAS_BOOK (bonobo_object (servant)); - pas_book_queue_authenticate_user (book, user, passwd, auth_method); + pas_backend_authenticate_user (pas_book_get_backend (book), book, + user, passwd, auth_method); } static void -impl_GNOME_Evolution_Addressbook_Book_addCard (PortableServer_Servant servant, - const CORBA_char *vcard, - CORBA_Environment *ev) +impl_GNOME_Evolution_Addressbook_Book_addContact (PortableServer_Servant servant, + const CORBA_char *vcard, + CORBA_Environment *ev) { PASBook *book = PAS_BOOK (bonobo_object (servant)); - pas_book_queue_create_card (book, (const char *) vcard); + pas_backend_create_contact (pas_book_get_backend (book), book, vcard); } static void -impl_GNOME_Evolution_Addressbook_Book_removeCards (PortableServer_Servant servant, - const GNOME_Evolution_Addressbook_CardIdList *ids, - CORBA_Environment *ev) +impl_GNOME_Evolution_Addressbook_Book_removeContacts (PortableServer_Servant servant, + const GNOME_Evolution_Addressbook_ContactIdList *ids, + CORBA_Environment *ev) { PASBook *book = PAS_BOOK (bonobo_object (servant)); + int i; + GList *id_list = NULL; + + for (i = 0; i < ids->_length; i ++) + id_list = g_list_append (id_list, ids->_buffer[i]); - pas_book_queue_remove_cards (book, ids); -} - -static void -impl_GNOME_Evolution_Addressbook_Book_modifyCard (PortableServer_Servant servant, - const CORBA_char *vcard, - CORBA_Environment *ev) -{ - PASBook *book = PAS_BOOK (bonobo_object (servant)); + pas_backend_remove_contacts (pas_book_get_backend (book), book, id_list); - pas_book_queue_modify_card (book, (const char *) vcard); + g_list_free (id_list); } static void -impl_GNOME_Evolution_Addressbook_Book_getCursor (PortableServer_Servant servant, - const CORBA_char *search, - CORBA_Environment *ev) +impl_GNOME_Evolution_Addressbook_Book_modifyContact (PortableServer_Servant servant, + const CORBA_char *vcard, + CORBA_Environment *ev) { PASBook *book = PAS_BOOK (bonobo_object (servant)); - pas_book_queue_get_cursor (book, search); + pas_backend_modify_contact (pas_book_get_backend (book), book, vcard); } static void impl_GNOME_Evolution_Addressbook_Book_getBookView (PortableServer_Servant servant, const GNOME_Evolution_Addressbook_BookViewListener listener, const CORBA_char *search, + const GNOME_Evolution_Addressbook_stringlist* requested_fields, + const CORBA_long max_results, CORBA_Environment *ev) { PASBook *book = PAS_BOOK (bonobo_object (servant)); + PASBackend *backend = pas_book_get_backend (book); + PASBackendCardSExp *card_sexp; + PASBookView *view; - pas_book_queue_get_book_view (book, listener, search); -} + g_warning ("impl_GNOME_Evolution_Addressbook_Book_getBookView (%s)\n", search); + /* we handle this entirely here, since it doesn't require any + backend involvement now that we have pas_book_view_start to + actually kick off the 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 (servant)); + card_sexp = pas_backend_card_sexp_new (search); + if (!card_sexp) { + pas_book_respond_get_book_view (book, GNOME_Evolution_Addressbook_InvalidQuery, NULL); + return; + } + + view = pas_book_view_new (backend, listener, search, card_sexp); - pas_book_queue_get_completion_view (book, listener, search); + if (!view) { + g_object_unref (card_sexp); + pas_book_respond_get_book_view (book, GNOME_Evolution_Addressbook_OtherError, NULL); + return; + } + + + pas_backend_add_book_view (backend, view); + + pas_book_respond_get_book_view (book, GNOME_Evolution_Addressbook_Success, view); + + g_object_unref (view); } + static void impl_GNOME_Evolution_Addressbook_Book_getChanges (PortableServer_Servant servant, - const GNOME_Evolution_Addressbook_BookViewListener listener, const CORBA_char *change_id, CORBA_Environment *ev) { PASBook *book = PAS_BOOK (bonobo_object (servant)); - pas_book_queue_get_changes (book, listener, change_id); -} - -static void -impl_GNOME_Evolution_Addressbook_Book_checkConnection (PortableServer_Servant servant, - CORBA_Environment *ev) -{ - PASBook *book = PAS_BOOK (bonobo_object (servant)); - - pas_book_queue_check_connection (book); + pas_backend_get_changes (pas_book_get_backend (book), book, change_id); } static char * @@ -379,7 +193,7 @@ impl_GNOME_Evolution_Addressbook_Book_getSupportedFields (PortableServer_Servant { PASBook *book = PAS_BOOK (bonobo_object (servant)); - pas_book_queue_get_supported_fields (book); + pas_backend_get_supported_fields (pas_book_get_backend (book), book); } static void @@ -388,7 +202,16 @@ impl_GNOME_Evolution_Addressbook_Book_getSupportedAuthMethods (PortableServer_Se { PASBook *book = PAS_BOOK (bonobo_object (servant)); - pas_book_queue_get_supported_auth_methods (book); + pas_backend_get_supported_auth_methods (pas_book_get_backend (book), book); +} + +static GNOME_Evolution_Addressbook_CallStatus +impl_GNOME_Evolution_Addressbook_Book_cancelOperation (PortableServer_Servant servant, + CORBA_Environment *ev) +{ + PASBook *book = PAS_BOOK (bonobo_object (servant)); + + return pas_backend_cancel_operation (pas_book_get_backend (book), book); } /** @@ -397,87 +220,59 @@ impl_GNOME_Evolution_Addressbook_Book_getSupportedAuthMethods (PortableServer_Se PASBackend * pas_book_get_backend (PASBook *book) { - g_return_val_if_fail (book != NULL, NULL); - g_return_val_if_fail (PAS_IS_BOOK (book), NULL); + g_return_val_if_fail (book && PAS_IS_BOOK (book), NULL); return book->priv->backend; } -/** - * pas_book_get_listener: - */ GNOME_Evolution_Addressbook_BookListener pas_book_get_listener (PASBook *book) { - g_return_val_if_fail (book != NULL, CORBA_OBJECT_NIL); - g_return_val_if_fail (PAS_IS_BOOK (book), CORBA_OBJECT_NIL); + g_return_val_if_fail (book && PAS_IS_BOOK (book), CORBA_OBJECT_NIL); return book->priv->listener; } -/** - * pas_book_check_pending - */ -gint -pas_book_check_pending (PASBook *book) +const char* +pas_book_get_uri (PASBook *book) { - g_return_val_if_fail (book != NULL, -1); - g_return_val_if_fail (PAS_IS_BOOK (book), -1); - - return g_list_length (book->priv->request_queue); + return book->priv->uri; } /** - * pas_book_pop_request: + * pas_book_respond_open: */ -PASRequest * -pas_book_pop_request (PASBook *book) +void +pas_book_respond_open (PASBook *book, + GNOME_Evolution_Addressbook_CallStatus status) { - GList *popped; - PASRequest *req; - - g_return_val_if_fail (book != NULL, NULL); - g_return_val_if_fail (PAS_IS_BOOK (book), NULL); - - if (book->priv->request_queue == NULL) - return NULL; - - req = book->priv->request_queue->data; + CORBA_Environment ev; - popped = book->priv->request_queue; - book->priv->request_queue = - g_list_remove_link (book->priv->request_queue, popped); + CORBA_exception_init (&ev); + GNOME_Evolution_Addressbook_BookListener_notifyBookOpened (book->priv->listener, status, &ev); - g_list_free_1 (popped); + if (ev._major != CORBA_NO_EXCEPTION) { + g_warning ("pas_book_respond_open: Exception " + "responding to BookListener!\n"); + } - return req; + CORBA_exception_free (&ev); } /** - * pas_book_respond_open: + * pas_book_respond_remove: */ void -pas_book_respond_open (PASBook *book, - GNOME_Evolution_Addressbook_BookListener_CallStatus status) +pas_book_respond_remove (PASBook *book, + GNOME_Evolution_Addressbook_CallStatus status) { CORBA_Environment ev; CORBA_exception_init (&ev); - - if (status == GNOME_Evolution_Addressbook_BookListener_Success) { - GNOME_Evolution_Addressbook_BookListener_notifyBookOpened ( - book->priv->listener, status, - bonobo_object_corba_objref (BONOBO_OBJECT (book)), - &ev); - } else { - GNOME_Evolution_Addressbook_BookListener_notifyBookOpened ( - book->priv->listener, status, - CORBA_OBJECT_NIL, &ev); - } - + GNOME_Evolution_Addressbook_BookListener_notifyBookRemoved (book->priv->listener, status, &ev); if (ev._major != CORBA_NO_EXCEPTION) { - g_warning ("pas_book_respond_open: Exception " + g_warning ("pas_book_respond_remove: Exception " "responding to BookListener!\n"); } @@ -488,16 +283,22 @@ pas_book_respond_open (PASBook *book, * pas_book_respond_create: */ void -pas_book_respond_create (PASBook *book, - GNOME_Evolution_Addressbook_BookListener_CallStatus status, - const char *id) +pas_book_respond_create (PASBook *book, + GNOME_Evolution_Addressbook_CallStatus status, + EContact *contact) { CORBA_Environment ev; + if (status == GNOME_Evolution_Addressbook_Success) { + pas_backend_notify_update (book->priv->backend, contact); + pas_backend_notify_complete (book->priv->backend); + } + CORBA_exception_init (&ev); - GNOME_Evolution_Addressbook_BookListener_notifyCardCreated ( - book->priv->listener, status, (char *)id, &ev); + GNOME_Evolution_Addressbook_BookListener_notifyContactCreated ( + book->priv->listener, status, + e_contact_get (contact, E_CONTACT_UID), &ev); if (ev._major != CORBA_NO_EXCEPTION) { g_warning ("pas_book_respond_create: Exception " @@ -508,17 +309,25 @@ pas_book_respond_create (PASBook *book, } /** - * pas_book_respond_remove: + * pas_book_respond_remove_contacts: */ void -pas_book_respond_remove (PASBook *book, - GNOME_Evolution_Addressbook_BookListener_CallStatus status) +pas_book_respond_remove_contacts (PASBook *book, + GNOME_Evolution_Addressbook_CallStatus status, + GList *ids) { CORBA_Environment ev; + GList *i; CORBA_exception_init (&ev); - GNOME_Evolution_Addressbook_BookListener_notifyCardsRemoved ( + if (ids) { + for (i = ids; i; i = i->next) + pas_backend_notify_remove (book->priv->backend, i->data); + pas_backend_notify_complete (book->priv->backend); + } + + GNOME_Evolution_Addressbook_BookListener_notifyContactsRemoved ( book->priv->listener, status, &ev); if (ev._major != CORBA_NO_EXCEPTION) { @@ -533,14 +342,20 @@ pas_book_respond_remove (PASBook *book, * pas_book_respond_modify: */ void -pas_book_respond_modify (PASBook *book, - GNOME_Evolution_Addressbook_BookListener_CallStatus status) +pas_book_respond_modify (PASBook *book, + GNOME_Evolution_Addressbook_CallStatus status, + EContact *contact) { CORBA_Environment ev; + if (status == GNOME_Evolution_Addressbook_Success) { + pas_backend_notify_update (book->priv->backend, contact); + pas_backend_notify_complete (book->priv->backend); + } + CORBA_exception_init (&ev); - GNOME_Evolution_Addressbook_BookListener_notifyCardModified ( + GNOME_Evolution_Addressbook_BookListener_notifyContactModified ( book->priv->listener, status, &ev); if (ev._major != CORBA_NO_EXCEPTION) { @@ -556,7 +371,7 @@ pas_book_respond_modify (PASBook *book, */ void pas_book_respond_authenticate_user (PASBook *book, - GNOME_Evolution_Addressbook_BookListener_CallStatus status) + GNOME_Evolution_Addressbook_CallStatus status) { CORBA_Environment ev; @@ -575,30 +390,28 @@ pas_book_respond_authenticate_user (PASBook *book, void pas_book_respond_get_supported_fields (PASBook *book, - GNOME_Evolution_Addressbook_BookListener_CallStatus status, - EList *fields) + GNOME_Evolution_Addressbook_CallStatus status, + GList *fields) { CORBA_Environment ev; GNOME_Evolution_Addressbook_stringlist stringlist; int num_fields; - EIterator *iter; int i; + GList *iter; CORBA_exception_init (&ev); - num_fields = e_list_length (fields); + num_fields = g_list_length (fields); stringlist._buffer = CORBA_sequence_CORBA_string_allocbuf (num_fields); stringlist._maximum = num_fields; stringlist._length = num_fields; - iter = e_list_get_iterator (fields); - - for (i = 0; e_iterator_is_valid (iter); e_iterator_next (iter), i ++) { - stringlist._buffer[i] = CORBA_string_dup (e_iterator_get(iter)); + for (i = 0, iter = fields; iter; iter = iter->next, i ++) { + stringlist._buffer[i] = CORBA_string_dup ((char*)iter->data); } - g_object_unref (fields); + printf ("calling GNOME_Evolution_Addressbook_BookListener_notifySupportedFields\n"); GNOME_Evolution_Addressbook_BookListener_notifySupportedFields ( book->priv->listener, status, @@ -612,31 +425,27 @@ pas_book_respond_get_supported_fields (PASBook *book, void pas_book_respond_get_supported_auth_methods (PASBook *book, - GNOME_Evolution_Addressbook_BookListener_CallStatus status, - EList *auth_methods) + GNOME_Evolution_Addressbook_CallStatus status, + GList *auth_methods) { CORBA_Environment ev; GNOME_Evolution_Addressbook_stringlist stringlist; int num_auth_methods; - EIterator *iter; + GList *iter; int i; CORBA_exception_init (&ev); - num_auth_methods = e_list_length (auth_methods); + num_auth_methods = g_list_length (auth_methods); stringlist._buffer = CORBA_sequence_CORBA_string_allocbuf (num_auth_methods); stringlist._maximum = num_auth_methods; stringlist._length = num_auth_methods; - iter = e_list_get_iterator (auth_methods); - - for (i = 0; e_iterator_is_valid (iter); e_iterator_next (iter), i ++) { - stringlist._buffer[i] = CORBA_string_dup (e_iterator_get(iter)); + for (i = 0, iter = auth_methods; iter; iter = iter->next, i ++) { + stringlist._buffer[i] = CORBA_string_dup ((char*)iter->data); } - g_object_unref (auth_methods); - GNOME_Evolution_Addressbook_BookListener_notifySupportedAuthMethods ( book->priv->listener, status, &stringlist, @@ -647,30 +456,28 @@ pas_book_respond_get_supported_auth_methods (PASBook *book, CORBA_free(stringlist._buffer); } -/** - * pas_book_respond_get_cursor: - */ -void -pas_book_respond_get_cursor (PASBook *book, - GNOME_Evolution_Addressbook_BookListener_CallStatus status, - PASCardCursor *cursor) -{ - CORBA_Environment ev; - CORBA_Object object; - - CORBA_exception_init (&ev); - - object = bonobo_object_corba_objref(BONOBO_OBJECT(cursor)); - - GNOME_Evolution_Addressbook_BookListener_notifyCursorRequested ( - book->priv->listener, status, object, &ev); - - if (ev._major != CORBA_NO_EXCEPTION) { - g_warning ("pas_book_respond_get_cursor: Exception " - "responding to BookListener!\n"); +static void +view_destroy(gpointer data, GObject *where_object_was) +{ + PASBook *book = (PASBook *)data; + EIterator *iterator; + gboolean success = FALSE; + EList *views = pas_backend_get_book_views (book->priv->backend); + + for (iterator = e_list_get_iterator(views); + e_iterator_is_valid(iterator); + e_iterator_next(iterator)) { + const PASBookView *view = e_iterator_get(iterator); + if (view == (PASBookView*)where_object_was) { + e_iterator_delete(iterator); + success = TRUE; + break; + } } - - CORBA_exception_free (&ev); + if (!success) + g_warning ("Failed to remove from book_views list"); + g_object_unref(iterator); + g_object_unref(views); } /** @@ -678,15 +485,21 @@ pas_book_respond_get_cursor (PASBook *book, */ void pas_book_respond_get_book_view (PASBook *book, - GNOME_Evolution_Addressbook_BookListener_CallStatus status, + GNOME_Evolution_Addressbook_CallStatus status, PASBookView *book_view) { CORBA_Environment ev; - CORBA_Object object; + CORBA_Object object = CORBA_OBJECT_NIL; + + printf ("pas_book_respond_get_book_view\n"); CORBA_exception_init (&ev); - - object = bonobo_object_corba_objref(BONOBO_OBJECT(book_view)); + + if (book_view) { + object = bonobo_object_corba_objref(BONOBO_OBJECT(book_view)); + + g_object_weak_ref (G_OBJECT (book_view), view_destroy, book); + } GNOME_Evolution_Addressbook_BookListener_notifyViewRequested ( book->priv->listener, status, object, &ev); @@ -700,100 +513,122 @@ pas_book_respond_get_book_view (PASBook *book, } /** - * pas_book_respond_get_book_view: + * pas_book_respond_get_contact: */ void -pas_book_respond_get_completion_view (PASBook *book, - GNOME_Evolution_Addressbook_BookListener_CallStatus status, - PASBookView *completion_view) +pas_book_respond_get_contact (PASBook *book, + GNOME_Evolution_Addressbook_CallStatus status, + char *vcard) { 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); + GNOME_Evolution_Addressbook_BookListener_notifyContactRequested (book->priv->listener, + status, + vcard, + &ev); - if (ev._major != CORBA_NO_EXCEPTION) { - g_warning ("pas_book_respond_get_completion_view: Exception " - "responding to BookListener!\n"); - } + if (ev._major != CORBA_NO_EXCEPTION) + g_message ("could not notify listener of get-contact response"); CORBA_exception_free (&ev); } /** - * pas_book_respond_get_changes: + * pas_book_respond_get_contact_list: */ void -pas_book_respond_get_vcard (PASBook *book, - GNOME_Evolution_Addressbook_BookListener_CallStatus status, - char *vcard) +pas_book_respond_get_contact_list (PASBook *book, + GNOME_Evolution_Addressbook_CallStatus status, + GList *card_list) { CORBA_Environment ev; + GNOME_Evolution_Addressbook_stringlist stringlist; + int num_cards; + int i; + GList *l; CORBA_exception_init (&ev); - GNOME_Evolution_Addressbook_BookListener_notifyCardRequested ( - book->priv->listener, status, vcard, &ev); + num_cards = g_list_length (card_list); - if (ev._major != CORBA_NO_EXCEPTION) { - g_warning ("pas_book_respond_get_card: Exception " - "responding to BookListener!\n"); - } + stringlist._buffer = CORBA_sequence_CORBA_string_allocbuf (num_cards); + stringlist._maximum = num_cards; + stringlist._length = num_cards; - CORBA_exception_free (&ev); -} + for (i = 0, l = card_list; l; l = l->next, i ++) + stringlist._buffer[i] = CORBA_string_dup (l->data); -/** - * pas_book_respond_get_changes: - */ -void -pas_book_respond_get_changes (PASBook *book, - GNOME_Evolution_Addressbook_BookListener_CallStatus status, - PASBookView *book_view) -{ - CORBA_Environment ev; - CORBA_Object object; + g_list_foreach (card_list, (GFunc)g_free, NULL); + g_list_free (card_list); - CORBA_exception_init (&ev); - - object = bonobo_object_corba_objref(BONOBO_OBJECT(book_view)); - GNOME_Evolution_Addressbook_BookListener_notifyChangesRequested ( - book->priv->listener, status, object, &ev); + GNOME_Evolution_Addressbook_BookListener_notifyContactListRequested (book->priv->listener, + status, + &stringlist, + &ev); - if (ev._major != CORBA_NO_EXCEPTION) { - g_warning ("pas_book_respond_get_changes: Exception " - "responding to BookListener!\n"); - } + if (ev._major != CORBA_NO_EXCEPTION) + g_message ("could not notify listener of get-contact-list response"); CORBA_exception_free (&ev); + + CORBA_free(stringlist._buffer); } /** - * pas_book_report_connection: + * pas_book_respond_get_changes: */ void -pas_book_report_connection (PASBook *book, - gboolean connected) +pas_book_respond_get_changes (PASBook *book, + GNOME_Evolution_Addressbook_CallStatus status, + GList *changes) { CORBA_Environment ev; + GNOME_Evolution_Addressbook_BookChangeList changelist; + int num_changes; + int i; + GList *l; CORBA_exception_init (&ev); - GNOME_Evolution_Addressbook_BookListener_notifyConnectionStatus ( - book->priv->listener, (CORBA_boolean) connected, &ev); - - if (ev._major != CORBA_NO_EXCEPTION) { - g_warning ("pas_book_report_connection: Exception " - "responding to BookListener!\n"); + num_changes = g_list_length (changes); + + changelist._buffer = CORBA_sequence_GNOME_Evolution_Addressbook_BookChangeItem_allocbuf (num_changes); + changelist._maximum = num_changes; + changelist._length = num_changes; + + for (i = 0, l = changes; l; l = l->next, i ++) { + GNOME_Evolution_Addressbook_BookChangeItem *change = (GNOME_Evolution_Addressbook_BookChangeItem*)l->data; + changelist._buffer[i] = *change; + switch (change->_d) { + case GNOME_Evolution_Addressbook_ContactAdded: + changelist._buffer[i]._u.add_vcard = CORBA_string_dup (change->_u.add_vcard); + break; + case GNOME_Evolution_Addressbook_ContactModified: + changelist._buffer[i]._u.mod_vcard = CORBA_string_dup (change->_u.mod_vcard); + break; + case GNOME_Evolution_Addressbook_ContactDeleted: + changelist._buffer[i]._u.del_id = CORBA_string_dup (change->_u.del_id); + break; + } } + g_list_foreach (changes, (GFunc)CORBA_free, NULL); + g_list_free (changes); + + GNOME_Evolution_Addressbook_BookListener_notifyChangesRequested (book->priv->listener, + status, + &changelist, + &ev); + + if (ev._major != CORBA_NO_EXCEPTION) + g_message ("could not notify listener of get-changes response"); + CORBA_exception_free (&ev); + + CORBA_free(changelist._buffer); } /** @@ -821,7 +656,8 @@ pas_book_report_writable (PASBook *book, static void pas_book_construct (PASBook *book, PASBackend *backend, - GNOME_Evolution_Addressbook_BookListener listener) + const char *uri, + GNOME_Evolution_Addressbook_BookListener listener) { PASBookPrivate *priv; CORBA_Environment ev; @@ -830,8 +666,6 @@ pas_book_construct (PASBook *book, priv = book->priv; - priv->backend = backend; - CORBA_exception_init (&ev); book->priv->listener = CORBA_Object_duplicate (listener, &ev); @@ -843,94 +677,31 @@ pas_book_construct (PASBook *book, CORBA_exception_free (&ev); - priv->listener = listener; + priv->backend = backend; + priv->uri = g_strdup (uri); + } /** * pas_book_new: */ PASBook * -pas_book_new (PASBackend *backend, +pas_book_new (PASBackend *backend, + const char *uri, GNOME_Evolution_Addressbook_BookListener listener) { PASBook *book; + char *caps = pas_backend_get_static_capabilities (backend); - book = g_object_new (PAS_TYPE_BOOK, NULL); - - pas_book_construct (book, backend, listener); + book = g_object_new (PAS_TYPE_BOOK, + "poa", bonobo_poa_get_threaded (ORBIT_THREAD_HINT_PER_REQUEST, NULL), + NULL); - return book; -} + pas_book_construct (book, backend, uri, listener); -void -pas_book_free_request (PASRequest *req) -{ - CORBA_Environment ev; - switch (req->op) { - case CreateCard: - g_free (req->create.id); - g_free (req->create.vcard); - break; - case RemoveCards: - g_list_foreach (req->remove.ids, (GFunc)g_free, NULL); - g_list_free (req->remove.ids); - break; - case ModifyCard: - g_free (req->modify.vcard); - break; - case GetVCard: - g_free (req->get_vcard.id); - break; - case GetCursor: - g_free (req->get_cursor.search); - break; - case GetBookView: - g_free (req->get_book_view.search); - CORBA_exception_init (&ev); - bonobo_object_release_unref (req->get_book_view.listener, &ev); + g_free (caps); - 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: - g_free (req->get_changes.change_id); - CORBA_exception_init (&ev); - bonobo_object_release_unref (req->get_changes.listener, &ev); - - if (ev._major != CORBA_NO_EXCEPTION) - g_message ("pas_book_free_request(GetChanges): could not release the listener"); - - CORBA_exception_free (&ev); - break; - case CheckConnection: - /* nothing to free */ - break; - case AuthenticateUser: - g_free (req->auth_user.user); - g_free (req->auth_user.passwd); - g_free (req->auth_user.auth_method); - break; - case GetSupportedFields: - /* nothing to free */ - break; - case GetSupportedAuthMethods: - /* nothing to free */ - break; - } - - g_free (req); + return book; } static void @@ -939,24 +710,8 @@ pas_book_dispose (GObject *object) PASBook *book = PAS_BOOK (object); if (book->priv) { - GList *l; CORBA_Environment ev; - for (l = book->priv->request_queue; l != NULL; l = l->next) { - pas_book_free_request ((PASRequest *)l->data); - } - g_list_free (book->priv->request_queue); - - /* We should never ever have timeout_id == 0 when we - get destroyed, unless there is some sort of - reference counting bug. Still, we do this to try - to avoid horrible crashes in those situations. */ - if (book->priv->timeout_id) { - g_warning ("PASBook destroyed with non-zero timeout_id. This shouldn't happen."); - g_source_remove (book->priv->timeout_id); - book->priv->timeout_id = 0; - } - CORBA_exception_init (&ev); CORBA_Object_release (book->priv->listener, &ev); @@ -965,6 +720,7 @@ pas_book_dispose (GObject *object) CORBA_exception_free (&ev); + g_free (book->priv->uri); g_free (book->priv); book->priv = NULL; } @@ -981,42 +737,30 @@ pas_book_class_init (PASBookClass *klass) pas_book_parent_class = g_type_class_peek_parent (klass); - pas_book_signals [REQUESTS_QUEUED] = - g_signal_new ("requests_queued", - G_OBJECT_CLASS_TYPE(object_class), - G_SIGNAL_RUN_LAST, - G_STRUCT_OFFSET (PASBookClass, requests_queued), - NULL, NULL, - pas_marshal_NONE__NONE, - G_TYPE_NONE, 0); - object_class->dispose = pas_book_dispose; epv = &klass->epv; - epv->getVCard = impl_GNOME_Evolution_Addressbook_Book_getVCard; + epv->open = impl_GNOME_Evolution_Addressbook_Book_open; + epv->remove = impl_GNOME_Evolution_Addressbook_Book_remove; + epv->getContact = impl_GNOME_Evolution_Addressbook_Book_getContact; + epv->getContactList = impl_GNOME_Evolution_Addressbook_Book_getContactList; epv->authenticateUser = impl_GNOME_Evolution_Addressbook_Book_authenticateUser; - epv->addCard = impl_GNOME_Evolution_Addressbook_Book_addCard; - epv->removeCards = impl_GNOME_Evolution_Addressbook_Book_removeCards; - epv->modifyCard = impl_GNOME_Evolution_Addressbook_Book_modifyCard; - epv->checkConnection = impl_GNOME_Evolution_Addressbook_Book_checkConnection; + epv->addContact = impl_GNOME_Evolution_Addressbook_Book_addContact; + epv->removeContacts = impl_GNOME_Evolution_Addressbook_Book_removeContacts; + epv->modifyContact = impl_GNOME_Evolution_Addressbook_Book_modifyContact; epv->getStaticCapabilities = impl_GNOME_Evolution_Addressbook_Book_getStaticCapabilities; epv->getSupportedFields = impl_GNOME_Evolution_Addressbook_Book_getSupportedFields; epv->getSupportedAuthMethods = impl_GNOME_Evolution_Addressbook_Book_getSupportedAuthMethods; - 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; + epv->cancelOperation = impl_GNOME_Evolution_Addressbook_Book_cancelOperation; } static void pas_book_init (PASBook *book) { book->priv = g_new0 (PASBookPrivate, 1); - book->priv->timeout_id = 0; - book->priv->request_queue = NULL; - book->priv->timeout_id = 0; - book->priv->timeout_lock = FALSE; } BONOBO_TYPE_FUNC_FULL ( diff --git a/addressbook/backend/pas/pas-book.h b/addressbook/backend/pas/pas-book.h index 761f906437..2cb84569c2 100644 --- a/addressbook/backend/pas/pas-book.h +++ b/addressbook/backend/pas/pas-book.h @@ -12,13 +12,11 @@ #ifndef __PAS_BOOK_H__ #define __PAS_BOOK_H__ -#include #include -#include +#include #include "e-util/e-list.h" -#include -#include +#include #define PAS_TYPE_BOOK (pas_book_get_type ()) #define PAS_BOOK(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), PAS_TYPE_BOOK, PASBook)) @@ -27,164 +25,68 @@ #define PAS_IS_BOOK_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), PAS_TYPE_BOOK)) #define PAS_BOOK_GET_CLASS(k) (G_TYPE_INSTANCE_GET_CLASS ((obj), PAS_TYPE_BOOK, PASBookClass)) -typedef struct _PASBook PASBook; typedef struct _PASBookPrivate PASBookPrivate; -typedef enum { - CreateCard, - RemoveCards, - ModifyCard, - GetVCard, - GetCursor, - GetBookView, - GetCompletionView, - GetChanges, - CheckConnection, - AuthenticateUser, - GetSupportedFields, - GetSupportedAuthMethods -} PASOperation; - -typedef struct { - PASOperation op; - char *id; - char *vcard; -} PASCreateCardRequest; - -typedef struct { - PASOperation op; - GList *ids; -} PASRemoveCardsRequest; - -typedef struct { - PASOperation op; - char *vcard; -} PASModifyCardRequest; - -typedef struct { - PASOperation op; - char *id; -} PASGetVCardRequest; - -typedef struct { - PASOperation op; - char *search; -} PASGetCursorRequest; - -typedef struct { - PASOperation op; - char *search; - 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; - GNOME_Evolution_Addressbook_BookViewListener listener; -} PASGetChangesRequest; - -typedef struct { - PASOperation op; -} PASCheckConnectionRequest; - -typedef struct { - PASOperation op; - char *user; - char *passwd; - char *auth_method; -} PASAuthenticateUserRequest; - -typedef struct { - PASOperation op; -} PASGetSupportedFieldsRequest; - -typedef struct { - PASOperation op; -} PASGetSupportedAuthMethodsRequest; - -typedef union { - PASOperation op; - - PASCreateCardRequest create; - PASRemoveCardsRequest 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; - PASGetSupportedAuthMethodsRequest get_supported_auth_methods; -} PASRequest; - struct _PASBook { - BonoboObject parent_object; - PASBookPrivate *priv; + BonoboObject parent_object; + PASBookPrivate *priv; }; -typedef struct { +struct _PASBookClass { BonoboObjectClass parent_class; POA_GNOME_Evolution_Addressbook_Book__epv epv; - /* Signals */ - void (*requests_queued) (void); -} PASBookClass; - - -typedef gboolean (*PASBookCanWriteFn) (PASBook *book); -typedef gboolean (*PASBookCanWriteCardFn) (PASBook *book, const char *id); - -PASBook *pas_book_new (PASBackend *backend, - GNOME_Evolution_Addressbook_BookListener listener); -PASBackend *pas_book_get_backend (PASBook *book); -GNOME_Evolution_Addressbook_BookListener pas_book_get_listener (PASBook *book); -int pas_book_check_pending (PASBook *book); -PASRequest *pas_book_pop_request (PASBook *book); -void pas_book_free_request (PASRequest *request); -void pas_book_respond_open (PASBook *book, - GNOME_Evolution_Addressbook_BookListener_CallStatus status); -void pas_book_respond_create (PASBook *book, - GNOME_Evolution_Addressbook_BookListener_CallStatus status, - const char *id); -void pas_book_respond_remove (PASBook *book, - GNOME_Evolution_Addressbook_BookListener_CallStatus status); -void pas_book_respond_modify (PASBook *book, - GNOME_Evolution_Addressbook_BookListener_CallStatus status); -void pas_book_respond_authenticate_user (PASBook *book, - GNOME_Evolution_Addressbook_BookListener_CallStatus status); -void pas_book_respond_get_supported_fields (PASBook *book, - GNOME_Evolution_Addressbook_BookListener_CallStatus status, - EList *fields); -void pas_book_respond_get_supported_auth_methods (PASBook *book, - GNOME_Evolution_Addressbook_BookListener_CallStatus status, - EList *fields); - -void pas_book_respond_get_cursor (PASBook *book, - GNOME_Evolution_Addressbook_BookListener_CallStatus status, - PASCardCursor *cursor); + /* Padding for future expansion */ + void (*_pas_reserved0) (void); + void (*_pas_reserved1) (void); + void (*_pas_reserved2) (void); + void (*_pas_reserved3) (void); + void (*_pas_reserved4) (void); +}; + + +PASBook *pas_book_new (PASBackend *backend, + const char *uri, + GNOME_Evolution_Addressbook_BookListener listener); +GNOME_Evolution_Addressbook_BookListener pas_book_get_listener (PASBook *book); +PASBackend *pas_book_get_backend (PASBook *book); +const char *pas_book_get_uri (PASBook *book); + +void pas_book_respond_open (PASBook *book, + GNOME_Evolution_Addressbook_CallStatus status); +void pas_book_respond_remove (PASBook *book, + GNOME_Evolution_Addressbook_CallStatus status); +void pas_book_respond_create (PASBook *book, + GNOME_Evolution_Addressbook_CallStatus status, + EContact *contact); +void pas_book_respond_remove_contacts (PASBook *book, + GNOME_Evolution_Addressbook_CallStatus status, + GList *ids); +void pas_book_respond_modify (PASBook *book, + GNOME_Evolution_Addressbook_CallStatus status, + EContact *contact); +void pas_book_respond_authenticate_user (PASBook *book, + GNOME_Evolution_Addressbook_CallStatus status); +void pas_book_respond_get_supported_fields (PASBook *book, + GNOME_Evolution_Addressbook_CallStatus status, + GList *fields); +void pas_book_respond_get_supported_auth_methods (PASBook *book, + GNOME_Evolution_Addressbook_CallStatus status, + GList *fields); + void pas_book_respond_get_book_view (PASBook *book, - GNOME_Evolution_Addressbook_BookListener_CallStatus status, + GNOME_Evolution_Addressbook_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, +void pas_book_respond_get_contact (PASBook *book, + GNOME_Evolution_Addressbook_CallStatus status, char *vcard); -void pas_book_respond_get_changes (PASBook *book, - GNOME_Evolution_Addressbook_BookListener_CallStatus status, - PASBookView *book_view); -void pas_book_report_connection (PASBook *book, - gboolean connected); +void pas_book_respond_get_contact_list (PASBook *book, + GNOME_Evolution_Addressbook_CallStatus status, + GList *cards); +void pas_book_respond_get_changes (PASBook *book, + GNOME_Evolution_Addressbook_CallStatus status, + GList *changes); void pas_book_report_writable (PASBook *book, gboolean writable); diff --git a/addressbook/backend/pas/pas-card-cursor.c b/addressbook/backend/pas/pas-card-cursor.c deleted file mode 100644 index 9637bb1fb7..0000000000 --- a/addressbook/backend/pas/pas-card-cursor.c +++ /dev/null @@ -1,139 +0,0 @@ -/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ -/* - * pas-card-cursor.c: Implements card cursors. - * - * Author: - * Christopher James Lahey -#include -#include "addressbook.h" -#include "pas-card-cursor.h" - -struct _PASCardCursorPrivate { - long (*get_length) (PASCardCursor *cursor, gpointer data); - char * (*get_nth) (PASCardCursor *cursor, long n, gpointer data); - gpointer data; -}; - -/* - * A pointer to our parent object class - */ -static BonoboObjectClass *parent_class; - -/* - * Implemented GObject::dispose - */ -static void -pas_card_cursor_dispose (GObject *object) -{ - PASCardCursor *cursor = PAS_CARD_CURSOR (object); - - if ( cursor->priv ) { - g_free ( cursor->priv ); - cursor->priv = NULL; - } - - if (G_OBJECT_CLASS (parent_class)->dispose) - G_OBJECT_CLASS (parent_class)->dispose (object); -} - -/* - * CORBA Demo::Echo::echo method implementation - */ -static CORBA_long -impl_pas_card_cursor_get_length (PortableServer_Servant servant, - CORBA_Environment *ev) -{ - PASCardCursor *cursor = PAS_CARD_CURSOR (bonobo_object (servant)); - if ( cursor->priv->get_length ) - return cursor->priv->get_length( cursor, cursor->priv->data ); - else - return 0; -} - -/* - * CORBA Demo::Echo::echo method implementation - */ -static char * -impl_pas_card_cursor_get_nth (PortableServer_Servant servant, - const CORBA_long n, - CORBA_Environment *ev) -{ - PASCardCursor *cursor = PAS_CARD_CURSOR (bonobo_object (servant)); - if ( cursor->priv->get_nth ) { - char *vcard = cursor->priv->get_nth( cursor, n, cursor->priv->data ); - char *retval = CORBA_string_dup (vcard); - g_free (vcard); - return retval; - } else - return CORBA_string_dup (""); -} - -static void -pas_card_cursor_class_init (PASCardCursorClass *klass) -{ - GObjectClass *object_class = G_OBJECT_CLASS (klass); - POA_GNOME_Evolution_Addressbook_CardCursor__epv *epv; - - parent_class = g_type_class_peek_parent (klass); - - object_class->dispose = pas_card_cursor_dispose; - - - epv = &klass->epv; - - epv->count = impl_pas_card_cursor_get_length; - epv->getNth = impl_pas_card_cursor_get_nth; -} - -static void -pas_card_cursor_init (PASCardCursor *cursor) -{ - cursor->priv = g_new0(PASCardCursorPrivate, 1); - cursor->priv->get_length = NULL; - cursor->priv->get_nth = NULL; - cursor->priv->data = NULL; -} - -static void -pas_card_cursor_construct (PASCardCursor *cursor, - PASCardCursorLengthFunc get_length, - PASCardCursorNthFunc get_nth, - gpointer data) -{ - PASCardCursorPrivate *priv; - - g_return_if_fail (cursor != NULL); - g_return_if_fail (PAS_IS_CARD_CURSOR (cursor)); - - priv = cursor->priv; - - priv->get_length = get_length; - priv->get_nth = get_nth; - priv->data = data; -} - -PASCardCursor * -pas_card_cursor_new (PASCardCursorLengthFunc get_length, - PASCardCursorNthFunc get_nth, - gpointer data) -{ - PASCardCursor *cursor; - - cursor = g_object_new (PAS_TYPE_CARD_CURSOR, NULL); - - pas_card_cursor_construct (cursor, - get_length, - get_nth, - data); - - return cursor; -} - -BONOBO_TYPE_FUNC_FULL ( - PASCardCursor, - GNOME_Evolution_Addressbook_CardCursor, - BONOBO_TYPE_OBJECT, - pas_card_cursor); diff --git a/addressbook/backend/pas/pas-card-cursor.h b/addressbook/backend/pas/pas-card-cursor.h deleted file mode 100644 index db5b05c0c2..0000000000 --- a/addressbook/backend/pas/pas-card-cursor.h +++ /dev/null @@ -1,56 +0,0 @@ -/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ -/* - * - * Author: - * Nat Friedman (nat@ximian.com) - * - * Copyright 2000, Ximian, Inc. - */ - -#ifndef __PAS_CARD_CURSOR_H__ -#define __PAS_CARD_CURSOR_H__ - -#include -#include - -G_BEGIN_DECLS - -#define PAS_TYPE_CARD_CURSOR (pas_card_cursor_get_type ()) -#define PAS_CARD_CURSOR(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), PAS_TYPE_CARD_CURSOR, PASCardCursor)) -#define PAS_CARD_CURSOR_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), PAS_TYPE_CARD_CURSOR, PASCardCursorClass)) -#define PAS_IS_CARD_CURSOR(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), PAS_TYPE_CARD_CURSOR)) -#define PAS_IS_CARD_CURSOR_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), PAS_TYPE_CARD_CURSOR)) -#define PAS_CARD_CURSOR_GET_CLASS(k) (G_TYPE_INSTANCE_GET_CLASS ((obj), PAS_TYPE_CARD_CURSOR, PASCardCursorClass)) - -typedef struct _PASCardCursor PASCardCursor; -typedef struct _PASCardCursorPrivate PASCardCursorPrivate; -typedef struct _PASCardCursorClass PASCardCursorClass; - -typedef long (*PASCardCursorLengthFunc) (PASCardCursor *cursor, gpointer data); -typedef char * (*PASCardCursorNthFunc) (PASCardCursor *cursor, long n, gpointer data); - -struct _PASCardCursor { - BonoboObject parent; - PASCardCursorPrivate *priv; -}; - -struct _PASCardCursorClass { - BonoboObjectClass parent; - - POA_GNOME_Evolution_Addressbook_CardCursor__epv epv; -}; - - - -/* Creating a new addressbook. */ -PASCardCursor *pas_card_cursor_new (PASCardCursorLengthFunc get_length, - PASCardCursorNthFunc get_nth, - gpointer data); - -GType pas_card_cursor_get_type (void); -POA_GNOME_Evolution_Addressbook_CardCursor__epv * - pas_card_cursor_get_epv (void); - -G_END_DECLS - -#endif /* ! __PAS_CARD_CURSOR_H__ */ diff --git a/addressbook/backend/pas/pas-marshal.list b/addressbook/backend/pas/pas-marshal.list index fa33740eaa..9d6744db44 100644 --- a/addressbook/backend/pas/pas-marshal.list +++ b/addressbook/backend/pas/pas-marshal.list @@ -1 +1,2 @@ NONE:NONE +NONE:POINTER diff --git a/addressbook/backend/pas/pas-types.h b/addressbook/backend/pas/pas-types.h new file mode 100644 index 0000000000..19611a4e23 --- /dev/null +++ b/addressbook/backend/pas/pas-types.h @@ -0,0 +1,32 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ +/* + * Blanket header containing the typedefs for object types used in the + * PAS stuff, so we can disentangle the #includes. + * + * Author: Chris Toshok + * + * Copyright 2003, Ximian, Inc. + */ + +#ifndef __PAS_TYPES_H__ +#define __PAS_TYPES_H__ + +typedef struct _PASBookView PASBookView; +typedef struct _PASBookViewClass PASBookViewClass; + +typedef struct _PASBackendCardSExp PASBackendCardSExp; +typedef struct _PASBackendCardSExpClass PASBackendCardSExpClass; + +typedef struct _PASBackend PASBackend; +typedef struct _PASBackendClass PASBackendClass; + +typedef struct _PASBackendSummary PASBackendSummary; +typedef struct _PASBackendSummaryClass PASBackendSummaryClass; + +typedef struct _PASBackendSync PASBackendSync; +typedef struct _PASBackendSyncClass PASBackendSyncClass; + +typedef struct _PASBook PASBook; +typedef struct _PASBookClass PASBookClass; + +#endif /* __PAS_TYPES_H__ */ diff --git a/addressbook/backend/pas/ximian-vcard.h b/addressbook/backend/pas/ximian-vcard.h new file mode 100644 index 0000000000..961a5cadb4 --- /dev/null +++ b/addressbook/backend/pas/ximian-vcard.h @@ -0,0 +1,81 @@ +#define XIMIAN_VCARD \ +"BEGIN:VCARD\n" \ +"X-EVOLUTION-FILE-AS:Ximian\\, Inc.\n" \ +"ADR;TYPE=WORK:;Suite 3 West;401 Park Drive;Boston;MA;02215;USA\n" \ +"LABEL;TYPE=WORK:401 Park Drive\\nSuite 3 West\\nBoston\\, MA\\n02215\\nUSA\n" \ +"TEL;WORK;VOICE:(617) 375-3800\n" \ +"TEL;WORK;FAX:(617) 236-8630\n" \ +"EMAIL;INTERNET:hello@ximian.com\n" \ +"URL:http://www.ximian.com/\n" \ +"ORG:Ximian\\, Inc.;\n" \ +"NOTE:Welcome to the Ximian Addressbook.\n" \ +"PHOTO;ENCODING=b;TYPE=JPEG:/9j/4AAQSkZJRgABAQEARwBHAAD//gAXQ3JlYXRlZCB3aXRo\n" \ +" IFRoZSBHSU1Q/9sAQwAIBgYHBgUIBwcHCQkICgwUDQwLCwwZEhMPFB0aHx4dGhwcICQuJyAiLCM\n" \ +" cHCg3KSwwMTQ0NB8nOT04MjwuMzQy/9sAQwEJCQkMCwwYDQ0YMiEcITIyMjIyMjIyMjIyMjIyMj\n" \ +" IyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIy/8AAEQgAbgBkAwEiAAIRAQMRAf/EA\n" \ +" BwAAAIDAQEBAQAAAAAAAAAAAAAHBQYIBAMBAv/EAEYQAAEDAwEFBgMEBgQPAAAAAAECAwQABREG\n" \ +" BxIhMWETIkFRcYEUkaEIMkLBFSNSsbLRFmJydRgkMzY3Q0RGgpKTosLh8P/EABsBAQACAwEBAAA\n" \ +" AAAAAAAAAAAAEBQIDBgEH/8QALREAAQMCAwYGAgMAAAAAAAAAAQACAwQREiFRBRMiMUFhMnGBkb\n" \ +" HRBsEUofD/2gAMAwEAAhEDEQA/AH/RRRREVwXe9W2wwFzbpNZixkc1uqwPQeZ6CoHXevLfom1ds\n" \ +" 9h6a6D8PGCsFZHMk+CR4n86yzdbrqfaZqYBSnp0hRPZMoG62ynoOSR1Pua8Lg0XPJegX5Jv6k+0\n" \ +" bBjrWxp22LlkcBIlHs0HqEjiR64peT9umupqyWrhHhpP4WI6eHureNW7Tmw+DGaTI1FJVJdxksM\n" \ +" qKG09CrmfbFMCHpCw2xATDs8JrH4gykq+Z4mqifbMUZsxpd/QUllK53M2SCb2xa+bXvf0gcV0Uw\n" \ +" 0R/DVktH2hdUwlpFxjQrg1490tLPuOH0pvv2qE4jdchx1p8lNAj91Va87OtM3RCt+2Nx3Dyci/q\n" \ +" yPYcD7g1EZ+RR4rSMI9b/S2mhdbhKsmkdtWmNTuNxnXVW2cvgGZRASo+SV8j74PSmOlQUMpORWP\n" \ +" NU7MrjY0rlQFmdDTxOE4cQOo8R1Hyqe2Z7ZJ2m32bXfHnJVpJCUuqO8uP7+Kenh4eVXkFRFUMxx\n" \ +" G4UOSN0Zs4LU1FeEOWxOityYzqHWXEhSFoOQoHkQa963rBFFFFERUdfr1E09Y5d1mr3Y8ZsrV5n\n" \ +" yA6k4A6mpGkL9ojUym0W/TrLmAsGU+AeYBwgfPJ/4RREqrrcb1tJ1oUpBXLmObqUZ7rSByT0SkZ\n" \ +" J8zk1pHQmiLXo+zpbabC3SAp55Q7zyvM9PIUudiGmURbS7fpCMvzFFton8LSTxx6qH0FM7VV9VY\n" \ +" 9MzZ7aQt5tASw3+26ohKB/zEVSVFVvZzGMw02tqe/kpbI8LMR6/C/Xxq9QagfbbP+IW1QQ4Rycf\n" \ +" xncHRAIJ/rEfsmu2a9Fgsl2XIZjtj8bqwgfM1+9L2VFksESAV9o6hG886ebjqjvLWepUSarutdn\n" \ +" MXV+obRcZks/CwCQ5DKMpeBOTxzwzgA9KwfTtfxPOSB5GQUXc9pOjoC+zXe2HV5xiOC6PmkEfWp\n" \ +" xe6tAWghSVDIIOQRXxekNOx4b0WPZYLLTram19mwlJKSMHjjNUzQd2dZM7SNxczcLOsttqVzdYz\n" \ +" 3FewI9iKpK2mjMZdFe7ed9NfT9qZDI4OAd1Vkko50ndoui22kuXq2NBOO9JZSOH9sD9/z86c8gc\n" \ +" DUJNQlaFJUkKSoYII4EVGoKp9PIHt9e6lyRNlZhcqlsJ2guQpydL3F4mO7kw1KP3Fcyj0PEjrnz\n" \ +" rSAIIyOVYfvsJ3TGqlCKpTfYuJfjLHMDOR8jw9q2Foy+o1FpWBckY/XMpUoeRxxHsciu/jeJGB7\n" \ +" eRXPvaWuLT0U/RRRWaxQeVY82x3BVw2oXbJyhgoZR0AQM/UmthK+6fSsWbRQW9pV73x/tZPtwNE\n" \ +" Wj9Nw0WuwwIKQAGI6G/cAZ+tRW0lx5nTEW4Ntqdat9xjy5CEjJLSFZP5H2qaYdCkpUk5BGQa7Ap\n" \ +" DrSm3EpWhYKVJUMgg8wRXz+kqyyTG7VXUsV22Clrfc48+CzMiPIejvIC23EHIUDXNe79b7HbXbh\n" \ +" c5SI8ZvmtZ5nyA5k9BS7d0nfdMPuSdD3JtEZaitdom5Uznx3DzT6cPWkvq/V1611fGW5nZtBCgy\n" \ +" zFbXhtCycE5JxknxPhXR07RUeB3D11H+9lAfwcxmrrqLbxcHpikWGAw1FScByUkqWvrgEBPpxqi\n" \ +" ztdXWdqmNqIIjx7gykJUphJCXAM/eBJ5g4PQCmBZNiDKWEu364uF0jJYh4AT6qUDn2FVu6bPIkT\n" \ +" aTB08xKeMOU2H99eCtKRvZGQMZ7hwceNZxVGzsbmMzIBv5dfNeOjnsCdUwbTtKsV8nJgIccZkqw\n" \ +" lJcThDqvJJz8s4zUtLVzpc2vZZKt+qBIkyUKt0V0ONKSe+7g5SCPDr9Kv0tznXP1cNMyQfxnXBC\n" \ +" tqUyuB3gslftPjJLkGWB3u82o/Ij86bf2e7iqRoxyIpWfhpC0JHQ4V/5GlVtJcBt0RPiXif+00w\n" \ +" Ps5BQtNxP4TJP8Ka6rZZJpW37/Kq68ATlPeiiirBQ0HlWR9t9qVbtpEp/dwiY0h5J8Mgbp/h+ta\n" \ +" 4pM7fdKLumn2rxGbKn4BKl4HEtn73ywD7GiL7o28JuulLbKCsqLKUL/tJ7p+oqyIe4c6RGyzU4g\n" \ +" THLNJc3WpCt9gk8A54j3GPcdaZuoosy82V23QpaYpkEIdeIJKUeIAHieXPkTXA11DuassJsCefY\n" \ +" /SvYZN5FiGZU9edRwLDAXJny2mRukoStQBWQOQHjSjg7PYE7ZmzcZb7cG6KK5CZD6txOCcJQvPg\n" \ +" QAQfAn2q6RNOWi1D9J3R5dwlR2xmZPVv9mlI8ByTj59ar09Lm0jUIQl5Y0zAUMrQSPiXfHHpyz4\n" \ +" D1qTRvMQIieQAQXOtllfIDre/X2WqVmI8Qz6D9q0bP9SO37SrSpW8ZUVXw7q+YcKeSgeRyMZ65q\n" \ +" qammvWTalEv1yjOJtaWfh25CBvBOUkHPlxUeHlyq/MiPCitxorSGWG07qG0DASK45xZlx3GJDaH\n" \ +" WljCkLGQR6VGinY2ofIG8Lri2gOi37hxYG3zC+uT2HY6ZDbyFMrAUlwK7pB5HNRcp7nxqpzdN3G\n" \ +" CFQ7NObTa3nApcaSN/suOe4SDw6VK3O4swojsp9WGmxk9fIDrW4UzWkbt2K/v691vjec8YtZUTa\n" \ +" BL+IuMaIjiWWytXQn/wBD608tgtrVC0W2+tOFSFqd9icD6AVnmFFl6n1AhoAmRPdwcfgR4n2H7q\n" \ +" 2Ppi1N2exRojaQlKEBIHkAK7Gmi3MTWaLn6iTeSF+qmaKKK3rSiuedEanQ3I7qQpC0kEEZzXRRR\n" \ +" FjnaRoSVoq/KcYQv9HOr3mHB/qzz3SenhVi0ftAbnNNwLo6G5iQEodUcJd9fJX760ZqLTkHUdsd\n" \ +" hTWEOtuJwQoVl/XGyS7aakOPwGnJcDORujK0DqPH2qJV0cdUzC/0Oi3QTuhddqY84IuFukwnFFK\n" \ +" JDSmlEcwFDGR86ISI1tgtQ4jYaYaTuoSP/udJS1azvFoAZLnbsp4dm/klPQHmKs0faVEWkfEw32\n" \ +" 1f1CFj8q56XZNSwYG5t7fSt46yB5ucimM5L4c643pXWqU5tCteMpRKUfIIH86ipmvnnAUwoQSf2\n" \ +" 3lZ+g/nWEey5yfCtrquBo8Su0+4sQ46pEp1LTSeZUfoPOlnfr67fZKQlK0QkK/VtficV5nrXOkX\n" \ +" XUk9KQHp0gnghI7qPyAp1bOdkCmH2rneQHHxxQjHdb9OvWr2j2c2Didm74VZVVplGFuQXRsc2fO\n" \ +" Qgb1cmsSXQN1JH+TT4D+dPEAAADkK848duMylppISkDGBXrVkoCKKKKIiiqrrbX9m0JARIua1re\n" \ +" dJDMdoArcI58+AA8zVLsO26RqiS9Gsukpct5lHaKbTLaSrd8wFEZ9s0RN6vGRGZktlDqAoHzFKq\n" \ +" JtomzrPOuzGjZvwEBRTJfckttpbUOae9jJ5cBk8R514Wrbo7e489+3aTlvtQGTIkqElsdm2Mkq4\n" \ +" 4zyPKiKf1Hsj09flKdXEQh4/jR3VfMUvJ/2et1ZMOe8keSgFfyqz2LbfJ1M9IZs2kJsx2O0XnEN\n" \ +" yEAhA4ZwcZ58hxr7ZdtkvUS5SbTo2fJMRsuPkPoSG0jzKsDPPhz4HyoipDewC47+FXFWOjYH51Y\n" \ +" bTsAgtrSqc88/jwWrA+QxUlYtujupZ6oNo0nLlSUtqdKEyW04SMZOVYHiKjP8ACUt5/wB3pX/XT\n" \ +" /KiJnWLQ1nsTSURorad39lIFWZKUoThIAHSlNqDbLP0siKu96MnQ0ygSyVyGzvYxnlnB4jga87F\n" \ +" ttlamXJbs2j50xcZvtXUtyEZCfPB5+gyaIm9RSetm3J68RbhJgaSmPM25vtZaviW09knjxIOM8j\n" \ +" y8q7LHtzstwv/AOhrlBftkkudkFOLS43v5xgqSeHHx5daImrRX5QtK0hSTkGiiLMP2ho8wa1iSn\n" \ +" QoxVRQ20fAKClFQ9eIqq7LLJe7vreG7ZZCoZhqD8iZjustjnnwORkY8c+Wa1ZqbStt1PBMa4MId\n" \ +" Rz7wzg+dL8bEbA1vpa7RtK+CkpdWAfXjRFB7UpCNe6Kdm6NnJft1qluKuUJlvdKznPbYH3hzPXJ\n" \ +" PMGqZsk/zc2gf3G5/Cumc3sRsTO92Rcb3uB3XVjP1r4jYfYGwoN76QsYUEurGR5HjREudhUt2BP\n" \ +" 1TMYID0eyuuoJGRvJII+oq96I2iwtVz7rb7ZZWbalyzyJ9wKUjLsrKEkjH4cE8+Jz049bew+wNb\n" \ +" 3Z76N4YO66sZHlzob2H2Bkktb6CRglLqxkeXOiJZbAv9IMj+7X/wB6ag9lGnEaj17CRJA+BhZmy\n" \ +" lK+6EI44PQq3R6E06W9h9gZVvNb6FYxlLqwcfOhvYhYWt7s99G8MK3XVjI68aIo7UxgbR9IajhQ\n" \ +" 7/Du9yiSF3S3tMNrStlkAAt94DPDI4eJFUvYfNetqNYz4xAfjWZx5skZAUnJHD1FMVrYhYWVbzW\n" \ +" +2ojGUOrBx86EbD7A0FBvfRvDCt11YyPI8aIo23zdP6i2e621TaUJiXCfa1IucFPJt5KVnfHRWS\n" \ +" euPPNZ2YadfkNsspUp1aglCU8yTyrTSNh9gbCgjfSFjCgl1YyPI8al9PbItP2WamUywkuJ5KOVE\n" \ +" emeVEVw02ZH9H4YkEqdDYCifE4oqXbaS02lCRhIGBRRF//Z\n" \ +"END:VCARD" diff --git a/addressbook/gui/component/GNOME_Evolution_Addressbook.server.in.in b/addressbook/gui/component/GNOME_Evolution_Addressbook.server.in.in index 6d46c5fbbe..6b3b252377 100644 --- a/addressbook/gui/component/GNOME_Evolution_Addressbook.server.in.in +++ b/addressbook/gui/component/GNOME_Evolution_Addressbook.server.in.in @@ -1,6 +1,6 @@ - @@ -13,9 +13,9 @@ - + location="OAFIID:GNOME_Evolution_Addressbook_Factory_2"> @@ -32,9 +32,9 @@ - + location="OAFIID:GNOME_Evolution_Addressbook_Factory_2"> @@ -46,27 +46,22 @@ - + location="OAFIID:GNOME_Evolution_Addressbook_Factory_2"> - + - - - + location="OAFIID:GNOME_Evolution_Addressbook_Factory_2"> @@ -80,7 +75,7 @@ + location="OAFIID:GNOME_Evolution_Addressbook_Factory_2"> @@ -94,7 +89,7 @@ + location="OAFIID:GNOME_Evolution_Addressbook_Factory_2"> diff --git a/addressbook/gui/component/Makefile.am b/addressbook/gui/component/Makefile.am index e13f8d853b..4234997e1d 100644 --- a/addressbook/gui/component/Makefile.am +++ b/addressbook/gui/component/Makefile.am @@ -9,7 +9,6 @@ INCLUDES = \ -I$(top_srcdir)/widgets/misc \ -I$(top_srcdir)/addressbook/gui/contact-editor \ -I$(top_srcdir)/addressbook/gui/contact-list-editor \ - -I$(top_srcdir)/addressbook/gui/minicard \ -I$(top_srcdir)/addressbook/gui/widgets \ -I$(top_srcdir)/addressbook/backend \ -I$(top_builddir)/addressbook/backend \ @@ -38,26 +37,22 @@ libevolution_addressbook_la_SOURCES = \ addressbook-storage.h \ addressbook.c \ addressbook.h \ - component-factory.c \ - e-cardlist-model.c \ - e-cardlist-model.h \ - e-address-widget.h \ - e-address-widget.c \ - e-address-popup.h \ - e-address-popup.c + component-factory.c + +# $(top_builddir)/addressbook/printing/libecontactprint.la libevolution_addressbook_la_LIBADD = \ - select-names/libeselectnames.la \ + $(top_builddir)/addressbook/gui/component/select-names/libeselectnames.la \ $(top_builddir)/shell/libeshell.la \ - $(top_builddir)/addressbook/gui/widgets/libeminicard.la \ - $(top_builddir)/addressbook/printing/libecontactprint.la \ + $(top_builddir)/addressbook/gui/merging/libeabbookmerging.la \ + $(top_builddir)/addressbook/gui/widgets/libeabwidgets.la \ $(top_builddir)/addressbook/gui/search/libeaddressbooksearch.la \ $(top_builddir)/filter/libfilter.la \ + $(top_builddir)/addressbook/util/libeabutil.la \ $(top_builddir)/addressbook/backend/ebook/libebook.la \ - $(top_builddir)/addressbook/gui/contact-list-editor/libecontactlisteditor.la \ $(top_builddir)/addressbook/gui/contact-editor/libecontacteditor.la \ + $(top_builddir)/addressbook/gui/contact-list-editor/libecontactlisteditor.la \ $(top_builddir)/widgets/misc/libemiscwidgets.la \ - $(top_builddir)/addressbook/gui/merging/libecardmerging.la \ $(top_builddir)/widgets/menus/libmenus.la \ $(EVOLUTION_ADDRESSBOOK_LIBS) $(LDAP_LIBS) diff --git a/addressbook/gui/component/addressbook-component.c b/addressbook/gui/component/addressbook-component.c index cdfeeb9755..c323a1bd78 100644 --- a/addressbook/gui/component/addressbook-component.c +++ b/addressbook/gui/component/addressbook-component.c @@ -1,7 +1,7 @@ /* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */ /* addressbook-component.c * - * Copyright (C) 2000 Ximian, Inc. + * Copyright (C) 2003 Ettore Perazzoli * * This program is free software; you can redistribute it and/or * modify it under the terms of version 2 of the GNU General Public @@ -17,633 +17,170 @@ * Free Software Foundation, Inc., 59 Temple Place - Suite 330, * Boston, MA 02111-1307, USA. * - * Author: Ettore Perazzoli + * Author: Ettore Perazzoli */ -#ifdef HAVE_CONFIG_H -#include -#endif - -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include - -#include -#include - -#include "evolution-shell-component.h" -#include "evolution-shell-component-dnd.h" -#include "evolution-storage.h" -#include "e-folder-list.h" - -#include "ebook/e-book.h" -#include "ebook/e-card.h" -#include "ebook/e-book-util.h" - -#include "addressbook-config.h" -#include "addressbook-storage.h" -#include "addressbook-component.h" -#include "addressbook.h" -#include "addressbook/gui/merging/e-card-merging.h" -#include "addressbook/gui/widgets/e-addressbook-util.h" - - - -#define GNOME_EVOLUTION_ADDRESSBOOK_COMPONENT_ID "OAFIID:GNOME_Evolution_Addressbook_ShellComponent" - -EvolutionShellClient *global_shell_client = NULL; +/* EPFIXME: Add autocompletion setting. */ -EvolutionShellClient * -addressbook_component_get_shell_client (void) -{ - return global_shell_client; -} -static char *accepted_dnd_types[] = { - "text/x-vcard", - NULL -}; +#include -static const EvolutionShellComponentFolderType folder_types[] = { - { "contacts", "evolution-contacts.png", N_("Contacts"), N_("Folder containing contact information"), - TRUE, accepted_dnd_types, NULL }, - { "contacts/ldap", "ldap.png", N_("LDAP Server"), N_("LDAP server containing contact information"), - FALSE, accepted_dnd_types, NULL }, - { "contacts/public", "evolution-contacts.png", N_("Public Contacts"), N_("Public folder containing contact information"), - FALSE, accepted_dnd_types, NULL }, - { NULL } -}; +#include "addressbook-component.h" -#define IS_CONTACT_TYPE(x) (g_ascii_strcasecmp((x), "contacts") == 0 || g_ascii_strcasecmp ((x), "contacts/ldap") == 0 || g_ascii_strcasecmp((x), "contacts/public") == 0) - -/* EvolutionShellComponent methods and signals. */ - -static EvolutionShellComponentResult -create_view (EvolutionShellComponent *shell_component, - const char *physical_uri, - const char *type, - const char *view_info, - BonoboControl **control_return, - void *closure) -{ - BonoboControl *control; +#include "addressbook.h" - if (!IS_CONTACT_TYPE (type)) - return EVOLUTION_SHELL_COMPONENT_UNSUPPORTEDTYPE; +#include "widgets/misc/e-source-selector.h" - control = addressbook_new_control (); - bonobo_control_set_property (control, NULL, "folder_uri", TC_CORBA_string, physical_uri, NULL); +#include +#include - *control_return = control; - return EVOLUTION_SHELL_COMPONENT_OK; -} +#define PARENT_TYPE bonobo_object_get_type () +static BonoboObjectClass *parent_class = NULL; -static void -create_folder (EvolutionShellComponent *shell_component, - const char *physical_uri, - const char *type, - const GNOME_Evolution_ShellComponentListener listener, - void *closure) -{ - CORBA_Environment ev; - GNOME_Evolution_ShellComponentListener_Result result; +struct _AddressbookComponentPrivate { + GConfClient *gconf_client; + ESourceList *source_list; +}; - if (!IS_CONTACT_TYPE (type)) - result = GNOME_Evolution_ShellComponentListener_UNSUPPORTED_TYPE; - else - result = GNOME_Evolution_ShellComponentListener_OK; - CORBA_exception_init(&ev); - GNOME_Evolution_ShellComponentListener_notifyResult(listener, result, &ev); - CORBA_exception_free(&ev); -} +/* Utility functions. */ static void -remove_folder (EvolutionShellComponent *shell_component, - const char *physical_uri, - const char *type, - const GNOME_Evolution_ShellComponentListener listener, - void *closure) +load_uri_for_selection (ESourceSelector *selector, + BonoboControl *view_control) { - CORBA_Environment ev; - char *db_path, *summary_path, *subdir_path; - struct stat sb; - int rv; - - CORBA_exception_init(&ev); - - if (!IS_CONTACT_TYPE (type)) { - GNOME_Evolution_ShellComponentListener_notifyResult (listener, - GNOME_Evolution_ShellComponentListener_UNSUPPORTED_TYPE, - &ev); - CORBA_exception_free(&ev); - return; - } - - if (!strncmp (physical_uri, "ldap://", 7)) { - GNOME_Evolution_ShellComponentListener_notifyResult (listener, - GNOME_Evolution_ShellComponentListener_UNSUPPORTED_OPERATION, - &ev); - CORBA_exception_free(&ev); - return; - } - if (strncmp (physical_uri, "file://", 7)) { - GNOME_Evolution_ShellComponentListener_notifyResult (listener, - GNOME_Evolution_ShellComponentListener_INVALID_URI, - &ev); - CORBA_exception_free(&ev); - return; - } - - subdir_path = g_build_filename (physical_uri + 7, "subfolders", NULL); - rv = stat (subdir_path, &sb); - g_free (subdir_path); - if (rv != -1) { - GNOME_Evolution_ShellComponentListener_notifyResult (listener, - GNOME_Evolution_ShellComponentListener_HAS_SUBFOLDERS, - &ev); - CORBA_exception_free(&ev); - return; - } - - db_path = g_build_filename (physical_uri + 7, "addressbook.db", NULL); - summary_path = g_build_filename (physical_uri + 7, "addressbook.db.summary", NULL); - rv = unlink (db_path); - - if (rv == 0 || (rv == -1 && errno == ENOENT)) - rv = unlink (summary_path); + ESource *selected_source = e_source_selector_peek_primary_selection (E_SOURCE_SELECTOR (selector)); - if (rv == 0 || (rv == -1 && errno == ENOENT)) { - GNOME_Evolution_ShellComponentListener_notifyResult (listener, - GNOME_Evolution_ShellComponentListener_OK, - &ev); - } - else { - GNOME_Evolution_ShellComponentListener_notifyResult (listener, - GNOME_Evolution_ShellComponentListener_PERMISSION_DENIED, - &ev); + if (selected_source != NULL) { + char *uri = e_source_get_uri (selected_source); + bonobo_control_set_property (view_control, NULL, "folder_uri", TC_CORBA_string, uri, NULL); + g_free (uri); } - - g_free (db_path); - g_free (summary_path); - - CORBA_exception_free(&ev); } -/* ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** */ -/* This code is cut & pasted from calendar/gui/component-factory.c */ +/* Callbacks. */ -static GNOME_Evolution_ShellComponentListener_Result -xfer_file (GnomeVFSURI *base_src_uri, - GnomeVFSURI *base_dest_uri, - const char *file_name, - int remove_source) +static void +primary_source_selection_changed_callback (ESourceSelector *selector, + BonoboControl *view_control) { - GnomeVFSURI *src_uri, *dest_uri; - GnomeVFSHandle *hin, *hout; - GnomeVFSResult result; - GnomeVFSFileInfo file_info; - GnomeVFSFileSize size; - char *buffer; - - src_uri = gnome_vfs_uri_append_file_name (base_src_uri, file_name); - - result = gnome_vfs_open_uri (&hin, src_uri, GNOME_VFS_OPEN_READ); - if (result == GNOME_VFS_ERROR_NOT_FOUND) { - gnome_vfs_uri_unref (src_uri); - return GNOME_Evolution_ShellComponentListener_OK; /* No need to xfer anything. */ - } - if (result != GNOME_VFS_OK) { - gnome_vfs_uri_unref (src_uri); - return GNOME_Evolution_ShellComponentListener_PERMISSION_DENIED; - } + load_uri_for_selection (selector, view_control); +} - result = gnome_vfs_get_file_info_uri (src_uri, &file_info, GNOME_VFS_FILE_INFO_DEFAULT); - if (result != GNOME_VFS_OK) { - gnome_vfs_uri_unref (src_uri); - return GNOME_Evolution_ShellComponentListener_PERMISSION_DENIED; - } - dest_uri = gnome_vfs_uri_append_file_name (base_dest_uri, file_name); +/* Evolution::Component CORBA methods. */ - result = gnome_vfs_create_uri (&hout, dest_uri, GNOME_VFS_OPEN_WRITE, FALSE, 0600); - if (result != GNOME_VFS_OK) { - gnome_vfs_close (hin); - gnome_vfs_uri_unref (src_uri); - gnome_vfs_uri_unref (dest_uri); - return GNOME_Evolution_ShellComponentListener_PERMISSION_DENIED; - } +static void +impl_createControls (PortableServer_Servant servant, + Bonobo_Control *corba_sidebar_control, + Bonobo_Control *corba_view_control, + CORBA_Environment *ev) +{ + AddressbookComponent *addressbook_component = ADDRESSBOOK_COMPONENT (bonobo_object_from_servant (servant)); + GtkWidget *selector; + GtkWidget *selector_scrolled_window; + BonoboControl *sidebar_control; + BonoboControl *view_control; - /* write source file to destination file */ - buffer = g_malloc (file_info.size); - result = gnome_vfs_read (hin, buffer, file_info.size, &size); - if (result != GNOME_VFS_OK) { - gnome_vfs_close (hin); - gnome_vfs_close (hout); - gnome_vfs_uri_unref (src_uri); - gnome_vfs_uri_unref (dest_uri); - g_free (buffer); - return GNOME_Evolution_ShellComponentListener_PERMISSION_DENIED; - } + selector = e_source_selector_new (addressbook_component->priv->source_list); + e_source_selector_show_selection (E_SOURCE_SELECTOR (selector), FALSE); + gtk_widget_show (selector); - result = gnome_vfs_write (hout, buffer, file_info.size, &size); - if (result != GNOME_VFS_OK) { - gnome_vfs_close (hin); - gnome_vfs_close (hout); - gnome_vfs_uri_unref (src_uri); - gnome_vfs_uri_unref (dest_uri); - g_free (buffer); - return GNOME_Evolution_ShellComponentListener_PERMISSION_DENIED; - } + selector_scrolled_window = gtk_scrolled_window_new (NULL, NULL); + gtk_container_add (GTK_CONTAINER (selector_scrolled_window), selector); + gtk_widget_show (selector_scrolled_window); - if (remove_source) { - char *text_uri; + sidebar_control = bonobo_control_new (selector_scrolled_window); - /* Sigh, we have to do this as there is no gnome_vfs_unlink_uri(). :-( */ + view_control = addressbook_new_control (); + g_signal_connect_object (selector, "primary_selection_changed", + G_CALLBACK (primary_source_selection_changed_callback), + G_OBJECT (view_control), 0); + load_uri_for_selection (E_SOURCE_SELECTOR (selector), view_control); - text_uri = gnome_vfs_uri_to_string (src_uri, GNOME_VFS_URI_HIDE_NONE); - result = gnome_vfs_unlink (text_uri); - g_free (text_uri); - } + *corba_sidebar_control = CORBA_Object_duplicate (BONOBO_OBJREF (sidebar_control), ev); + *corba_view_control = CORBA_Object_duplicate (BONOBO_OBJREF (view_control), ev); +} - gnome_vfs_close (hin); - gnome_vfs_close (hout); - gnome_vfs_uri_unref (src_uri); - gnome_vfs_uri_unref (dest_uri); - g_free (buffer); - return GNOME_Evolution_ShellComponentListener_OK; -} +/* GObject methods. */ static void -xfer_folder (EvolutionShellComponent *shell_component, - const char *source_physical_uri, - const char *destination_physical_uri, - const char *type, - gboolean remove_source, - const GNOME_Evolution_ShellComponentListener listener, - void *closure) +impl_dispose (GObject *object) { - CORBA_Environment ev; - - GnomeVFSURI *src_uri; - GnomeVFSURI *dest_uri; - GnomeVFSResult result; - GNOME_Evolution_ShellComponentListener_Result e_result; - - CORBA_exception_init (&ev); - - if (!IS_CONTACT_TYPE (type)) { - GNOME_Evolution_ShellComponentListener_notifyResult (listener, - GNOME_Evolution_ShellComponentListener_UNSUPPORTED_TYPE, - &ev); - CORBA_exception_free(&ev); - return; - } - - if (!strncmp (source_physical_uri, "ldap://", 7) - || !strncmp (destination_physical_uri, "ldap://", 7)) { - GNOME_Evolution_ShellComponentListener_notifyResult (listener, - GNOME_Evolution_ShellComponentListener_UNSUPPORTED_OPERATION, - &ev); - CORBA_exception_free(&ev); - return; - } - - if (strncmp (source_physical_uri, "file://", 7) - || strncmp (destination_physical_uri, "file://", 7)) { - GNOME_Evolution_ShellComponentListener_notifyResult (listener, - GNOME_Evolution_ShellComponentListener_INVALID_URI, - &ev); - CORBA_exception_free(&ev); - return; - } + AddressbookComponentPrivate *priv = ADDRESSBOOK_COMPONENT (object)->priv; - /* check URIs */ - src_uri = gnome_vfs_uri_new (source_physical_uri); - dest_uri = gnome_vfs_uri_new (destination_physical_uri); - if (!src_uri || ! dest_uri) { - GNOME_Evolution_ShellComponentListener_notifyResult ( - listener, - GNOME_Evolution_ShellComponentListener_INVALID_URI, - &ev); - gnome_vfs_uri_unref (src_uri); - gnome_vfs_uri_unref (dest_uri); - CORBA_exception_free (&ev); - return; + if (priv->source_list != NULL) { + g_object_unref (priv->source_list); + priv->source_list = NULL; } - e_result = xfer_file (src_uri, dest_uri, "addressbook.db", remove_source); - - if ((e_result == GNOME_Evolution_ShellComponentListener_OK) && remove_source) { - char *summary_uri; - - summary_uri = g_strconcat (source_physical_uri, "/addressbook.db.summary", NULL); - result = gnome_vfs_unlink (summary_uri); - if (result != GNOME_VFS_OK && result != GNOME_VFS_ERROR_NOT_FOUND) - e_result = GNOME_Evolution_ShellComponentListener_PERMISSION_DENIED; - g_free (summary_uri); + if (priv->gconf_client != NULL) { + g_object_unref (priv->gconf_client); + priv->gconf_client = NULL; } - GNOME_Evolution_ShellComponentListener_notifyResult (listener, e_result, &ev); - - gnome_vfs_uri_unref (src_uri); - gnome_vfs_uri_unref (dest_uri); - - CORBA_exception_free (&ev); -} - -static char* -get_dnd_selection (EvolutionShellComponent *shell_component, - const char *physical_uri, - int type, - int *format_return, - const char **selection_return, - int *selection_length_return, - void *closure) -{ - /* g_print ("should get dnd selection for %s\n", physical_uri); */ - return NULL; + (* G_OBJECT_CLASS (parent_class)->dispose) (object); } -static int owner_count = 0; - static void -owner_set_cb (EvolutionShellComponent *shell_component, - EvolutionShellClient *shell_client, - const char *evolution_homedir, - gpointer user_data) +impl_finalize (GObject *object) { - owner_count ++; + AddressbookComponentPrivate *priv = ADDRESSBOOK_COMPONENT (object)->priv; - if (global_shell_client == NULL) - global_shell_client = shell_client; + g_free (priv); - addressbook_storage_setup (shell_component, evolution_homedir); + (* G_OBJECT_CLASS (parent_class)->finalize) (object); } -static void -owner_unset_cb (EvolutionShellComponent *shell_component, - GNOME_Evolution_Shell shell_interface, - gpointer user_data) -{ - owner_count --; - - if (owner_count == 0) - global_shell_client = NULL; - addressbook_storage_cleanup (); -} +/* Initialization. */ -/* FIXME We should perhaps take the time to figure out if the book is editable. */ static void -new_item_cb (EBook *book, gpointer closure) +addressbook_component_class_init (AddressbookComponentClass *class) { - gboolean is_list = GPOINTER_TO_INT (closure); - ECard *card; - - if (book == NULL) - return; - - card = e_card_new (""); - if (is_list) - e_addressbook_show_contact_list_editor (book, card, TRUE, TRUE); - else - e_addressbook_show_contact_editor (book, card, TRUE, TRUE); - g_object_unref (card); -} + POA_GNOME_Evolution_Component__epv *epv = &class->epv; + GObjectClass *object_class = G_OBJECT_CLASS (class); -static void -user_create_new_item_cb (EvolutionShellComponent *shell_component, - const char *id, - const char *parent_folder_physical_uri, - const char *parent_folder_type, - gpointer data) -{ - gboolean is_contact_list; - if (!strcmp (id, "contact")) { - is_contact_list = FALSE; - } else if (!strcmp (id, "contact_list")) { - is_contact_list = TRUE; - } else { - g_warning ("Don't know how to create item of type \"%s\"", id); - return; - } - if (IS_CONTACT_TYPE (parent_folder_type)) { - e_book_use_address_book_by_uri (parent_folder_physical_uri, - new_item_cb, GINT_TO_POINTER (is_contact_list)); - } else { - e_book_use_default_book (new_item_cb, GINT_TO_POINTER (is_contact_list)); - } -} + epv->createControls = impl_createControls; - -/* Destination side DnD */ + object_class->dispose = impl_dispose; + object_class->finalize = impl_finalize; -static CORBA_boolean -destination_folder_handle_motion (EvolutionShellComponentDndDestinationFolder *folder, - const char *physical_uri, - const char *folder_type, - const GNOME_Evolution_ShellComponentDnd_DestinationFolder_Context * destination_context, - GNOME_Evolution_ShellComponentDnd_Action * suggested_action_return, - gpointer user_data) -{ - *suggested_action_return = GNOME_Evolution_ShellComponentDnd_ACTION_MOVE; - return TRUE; + parent_class = g_type_class_peek_parent (class); } static void -dnd_drop_book_open_cb (EBook *book, EBookStatus status, GList *card_list) -{ - GList *l; - - for (l = card_list; l; l = l->next) { - ECard *card = l->data; - - e_card_merging_book_add_card (book, card, NULL /* XXX */, NULL); - } -} - -static CORBA_boolean -destination_folder_handle_drop (EvolutionShellComponentDndDestinationFolder *folder, - const char *physical_uri, - const char *folder_type, - const GNOME_Evolution_ShellComponentDnd_DestinationFolder_Context * destination_context, - const GNOME_Evolution_ShellComponentDnd_Action action, - const GNOME_Evolution_ShellComponentDnd_Data * data, - gpointer user_data) +addressbook_component_init (AddressbookComponent *component) { - EBook *book; - GList *card_list; - char *expanded_uri; - - if (action == GNOME_Evolution_ShellComponentDnd_ACTION_LINK) - return FALSE; /* we can't create links in our addressbook format */ - - /* g_print ("in destination_folder_handle_drop (%s)\n", physical_uri); */ - - card_list = e_card_load_cards_from_string_with_default_charset (data->bytes._buffer, "ISO-8859-1"); - - expanded_uri = e_book_expand_uri (physical_uri); + AddressbookComponentPrivate *priv; - book = e_book_new (); - addressbook_load_uri (book, expanded_uri, - (EBookCallback)dnd_drop_book_open_cb, card_list); + priv = g_new0 (AddressbookComponentPrivate, 1); - g_free (expanded_uri); + /* EPFIXME: Should use a custom one instead? Also we should add + addressbook_component_peek_gconf_client(). */ + priv->gconf_client = gconf_client_get_default (); - return TRUE; -} - - -/* Quitting. */ + priv->source_list = e_source_list_new_for_gconf (priv->gconf_client, + "/apps/evolution/addressbook/sources"); -static gboolean -request_quit (EvolutionShellComponent *shell_component, - void *data) -{ - if (! e_contact_editor_request_close_all () - || ! e_contact_list_editor_request_close_all ()) - return FALSE; - else - return TRUE; + component->priv = priv; } - -/* The factory function. */ - -static void -add_creatable_item (EvolutionShellComponent *shell_component, - const char *id, - const char *description, - const char *menu_description, - const char *tooltip, - char menu_shortcut, - const char *icon_name) -{ - char *icon_path; - GdkPixbuf *icon; - - if (icon_name == NULL) { - icon_path = NULL; - icon = NULL; - } else { - icon_path = g_build_filename (EVOLUTION_IMAGESDIR, icon_name, NULL); - icon = gdk_pixbuf_new_from_file (icon_path, NULL); - } - - evolution_shell_component_add_user_creatable_item (shell_component, - id, - description, - menu_description, - tooltip, - "contacts", - menu_shortcut, - icon); - - if (icon != NULL) - gdk_pixbuf_unref (icon); - g_free (icon_path); -} +/* Public API. */ -static BonoboObject * -create_component (void) +AddressbookComponent * +addressbook_component_peek (void) { - EvolutionShellComponent *shell_component; - EvolutionShellComponentDndDestinationFolder *destination_interface; - - shell_component = evolution_shell_component_new (folder_types, NULL, - create_view, create_folder, - remove_folder, xfer_folder, - NULL, NULL, - get_dnd_selection, - request_quit, - NULL); - - destination_interface = evolution_shell_component_dnd_destination_folder_new (destination_folder_handle_motion, - destination_folder_handle_drop, - shell_component); - - bonobo_object_add_interface (BONOBO_OBJECT (shell_component), - BONOBO_OBJECT (destination_interface)); - - add_creatable_item (shell_component, "contact", - _("New Contact"), _("_Contact"), - _("Create a new contact"), 'c', - "evolution-contacts-mini.png"); - add_creatable_item (shell_component, "contact_list", - _("New Contact List"), _("Contact _List"), - _("Create a new contact list"), 'l', - "contact-list-16.png"); - - g_signal_connect (shell_component, "owner_set", - G_CALLBACK (owner_set_cb), NULL); - g_signal_connect (shell_component, "owner_unset", - G_CALLBACK (owner_unset_cb), NULL); - g_signal_connect (shell_component, "user_create_new_item", - G_CALLBACK (user_create_new_item_cb), NULL); - - return BONOBO_OBJECT (shell_component); -} + static AddressbookComponent *component = NULL; -static void -ensure_completion_uris_exist() -{ - /* Initialize the completion uris if they aren't set yet. The - default set is just the local Contacts folder. */ - EConfigListener *db; - char *val; - - db = e_book_get_config_database (); - - val = e_config_listener_get_string (db, "/apps/evolution/addressbook/completion/uris"); - - if (val && !*val) { - g_free (val); - val = NULL; - } - - if (!val) { - EFolderListItem f[2]; - char *dirname, *uri; - /* in the case where the user is running for the first - time, populate the list with the local contact - folder */ - dirname = g_build_filename (g_get_home_dir (), "evolution/local/Contacts", NULL); - uri = g_strdup_printf ("file://%s", dirname); - - f[0].uri = "evolution:/local/Contacts"; - f[0].physical_uri = uri; - f[0].display_name = _("Contacts"); - - memset (&f[1], 0, sizeof (f[1])); - - val = e_folder_list_create_xml (f); - - g_free (dirname); - g_free (uri); - e_config_listener_set_string (db, "/apps/evolution/addressbook/completion/uris", val); - } + if (component == NULL) + component = g_object_new (addressbook_component_get_type (), NULL); - g_free (val); + return component; } - -/* FIXME this is wrong. */ -BonoboObject * -addressbook_component_init (void) -{ - ensure_completion_uris_exist (); - return create_component (); -} +BONOBO_TYPE_FUNC_FULL (AddressbookComponent, GNOME_Evolution_Component, PARENT_TYPE, addressbook_component) diff --git a/addressbook/gui/component/addressbook-component.h b/addressbook/gui/component/addressbook-component.h index 4c6f0cdd8b..bf72a431d8 100644 --- a/addressbook/gui/component/addressbook-component.h +++ b/addressbook/gui/component/addressbook-component.h @@ -1,7 +1,7 @@ /* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */ /* addressbook-component.h * - * Copyright (C) 2000 Ximian, Inc. + * Copyright (C) 2003 Ximian, Inc. * * This program is free software; you can redistribute it and/or * modify it under the terms of version 2 of the GNU General Public @@ -17,16 +17,43 @@ * Free Software Foundation, Inc., 59 Temple Place - Suite 330, * Boston, MA 02111-1307, USA. * - * Author: Ettore Perazzoli + * Author: Ettore Perazzoli */ -#ifndef _ADDRESSBOOK_COMPONENT_H -#define _ADDRESSBOOK_COMPONENT_H +#ifndef _ADDRESSBOOK_COMPONENT_H_ +#define _ADDRESSBOOK_COMPONENT_H_ -#include "evolution-shell-component.h" -#include "evolution-storage.h" +#include -BonoboObject *addressbook_component_init (void); -EvolutionShellClient *addressbook_component_get_shell_client (void); +#include "Evolution.h" -#endif /* _ADDRESSBOOK_COMPONENT_H */ +#define ADDRESSBOOK_TYPE_COMPONENT (addressbook_component_get_type ()) +#define ADDRESSBOOK_COMPONENT(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), ADDRESSBOOK_TYPE_COMPONENT, AddressbookComponent)) +#define ADDRESSBOOK_COMPONENT_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), ADDRESSBOOK_TYPE_COMPONENT, AddressbookComponentClass)) +#define ADDRESSBOOK_IS_COMPONENT(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), ADDRESSBOOK_TYPE_COMPONENT)) +#define ADDRESSBOOK_IS_COMPONENT_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((obj), ADDRESSBOOK_TYPE_COMPONENT)) + + +typedef struct _AddressbookComponent AddressbookComponent; +typedef struct _AddressbookComponentPrivate AddressbookComponentPrivate; +typedef struct _AddressbookComponentClass AddressbookComponentClass; + +struct _AddressbookComponent { + BonoboObject parent; + + AddressbookComponentPrivate *priv; +}; + +struct _AddressbookComponentClass { + BonoboObjectClass parent_class; + + POA_GNOME_Evolution_Component__epv epv; +}; + + +GType addressbook_component_get_type (void); + +AddressbookComponent *addressbook_component_peek (void); + + +#endif /* _ADDRESSBOOK_COMPONENT_H_ */ diff --git a/addressbook/gui/component/addressbook-config.c b/addressbook/gui/component/addressbook-config.c index e2855ac7f4..c5fc9c127a 100644 --- a/addressbook/gui/component/addressbook-config.c +++ b/addressbook/gui/component/addressbook-config.c @@ -107,7 +107,6 @@ struct _AddressbookDialog { GtkWidget *page; GladeXML *gui; - GNOME_Evolution_Shell shell; GtkWidget *sourcesTable; GtkTreeModel *sourcesModel; @@ -1555,7 +1554,7 @@ sources_table_row_activated (GtkTreeView *tree_view, GtkTreePath *path, static AddressbookDialog * -ldap_dialog_new (GNOME_Evolution_Shell shell) +ldap_dialog_new (void) { AddressbookDialog *dialog; GList *l; @@ -1564,7 +1563,6 @@ ldap_dialog_new (GNOME_Evolution_Shell shell) dialog = g_new0 (AddressbookDialog, 1); dialog->gui = glade_xml_new (EVOLUTION_GLADEDIR "/" GLADE_FILE_NAME, NULL, NULL); - dialog->shell = shell; scrolled = glade_xml_get_widget (dialog->gui, "sourcesTable"); dialog->sourcesTable = g_object_get_data (G_OBJECT (scrolled), "table"); @@ -1657,7 +1655,7 @@ addressbook_dialog_create_sources_table (char *name, char *string1, char *string #endif /* HAVE_LDAP */ static EvolutionConfigControl * -ldap_config_control_new (GNOME_Evolution_Shell shell) +ldap_config_control_new (void) { GtkWidget *control_widget; EvolutionConfigControl *control; @@ -1665,7 +1663,7 @@ ldap_config_control_new (GNOME_Evolution_Shell shell) #ifdef HAVE_LDAP AddressbookDialog *dialog; - dialog = ldap_dialog_new (shell); + dialog = ldap_dialog_new (); control_widget = dialog->page; @@ -1697,13 +1695,7 @@ ldap_config_control_new (GNOME_Evolution_Shell shell) EvolutionConfigControl * addressbook_config_control_new (void) { - GNOME_Evolution_Shell shell; - - shell = evolution_shell_client_corba_objref (addressbook_component_get_shell_client ()); - if (! shell) - return NULL; - - return ldap_config_control_new (shell); + return ldap_config_control_new (); } void diff --git a/addressbook/gui/component/addressbook.c b/addressbook/gui/component/addressbook.c index b21c70a83d..32c5ab1288 100644 --- a/addressbook/gui/component/addressbook.c +++ b/addressbook/gui/component/addressbook.c @@ -24,7 +24,6 @@ #include #include -#include #include #include #include @@ -41,23 +40,20 @@ #include "e-util/e-categories-master-list-wombat.h" #include "e-util/e-sexp.h" #include "e-util/e-passwords.h" -#include "select-names/e-select-names.h" -#include "select-names/e-select-names-manager.h" #include "evolution-shell-component-utils.h" #include "evolution-activity-client.h" #include "e-contact-editor.h" -#include "e-contact-save-as.h" #include "addressbook-config.h" #include "addressbook.h" #include "addressbook-component.h" #include "addressbook/gui/search/e-addressbook-search-dialog.h" #include "addressbook/gui/widgets/e-addressbook-view.h" -#include "addressbook/gui/widgets/e-addressbook-util.h" +#include "addressbook/gui/widgets/eab-gui-util.h" #include "addressbook/printing/e-contact-print.h" +#include "addressbook/util/eab-book-util.h" -#include -#include +#include #include #include @@ -73,7 +69,7 @@ static GdkPixbuf *progress_icon[2] = { NULL, NULL }; typedef struct { gint refs; - EAddressbookView *view; + EABView *view; ESearchBar *search; gint ecml_changed_id; GtkWidget *vbox; @@ -100,7 +96,7 @@ save_contact_cb (BonoboUIComponent *uih, void *user_data, const char *path) { AddressbookView *view = (AddressbookView *) user_data; if (view->view) - e_addressbook_view_save_as(view->view); + eab_view_save_as(view->view); } static void @@ -108,7 +104,7 @@ view_contact_cb (BonoboUIComponent *uih, void *user_data, const char *path) { AddressbookView *view = (AddressbookView *) user_data; if (view->view) - e_addressbook_view_view(view->view); + eab_view_view(view->view); } static void @@ -117,7 +113,7 @@ search_cb (BonoboUIComponent *uih, void *user_data, const char *path) AddressbookView *view = (AddressbookView *) user_data; if (view->view) - gtk_widget_show(e_addressbook_search_dialog_new(view->view)); + gtk_widget_show(eab_search_dialog_new(view->view)); } static void @@ -125,7 +121,7 @@ delete_contact_cb (BonoboUIComponent *uih, void *user_data, const char *path) { AddressbookView *view = (AddressbookView *) user_data; if (view->view) { - e_addressbook_view_delete_selection(view->view); + eab_view_delete_selection(view->view); } } @@ -134,7 +130,7 @@ print_cb (BonoboUIComponent *uih, void *user_data, const char *path) { AddressbookView *view = (AddressbookView *) user_data; if (view->view) - e_addressbook_view_print(view->view); + eab_view_print(view->view); } static void @@ -142,7 +138,7 @@ print_preview_cb (BonoboUIComponent *uih, void *user_data, const char *path) { AddressbookView *view = (AddressbookView *) user_data; if (view->view) - e_addressbook_view_print_preview(view->view); + eab_view_print_preview(view->view); } static void @@ -150,7 +146,7 @@ stop_loading_cb (BonoboUIComponent *uih, void *user_data, const char *path) { AddressbookView *view = (AddressbookView *) user_data; if (view->view) - e_addressbook_view_stop(view->view); + eab_view_stop(view->view); } static void @@ -158,7 +154,7 @@ cut_contacts_cb (BonoboUIComponent *uih, void *user_data, const char *path) { AddressbookView *view = (AddressbookView *) user_data; if (view->view) - e_addressbook_view_cut(view->view); + eab_view_cut(view->view); } static void @@ -166,7 +162,7 @@ copy_contacts_cb (BonoboUIComponent *uih, void *user_data, const char *path) { AddressbookView *view = (AddressbookView *) user_data; if (view->view) - e_addressbook_view_copy(view->view); + eab_view_copy(view->view); } static void @@ -174,7 +170,7 @@ paste_contacts_cb (BonoboUIComponent *uih, void *user_data, const char *path) { AddressbookView *view = (AddressbookView *) user_data; if (view->view) - e_addressbook_view_paste(view->view); + eab_view_paste(view->view); } static void @@ -182,7 +178,7 @@ select_all_contacts_cb (BonoboUIComponent *uih, void *user_data, const char *pat { AddressbookView *view = (AddressbookView *) user_data; if (view->view) - e_addressbook_view_select_all (view->view); + eab_view_select_all (view->view); } static void @@ -190,7 +186,7 @@ send_contact_cb (BonoboUIComponent *uih, void *user_data, const char *path) { AddressbookView *view = (AddressbookView *) user_data; if (view->view) - e_addressbook_view_send (view->view); + eab_view_send (view->view); } static void @@ -198,7 +194,7 @@ send_contact_to_cb (BonoboUIComponent *uih, void *user_data, const char *path) { AddressbookView *view = (AddressbookView *) user_data; if (view->view) - e_addressbook_view_send_to (view->view); + eab_view_send_to (view->view); } static void @@ -206,7 +202,7 @@ copy_contact_to_cb (BonoboUIComponent *uih, void *user_data, const char *path) { AddressbookView *view = (AddressbookView *) user_data; if (view->view) - e_addressbook_view_copy_to_folder (view->view); + eab_view_copy_to_folder (view->view); } static void @@ -214,7 +210,7 @@ move_contact_to_cb (BonoboUIComponent *uih, void *user_data, const char *path) { AddressbookView *view = (AddressbookView *) user_data; if (view->view) - e_addressbook_view_move_to_folder (view->view); + eab_view_move_to_folder (view->view); } static void @@ -224,7 +220,7 @@ forget_passwords_cb (BonoboUIComponent *uih, void *user_data, const char *path) } static void -update_command_state (EAddressbookView *eav, AddressbookView *view) +update_command_state (EABView *eav, AddressbookView *view) { BonoboUIComponent *uic; @@ -239,78 +235,78 @@ update_command_state (EAddressbookView *eav, AddressbookView *view) bonobo_ui_component_set_prop (uic, "/commands/ContactsSaveAsVCard", "sensitive", - e_addressbook_view_can_save_as (view->view) ? "1" : "0", NULL); + eab_view_can_save_as (view->view) ? "1" : "0", NULL); bonobo_ui_component_set_prop (uic, "/commands/ContactsView", "sensitive", - e_addressbook_view_can_view (view->view) ? "1" : "0", NULL); + eab_view_can_view (view->view) ? "1" : "0", NULL); /* Print Contact */ bonobo_ui_component_set_prop (uic, "/commands/ContactsPrint", "sensitive", - e_addressbook_view_can_print (view->view) ? "1" : "0", NULL); + eab_view_can_print (view->view) ? "1" : "0", NULL); /* Print Contact */ bonobo_ui_component_set_prop (uic, "/commands/ContactsPrintPreview", "sensitive", - e_addressbook_view_can_print (view->view) ? "1" : "0", NULL); + eab_view_can_print (view->view) ? "1" : "0", NULL); /* Delete Contact */ bonobo_ui_component_set_prop (uic, "/commands/ContactDelete", "sensitive", - e_addressbook_view_can_delete (view->view) ? "1" : "0", NULL); + eab_view_can_delete (view->view) ? "1" : "0", NULL); bonobo_ui_component_set_prop (uic, "/commands/ContactsCut", "sensitive", - e_addressbook_view_can_cut (view->view) ? "1" : "0", NULL); + eab_view_can_cut (view->view) ? "1" : "0", NULL); bonobo_ui_component_set_prop (uic, "/commands/ContactsCopy", "sensitive", - e_addressbook_view_can_copy (view->view) ? "1" : "0", NULL); + eab_view_can_copy (view->view) ? "1" : "0", NULL); bonobo_ui_component_set_prop (uic, "/commands/ContactsPaste", "sensitive", - e_addressbook_view_can_paste (view->view) ? "1" : "0", NULL); + eab_view_can_paste (view->view) ? "1" : "0", NULL); bonobo_ui_component_set_prop (uic, "/commands/ContactsSelectAll", "sensitive", - e_addressbook_view_can_select_all (view->view) ? "1" : "0", NULL); + eab_view_can_select_all (view->view) ? "1" : "0", NULL); bonobo_ui_component_set_prop (uic, "/commands/ContactsSendContactToOther", "sensitive", - e_addressbook_view_can_send (view->view) ? "1" : "0", NULL); + eab_view_can_send (view->view) ? "1" : "0", NULL); bonobo_ui_component_set_prop (uic, "/commands/ContactsSendMessageToContact", "sensitive", - e_addressbook_view_can_send_to (view->view) ? "1" : "0", NULL); + eab_view_can_send_to (view->view) ? "1" : "0", NULL); bonobo_ui_component_set_prop (uic, "/commands/ContactsMoveToFolder", "sensitive", - e_addressbook_view_can_move_to_folder (view->view) ? "1" : "0", NULL); + eab_view_can_move_to_folder (view->view) ? "1" : "0", NULL); bonobo_ui_component_set_prop (uic, "/commands/ContactsCopyToFolder", "sensitive", - e_addressbook_view_can_copy_to_folder (view->view) ? "1" : "0", NULL); + eab_view_can_copy_to_folder (view->view) ? "1" : "0", NULL); /* Stop */ bonobo_ui_component_set_prop (uic, "/commands/ContactStop", "sensitive", - e_addressbook_view_can_stop (view->view) ? "1" : "0", NULL); + eab_view_can_stop (view->view) ? "1" : "0", NULL); } addressbook_view_unref (view); } static void -change_view_type (AddressbookView *view, EAddressbookViewType view_type) +change_view_type (AddressbookView *view, EABViewType view_type) { g_object_set (view->view, "type", view_type, NULL); } @@ -379,7 +375,7 @@ control_activate (BonoboControl *control, EVOLUTION_UIDIR "/evolution-addressbook.xml", "evolution-addressbook", NULL); - e_addressbook_view_setup_menus (view->view, uic); + eab_view_setup_menus (view->view, uic); e_pixmaps_update (uic, pixmaps); @@ -401,25 +397,21 @@ control_activate_cb (BonoboControl *control, if (activate) { control_activate (control, uic, view); if (activate && view->view && view->view->model) - e_addressbook_model_force_folder_bar_message (view->view->model); + eab_model_force_folder_bar_message (view->view->model); /* if the book failed to load, we kick off another load here */ if (view->failed_to_load && view->uri) { EBook *book; - char *uri_data; book = e_book_new (); - uri_data = e_book_expand_uri (view->uri); - addressbook_load_uri (book, uri_data, book_open_cb, view); - - g_free(uri_data); + addressbook_load_uri (book, view->uri, book_open_cb, view); } } else { bonobo_ui_component_unset_container (uic, NULL); - e_addressbook_view_discard_menus (view->view); + eab_view_discard_menus (view->view); } } @@ -482,7 +474,7 @@ book_open_cb (EBook *book, EBookStatus status, gpointer closure) { AddressbookView *view = closure; - if (status == E_BOOK_STATUS_SUCCESS) { + if (status == E_BOOK_ERROR_OK) { view->failed_to_load = FALSE; g_object_set(view->view, "book", book, @@ -596,8 +588,8 @@ load_uri_auth_cb (EBook *book, EBookStatus status, gpointer closure) { LoadUriData *data = closure; - if (status != E_BOOK_STATUS_SUCCESS) { - if (status == E_BOOK_STATUS_CANCELLED) { + if (status != E_BOOK_ERROR_OK) { + if (status == E_BOOK_ERROR_CANCELLED) { /* the user clicked cancel in the password dialog */ GtkWidget *dialog; dialog = gtk_message_dialog_new (NULL, @@ -607,7 +599,7 @@ load_uri_auth_cb (EBook *book, EBookStatus status, gpointer closure) _("Accessing LDAP Server anonymously")); g_signal_connect (dialog, "response", G_CALLBACK(gtk_widget_destroy), NULL); gtk_widget_show (dialog); - data->cb (book, E_BOOK_STATUS_SUCCESS, data->closure); + data->cb (book, E_BOOK_ERROR_OK, data->closure); g_free (data->clean_uri); g_free (data); return; @@ -682,15 +674,15 @@ addressbook_authenticate (EBook *book, gboolean previous_failure, AddressbookSou user = source->email_addr; if (!user) user = ""; - e_book_authenticate_user (book, user, password ? password : pass_dup, - addressbook_storage_auth_type_to_string (source->auth), - cb, closure); + e_book_async_authenticate_user (book, user, password ? password : pass_dup, + addressbook_storage_auth_type_to_string (source->auth), + cb, closure); g_free (pass_dup); return; } else { /* they hit cancel */ - cb (book, E_BOOK_STATUS_CANCELLED, closure); + cb (book, E_BOOK_ERROR_CANCELLED, closure); } } @@ -699,7 +691,7 @@ load_uri_cb (EBook *book, EBookStatus status, gpointer closure) { LoadUriData *load_uri_data = closure; - if (status == E_BOOK_STATUS_SUCCESS && book != NULL) { + if (status == E_BOOK_ERROR_OK && book != NULL) { /* check if the addressbook needs authentication */ @@ -728,18 +720,18 @@ addressbook_load_uri (EBook *book, const char *uri, load_uri_data->cb = cb; load_uri_data->closure = closure; - e_book_load_uri (book, uri, load_uri_cb, load_uri_data); + e_book_async_load_uri (book, uri, load_uri_cb, load_uri_data); } void -addressbook_load_default_book (EBook *book, EBookCallback cb, gpointer closure) +addressbook_load_default_book (EBookCallback cb, gpointer closure) { LoadUriData *load_uri_data = g_new (LoadUriData, 1); load_uri_data->cb = cb; load_uri_data->closure = closure; - e_book_load_default_book (book, load_uri_cb, load_uri_data); + e_book_async_get_default_addressbook (load_uri_cb, load_uri_data); } static void @@ -751,14 +743,12 @@ set_prop (BonoboPropertyBag *bag, { AddressbookView *view = user_data; - char *uri_data; - switch (arg_id) { case PROPERTY_FOLDER_URI_IDX: if (view->uri) { /* we've already had a uri set on this view, so unload it */ - e_book_unload_uri (view->book); + e_book_async_unload_uri (view->book); g_free (view->uri); } else { view->book = e_book_new (); @@ -768,11 +758,7 @@ set_prop (BonoboPropertyBag *bag, view->uri = g_strdup(BONOBO_ARG_GET_STRING (arg)); - uri_data = e_book_expand_uri (view->uri); - - addressbook_load_uri (view->book, uri_data, book_open_cb, view); - - g_free(uri_data); + addressbook_load_uri (view->book, view->uri, book_open_cb, view); break; @@ -799,19 +785,6 @@ static ESearchBarItem addressbook_search_option_items[] = { { NULL, -1, NULL } }; -static void -alphabet_state_changed (EAddressbookView *eav, gunichar letter, AddressbookView *view) -{ - view->ignore_search_changes = TRUE; - if (letter == 0) { - e_search_bar_set_item_id (view->search, ESB_FULL_NAME); - e_search_bar_set_text (view->search, ""); - } else { - e_search_bar_set_item_id (view->search, ESB_FULL_NAME); - } - view->ignore_search_changes = FALSE; -} - static void addressbook_search_activated (ESearchBar *esb, AddressbookView *view) { @@ -830,7 +803,7 @@ addressbook_search_activated (ESearchBar *esb, AddressbookView *view) NULL); if (search_type == ESB_ADVANCED) { - gtk_widget_show(e_addressbook_search_dialog_new(view->view)); + gtk_widget_show(eab_search_dialog_new(view->view)); } else { if ((search_word && strlen (search_word)) || search_type == ESB_CATEGORY) { @@ -890,7 +863,7 @@ addressbook_query_changed (ESearchBar *esb, AddressbookView *view) NULL); if (search_type == ESB_ADVANCED) { - gtk_widget_show(e_addressbook_search_dialog_new(view->view)); + gtk_widget_show(eab_search_dialog_new(view->view)); } } @@ -916,7 +889,7 @@ retrieve_shell_view_interface_from_control (BonoboControl *control) } static void -set_status_message (EAddressbookView *eav, const char *message, AddressbookView *view) +set_status_message (EABView *eav, const char *message, AddressbookView *view) { if (!message || !*message) { @@ -925,6 +898,7 @@ set_status_message (EAddressbookView *eav, const char *message, AddressbookView view->activity = NULL; } } +#if 0 /* EPFIXME */ else if (!view->activity) { int display; char *clientid = g_strdup_printf ("%p", view); @@ -937,6 +911,7 @@ set_status_message (EAddressbookView *eav, const char *message, AddressbookView g_free (clientid); } +#endif else { evolution_activity_client_update (view->activity, message, -1.0); } @@ -944,12 +919,12 @@ set_status_message (EAddressbookView *eav, const char *message, AddressbookView } static void -search_result (EAddressbookView *eav, EBookViewStatus status, AddressbookView *view) +search_result (EABView *eav, EBookViewStatus status, AddressbookView *view) { char *str = NULL; switch (status) { - case E_BOOK_VIEW_STATUS_SUCCESS: + case E_BOOK_VIEW_STATUS_OK: return; case E_BOOK_VIEW_STATUS_SIZE_LIMIT_EXCEEDED: str = _("More cards matched this query than either the server is \n" @@ -963,14 +938,13 @@ search_result (EAddressbookView *eav, EBookViewStatus status, AddressbookView *v "more specific or raise the time limit in the directory server\n" "preferences for this addressbook."); break; - case E_BOOK_VIEW_STATUS_INVALID_QUERY: + case E_BOOK_VIEW_ERROR_INVALID_QUERY: str = _("The backend for this addressbook was unable to parse this query."); break; - case E_BOOK_VIEW_STATUS_QUERY_REFUSED: + case E_BOOK_VIEW_ERROR_QUERY_REFUSED: str = _("The backend for this addressbook refused to perform this query."); break; - case E_BOOK_VIEW_STATUS_OTHER_ERROR: - case E_BOOK_VIEW_STATUS_UNKNOWN: + case E_BOOK_VIEW_ERROR_OTHER_ERROR: str = _("This query did not complete successfully."); break; } @@ -988,7 +962,7 @@ search_result (EAddressbookView *eav, EBookViewStatus status, AddressbookView *v } static void -set_folder_bar_label (EAddressbookView *eav, const char *message, AddressbookView *view) +set_folder_bar_label (EABView *eav, const char *message, AddressbookView *view) { CORBA_Environment ev; GNOME_Evolution_ShellView shell_view_interface; @@ -1023,18 +997,6 @@ set_folder_bar_label (EAddressbookView *eav, const char *message, AddressbookVie bonobo_object_release_unref (shell_view_interface, NULL); } -/* Our global singleton config database */ -static Bonobo_ConfigDatabase config_db = NULL; - -Bonobo_ConfigDatabase -addressbook_config_database (CORBA_Environment *ev) -{ - if (config_db == NULL) - config_db = bonobo_get_object ("wombat:", "Bonobo/ConfigDatabase", ev); - - return config_db; -} - static int compare_subitems (const void *a, const void *b) { @@ -1098,10 +1060,6 @@ BonoboControl * addressbook_new_control (void) { AddressbookView *view; - GtkWidget *frame; - - frame = gtk_frame_new (NULL); - gtk_frame_set_shadow_type (GTK_FRAME (frame), GTK_SHADOW_IN); view = g_new0 (AddressbookView, 1); view->refs = 1; @@ -1125,15 +1083,13 @@ addressbook_new_control (void) g_signal_connect (view->search, "search_activated", G_CALLBACK (addressbook_search_activated), view); - view->view = E_ADDRESSBOOK_VIEW(e_addressbook_view_new()); - gtk_container_add (GTK_CONTAINER (frame), GTK_WIDGET (view->view)); - gtk_box_pack_start (GTK_BOX (view->vbox), frame, + view->view = EAB_VIEW(eab_view_new()); + gtk_box_pack_start (GTK_BOX (view->vbox), GTK_WIDGET (view->view), TRUE, TRUE, 0); /* create the initial view */ - change_view_type (view, E_ADDRESSBOOK_VIEW_MINICARD); + change_view_type (view, EAB_VIEW_TABLE); - gtk_widget_show (frame); gtk_widget_show (view->vbox); gtk_widget_show (GTK_WIDGET(view->view)); gtk_widget_show (GTK_WIDGET(view->search)); @@ -1142,36 +1098,24 @@ addressbook_new_control (void) bonobo_property_bag_add (view->properties, PROPERTY_FOLDER_URI, PROPERTY_FOLDER_URI_IDX, - BONOBO_ARG_STRING, NULL, _("The URI that the Folder Browser will display"), 0); + BONOBO_ARG_STRING, NULL, + _("URI of the contacts that the control will display"), 0); bonobo_control_set_properties (view->control, bonobo_object_corba_objref (BONOBO_OBJECT (view->properties)), NULL); - g_signal_connect (view->view, - "status_message", - G_CALLBACK(set_status_message), - view); - - g_signal_connect (view->view, - "search_result", - G_CALLBACK(search_result), - view); - - g_signal_connect (view->view, - "folder_bar_message", - G_CALLBACK(set_folder_bar_label), - view); - - g_signal_connect (view->view, - "command_state_change", - G_CALLBACK(update_command_state), - view); - - g_signal_connect (view->view, - "alphabet_state_change", - G_CALLBACK(alphabet_state_changed), - view); + g_signal_connect (view->view, "status_message", + G_CALLBACK(set_status_message), view); + + g_signal_connect (view->view, "search_result", + G_CALLBACK(search_result), view); + + g_signal_connect (view->view, "folder_bar_message", + G_CALLBACK(set_folder_bar_label), view); + + g_signal_connect (view->view, "command_state_change", + G_CALLBACK(update_command_state), view); view->uri = NULL; diff --git a/addressbook/gui/component/addressbook.h b/addressbook/gui/component/addressbook.h index 3d4bba5187..573adbf38d 100644 --- a/addressbook/gui/component/addressbook.h +++ b/addressbook/gui/component/addressbook.h @@ -5,12 +5,12 @@ #include #include #include -#include +#include /* use this instead of e_book_load_uri everywhere where you want the authentication to be handled for you. */ void addressbook_load_uri (EBook *book, const char *uri, EBookCallback cb, gpointer closure); -void addressbook_load_default_book (EBook *book, EBookCallback open_response, gpointer closure); +void addressbook_load_default_book (EBookCallback open_response, gpointer closure); BonoboControl *addressbook_new_control (void); diff --git a/addressbook/gui/component/component-factory.c b/addressbook/gui/component/component-factory.c index 9d5e946dc0..512ab72f2a 100644 --- a/addressbook/gui/component/component-factory.c +++ b/addressbook/gui/component/component-factory.c @@ -26,20 +26,18 @@ #include "addressbook.h" #include "addressbook-component.h" #include "addressbook-config.h" -#include "e-address-popup.h" -#include "e-address-widget.h" -#include "e-minicard-control.h" +#include "eab-popup-control.h" +#include "eab-vcard-control.h" #include "select-names/e-select-names-bonobo.h" #include -#define FACTORY_ID "OAFIID:GNOME_Evolution_Addressbook_Factory" +#define FACTORY_ID "OAFIID:GNOME_Evolution_Addressbook_Factory_2" -#define MINICARD_CONTROL_ID "OAFIID:GNOME_Evolution_Addressbook_MiniCard_Control" +#define VCARD_CONTROL_ID "OAFIID:GNOME_Evolution_Addressbook_VCard_Control" #define ADDRESSBOOK_CONTROL_ID "OAFIID:GNOME_Evolution_Addressbook_Control" -#define SHELL_COMPONENT_ID "OAFIID:GNOME_Evolution_Addressbook_ShellComponent" -#define ADDRESS_WIDGET_ID "OAFIID:GNOME_Evolution_Addressbook_AddressWidget" +#define COMPONENT_ID "OAFIID:GNOME_Evolution_Addressbook_Component" #define ADDRESS_POPUP_ID "OAFIID:GNOME_Evolution_Addressbook_AddressPopup" #define SELECT_NAMES_ID "OAFIID:GNOME_Evolution_Addressbook_SelectNames" #define LDAP_STORAGE_CONFIG_CONTROL_ID "OAFIID:GNOME_Evolution_LDAPStorage_ConfigControl" @@ -50,16 +48,19 @@ factory (BonoboGenericFactory *factory, const char *component_id, void *closure) { - if (strcmp (component_id, MINICARD_CONTROL_ID) == 0) - return BONOBO_OBJECT (e_minicard_control_new ()); + printf ("asked to activate component_id `%s'\n", component_id); + + if (strcmp (component_id, VCARD_CONTROL_ID) == 0) + return BONOBO_OBJECT (eab_vcard_control_new ()); if (strcmp (component_id, ADDRESSBOOK_CONTROL_ID) == 0) return BONOBO_OBJECT (addressbook_new_control ()); - if (strcmp (component_id, SHELL_COMPONENT_ID) == 0) - return addressbook_component_init (); - if (strcmp (component_id, ADDRESS_WIDGET_ID) == 0) - return BONOBO_OBJECT (e_address_widget_new_control ()); + if (strcmp (component_id, COMPONENT_ID) == 0) { + BonoboObject *object = BONOBO_OBJECT (addressbook_component_peek ()); + bonobo_object_ref (object); + return object; + } if (strcmp (component_id, ADDRESS_POPUP_ID) == 0) - return BONOBO_OBJECT (e_address_popup_new_control ()); + return BONOBO_OBJECT (eab_popup_control_new ()); if (strcmp (component_id, LDAP_STORAGE_CONFIG_CONTROL_ID) == 0) return BONOBO_OBJECT (addressbook_config_control_new ()); if (strcmp (component_id, SELECT_NAMES_ID) == 0) diff --git a/addressbook/gui/component/e-address-popup.c b/addressbook/gui/component/e-address-popup.c deleted file mode 100644 index 9d87fd0fb3..0000000000 --- a/addressbook/gui/component/e-address-popup.c +++ /dev/null @@ -1,1261 +0,0 @@ -/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ - -/* - * e-address-popup.c - * - * Copyright (C) 2001 Ximian, Inc. - * - * Developed by Jon Trowbridge - */ - -/* - * This program is free software; you can redistribute it and/or - * modify it under the terms of version 2 of the GNU General Public - * License as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - * USA. - */ - -/* - * This file is too big and this widget is too complicated. Forgive me. - */ - -#include -#include -#include "addressbook.h" -#include "e-address-popup.h" -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "e-util/e-gui-utils.h" - -/* - * Some general scaffolding for our widgets. Think of this as a really, really - * lame implementation of a wizard (...which is still somewhat more general that - * we really need it to be). - */ - -typedef struct _MiniWizard MiniWizard; -struct _MiniWizard { - GtkWidget *body; - - GtkWidget *vbox; - GtkWidget *ok_button; - GtkWidget *cancel_button; - - void (*ok_cb) (MiniWizard *, gpointer); - void (*cleanup_cb) (gpointer); - gpointer closure; - - void (*destroy_cb) (MiniWizard *, gpointer); - gpointer destroy_closure; -}; - -static void -mini_wizard_container_add (MiniWizard *wiz, GtkWidget *w) -{ - GList *iter = gtk_container_get_children (GTK_CONTAINER (wiz->vbox)); - while (iter != NULL) { - GtkWidget *oldw = (GtkWidget *) iter->data; - iter = g_list_next (iter); - gtk_container_remove (GTK_CONTAINER (wiz->vbox), oldw); - } - gtk_container_add (GTK_CONTAINER (wiz->vbox), w); -} - -static void -mini_wizard_destroy (MiniWizard *wiz) -{ - if (wiz->cleanup_cb) - wiz->cleanup_cb (wiz->closure); - wiz->cleanup_cb = NULL; - - if (wiz->destroy_cb) - wiz->destroy_cb (wiz, wiz->destroy_closure); -} - -static void -mini_wizard_ok_cb (GtkWidget *b, gpointer closure) -{ - MiniWizard *wiz = (MiniWizard *) closure; - - gpointer old_closure = wiz->closure; - void (*old_cleanup) (gpointer) = wiz->cleanup_cb; - - wiz->cleanup_cb = NULL; - - if (wiz->ok_cb) - wiz->ok_cb (wiz, wiz->closure); - - if (old_cleanup) - old_cleanup (old_closure); - -} - -static void -mini_wizard_cancel_cb (GtkWidget *b, gpointer closure) -{ - mini_wizard_destroy ((MiniWizard *) closure); -} - -static void -mini_wizard_destroy_cb (gpointer closure, GObject *where_object_was) -{ - MiniWizard *wiz = (MiniWizard *) closure; - if (wiz->cleanup_cb) - wiz->cleanup_cb (wiz->closure); - g_free (wiz); -} - -static MiniWizard * -mini_wizard_new (void) -{ - MiniWizard *wiz = g_new (MiniWizard, 1); - GtkWidget *bbox; - - wiz->body = gtk_vbox_new (FALSE, 2); - wiz->vbox = gtk_vbox_new (FALSE, 2); - wiz->ok_button = gtk_button_new_from_stock (GTK_STOCK_OK); - wiz->cancel_button = gtk_button_new_from_stock (GTK_STOCK_CANCEL); - - wiz->ok_cb = NULL; - wiz->cleanup_cb = NULL; - wiz->closure = NULL; - - wiz->destroy_cb = NULL; - wiz->destroy_closure = NULL; - - bbox = gtk_hbutton_box_new (); - gtk_button_box_set_layout (GTK_BUTTON_BOX (bbox), - GTK_BUTTONBOX_END); - - gtk_box_pack_start (GTK_BOX (bbox), wiz->cancel_button, FALSE, TRUE, 0); - gtk_box_pack_start (GTK_BOX (bbox), wiz->ok_button, FALSE, TRUE, 0); - - gtk_box_set_spacing (GTK_BOX (bbox), - 10 /* ugh */); - - gtk_box_pack_start (GTK_BOX (wiz->body), wiz->vbox, TRUE, TRUE, 2); - gtk_box_pack_start (GTK_BOX (wiz->body), gtk_hseparator_new (), FALSE, TRUE, 2); - gtk_box_pack_start (GTK_BOX (wiz->body), bbox, FALSE, TRUE, 2); - - gtk_widget_show_all (wiz->body); - - g_signal_connect (wiz->ok_button, - "clicked", - G_CALLBACK (mini_wizard_ok_cb), - wiz); - g_signal_connect (wiz->cancel_button, - "clicked", - G_CALLBACK (mini_wizard_cancel_cb), - wiz); - - g_object_weak_ref (G_OBJECT (wiz->body), - mini_wizard_destroy_cb, - wiz); - - return wiz; - -} - - - -/* - * This is the code for the UI thingie that lets you manipulate the e-mail - * addresses (and *only* the e-mail addresses) associated with an existing - * card. - */ - -#define EMPTY_ENTRY N_("(none)") - -typedef struct _EMailMenu EMailMenu; -struct _EMailMenu { - GtkWidget *option_menu; - GList *options; - gchar *current_selection; -}; - -static void -email_menu_free (EMailMenu *menu) -{ - if (menu == NULL) - return; - - g_list_foreach (menu->options, (GFunc) g_free, NULL); - g_list_free (menu->options); - g_free (menu); -} - -static EMailMenu * -email_menu_new (void) -{ - EMailMenu *menu = g_new (EMailMenu, 1); - - menu->option_menu = gtk_option_menu_new (); - menu->options = NULL; - menu->current_selection = NULL; - - gtk_option_menu_set_menu (GTK_OPTION_MENU (menu->option_menu), gtk_menu_new ()); - - return menu; -} - -static void -menu_activate_cb (GtkWidget *w, gpointer closure) -{ - EMailMenu *menu = (EMailMenu *) closure; - gchar *addr = (gchar *) g_object_get_data (G_OBJECT (w), "addr"); - - menu->current_selection = addr; -} - -static void -email_menu_add_option (EMailMenu *menu, const gchar *addr) -{ - GtkWidget *menu_item; - gchar *addr_cpy; - - g_return_if_fail (menu != NULL); - if (addr == NULL) - return; - - addr_cpy = g_strdup (addr); - menu->options = g_list_append (menu->options, addr_cpy); - - menu_item = gtk_menu_item_new_with_label (addr); - g_object_set_data (G_OBJECT (menu_item), "addr", addr_cpy); - gtk_widget_show_all (menu_item); - gtk_menu_shell_append (GTK_MENU_SHELL (gtk_option_menu_get_menu (GTK_OPTION_MENU (menu->option_menu))), menu_item); - - g_signal_connect (menu_item, - "activate", - G_CALLBACK (menu_activate_cb), - menu); -} - -static void -email_menu_add_options_from_card (EMailMenu *menu, ECard *card, const gchar *extra_addr) -{ - ECardSimple *simple; - - g_return_if_fail (card && E_IS_CARD (card)); - - simple = e_card_simple_new (card); - - /* If any of these three e-mail fields are NULL, email_menu_add_option will just - return without doing anything. */ - email_menu_add_option (menu, e_card_simple_get_email (simple, E_CARD_SIMPLE_EMAIL_ID_EMAIL)); - email_menu_add_option (menu, e_card_simple_get_email (simple, E_CARD_SIMPLE_EMAIL_ID_EMAIL_2)); - email_menu_add_option (menu, e_card_simple_get_email (simple, E_CARD_SIMPLE_EMAIL_ID_EMAIL_3)); - email_menu_add_option (menu, extra_addr); - email_menu_add_option (menu, EMPTY_ENTRY); - - g_object_unref (simple); -} - -static void -email_menu_set_option (EMailMenu *menu, const gchar *addr) -{ - guint count = 0; - GList *iter; - - g_return_if_fail (menu != NULL); - - if (addr == NULL) { - email_menu_set_option (menu, EMPTY_ENTRY); - return; - } - - iter = menu->options; - while (iter && strcmp (addr, (gchar *) iter->data)) { - ++count; - iter = g_list_next (iter); - } - - if (iter) { - gtk_option_menu_set_history (GTK_OPTION_MENU (menu->option_menu), count); - menu->current_selection = (gchar *) iter->data; - } -} - -#ifdef UNDEFINED_FUNCTIONS_SHOULD_PLEASE_BE_INCLUDED -static void -email_menu_unset_option (EMailMenu *menu, const gchar *addr) -{ - GList *iter; - - g_return_if_fail (menu != NULL); - g_return_if_fail (addr != NULL); - - if (menu->current_selection == NULL || strcmp (addr, menu->current_selection)) - return; - - iter = menu->options; - while (iter && strcmp (addr, (gchar *) iter->data)) { - iter = g_list_next (iter); - } - if (iter) { - iter = g_list_next (iter); - if (iter) { - email_menu_set_option (menu, (gchar *) iter->data); - } else { - email_menu_set_option (menu, EMPTY_ENTRY); - } - } -} -#endif - - - -typedef struct _EMailTable EMailTable; -struct _EMailTable { - GtkWidget *table; - ECard *card; - EMailMenu *primary; - EMailMenu *email2; - EMailMenu *email3; -}; - -static void -email_table_cleanup_cb (gpointer closure) -{ - EMailTable *et = (EMailTable *) closure; - - if (et == NULL) - return; - - g_object_unref (et->card); - email_menu_free (et->primary); - email_menu_free (et->email2); - email_menu_free (et->email3); - - g_free (et); -} - -static void -email_table_from_card (EMailTable *et) -{ - ECardSimple *simple; - - g_return_if_fail (et != NULL); - - simple = e_card_simple_new (et->card); - email_menu_set_option (et->primary, e_card_simple_get_email (simple, E_CARD_SIMPLE_EMAIL_ID_EMAIL)); - email_menu_set_option (et->email2, e_card_simple_get_email (simple, E_CARD_SIMPLE_EMAIL_ID_EMAIL_2)); - email_menu_set_option (et->email3, e_card_simple_get_email (simple, E_CARD_SIMPLE_EMAIL_ID_EMAIL_3)); - g_object_unref (simple); -} - -static void -email_table_to_card (EMailTable *et) -{ - ECardSimple *simple; - gchar *curr; - - g_return_if_fail (et != NULL); - - simple = e_card_simple_new (et->card); - - curr = et->primary->current_selection; - if (curr && !strcmp (curr, _(EMPTY_ENTRY))) - curr = NULL; - e_card_simple_set_email (simple, E_CARD_SIMPLE_EMAIL_ID_EMAIL, curr); - - curr = et->email2->current_selection; - if (curr && !strcmp (curr, _(EMPTY_ENTRY))) - curr = NULL; - e_card_simple_set_email (simple, E_CARD_SIMPLE_EMAIL_ID_EMAIL_2, curr); - - curr = et->email3->current_selection; - if (curr && !strcmp (curr, _(EMPTY_ENTRY))) - curr = NULL; - e_card_simple_set_email (simple, E_CARD_SIMPLE_EMAIL_ID_EMAIL_3, curr); - - e_card_simple_sync_card (simple); - g_object_unref (simple); -} - -static void -email_table_save_card_cb (EBook *book, EBookStatus status, gpointer closure) -{ - ECard *card = E_CARD (closure); - - if (status == E_BOOK_STATUS_SUCCESS) { - e_book_commit_card (book, card, NULL, NULL); - } - if (book) - g_object_unref (book); - g_object_unref (card); -} - -/* - * We have to do this in an idle function because of what might be a - * re-entrancy problems with EBook. - */ -static gint -add_card_idle_cb (gpointer closure) -{ - EBook *book; - - book = e_book_new (); - addressbook_load_default_book (book, email_table_save_card_cb, closure); - - return 0; -} - -static void -email_table_ok_cb (MiniWizard *wiz, gpointer closure) -{ - EMailTable *et = (EMailTable *) closure; - - email_table_to_card (et); - - g_object_ref (et->card); - gtk_idle_add (add_card_idle_cb, et->card); - - mini_wizard_destroy (wiz); -} - -static void -email_table_init (MiniWizard *wiz, ECard *card, const gchar *extra_address) -{ - EMailTable *et; - - gchar *name_str; - gint xpad, ypad; - GtkAttachOptions label_x_opts, label_y_opts; - GtkAttachOptions menu_x_opts, menu_y_opts; - - g_return_if_fail (card && E_IS_CARD (card)); - - et = g_new (EMailTable, 1); - - et->card = card; - g_object_ref (et->card); - - et->table = gtk_table_new (4, 2, FALSE); - - et->primary = email_menu_new (); - et->email2 = email_menu_new (); - et->email3 = email_menu_new (); - - email_menu_add_options_from_card (et->primary, et->card, extra_address); - email_menu_add_options_from_card (et->email2, et->card, extra_address); - email_menu_add_options_from_card (et->email3, et->card, extra_address); - - email_table_from_card (et); - - label_x_opts = GTK_FILL; - label_y_opts = GTK_FILL; - menu_x_opts = GTK_EXPAND | GTK_FILL; - menu_y_opts = GTK_EXPAND | GTK_FILL; - xpad = 3; - ypad = 3; - - name_str = e_card_name_to_string (et->card->name); - gtk_table_attach (GTK_TABLE (et->table), - gtk_label_new (name_str), - 0, 2, 0, 1, - label_x_opts, label_y_opts, xpad, ypad); - g_free (name_str); - - gtk_table_attach (GTK_TABLE (et->table), - gtk_label_new (_("Primary Email")), - 0, 1, 1, 2, - label_x_opts, label_y_opts, xpad, ypad); - - gtk_table_attach (GTK_TABLE (et->table), - et->primary->option_menu, - 1, 2, 1, 2, - menu_x_opts, menu_y_opts, xpad, ypad); - - gtk_table_attach (GTK_TABLE (et->table), - gtk_label_new (_("Email 2")), - 0, 1, 2, 3, - label_x_opts, label_y_opts, xpad, ypad); - - gtk_table_attach (GTK_TABLE (et->table), - et->email2->option_menu, - 1, 2, 2, 3, - menu_x_opts, menu_y_opts, xpad, ypad); - - gtk_table_attach (GTK_TABLE (et->table), - gtk_label_new (_("Email 3")), - 0, 1, 3, 4, - label_x_opts, label_y_opts, xpad, ypad); - - gtk_table_attach (GTK_TABLE (et->table), - et->email3->option_menu, - 1, 2, 3, 4, - menu_x_opts, menu_y_opts, xpad, ypad); - - gtk_widget_show_all (et->primary->option_menu); - gtk_widget_show_all (et->email2->option_menu); - gtk_widget_show_all (et->email3->option_menu); - - gtk_widget_show_all (et->table); - mini_wizard_container_add (wiz, et->table); - wiz->ok_cb = email_table_ok_cb; - wiz->cleanup_cb = email_table_cleanup_cb; - wiz->closure = et; -} - -/* - * This code is for the little UI thing that lets you pick from a set of cards - * and decide which one you want to add the e-mail address to. - */ - -typedef struct _CardPicker CardPicker; -struct _CardPicker { - GtkWidget *body; - GtkWidget *list; - GtkListStore *model; - GList *cards; - gchar *new_name; - gchar *new_email; - - ECard *current_card; -}; - -enum { - COLUMN_ACTION, - COLUMN_CARD -}; - -static void -card_picker_selection_changed (GtkTreeSelection *selection, gpointer closure) -{ - MiniWizard *wiz = (MiniWizard *) closure; - CardPicker *pick = (CardPicker *) wiz->closure; - gboolean selected; - GtkTreeIter iter; - - selected = gtk_tree_selection_get_selected (selection, NULL, &iter); - - gtk_widget_set_sensitive (wiz->ok_button, selected); - - if (selected) { - gtk_tree_model_get (GTK_TREE_MODEL (pick->model), &iter, - COLUMN_CARD, &pick->current_card, - -1); - } - else { - pick->current_card = NULL; - } -} - -static void -card_picker_ok_cb (MiniWizard *wiz, gpointer closure) -{ - CardPicker *pick = (CardPicker *) closure; - - if (pick->current_card == NULL) { - e_contact_quick_add (pick->new_name, pick->new_email, NULL, NULL); - mini_wizard_destroy (wiz); - } else { - email_table_init (wiz, pick->current_card, pick->new_email); - } -} - -static void -card_picker_cleanup_cb (gpointer closure) -{ - CardPicker *pick = (CardPicker *) closure; - - g_list_foreach (pick->cards, (GFunc) g_object_unref, NULL); - g_list_free (pick->cards); - - g_free (pick->new_name); - g_free (pick->new_email); -} - -static void -free_str (gpointer data, - GObject *where_the_object_was) -{ - g_free (data); -} - -static void -card_picker_init (MiniWizard *wiz, const GList *cards, const gchar *new_name, const gchar *new_email) -{ - CardPicker *pick; - gchar *str; - GtkWidget *w; - GtkTreeIter iter; - - pick = g_new (CardPicker, 1); - - pick->body = gtk_vbox_new (FALSE, 2); - - pick->model = gtk_list_store_new (2, G_TYPE_STRING, G_TYPE_POINTER); - - pick->list = gtk_tree_view_new_with_model (GTK_TREE_MODEL (pick->model)); - - gtk_tree_view_set_headers_visible (GTK_TREE_VIEW (pick->list), TRUE); - - gtk_tree_view_insert_column_with_attributes (GTK_TREE_VIEW (pick->list), - COLUMN_ACTION, - _("Select an Action"), - gtk_cell_renderer_text_new (), - "text", COLUMN_ACTION, - NULL); - - gtk_tree_selection_set_mode (gtk_tree_view_get_selection (GTK_TREE_VIEW (pick->list)), - GTK_SELECTION_SINGLE); - - str = g_strdup_printf (_("Create a new contact \"%s\""), new_name); - gtk_list_store_append (pick->model, &iter); - gtk_list_store_set (pick->model, &iter, - COLUMN_ACTION, str, - COLUMN_CARD, NULL, - -1); - g_object_weak_ref (G_OBJECT (pick->model), free_str, str); - - pick->cards = NULL; - while (cards) { - ECard *card = (ECard *) cards->data; - gchar *name_str = e_card_name_to_string (card->name); - - pick->cards = g_list_append (pick->cards, card); - g_object_ref (card); - - str = g_strdup_printf (_("Add address to existing contact \"%s\""), name_str); - gtk_list_store_append (pick->model, &iter); - gtk_list_store_set (pick->model, &iter, - COLUMN_ACTION, str, - COLUMN_CARD, card, - -1); - g_free (name_str); - - g_object_weak_ref (G_OBJECT (pick->model), free_str, str); - - cards = g_list_next (cards); - } - - pick->new_name = g_strdup (new_name); - pick->new_email = g_strdup (new_email); - - pick->current_card = NULL; - gtk_widget_set_sensitive (wiz->ok_button, FALSE); - - /* Connect some signals & callbacks */ - - wiz->ok_cb = card_picker_ok_cb; - wiz->cleanup_cb = card_picker_cleanup_cb; - - g_signal_connect (gtk_tree_view_get_selection (GTK_TREE_VIEW (pick->list)), - "changed", G_CALLBACK (card_picker_selection_changed), - wiz); - - /* Build our widget */ - - w = gtk_label_new (new_email); - gtk_box_pack_start (GTK_BOX (pick->body), w, FALSE, TRUE, 3); - - gtk_box_pack_start (GTK_BOX (pick->body), pick->list, TRUE, TRUE, 2); - gtk_widget_show_all (pick->body); - - - /* Put it in our mini-wizard */ - - wiz->closure = pick; - mini_wizard_container_add (wiz, pick->body); -} - -/* ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** */ - -/* - * The code for the actual EAddressPopup widget begins here. - */ - -/* ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** */ - - -static GtkObjectClass *parent_class; - -static void e_address_popup_dispose (GObject *); -static void e_address_popup_query (EAddressPopup *); - - -static void -e_address_popup_class_init (EAddressPopupClass *klass) -{ - GObjectClass *object_class = G_OBJECT_CLASS (klass); - - parent_class = g_type_class_peek_parent (klass); - - object_class->dispose = e_address_popup_dispose; -} - -static void -e_address_popup_init (EAddressPopup *pop) -{ - pop->transitory = TRUE; -} - -static void -e_address_popup_cleanup (EAddressPopup *pop) -{ - if (pop->card) { - g_object_unref (pop->card); - pop->card = NULL; - } - - if (pop->scheduled_refresh) { - gtk_timeout_remove (pop->scheduled_refresh); - pop->scheduled_refresh = 0; - } - - if (pop->query_tag) { - e_book_simple_query_cancel (pop->book, pop->query_tag); - pop->query_tag = 0; - } - - if (pop->book) { - g_object_unref (pop->book); - pop->book = NULL; - } - - g_free (pop->name); - pop->name = NULL; - - g_free (pop->email); - pop->email = NULL; -} - -static void -e_address_popup_dispose (GObject *obj) -{ - EAddressPopup *pop = E_ADDRESS_POPUP (obj); - - e_address_popup_cleanup (pop); - - if (G_OBJECT_CLASS (parent_class)->dispose) - G_OBJECT_CLASS (parent_class)->dispose (obj); -} - -GType -e_address_popup_get_type (void) -{ - static GType pop_type = 0; - - if (!pop_type) { - static const GTypeInfo pop_info = { - sizeof (EAddressPopupClass), - NULL, /* base_init */ - NULL, /* base_finalize */ - (GClassInitFunc) e_address_popup_class_init, - NULL, /* class_finalize */ - NULL, /* class_data */ - sizeof (EAddressPopup), - 0, /* n_preallocs */ - (GInstanceInitFunc) e_address_popup_init, - }; - - pop_type = g_type_register_static (gtk_event_box_get_type (), "EAddressPopup", &pop_info, 0); - } - - return pop_type; -} - -static void -e_address_popup_refresh_names (EAddressPopup *pop) -{ - if (pop->name_widget) { - if (pop->name && *pop->name) { - gtk_label_set_text (GTK_LABEL (pop->name_widget), pop->name); - gtk_widget_show (pop->name_widget); - } else { - gtk_widget_hide (pop->name_widget); - } - } - - if (pop->email_widget) { - if (pop->email && *pop->email) { - gtk_label_set_text (GTK_LABEL (pop->email_widget), pop->email); - gtk_widget_show (pop->email_widget); - } else { - gtk_widget_hide (pop->email_widget); - } - } - - e_address_popup_query (pop); -} - -static gint -refresh_timeout_cb (gpointer ptr) -{ - EAddressPopup *pop = E_ADDRESS_POPUP (ptr); - e_address_popup_refresh_names (pop); - pop->scheduled_refresh = 0; - return 0; -} - -static void -e_address_popup_schedule_refresh (EAddressPopup *pop) -{ - if (pop->scheduled_refresh == 0) - pop->scheduled_refresh = gtk_timeout_add (20, refresh_timeout_cb, pop); -} - -/* If we are handed something of the form "Foo ", - do the right thing. */ -static gboolean -e_address_popup_set_free_form (EAddressPopup *pop, const gchar *txt) -{ - gchar *lt, *gt = NULL; - - g_return_val_if_fail (pop && E_IS_ADDRESS_POPUP (pop), FALSE); - - if (txt == NULL) - return FALSE; - - lt = strchr (txt, '<'); - if (lt) - gt = strchr (txt, '>'); - - if (lt && gt && lt+1 < gt) { - gchar *name = g_strndup (txt, lt-txt); - gchar *email = g_strndup (lt+1, gt-lt-1); - e_address_popup_set_name (pop, name); - e_address_popup_set_email (pop, email); - - g_free (name); - g_free (email); - - return TRUE; - } - - return FALSE; -} - -void -e_address_popup_set_name (EAddressPopup *pop, const gchar *name) -{ - g_return_if_fail (pop && E_IS_ADDRESS_POPUP (pop)); - - /* We only allow the name to be set once. */ - if (pop->name) - return; - - if (!e_address_popup_set_free_form (pop, name)) { - pop->name = g_strdup (name); - if (pop->name) - g_strstrip (pop->name); - } - - e_address_popup_schedule_refresh (pop); -} - -void -e_address_popup_set_email (EAddressPopup *pop, const gchar *email) -{ - g_return_if_fail (pop && E_IS_ADDRESS_POPUP (pop)); - - /* We only allow the e-mail to be set once. */ - if (pop->email) - return; - - if (!e_address_popup_set_free_form (pop, email)) { - pop->email = g_strdup (email); - if (pop->email) - g_strstrip (pop->email); - } - - e_address_popup_schedule_refresh (pop); -} - -void -e_address_popup_construct (EAddressPopup *pop) -{ - GtkWidget *vbox, *name_holder; - GdkColor color = { 0x0, 0xffff, 0xffff, 0xffff }; - - g_return_if_fail (pop && E_IS_ADDRESS_POPUP (pop)); - - pop->main_vbox = gtk_vbox_new (FALSE, 0); - - /* Build Generic View */ - - name_holder = gtk_event_box_new (); - vbox = gtk_vbox_new (FALSE, 2); - pop->name_widget = gtk_label_new (""); - pop->email_widget = gtk_label_new (""); - - gtk_box_pack_start (GTK_BOX (vbox), pop->name_widget, TRUE, TRUE, 2); - gtk_box_pack_start (GTK_BOX (vbox), pop->email_widget, TRUE, TRUE, 2); - gtk_container_add (GTK_CONTAINER (name_holder), GTK_WIDGET (vbox)); - - if (gdk_colormap_alloc_color (gtk_widget_get_colormap (GTK_WIDGET (name_holder)), &color, FALSE, TRUE)) { - GtkStyle *style = gtk_style_copy (gtk_widget_get_style (GTK_WIDGET (name_holder))); - style->bg[0] = color; - gtk_widget_set_style (GTK_WIDGET (name_holder), style); - g_object_unref (style); - } - - pop->generic_view = gtk_frame_new (NULL); - gtk_container_add (GTK_CONTAINER (pop->generic_view), name_holder); - gtk_box_pack_start (GTK_BOX (pop->main_vbox), pop->generic_view, TRUE, TRUE, 0); - gtk_widget_show_all (pop->generic_view); - - pop->query_msg = gtk_label_new (_("Querying Addressbook...")); - gtk_box_pack_start (GTK_BOX (pop->main_vbox), pop->query_msg, TRUE, TRUE, 0); - gtk_widget_show (pop->query_msg); - - /* Build Minicard View */ - pop->minicard_view = e_minicard_widget_new (); - gtk_box_pack_start (GTK_BOX (pop->main_vbox), pop->minicard_view, TRUE, TRUE, 0); - - - /* Final assembly */ - - gtk_container_add (GTK_CONTAINER (pop), pop->main_vbox); - gtk_widget_show (pop->main_vbox); - - gtk_container_set_border_width (GTK_CONTAINER (vbox), 3); - gtk_container_set_border_width (GTK_CONTAINER (pop), 2); -} - -GtkWidget * -e_address_popup_new (void) -{ - EAddressPopup *pop = g_object_new (E_TYPE_ADDRESS_POPUP, NULL); - e_address_popup_construct (pop); - return GTK_WIDGET (pop); -} - -static void -emit_event (EAddressPopup *pop, const char *event) -{ - if (pop->es) { - BonoboArg *arg; - - arg = bonobo_arg_new (BONOBO_ARG_BOOLEAN); - BONOBO_ARG_SET_BOOLEAN (arg, TRUE); - bonobo_event_source_notify_listeners_full (pop->es, - "GNOME/Evolution/Addressbook/AddressPopup", - "Event", - event, - arg, NULL); - bonobo_arg_release (arg); - } -} - -static void -contact_editor_cb (EBook *book, EBookStatus status, gpointer closure) -{ - if (status == E_BOOK_STATUS_SUCCESS) { - EAddressPopup *pop = E_ADDRESS_POPUP (closure); - EContactEditor *ce = e_addressbook_show_contact_editor (book, pop->card, FALSE, TRUE); - e_address_popup_cleanup (pop); - emit_event (pop, "Destroy"); - e_contact_editor_raise (ce); - } - - if (book) - g_object_unref (book); -} - -static void -edit_contact_info_cb (GtkWidget *button, EAddressPopup *pop) -{ - EBook *book; - emit_event (pop, "Hide"); - - book = e_book_new (); - addressbook_load_default_book (book, contact_editor_cb, pop); -} - -static void -e_address_popup_cardify (EAddressPopup *pop, ECard *card) -{ - GtkWidget *b; - - g_return_if_fail (pop && E_IS_ADDRESS_POPUP (pop)); - g_return_if_fail (card && E_IS_CARD (card)); - g_return_if_fail (pop->card == NULL); - - pop->card = card; - g_object_ref (pop->card); - - e_minicard_widget_set_card (E_MINICARD_WIDGET (pop->minicard_view), card); - gtk_widget_show (pop->minicard_view); - gtk_widget_hide (pop->generic_view); - - b = gtk_button_new_with_label (_("Edit Contact Info")); - gtk_box_pack_start (GTK_BOX (pop->main_vbox), b, TRUE, TRUE, 0); - g_signal_connect (b, - "clicked", - G_CALLBACK (edit_contact_info_cb), - pop); - gtk_widget_show (b); -} - -static void -add_contacts_cb (GtkWidget *button, EAddressPopup *pop) -{ - if (pop->email && *pop->email) { - if (pop->name && *pop->name) - e_contact_quick_add (pop->name, pop->email, NULL, NULL); - else - e_contact_quick_add_free_form (pop->email, NULL, NULL); - - } - e_address_popup_cleanup (pop); - emit_event (pop, "Destroy"); -} - -static void -e_address_popup_no_matches (EAddressPopup *pop) -{ - GtkWidget *b; - - g_return_if_fail (pop && E_IS_ADDRESS_POPUP (pop)); - - b = e_button_new_with_stock_icon (_("Add to Contacts"), "gtk-add"); - - gtk_box_pack_start (GTK_BOX (pop->main_vbox), b, TRUE, TRUE, 0); - g_signal_connect (b, - "clicked", - G_CALLBACK (add_contacts_cb), - pop); - gtk_widget_show (b); -} - -static void -wizard_destroy_cb (MiniWizard *wiz, gpointer closure) -{ - gtk_widget_destroy (GTK_WIDGET (closure)); -} - -static void -e_address_popup_ambiguous_email_add (EAddressPopup *pop, const GList *cards) -{ - MiniWizard *wiz = mini_wizard_new (); - GtkWidget *win = gtk_window_new (GTK_WINDOW_TOPLEVEL); - - wiz->destroy_cb = wizard_destroy_cb; - wiz->destroy_closure = win; - - gtk_window_set_title (GTK_WINDOW (win), _("Merge E-Mail Address")); - gtk_window_set_position (GTK_WINDOW (win), GTK_WIN_POS_MOUSE); - - card_picker_init (wiz, cards, pop->name, pop->email); - - e_address_popup_cleanup (pop); - emit_event (pop, "Destroy"); - - gtk_container_add (GTK_CONTAINER (win), wiz->body); - gtk_widget_show_all (win); -} - -static void -e_address_popup_multiple_matches (EAddressPopup *pop, const GList *cards) -{ - pop->multiple_matches = TRUE; - - e_address_popup_ambiguous_email_add (pop, cards); -} - -/** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** **/ - -/* - * Addressbook Query Fun - */ - -static void -name_only_query_cb (EBook *book, EBookSimpleQueryStatus status, const GList *cards, gpointer closure) -{ - EAddressPopup *pop; - - if (status != E_BOOK_SIMPLE_QUERY_STATUS_SUCCESS) - return; - - pop = E_ADDRESS_POPUP (closure); - - pop->query_tag = 0; - - if (cards == NULL) { - e_address_popup_no_matches (pop); - } else { - e_address_popup_ambiguous_email_add (pop, cards); - } -} - -static void -query_cb (EBook *book, EBookSimpleQueryStatus status, const GList *cards, gpointer closure) -{ - EAddressPopup *pop; - - if (status != E_BOOK_SIMPLE_QUERY_STATUS_SUCCESS) - return; - - pop = E_ADDRESS_POPUP (closure); - - pop->query_tag = 0; - gtk_widget_hide (pop->query_msg); - - if (cards == NULL) { - - /* Do a name-only query if: - (1) The name is non-empty. - (2) The e-mail is also non-empty (so that the query we just did wasn't actually a name-only query. - */ - if (pop->name && *pop->name && pop->email && *pop->email) { - pop->query_tag = e_book_name_and_email_query (book, pop->name, NULL, name_only_query_cb, pop); - } else { - e_address_popup_no_matches (pop); - } - - } else { - if (g_list_length ((GList *) cards) == 1) - e_address_popup_cardify (pop, E_CARD (cards->data)); - else - e_address_popup_multiple_matches (pop, cards); - } -} - -static void -start_query (EBook *book, EBookStatus status, gpointer closure) -{ - EAddressPopup *pop = E_ADDRESS_POPUP (closure); - - if (status != E_BOOK_STATUS_SUCCESS) { - e_address_popup_no_matches (pop); - if (book) - g_object_unref (book); - return; - } - - if (pop->query_tag) - e_book_simple_query_cancel (book, pop->query_tag); - - if (pop->book != book) { - g_object_ref (book); - if (pop->book) - g_object_unref (pop->book); - pop->book = book; - } - - pop->query_tag = e_book_name_and_email_query (book, pop->name, pop->email, query_cb, pop); - - g_object_unref (pop); -} - -static void -e_address_popup_query (EAddressPopup *pop) -{ - EBook *book; - - g_return_if_fail (pop && E_IS_ADDRESS_POPUP (pop)); - - book = e_book_new (); - g_object_ref (pop); - - addressbook_load_default_book (book, start_query, pop); -} - -/** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** **/ - -enum { - PROPERTY_NAME, - PROPERTY_EMAIL, - PROPERTY_TRANSITORY -}; - -static void -set_prop (BonoboPropertyBag *bag, const BonoboArg *arg, guint arg_id, CORBA_Environment *ev, gpointer user_data) -{ - EAddressPopup *pop = E_ADDRESS_POPUP (user_data); - - switch (arg_id) { - - case PROPERTY_NAME: - e_address_popup_set_name (pop, BONOBO_ARG_GET_STRING (arg)); - break; - - case PROPERTY_EMAIL: - e_address_popup_set_email (pop, BONOBO_ARG_GET_STRING (arg)); - break; - - default: - g_assert_not_reached (); - } -} - -static void -get_prop (BonoboPropertyBag *bag, BonoboArg *arg, guint arg_id, CORBA_Environment *ev, gpointer user_data) -{ - EAddressPopup *pop = E_ADDRESS_POPUP (user_data); - - switch (arg_id) { - - case PROPERTY_NAME: - BONOBO_ARG_SET_STRING (arg, pop->name); - break; - - case PROPERTY_EMAIL: - BONOBO_ARG_SET_STRING (arg, pop->email); - break; - - case PROPERTY_TRANSITORY: - BONOBO_ARG_SET_BOOLEAN (arg, pop->transitory); - break; - - default: - g_assert_not_reached (); - } -} - -BonoboControl * -e_address_popup_new_control (void) -{ - BonoboControl *control; - BonoboPropertyBag *bag; - EAddressPopup *addy; - GtkWidget *w; - - w = e_address_popup_new (); - addy = E_ADDRESS_POPUP (w); - - control = bonobo_control_new (w); - gtk_widget_show (w); - - bag = bonobo_property_bag_new (get_prop, set_prop, w); - bonobo_property_bag_add (bag, "name", PROPERTY_NAME, - BONOBO_ARG_STRING, NULL, NULL, - BONOBO_PROPERTY_WRITEABLE | BONOBO_PROPERTY_READABLE); - - bonobo_property_bag_add (bag, "email", PROPERTY_EMAIL, - BONOBO_ARG_STRING, NULL, NULL, - BONOBO_PROPERTY_WRITEABLE | BONOBO_PROPERTY_READABLE); - - bonobo_property_bag_add (bag, "transitory", PROPERTY_TRANSITORY, - BONOBO_ARG_BOOLEAN, NULL, NULL, - BONOBO_PROPERTY_READABLE); - - bonobo_control_set_properties (control, bonobo_object_corba_objref (BONOBO_OBJECT (bag)), NULL); - bonobo_object_unref (BONOBO_OBJECT (bag)); - - addy->es = bonobo_event_source_new (); - bonobo_object_add_interface (BONOBO_OBJECT (control), - BONOBO_OBJECT (addy->es)); - - return control; -} diff --git a/addressbook/gui/component/e-address-popup.h b/addressbook/gui/component/e-address-popup.h deleted file mode 100644 index b2519b0ee6..0000000000 --- a/addressbook/gui/component/e-address-popup.h +++ /dev/null @@ -1,88 +0,0 @@ -/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ - -/* - * e-address-popup.h - * - * Copyright (C) 2001 Ximian, Inc. - * - * Developed by Jon Trowbridge - */ - -/* - * This program is free software; you can redistribute it and/or - * modify it under the terms of version 2 of the GNU General Public - * License as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - * USA. - */ - -#ifndef __E_ADDRESS_POPUP_H__ -#define __E_ADDRESS_POPUP_H__ - -#include -#include -#include -#include - -G_BEGIN_DECLS - -#define E_TYPE_ADDRESS_POPUP (e_address_popup_get_type ()) -#define E_ADDRESS_POPUP(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), E_TYPE_ADDRESS_POPUP, EAddressPopup)) -#define E_ADDRESS_POPUP_CLASS(k) (G_TYPE_CHECK_CLASS_CAST ((k), E_TYPE_ADDRESS_POPUP, EAddressPopupClass)) -#define E_IS_ADDRESS_POPUP(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), E_TYPE_ADDRESS_POPUP)) -#define E_IS_ADDRESS_POPUP_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), E_TYPE_ADDRESS_POPUP)) - -typedef struct _EAddressPopup EAddressPopup; -typedef struct _EAddressPopupClass EAddressPopupClass; - -struct _EAddressPopup { - GtkEventBox parent; - - gchar *name; - gchar *email; - - GtkWidget *name_widget; - GtkWidget *email_widget; - GtkWidget *query_msg; - - GtkWidget *main_vbox; - GtkWidget *generic_view; - GtkWidget *minicard_view; - - gboolean transitory; - - guint scheduled_refresh; - EBook *book; - guint query_tag; - gboolean multiple_matches; - ECard *card; - - BonoboEventSource *es; -}; - -struct _EAddressPopupClass { - GtkEventBoxClass parent_class; -}; - -GType e_address_popup_get_type (void); - -void e_address_popup_set_name (EAddressPopup *, const gchar *name); -void e_address_popup_set_email (EAddressPopup *, const gchar *email); - -void e_address_popup_construct (EAddressPopup *); -GtkWidget *e_address_popup_new (void); - -BonoboControl *e_address_popup_new_control (void); - -G_END_DECLS - -#endif /* __E_ADDRESS_POPUP_H__ */ - diff --git a/addressbook/gui/component/e-address-widget.c b/addressbook/gui/component/e-address-widget.c deleted file mode 100644 index 9ec1e6ebba..0000000000 --- a/addressbook/gui/component/e-address-widget.c +++ /dev/null @@ -1,568 +0,0 @@ -/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ - -/* - * e-address-widget.c - * - * Copyright (C) 2001 Ximian, Inc. - * - * Developed by Jon Trowbridge - */ - -/* - * This program is free software; you can redistribute it and/or - * modify it under the terms of version 2 of the GNU General Public - * License as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - * USA. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "e-address-widget.h" - -static void e_address_widget_class_init (EAddressWidgetClass *klass); -static void e_address_widget_init (EAddressWidget *obj); -static void e_address_widget_destroy (GtkObject *obj); - -static gint e_address_widget_button_press_handler (GtkWidget *w, GdkEventButton *ev); -static void e_address_widget_popup (EAddressWidget *, GdkEventButton *ev); -static void e_address_widget_schedule_query (EAddressWidget *); - -static GtkObjectClass *parent_class; - -static EBook *common_book = NULL; /* sort of lame */ - -static gboolean doing_queries = FALSE; - -static void -e_address_widget_class_init (EAddressWidgetClass *klass) -{ - GtkObjectClass *object_class = (GtkObjectClass *) klass; - GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass); - - parent_class = g_type_class_peek_parent (klass); - - object_class->destroy = e_address_widget_destroy; - - widget_class->button_press_event = e_address_widget_button_press_handler; -} - -static void -e_address_widget_init (EAddressWidget *addr) -{ - -} - -static void -e_address_widget_destroy (GtkObject *obj) -{ - EAddressWidget *addr = E_ADDRESS_WIDGET (obj); - - g_free (addr->name); - addr->name = NULL; - - g_free (addr->email); - addr->email = NULL; - - if (addr->query_tag) { - e_book_simple_query_cancel (common_book, addr->query_tag); - addr->query_tag = 0; - } - - if (addr->query_idle_tag) { - g_source_remove (addr->query_idle_tag); - addr->query_idle_tag = 0; - } - - (* GTK_OBJECT_CLASS (parent_class)->destroy) (obj); -} - -static gint -e_address_widget_button_press_handler (GtkWidget *w, GdkEventButton *ev) -{ - EAddressWidget *addr = E_ADDRESS_WIDGET (w); - if (ev->button == 3 && ev->state == 0) { - e_address_widget_popup (addr, ev); - return TRUE; - } - - return FALSE; -} - -GType -e_address_widget_get_type (void) -{ - static GType aw_type = 0; - - if (!aw_type) { - static const GTypeInfo aw_info = { - sizeof (EAddressWidgetClass), - NULL, /* base_init */ - NULL, /* base_finalize */ - (GClassInitFunc) e_address_widget_class_init, - NULL, /* class_finalize */ - NULL, /* class_data */ - sizeof (EAddressWidget), - 0, /* n_preallocs */ - (GInstanceInitFunc) e_address_widget_init, - }; - - aw_type = g_type_register_static (gtk_event_box_get_type (), "EAddressWidget", &aw_info, 0); - } - - return aw_type; -} - -static void -gtk_widget_visible (GtkWidget *w, gboolean x) -{ - if (x) - gtk_widget_show (w); - else - gtk_widget_hide (w); -} - -static void -e_address_widget_refresh (EAddressWidget *addr) -{ - gchar *str; - gboolean have_name, have_email; - - g_return_if_fail (addr && E_IS_ADDRESS_WIDGET (addr)); - - have_name = addr->name && *addr->name; - have_email = addr->email && *addr->email && (addr->card == NULL || !addr->known_email); - - gtk_label_set_text (GTK_LABEL (addr->name_widget), have_name ? addr->name : ""); - gtk_widget_visible (addr->name_widget, have_name); - if (addr->card) { - gint i, N = strlen (addr->name); - gchar *pattern = g_malloc (N+1); - for (i=0; iname_widget), pattern); - g_free (pattern); - } else { - gtk_label_set_pattern (GTK_LABEL (addr->name_widget), ""); - } - - if (have_email) { - str = g_strdup_printf (have_name ? "<%s>" : "%s", addr->email); - gtk_label_set_text (GTK_LABEL (addr->email_widget), str); - g_free (str); - } else { - gtk_label_set_text (GTK_LABEL (addr->email_widget), ""); - } - gtk_widget_visible (addr->email_widget, have_email); - - gtk_widget_visible (addr->spacer, have_name && have_email); - - /* Launch a query to find the appropriate card, if necessary. */ - if (addr->card == NULL) - e_address_widget_schedule_query (addr); -} - -void -e_address_widget_set_name (EAddressWidget *addr, const gchar *name) -{ - g_return_if_fail (addr && E_IS_ADDRESS_WIDGET (addr)); - - g_free (addr->name); - addr->name = g_strdup (name); - - e_address_widget_refresh (addr); -} - -void -e_address_widget_set_email (EAddressWidget *addr, const gchar *email) -{ - g_return_if_fail (addr && E_IS_ADDRESS_WIDGET (addr)); - - g_free (addr->email); - addr->email = g_strdup (email); - - e_address_widget_refresh (addr); -} - - -void -e_address_widget_set_text (EAddressWidget *addr, const gchar *text) -{ - g_return_if_fail (addr && E_IS_ADDRESS_WIDGET (addr)); - - e_address_widget_set_email (addr, text); /* CRAP */ -} - -void -e_address_widget_construct (EAddressWidget *addr) -{ - GtkWidget *box; - - g_return_if_fail (addr && E_IS_ADDRESS_WIDGET (addr)); - - box = gtk_hbox_new (FALSE, 2); - - addr->name_widget = gtk_label_new (""); - addr->spacer = gtk_label_new (" "); - addr->email_widget = gtk_label_new (""); - - gtk_box_pack_start (GTK_BOX (box), addr->name_widget, FALSE, FALSE, 0); - gtk_box_pack_start (GTK_BOX (box), addr->spacer, FALSE, FALSE, 0); - gtk_box_pack_start (GTK_BOX (box), addr->email_widget, FALSE, FALSE, 0); - - gtk_container_add (GTK_CONTAINER (addr), box); - - gtk_widget_show (box); - gtk_widget_show (addr->name_widget); - gtk_widget_show (addr->email_widget); -} - -GtkWidget * -e_address_widget_new (void) -{ - EAddressWidget *addr = g_object_new (E_TYPE_ADDRESS_WIDGET, NULL); - e_address_widget_construct (addr); - return GTK_WIDGET (addr); -} - -/* - * - * Cardification - * - */ - -static void -e_address_widget_cardify (EAddressWidget *addr, ECard *card, gboolean known_email) -{ - if (addr->card != card || addr->known_email != known_email) { - - if (addr->card != card) { - if (addr->card) - g_object_unref (addr->card); - addr->card = card; - g_object_ref (addr->card); - } - - addr->known_email = known_email; - - if (!(addr->name && *addr->name)) { - gchar *s = e_card_name_to_string (card->name); - e_address_widget_set_name (addr, s); - g_free (s); - } - - e_address_widget_refresh (addr); - } -} - -static void -query_results_cb (EBook *book, EBookSimpleQueryStatus status, const GList *cards, gpointer user_data) -{ - EAddressWidget *addr = user_data; - - if (g_list_length ((GList *) cards) == 1) { - ECard *card = E_CARD (cards->data); - e_address_widget_cardify (addr, card, TRUE); - } - - addr->query_tag = 0; -} - -static void -e_address_widget_do_query (EAddressWidget *addr) -{ - e_book_name_and_email_query (common_book, addr->name, addr->email, query_results_cb, addr); -} - -static void -book_ready_cb (EBook *book, EBookStatus status, gpointer user_data) -{ - EAddressWidget *addr = E_ADDRESS_WIDGET (user_data); - - if (common_book == NULL) { - common_book = book; - g_object_ref (common_book); - } else - g_object_unref (book); - - e_address_widget_do_query (addr); -} - -static gint -query_idle_fn (gpointer ptr) -{ - EAddressWidget *addr = E_ADDRESS_WIDGET (ptr); - - if (common_book) { - e_address_widget_do_query (addr); - } else { - e_book_load_default_book (e_book_new (), book_ready_cb, addr); - } - - addr->query_idle_tag = 0; - return FALSE; -} - -static void -e_address_widget_schedule_query (EAddressWidget *addr) -{ - if (addr->query_idle_tag || !doing_queries) - return; - addr->query_idle_tag = g_idle_add (query_idle_fn, addr); -} - -/* - * - * Popup Menu - * - */ - -#define ARBITRARY_UIINFO_LIMIT 64 - -static gint -popup_add_name_and_address (EAddressWidget *addr, GnomeUIInfo *uiinfo, gint i) -{ - gboolean flag = FALSE; - - if (addr->name && *addr->name) { - uiinfo[i].type = GNOME_APP_UI_ITEM; - uiinfo[i].label = addr->name; - ++i; - flag = TRUE; - } - - if (addr->email && *addr->email) { - uiinfo[i].type = GNOME_APP_UI_ITEM; - uiinfo[i].label = addr->email; - ++i; - flag = TRUE; - } - - if (flag) { - uiinfo[i].type = GNOME_APP_UI_SEPARATOR; - ++i; - } - - return i; -} - -static void -flip_queries_flag_cb (GtkWidget *w, gpointer user_data) -{ - doing_queries = !doing_queries; -} - -static gint -popup_add_query_change (EAddressWidget *addr, GnomeUIInfo *uiinfo, gint i) -{ - uiinfo[i].type = GNOME_APP_UI_SEPARATOR; - ++i; - - uiinfo[i].type = GNOME_APP_UI_ITEM; - uiinfo[i].label = doing_queries ? _("Disable Queries") : _("Enable Queries (Dangerous!)"); - uiinfo[i].moreinfo = flip_queries_flag_cb; - ++i; - - return i; -} - - -static GtkWidget * -popup_menu_card (EAddressWidget *addr) -{ - GnomeUIInfo uiinfo[ARBITRARY_UIINFO_LIMIT]; - GtkWidget *pop; - gint i=0; - ECard *card = E_CARD (addr->card); - - g_return_val_if_fail (card != NULL, NULL); - - memset (uiinfo, 0, sizeof (uiinfo)); - - i = popup_add_name_and_address (addr, uiinfo, i); - - uiinfo[i].type = GNOME_APP_UI_ITEM; - uiinfo[i].label = _("Edit Contact Info"); - ++i; - - i = popup_add_query_change (addr, uiinfo, i); - - uiinfo[i].type = GNOME_APP_UI_ENDOFINFO; - pop = gnome_popup_menu_new (uiinfo); - return pop; -} - -static void -post_quick_add_cb (ECard *card, gpointer user_data) -{ - e_address_widget_cardify (E_ADDRESS_WIDGET (user_data), card, TRUE); -} - -static void -add_contacts_cb (GtkWidget *w, gpointer user_data) -{ - EAddressWidget *addr = E_ADDRESS_WIDGET (user_data); - - e_contact_quick_add (addr->name, addr->email, post_quick_add_cb, addr); -} - -static GtkWidget * -popup_menu_nocard (EAddressWidget *addr) -{ - GnomeUIInfo uiinfo[ARBITRARY_UIINFO_LIMIT]; - GtkWidget *pop; - gint i=0; - - memset (uiinfo, 0, sizeof (uiinfo)); - - i = popup_add_name_and_address (addr, uiinfo, i); - - uiinfo[i].type = GNOME_APP_UI_ITEM; - uiinfo[i].label = _("Add to Contacts"); - uiinfo[i].moreinfo = add_contacts_cb; - ++i; - - i = popup_add_query_change (addr, uiinfo, i); - - uiinfo[i].type = GNOME_APP_UI_ENDOFINFO; - pop = gnome_popup_menu_new (uiinfo); - return pop; -} - -static void -e_address_widget_popup (EAddressWidget *addr, GdkEventButton *ev) -{ - GtkWidget *pop; - - g_return_if_fail (addr && E_IS_ADDRESS_WIDGET (addr)); - - pop = addr->card ? popup_menu_card (addr) : popup_menu_nocard (addr); - - if (pop) - gnome_popup_menu_do_popup (pop, NULL, NULL, ev, addr, GTK_WIDGET (addr)); -} - -/* - * - * Bonobo Control Magic - * - */ - -enum { - ADDRESS_PROPERTY_NAME, - ADDRESS_PROPERTY_EMAIL, - ADDRESS_PROPERTY_TEXT, - ADDRESS_PROPERTY_BACKGROUND_RGB -}; - - -static void -get_prop (BonoboPropertyBag *bag, BonoboArg *arg, guint arg_id, CORBA_Environment *ev, gpointer user_data) -{ - EAddressWidget *addr = E_ADDRESS_WIDGET (user_data); - - switch (arg_id) { - - case ADDRESS_PROPERTY_NAME: - BONOBO_ARG_SET_STRING (arg, addr->name ? addr->name :""); - break; - - case ADDRESS_PROPERTY_EMAIL: - BONOBO_ARG_SET_STRING (arg, addr->email ? addr->email : ""); - break; - - case ADDRESS_PROPERTY_TEXT: - BONOBO_ARG_SET_STRING (arg, "?"); - break; - } -} - -static void -set_prop (BonoboPropertyBag *bag, const BonoboArg *arg, guint arg_id, CORBA_Environment *ev, gpointer user_data) -{ - EAddressWidget *addr = E_ADDRESS_WIDGET (user_data); - - switch (arg_id) { - case ADDRESS_PROPERTY_NAME: - e_address_widget_set_name (addr, BONOBO_ARG_GET_STRING (arg)); - break; - - case ADDRESS_PROPERTY_EMAIL: - e_address_widget_set_email (addr, BONOBO_ARG_GET_STRING (arg)); - break; - - case ADDRESS_PROPERTY_TEXT: - e_address_widget_set_text (addr, BONOBO_ARG_GET_STRING (arg)); - break; - - - case ADDRESS_PROPERTY_BACKGROUND_RGB: - { - gint bg = BONOBO_ARG_GET_INT (arg); - GdkColor color; - - color.red = (bg & 0xff0000) >> 8; - color.green = (bg & 0x00ff00); - color.blue = (bg & 0x0000ff) << 8; - - if (gdk_colormap_alloc_color (gtk_widget_get_colormap (GTK_WIDGET (addr)), &color, FALSE, TRUE)) { - GtkStyle *style = gtk_style_copy (gtk_widget_get_style (GTK_WIDGET (addr))); - style->bg[0] = color; - gtk_widget_set_style (GTK_WIDGET (addr), style); - } - } - - break; - } -} - -BonoboControl * -e_address_widget_factory_new_control (void) -{ - BonoboControl *control; - BonoboPropertyBag *bag; - GtkWidget *w; - - w = e_address_widget_new (); - gtk_widget_show (w); - - control = bonobo_control_new (w); - - bag = bonobo_property_bag_new (get_prop, set_prop, w); - bonobo_property_bag_add (bag, "name", ADDRESS_PROPERTY_NAME, - BONOBO_ARG_STRING, NULL, NULL, - BONOBO_PROPERTY_READABLE | BONOBO_PROPERTY_WRITEABLE); - - bonobo_property_bag_add (bag, "email", ADDRESS_PROPERTY_EMAIL, - BONOBO_ARG_STRING, NULL, NULL, - BONOBO_PROPERTY_READABLE | BONOBO_PROPERTY_WRITEABLE); - - bonobo_property_bag_add (bag, "text", ADDRESS_PROPERTY_TEXT, - BONOBO_ARG_STRING, NULL, NULL, - BONOBO_PROPERTY_READABLE | BONOBO_PROPERTY_WRITEABLE); - - bonobo_property_bag_add (bag, "background_rgb", ADDRESS_PROPERTY_BACKGROUND_RGB, - BONOBO_ARG_INT, NULL, NULL, - BONOBO_PROPERTY_WRITEABLE); - - bonobo_control_set_properties (control, bonobo_object_corba_objref (BONOBO_OBJECT (bag)), NULL); - bonobo_object_unref (BONOBO_OBJECT (bag)); - - return control; -} diff --git a/addressbook/gui/component/e-address-widget.h b/addressbook/gui/component/e-address-widget.h deleted file mode 100644 index 13e4a417d0..0000000000 --- a/addressbook/gui/component/e-address-widget.h +++ /dev/null @@ -1,82 +0,0 @@ -/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ - -/* - * e-address-widget.h - * - * Copyright (C) 2001 Ximian, Inc. - * - * Developed by Jon Trowbridge - */ - -/* - * This program is free software; you can redistribute it and/or - * modify it under the terms of version 2 of the GNU General Public - * License as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - * USA. - */ - -#ifndef __E_ADDRESS_WIDGET_H__ -#define __E_ADDRESS_WIDGET_H__ - -#include -#include -#include -#include -#include -#include - -G_BEGIN_DECLS - -#define E_TYPE_ADDRESS_WIDGET (e_address_widget_get_type ()) -#define E_ADDRESS_WIDGET(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), E_TYPE_ADDRESS_WIDGET, EAddressWidget)) -#define E_ADDRESS_WIDGET_CLASS(k) (G_TYPE_CHECK_CLASS_CAST ((k), E_TYPE_ADDRESS_WIDGET, EAddressWidgetClass)) -#define E_IS_ADDRESS_WIDGET(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), E_TYPE_ADDRESS_WIDGET)) -#define E_IS_ADDRESS_WIDGET_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), E_TYPE_ADDRESS_WIDGET)) - -typedef struct _EAddressWidget EAddressWidget; -typedef struct _EAddressWidgetClass EAddressWidgetClass; - -struct _EAddressWidget { - GtkEventBox parent; - - gchar *name; - gchar *email; - - GtkWidget *name_widget; - GtkWidget *email_widget; - GtkWidget *spacer; - - guint query_idle_tag; - guint query_tag; - - ECard *card; - gboolean known_email; -}; - -struct _EAddressWidgetClass { - GtkEventBoxClass parent_class; -}; - -GType e_address_widget_get_type (void); - -void e_address_widget_set_name (EAddressWidget *, const gchar *name); -void e_address_widget_set_email (EAddressWidget *, const gchar *email); -void e_address_widget_set_text (EAddressWidget *, const gchar *text); - -void e_address_widget_construct (EAddressWidget *); -GtkWidget *e_address_widget_new (void); - -BonoboControl *e_address_widget_new_control (void); - -G_END_DECLS - -#endif /* __E_ADDRESS_WIDGET_H__ */ diff --git a/addressbook/gui/component/e-cardlist-model.c b/addressbook/gui/component/e-cardlist-model.c deleted file mode 100644 index be1ff3ddd2..0000000000 --- a/addressbook/gui/component/e-cardlist-model.c +++ /dev/null @@ -1,239 +0,0 @@ -/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ -/* - * - * Author: - * Christopher James Lahey - * - * (C) 1999 Ximian, Inc. - */ - -#include -#include -#include -#include - -#include - -#include "e-cardlist-model.h" - -#define PARENT_TYPE e_table_model_get_type() - -static GObjectClass *parent_class = NULL; - -static void -e_cardlist_model_dispose(GObject *object) -{ - ECardlistModel *model = E_CARDLIST_MODEL(object); - int i; - - if (model->data != NULL) { - for ( i = 0; i < model->data_count; i++ ) { - g_object_unref(model->data[i]); - } - g_free(model->data); - model->data = NULL; - } - - if (G_OBJECT_CLASS (parent_class)->dispose) - (* G_OBJECT_CLASS (parent_class)->dispose) (object); -} - -/* This function returns the number of columns in our ETableModel. */ -static int -e_cardlist_model_col_count (ETableModel *etc) -{ - return E_CARD_SIMPLE_FIELD_LAST; -} - -/* This function returns the number of rows in our ETableModel. */ -static int -e_cardlist_model_row_count (ETableModel *etc) -{ - ECardlistModel *e_cardlist_model = E_CARDLIST_MODEL(etc); - return e_cardlist_model->data_count; -} - -/* This function returns the value at a particular point in our ETableModel. */ -static void * -e_cardlist_model_value_at (ETableModel *etc, int col, int row) -{ - ECardlistModel *e_cardlist_model = E_CARDLIST_MODEL(etc); - const char *value; - if ( col >= E_CARD_SIMPLE_FIELD_LAST - 1|| row >= e_cardlist_model->data_count ) - return NULL; - value = e_card_simple_get_const(e_cardlist_model->data[row], - col + 1); - return (void *)(value ? value : ""); -} - -/* This function sets the value at a particular point in our ETableModel. */ -static void -e_cardlist_model_set_value_at (ETableModel *etc, int col, int row, const void *val) -{ - ECardlistModel *e_cardlist_model = E_CARDLIST_MODEL(etc); - - if ( col >= E_CARD_SIMPLE_FIELD_LAST - 1|| row >= e_cardlist_model->data_count ) - return; - e_table_model_pre_change(etc); - e_card_simple_set(e_cardlist_model->data[row], - col + 1, - val); - - e_table_model_cell_changed(etc, col, row); -} - -/* This function returns whether a particular cell is editable. */ -static gboolean -e_cardlist_model_is_cell_editable (ETableModel *etc, int col, int row) -{ - return TRUE; -} - -/* This function duplicates the value passed to it. */ -static void * -e_cardlist_model_duplicate_value (ETableModel *etc, int col, const void *value) -{ - return g_strdup(value); -} - -/* This function frees the value passed to it. */ -static void -e_cardlist_model_free_value (ETableModel *etc, int col, void *value) -{ - g_free(value); -} - -static void * -e_cardlist_model_initialize_value (ETableModel *etc, int col) -{ - return g_strdup(""); -} - -static gboolean -e_cardlist_model_value_is_empty (ETableModel *etc, int col, const void *value) -{ - return !(value && *(char *)value); -} - -static char * -e_cardlist_model_value_to_string (ETableModel *etc, int col, const void *value) -{ - return g_strdup(value); -} - -void -e_cardlist_model_add(ECardlistModel *model, - ECard **cards, - int count) -{ - int i; - model->data = g_realloc(model->data, model->data_count + count * sizeof(ECard *)); - for (i = 0; i < count; i++) { - gboolean found = FALSE; - const gchar *id = e_card_get_id(cards[i]); - for ( i = 0; i < model->data_count; i++) { - if ( !strcmp(e_card_simple_get_id(model->data[i]), id) ) { - found = TRUE; - break; - } - } - if (!found) { - e_table_model_pre_change(E_TABLE_MODEL(model)); - g_object_ref(cards[i]); - model->data[model->data_count++] = e_card_simple_new (cards[i]); - e_table_model_row_inserted(E_TABLE_MODEL(model), model->data_count - 1); - } - } -} - -void -e_cardlist_model_remove(ECardlistModel *model, - const char *id) -{ - int i; - for ( i = 0; i < model->data_count; i++) { - if ( !strcmp(e_card_simple_get_id(model->data[i]), id) ) { - e_table_model_pre_change(E_TABLE_MODEL(model)); - g_object_unref(model->data[i]); - memmove(model->data + i, model->data + i + 1, (model->data_count - i - 1) * sizeof (ECard *)); - e_table_model_row_deleted(E_TABLE_MODEL(model), i); - } - } -} - -static void -e_cardlist_model_class_init (GObjectClass *object_class) -{ - ETableModelClass *model_class = (ETableModelClass *) object_class; - - parent_class = g_type_class_peek_parent (object_class); - - object_class->dispose = e_cardlist_model_dispose; - - model_class->column_count = e_cardlist_model_col_count; - model_class->row_count = e_cardlist_model_row_count; - model_class->value_at = e_cardlist_model_value_at; - model_class->set_value_at = e_cardlist_model_set_value_at; - model_class->is_cell_editable = e_cardlist_model_is_cell_editable; - model_class->duplicate_value = e_cardlist_model_duplicate_value; - model_class->free_value = e_cardlist_model_free_value; - model_class->initialize_value = e_cardlist_model_initialize_value; - model_class->value_is_empty = e_cardlist_model_value_is_empty; - model_class->value_to_string = e_cardlist_model_value_to_string; -} - -static void -e_cardlist_model_init (GObject *object) -{ - ECardlistModel *model = E_CARDLIST_MODEL(object); - model->data = NULL; - model->data_count = 0; -} - -ECard * -e_cardlist_model_get(ECardlistModel *model, - int row) -{ - if (model->data && row < model->data_count) { - ECard *card; - g_object_get(model->data[row], - "card", &card, - NULL); - return card; - } - return NULL; -} - -GType -e_cardlist_model_get_type (void) -{ - static GType aw_type = 0; - - if (!aw_type) { - static const GTypeInfo aw_info = { - sizeof (ECardlistModelClass), - NULL, /* base_init */ - NULL, /* base_finalize */ - (GClassInitFunc) e_cardlist_model_class_init, - NULL, /* class_finalize */ - NULL, /* class_data */ - sizeof (ECardlistModel), - 0, /* n_preallocs */ - (GInstanceInitFunc) e_cardlist_model_init, - }; - - aw_type = g_type_register_static (PARENT_TYPE, "ECardlistModel", &aw_info, 0); - } - - return aw_type; -} - -ETableModel * -e_cardlist_model_new (void) -{ - ECardlistModel *et; - - et = g_object_new (E_TYPE_CARDLIST_MODEL, NULL); - - return E_TABLE_MODEL(et); -} diff --git a/addressbook/gui/component/e-cardlist-model.h b/addressbook/gui/component/e-cardlist-model.h deleted file mode 100644 index 0968e936fc..0000000000 --- a/addressbook/gui/component/e-cardlist-model.h +++ /dev/null @@ -1,42 +0,0 @@ -/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ -#ifndef _E_CARDLIST_MODEL_H_ -#define _E_CARDLIST_MODEL_H_ - -#include -#include -#include -#include - -#define E_TYPE_CARDLIST_MODEL (e_cardlist_model_get_type ()) -#define E_CARDLIST_MODEL(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), E_TYPE_CARDLIST_MODEL, ECardlistModel)) -#define E_CARDLIST_MODEL_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), E_TYPE_CARDLIST_MODEL, ECardlistModelClass)) -#define E_IS_CARDLIST_MODEL(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), E_TYPE_CARDLIST_MODEL)) -#define E_IS_CARDLIST_MODEL_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), E_TYPE_CARDLIST_MODEL)) - -typedef struct { - ETableModel parent; - - /* item specific fields */ - ECardSimple **data; - int data_count; -} ECardlistModel; - - -typedef struct { - ETableModelClass parent_class; -} ECardlistModelClass; - - -GType e_cardlist_model_get_type (void); -ETableModel *e_cardlist_model_new (void); - -/* Returns object with an extra ref count. */ -ECard *e_cardlist_model_get (ECardlistModel *model, - int row); -void e_cardlist_model_add (ECardlistModel *model, - ECard **card, - int count); -void e_cardlist_model_remove (ECardlistModel *model, - const char *id); - -#endif /* _E_CARDLIST_MODEL_H_ */ diff --git a/addressbook/gui/component/select-names/Evolution-Addressbook-SelectNames.idl b/addressbook/gui/component/select-names/Evolution-Addressbook-SelectNames.idl index 2959597cc5..6feb6b54bb 100644 --- a/addressbook/gui/component/select-names/Evolution-Addressbook-SelectNames.idl +++ b/addressbook/gui/component/select-names/Evolution-Addressbook-SelectNames.idl @@ -14,78 +14,6 @@ module GNOME { module Evolution { module Addressbook { - interface SimpleCard : Bonobo::Unknown { - struct Arbitrary { - string key; - string type; - string value; - }; - - enum Field { - FileAs, - FullName, - Email, - PhonePrimary, - PhoneAssistant, - PhoneBusiness, - PhoneCallback, - PhoneCompany, - PhoneHome, - Org, - AddressBusiness, - AddressHome, - PhoneMobile, - PhoneCar, - PhoneBusinessFax, - PhoneHomeFax, - PhoneBusiness2, - PhoneHome2, - PhoneIsdn, - PhoneOther, - PhoneOtherFax, - PhonePager, - PhoneRadio, - PhoneTelex, - PhoneTtytdd, - AddressOther, - Email2, - Email3, - Url, - OrgUnit, - Office, - Title, - Role, - Manager, - Assistant, - Nickname, - Spouse, - Note, - Caluri, - Fburl, - Icscalendar, - Anniversary, - BirthDate, - Mailer, - NameOrOrg, - Categories, - FamilyName, - GivenName, - AdditionalName, - NameSuffix, - WantsHtml, - IsList, - Last - }; - - Arbitrary getArbitrary (in string key); - void setArbitrary (in string key, in string type, in string value); - - string get (in Field field); - void set (in Field field, in string value); - }; - - typedef sequence SimpleCardList; - interface SelectNames : Bonobo::Unknown { struct Section { string id; diff --git a/addressbook/gui/component/select-names/GNOME_Evolution_Addressbook_SelectNames.server.in.in b/addressbook/gui/component/select-names/GNOME_Evolution_Addressbook_SelectNames.server.in.in index 6e4d156051..80b138f1dc 100644 --- a/addressbook/gui/component/select-names/GNOME_Evolution_Addressbook_SelectNames.server.in.in +++ b/addressbook/gui/component/select-names/GNOME_Evolution_Addressbook_SelectNames.server.in.in @@ -17,7 +17,7 @@ + location="OAFIID:GNOME_Evolution_Addressbook_Factory_2"> @@ -28,4 +28,4 @@ - \ No newline at end of file + diff --git a/addressbook/gui/component/select-names/Makefile.am b/addressbook/gui/component/select-names/Makefile.am index 051a168815..b78e5b69fe 100644 --- a/addressbook/gui/component/select-names/Makefile.am +++ b/addressbook/gui/component/select-names/Makefile.am @@ -69,9 +69,7 @@ libeselectnames_la_SOURCES = \ e-select-names-text-model.c \ e-select-names-text-model.h \ e-select-names.c \ - e-select-names.h \ - e-simple-card-bonobo.c \ - e-simple-card-bonobo.h + e-select-names.h libeselectnames_la_LIBADD = \ $(top_builddir)/addressbook/backend/ebook/libebook.la \ diff --git a/addressbook/gui/component/select-names/e-select-names-bonobo.c b/addressbook/gui/component/select-names/e-select-names-bonobo.c index 10fc9caee7..f10fa3b804 100644 --- a/addressbook/gui/component/select-names/e-select-names-bonobo.c +++ b/addressbook/gui/component/select-names/e-select-names-bonobo.c @@ -25,7 +25,6 @@ #endif #include "e-select-names-bonobo.h" -#include "e-simple-card-bonobo.h" #include @@ -63,7 +62,6 @@ enum _EntryPropertyID { ENTRY_PROPERTY_ID_TEXT, ENTRY_PROPERTY_ID_ADDRESSES, ENTRY_PROPERTY_ID_DESTINATIONS, - ENTRY_PROPERTY_ID_SIMPLE_CARD_LIST, ENTRY_PROPERTY_ID_ALLOW_CONTACT_LISTS, ENTRY_PROPERTY_ID_ENTRY_CHANGED }; @@ -122,38 +120,6 @@ entry_get_property_fn (BonoboPropertyBag *bag, } break; - case ENTRY_PROPERTY_ID_SIMPLE_CARD_LIST: - { - ESelectNamesModel *model; - int count; - int i; - GNOME_Evolution_Addressbook_SimpleCardList *card_list; - - model = E_SELECT_NAMES_MODEL (g_object_get_data (G_OBJECT (w), "select_names_model")); - g_assert (model != NULL); - - count = e_select_names_model_count (model); - - card_list = GNOME_Evolution_Addressbook_SimpleCardList__alloc (); - card_list->_buffer = CORBA_sequence_GNOME_Evolution_Addressbook_SimpleCard_allocbuf (count); - card_list->_maximum = count; - card_list->_length = count; - - for (i = 0; i < count; i++) { - const EDestination *destination = e_select_names_model_get_destination (model, i); - const ECard *card = e_destination_get_card (destination); - ECardSimple *simple = e_card_simple_new ((ECard *) card); - ESimpleCardBonobo *simple_card = e_simple_card_bonobo_new (simple); - g_object_unref (simple); - - card_list->_buffer[i] = bonobo_object_corba_objref (BONOBO_OBJECT (simple_card)); - } - - CORBA_free (*(GNOME_Evolution_Addressbook_SimpleCardList **)arg->_value); - BONOBO_ARG_SET_GENERAL (arg, *card_list, TC_GNOME_Evolution_Addressbook_SimpleCardList, GNOME_Evolution_Addressbook_SimpleCardList, NULL); - } - break; - case ENTRY_PROPERTY_ID_ALLOW_CONTACT_LISTS: { ESelectNamesCompletion *comp; @@ -195,7 +161,7 @@ entry_set_property_fn (BonoboPropertyBag *bag, g_assert (model != NULL); e_entry_set_text (E_ENTRY (w), BONOBO_ARG_GET_STRING (arg)); - e_select_names_model_cardify_all (model, NULL, 0); + e_select_names_model_load_all_contacts (model, NULL); break; } @@ -206,7 +172,7 @@ entry_set_property_fn (BonoboPropertyBag *bag, g_assert (model != NULL); e_select_names_model_import_destinationv (model, BONOBO_ARG_GET_STRING (arg)); - e_select_names_model_cardify_all (model, NULL, 0); + e_select_names_model_load_all_contacts (model, NULL); break; } @@ -499,9 +465,6 @@ impl_SelectNames_get_entry_for_section (PortableServer_Servant servant, bonobo_property_bag_add (property_bag, "destinations", ENTRY_PROPERTY_ID_DESTINATIONS, BONOBO_ARG_STRING, NULL, NULL, BONOBO_PROPERTY_READABLE | BONOBO_PROPERTY_WRITEABLE); - bonobo_property_bag_add (property_bag, "simple_card_list", ENTRY_PROPERTY_ID_SIMPLE_CARD_LIST, - TC_GNOME_Evolution_Addressbook_SimpleCardList, NULL, NULL, - BONOBO_PROPERTY_READABLE); bonobo_property_bag_add (property_bag, "allow_contact_lists", ENTRY_PROPERTY_ID_ALLOW_CONTACT_LISTS, BONOBO_ARG_BOOLEAN, NULL, NULL, BONOBO_PROPERTY_READABLE | BONOBO_PROPERTY_WRITEABLE); diff --git a/addressbook/gui/component/select-names/e-select-names-completion.c b/addressbook/gui/component/select-names/e-select-names-completion.c index 5a9fc2deb4..7bfbfd2a5a 100644 --- a/addressbook/gui/component/select-names/e-select-names-completion.c +++ b/addressbook/gui/component/select-names/e-select-names-completion.c @@ -34,17 +34,17 @@ #include -#include -#include -#include -#include +#include +#include +#include +#include typedef struct { EBook *book; guint book_view_tag; EBookView *book_view; ESelectNamesCompletion *comp; - guint card_added_tag; + guint contacts_added_tag; guint seq_complete_tag; gboolean sequence_complete_received; @@ -76,7 +76,7 @@ static void e_select_names_completion_init (ESelectNamesCompletion *); static void e_select_names_completion_dispose (GObject *object); static void e_select_names_completion_got_book_view_cb (EBook *book, EBookStatus status, EBookView *view, gpointer user_data); -static void e_select_names_completion_card_added_cb (EBookView *, const GList *cards, gpointer user_data); +static void e_select_names_completion_contacts_added_cb (EBookView *, const GList *cards, gpointer user_data); static void e_select_names_completion_seq_complete_cb (EBookView *, EBookViewStatus status, gpointer user_data); static void e_select_names_completion_do_query (ESelectNamesCompletion *, const gchar *query_text, gint pos, gint limit); @@ -95,7 +95,7 @@ static FILE *out; */ typedef gchar *(*BookQuerySExp) (ESelectNamesCompletion *); -typedef ECompletionMatch *(*BookQueryMatchTester) (ESelectNamesCompletion *, EDestination *); +typedef ECompletionMatch *(*BookQueryMatchTester) (ESelectNamesCompletion *, EABDestination *); static int utf8_casefold_collate_len (const gchar *str1, const gchar *str2, int len) @@ -125,14 +125,16 @@ our_match_destroy (ECompletionMatch *match) } static ECompletionMatch * -make_match (EDestination *dest, const gchar *menu_form, double score) +make_match (EABDestination *dest, const gchar *menu_form, double score) { ECompletionMatch *match; - ECard *card = e_destination_get_card (dest); +#if notyet + EContact *contact = eab_destination_get_contact (dest); +#endif - match = e_completion_match_new (e_destination_get_name (dest), menu_form, score); + match = e_completion_match_new (eab_destination_get_name (dest), menu_form, score); - e_completion_match_set_text (match, e_destination_get_name (dest), menu_form); + e_completion_match_set_text (match, eab_destination_get_name (dest), menu_form); /* Reject any match that has null text fields. */ if (! (e_completion_match_get_match_text (match) && e_completion_match_get_menu_text (match))) { @@ -140,10 +142,15 @@ make_match (EDestination *dest, const gchar *menu_form, double score) return NULL; } +#if notyet + /* XXX toshok - EContact doesn't have the use_score stuff */ /* Since we sort low to high, we negate so that larger use scores will come first */ - match->sort_major = card ? -floor (e_card_get_use_score (card)) : 0; + match->sort_major = contact ? -floor (e_contact_get_use_score (contact)) : 0; +#else + match->sort_major = 0; +#endif - match->sort_minor = e_destination_get_email_num (dest); + match->sort_minor = eab_destination_get_email_num (dest); match->user_data = dest; g_object_ref (dest); @@ -166,31 +173,33 @@ sexp_nickname (ESelectNamesCompletion *comp) } static ECompletionMatch * -match_nickname (ESelectNamesCompletion *comp, EDestination *dest) +match_nickname (ESelectNamesCompletion *comp, EABDestination *dest) { ECompletionMatch *match = NULL; gint len; - ECard *card = e_destination_get_card (dest); + EContact *contact = eab_destination_get_contact (dest); double score; + const char *nickname; - if (card->nickname == NULL) + nickname = e_contact_get_const (contact, E_CONTACT_NICKNAME); + if (nickname == NULL) return NULL; len = g_utf8_strlen (comp->priv->query_text, -1); - if (card->nickname && !utf8_casefold_collate_len (comp->priv->query_text, card->nickname, len)) { + if (nickname && !utf8_casefold_collate_len (comp->priv->query_text, nickname, len)) { const gchar *name; gchar *str; score = len * 2; /* nickname gives 2 points per matching character */ - if (len == g_utf8_strlen (card->nickname, -1)) /* boost score on an exact match */ + if (len == g_utf8_strlen (nickname, -1)) /* boost score on an exact match */ score *= 10; - name = e_destination_get_name (dest); + name = eab_destination_get_name (dest); if (name && *name) - str = g_strdup_printf ("'%s' %s <%s>", card->nickname, name, e_destination_get_email (dest)); + str = g_strdup_printf ("'%s' %s <%s>", nickname, name, eab_destination_get_email (dest)); else - str = g_strdup_printf ("'%s' <%s>", card->nickname, e_destination_get_email (dest)); + str = g_strdup_printf ("'%s' <%s>", nickname, eab_destination_get_email (dest)); match = make_match (dest, str, score); g_free (str); @@ -210,17 +219,17 @@ sexp_email (ESelectNamesCompletion *comp) } static ECompletionMatch * -match_email (ESelectNamesCompletion *comp, EDestination *dest) +match_email (ESelectNamesCompletion *comp, EABDestination *dest) { ECompletionMatch *match; gint len = strlen (comp->priv->query_text); - const gchar *name = e_destination_get_name (dest); - const gchar *email = e_destination_get_email (dest); + const gchar *name = eab_destination_get_name (dest); + const gchar *email = eab_destination_get_email (dest); double score; if (email && !utf8_casefold_collate_len (comp->priv->query_text, email, len) - && !e_destination_is_evolution_list (dest)) { + && !eab_destination_is_evolution_list (dest)) { gchar *str; @@ -294,78 +303,82 @@ sexp_name (ESelectNamesCompletion *comp) } static ECompletionMatch * -match_name (ESelectNamesCompletion *comp, EDestination *dest) +match_name (ESelectNamesCompletion *comp, EABDestination *dest) { ECompletionMatch *final_match = NULL; gchar *menu_text = NULL; - ECard *card; + EContact *contact; const gchar *email; gint match_len = 0; - ECardMatchType match; - ECardMatchPart first_match; + EABContactMatchType match; + EABContactMatchPart first_match; double score = 0; gboolean have_given, have_additional, have_family; + EContactName *contact_name; - card = e_destination_get_card (dest); - - if (card->name == NULL) + contact = eab_destination_get_contact (dest); + + contact_name = e_contact_get (contact, E_CONTACT_NAME); + if (!contact_name) return NULL; - email = e_destination_get_email (dest); + email = eab_destination_get_email (dest); - match = e_card_compare_name_to_string_full (card, comp->priv->query_text, TRUE /* yes, allow partial matches */, - NULL, &first_match, &match_len); + match = eab_contact_compare_name_to_string_full (contact, comp->priv->query_text, TRUE /* yes, allow partial matches */, + NULL, &first_match, &match_len); - if (match <= E_CARD_MATCH_NONE) + if (match <= EAB_CONTACT_MATCH_NONE) { + e_contact_name_free (contact_name); return NULL; + } score = match_len * 3; /* three points per match character */ - have_given = card->name->given && *card->name->given; - have_additional = card->name->additional && *card->name->additional; - have_family = card->name->family && *card->name->family; + have_given = contact_name->given && *contact_name->given; + have_additional = contact_name->additional && *contact_name->additional; + have_family = contact_name->family && *contact_name->family; - if (e_card_evolution_list (card)) { + if (e_contact_get (contact, E_CONTACT_IS_LIST)) { - menu_text = e_card_name_to_string (card->name); + menu_text = e_contact_name_to_string (contact_name); - } else if (first_match == E_CARD_MATCH_PART_GIVEN_NAME) { + } else if (first_match == EAB_CONTACT_MATCH_PART_GIVEN_NAME) { if (have_family) - menu_text = g_strdup_printf ("%s %s <%s>", card->name->given, card->name->family, email); + menu_text = g_strdup_printf ("%s %s <%s>", contact_name->given, contact_name->family, email); else - menu_text = g_strdup_printf ("%s <%s>", card->name->given, email); + menu_text = g_strdup_printf ("%s <%s>", contact_name->given, email); - } else if (first_match == E_CARD_MATCH_PART_ADDITIONAL_NAME) { + } else if (first_match == EAB_CONTACT_MATCH_PART_ADDITIONAL_NAME) { if (have_given) { menu_text = g_strdup_printf ("%s%s%s, %s <%s>", - card->name->additional, + contact_name->additional, have_family ? " " : "", - have_family ? card->name->family : "", - card->name->given, + have_family ? contact_name->family : "", + contact_name->given, email); } else { menu_text = g_strdup_printf ("%s%s%s <%s>", - card->name->additional, + contact_name->additional, have_family ? " " : "", - have_family ? card->name->family : "", + have_family ? contact_name->family : "", email); } - } else if (first_match == E_CARD_MATCH_PART_FAMILY_NAME) { + } else if (first_match == EAB_CONTACT_MATCH_PART_FAMILY_NAME) { if (have_given) menu_text = g_strdup_printf ("%s, %s%s%s <%s>", - card->name->family, - card->name->given, + contact_name->family, + contact_name->given, have_additional ? " " : "", - have_additional ? card->name->additional : "", + have_additional ? contact_name->additional : "", email); else - menu_text = g_strdup_printf ("%s <%s>", card->name->family, email); + menu_text = g_strdup_printf ("%s <%s>", contact_name->family, email); } else { /* something funny happened */ @@ -379,6 +392,8 @@ match_name (ESelectNamesCompletion *comp, EDestination *dest) g_free (menu_text); } + e_contact_name_free (contact_name); + return final_match; } @@ -393,7 +408,7 @@ sexp_file_as (ESelectNamesCompletion *comp) } static ECompletionMatch * -match_file_as (ESelectNamesCompletion *comp, EDestination *dest) +match_file_as (ESelectNamesCompletion *comp, EABDestination *dest) { const gchar *name; const gchar *email; @@ -402,8 +417,8 @@ match_file_as (ESelectNamesCompletion *comp, EDestination *dest) double score = 0.00001; ECompletionMatch *match; - name = e_destination_get_name (dest); - email = e_destination_get_email (dest); + name = eab_destination_get_name (dest); + email = eab_destination_get_email (dest); if (!(name && *name)) return NULL; @@ -491,13 +506,13 @@ book_query_sexp (ESelectNamesCompletion *comp) * string that applies to a given destination. */ static ECompletionMatch * -book_query_score (ESelectNamesCompletion *comp, EDestination *dest) +book_query_score (ESelectNamesCompletion *comp, EABDestination *dest) { ECompletionMatch *best_match = NULL; gint i; g_return_val_if_fail (E_IS_SELECT_NAMES_COMPLETION (comp), NULL); - g_return_val_if_fail (E_IS_DESTINATION (dest), NULL); + g_return_val_if_fail (EAB_IS_DESTINATION (dest), NULL); if (! (comp->priv->query_text && *comp->priv->query_text)) return NULL; @@ -506,7 +521,7 @@ book_query_score (ESelectNamesCompletion *comp, EDestination *dest) ECompletionMatch *this_match = NULL; - if (book_queries[i].tester && e_destination_get_card (dest)) { + if (book_queries[i].tester && eab_destination_get_contact (dest)) { this_match = book_queries[i].tester (comp, dest); } @@ -524,18 +539,18 @@ book_query_score (ESelectNamesCompletion *comp, EDestination *dest) } static void -book_query_process_card_list (ESelectNamesCompletion *comp, const GList *cards) +book_query_process_card_list (ESelectNamesCompletion *comp, const GList *contacts) { - while (cards) { - ECard *card = E_CARD (cards->data); + while (contacts) { + EContact *contact = E_CONTACT (contacts->data); - if (e_card_evolution_list (card)) { + if (e_contact_get (contact, E_CONTACT_IS_LIST)) { if (comp->priv->match_contact_lists) { - EDestination *dest = e_destination_new (); + EABDestination *dest = eab_destination_new (); ECompletionMatch *match; - e_destination_set_card (dest, card, 0); + eab_destination_set_contact (dest, contact, 0); match = book_query_score (comp, dest); if (match && match->score > 0) { e_completion_found_match (E_COMPLETION (comp), match); @@ -546,31 +561,38 @@ book_query_process_card_list (ESelectNamesCompletion *comp, const GList *cards) } - } else if (card->email) { - gint i; - for (i=0; iemail); ++i) { - EDestination *dest = e_destination_new (); - const gchar *email; - ECompletionMatch *match; + } + else { + GList *email = e_contact_get (contact, E_CONTACT_EMAIL); + if (email) { + GList *iter; + gint i; + for (i=0, iter = email; iter; ++i, iter = iter->next) { + EABDestination *dest = eab_destination_new (); + gchar *e; + ECompletionMatch *match; - e_destination_set_card (dest, card, i); - email = e_destination_get_email (dest); + eab_destination_set_contact (dest, contact, i); + e = iter->data; - if (email && *email) { + if (e && *e) { - match = book_query_score (comp, dest); - if (match && match->score > 0) { - e_completion_found_match (E_COMPLETION (comp), match); - } else { - e_completion_match_unref (match); + match = book_query_score (comp, dest); + if (match && match->score > 0) { + e_completion_found_match (E_COMPLETION (comp), match); + } else { + e_completion_match_unref (match); + } } - } - g_object_unref (dest); + g_object_unref (dest); + } } + g_list_foreach (email, (GFunc)g_free, NULL); + g_list_free (email); } - cards = g_list_next (cards); + contacts = contacts->next; } } @@ -640,9 +662,9 @@ e_select_names_completion_clear_book_data (ESelectNamesCompletion *comp) for (l = comp->priv->book_data; l; l = l->next) { ESelectNamesCompletionBookData *book_data = l->data; - if (book_data->card_added_tag) { - g_signal_handler_disconnect (book_data->book_view, book_data->card_added_tag); - book_data->card_added_tag = 0; + if (book_data->contacts_added_tag) { + g_signal_handler_disconnect (book_data->book_view, book_data->contacts_added_tag); + book_data->contacts_added_tag = 0; } if (book_data->seq_complete_tag) { @@ -756,7 +778,7 @@ e_select_names_completion_got_book_view_cb (EBook *book, EBookStatus status, EBo book_data = (ESelectNamesCompletionBookData*)user_data; comp = book_data->comp; - if (status != E_BOOK_STATUS_SUCCESS) { + if (status != E_BOOK_ERROR_OK) { comp->priv->pending_completion_seq--; if (!comp->priv->pending_completion_seq) e_select_names_completion_done (comp); @@ -765,9 +787,9 @@ e_select_names_completion_got_book_view_cb (EBook *book, EBookStatus status, EBo book_data->book_view_tag = 0; - if (book_data->card_added_tag) { - g_signal_handler_disconnect (book_data->book_view, book_data->card_added_tag); - book_data->card_added_tag = 0; + if (book_data->contacts_added_tag) { + g_signal_handler_disconnect (book_data->book_view, book_data->contacts_added_tag); + book_data->contacts_added_tag = 0; } if (book_data->seq_complete_tag) { g_signal_handler_disconnect (book_data->book_view, book_data->seq_complete_tag); @@ -781,10 +803,10 @@ e_select_names_completion_got_book_view_cb (EBook *book, EBookStatus status, EBo } book_data->book_view = view; - book_data->card_added_tag = + book_data->contacts_added_tag = g_signal_connect (view, - "card_added", - G_CALLBACK (e_select_names_completion_card_added_cb), + "contacts_added", + G_CALLBACK (e_select_names_completion_contacts_added_cb), book_data); book_data->seq_complete_tag = @@ -792,11 +814,14 @@ e_select_names_completion_got_book_view_cb (EBook *book, EBookStatus status, EBo "sequence_complete", G_CALLBACK (e_select_names_completion_seq_complete_cb), book_data); + + e_book_view_start (view); + book_data->sequence_complete_received = FALSE; } static void -e_select_names_completion_card_added_cb (EBookView *book_view, const GList *cards, gpointer user_data) +e_select_names_completion_contacts_added_cb (EBookView *book_view, const GList *cards, gpointer user_data) { ESelectNamesCompletionBookData *book_data = user_data; ESelectNamesCompletion *comp = book_data->comp; @@ -834,7 +859,7 @@ e_select_names_completion_seq_complete_cb (EBookView *book_view, EBookViewStatus } if (book_data->cached_query_text - && status == E_BOOK_STATUS_SUCCESS + && status == E_BOOK_ERROR_OK && !book_data->cache_complete && !strcmp (book_data->cached_query_text, comp->priv->query_text)) book_data->cache_complete = TRUE; @@ -845,9 +870,9 @@ e_select_names_completion_seq_complete_cb (EBookView *book_view, EBookViewStatus if (!book_data->sequence_complete_received) { book_data->sequence_complete_received = TRUE; - if (book_data->card_added_tag) { - g_signal_handler_disconnect (book_data->book_view, book_data->card_added_tag); - book_data->card_added_tag = 0; + if (book_data->contacts_added_tag) { + g_signal_handler_disconnect (book_data->book_view, book_data->contacts_added_tag); + book_data->contacts_added_tag = 0; } if (book_data->seq_complete_tag) { g_signal_handler_disconnect (book_data->book_view, book_data->seq_complete_tag); @@ -888,13 +913,15 @@ e_select_names_completion_stop_query (ESelectNamesCompletion *comp) for (l = comp->priv->book_data; l; l = l->next) { ESelectNamesCompletionBookData *book_data = l->data; if (book_data->book_view_tag) { +#if notyet e_book_cancel (book_data->book, book_data->book_view_tag); +#endif book_data->book_view_tag = 0; } if (book_data->book_view) { - if (book_data->card_added_tag) { - g_signal_handler_disconnect (book_data->book_view, book_data->card_added_tag); - book_data->card_added_tag = 0; + if (book_data->contacts_added_tag) { + g_signal_handler_disconnect (book_data->book_view, book_data->contacts_added_tag); + book_data->contacts_added_tag = 0; } if (book_data->seq_complete_tag) { g_signal_handler_disconnect (book_data->book_view, book_data->seq_complete_tag); @@ -977,13 +1004,10 @@ e_select_names_completion_start_query (ESelectNamesCompletion *comp, const gchar e_select_names_completion_clear_cache (book_data); book_data->cached_query_text = g_strdup (query_text); - book_data->book_view_tag = e_book_get_completion_view (book_data->book, + book_data->book_view_tag = e_book_async_get_book_view (book_data->book, sexp, e_select_names_completion_got_book_view_cb, book_data); - if (! book_data->book_view_tag) - g_warning ("Exception calling e_book_get_completion_view"); - else - comp->priv->pending_completion_seq++; + comp->priv->pending_completion_seq++; } if (out) diff --git a/addressbook/gui/component/select-names/e-select-names-completion.h b/addressbook/gui/component/select-names/e-select-names-completion.h index 6565208378..435fe80041 100644 --- a/addressbook/gui/component/select-names/e-select-names-completion.h +++ b/addressbook/gui/component/select-names/e-select-names-completion.h @@ -28,7 +28,7 @@ #define E_SELECT_NAMES_COMPLETION_H #include -#include +#include #include "e-select-names-text-model.h" G_BEGIN_DECLS diff --git a/addressbook/gui/component/select-names/e-select-names-manager.c b/addressbook/gui/component/select-names/e-select-names-manager.c index a3875cea97..e095f7308f 100644 --- a/addressbook/gui/component/select-names/e-select-names-manager.c +++ b/addressbook/gui/component/select-names/e-select-names-manager.c @@ -24,8 +24,8 @@ #include "e-select-names-completion.h" #include "e-select-names-popup.h" #include "e-folder-list.h" -#include -#include +#include +#include #include "addressbook/gui/component/addressbook.h" #include @@ -175,7 +175,7 @@ focus_in_cb (GtkWidget *w, GdkEventFocus *ev, gpointer user_data) entry->cleaning_tag = 0; } - e_select_names_model_cancel_cardify_all (entry->model); + e_select_names_model_cancel_all_contact_load (entry->model); return FALSE; } @@ -189,7 +189,7 @@ focus_out_cb (GtkWidget *w, GdkEventFocus *ev, gpointer user_data) gboolean visible = e_entry_completion_popup_is_visible (entry->entry); if (! visible) { - e_select_names_model_cardify_all (entry->model, entry->manager->completion_book, 100); + e_select_names_model_load_all_contacts (entry->model, entry->manager->completion_book, 100); if (entry->cleaning_tag == 0) entry->cleaning_tag = gtk_timeout_add (100, clean_cb, entry); } @@ -205,7 +205,7 @@ completion_popup_cb (EEntry *w, gint visible, gpointer user_data) ESelectNamesManagerEntry *entry = user_data; if (!visible && !GTK_WIDGET_HAS_FOCUS (GTK_WIDGET (entry->entry->canvas))) - e_select_names_model_cardify_all (entry->model, entry->manager->completion_book, 0); + e_select_names_model_load_all_contacts (entry->model, entry->manager->completion_book, 0); #endif } @@ -214,14 +214,14 @@ completion_handler (EEntry *entry, ECompletionMatch *match) { ESelectNamesManagerEntry *mgr_entry; ESelectNamesTextModel *text_model; - EDestination *dest; + EABDestination *dest; gint i, pos, start_pos, len; if (match == NULL || match->user_data == NULL) return; mgr_entry = get_entry_info (entry); - dest = E_DESTINATION (match->user_data); + dest = EAB_DESTINATION (match->user_data); /* Sometimes I really long for garbage collection. Reference counting makes you feel 31337, but sometimes it is just a @@ -377,7 +377,7 @@ e_select_names_manager_discard_saved_models (ESelectNamesManager *manager) static void open_book_cb (EBook *book, EBookStatus status, ESelectNamesManager *manager) { - if (status == E_BOOK_STATUS_SUCCESS) { + if (status == E_BOOK_ERROR_OK) { GList *l; for (l = manager->entries; l; l = l->next) { ESelectNamesManagerEntry *entry = l->data; @@ -398,15 +398,10 @@ load_completion_books (ESelectNamesManager *manager) EFolderListItem *f; for (f = folders; f && f->physical_uri; f++) { - char *uri; EBook *book = e_book_new (); g_object_ref (manager); /* ref ourself before our async call */ - uri = e_book_expand_uri (f->physical_uri); - - addressbook_load_uri (book, uri, (EBookCallback)open_book_cb, manager); - - g_free (uri); + addressbook_load_uri (book, f->physical_uri, (EBookCallback)open_book_cb, manager); } e_folder_list_free_items (folders); } @@ -485,7 +480,7 @@ e_select_names_manager_new (void) ESelectNamesManager *manager = g_object_new (E_TYPE_SELECT_NAMES_MANAGER, NULL); EConfigListener *db; - db = e_book_get_config_database(); + db = eab_get_config_database(); manager->listener_id = g_signal_connect (db, "key_changed", @@ -685,7 +680,7 @@ e_select_names_manager_dispose (GObject *object) } if (manager->listener_id) { - g_signal_handler_disconnect (e_book_get_config_database(), manager->listener_id); + g_signal_handler_disconnect (eab_get_config_database(), manager->listener_id); manager->listener_id = 0; } diff --git a/addressbook/gui/component/select-names/e-select-names-model.c b/addressbook/gui/component/select-names/e-select-names-model.c index 6c3cb0f9c6..d95aebde5d 100644 --- a/addressbook/gui/component/select-names/e-select-names-model.c +++ b/addressbook/gui/component/select-names/e-select-names-model.c @@ -19,7 +19,7 @@ #include "e-select-names-model.h" #include "e-select-names-marshal.h" -#include "addressbook/backend/ebook/e-card-simple.h" +#include "addressbook/backend/ebook/e-contact.h" #define MAX_LENGTH 2047 @@ -35,14 +35,14 @@ static guint e_select_names_model_signals[E_SELECT_NAMES_MODEL_LAST_SIGNAL] = { /* Object argument IDs */ enum { ARG_0, - ARG_CARD, + ARG_CONTACT, }; struct _ESelectNamesModelPrivate { gchar *id; gchar *title; - GList *data; /* of EDestination */ + GList *data; /* of EABDestination */ gint limit; @@ -159,7 +159,7 @@ e_select_names_model_changed (ESelectNamesModel *model) } static void -destination_changed_proxy (EDestination *dest, gpointer closure) +destination_changed_proxy (EABDestination *dest, gpointer closure) { e_select_names_model_changed (E_SELECT_NAMES_MODEL (closure)); } @@ -184,7 +184,7 @@ e_select_names_model_duplicate (ESelectNamesModel *old) model->priv->title = g_strdup (old->priv->title); for (iter = old->priv->data; iter != NULL; iter = g_list_next (iter)) { - EDestination *dup = e_destination_copy (E_DESTINATION (iter->data)); + EABDestination *dup = eab_destination_copy (EAB_DESTINATION (iter->data)); e_select_names_model_append (model, dup); } @@ -212,8 +212,8 @@ e_select_names_model_get_textification (ESelectNamesModel *model, const char *se GList *iter = model->priv->data; while (iter) { - EDestination *dest = E_DESTINATION (iter->data); - strv[i] = (gchar *) e_destination_get_textrep (dest, FALSE); + EABDestination *dest = EAB_DESTINATION (iter->data); + strv[i] = (gchar *) eab_destination_get_textrep (dest, FALSE); ++i; iter = g_list_next (iter); } @@ -252,8 +252,8 @@ e_select_names_model_get_address_text (ESelectNamesModel *model, const char *sep GList *iter = model->priv->data; while (iter) { - EDestination *dest = E_DESTINATION (iter->data); - strv[i] = (gchar *) e_destination_get_address (dest); + EABDestination *dest = EAB_DESTINATION (iter->data); + strv[i] = (gchar *) eab_destination_get_address (dest); if (strv[i]) ++i; iter = g_list_next (iter); @@ -304,43 +304,42 @@ e_select_names_model_at_limit (ESelectNamesModel *model) return model->priv->limit >= 0 && g_list_length (model->priv->data) >= model->priv->limit; } -const EDestination * +const EABDestination * e_select_names_model_get_destination (ESelectNamesModel *model, gint index) { g_return_val_if_fail (model && E_IS_SELECT_NAMES_MODEL (model), NULL); g_return_val_if_fail (0 <= index, NULL); g_return_val_if_fail (index < g_list_length (model->priv->data), NULL); - return E_DESTINATION (g_list_nth_data (model->priv->data, index)); + return EAB_DESTINATION (g_list_nth_data (model->priv->data, index)); } gchar * e_select_names_model_export_destinationv (ESelectNamesModel *model) { - EDestination **destv; + EABDestination **destv; gchar *str; gint i, len = 0; GList *j; g_return_val_if_fail (model && E_IS_SELECT_NAMES_MODEL (model), NULL); len = g_list_length (model->priv->data); - destv = g_new0 (EDestination *, len+1); + destv = g_new0 (EABDestination *, len+1); for (i=0, j = model->priv->data; j != NULL; j = g_list_next (j)) { - EDestination *dest = E_DESTINATION (j->data); + EABDestination *dest = EAB_DESTINATION (j->data); if (dest) destv[i++] = dest; } - str = e_destination_exportv (destv); + str = eab_destination_exportv (destv); g_free (destv); return str; } -static -void send_changed (EDestination *dest, ECard *card, gpointer closure) +static void send_changed (EABDestination *dest, EContact *contact, gpointer closure) { ESelectNamesModel *model = closure; e_select_names_model_changed (model); @@ -350,12 +349,12 @@ void e_select_names_model_import_destinationv (ESelectNamesModel *model, gchar *destinationv) { - EDestination **destv; + EABDestination **destv; gint i; g_return_if_fail (model && E_IS_SELECT_NAMES_MODEL (model)); - destv = e_destination_importv (destinationv); + destv = eab_destination_importv (destinationv); e_select_names_model_delete_all (model); @@ -363,30 +362,30 @@ e_select_names_model_import_destinationv (ESelectNamesModel *model, return; for (i = 0; destv[i]; i++) { - e_destination_use_card (destv[i], send_changed, model); + eab_destination_use_contact (destv[i], send_changed, model); e_select_names_model_append (model, destv[i]); } g_free (destv); } -ECard * -e_select_names_model_get_card (ESelectNamesModel *model, gint index) +EContact * +e_select_names_model_get_contact (ESelectNamesModel *model, gint index) { - const EDestination *dest; + const EABDestination *dest; g_return_val_if_fail (model && E_IS_SELECT_NAMES_MODEL (model), NULL); g_return_val_if_fail (0 <= index, NULL); g_return_val_if_fail (index < g_list_length (model->priv->data), NULL); dest = e_select_names_model_get_destination (model, index); - return dest ? e_destination_get_card (dest) : NULL; + return dest ? eab_destination_get_contact (dest) : NULL; } const gchar * e_select_names_model_get_string (ESelectNamesModel *model, gint index) { - const EDestination *dest; + const EABDestination *dest; g_return_val_if_fail (model && E_IS_SELECT_NAMES_MODEL (model), NULL); g_return_val_if_fail (0 <= index, NULL); @@ -394,11 +393,11 @@ e_select_names_model_get_string (ESelectNamesModel *model, gint index) dest = e_select_names_model_get_destination (model, index); - return dest ? e_destination_get_textrep (dest, FALSE) : ""; + return dest ? eab_destination_get_textrep (dest, FALSE) : ""; } static void -connect_destination (ESelectNamesModel *model, EDestination *dest) +connect_destination (ESelectNamesModel *model, EABDestination *dest) { g_signal_connect (dest, "changed", @@ -407,21 +406,21 @@ connect_destination (ESelectNamesModel *model, EDestination *dest) } static void -disconnect_destination (ESelectNamesModel *model, EDestination *dest) +disconnect_destination (ESelectNamesModel *model, EABDestination *dest) { g_signal_handlers_disconnect_by_func (dest, destination_changed_proxy, model); } gboolean -e_select_names_model_contains (ESelectNamesModel *model, const EDestination *dest) +e_select_names_model_contains (ESelectNamesModel *model, const EABDestination *dest) { GList *iter; g_return_val_if_fail (E_IS_SELECT_NAMES_MODEL (model), FALSE); - g_return_val_if_fail (E_IS_DESTINATION (dest), FALSE); + g_return_val_if_fail (EAB_IS_DESTINATION (dest), FALSE); for (iter = model->priv->data; iter != NULL; iter = g_list_next (iter)) { - if (iter->data != NULL && e_destination_equal (dest, E_DESTINATION (iter->data))) + if (iter->data != NULL && eab_destination_equal (dest, EAB_DESTINATION (iter->data))) return TRUE; } @@ -429,12 +428,12 @@ e_select_names_model_contains (ESelectNamesModel *model, const EDestination *des } void -e_select_names_model_insert (ESelectNamesModel *model, gint index, EDestination *dest) +e_select_names_model_insert (ESelectNamesModel *model, gint index, EABDestination *dest) { g_return_if_fail (model != NULL); g_return_if_fail (E_IS_SELECT_NAMES_MODEL (model)); g_return_if_fail (0 <= index && index <= g_list_length (model->priv->data)); - g_return_if_fail (dest && E_IS_DESTINATION (dest)); + g_return_if_fail (dest && EAB_IS_DESTINATION (dest)); if (e_select_names_model_at_limit (model)) { /* FIXME: This is bad. */ @@ -452,10 +451,10 @@ e_select_names_model_insert (ESelectNamesModel *model, gint index, EDestination } void -e_select_names_model_append (ESelectNamesModel *model, EDestination *dest) +e_select_names_model_append (ESelectNamesModel *model, EABDestination *dest) { g_return_if_fail (model && E_IS_SELECT_NAMES_MODEL (model)); - g_return_if_fail (dest && E_IS_DESTINATION (dest)); + g_return_if_fail (dest && EAB_IS_DESTINATION (dest)); if (e_select_names_model_at_limit (model)) { /* FIXME: This is bad. */ @@ -473,7 +472,7 @@ e_select_names_model_append (ESelectNamesModel *model, EDestination *dest) } void -e_select_names_model_replace (ESelectNamesModel *model, gint index, EDestination *dest) +e_select_names_model_replace (ESelectNamesModel *model, gint index, EABDestination *dest) { GList *node; const gchar *new_str, *old_str; @@ -482,9 +481,9 @@ e_select_names_model_replace (ESelectNamesModel *model, gint index, EDestination g_return_if_fail (model != NULL); g_return_if_fail (E_IS_SELECT_NAMES_MODEL (model)); g_return_if_fail (model->priv->data == NULL || (0 <= index && index < g_list_length (model->priv->data))); - g_return_if_fail (dest && E_IS_DESTINATION (dest)); + g_return_if_fail (dest && EAB_IS_DESTINATION (dest)); - new_str = e_destination_get_textrep (dest, FALSE); + new_str = eab_destination_get_textrep (dest, FALSE); new_strlen = new_str ? strlen (new_str) : 0; if (model->priv->data == NULL) { @@ -500,10 +499,10 @@ e_select_names_model_replace (ESelectNamesModel *model, gint index, EDestination if (node->data != dest) { - disconnect_destination (model, E_DESTINATION (node->data)); + disconnect_destination (model, EAB_DESTINATION (node->data)); connect_destination (model, dest); - old_str = e_destination_get_textrep (E_DESTINATION (node->data), FALSE); + old_str = eab_destination_get_textrep (EAB_DESTINATION (node->data), FALSE); old_strlen = old_str ? strlen (old_str) : 0; g_object_unref (node->data); @@ -523,14 +522,14 @@ void e_select_names_model_delete (ESelectNamesModel *model, gint index) { GList *node; - EDestination *dest; + EABDestination *dest; g_return_if_fail (model != NULL); g_return_if_fail (E_IS_SELECT_NAMES_MODEL (model)); g_return_if_fail (0 <= index && index < g_list_length (model->priv->data)); node = g_list_nth (model->priv->data, index); - dest = E_DESTINATION (node->data); + dest = EAB_DESTINATION (node->data); disconnect_destination (model, dest); g_object_unref (dest); @@ -552,16 +551,16 @@ e_select_names_model_clean (ESelectNamesModel *model, gboolean clean_last_entry) iter = model->priv->data; while (iter) { - EDestination *dest; + EABDestination *dest; next = g_list_next (iter); if (next == NULL && !clean_last_entry) break; - dest = iter->data ? E_DESTINATION (iter->data) : NULL; + dest = iter->data ? EAB_DESTINATION (iter->data) : NULL; - if (dest == NULL || e_destination_is_empty (dest)) { + if (dest == NULL || eab_destination_is_empty (dest)) { if (dest) { disconnect_destination (model, dest); g_object_unref (dest); @@ -581,7 +580,7 @@ e_select_names_model_clean (ESelectNamesModel *model, gboolean clean_last_entry) static void delete_all_iter (gpointer data, gpointer closure) { - disconnect_destination (E_SELECT_NAMES_MODEL (closure), E_DESTINATION (data)); + disconnect_destination (E_SELECT_NAMES_MODEL (closure), EAB_DESTINATION (data)); g_object_unref (data); } @@ -611,9 +610,9 @@ e_select_names_model_overwrite_copy (ESelectNamesModel *dest, ESelectNamesModel e_select_names_model_delete_all (dest); len = e_select_names_model_count (src); for (i = 0; i < len; ++i) { - const EDestination *d = e_select_names_model_get_destination (src, i); + const EABDestination *d = e_select_names_model_get_destination (src, i); if (d) - e_select_names_model_append (dest, e_destination_copy (d)); + e_select_names_model_append (dest, eab_destination_copy (d)); } } @@ -630,9 +629,9 @@ e_select_names_model_merge (ESelectNamesModel *dest, ESelectNamesModel *src) len = e_select_names_model_count (src); for (i = 0; i < len; ++i) { - const EDestination *d = e_select_names_model_get_destination (src, i); + const EABDestination *d = e_select_names_model_get_destination (src, i); if (d && !e_select_names_model_contains (dest, d)) - e_select_names_model_append (dest, e_destination_copy (d)); + e_select_names_model_append (dest, eab_destination_copy (d)); } } @@ -650,7 +649,7 @@ e_select_names_model_name_pos (ESelectNamesModel *model, gint seplen, gint index iter = model->priv->data; while (iter && i <= index) { rp += len + (i > 0 ? seplen : 0); - str = e_destination_get_textrep (E_DESTINATION (iter->data), FALSE); + str = eab_destination_get_textrep (EAB_DESTINATION (iter->data), FALSE); len = str ? g_utf8_strlen (str, -1) : 0; ++i; iter = g_list_next (iter); @@ -680,7 +679,7 @@ e_select_names_model_text_pos (ESelectNamesModel *model, gint seplen, gint pos, iter = model->priv->data; while (iter != NULL) { - str = e_destination_get_textrep (E_DESTINATION (iter->data), FALSE); + str = eab_destination_get_textrep (EAB_DESTINATION (iter->data), FALSE); len = str ? g_utf8_strlen (str, -1) : 0; if (sp <= pos && pos <= sp + len + adj) { @@ -719,65 +718,7 @@ e_select_names_model_text_pos (ESelectNamesModel *model, gint seplen, gint pos, } void -e_select_names_model_cardify (ESelectNamesModel *model, EBook *book, gint index, gint delay) -{ - EDestination *dest; - - g_return_if_fail (E_IS_SELECT_NAMES_MODEL (model)); - g_return_if_fail (book == NULL || E_IS_BOOK (book)); - g_return_if_fail (0 <= index && index < g_list_length (model->priv->data)); - - dest = E_DESTINATION (g_list_nth_data (model->priv->data, index)); - - if (!e_destination_is_empty (dest)) { - - if (delay > 0) - e_destination_cardify_delayed (dest, book, delay); - else - e_destination_cardify (dest, book); - } -} - -gboolean -e_select_names_model_uncardify (ESelectNamesModel *model, gint index) -{ - EDestination *dest; - gboolean rv = FALSE; - - g_return_val_if_fail (E_IS_SELECT_NAMES_MODEL (model), FALSE); - g_return_val_if_fail (0 <= index && index < g_list_length (model->priv->data), FALSE); - - dest = E_DESTINATION (g_list_nth_data (model->priv->data, index)); - - if (!e_destination_is_empty (dest)) { - EDestination *cpy_dest = e_destination_copy (dest); - - rv = e_destination_uncardify (cpy_dest); - - if (rv) { - e_select_names_model_replace (model, index, cpy_dest); - } - - } - - return rv; -} - -void -e_select_names_model_cancel_cardify (ESelectNamesModel *model, gint index) -{ - EDestination *dest; - - g_return_if_fail (E_IS_SELECT_NAMES_MODEL (model)); - g_return_if_fail (0 <= index && index < g_list_length (model->priv->data)); - - dest = E_DESTINATION (g_list_nth_data (model->priv->data, index)); - - e_destination_cancel_cardify (dest); -} - -void -e_select_names_model_cardify_all (ESelectNamesModel *model, EBook *book, gint delay) +e_select_names_model_load_all_contacts (ESelectNamesModel *model, EBook *book) { GList *iter; @@ -785,27 +726,27 @@ e_select_names_model_cardify_all (ESelectNamesModel *model, EBook *book, gint de g_return_if_fail (book == NULL || E_IS_BOOK (book)); for (iter = model->priv->data; iter != NULL; iter = g_list_next (iter)) { - EDestination *dest = E_DESTINATION (iter->data); - if (!e_destination_is_empty (dest)) { + EABDestination *dest = EAB_DESTINATION (iter->data); + if (!eab_destination_is_empty (dest)) { - if (delay > 0) - e_destination_cardify_delayed (dest, book, delay); - else - e_destination_cardify (dest, book); + eab_destination_load_contact (dest, book); } } } void -e_select_names_model_cancel_cardify_all (ESelectNamesModel *model) +e_select_names_model_cancel_all_contact_load (ESelectNamesModel *model) { GList *iter; g_return_if_fail (E_IS_SELECT_NAMES_MODEL (model)); for (iter = model->priv->data; iter != NULL; iter = g_list_next (iter)) { - EDestination *dest = E_DESTINATION (iter->data); - e_destination_cancel_cardify (dest); + EABDestination *dest = EAB_DESTINATION (iter->data); + if (!eab_destination_is_empty (dest)) { + + eab_destination_cancel_contact_load (dest); + } } } diff --git a/addressbook/gui/component/select-names/e-select-names-model.h b/addressbook/gui/component/select-names/e-select-names-model.h index 8a3c5381b7..41d5100f59 100644 --- a/addressbook/gui/component/select-names/e-select-names-model.h +++ b/addressbook/gui/component/select-names/e-select-names-model.h @@ -15,8 +15,8 @@ #include #include #include -#include -#include +#include +#include #define E_TYPE_SELECT_NAMES_MODEL (e_select_names_model_get_type ()) #define E_SELECT_NAMES_MODEL(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), E_TYPE_SELECT_NAMES_MODEL, ESelectNamesModel)) @@ -54,18 +54,18 @@ gint e_select_names_model_get_limit (ESelectNamesModel void e_select_names_model_set_limit (ESelectNamesModel *model, gint limit); gboolean e_select_names_model_at_limit (ESelectNamesModel *model); -const EDestination *e_select_names_model_get_destination (ESelectNamesModel *model, gint index); -gchar *e_select_names_model_export_destinationv (ESelectNamesModel *model); -void e_select_names_model_import_destinationv (ESelectNamesModel *model, +const EABDestination *e_select_names_model_get_destination (ESelectNamesModel *model, gint index); +gchar *e_select_names_model_export_destinationv (ESelectNamesModel *model); +void e_select_names_model_import_destinationv (ESelectNamesModel *model, gchar *destinationv); -ECard *e_select_names_model_get_card (ESelectNamesModel *model, gint index); +EContact *e_select_names_model_get_contact (ESelectNamesModel *model, gint index); const gchar *e_select_names_model_get_string (ESelectNamesModel *model, gint index); -gboolean e_select_names_model_contains (ESelectNamesModel *model, const EDestination *dest); +gboolean e_select_names_model_contains (ESelectNamesModel *model, const EABDestination *dest); -void e_select_names_model_insert (ESelectNamesModel *model, gint index, EDestination *dest); -void e_select_names_model_append (ESelectNamesModel *model, EDestination *dest); -void e_select_names_model_replace (ESelectNamesModel *model, gint index, EDestination *dest); +void e_select_names_model_insert (ESelectNamesModel *model, gint index, EABDestination *dest); +void e_select_names_model_append (ESelectNamesModel *model, EABDestination *dest); +void e_select_names_model_replace (ESelectNamesModel *model, gint index, EABDestination *dest); void e_select_names_model_delete (ESelectNamesModel *model, gint index); void e_select_names_model_delete_all (ESelectNamesModel *model); void e_select_names_model_overwrite_copy (ESelectNamesModel *dest, ESelectNamesModel *src); @@ -76,11 +76,8 @@ void e_select_names_model_clean (ESelectNamesModel *model, gboolea void e_select_names_model_name_pos (ESelectNamesModel *model, gint seplen, gint index, gint *pos, gint *length); void e_select_names_model_text_pos (ESelectNamesModel *model, gint seplen, gint pos, gint *index, gint *start_pos, gint *length); -void e_select_names_model_cardify (ESelectNamesModel *model, EBook *book, gint index, gint delay); -gboolean e_select_names_model_uncardify (ESelectNamesModel *model, gint index); -void e_select_names_model_cancel_cardify (ESelectNamesModel *model, gint index); -void e_select_names_model_cardify_all (ESelectNamesModel *model, EBook *book, gint delay); -void e_select_names_model_cancel_cardify_all (ESelectNamesModel *model); +void e_select_names_model_load_all_contacts (ESelectNamesModel *model, EBook *book); +void e_select_names_model_cancel_all_contact_load (ESelectNamesModel *model); /* This is a mildly annoying freeze/thaw pair, in that it only applies to the 'changed' signal and not to 'resized'. This could cause unexpected results in some cases. */ diff --git a/addressbook/gui/component/select-names/e-select-names-popup.c b/addressbook/gui/component/select-names/e-select-names-popup.c index d7fabd9426..bb0f331516 100644 --- a/addressbook/gui/component/select-names/e-select-names-popup.c +++ b/addressbook/gui/component/select-names/e-select-names-popup.c @@ -39,10 +39,11 @@ #include #include -#include +#include #include +#include #include -#include "e-addressbook-util.h" +#include "eab-gui-util.h" #include "e-select-names-popup.h" #define LIST_ICON_FILENAME "contact-list-16.png" @@ -51,13 +52,13 @@ typedef struct _PopupInfo PopupInfo; struct _PopupInfo { ESelectNamesTextModel *text_model; - EDestination *dest; + EABDestination *dest; gint pos; gint index; }; static PopupInfo * -popup_info_new (ESelectNamesTextModel *text_model, EDestination *dest, gint pos, gint index) +popup_info_new (ESelectNamesTextModel *text_model, EABDestination *dest, gint pos, gint index) { PopupInfo *info = g_new0 (PopupInfo, 1); info->text_model = text_model; @@ -97,29 +98,29 @@ popup_info_cleanup (GtkWidget *w, gpointer info) /* You are in a maze of twisty little callbacks, all alike... */ +#if TOO_MANY_MENU_ITEMS static void make_contact_editor_cb (EBook *book, gpointer user_data) { if (book) { - EDestination *dest = E_DESTINATION (user_data); - ECard *card; + EABDestination *dest = EAB_DESTINATION (user_data); + EContact *contact; - card = (ECard *) e_destination_get_card (dest); - if (e_card_evolution_list (card)) { + contact = (EContact *) eab_destination_get_contact (dest); + if (e_contact_get (contact, E_CONTACT_IS_LIST)) { EContactListEditor *ce; - ce = e_addressbook_show_contact_list_editor (book, card, FALSE, TRUE); + ce = e_addressbook_show_contact_list_editor (book, contact, FALSE, TRUE); e_contact_list_editor_raise (ce); } else { EContactEditor *ce; - ce = e_addressbook_show_contact_editor (book, card, FALSE, TRUE); + ce = e_addressbook_show_contact_editor (book, contact, FALSE, TRUE); e_contact_editor_raise (ce); } g_object_unref (dest); } } -#if TOO_MANY_MENU_ITEMS static void edit_contact_info_cb (GtkWidget *w, gpointer user_data) { @@ -137,7 +138,7 @@ change_email_num_cb (GtkWidget *w, gpointer user_data) { PopupInfo *info = (PopupInfo *) user_data; gint n; - EDestination *dest; + EABDestination *dest; if (info == NULL) return; @@ -147,9 +148,9 @@ change_email_num_cb (GtkWidget *w, gpointer user_data) n = GPOINTER_TO_INT (g_object_get_data (G_OBJECT (w), "number")); - if (n != e_destination_get_email_num (info->dest)) { - dest = e_destination_new (); - e_destination_set_card (dest, e_destination_get_card (info->dest), n); + if (n != eab_destination_get_email_num (info->dest)) { + dest = eab_destination_new (); + eab_destination_set_contact (dest, eab_destination_get_contact (info->dest), n); e_select_names_model_replace (info->text_model->source, info->index, dest); } } @@ -174,7 +175,7 @@ toggle_html_mail_cb (GtkWidget *w, gpointer user_data) { PopupInfo *info = (PopupInfo *) user_data; GtkCheckMenuItem *item = GTK_CHECK_MENU_ITEM (w); - const EDestination *dest; + const EABDestination *dest; if (info == NULL) return; @@ -182,19 +183,19 @@ toggle_html_mail_cb (GtkWidget *w, gpointer user_data) dest = info->dest; item = GTK_CHECK_MENU_ITEM (item); - e_destination_set_html_mail_pref ((EDestination *) dest, item->active); + eab_destination_set_html_mail_pref ((EABDestination *) dest, item->active); } #endif static void -populate_popup_card (GtkWidget *pop, gboolean list, PopupInfo *info) +populate_popup_contact (GtkWidget *pop, gboolean list, PopupInfo *info) { GtkWidget *image; - ECard *card; - EIterator *iterator; + EContact *contact; GtkWidget *menuitem; + GList *email_list; - card = e_destination_get_card (info->dest); + contact = eab_destination_get_contact (info->dest); #if TOO_MANY_MENU_ITEMS menuitem = gtk_separator_menu_item_new(); @@ -224,7 +225,7 @@ populate_popup_card (GtkWidget *pop, gboolean list, PopupInfo *info) menuitem = gtk_check_menu_item_new_with_label (_("Send HTML Mail?")); gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (menuitem), - e_destination_get_html_mail_pref (info->dest)); + eab_destination_get_html_mail_pref (info->dest)); g_signal_connect (menuitem, "toggled", G_CALLBACK (toggle_html_mail_cb), info); @@ -232,25 +233,27 @@ populate_popup_card (GtkWidget *pop, gboolean list, PopupInfo *info) gtk_menu_shell_prepend (GTK_MENU_SHELL (pop), menuitem); #endif - if (card->email) { + email_list = e_contact_get (contact, E_CONTACT_EMAIL); + + if (email_list) { menuitem = gtk_separator_menu_item_new(); gtk_widget_show (menuitem); gtk_menu_shell_prepend (GTK_MENU_SHELL (pop), menuitem); - if (e_list_length (card->email) > 1) { + if (g_list_length (email_list) > 1) { + GList *l; GSList *radiogroup = NULL; - gint n = e_destination_get_email_num (info->dest); - gint j = e_list_length (card->email) - 1; + gint n = eab_destination_get_email_num (info->dest); + gint j = g_list_length (email_list) - 1; - iterator = e_list_get_iterator (card->email); - for (e_iterator_last (iterator); e_iterator_is_valid (iterator); e_iterator_prev (iterator)) { - char *email = (char *)e_iterator_get (iterator); + for (l = g_list_last (email_list); l; l = l->prev) { + char *email = l->data; char *label = NULL; if (!strncmp (email, "dest)); + menuitem = gtk_menu_item_new_with_label (eab_destination_get_email (info->dest)); gtk_widget_show (menuitem); gtk_menu_shell_prepend (GTK_MENU_SHELL (pop), menuitem); } + + g_list_foreach (email_list, (GFunc)g_free, NULL); + g_list_free (email_list); } menuitem = gtk_separator_menu_item_new (); @@ -297,7 +301,7 @@ populate_popup_card (GtkWidget *pop, gboolean list, PopupInfo *info) ? EVOLUTION_IMAGESDIR "/" LIST_ICON_FILENAME : EVOLUTION_IMAGESDIR "/" CONTACT_ICON_FILENAME); gtk_widget_show (image); - menuitem = gtk_image_menu_item_new_with_label (e_destination_get_name (info->dest)); + menuitem = gtk_image_menu_item_new_with_label (eab_destination_get_name (info->dest)); gtk_image_menu_item_set_image (GTK_IMAGE_MENU_ITEM (menuitem), image); gtk_widget_show (menuitem); @@ -308,11 +312,11 @@ static void quick_add_cb (GtkWidget *w, gpointer user_data) { PopupInfo *info = (PopupInfo *) user_data; - e_contact_quick_add_free_form (e_destination_get_address (info->dest), NULL, NULL); + e_contact_quick_add_free_form (eab_destination_get_address (info->dest), NULL, NULL); } static void -populate_popup_nocard (GtkWidget *pop, PopupInfo *info) +populate_popup_nocontact (GtkWidget *pop, PopupInfo *info) { const gchar *str; GtkWidget *menuitem; @@ -331,7 +335,7 @@ populate_popup_nocard (GtkWidget *pop, PopupInfo *info) #if TOO_MANY_MENU_ITEMS menuitem = gtk_check_menu_item_new_with_label (_("Send HTML Mail?")); gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (menuitem), - e_destination_get_html_mail_pref (info->dest)); + eab_destination_get_html_mail_pref (info->dest)); g_signal_connect (menuitem, "toggled", G_CALLBACK (toggle_html_mail_cb), info); @@ -343,9 +347,9 @@ populate_popup_nocard (GtkWidget *pop, PopupInfo *info) gtk_widget_show (menuitem); gtk_menu_shell_prepend (GTK_MENU_SHELL (pop), menuitem); - str = e_destination_get_name (info->dest); + str = eab_destination_get_name (info->dest); if (! (str && *str)) - str = e_destination_get_email (info->dest); + str = eab_destination_get_email (info->dest); if (! (str && *str)) str = _("Unnamed Contact"); @@ -360,7 +364,7 @@ e_select_names_populate_popup (GtkWidget *menu, ESelectNamesTextModel *text_mode { ESelectNamesModel *model; PopupInfo *info; - EDestination *dest; + EABDestination *dest; gint index; g_return_if_fail (GTK_IS_MENU_SHELL (menu)); @@ -375,16 +379,16 @@ e_select_names_populate_popup (GtkWidget *menu, ESelectNamesTextModel *text_mode return; /* XXX yuck, why does this return a const? */ - dest = (EDestination *)e_select_names_model_get_destination (model, index); - if (e_destination_is_empty (dest)) + dest = (EABDestination *)e_select_names_model_get_destination (model, index); + if (eab_destination_is_empty (dest)) return; info = popup_info_new (text_model, dest, pos, index); - if (e_destination_contains_card (dest)) { - populate_popup_card (menu, e_destination_is_evolution_list (dest), info); + if (eab_destination_get_contact (dest)) { + populate_popup_contact (menu, eab_destination_is_evolution_list (dest), info); } else { - populate_popup_nocard (menu, info); + populate_popup_nocontact (menu, info); } /* Clean up our info item after we've made our selection. */ diff --git a/addressbook/gui/component/select-names/e-select-names-table-model.c b/addressbook/gui/component/select-names/e-select-names-table-model.c index 1c55c3804d..14261e9d80 100644 --- a/addressbook/gui/component/select-names/e-select-names-table-model.c +++ b/addressbook/gui/component/select-names/e-select-names-table-model.c @@ -16,7 +16,7 @@ #include #include "e-select-names-table-model.h" -#include "addressbook/backend/ebook/e-card-simple.h" +#include "addressbook/backend/ebook/e-contact.h" /* Object argument IDs */ enum { @@ -118,21 +118,19 @@ fill_in_info (ESelectNamesTableModel *model) model->data = g_new(ESelectNamesTableModelData, count); for (i = 0; i < count; ++i) { - const EDestination *dest = e_select_names_model_get_destination (model->source, i); - ECard *card = dest ? e_destination_get_card (dest) : NULL; + const EABDestination *dest = e_select_names_model_get_destination (model->source, i); + EContact *contact = dest ? eab_destination_get_contact (dest) : NULL; - if (card) { - ECardSimple *simple = e_card_simple_new(card); - model->data[i].name = e_card_simple_get(simple, E_CARD_SIMPLE_FIELD_NAME_OR_ORG); + if (contact) { + model->data[i].name = e_contact_get(contact, E_CONTACT_FULL_NAME); if (model->data[i].name == 0) model->data[i].name = g_strdup(""); - model->data[i].email = e_card_simple_get(simple, E_CARD_SIMPLE_FIELD_EMAIL); + model->data[i].email = e_contact_get(contact, E_CONTACT_EMAIL_1); if (model->data[i].email == 0) model->data[i].email = g_strdup(""); - g_object_unref(simple); } else { - const gchar *name = e_destination_get_name (dest); - const gchar *email = e_destination_get_email (dest); + const gchar *name = eab_destination_get_name (dest); + const gchar *email = eab_destination_get_email (dest); model->data[i].name = g_strdup (name && *name ? name : email); model->data[i].email = g_strdup (email); diff --git a/addressbook/gui/component/select-names/e-select-names-text-model.c b/addressbook/gui/component/select-names/e-select-names-text-model.c index 7859d5b056..e885de5bf6 100644 --- a/addressbook/gui/component/select-names/e-select-names-text-model.c +++ b/addressbook/gui/component/select-names/e-select-names-text-model.c @@ -19,7 +19,7 @@ #include #include "e-select-names-text-model.h" -#include "e-addressbook-util.h" +#include "eab-gui-util.h" static FILE *out = NULL; /* stream for debugging spew */ @@ -137,7 +137,7 @@ dump_model (ESelectNamesTextModel *text_model) for (i=0; i" : ""); + e_select_names_model_get_contact (model, i) ? "" : ""); fprintf (out, "\n"); } @@ -372,9 +372,9 @@ e_select_names_text_model_insert_length (ETextModel *model, gint pos, const gcha /* Is this a quoted or an unquoted separator we are dealing with? */ if (ut == g_utf8_get_char(text_model->sep) && index >= 0) { - const EDestination *dest = e_select_names_model_get_destination (source, index); + const EABDestination *dest = e_select_names_model_get_destination (source, index); if (dest) { - const gchar *str = e_destination_get_textrep (dest, FALSE); + const gchar *str = eab_destination_get_textrep (dest, FALSE); int j; const char *jp; @@ -400,8 +400,8 @@ e_select_names_text_model_insert_length (ETextModel *model, gint pos, const gcha if (index == -1) { EReposAbsolute repos; - e_select_names_model_insert (source, 0, e_destination_new ()); - e_select_names_model_insert (source, 0, e_destination_new ()); + e_select_names_model_insert (source, 0, eab_destination_new ()); + e_select_names_model_insert (source, 0, eab_destination_new ()); repos.model = model; repos.pos = -1; /* At end */ @@ -420,7 +420,7 @@ e_select_names_text_model_insert_length (ETextModel *model, gint pos, const gcha (e_select_names_model_get_string (source, ins_point) == NULL)) || (ins_point > 0 && (e_select_names_model_get_string (source, ins_point-1) == NULL)))) { - e_select_names_model_insert (source, ins_point, e_destination_new ()); + e_select_names_model_insert (source, ins_point, eab_destination_new ()); repos.model = model; repos.pos = pos; @@ -435,10 +435,10 @@ e_select_names_text_model_insert_length (ETextModel *model, gint pos, const gcha const gchar *str = e_select_names_model_get_string (source, index); gchar *str1 = g_strndup (str, offset); gchar *str2 = g_strdup (str+offset); - EDestination *d1 = e_destination_new (), *d2 = e_destination_new (); + EABDestination *d1 = eab_destination_new (), *d2 = eab_destination_new (); - e_destination_set_raw (d1, str1); - e_destination_set_raw (d2, str2); + eab_destination_set_raw (d1, str1); + eab_destination_set_raw (d2, str2); e_select_names_model_replace (source, index, d1); e_select_names_model_insert (source, index+1, d2); @@ -498,9 +498,9 @@ e_select_names_text_model_insert_length (ETextModel *model, gint pos, const gcha if (new_str->len) { - EDestination *dest; - dest = index >= 0 ? e_destination_copy (e_select_names_model_get_destination (source, index)) : e_destination_new (); - e_destination_set_raw (dest, new_str->str); + EABDestination *dest; + dest = index >= 0 ? eab_destination_copy (e_select_names_model_get_destination (source, index)) : eab_destination_new (); + eab_destination_set_raw (dest, new_str->str); e_select_names_model_replace (source, index, dest); /* e_select_names_model_replace (source, index, dest); */ @@ -589,7 +589,7 @@ e_select_names_text_model_delete (ETextModel *model, gint pos, gint length) if (index+1 < e_select_names_model_count (source)) { EReposDeleteShift repos; - EDestination *new_dest; + EABDestination *new_dest; const gchar *str1 = e_select_names_model_get_string (source, index); const gchar *str2 = e_select_names_model_get_string (source, index+1); gchar *new_str; @@ -613,8 +613,8 @@ e_select_names_text_model_delete (ETextModel *model, gint pos, gint length) e_select_names_model_delete (source, index+1); - new_dest = e_destination_new (); - e_destination_set_raw (new_dest, new_str); + new_dest = eab_destination_new (); + eab_destination_set_raw (new_dest, new_str); e_select_names_model_replace (source, index, new_dest); g_free (new_str); @@ -689,7 +689,7 @@ e_select_names_text_model_delete (ETextModel *model, gint pos, gint length) char *np; int i; EReposDeleteShift repos; - EDestination *dest; + EABDestination *dest; new_str = g_new0 (char, strlen (str) * 6 + 1); /* worse case it can't be any longer than this */ @@ -718,8 +718,8 @@ e_select_names_text_model_delete (ETextModel *model, gint pos, gint length) np = g_utf8_next_char (np); } - dest = index >= 0 ? e_destination_copy (e_select_names_model_get_destination (source, index)) : e_destination_new (); - e_destination_set_raw (dest, new_str); + dest = index >= 0 ? eab_destination_copy (e_select_names_model_get_destination (source, index)) : eab_destination_new (); + eab_destination_set_raw (dest, new_str); e_select_names_model_replace (source, index, dest); if (out) @@ -764,10 +764,10 @@ e_select_names_text_model_obj_count (ETextModel *model) count = i = e_select_names_model_count (source); while (i > 0) { - const EDestination *dest; + const EABDestination *dest; --i; dest = e_select_names_model_get_destination (source, i); - if (e_destination_get_card (dest) == NULL) + if (eab_destination_get_contact (dest) == NULL) --count; } @@ -783,8 +783,8 @@ nth_obj_index (ESelectNamesModel *source, gint n) N = e_select_names_model_count (source); do { - const EDestination *dest = e_select_names_model_get_destination (source, i); - if (e_destination_get_card (dest)) + const EABDestination *dest = e_select_names_model_get_destination (source, i); + if (eab_destination_get_contact (dest)) --n; ++i; } while (n >= 0 && i < N); @@ -820,27 +820,32 @@ e_select_names_text_model_get_nth_obj (ETextModel *model, gint n, gint *len) static void e_select_names_text_model_activate_obj (ETextModel *model, gint n) { +#if notyet + /* XXX the new ebook doesn't have e_contact_get_book, and we + don't really want to add it, so this can't be implemented + this simply anymore */ ESelectNamesModel *source = E_SELECT_NAMES_TEXT_MODEL (model)->source; - ECard *card; + EContact *contact; gint i; i = nth_obj_index (source, n); g_return_if_fail (i >= 0); - card = e_select_names_model_get_card (source, i); - g_return_if_fail (card != NULL); + contact = e_select_names_model_get_contact (source, i); + g_return_if_fail (contact != NULL); /* present read-only contact editor when someone double clicks from here */ - if (e_card_evolution_list (card)) { + if (e_contact_get (contact, E_CONTACT_IS_LIST)) { EContactListEditor *ce; - ce = e_addressbook_show_contact_list_editor (e_card_get_book(card), card, FALSE, FALSE); + ce = e_addressbook_show_contact_list_editor (e_contact_get_book(contact), contact, FALSE, FALSE); e_contact_list_editor_raise (ce); } else { - EContactEditor *ce; - ce = e_addressbook_show_contact_editor (e_card_get_book(card), card, FALSE, FALSE); + EABContactEditor *ce; + ce = e_addressbook_show_contact_editor (e_contact_get_book(contact), contact, FALSE, FALSE); e_contact_editor_raise (ce); } +#endif } diff --git a/addressbook/gui/component/select-names/e-select-names.c b/addressbook/gui/component/select-names/e-select-names.c index f009fbbd63..b50a6d0ca0 100644 --- a/addressbook/gui/component/select-names/e-select-names.c +++ b/addressbook/gui/component/select-names/e-select-names.c @@ -30,9 +30,8 @@ #include #include -#include -#include -#include +#include +#include #include #include #include @@ -40,7 +39,7 @@ #include #include "e-select-names.h" -#include +#include #include "e-select-names-table-model.h" #include #include @@ -113,7 +112,7 @@ GtkWidget *e_addressbook_create_ebook_table(char *name, char *string1, char *str GtkWidget *e_addressbook_create_folder_selector(char *name, char *string1, char *string2, int num1, int num2); static void -search_result (EAddressbookModel *model, EBookViewStatus status, ESelectNames *esn) +search_result (EABModel *model, EBookViewStatus status, ESelectNames *esn) { sync_table_and_models (NULL, esn); } @@ -131,19 +130,15 @@ set_book(EBook *book, EBookStatus status, ESelectNames *esn) } static void -addressbook_model_set_uri(ESelectNames *e_select_names, EAddressbookModel *model, const char *uri) +addressbook_model_set_uri(ESelectNames *e_select_names, EABModel *model, const char *uri) { EBook *book; - char *book_uri; - - book_uri = e_book_expand_uri (uri); /* If uri == the current uri, then we don't have to do anything */ - book = e_addressbook_model_get_ebook (model); + book = eab_model_get_ebook (model); if (book) { const gchar *current_uri = e_book_get_uri (book); - if (current_uri && !strcmp (book_uri, current_uri)) { - g_free (book_uri); + if (current_uri && !strcmp (uri, current_uri)) { return; } } @@ -152,25 +147,28 @@ addressbook_model_set_uri(ESelectNames *e_select_names, EAddressbookModel *model g_object_ref(e_select_names); g_object_ref(model); - addressbook_load_uri(book, book_uri, (EBookCallback) set_book, e_select_names); - - g_free (book_uri); + addressbook_load_uri(book, uri, (EBookCallback) set_book, e_select_names); } static void * -card_key (ECard *card) +contact_key (const EContact *contact) { - EBook *book; + EBook *book = NULL; const gchar *book_uri; - if (card == NULL) + if (contact == NULL) return NULL; - g_assert (E_IS_CARD (card)); + g_assert (E_IS_CONTACT (contact)); - book = e_card_get_book (card); +#if notyet + /* XXX we need a way to reproduce this here somehow.. or at + least make sure we never collide between two contacts in + different books. */ + book = e_contact_get_book (contact); +#endif book_uri = book ? e_book_get_uri (book) : "NoBook"; - return g_strdup_printf ("%s|%s", book_uri ? book_uri : "NoURI", e_card_get_id (card)); + return g_strdup_printf ("%s|%s", book_uri ? book_uri : "NoURI", (char*)e_contact_get_const ((EContact*)contact, E_CONTACT_UID)); } static void @@ -180,14 +178,14 @@ sync_one_model (gpointer k, gpointer val, gpointer closure) ESelectNamesChild *child = val; ESelectNamesModel *model = child->source; gint i, count; - ECard *card; + EContact *contact; void *key; count = e_select_names_model_count (model); for (i = 0; i < count; ++i) { - card = e_select_names_model_get_card (model, i); - if (card) { - key = card_key (card); + contact = e_select_names_model_get_contact (model, i); + if (contact) { + key = contact_key (contact); e_table_without_hide (etw, key); g_free (key); } @@ -206,21 +204,19 @@ real_add_address_cb (int model_row, gpointer closure) { ESelectNamesChild *child = closure; ESelectNames *names = child->names; - ECard *card; - EDestination *dest = e_destination_new (); + const EContact *contact; + EABDestination *dest = eab_destination_new (); gint mapped_row; mapped_row = e_table_subset_view_to_model_row (E_TABLE_SUBSET (names->without), model_row); - card = e_addressbook_model_get_card (E_ADDRESSBOOK_MODEL(names->model), mapped_row); + contact = eab_model_contact_at (EAB_MODEL(names->model), mapped_row); - if (card != NULL) { - e_destination_set_card (dest, card, 0); + if (contact != NULL) { + eab_destination_set_contact (dest, (EContact*)contact, 0); e_select_names_model_append (child->source, dest); e_select_names_model_clean (child->source, FALSE); - - g_object_unref(card); } } @@ -266,10 +262,9 @@ selection_change (ETable *table, ESelectNames *names) static void * esn_get_key_fn (ETableModel *source, int row, void *closure) { - EAddressbookModel *model = E_ADDRESSBOOK_MODEL (closure); - ECard *card = e_addressbook_model_get_card (model, row); - void *key = card_key (card); - g_object_unref (card); + EABModel *model = EAB_MODEL (closure); + const EContact *contact = eab_model_contact_at (model, row); + void *key = contact_key (contact); return key; } @@ -297,11 +292,11 @@ e_addressbook_create_ebook_table(char *name, char *string1, char *string2, int n { ETableModel *adapter; ETableModel *without; - EAddressbookModel *model; + EABModel *model; GtkWidget *table; - model = e_addressbook_model_new (); - adapter = E_TABLE_MODEL (e_addressbook_table_adapter_new (model)); + model = eab_model_new (); + adapter = E_TABLE_MODEL (eab_table_adapter_new (model)); g_object_set(model, "editable", FALSE, @@ -340,7 +335,7 @@ folder_selected (EvolutionFolderSelectorButton *button, GNOME_Evolution_Folder * { addressbook_model_set_uri(e_select_names, e_select_names->model, folder->physicalUri); - e_config_listener_set_string (e_book_get_config_database(), + e_config_listener_set_string (eab_get_config_database(), "/apps/evolution/addressbook/select_names/last_used_uri", folder->physicalUri); } @@ -392,7 +387,7 @@ update_query (GtkWidget *widget, ESelectNames *e_select_names) } static void -status_message (EAddressbookModel *model, const gchar *message, ESelectNames *e_select_names) +status_message (EABModel *model, const gchar *message, ESelectNames *e_select_names) { if (message == NULL) gtk_label_set_text (GTK_LABEL (e_select_names->status_message), ""); @@ -424,7 +419,7 @@ select_entry_changed (GtkWidget *widget, ESelectNames *e_select_names) int model_row = e_table_view_to_model_row (table, i); char *row_strcoll_string = g_utf8_collate_key (e_table_model_value_at (e_select_names->without, - E_CARD_SIMPLE_FIELD_NAME_OR_ORG, + E_CONTACT_FULL_NAME, model_row), -1); if (g_utf8_collate (select_strcoll_string, row_strcoll_string) <= 0) { @@ -637,12 +632,14 @@ e_select_names_new (EvolutionShellClient *shell_client) e_select_names = g_object_new (E_TYPE_SELECT_NAMES, NULL); - db = e_book_get_config_database (); + db = eab_get_config_database (); contacts_uri = e_config_listener_get_string_with_default ( db, "/apps/evolution/addressbook/select_names/last_used_uri", NULL, NULL); +#if notyet if (!contacts_uri) contacts_uri = g_strdup (e_book_get_default_book_uri ()); +#endif button = glade_xml_get_widget (e_select_names->gui, "folder-selector"); evolution_folder_selector_button_construct (EVOLUTION_FOLDER_SELECTOR_BUTTON (button), diff --git a/addressbook/gui/component/select-names/e-select-names.h b/addressbook/gui/component/select-names/e-select-names.h index 8e672da92a..e67f64b70b 100644 --- a/addressbook/gui/component/select-names/e-select-names.h +++ b/addressbook/gui/component/select-names/e-select-names.h @@ -67,7 +67,7 @@ struct _ESelectNames ETableScrolled *table; ETableModel *adapter; ETableModel *without; - EAddressbookModel *model; + EABModel *model; GtkWidget *categories; GtkWidget *select_entry; GtkWidget *status_message; diff --git a/addressbook/gui/component/select-names/e-simple-card-bonobo.c b/addressbook/gui/component/select-names/e-simple-card-bonobo.c deleted file mode 100644 index 07203618b3..0000000000 --- a/addressbook/gui/component/select-names/e-simple-card-bonobo.c +++ /dev/null @@ -1,216 +0,0 @@ -/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */ -/* e-simple-card-bonobo.c - * - * Copyright (C) 2000 Ximian, Inc. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of version 2 of the GNU General Public - * License as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public - * License along with this program; if not, write to the - * Free Software Foundation, Inc., 59 Temple Place - Suite 330, - * Boston, MA 02111-1307, USA. - * - * Authors: - * Ettore Perazzoli - * Chris Lahey - */ - -#ifdef HAVE_CONFIG_H -#include -#endif - -#include "e-simple-card-bonobo.h" - -#include - -#include "Evolution-Addressbook-SelectNames.h" - - -#define PARENT_TYPE BONOBO_TYPE_OBJECT -static BonoboObjectClass *parent_class = NULL; - -struct _ESimpleCardBonoboPrivate { - ECardSimple *card_simple; -}; - - - -static GNOME_Evolution_Addressbook_SimpleCard_Arbitrary * -impl_SimpleCard_get_arbitrary (PortableServer_Servant servant, - const CORBA_char *key, - CORBA_Environment *ev) -{ - ESimpleCardBonobo *simple_card; - ESimpleCardBonoboPrivate *priv; - GNOME_Evolution_Addressbook_SimpleCard_Arbitrary *ret_val = GNOME_Evolution_Addressbook_SimpleCard_Arbitrary__alloc (); - - simple_card = E_SIMPLE_CARD_BONOBO (bonobo_object (servant)); - priv = simple_card->priv; - - if (priv->card_simple) { - const ECardArbitrary *arbitrary = e_card_simple_get_arbitrary (priv->card_simple, key); - ret_val->key = CORBA_string_dup (arbitrary->key); - ret_val->value = CORBA_string_dup (arbitrary->value); - ret_val->type = CORBA_string_dup (arbitrary->type); - } else { - ret_val->key = CORBA_string_dup (""); - ret_val->value = CORBA_string_dup (""); - ret_val->type = CORBA_string_dup (""); - } - - return ret_val; -} - -static void -impl_SimpleCard_set_arbitrary (PortableServer_Servant servant, - const CORBA_char *key, - const CORBA_char *type, - const CORBA_char *value, - CORBA_Environment *ev) -{ - ESimpleCardBonobo *simple_card; - ESimpleCardBonoboPrivate *priv; - - simple_card = E_SIMPLE_CARD_BONOBO (bonobo_object (servant)); - priv = simple_card->priv; - - if (priv->card_simple) { - e_card_simple_set_arbitrary (priv->card_simple, key, type, value); - } -} - -static CORBA_char * -impl_SimpleCard_get (PortableServer_Servant servant, - GNOME_Evolution_Addressbook_SimpleCard_Field field, - CORBA_Environment *ev) -{ - ESimpleCardBonobo *simple_card; - ESimpleCardBonoboPrivate *priv; - - simple_card = E_SIMPLE_CARD_BONOBO (bonobo_object (servant)); - priv = simple_card->priv; - - if (priv->card_simple) { - char *value = e_card_simple_get (priv->card_simple, - field); - char *ret_val = CORBA_string_dup (value ? value : ""); - g_free (value); - return ret_val; - } else { - return CORBA_string_dup (""); - } -} - -static void -impl_SimpleCard_set (PortableServer_Servant servant, - GNOME_Evolution_Addressbook_SimpleCard_Field field, - const CORBA_char *value, - CORBA_Environment *ev) -{ - - ESimpleCardBonobo *simple_card; - ESimpleCardBonoboPrivate *priv; - - simple_card = E_SIMPLE_CARD_BONOBO (bonobo_object (servant)); - priv = simple_card->priv; - - if (priv->card_simple) { - e_card_simple_set (priv->card_simple, - field, - value); - } -} - - -/* GtkObject methods. */ - -static void -impl_dispose (GObject *object) -{ - ESimpleCardBonobo *simple_card; - ESimpleCardBonoboPrivate *priv; - - simple_card = E_SIMPLE_CARD_BONOBO (object); - priv = simple_card->priv; - - if (priv) { - if (priv->card_simple) { - g_object_unref (priv->card_simple); - } - - g_free (priv); - simple_card->priv = NULL; - } - - if (G_OBJECT_CLASS(parent_class)->dispose) - G_OBJECT_CLASS(parent_class)->dispose(object); -} - - -static void -e_simple_card_bonobo_class_init (ESimpleCardBonoboClass *klass) -{ - GObjectClass *object_class; - POA_GNOME_Evolution_Addressbook_SimpleCard__epv *epv; - - object_class = G_OBJECT_CLASS (klass); - parent_class = g_type_class_ref (BONOBO_TYPE_OBJECT); - - object_class->dispose = impl_dispose; - - epv = &klass->epv; - epv->getArbitrary = impl_SimpleCard_get_arbitrary; - epv->setArbitrary = impl_SimpleCard_set_arbitrary; - epv->get = impl_SimpleCard_get; - epv->set = impl_SimpleCard_set; -} - -static void -e_simple_card_bonobo_init (ESimpleCardBonobo *simple_card) -{ - ESimpleCardBonoboPrivate *priv; - - priv = g_new (ESimpleCardBonoboPrivate, 1); - - priv->card_simple = NULL; - - simple_card->priv = priv; -} - - -void -e_simple_card_bonobo_construct (ESimpleCardBonobo *simple_card, - ECardSimple *card_simple) -{ - g_return_if_fail (simple_card != NULL); - g_return_if_fail (E_IS_SIMPLE_CARD_BONOBO (simple_card)); - - simple_card->priv->card_simple = card_simple; - g_object_ref (card_simple); -} - -ESimpleCardBonobo * -e_simple_card_bonobo_new (ECardSimple *card_simple) -{ - ESimpleCardBonobo *simple_card; - - simple_card = g_object_new (E_TYPE_SIMPLE_CARD_BONOBO, NULL); - - e_simple_card_bonobo_construct (simple_card, card_simple); - - return simple_card; -} - - -BONOBO_TYPE_FUNC_FULL ( - ESimpleCardBonobo, - GNOME_Evolution_Addressbook_SimpleCard, - PARENT_TYPE, - e_simple_card_bonobo); diff --git a/addressbook/gui/component/select-names/e-simple-card-bonobo.h b/addressbook/gui/component/select-names/e-simple-card-bonobo.h deleted file mode 100644 index 7bc2d65830..0000000000 --- a/addressbook/gui/component/select-names/e-simple-card-bonobo.h +++ /dev/null @@ -1,71 +0,0 @@ -/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */ -/* e-simple-card-bonobo.h - * - * Copyright (C) 2000 Ximian, Inc. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of version 2 of the GNU General Public - * License as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public - * License along with this program; if not, write to the - * Free Software Foundation, Inc., 59 Temple Place - Suite 330, - * Boston, MA 02111-1307, USA. - * - * Authors: - * Ettore Perazzoli - * Chris Lahey - */ - -#ifndef __E_SIMPLE_CARD_BONOBO_H__ -#define __E_SIMPLE_CARD_BONOBO_H__ - -#include - -#include "Evolution-Addressbook-SelectNames.h" -#include - -#ifdef __cplusplus -extern "C" { -#pragma } -#endif /* __cplusplus */ - -#define E_TYPE_SIMPLE_CARD_BONOBO (e_simple_card_bonobo_get_type ()) -#define E_SIMPLE_CARD_BONOBO(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), E_TYPE_SIMPLE_CARD_BONOBO, ESimpleCardBonobo)) -#define E_SIMPLE_CARD_BONOBO_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), E_TYPE_SIMPLE_CARD_BONOBO, ESimpleCardBonoboClass)) -#define E_IS_SIMPLE_CARD_BONOBO(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), E_TYPE_SIMPLE_CARD_BONOBO)) -#define E_IS_SIMPLE_CARD_BONOBO_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), E_TYPE_SIMPLE_CARD_BONOBO)) - - -typedef struct _ESimpleCardBonobo ESimpleCardBonobo; -typedef struct _ESimpleCardBonoboPrivate ESimpleCardBonoboPrivate; -typedef struct _ESimpleCardBonoboClass ESimpleCardBonoboClass; - -struct _ESimpleCardBonobo { - BonoboObject parent; - - ESimpleCardBonoboPrivate *priv; -}; - -struct _ESimpleCardBonoboClass { - BonoboObjectClass parent_class; - - POA_GNOME_Evolution_Addressbook_SimpleCard__epv epv; -}; - - -GType e_simple_card_bonobo_get_type (void); -ESimpleCardBonobo *e_simple_card_bonobo_new (ECardSimple *card_simple); -void e_simple_card_bonobo_construct (ESimpleCardBonobo *simple_card, - ECardSimple *card_simple); - -#ifdef __cplusplus -} -#endif /* __cplusplus */ - -#endif /* __E_SIMPLE_CARD_BONOBO_H__ */ diff --git a/addressbook/gui/contact-editor/Makefile.am b/addressbook/gui/contact-editor/Makefile.am index fc3a0a71d0..ae9f99cd35 100644 --- a/addressbook/gui/contact-editor/Makefile.am +++ b/addressbook/gui/contact-editor/Makefile.am @@ -29,8 +29,6 @@ libecontacteditor_la_SOURCES = \ e-contact-editor-marshal.c \ e-contact-editor.c \ e-contact-editor.h \ - e-contact-save-as.c \ - e-contact-save-as.h \ e-contact-quick-add.c \ e-contact-quick-add.h diff --git a/addressbook/gui/contact-editor/contact-editor.glade b/addressbook/gui/contact-editor/contact-editor.glade index 2ef6954d10..10b05c27b4 100644 --- a/addressbook/gui/contact-editor/contact-editor.glade +++ b/addressbook/gui/contact-editor/contact-editor.glade @@ -1478,6 +1478,49 @@ fill + + + + True + Blog address: + True + False + GTK_JUSTIFY_CENTER + False + False + 1 + 0.5 + 0 + 0 + entry-web + + + 1 + 3 + 9 + 10 + fill + + + + + + + True + e_contact_editor_create_web + 0 + 0 + Sat, 08 Feb 2003 09:14:46 GMT + + + 3 + 4 + 9 + 10 + fill + fill + + False diff --git a/addressbook/gui/contact-editor/e-contact-editor-address.c b/addressbook/gui/contact-editor/e-contact-editor-address.c index da8bb5421f..34977e3fb7 100644 --- a/addressbook/gui/contact-editor/e-contact-editor-address.c +++ b/addressbook/gui/contact-editor/e-contact-editor-address.c @@ -420,7 +420,9 @@ e_contact_editor_address_init (EContactEditorAddress *e_contact_editor_address) gtk_window_set_resizable(GTK_WINDOW(e_contact_editor_address), TRUE); +#if notyet e_contact_editor_address->address = NULL; +#endif gui = glade_xml_new (EVOLUTION_GLADEDIR "/fulladdr.glade", NULL, NULL); e_contact_editor_address->gui = gui; @@ -453,22 +455,26 @@ e_contact_editor_address_dispose (GObject *object) e_contact_editor_address->gui = NULL; } +#if notyet if (e_contact_editor_address->address) { e_card_delivery_address_unref(e_contact_editor_address->address); e_contact_editor_address->address = NULL; } +#endif if (G_OBJECT_CLASS (parent_class)->dispose) (* G_OBJECT_CLASS (parent_class)->dispose) (object); } GtkWidget* -e_contact_editor_address_new (const ECardDeliveryAddress *address) +e_contact_editor_address_new (/* XXX notyet const ECardDeliveryAddress *address*/) { GtkWidget *widget = g_object_new (E_TYPE_CONTACT_EDITOR_ADDRESS, NULL); +#if notyet g_object_set (widget, "address", address, NULL); +#endif return widget; } @@ -482,9 +488,11 @@ e_contact_editor_address_set_property (GObject *object, guint prop_id, switch (prop_id){ case PROP_ADDRESS: +#if notyet e_card_delivery_address_unref(e_contact_editor_address->address); e_contact_editor_address->address = e_card_delivery_address_copy(g_value_get_pointer (value)); fill_in_info(e_contact_editor_address); +#endif break; case PROP_EDITABLE: { int i; @@ -540,7 +548,9 @@ e_contact_editor_address_get_property (GObject *object, guint prop_id, switch (prop_id) { case PROP_ADDRESS: extract_info(e_contact_editor_address); +#if notyet g_value_set_pointer (value, e_card_delivery_address_ref(e_contact_editor_address->address)); +#endif break; case PROP_EDITABLE: g_value_set_boolean (value, e_contact_editor_address->editable ? TRUE : FALSE); @@ -566,6 +576,7 @@ fill_in_field(EContactEditorAddress *editor, char *field, char *string) static void fill_in_info(EContactEditorAddress *editor) { +#if notyet ECardDeliveryAddress *address = editor->address; if (address) { fill_in_field(editor, "entry-street" , address->street ); @@ -576,6 +587,7 @@ fill_in_info(EContactEditorAddress *editor) fill_in_field(editor, "entry-code" , address->code ); fill_in_field(editor, "entry-country", address->country); } +#endif } static char * @@ -591,6 +603,7 @@ extract_field(EContactEditorAddress *editor, char *field) static void extract_info(EContactEditorAddress *editor) { +#if notyet ECardDeliveryAddress *address = editor->address; if (!address) { address = e_card_delivery_address_new(); @@ -603,4 +616,5 @@ extract_info(EContactEditorAddress *editor) address->region = extract_field(editor, "entry-region" ); address->code = extract_field(editor, "entry-code" ); address->country = extract_field(editor, "entry-country"); +#endif } diff --git a/addressbook/gui/contact-editor/e-contact-editor-address.h b/addressbook/gui/contact-editor/e-contact-editor-address.h index 7faab47a4f..c20f020152 100644 --- a/addressbook/gui/contact-editor/e-contact-editor-address.h +++ b/addressbook/gui/contact-editor/e-contact-editor-address.h @@ -22,7 +22,7 @@ #include #include -#include +#include G_BEGIN_DECLS @@ -49,8 +49,10 @@ struct _EContactEditorAddress { GtkDialog parent; +#if notyet /* item specific fields */ ECardDeliveryAddress *address; +#endif guint editable : 1; @@ -63,7 +65,7 @@ struct _EContactEditorAddressClass }; -GtkWidget *e_contact_editor_address_new(const ECardDeliveryAddress *name); +GtkWidget *e_contact_editor_address_new(/* XXX not yet const ECardDeliveryAddress *name*/); GType e_contact_editor_address_get_type (void); G_END_DECLS diff --git a/addressbook/gui/contact-editor/e-contact-editor-fullname.c b/addressbook/gui/contact-editor/e-contact-editor-fullname.c index 4a7d6cec1b..c37f4cc8b7 100644 --- a/addressbook/gui/contact-editor/e-contact-editor-fullname.c +++ b/addressbook/gui/contact-editor/e-contact-editor-fullname.c @@ -1,8 +1,8 @@ /* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ /* - * e-contact-editor-fullname.c - * Copyright (C) 2000 Ximian, Inc. - * Author: Chris Lahey + * eab-contact-editor-phones.c + * Copyright (C) 2003 Ximian, Inc. + * Author: Chris Toshok * * This library is free software; you can redistribute it and/or * modify it under the terms of version 2 of the GNU General Public @@ -142,7 +142,7 @@ e_contact_editor_fullname_dispose (GObject *object) } if (e_contact_editor_fullname->name) { - e_card_name_unref(e_contact_editor_fullname->name); + e_contact_name_free(e_contact_editor_fullname->name); e_contact_editor_fullname->name = NULL; } @@ -151,12 +151,12 @@ e_contact_editor_fullname_dispose (GObject *object) } GtkWidget* -e_contact_editor_fullname_new (const ECardName *name) +e_contact_editor_fullname_new (const EContactName *name) { GtkWidget *widget = g_object_new (E_TYPE_CONTACT_EDITOR_FULLNAME, NULL); g_object_set (widget, - "name", name, - NULL); + "name", name, + NULL); return widget; } @@ -170,8 +170,8 @@ e_contact_editor_fullname_set_property (GObject *object, guint prop_id, switch (prop_id){ case PROP_NAME: - e_card_name_unref(e_contact_editor_fullname->name); - e_contact_editor_fullname->name = e_card_name_copy(g_value_get_pointer (value)); + e_contact_name_free(e_contact_editor_fullname->name); + e_contact_editor_fullname->name = e_contact_name_copy(g_value_get_pointer (value)); fill_in_info(e_contact_editor_fullname); break; case PROP_EDITABLE: { @@ -224,7 +224,7 @@ e_contact_editor_fullname_get_property (GObject *object, guint prop_id, switch (prop_id) { case PROP_NAME: extract_info(e_contact_editor_fullname); - g_value_set_pointer (value, e_card_name_ref(e_contact_editor_fullname->name)); + g_value_set_pointer (value, e_contact_name_copy(e_contact_editor_fullname->name)); break; case PROP_EDITABLE: g_value_set_boolean (value, e_contact_editor_fullname->editable ? TRUE : FALSE); @@ -250,13 +250,13 @@ fill_in_field(EContactEditorFullname *editor, char *field, char *string) static void fill_in_info(EContactEditorFullname *editor) { - ECardName *name = editor->name; + EContactName *name = editor->name; if (name) { - fill_in_field(editor, "entry-title", name->prefix); + fill_in_field(editor, "entry-title", name->prefixes); fill_in_field(editor, "entry-first", name->given); fill_in_field(editor, "entry-middle", name->additional); fill_in_field(editor, "entry-last", name->family); - fill_in_field(editor, "entry-suffix", name->suffix); + fill_in_field(editor, "entry-suffix", name->suffixes); } } @@ -273,15 +273,15 @@ extract_field(EContactEditorFullname *editor, char *field) static void extract_info(EContactEditorFullname *editor) { - ECardName *name = editor->name; + EContactName *name = editor->name; if (!name) { - name = e_card_name_new(); + name = e_contact_name_new(); editor->name = name; } - name->prefix = extract_field(editor, "entry-title" ); + name->prefixes = extract_field(editor, "entry-title" ); name->given = extract_field(editor, "entry-first" ); name->additional = extract_field(editor, "entry-middle"); name->family = extract_field(editor, "entry-last" ); - name->suffix = extract_field(editor, "entry-suffix"); + name->suffixes = extract_field(editor, "entry-suffix"); } diff --git a/addressbook/gui/contact-editor/e-contact-editor-fullname.h b/addressbook/gui/contact-editor/e-contact-editor-fullname.h index 3c8e055a96..408fcffdc3 100644 --- a/addressbook/gui/contact-editor/e-contact-editor-fullname.h +++ b/addressbook/gui/contact-editor/e-contact-editor-fullname.h @@ -22,7 +22,7 @@ #include #include -#include +#include G_BEGIN_DECLS @@ -50,7 +50,7 @@ struct _EContactEditorFullname GtkDialog parent; /* item specific fields */ - ECardName *name; + EContactName *name; GladeXML *gui; /* Whether the dialog will accept modifications */ @@ -63,7 +63,7 @@ struct _EContactEditorFullnameClass }; -GtkWidget *e_contact_editor_fullname_new(const ECardName *name); +GtkWidget *e_contact_editor_fullname_new(const EContactName *name); GType e_contact_editor_fullname_get_type (void); G_END_DECLS diff --git a/addressbook/gui/contact-editor/e-contact-editor.c b/addressbook/gui/contact-editor/e-contact-editor.c index 2330daf063..1391ccf1b0 100644 --- a/addressbook/gui/contact-editor/e-contact-editor.c +++ b/addressbook/gui/contact-editor/e-contact-editor.c @@ -49,29 +49,28 @@ #include "addressbook/printing/e-contact-print.h" #include "addressbook/printing/e-contact-print-envelope.h" -#include "addressbook/gui/widgets/e-addressbook-util.h" +#include "addressbook/gui/widgets/eab-gui-util.h" #include "e-util/e-gui-utils.h" #include "widgets/misc/e-dateedit.h" #include "widgets/misc/e-url-entry.h" #include "shell/evolution-shell-component-utils.h" -#include "e-card-merging.h" +#include "eab-contact-merging.h" #include "e-contact-editor-address.h" #include "e-contact-editor-fullname.h" #include "e-contact-editor-marshal.h" -#include "e-contact-save-as.h" /* Signal IDs */ enum { - CARD_ADDED, - CARD_MODIFIED, - CARD_DELETED, + CONTACT_ADDED, + CONTACT_MODIFIED, + CONTACT_DELETED, EDITOR_CLOSED, LAST_SIGNAL }; -static void e_contact_editor_init (EContactEditor *card); +static void e_contact_editor_init (EContactEditor *editor); static void e_contact_editor_class_init (EContactEditorClass *klass); static void e_contact_editor_set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec); static void e_contact_editor_get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec); @@ -85,9 +84,10 @@ static void enable_writable_fields(EContactEditor *editor); static void set_editable(EContactEditor *editor); static void fill_in_info(EContactEditor *editor); static void extract_info(EContactEditor *editor); -static void set_fields(EContactEditor *editor); +static void set_field(EContactEditor *editor, GtkEntry *entry, const char *string); static void set_address_field(EContactEditor *editor, int result); -static void add_field_callback(GtkWidget *widget, EContactEditor *editor); +static void set_phone_field(EContactEditor *editor, GtkWidget *entry, const char *phone_number); +static void set_fields(EContactEditor *editor); static void command_state_changed (EContactEditor *ce); static void widget_changed (GtkWidget *widget, EContactEditor *editor); static void close_dialog (EContactEditor *ce); @@ -101,8 +101,8 @@ static guint contact_editor_signals[LAST_SIGNAL]; enum { PROP_0, PROP_BOOK, - PROP_CARD, - PROP_IS_NEW_CARD, + PROP_CONTACT, + PROP_IS_NEW_CONTACT, PROP_EDITABLE, PROP_CHANGED, PROP_WRITABLE_FIELDS @@ -114,6 +114,34 @@ enum { DYNAMIC_LIST_ADDRESS }; +static EContactField phones[] = { + E_CONTACT_PHONE_ASSISTANT, + E_CONTACT_PHONE_BUSINESS, + E_CONTACT_PHONE_BUSINESS_2, + E_CONTACT_PHONE_BUSINESS_FAX, + E_CONTACT_PHONE_CALLBACK, + E_CONTACT_PHONE_CAR, + E_CONTACT_PHONE_COMPANY, + E_CONTACT_PHONE_HOME, + E_CONTACT_PHONE_HOME_2, + E_CONTACT_PHONE_HOME_FAX, + E_CONTACT_PHONE_ISDN, + E_CONTACT_PHONE_MOBILE, + E_CONTACT_PHONE_OTHER, + E_CONTACT_PHONE_OTHER_FAX, + E_CONTACT_PHONE_PAGER, + E_CONTACT_PHONE_PRIMARY, + E_CONTACT_PHONE_RADIO, + E_CONTACT_PHONE_TELEX, + E_CONTACT_PHONE_TTYTDD, +}; + +static EContactField emails[] = { + E_CONTACT_EMAIL_1, + E_CONTACT_EMAIL_2, + E_CONTACT_EMAIL_3 +}; + static GSList *all_contact_editors = NULL; GType @@ -158,16 +186,16 @@ e_contact_editor_class_init (EContactEditorClass *klass) E_TYPE_BOOK, G_PARAM_READWRITE)); - g_object_class_install_property (object_class, PROP_CARD, - g_param_spec_object ("card", - _("Card"), + g_object_class_install_property (object_class, PROP_CONTACT, + g_param_spec_object ("contact", + _("Contact"), /*_( */"XXX blurb" /*)*/, - E_TYPE_CARD, + E_TYPE_CONTACT, G_PARAM_READWRITE)); - g_object_class_install_property (object_class, PROP_IS_NEW_CARD, - g_param_spec_boolean ("is_new_card", - _("Is New Card"), + g_object_class_install_property (object_class, PROP_IS_NEW_CONTACT, + g_param_spec_boolean ("is_new_contact", + _("Is New Contact"), /*_( */"XXX blurb" /*)*/, FALSE, G_PARAM_READWRITE)); @@ -193,31 +221,31 @@ e_contact_editor_class_init (EContactEditorClass *klass) FALSE, G_PARAM_READWRITE)); - contact_editor_signals[CARD_ADDED] = - g_signal_new ("card_added", + contact_editor_signals[CONTACT_ADDED] = + g_signal_new ("contact_added", G_OBJECT_CLASS_TYPE (object_class), G_SIGNAL_RUN_FIRST, - G_STRUCT_OFFSET (EContactEditorClass, card_added), + G_STRUCT_OFFSET (EContactEditorClass, contact_added), NULL, NULL, e_contact_editor_marshal_NONE__INT_OBJECT, G_TYPE_NONE, 2, G_TYPE_INT, G_TYPE_OBJECT); - contact_editor_signals[CARD_MODIFIED] = - g_signal_new ("card_modified", + contact_editor_signals[CONTACT_MODIFIED] = + g_signal_new ("contact_modified", G_OBJECT_CLASS_TYPE (object_class), G_SIGNAL_RUN_FIRST, - G_STRUCT_OFFSET (EContactEditorClass, card_modified), + G_STRUCT_OFFSET (EContactEditorClass, contact_modified), NULL, NULL, e_contact_editor_marshal_NONE__INT_OBJECT, G_TYPE_NONE, 2, G_TYPE_INT, G_TYPE_OBJECT); - contact_editor_signals[CARD_DELETED] = - g_signal_new ("card_deleted", + contact_editor_signals[CONTACT_DELETED] = + g_signal_new ("contact_deleted", G_OBJECT_CLASS_TYPE (object_class), G_SIGNAL_RUN_FIRST, - G_STRUCT_OFFSET (EContactEditorClass, card_deleted), + G_STRUCT_OFFSET (EContactEditorClass, contact_deleted), NULL, NULL, e_contact_editor_marshal_NONE__INT_OBJECT, G_TYPE_NONE, 2, @@ -259,11 +287,10 @@ wants_html_changed (GtkWidget *widget, EContactEditor *editor) { gboolean wants_html; g_object_get (widget, - "active", &wants_html, - NULL); - g_object_set (editor->card, - "wants_html", wants_html, - NULL); + "active", &wants_html, + NULL); + + e_contact_set (editor->contact, E_CONTACT_WANTS_HTML, GINT_TO_POINTER (wants_html)); widget_changed (widget, editor); } @@ -273,23 +300,20 @@ phone_entry_changed (GtkWidget *widget, EContactEditor *editor) { int which; GtkEntry *entry = GTK_ENTRY(widget); - ECardPhone *phone; - if ( widget == glade_xml_get_widget(editor->gui, "entry-phone1") ) { + if ( widget == glade_xml_get_widget(editor->gui, "entry-phone1") ) which = 1; - } else if ( widget == glade_xml_get_widget(editor->gui, "entry-phone2") ) { + else if ( widget == glade_xml_get_widget(editor->gui, "entry-phone2") ) which = 2; - } else if ( widget == glade_xml_get_widget(editor->gui, "entry-phone3") ) { + else if ( widget == glade_xml_get_widget(editor->gui, "entry-phone3") ) which = 3; - } else if ( widget == glade_xml_get_widget(editor->gui, "entry-phone4") ) { + else if ( widget == glade_xml_get_widget(editor->gui, "entry-phone4") ) which = 4; - } else + else return; - phone = e_card_phone_new(); - phone->number = g_strdup (gtk_entry_get_text(entry)); - e_card_simple_set_phone(editor->simple, editor->phone_choice[which - 1], phone); - e_card_phone_unref(phone); - set_fields(editor); + + printf ("gtk_entry_get_text(entry) == %s\n", (char*)gtk_entry_get_text(entry)); + e_contact_set(editor->contact, editor->phone_choice[which - 1], (char*)gtk_entry_get_text(entry)); widget_changed (widget, editor); } @@ -297,12 +321,9 @@ phone_entry_changed (GtkWidget *widget, EContactEditor *editor) static void email_entry_changed (GtkWidget *widget, EContactEditor *editor) { - const gchar *string; GtkEntry *entry = GTK_ENTRY(widget); - string = gtk_entry_get_text(entry); - - e_card_simple_set_email(editor->simple, editor->email_choice, string); + e_contact_set (editor->contact, editor->email_choice, (char*)gtk_entry_get_text(entry)); widget_changed (widget, editor); } @@ -310,6 +331,7 @@ email_entry_changed (GtkWidget *widget, EContactEditor *editor) static void address_text_changed (GtkTextBuffer *buffer, EContactEditor *editor) { +#if notyet ECardAddrLabel *address; GtkTextIter start_iter, end_iter; @@ -346,12 +368,14 @@ address_text_changed (GtkTextBuffer *buffer, EContactEditor *editor) e_card_address_label_unref(address); widget_changed (NULL, editor); +#endif } static void address_mailing_changed (GtkWidget *widget, EContactEditor *editor) { +#if notyet const ECardDeliveryAddress *curr; ECardDeliveryAddress *address; gboolean mailing_address; @@ -399,12 +423,13 @@ address_mailing_changed (GtkWidget *widget, EContactEditor *editor) editor->address_mailing = -1; widget_changed (widget, editor); +#endif } /* This function tells you whether name_to_style will make sense. */ static gboolean -style_makes_sense(const ECardName *name, char *company, int style) +style_makes_sense(const EContactName *name, char *company, int style) { switch (style) { case 0: /* Fall Through */ @@ -427,7 +452,7 @@ style_makes_sense(const ECardName *name, char *company, int style) } static char * -name_to_style(const ECardName *name, char *company, int style) +name_to_style(const EContactName *name, char *company, int style) { char *string; char *strings[4], **stringptr; @@ -489,7 +514,7 @@ file_as_get_style (EContactEditor *editor) GtkEntry *file_as = GTK_ENTRY(glade_xml_get_widget(editor->gui, "entry-file-as")); char *filestring; char *trystring; - ECardName *name = editor->name; + EContactName *name = editor->name; int i; int style; @@ -561,11 +586,12 @@ name_entry_changed (GtkWidget *widget, EContactEditor *editor) const char *string; style = file_as_get_style(editor); - - e_card_name_unref(editor->name); + + e_contact_name_free (editor->name); string = gtk_entry_get_text (GTK_ENTRY(widget)); - editor->name = e_card_name_from_string(string); + + editor->name = e_contact_name_from_string(string); file_as_set_style(editor, style); @@ -680,6 +706,7 @@ set_entry_changed_signals(EContactEditor *editor) } set_urlentry_changed_signal_field (editor, "entry-web"); + set_urlentry_changed_signal_field (editor, "entry-blog"); set_urlentry_changed_signal_field (editor, "entry-caluri"); set_urlentry_changed_signal_field (editor, "entry-fburl"); @@ -719,32 +746,32 @@ full_name_clicked(GtkWidget *button, EContactEditor *editor) int result; g_object_set (dialog, - "editable", editor->fullname_editable, - NULL); + "editable", editor->fullname_editable, + NULL); gtk_widget_show(GTK_WIDGET(dialog)); result = gtk_dialog_run (dialog); gtk_widget_hide (GTK_WIDGET (dialog)); if (editor->fullname_editable && result == GTK_RESPONSE_OK) { - ECardName *name; + EContactName *name; GtkWidget *fname_widget; int style = 0; g_object_get (dialog, - "name", &name, - NULL); + "name", &name, + NULL); style = file_as_get_style(editor); fname_widget = glade_xml_get_widget(editor->gui, "entry-fullname"); if (fname_widget && GTK_IS_ENTRY(fname_widget)) { - char *full_name = e_card_name_to_string(name); + char *full_name = e_contact_name_to_string(name); gtk_entry_set_text(GTK_ENTRY(fname_widget), full_name); g_free(full_name); } - e_card_name_unref(editor->name); - editor->name = e_card_name_ref(name); + e_contact_name_free(editor->name); + editor->name = name; file_as_set_style(editor, style); } @@ -754,6 +781,7 @@ full_name_clicked(GtkWidget *button, EContactEditor *editor) static void full_addr_clicked(GtkWidget *button, EContactEditor *editor) { +#if notyet GtkDialog *dialog; int result; const ECardDeliveryAddress *address; @@ -802,6 +830,7 @@ full_addr_clicked(GtkWidget *button, EContactEditor *editor) widget_changed (NULL, editor); } gtk_widget_destroy (GTK_WIDGET (dialog)); +#endif } static void @@ -814,10 +843,9 @@ categories_clicked(GtkWidget *button, EContactEditor *editor) ECategoriesMasterList *ecml; if (entry && GTK_IS_ENTRY(entry)) categories = g_strdup (gtk_entry_get_text(GTK_ENTRY(entry))); - else if (editor->card) - g_object_get (editor->card, - "categories", &categories, - NULL); + else if (editor->contact) + categories = e_contact_get (editor->contact, E_CONTACT_CATEGORIES); + dialog = GTK_DIALOG(e_categories_new(categories)); if (dialog == NULL) { @@ -841,14 +869,13 @@ categories_clicked(GtkWidget *button, EContactEditor *editor) g_free (categories); if (result == GTK_RESPONSE_OK) { g_object_get (dialog, - "categories", &categories, - NULL); + "categories", &categories, + NULL); if (entry && GTK_IS_ENTRY(entry)) gtk_entry_set_text(GTK_ENTRY(entry), categories); else - g_object_set (editor->card, - "categories", categories, - NULL); + e_contact_set (editor->contact, E_CONTACT_CATEGORIES, categories); + g_free(categories); } gtk_widget_destroy(GTK_WIDGET(dialog)); @@ -860,7 +887,7 @@ typedef struct { } EditorCloseStruct; static void -card_added_cb (EBook *book, EBookStatus status, const char *id, EditorCloseStruct *ecs) +contact_added_cb (EBook *book, EBookStatus status, const char *id, EditorCloseStruct *ecs) { EContactEditor *ce = ecs->ce; gboolean should_close = ecs->should_close; @@ -868,13 +895,13 @@ card_added_cb (EBook *book, EBookStatus status, const char *id, EditorCloseStruc gtk_widget_set_sensitive (ce->app, TRUE); ce->in_async_call = FALSE; - e_card_set_id (ce->card, id); + e_contact_set (ce->contact, E_CONTACT_UID, (char*)id); - g_signal_emit (ce, contact_editor_signals[CARD_ADDED], 0, - status, ce->card); + g_signal_emit (ce, contact_editor_signals[CONTACT_ADDED], 0, + status, ce->contact); - if (status == E_BOOK_STATUS_SUCCESS) { - ce->is_new_card = FALSE; + if (status == E_BOOK_ERROR_OK) { + ce->is_new_contact = FALSE; if (should_close) { close_dialog (ce); @@ -890,7 +917,7 @@ card_added_cb (EBook *book, EBookStatus status, const char *id, EditorCloseStruc } static void -card_modified_cb (EBook *book, EBookStatus status, EditorCloseStruct *ecs) +contact_modified_cb (EBook *book, EBookStatus status, EditorCloseStruct *ecs) { EContactEditor *ce = ecs->ce; gboolean should_close = ecs->should_close; @@ -898,10 +925,10 @@ card_modified_cb (EBook *book, EBookStatus status, EditorCloseStruct *ecs) gtk_widget_set_sensitive (ce->app, TRUE); ce->in_async_call = FALSE; - g_signal_emit (ce, contact_editor_signals[CARD_MODIFIED], 0, - status, ce->card); + g_signal_emit (ce, contact_editor_signals[CONTACT_MODIFIED], 0, + status, ce->contact); - if (status == E_BOOK_STATUS_SUCCESS) { + if (status == E_BOOK_ERROR_OK) { if (should_close) { close_dialog (ce); } @@ -915,12 +942,11 @@ card_modified_cb (EBook *book, EBookStatus status, EditorCloseStruct *ecs) g_free (ecs); } -/* Emits the signal to request saving a card */ +/* Emits the signal to request saving a contact */ static void -save_card (EContactEditor *ce, gboolean should_close) +save_contact (EContactEditor *ce, gboolean should_close) { extract_info (ce); - e_card_simple_sync_card (ce->simple); if (ce->book) { EditorCloseStruct *ecs = g_new(EditorCloseStruct, 1); @@ -933,10 +959,10 @@ save_card (EContactEditor *ce, gboolean should_close) gtk_widget_set_sensitive (ce->app, FALSE); ce->in_async_call = TRUE; - if (ce->is_new_card) - e_card_merging_book_add_card (ce->book, ce->card, (EBookIdCallback)card_added_cb, ecs); + if (ce->is_new_contact) + eab_merging_book_add_contact (ce->book, ce->contact, (EBookIdCallback)contact_added_cb, ecs); else - e_card_merging_book_commit_card (ce->book, ce->card, (EBookCallback)card_modified_cb, ecs); + eab_merging_book_commit_contact (ce->book, ce->contact, (EBookCallback)contact_modified_cb, ecs); } } @@ -957,9 +983,9 @@ prompt_to_save_changes (EContactEditor *editor) if (!editor->changed) return TRUE; - switch (e_addressbook_prompt_save_dialog (GTK_WINDOW(editor->app))) { + switch (eab_prompt_save_dialog (GTK_WINDOW(editor->app))) { case GTK_RESPONSE_YES: - save_card (editor, FALSE); + save_contact (editor, FALSE); return TRUE; case GTK_RESPONSE_NO: return TRUE; @@ -978,7 +1004,7 @@ file_save_cb (GtkWidget *widget, gpointer data) EContactEditor *ce; ce = E_CONTACT_EDITOR (data); - save_card (ce, FALSE); + save_contact (ce, FALSE); } /* File/Close callback */ @@ -998,45 +1024,38 @@ static void file_save_as_cb (GtkWidget *widget, gpointer data) { EContactEditor *ce; - ECard *card; + EContact *contact; ce = E_CONTACT_EDITOR (data); extract_info (ce); - e_card_simple_sync_card (ce->simple); - card = ce->card; - e_contact_save_as(_("Save Contact as VCard"), card, GTK_WINDOW (ce->app)); + contact = ce->contact; + eab_contact_save(_("Save Contact as VCard"), contact, GTK_WINDOW (ce->app)); } static void file_send_as_cb (GtkWidget *widget, gpointer data) { EContactEditor *ce; - ECard *card; ce = E_CONTACT_EDITOR (data); extract_info (ce); - e_card_simple_sync_card (ce->simple); - card = ce->card; - e_addressbook_send_card(card, E_ADDRESSBOOK_DISPOSITION_AS_ATTACHMENT); + eab_send_contact(ce->contact, EAB_DISPOSITION_AS_ATTACHMENT); } static void file_send_to_cb (GtkWidget *widget, gpointer data) { EContactEditor *ce; - ECard *card; ce = E_CONTACT_EDITOR (data); extract_info (ce); - e_card_simple_sync_card (ce->simple); - card = ce->card; - e_addressbook_send_card(card, E_ADDRESSBOOK_DISPOSITION_AS_TO); + eab_send_contact(ce->contact, EAB_DISPOSITION_AS_TO); } gboolean @@ -1071,16 +1090,16 @@ e_contact_editor_confirm_delete (GtkWindow *parent) } static void -card_deleted_cb (EBook *book, EBookStatus status, EContactEditor *ce) +contact_deleted_cb (EBook *book, EBookStatus status, EContactEditor *ce) { gtk_widget_set_sensitive (ce->app, TRUE); ce->in_async_call = FALSE; - g_signal_emit (ce, contact_editor_signals[CARD_DELETED], 0, - status, ce->card); + g_signal_emit (ce, contact_editor_signals[CONTACT_DELETED], 0, + status, ce->contact); /* always close the dialog after we successfully delete a card */ - if (status == E_BOOK_STATUS_SUCCESS) + if (status == E_BOOK_ERROR_OK) close_dialog (ce); } @@ -1088,27 +1107,23 @@ static void delete_cb (GtkWidget *widget, gpointer data) { EContactEditor *ce = E_CONTACT_EDITOR (data); - ECard *card = ce->card; - ECardSimple *simple = ce->simple; + EContact *contact = ce->contact; - g_object_ref(card); - g_object_ref(simple); + g_object_ref(contact); if (e_contact_editor_confirm_delete(GTK_WINDOW(ce->app))) { extract_info (ce); - e_card_simple_sync_card (simple); - if (!ce->is_new_card && ce->book) { + if (!ce->is_new_contact && ce->book) { gtk_widget_set_sensitive (ce->app, FALSE); ce->in_async_call = TRUE; - e_book_remove_card (ce->book, card, (EBookCallback)card_deleted_cb, ce); + e_book_async_remove_contact (ce->book, contact, (EBookCallback)contact_deleted_cb, ce); } } - g_object_unref(card); - g_object_unref(simple); + g_object_unref(contact); } /* Emits the signal to request printing a card */ @@ -1120,9 +1135,8 @@ print_cb (BonoboUIComponent *uih, void *data, const char *path) ce = E_CONTACT_EDITOR (data); extract_info (ce); - e_card_simple_sync_card (ce->simple); - gtk_widget_show(e_contact_print_card_dialog_new(ce->card)); + gtk_widget_show(e_contact_print_contact_dialog_new(ce->contact)); } #if 0 /* Envelope printing is disabled for Evolution 1.0. */ @@ -1148,7 +1162,7 @@ tb_save_and_close_cb (BonoboUIComponent *uih, void *data, const char *path) EContactEditor *ce; ce = E_CONTACT_EDITOR (data); - save_card (ce, TRUE); + save_contact (ce, TRUE); } static @@ -1244,6 +1258,7 @@ setup_tab_order(GladeXML *gui) list = add_to_tab_order(list, gui, "entry-email1"); list = add_to_tab_order(list, gui, "alignment-htmlmail"); list = add_to_tab_order(list, gui, "entry-web"); + list = add_to_tab_order(list, gui, "entry-blog"); list = add_to_tab_order(list, gui, "button-fulladdr"); list = add_to_tab_order(list, gui, "text-address"); list = g_list_reverse(list); @@ -1271,22 +1286,20 @@ e_contact_editor_init (EContactEditor *e_contact_editor) e_contact_editor->email_list = NULL; e_contact_editor->phone_list = NULL; e_contact_editor->address_list = NULL; - e_contact_editor->name = e_card_name_new(); + e_contact_editor->name = e_contact_name_new(); e_contact_editor->company = g_strdup(""); - e_contact_editor->email_choice = 0; - e_contact_editor->phone_choice[0] = E_CARD_SIMPLE_PHONE_ID_BUSINESS; - e_contact_editor->phone_choice[1] = E_CARD_SIMPLE_PHONE_ID_HOME; - e_contact_editor->phone_choice[2] = E_CARD_SIMPLE_PHONE_ID_BUSINESS_FAX; - e_contact_editor->phone_choice[3] = E_CARD_SIMPLE_PHONE_ID_MOBILE; + e_contact_editor->email_choice = E_CONTACT_EMAIL_1; + e_contact_editor->phone_choice[0] = E_CONTACT_PHONE_BUSINESS; + e_contact_editor->phone_choice[1] = E_CONTACT_PHONE_HOME; + e_contact_editor->phone_choice[2] = E_CONTACT_PHONE_BUSINESS_FAX; + e_contact_editor->phone_choice[3] = E_CONTACT_PHONE_MOBILE; +#if 0 e_contact_editor->address_choice = 0; e_contact_editor->address_mailing = -1; +#endif - e_contact_editor->arbitrary_fields = NULL; - - e_contact_editor->simple = e_card_simple_new(NULL); - - e_contact_editor->card = NULL; + e_contact_editor->contact = NULL; e_contact_editor->changed = FALSE; e_contact_editor->in_async_call = FALSE; e_contact_editor->editable = TRUE; @@ -1298,10 +1311,6 @@ e_contact_editor_init (EContactEditor *e_contact_editor) e_contact_editor->app = glade_xml_get_widget (gui, "contact editor"); - e_container_foreach_leaf (GTK_CONTAINER (e_contact_editor->app), - (GtkCallback) add_field_callback, - e_contact_editor); - connect_arrow_button_signals(e_contact_editor); set_entry_changed_signals(e_contact_editor); @@ -1429,23 +1438,18 @@ e_contact_editor_dispose (GObject *object) { e_contact_editor->address_popup = NULL; } - if (e_contact_editor->simple) { - g_object_unref(e_contact_editor->simple); - e_contact_editor->simple = NULL; + if (e_contact_editor->contact) { + g_object_unref(e_contact_editor->contact); + e_contact_editor->contact = NULL; } - if (e_contact_editor->card) { - g_object_unref(e_contact_editor->card); - e_contact_editor->card = NULL; - } - if (e_contact_editor->book) { g_object_unref(e_contact_editor->book); e_contact_editor->book = NULL; } if (e_contact_editor->name) { - e_card_name_unref(e_contact_editor->name); + e_contact_name_free(e_contact_editor->name); e_contact_editor->name = NULL; } @@ -1474,7 +1478,7 @@ command_state_changed (EContactEditor *ce) bonobo_ui_component_set_prop (ce->uic, "/commands/ContactEditorDelete", "sensitive", - (ce->editable && !ce->is_new_card) ? "1" : "0", NULL); + (ce->editable && !ce->is_new_contact) ? "1" : "0", NULL); } static void @@ -1506,14 +1510,14 @@ contact_editor_destroy_notify (void *data, EContactEditor * e_contact_editor_new (EBook *book, - ECard *card, - gboolean is_new_card, + EContact *contact, + gboolean is_new_contact, gboolean editable) { EContactEditor *ce; g_return_val_if_fail (E_IS_BOOK (book), NULL); - g_return_val_if_fail (E_IS_CARD (card), NULL); + g_return_val_if_fail (E_IS_CONTACT (contact), NULL); ce = g_object_new (E_TYPE_CONTACT_EDITOR, NULL); @@ -1525,13 +1529,13 @@ e_contact_editor_new (EBook *book, g_object_set (ce, "book", book, - "card", card, - "is_new_card", is_new_card, + "contact", contact, + "is_new_contact", is_new_contact, "editable", editable, NULL); if (book) - e_book_get_supported_fields (book, (EBookFieldsCallback)supported_fields_cb, ce); + e_book_async_get_supported_fields (book, (EBookFieldsCallback)supported_fields_cb, ce); return ce; } @@ -1551,19 +1555,16 @@ e_contact_editor_set_property (GObject *object, guint prop_id, const GValue *val g_object_ref (editor->book); /* XXX more here about editable/etc. */ break; - case PROP_CARD: - if (editor->card) - g_object_unref(editor->card); - editor->card = e_card_duplicate(E_CARD(g_value_get_object (value))); - g_object_set(editor->simple, - "card", editor->card, - NULL); + case PROP_CONTACT: + if (editor->contact) + g_object_unref(editor->contact); + editor->contact = e_contact_duplicate(E_CONTACT(g_value_get_object (value))); fill_in_info(editor); editor->changed = FALSE; break; - case PROP_IS_NEW_CARD: - editor->is_new_card = g_value_get_boolean (value) ? TRUE : FALSE; + case PROP_IS_NEW_CONTACT: + editor->is_new_contact = g_value_get_boolean (value) ? TRUE : FALSE; break; case PROP_EDITABLE: { @@ -1617,14 +1618,13 @@ e_contact_editor_get_property (GObject *object, guint prop_id, GValue *value, GP g_value_set_object (value, e_contact_editor->book); break; - case PROP_CARD: - e_card_simple_sync_card(e_contact_editor->simple); + case PROP_CONTACT: extract_info(e_contact_editor); - g_value_set_object (value, e_contact_editor->card); + g_value_set_object (value, e_contact_editor->contact); break; - case PROP_IS_NEW_CARD: - g_value_set_boolean (value, e_contact_editor->is_new_card ? TRUE : FALSE); + case PROP_IS_NEW_CONTACT: + g_value_set_boolean (value, e_contact_editor->is_new_contact ? TRUE : FALSE); break; case PROP_EDITABLE: @@ -1730,33 +1730,11 @@ e_contact_editor_build_ui_info(GList *list, GnomeUIInfo **infop) static void e_contact_editor_build_phone_ui (EContactEditor *editor) { - int i; - if (editor->phone_list == NULL) { - static char *info[] = { - N_("Assistant"), - N_("Business"), - N_("Business 2"), - N_("Business Fax"), - N_("Callback"), - N_("Car"), - N_("Company"), - N_("Home"), - N_("Home 2"), - N_("Home Fax"), - N_("ISDN"), - N_("Mobile"), - N_("Other"), - N_("Other Fax"), - N_("Pager"), - N_("Primary"), - N_("Radio"), - N_("Telex"), - N_("TTY/TDD") - }; - - for (i = 0; i < sizeof(info) / sizeof(info[0]); i++) { - editor->phone_list = g_list_append(editor->phone_list, g_strdup(info[i])); + int i; + + for (i = 0; i < G_N_ELEMENTS (phones); i ++) { + editor->phone_list = g_list_append(editor->phone_list, g_strdup(e_contact_pretty_name (phones[i]))); } } if (editor->phone_info == NULL) { @@ -1777,15 +1755,8 @@ e_contact_editor_build_email_ui (EContactEditor *editor) int i; if (editor->email_list == NULL) { - static char *info[] = { - N_("Primary Email"), - N_("Email 2"), - N_("Email 3") - }; - - for (i = 0; i < sizeof(info) / sizeof(info[0]); i++) { - editor->email_list = g_list_append(editor->email_list, g_strdup(info[i])); - } + for (i = 0; i < G_N_ELEMENTS (emails); i++) + editor->email_list = g_list_append(editor->email_list, g_strdup(e_contact_pretty_name (emails[i]))); } if (editor->email_info == NULL) { e_contact_editor_build_ui_info(editor->email_list, &editor->email_info); @@ -1851,21 +1822,21 @@ _phone_arrow_pressed (GtkWidget *widget, GdkEventButton *button, EContactEditor e_contact_editor_build_phone_ui (editor); - for(i = 0; i < E_CARD_SIMPLE_PHONE_ID_LAST; i++) { - const ECardPhone *phone = e_card_simple_get_phone(editor->simple, i); - gboolean checked; - checked = phone && phone->number && *phone->number; + for(i = 0; i < G_N_ELEMENTS (phones); i++) { + char *phone = e_contact_get (editor->contact, phones[i]); gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(editor->phone_info[i].widget), - checked); + phone && *phone); + g_free (phone); } result = _arrow_pressed (widget, button, editor, editor->phone_popup, &editor->phone_list, &editor->phone_info, label); if (result != -1) { - editor->phone_choice[which - 1] = result; - set_fields(editor); + GtkWidget *w = glade_xml_get_widget (editor->gui, entry); + editor->phone_choice[which - 1] = phones[result]; + set_fields (editor); enable_widget (glade_xml_get_widget (editor->gui, label), TRUE); - enable_widget (glade_xml_get_widget (editor->gui, entry), editor->editable); + enable_widget (w, editor->editable); } g_free(label); @@ -1880,23 +1851,26 @@ _email_arrow_pressed (GtkWidget *widget, GdkEventButton *button, EContactEditor e_contact_editor_build_email_ui (editor); - for(i = 0; i < E_CARD_SIMPLE_EMAIL_ID_LAST; i++) { - const char *string = e_card_simple_get_email(editor->simple, i); + for(i = 0; i < G_N_ELEMENTS (emails); i++) { + char *string = e_contact_get (editor->contact, emails[i]); gboolean checked; checked = string && *string; gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(editor->email_info[i].widget), checked); + g_free (string); } result = _arrow_pressed (widget, button, editor, editor->email_popup, &editor->email_list, &editor->email_info, "label-email1"); if (result != -1) { + GtkWidget *entry = glade_xml_get_widget (editor->gui, "entry-email1"); editor->email_choice = result; - set_fields(editor); + + set_fields (editor); /* make sure the buttons/entry is/are sensitive */ enable_widget (glade_xml_get_widget (editor->gui, "label-email1"), TRUE); - enable_widget (glade_xml_get_widget (editor->gui, "entry-email1"), editor->editable); + enable_widget (entry, editor->editable); enable_widget (glade_xml_get_widget (editor->gui, "checkbutton-htmlmail"), editor->editable); } } @@ -1904,6 +1878,7 @@ _email_arrow_pressed (GtkWidget *widget, GdkEventButton *button, EContactEditor static void _address_arrow_pressed (GtkWidget *widget, GdkEventButton *button, EContactEditor *editor) { +#if notyet int i; int result; @@ -1927,11 +1902,13 @@ _address_arrow_pressed (GtkWidget *widget, GdkEventButton *button, EContactEdito enable_widget (glade_xml_get_widget (editor->gui, "text-address"), editor->address_editable[result]); enable_widget (glade_xml_get_widget (editor->gui, "checkbutton-mailingaddress"), editor->address_editable[result]); } +#endif } static void find_address_mailing (EContactEditor *editor) { +#if notyet const ECardDeliveryAddress *address; int i; @@ -1951,6 +1928,7 @@ find_address_mailing (EContactEditor *editor) } } } +#endif } static void @@ -1971,9 +1949,9 @@ set_field(EContactEditor *editor, GtkEntry *entry, const char *string) } static void -set_phone_field(EContactEditor *editor, GtkWidget *entry, const ECardPhone *phone) +set_phone_field(EContactEditor *editor, GtkWidget *entry, const char *phone_number) { - set_field(editor, GTK_ENTRY(entry), phone ? phone->number : ""); + set_field(editor, GTK_ENTRY(entry), phone_number ? phone_number : ""); } static void @@ -1985,28 +1963,28 @@ set_fields(EContactEditor *editor) entry = glade_xml_get_widget(editor->gui, "entry-phone1"); if (entry && GTK_IS_ENTRY(entry)) - set_phone_field(editor, entry, e_card_simple_get_phone(editor->simple, editor->phone_choice[0])); + set_phone_field(editor, entry, e_contact_get_const(editor->contact, editor->phone_choice[0])); entry = glade_xml_get_widget(editor->gui, "entry-phone2"); if (entry && GTK_IS_ENTRY(entry)) - set_phone_field(editor, entry, e_card_simple_get_phone(editor->simple, editor->phone_choice[1])); + set_phone_field(editor, entry, e_contact_get_const(editor->contact, editor->phone_choice[1])); entry = glade_xml_get_widget(editor->gui, "entry-phone3"); if (entry && GTK_IS_ENTRY(entry)) - set_phone_field(editor, entry, e_card_simple_get_phone(editor->simple, editor->phone_choice[2])); + set_phone_field(editor, entry, e_contact_get_const(editor->contact, editor->phone_choice[2])); entry = glade_xml_get_widget(editor->gui, "entry-phone4"); if (entry && GTK_IS_ENTRY(entry)) - set_phone_field(editor, entry, e_card_simple_get_phone(editor->simple, editor->phone_choice[3])); + set_phone_field(editor, entry, e_contact_get_const(editor->contact, editor->phone_choice[3])); entry = glade_xml_get_widget(editor->gui, "entry-email1"); if (entry && GTK_IS_ENTRY(entry)) - set_field(editor, GTK_ENTRY(entry), e_card_simple_get_email(editor->simple, editor->email_choice)); - + set_field(editor, GTK_ENTRY(entry), e_contact_get_const(editor->contact, editor->email_choice)); e_contact_editor_build_address_ui (editor); +#if notyet for (i = 0; i < E_CARD_SIMPLE_ADDRESS_ID_LAST; i++) { const ECardAddrLabel *address = e_card_simple_get_address(editor->simple, i); @@ -2024,11 +2002,13 @@ set_fields(EContactEditor *editor) } set_address_field(editor, i); +#endif } static void set_address_field(EContactEditor *editor, int result) { +#if notyet GtkWidget *text, *check; text = glade_xml_get_widget(editor->gui, "text-address"); @@ -2064,73 +2044,29 @@ set_address_field(EContactEditor *editor, int result) editor->address_choice = result; } -} - -static void -add_field_callback(GtkWidget *widget, EContactEditor *editor) -{ - const char *name; - int i; - static const char *builtins[] = { - "entry-fullname", - "entry-web", - "entry-company", - "entry-department", - "entry-office", - "entry-jobtitle", - "entry-profession", - "entry-manager", - "entry-assistant", - "entry-nickname", - "entry-spouse", - "text-comments", - "entry-categories", - "entry-file-as", - "dateedit-anniversary", - "dateedit-birthday", - "entry-phone1", - "entry-phone2", - "entry-phone3", - "entry-phone4", - "entry-email1", - "text-address", - "checkbutton-mailingaddress", - "checkbutton-htmlmail", - "entry-caluri", - "entry-fburl", - NULL - }; - name = glade_get_widget_name(widget); - if (name) { - for (i = 0; builtins[i]; i++) { - if (!strcmp(name, builtins[i])) - return; - } - if (GTK_IS_ENTRY(widget) || GTK_IS_TEXT_VIEW(widget)) { - editor->arbitrary_fields = g_list_prepend(editor->arbitrary_fields, g_strdup(name)); - } - } +#endif } static struct { char *id; - char *key; + EContactField field; } field_mapping [] = { - { "entry-fullname", "full_name" }, - { "entry-web", "url" }, - { "entry-company", "org" }, - { "entry-department", "org_unit" }, - { "entry-office", "office" }, - { "entry-jobtitle", "title" }, - { "entry-profession", "role" }, - { "entry-manager", "manager" }, - { "entry-assistant", "assistant" }, - { "entry-nickname", "nickname" }, - { "entry-spouse", "spouse" }, - { "text-comments", "note" }, - { "entry-categories", "categories" }, - { "entry-caluri", "caluri" }, - { "entry-fburl", "fburl" }, + { "entry-fullname", E_CONTACT_FULL_NAME }, + { "entry-web", E_CONTACT_HOMEPAGE_URL }, + { "entry-blog", E_CONTACT_BLOG_URL }, + { "entry-company", E_CONTACT_ORG }, + { "entry-department", E_CONTACT_ORG_UNIT }, + { "entry-office", E_CONTACT_OFFICE }, + { "entry-jobtitle", E_CONTACT_TITLE }, + { "entry-profession", E_CONTACT_ROLE }, + { "entry-manager", E_CONTACT_MANAGER }, + { "entry-assistant", E_CONTACT_ASSISTANT }, + { "entry-nickname", E_CONTACT_NICKNAME }, + { "entry-spouse", E_CONTACT_SPOUSE }, + { "text-comments", E_CONTACT_NOTE }, + { "entry-categories", E_CONTACT_CATEGORIES }, + { "entry-caluri", E_CONTACT_CALENDAR_URI }, + { "entry-fburl", E_CONTACT_FREEBUSY_URL }, }; static void @@ -2158,36 +2094,6 @@ fill_in_field(EContactEditor *editor, char *id, char *value) } } -static void -fill_in_card_field(EContactEditor *editor, ECard *card, char *id, char *key) -{ - char *string; - g_object_get (card, - key, &string, - NULL); - fill_in_field(editor, id, string); - g_free (string); -} - -static void -fill_in_single_field(EContactEditor *editor, char *name) -{ - ECardSimple *simple = editor->simple; - GtkWidget *widget = glade_xml_get_widget(editor->gui, name); - - if (widget && GTK_IS_EDITABLE(widget)) { - int position = 0; - GtkEditable *editable = GTK_EDITABLE(widget); - const ECardArbitrary *arbitrary; - - gtk_editable_delete_text(editable, 0, -1); - arbitrary = e_card_simple_get_arbitrary(simple, - name); - if (arbitrary && arbitrary->value) - gtk_editable_insert_text(editable, arbitrary->value, strlen(arbitrary->value), &position); - } -} - static void disable_widget_foreach (char *key, GtkWidget *widget, gpointer closure) { @@ -2196,62 +2102,65 @@ disable_widget_foreach (char *key, GtkWidget *widget, gpointer closure) static struct { char *widget_name; - ECardSimpleField field_id; + EContactField field_id; gboolean desensitize_for_read_only; } widget_field_mappings[] = { - { "entry-web", E_CARD_SIMPLE_FIELD_URL, TRUE }, - { "accellabel-web", E_CARD_SIMPLE_FIELD_URL }, + { "entry-web", E_CONTACT_HOMEPAGE_URL, TRUE }, + { "accellabel-web", E_CONTACT_HOMEPAGE_URL }, - { "entry-jobtitle", E_CARD_SIMPLE_FIELD_TITLE, TRUE }, - { "label-jobtitle", E_CARD_SIMPLE_FIELD_TITLE }, + { "entry-blog", E_CONTACT_BLOG_URL, TRUE }, + { "accellabel-blog", E_CONTACT_BLOG_URL }, - { "entry-company", E_CARD_SIMPLE_FIELD_ORG, TRUE }, - { "label-company", E_CARD_SIMPLE_FIELD_ORG }, + { "entry-jobtitle", E_CONTACT_TITLE, TRUE }, + { "label-jobtitle", E_CONTACT_TITLE }, - { "combo-file-as", E_CARD_SIMPLE_FIELD_FILE_AS, TRUE }, - { "entry-file-as", E_CARD_SIMPLE_FIELD_FILE_AS, TRUE }, - { "accellabel-fileas", E_CARD_SIMPLE_FIELD_FILE_AS }, + { "entry-company", E_CONTACT_ORG, TRUE }, + { "label-company", E_CONTACT_ORG }, - { "label-department", E_CARD_SIMPLE_FIELD_ORG_UNIT }, - { "entry-department", E_CARD_SIMPLE_FIELD_ORG_UNIT, TRUE }, + { "combo-file-as", E_CONTACT_FILE_AS, TRUE }, + { "entry-file-as", E_CONTACT_FILE_AS, TRUE }, + { "accellabel-fileas", E_CONTACT_FILE_AS }, - { "label-office", E_CARD_SIMPLE_FIELD_OFFICE }, - { "entry-office", E_CARD_SIMPLE_FIELD_OFFICE, TRUE }, + { "label-department", E_CONTACT_ORG_UNIT }, + { "entry-department", E_CONTACT_ORG_UNIT, TRUE }, - { "label-profession", E_CARD_SIMPLE_FIELD_ROLE }, - { "entry-profession", E_CARD_SIMPLE_FIELD_ROLE, TRUE }, + { "label-office", E_CONTACT_OFFICE }, + { "entry-office", E_CONTACT_OFFICE, TRUE }, - { "label-manager", E_CARD_SIMPLE_FIELD_MANAGER }, - { "entry-manager", E_CARD_SIMPLE_FIELD_MANAGER, TRUE }, + { "label-profession", E_CONTACT_ROLE }, + { "entry-profession", E_CONTACT_ROLE, TRUE }, - { "label-assistant", E_CARD_SIMPLE_FIELD_ASSISTANT }, - { "entry-assistant", E_CARD_SIMPLE_FIELD_ASSISTANT, TRUE }, + { "label-manager", E_CONTACT_MANAGER }, + { "entry-manager", E_CONTACT_MANAGER, TRUE }, - { "label-nickname", E_CARD_SIMPLE_FIELD_NICKNAME }, - { "entry-nickname", E_CARD_SIMPLE_FIELD_NICKNAME, TRUE }, + { "label-assistant", E_CONTACT_ASSISTANT }, + { "entry-assistant", E_CONTACT_ASSISTANT, TRUE }, - { "label-spouse", E_CARD_SIMPLE_FIELD_SPOUSE }, - { "entry-spouse", E_CARD_SIMPLE_FIELD_SPOUSE, TRUE }, + { "label-nickname", E_CONTACT_NICKNAME }, + { "entry-nickname", E_CONTACT_NICKNAME, TRUE }, - { "label-birthday", E_CARD_SIMPLE_FIELD_BIRTH_DATE }, - { "dateedit-birthday", E_CARD_SIMPLE_FIELD_BIRTH_DATE, TRUE }, + { "label-spouse", E_CONTACT_SPOUSE }, + { "entry-spouse", E_CONTACT_SPOUSE, TRUE }, - { "label-anniversary", E_CARD_SIMPLE_FIELD_ANNIVERSARY }, - { "dateedit-anniversary", E_CARD_SIMPLE_FIELD_ANNIVERSARY, TRUE }, + { "label-birthday", E_CONTACT_BIRTH_DATE }, + { "dateedit-birthday", E_CONTACT_BIRTH_DATE, TRUE }, - { "label-comments", E_CARD_SIMPLE_FIELD_NOTE }, - { "text-comments", E_CARD_SIMPLE_FIELD_NOTE, TRUE }, + { "label-anniversary", E_CONTACT_ANNIVERSARY }, + { "dateedit-anniversary", E_CONTACT_ANNIVERSARY, TRUE }, - { "entry-fullname", E_CARD_SIMPLE_FIELD_FULL_NAME, TRUE }, + { "label-comments", E_CONTACT_NOTE }, + { "text-comments", E_CONTACT_NOTE, TRUE }, - { "button-categories", E_CARD_SIMPLE_FIELD_CATEGORIES, TRUE }, - { "entry-categories", E_CARD_SIMPLE_FIELD_CATEGORIES, TRUE }, + { "entry-fullname", E_CONTACT_FULL_NAME, TRUE }, - { "label-caluri", E_CARD_SIMPLE_FIELD_CALURI }, - { "entry-caluri", E_CARD_SIMPLE_FIELD_CALURI, TRUE }, + { "button-categories", E_CONTACT_CATEGORIES, TRUE }, + { "entry-categories", E_CONTACT_CATEGORIES, TRUE }, - { "label-fburl", E_CARD_SIMPLE_FIELD_FBURL }, - { "entry-fburl", E_CARD_SIMPLE_FIELD_FBURL, TRUE } + { "label-caluri", E_CONTACT_CALENDAR_URI }, + { "entry-caluri", E_CONTACT_CALENDAR_URI, TRUE }, + + { "label-fburl", E_CONTACT_FREEBUSY_URL }, + { "entry-fburl", E_CONTACT_FREEBUSY_URL, TRUE } }; static int num_widget_field_mappings = sizeof(widget_field_mappings) / sizeof (widget_field_mappings[0]); @@ -2262,35 +2171,32 @@ enable_writable_fields(EContactEditor *editor) EIterator *iter; GHashTable *dropdown_hash, *supported_hash; int i; - ECardSimple *simple; - ECard *card; char *widget_name; if (!fields) return; - card = e_card_new (""); - simple = e_card_simple_new (card); - dropdown_hash = g_hash_table_new (g_str_hash, g_str_equal); supported_hash = g_hash_table_new (g_str_hash, g_str_equal); /* build our hashtable of the drop down menu items */ e_contact_editor_build_phone_ui (editor); - for (i = 0; i < E_CARD_SIMPLE_PHONE_ID_LAST; i ++) + for (i = 0; i < G_N_ELEMENTS (phones); i ++) g_hash_table_insert (dropdown_hash, - (char*)e_card_simple_get_ecard_field(simple, e_card_simple_map_phone_to_field (i)), + (char*)e_contact_field_name(phones[i]), editor->phone_info[i].widget); e_contact_editor_build_email_ui (editor); - for (i = 0; i < E_CARD_SIMPLE_EMAIL_ID_LAST; i ++) + for (i = 0; i < G_N_ELEMENTS (emails); i ++) g_hash_table_insert (dropdown_hash, - (char*)e_card_simple_get_ecard_field(simple, e_card_simple_map_email_to_field (i)), + (char*)e_contact_field_name(phones[i]), editor->email_info[i].widget); +#if notyet e_contact_editor_build_address_ui (editor); for (i = 0; i < E_CARD_SIMPLE_ADDRESS_ID_LAST; i ++) g_hash_table_insert (dropdown_hash, (char*)e_card_simple_get_ecard_field(simple, e_card_simple_map_address_to_field (i)), editor->address_info[i].widget); +#endif /* then disable them all */ g_hash_table_foreach (dropdown_hash, (GHFunc)disable_widget_foreach, NULL); @@ -2332,28 +2238,30 @@ enable_writable_fields(EContactEditor *editor) g_hash_table_insert (supported_hash, field, field); } +#if notyet for (i = 0; i < E_CARD_SIMPLE_ADDRESS_ID_LAST; i ++) { if (!strcmp (field, e_card_simple_get_ecard_field (simple, e_card_simple_map_address_to_field(i)))) { editor->address_editable [i] = TRUE; } } +#endif /* ugh - this is needed to make sure we don't have a disabled label next to a drop down when the item in the menu (the one reflected in the label) is enabled. */ - if (!strcmp (field, e_card_simple_get_ecard_field (simple, e_card_simple_map_email_to_field(editor->email_choice)))) { + if (!strcmp (field, e_contact_field_name (editor->email_choice))) { enable_widget (glade_xml_get_widget (editor->gui, "label-email1"), TRUE); enable_widget (glade_xml_get_widget (editor->gui, "entry-email1"), editor->editable); enable_widget (glade_xml_get_widget (editor->gui, "checkbutton-htmlmail"), editor->editable); } - else if (!strcmp (field, e_card_simple_get_ecard_field (simple, e_card_simple_map_address_to_field(editor->address_choice)))) { + else if (!strcmp (field, e_contact_field_name (editor->address_choice))) { enable_widget (glade_xml_get_widget (editor->gui, "label-address"), TRUE); enable_widget (glade_xml_get_widget (editor->gui, "checkbutton-mailingaddress"), editor->editable); enable_widget (glade_xml_get_widget (editor->gui, "text-address"), editor->editable); } else for (i = 0; i < 4; i ++) { - if (!strcmp (field, e_card_simple_get_ecard_field (simple, e_card_simple_map_phone_to_field(editor->phone_choice[i])))) { + if (!strcmp (field, e_contact_field_name (editor->phone_choice[i]))) { widget_name = g_strdup_printf ("label-phone%d", i+1); enable_widget (glade_xml_get_widget (editor->gui, widget_name), TRUE); g_free (widget_name); @@ -2377,8 +2285,7 @@ enable_writable_fields(EContactEditor *editor) widget_field_mappings[i].widget_name); continue; } - field = e_card_simple_get_ecard_field (simple, - widget_field_mappings[i].field_id); + field = e_contact_field_name (widget_field_mappings[i].field_id); enabled = (g_hash_table_lookup (supported_hash, field) != NULL); @@ -2393,8 +2300,6 @@ enable_writable_fields(EContactEditor *editor) g_hash_table_destroy (dropdown_hash); g_hash_table_destroy (supported_hash); - g_object_unref (simple); - g_object_unref (card); } static void @@ -2436,51 +2341,46 @@ set_editable (EContactEditor *editor) static void fill_in_info(EContactEditor *editor) { - ECard *card = editor->card; - if (card) { + EContact *contact = editor->contact; + if (contact) { char *file_as; - ECardName *name; - const ECardDate *anniversary; - const ECardDate *bday; + EContactName *name; + EContactDate *anniversary; + EContactDate *bday; int i; GtkWidget *widget; - GList *list; - gboolean wants_html, wants_html_set; - - g_object_get (card, - "file_as", &file_as, - "name", &name, - "anniversary", &anniversary, - "birth_date", &bday, - "wants_html_set", &wants_html_set, - "wants_html", &wants_html, - NULL); - - for (i = 0; i < sizeof(field_mapping) / sizeof(field_mapping[0]); i++) { - fill_in_card_field(editor, card, field_mapping[i].id, field_mapping[i].key); - } + gboolean wants_html; + + g_object_get (contact, + "file_as", &file_as, + "name", &name, + "anniversary", &anniversary, + "birth_date", &bday, + "wants_html", &wants_html, + NULL); - for (list = editor->arbitrary_fields; list; list = list->next) { - fill_in_single_field(editor, list->data); + for (i = 0; i < sizeof(field_mapping) / sizeof(field_mapping[0]); i++) { + char *string = e_contact_get (contact, field_mapping[i].field); + fill_in_field(editor, field_mapping[i].id, string); + g_free (string); } find_address_mailing (editor); - if (wants_html_set) { - GtkWidget *widget = glade_xml_get_widget(editor->gui, "checkbutton-htmlmail"); - if (widget && GTK_IS_CHECK_BUTTON(widget)) { - g_object_set (widget, - "active", wants_html, - NULL); - } + widget = glade_xml_get_widget(editor->gui, "checkbutton-htmlmail"); + if (widget && GTK_IS_CHECK_BUTTON(widget)) { + g_object_set (widget, + "active", wants_html, + NULL); } /* File as has to come after company and name or else it'll get messed up when setting them. */ fill_in_field(editor, "entry-file-as", file_as); - g_free (file_as); - e_card_name_unref(editor->name); - editor->name = e_card_name_ref(name); + g_free (file_as); + if (editor->name) + e_contact_name_free(editor->name); + editor->name = name; widget = glade_xml_get_widget(editor->gui, "dateedit-anniversary"); if (widget && E_IS_DATE_EDIT(widget)) { @@ -2508,12 +2408,15 @@ fill_in_info(EContactEditor *editor) e_date_edit_set_time (dateedit, -1); } + e_contact_date_free (anniversary); + e_contact_date_free (bday); + set_fields(editor); } } static void -extract_field(EContactEditor *editor, ECard *card, char *editable_id, char *key) +extract_field(EContactEditor *editor, EContact *contact, char *editable_id, EContactField field) { GtkWidget *widget = glade_xml_get_widget(editor->gui, editable_id); char *string = NULL; @@ -2538,50 +2441,22 @@ extract_field(EContactEditor *editor, ECard *card, char *editable_id, char *key) } if (string && *string) - g_object_set (card, - key, string, - NULL); + e_contact_set (contact, field, string); else - g_object_set (card, - key, NULL, - NULL); + e_contact_set (contact, field, NULL); if (string) g_free(string); } -static void -extract_single_field(EContactEditor *editor, char *name) -{ - GtkWidget *widget = glade_xml_get_widget(editor->gui, name); - ECardSimple *simple = editor->simple; - if (widget && GTK_IS_EDITABLE(widget)) { - GtkEditable *editable = GTK_EDITABLE(widget); - char *string = gtk_editable_get_chars(editable, 0, -1); - - if (string && *string) - e_card_simple_set_arbitrary(simple, - name, - NULL, - string); - else - e_card_simple_set_arbitrary(simple, - name, - NULL, - NULL); - if (string) g_free(string); - } -} - static void extract_info(EContactEditor *editor) { - ECard *card = editor->card; - if (card) { - ECardDate anniversary; - ECardDate bday; + EContact *contact = editor->contact; + if (contact) { + EContactDate anniversary; + EContactDate bday; int i; GtkWidget *widget; - GList *list; widget = glade_xml_get_widget(editor->gui, "entry-file-as"); if (widget && GTK_IS_EDITABLE(widget)) { @@ -2589,25 +2464,17 @@ extract_info(EContactEditor *editor) char *string = gtk_editable_get_chars(editable, 0, -1); if (string && *string) - g_object_set (card, - "file_as", string, - NULL); + e_contact_set (contact, E_CONTACT_FILE_AS, string); - if (string) g_free(string); + g_free(string); } for (i = 0; i < sizeof(field_mapping) / sizeof(field_mapping[0]); i++) { - extract_field(editor, card, field_mapping[i].id, field_mapping[i].key); - } - - for (list = editor->arbitrary_fields; list; list = list->next) { - extract_single_field(editor, list->data); + extract_field(editor, contact, field_mapping[i].id, field_mapping[i].field); } if (editor->name) - g_object_set (card, - "name", editor->name, - NULL); + e_contact_set (contact, E_CONTACT_NAME, editor->name); widget = glade_xml_get_widget(editor->gui, "dateedit-anniversary"); if (widget && E_IS_DATE_EDIT(widget)) { @@ -2616,13 +2483,9 @@ extract_info(EContactEditor *editor) &anniversary.month, &anniversary.day)) { /* g_print ("%d %d %d\n", anniversary.year, anniversary.month, anniversary.day); */ - g_object_set (card, - "anniversary", &anniversary, - NULL); + e_contact_set (contact, E_CONTACT_ANNIVERSARY, &anniversary); } else - g_object_set (card, - "anniversary", NULL, - NULL); + e_contact_set (contact, E_CONTACT_ANNIVERSARY, NULL); } widget = glade_xml_get_widget(editor->gui, "dateedit-birthday"); @@ -2632,13 +2495,9 @@ extract_info(EContactEditor *editor) &bday.month, &bday.day)) { /* g_print ("%d %d %d\n", bday.year, bday.month, bday.day); */ - g_object_set (card, - "birth_date", &bday, - NULL); + e_contact_set (contact, E_CONTACT_BIRTH_DATE, &bday); } else - g_object_set (card, - "birth_date", NULL, - NULL); + e_contact_set (contact, E_CONTACT_BIRTH_DATE, NULL); } } } diff --git a/addressbook/gui/contact-editor/e-contact-editor.h b/addressbook/gui/contact-editor/e-contact-editor.h index 8642aecac1..efee496539 100644 --- a/addressbook/gui/contact-editor/e-contact-editor.h +++ b/addressbook/gui/contact-editor/e-contact-editor.h @@ -25,9 +25,8 @@ #include #include -#include "addressbook/backend/ebook/e-book.h" -#include "addressbook/backend/ebook/e-card.h" -#include "addressbook/backend/ebook/e-card-simple.h" +#include "addressbook/backend/ebook/e-book-async.h" +#include "addressbook/backend/ebook/e-contact.h" G_BEGIN_DECLS @@ -56,8 +55,7 @@ struct _EContactEditor /* item specific fields */ EBook *book; - ECard *card; - ECardSimple *simple; + EContact *contact; /* UI handler */ BonoboUIComponent *uic; @@ -74,20 +72,18 @@ struct _EContactEditor GList *phone_list; GList *address_list; - ECardName *name; + EContactName *name; char *company; - ECardSimpleEmailId email_choice; - ECardSimplePhoneId phone_choice[4]; - ECardSimpleAddressId address_choice; - ECardSimpleAddressId address_mailing; + EContactField email_choice; + EContactField phone_choice[4]; + EContactField address_choice; + EContactField address_mailing; - GList *arbitrary_fields; + /* Whether we are editing a new contact or an existing one */ + guint is_new_contact : 1; - /* Whether we are editing a new card or an existing one */ - guint is_new_card : 1; - - /* Whether the card has been changed since bringing up the contact editor */ + /* Whether the contact has been changed since bringing up the contact editor */ guint changed : 1; /* Whether the contact editor will accept modifications */ @@ -96,8 +92,10 @@ struct _EContactEditor /* Whether the fullname will accept modifications */ guint fullname_editable : 1; +#if notyet /* Whether each of the addresses are editable */ gboolean address_editable[E_CARD_SIMPLE_ADDRESS_ID_LAST]; +#endif /* Whether an async wombat call is in progress */ guint in_async_call : 1; @@ -111,15 +109,15 @@ struct _EContactEditorClass /* Notification signals */ - void (* card_added) (EContactEditor *ce, EBookStatus status, ECard *card); - void (* card_modified) (EContactEditor *ce, EBookStatus status, ECard *card); - void (* card_deleted) (EContactEditor *ce, EBookStatus status, ECard *card); - void (* editor_closed) (EContactEditor *ce); + void (* contact_added) (EContactEditor *ce, EBookStatus status, EContact *contact); + void (* contact_modified) (EContactEditor *ce, EBookStatus status, EContact *contact); + void (* contact_deleted) (EContactEditor *ce, EBookStatus status, EContact *contact); + void (* editor_closed) (EContactEditor *ce); }; EContactEditor *e_contact_editor_new (EBook *book, - ECard *card, - gboolean is_new_card, + EContact *contact, + gboolean is_new_contact, gboolean editable); GType e_contact_editor_get_type (void); diff --git a/addressbook/gui/contact-editor/e-contact-quick-add.c b/addressbook/gui/contact-editor/e-contact-quick-add.c index 703996ee07..65b321c997 100644 --- a/addressbook/gui/contact-editor/e-contact-quick-add.c +++ b/addressbook/gui/contact-editor/e-contact-quick-add.c @@ -37,17 +37,17 @@ #include #include #include -#include -#include +#include +#include #include "e-contact-editor.h" #include "e-contact-quick-add.h" -#include "e-card-merging.h" +#include "eab-contact-merging.h" typedef struct _QuickAdd QuickAdd; struct _QuickAdd { gchar *name; gchar *email; - ECard *card; + EContact *contact; EContactQuickAddCallback cb; gpointer closure; @@ -63,7 +63,7 @@ static QuickAdd * quick_add_new (void) { QuickAdd *qa = g_new0 (QuickAdd, 1); - qa->card = e_card_new (""); + qa->contact = e_contact_new (); qa->refs = 1; return qa; } @@ -84,7 +84,7 @@ quick_add_unref (QuickAdd *qa) if (qa->refs == 0) { g_free (qa->name); g_free (qa->email); - g_object_unref (qa->card); + g_object_unref (qa->contact); g_free (qa); } } @@ -93,7 +93,8 @@ quick_add_unref (QuickAdd *qa) static void quick_add_set_name (QuickAdd *qa, const gchar *name) { - ECardName *card_name; +#if notyet + EContactName *card_name; if (name == qa->name) return; @@ -108,23 +109,19 @@ quick_add_set_name (QuickAdd *qa, const gchar *name) NULL); e_card_name_unref (card_name); +#endif } static void quick_add_set_email (QuickAdd *qa, const gchar *email) { - ECardSimple *simple; - if (email == qa->email) return; g_free (qa->email); qa->email = g_strdup (email); - simple = e_card_simple_new (qa->card); - e_card_simple_set (simple, E_CARD_SIMPLE_FIELD_EMAIL, email); - e_card_simple_sync_card (simple); - g_object_unref (simple); + e_contact_set (qa->contact, E_CONTACT_EMAIL_1, (char*)email); } static void @@ -132,10 +129,10 @@ merge_cb (EBook *book, EBookStatus status, gpointer closure) { QuickAdd *qa = (QuickAdd *) closure; - if (status == E_BOOK_STATUS_SUCCESS) { - e_card_merging_book_add_card (book, qa->card, NULL, NULL); + if (status == E_BOOK_ERROR_OK) { + eab_merging_book_add_contact (book, qa->contact, NULL, NULL); if (qa->cb) - qa->cb (qa->card, qa->closure); + qa->cb (qa->contact, qa->closure); g_object_unref (book); } else { /* Something went wrong. */ @@ -149,14 +146,11 @@ merge_cb (EBook *book, EBookStatus status, gpointer closure) } static void -quick_add_merge_card (QuickAdd *qa) +quick_add_merge_contact (QuickAdd *qa) { - EBook *book; - quick_add_ref (qa); - book = e_book_new (); - addressbook_load_default_book (book, merge_cb, qa); + addressbook_load_default_book (merge_cb, qa); } @@ -165,14 +159,14 @@ quick_add_merge_card (QuickAdd *qa) */ static void -card_added_cb (EContactEditor *ce, EBookStatus status, ECard *card, gpointer closure) +contact_added_cb (EContactEditor *ce, EBookStatus status, EContact *contact, gpointer closure) { QuickAdd *qa = (QuickAdd *) g_object_get_data (G_OBJECT (ce), "quick_add"); if (qa) { if (qa->cb) - qa->cb (qa->card, qa->closure); + qa->cb (qa->contact, qa->closure); /* We don't need to unref qa because we set_data_full below */ g_object_set_data (G_OBJECT (ce), "quick_add", NULL); @@ -196,13 +190,13 @@ ce_have_book (EBook *book, EBookStatus status, gpointer closure) { QuickAdd *qa = (QuickAdd *) closure; - if (status != E_BOOK_STATUS_SUCCESS) { + if (status != E_BOOK_ERROR_OK) { if (book) g_object_unref (book); g_warning ("Couldn't open local address book."); quick_add_unref (qa); } else { - EContactEditor *contact_editor = e_contact_editor_new (book, qa->card, TRUE, TRUE /* XXX */); + EContactEditor *contact_editor = e_contact_editor_new (book, qa->contact, TRUE, TRUE /* XXX */); /* mark it as changed so the Save buttons are enabled when we bring up the dialog. */ g_object_set (contact_editor, @@ -210,14 +204,14 @@ ce_have_book (EBook *book, EBookStatus status, gpointer closure) NULL); /* We pass this via object data, so that we don't get a dangling pointer referenced if both - the "card_added" and "editor_closed" get emitted. (Which, based on a backtrace in bugzilla, + the "contact_added" and "editor_closed" get emitted. (Which, based on a backtrace in bugzilla, I think can happen and cause a crash. */ g_object_set_data_full (G_OBJECT (contact_editor), "quick_add", qa, (GDestroyNotify) quick_add_unref); g_signal_connect (contact_editor, - "card_added", - G_CALLBACK (card_added_cb), + "contact_added", + G_CALLBACK (contact_added_cb), NULL); g_signal_connect (contact_editor, "editor_closed", @@ -229,11 +223,9 @@ ce_have_book (EBook *book, EBookStatus status, gpointer closure) } static void -edit_card (QuickAdd *qa) +edit_contact (QuickAdd *qa) { - EBook *book; - book = e_book_new (); - addressbook_load_default_book (book, ce_have_book, qa); + addressbook_load_default_book (ce_have_book, qa); } #define QUICK_ADD_RESPONSE_EDIT_FULL 2 @@ -272,12 +264,12 @@ clicked_cb (GtkWidget *w, gint button, gpointer closure) if (button == GTK_RESPONSE_OK) { /* OK */ - quick_add_merge_card (qa); + quick_add_merge_contact (qa); } else if (button == QUICK_ADD_RESPONSE_EDIT_FULL) { /* EDIT FULL */ - edit_card (qa); + edit_contact (qa); } else { /* CANCEL */ diff --git a/addressbook/gui/contact-editor/e-contact-quick-add.h b/addressbook/gui/contact-editor/e-contact-quick-add.h index 1bf69ee114..ad98c73c23 100644 --- a/addressbook/gui/contact-editor/e-contact-quick-add.h +++ b/addressbook/gui/contact-editor/e-contact-quick-add.h @@ -27,9 +27,9 @@ #ifndef __E_CONTACT_QUICK_ADD_H__ #define __E_CONTACT_QUICK_ADD_H__ -#include +#include -typedef void (*EContactQuickAddCallback) (ECard *new_card, gpointer closure); +typedef void (*EContactQuickAddCallback) (EContact *new_contact, gpointer closure); void e_contact_quick_add (const gchar *name, const gchar *email, EContactQuickAddCallback cb, gpointer closure); diff --git a/addressbook/gui/contact-editor/e-contact-save-as.c b/addressbook/gui/contact-editor/e-contact-save-as.c deleted file mode 100644 index a141560763..0000000000 --- a/addressbook/gui/contact-editor/e-contact-save-as.c +++ /dev/null @@ -1,218 +0,0 @@ -/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ -/* e-contact-editor.h - * Copyright (C) 2000 Ximian, Inc. - * Author: Chris Lahey - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of version 2 of the GNU General Public - * License as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public - * License along with this library; if not, write to the - * Free Software Foundation, Inc., 59 Temple Place - Suite 330, - * Boston, MA 02111-1307, USA. - */ - -#include - -#include "e-contact-save-as.h" - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -static gint file_exists(GtkFileSelection *filesel, const char *filename); - -typedef struct { - GtkFileSelection *filesel; - char *vcard; -} SaveAsInfo; - -static void -save_it(GtkWidget *widget, SaveAsInfo *info) -{ - gint error = 0; - gint response = 0; - - const char *filename = gtk_file_selection_get_filename (info->filesel); - - error = e_write_file (filename, info->vcard, O_WRONLY | O_CREAT | O_EXCL | O_TRUNC); - - if (error == EEXIST) { - response = file_exists(info->filesel, filename); - switch (response) { - case GTK_RESPONSE_ACCEPT : /* Overwrite */ - e_write_file(filename, info->vcard, O_WRONLY | O_CREAT | O_TRUNC); - break; - case GTK_RESPONSE_REJECT : /* cancel */ - return; - } - } else if (error != 0) { - GtkWidget *dialog; - char *str; - - str = g_strdup_printf (_("Error saving %s: %s"), filename, strerror(errno)); - dialog = gtk_message_dialog_new (GTK_WINDOW (info->filesel), - GTK_DIALOG_DESTROY_WITH_PARENT, - GTK_MESSAGE_ERROR, - GTK_BUTTONS_OK, - str); - g_free (str); - - gtk_widget_show (dialog); - - return; - } - - gtk_widget_destroy(GTK_WIDGET(info->filesel)); -} - -static void -close_it(GtkWidget *widget, SaveAsInfo *info) -{ - gtk_widget_destroy (GTK_WIDGET (info->filesel)); -} - -static void -destroy_it(void *data, GObject *where_the_object_was) -{ - SaveAsInfo *info = data; - g_free (info->vcard); - g_free (info); -} - -static char * -make_safe_filename (const char *prefix, char *name) -{ - char *safe, *p; - - if (!name) { - /* This is a filename. Translators take note. */ - name = _("card.vcf"); - } - - p = strrchr (name, '/'); - if (p) - safe = g_strdup_printf ("%s%s%s", prefix, p, ".vcf"); - else - safe = g_strdup_printf ("%s/%s%s", prefix, name, ".vcf"); - - p = strrchr (safe, '/') + 1; - if (p) - e_filename_make_safe (p); - - return safe; -} - -void -e_contact_save_as(char *title, ECard *card, GtkWindow *parent_window) -{ - GtkFileSelection *filesel; - char *file; - char *name; - SaveAsInfo *info = g_new(SaveAsInfo, 1); - - filesel = GTK_FILE_SELECTION(gtk_file_selection_new(title)); - - g_object_get (card, - "file_as", &name, - NULL); - file = make_safe_filename (g_get_home_dir(), name); - gtk_file_selection_set_filename (filesel, file); - g_free (file); - g_free (name); - - info->filesel = filesel; - info->vcard = e_card_get_vcard(card); - - g_signal_connect(filesel->ok_button, "clicked", - G_CALLBACK (save_it), info); - g_signal_connect(filesel->cancel_button, "clicked", - G_CALLBACK (close_it), info); - g_object_weak_ref (G_OBJECT (filesel), destroy_it, info); - - if (parent_window) { - gtk_window_set_transient_for (GTK_WINDOW (filesel), - parent_window); - gtk_window_set_modal (GTK_WINDOW (filesel), TRUE); - } - - gtk_widget_show(GTK_WIDGET(filesel)); -} - -void -e_contact_list_save_as(char *title, GList *list, GtkWindow *parent_window) -{ - GtkFileSelection *filesel; - SaveAsInfo *info = g_new(SaveAsInfo, 1); - - filesel = GTK_FILE_SELECTION(gtk_file_selection_new(title)); - - /* This is a filename. Translators take note. */ - if (list && list->data && list->next == NULL) { - char *name, *file; - g_object_get (list->data, - "file_as", &name, - NULL); - file = make_safe_filename (g_get_home_dir(), name); - gtk_file_selection_set_filename (filesel, file); - g_free (file); - g_free (name); - } else { - char *file; - file = make_safe_filename (g_get_home_dir(), _("list")); - gtk_file_selection_set_filename (filesel, file); - g_free (file); - } - - info->filesel = filesel; - info->vcard = e_card_list_get_vcard (list); - - g_signal_connect(filesel->ok_button, "clicked", - G_CALLBACK (save_it), info); - g_signal_connect(filesel->cancel_button, "clicked", - G_CALLBACK (close_it), info); - g_object_weak_ref (G_OBJECT (filesel), destroy_it, info); - - if (parent_window) { - gtk_window_set_transient_for (GTK_WINDOW (filesel), - parent_window); - gtk_window_set_modal (GTK_WINDOW (filesel), TRUE); - } - - gtk_widget_show(GTK_WIDGET(filesel)); -} - -static gint -file_exists(GtkFileSelection *filesel, const char *filename) -{ - GtkWidget *dialog; - gint response; - - dialog = gtk_message_dialog_new (GTK_WINDOW (filesel), - 0, - GTK_MESSAGE_QUESTION, - GTK_BUTTONS_NONE, - _("%s already exists\nDo you want to overwrite it?"), filename); - - gtk_dialog_add_buttons (GTK_DIALOG (dialog), - GTK_STOCK_CANCEL, GTK_RESPONSE_REJECT, - _("Overwrite"), GTK_RESPONSE_ACCEPT, - NULL); - - response = gtk_dialog_run (GTK_DIALOG (dialog)); - gtk_widget_destroy (dialog); - return response; -} diff --git a/addressbook/gui/contact-editor/e-contact-save-as.h b/addressbook/gui/contact-editor/e-contact-save-as.h deleted file mode 100644 index 2b01ad8435..0000000000 --- a/addressbook/gui/contact-editor/e-contact-save-as.h +++ /dev/null @@ -1,41 +0,0 @@ -/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ -/* e-contact-save-as.h - * Copyright (C) 2000 Ximian, Inc. - * Author: Chris Lahey - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of version 2 of the GNU General Public - * License as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public - * License along with this library; if not, write to the - * Free Software Foundation, Inc., 59 Temple Place - Suite 330, - * Boston, MA 02111-1307, USA. - */ -#ifndef __E_CONTACT_SAVE_AS_H__ -#define __E_CONTACT_SAVE_AS_H__ - -#include -#include -#include "addressbook/backend/ebook/e-card.h" -#include "addressbook/backend/ebook/e-card-simple.h" - -#ifdef __cplusplus -extern "C" { -#pragma } -#endif /* __cplusplus */ - -void e_contact_save_as (gchar *title, ECard *card, GtkWindow *parent_window); -void e_contact_list_save_as (gchar *title, GList *list, GtkWindow *parent_window); - -#ifdef __cplusplus -} -#endif /* __cplusplus */ - - -#endif /* __E_CONTACT_EDITOR_H__ */ diff --git a/addressbook/gui/contact-list-editor/contact-list-editor.glade b/addressbook/gui/contact-list-editor/contact-list-editor.glade index c64eebd520..002e697105 100644 --- a/addressbook/gui/contact-list-editor/contact-list-editor.glade +++ b/addressbook/gui/contact-list-editor/contact-list-editor.glade @@ -78,7 +78,7 @@ - + True e_create_image_widget evolution-contacts-plain.png diff --git a/addressbook/gui/contact-list-editor/e-contact-list-editor.c b/addressbook/gui/contact-list-editor/e-contact-list-editor.c index 39f251f5ee..a475d15cd6 100644 --- a/addressbook/gui/contact-list-editor/e-contact-list-editor.c +++ b/addressbook/gui/contact-list-editor/e-contact-list-editor.c @@ -30,12 +30,13 @@ #include #include #include +#include #include "shell/evolution-shell-component-utils.h" -#include "addressbook/gui/widgets/e-addressbook-util.h" +#include "addressbook/gui/widgets/eab-gui-util.h" +#include "addressbook/util/eab-book-util.h" #include "e-contact-editor.h" -#include "e-contact-save-as.h" #include "e-contact-list-model.h" #include "e-contact-list-editor-marshal.h" @@ -76,6 +77,17 @@ static void table_drag_data_received_cb (ETable *table, int row, int col, gint x, gint y, GtkSelectionData *selection_data, guint info, guint time, EContactListEditor *editor); +static gboolean image_drag_motion_cb (GtkWidget *widget, + GdkDragContext *context, + gint x, gint y, guint time, EContactListEditor *editor); +static gboolean image_drag_drop_cb (GtkWidget *widget, + GdkDragContext *context, + gint x, gint y, guint time, EContactListEditor *editor); +static void image_drag_data_received_cb (GtkWidget *widget, + GdkDragContext *context, + gint x, gint y, + GtkSelectionData *selection_data, + guint info, guint time, EContactListEditor *editor); static GtkObjectClass *parent_class = NULL; @@ -83,18 +95,26 @@ static guint contact_list_editor_signals[LAST_SIGNAL]; enum DndTargetType { DND_TARGET_TYPE_VCARD, + DND_TARGET_TYPE_URI_LIST }; #define VCARD_TYPE "text/x-vcard" -static GtkTargetEntry drag_types[] = { +#define URI_LIST_TYPE "text/uri-list" + +static GtkTargetEntry list_drag_types[] = { { VCARD_TYPE, 0, DND_TARGET_TYPE_VCARD }, }; -static const int num_drag_types = sizeof (drag_types) / sizeof (drag_types[0]); +static const int num_list_drag_types = sizeof (list_drag_types) / sizeof (list_drag_types[0]); + +static GtkTargetEntry image_drag_types[] = { + { URI_LIST_TYPE, 0, DND_TARGET_TYPE_URI_LIST }, +}; +static const int num_image_drag_types = sizeof (image_drag_types) / sizeof (image_drag_types[0]); /* The arguments we take */ enum { PROP_0, PROP_BOOK, - PROP_CARD, + PROP_CONTACT, PROP_IS_NEW_LIST, PROP_EDITABLE }; @@ -144,11 +164,11 @@ e_contact_list_editor_class_init (EContactListEditorClass *klass) E_TYPE_BOOK, G_PARAM_READWRITE)); - g_object_class_install_property (object_class, PROP_CARD, - g_param_spec_object ("card", - _("Card"), + g_object_class_install_property (object_class, PROP_CONTACT, + g_param_spec_object ("contact", + _("Contact"), /*_( */"XXX blurb" /*)*/, - E_TYPE_CARD, + E_TYPE_CONTACT, G_PARAM_READWRITE)); g_object_class_install_property (object_class, PROP_IS_NEW_LIST, @@ -212,8 +232,10 @@ e_contact_list_editor_init (EContactListEditor *editor) GtkWidget *bonobo_win; BonoboUIContainer *container; char *icon_path; + GdkPixbuf *pixbuf; - editor->card = NULL; + editor->image_buf = NULL; + editor->contact = NULL; editor->changed = FALSE; editor->editable = TRUE; editor->in_async_call = FALSE; @@ -235,9 +257,17 @@ e_contact_list_editor_init (EContactListEditor *editor) editor->email_entry = glade_xml_get_widget (gui, "email-entry"); editor->list_name_entry = glade_xml_get_widget (gui, "list-name-entry"); - + editor->list_image = glade_xml_get_widget (gui, "list-image"); + if (GTK_IS_ALIGNMENT (editor->list_image)) { + /* deal with the e_create_image_widget code, that wraps the image in an alignment */ + editor->list_image = GTK_BIN (editor->list_image)->child; + } editor->visible_addrs_checkbutton = glade_xml_get_widget (gui, "visible-addrs-checkbutton"); + pixbuf = gtk_image_get_pixbuf (GTK_IMAGE (editor->list_image)); + editor->list_image_width = gdk_pixbuf_get_width (pixbuf); + editor->list_image_height = gdk_pixbuf_get_height (pixbuf); + /* Construct the app */ bonobo_win = bonobo_window_new ("contact-list-editor", _("Contact List Editor")); @@ -286,7 +316,7 @@ e_contact_list_editor_init (EContactListEditor *editor) "toggled", G_CALLBACK(visible_addrs_toggled_cb), editor); e_table_drag_dest_set (e_table_scrolled_get_table (E_TABLE_SCROLLED (editor->table)), - 0, drag_types, num_drag_types, GDK_ACTION_LINK); + 0, list_drag_types, num_list_drag_types, GDK_ACTION_LINK); g_signal_connect (e_table_scrolled_get_table (E_TABLE_SCROLLED (editor->table)), "table_drag_motion", G_CALLBACK(table_drag_motion_cb), editor); @@ -295,6 +325,14 @@ e_contact_list_editor_init (EContactListEditor *editor) g_signal_connect (e_table_scrolled_get_table (E_TABLE_SCROLLED (editor->table)), "table_drag_data_received", G_CALLBACK(table_drag_data_received_cb), editor); + gtk_drag_dest_set (editor->list_image, 0, image_drag_types, num_image_drag_types, GDK_ACTION_COPY); + g_signal_connect (editor->list_image, + "drag_motion", G_CALLBACK (image_drag_motion_cb), editor); + g_signal_connect (editor->list_image, + "drag_drop", G_CALLBACK (image_drag_drop_cb), editor); + g_signal_connect (editor->list_image, + "drag_data_received", G_CALLBACK (image_drag_data_received_cb), editor); + command_state_changed (editor); /* Connect to the deletion of the dialog */ @@ -311,6 +349,13 @@ e_contact_list_editor_init (EContactListEditor *editor) static void e_contact_list_editor_dispose (GObject *object) { + EContactListEditor *cle = E_CONTACT_LIST_EDITOR (object); + + if (cle->image_buf) { + g_free (cle->image_buf); + cle->image_buf = NULL; + } + if (G_OBJECT_CLASS (parent_class)->dispose) (* G_OBJECT_CLASS (parent_class)->dispose) (object); } @@ -330,12 +375,12 @@ list_added_cb (EBook *book, EBookStatus status, const char *id, EditorCloseStruc gtk_widget_set_sensitive (cle->app, TRUE); cle->in_async_call = FALSE; - e_card_set_id (cle->card, id); + e_contact_set (cle->contact, E_CONTACT_UID, (char*)id); g_signal_emit (cle, contact_list_editor_signals[LIST_ADDED], 0, - status, cle->card); + status, cle->contact); - if (status == E_BOOK_STATUS_SUCCESS) { + if (status == E_BOOK_ERROR_OK) { cle->is_new_list = FALSE; if (should_close) @@ -359,9 +404,9 @@ list_modified_cb (EBook *book, EBookStatus status, EditorCloseStruct *ecs) cle->in_async_call = FALSE; g_signal_emit (cle, contact_list_editor_signals[LIST_MODIFIED], 0, - status, cle->card); + status, cle->contact); - if (status == E_BOOK_STATUS_SUCCESS) { + if (status == E_BOOK_ERROR_OK) { if (should_close) close_dialog (cle); } @@ -371,7 +416,7 @@ list_modified_cb (EBook *book, EBookStatus status, EditorCloseStruct *ecs) } static void -save_card (EContactListEditor *cle, gboolean should_close) +save_contact (EContactListEditor *cle, gboolean should_close) { extract_info (cle); @@ -387,9 +432,9 @@ save_card (EContactListEditor *cle, gboolean should_close) cle->in_async_call = TRUE; if (cle->is_new_list) - e_book_add_card (cle->book, cle->card, (EBookIdCallback)list_added_cb, ecs); + e_book_async_add_contact (cle->book, cle->contact, (EBookIdCallback)list_added_cb, ecs); else - e_book_commit_card (cle->book, cle->card, (EBookCallback)list_modified_cb, ecs); + e_book_async_commit_contact (cle->book, cle->contact, (EBookCallback)list_modified_cb, ecs); cle->changed = FALSE; } @@ -416,9 +461,9 @@ prompt_to_save_changes (EContactListEditor *editor) if (!editor->changed || !is_named (editor)) return TRUE; - switch (e_addressbook_prompt_save_dialog (GTK_WINDOW(editor->app))) { + switch (eab_prompt_save_dialog (GTK_WINDOW(editor->app))) { case GTK_RESPONSE_YES: - save_card (editor, FALSE); + save_contact (editor, FALSE); return TRUE; case GTK_RESPONSE_NO: return TRUE; @@ -444,7 +489,7 @@ file_save_cb (GtkWidget *widget, gpointer data) { EContactListEditor *cle = E_CONTACT_LIST_EDITOR (data); - save_card (cle, FALSE); + save_contact (cle, FALSE); } static void @@ -454,7 +499,7 @@ file_save_as_cb (GtkWidget *widget, gpointer data) extract_info (cle); - e_contact_save_as(_("Save List as VCard"), cle->card, GTK_WINDOW (cle->app)); + eab_contact_save(_("Save List as VCard"), cle->contact, GTK_WINDOW (cle->app)); } static void @@ -464,7 +509,7 @@ file_send_as_cb (GtkWidget *widget, gpointer data) extract_info (cle); - e_addressbook_send_card(cle->card, E_ADDRESSBOOK_DISPOSITION_AS_ATTACHMENT); + eab_send_contact(cle->contact, EAB_DISPOSITION_AS_ATTACHMENT); } static void @@ -474,14 +519,14 @@ file_send_to_cb (GtkWidget *widget, gpointer data) extract_info (cle); - e_addressbook_send_card(cle->card, E_ADDRESSBOOK_DISPOSITION_AS_TO); + eab_send_contact(cle->contact, EAB_DISPOSITION_AS_TO); } static void tb_save_and_close_cb (GtkWidget *widget, gpointer data) { EContactListEditor *cle = E_CONTACT_LIST_EDITOR (data); - save_card (cle, TRUE); + save_contact (cle, TRUE); } static void @@ -492,10 +537,10 @@ list_deleted_cb (EBook *book, EBookStatus status, EContactListEditor *cle) cle->in_async_call = FALSE; g_signal_emit (cle, contact_list_editor_signals[LIST_DELETED], 0, - status, cle->card); + status, cle->contact); /* always close the dialog after we successfully delete a list */ - if (status == E_BOOK_STATUS_SUCCESS) + if (status == E_BOOK_ERROR_OK) close_dialog (cle); g_object_unref (cle); /* release reference held for callback */ @@ -505,9 +550,9 @@ static void delete_cb (GtkWidget *widget, gpointer data) { EContactListEditor *cle = E_CONTACT_LIST_EDITOR (data); - ECard *card = cle->card; + EContact *contact = cle->contact; - g_object_ref (card); + g_object_ref (contact); if (e_contact_editor_confirm_delete(GTK_WINDOW(cle->app))) { @@ -518,11 +563,11 @@ delete_cb (GtkWidget *widget, gpointer data) cle->in_async_call = TRUE; g_object_ref (cle); /* hold reference for callback */ - e_book_remove_card (cle->book, card, (EBookCallback)list_deleted_cb, cle); + e_book_async_remove_contact (cle->book, contact, (EBookCallback)list_deleted_cb, cle); } } - g_object_unref (card); + g_object_unref (contact); } static @@ -578,7 +623,7 @@ contact_list_editor_destroy_notify (gpointer data, EContactListEditor * e_contact_list_editor_new (EBook *book, - ECard *list_card, + EContact *list_contact, gboolean is_new_list, gboolean editable) { @@ -592,7 +637,7 @@ e_contact_list_editor_new (EBook *book, g_object_set (ce, "book", book, - "card", list_card, + "contact", list_contact, "is_new_list", is_new_list, "editable", editable, NULL); @@ -616,10 +661,10 @@ e_contact_list_editor_set_property (GObject *object, guint prop_id, g_object_ref (editor->book); /* XXX more here about editable/etc. */ break; - case PROP_CARD: - if (editor->card) - g_object_unref (editor->card); - editor->card = e_card_duplicate(E_CARD(g_value_get_object (value))); + case PROP_CONTACT: + if (editor->contact) + g_object_unref (editor->contact); + editor->contact = e_contact_duplicate(E_CONTACT(g_value_get_object (value))); fill_in_info(editor); editor->changed = FALSE; command_state_changed (editor); @@ -665,9 +710,9 @@ e_contact_list_editor_get_property (GObject *object, guint prop_id, g_value_set_object (value, editor->book); break; - case PROP_CARD: + case PROP_CONTACT: extract_info(editor); - g_value_set_object (value, editor->card); + g_value_set_object (value, editor->contact); break; case PROP_IS_NEW_LIST: @@ -822,7 +867,7 @@ table_drag_motion_cb (ETable *table, int row, int col, for (p = context->targets; p != NULL; p = p->next) { char *possible_type; - possible_type = gdk_atom_name ((GdkAtom) p->data); + possible_type = gdk_atom_name (GDK_POINTER_TO_ATOM (p->data)); if (!strcmp (possible_type, VCARD_TYPE)) { g_free (possible_type); gdk_drag_status (context, GDK_ACTION_LINK, time); @@ -866,28 +911,24 @@ table_drag_data_received_cb (ETable *table, int row, int col, if (!strcmp (target_type, VCARD_TYPE)) { - GList *card_list = e_card_load_cards_from_string_with_default_charset (selection_data->data, "ISO-8859-1"); + GList *contact_list = eab_contact_list_from_string (selection_data->data); GList *c; - if (card_list) + if (contact_list) handled = TRUE; - for (c = card_list; c; c = c->next) { - ECard *ecard = c->data; - - if (!e_card_evolution_list (ecard)) { - ECardSimple *simple = e_card_simple_new (ecard); + for (c = contact_list; c; c = c->next) { + EContact *contact = c->data; - e_contact_list_model_add_card (E_CONTACT_LIST_MODEL (editor->model), - simple); - - g_object_unref (simple); + if (!e_contact_get (contact, E_CONTACT_IS_LIST)) { + e_contact_list_model_add_contact (E_CONTACT_LIST_MODEL (editor->model), + contact); changed = TRUE; } } - g_list_foreach (card_list, (GFunc)g_object_unref, NULL); - g_list_free (card_list); + g_list_foreach (contact_list, (GFunc)g_object_unref, NULL); + g_list_free (contact_list); /* Skip to the end of the list */ if (adj->upper - adj->lower > adj->page_size) @@ -902,6 +943,219 @@ table_drag_data_received_cb (ETable *table, int row, int col, gtk_drag_finish (context, handled, FALSE, time); } +static gboolean +set_image_from_data (EContactListEditor *editor, + char *data, int length) +{ + gboolean rv = FALSE; + GdkPixbufLoader *loader = gdk_pixbuf_loader_new (); + GdkPixbuf *pixbuf; + + gdk_pixbuf_loader_write (loader, data, length, NULL); + + pixbuf = gdk_pixbuf_loader_get_pixbuf (loader); + if (pixbuf) + gdk_pixbuf_ref (pixbuf); + gdk_pixbuf_loader_close (loader, NULL); + g_object_unref (loader); + + if (pixbuf) { + GdkPixbuf *scaled; + GdkPixbuf *composite; + + float scale; + int new_height, new_width; + + new_height = gdk_pixbuf_get_height (pixbuf); + new_width = gdk_pixbuf_get_width (pixbuf); + + printf ("new dimensions = (%d,%d)\n", new_width, new_height); + + if (editor->list_image_height < new_height + || editor->list_image_width < new_width) { + /* we need to scale down */ + printf ("we need to scale down\n"); + if (new_height > new_width) + scale = (float)editor->list_image_height / new_height; + else + scale = (float)editor->list_image_width / new_width; + } + else { + /* we need to scale up */ + printf ("we need to scale up\n"); + if (new_height > new_width) + scale = (float)new_height / editor->list_image_height; + else + scale = (float)new_width / editor->list_image_width; + } + + printf ("scale = %g\n", scale); + + new_width *= scale; + new_height *= scale; + new_width = MIN (new_width, editor->list_image_width); + new_height = MIN (new_height, editor->list_image_height); + + printf ("new scaled dimensions = (%d,%d)\n", new_width, new_height); + + scaled = gdk_pixbuf_scale_simple (pixbuf, + new_width, new_height, + GDK_INTERP_BILINEAR); + + composite = gdk_pixbuf_new (GDK_COLORSPACE_RGB, TRUE, gdk_pixbuf_get_bits_per_sample (pixbuf), + editor->list_image_width, editor->list_image_height); + + gdk_pixbuf_fill (composite, 0x00000000); + + gdk_pixbuf_copy_area (scaled, 0, 0, new_width, new_height, + composite, + editor->list_image_width / 2 - new_width / 2, + editor->list_image_height / 2 - new_height / 2); + + gtk_image_set_from_pixbuf (GTK_IMAGE (editor->list_image), composite); + gdk_pixbuf_unref (pixbuf); + gdk_pixbuf_unref (scaled); + gdk_pixbuf_unref (composite); + + rv = TRUE; + } + + return rv; +} + +static gboolean +image_drag_motion_cb (GtkWidget *widget, + GdkDragContext *context, + gint x, gint y, guint time, EContactListEditor *editor) +{ + GList *p; + + for (p = context->targets; p != NULL; p = p->next) { + char *possible_type; + + possible_type = gdk_atom_name (GDK_POINTER_TO_ATOM (p->data)); + if (!strcmp (possible_type, URI_LIST_TYPE)) { + g_free (possible_type); + gdk_drag_status (context, GDK_ACTION_COPY, time); + return TRUE; + } + + g_free (possible_type); + } + + return FALSE; +} + +static gboolean +image_drag_drop_cb (GtkWidget *widget, + GdkDragContext *context, + gint x, gint y, guint time, EContactListEditor *editor) +{ + GList *p; + + if (context->targets == NULL) + return FALSE; + + + for (p = context->targets; p != NULL; p = p->next) { + char *possible_type; + + possible_type = gdk_atom_name (GDK_POINTER_TO_ATOM (p->data)); + if (!strcmp (possible_type, URI_LIST_TYPE)) { + g_free (possible_type); + gtk_drag_get_data (widget, context, + GDK_POINTER_TO_ATOM (p->data), + time); + return TRUE; + } + + g_free (possible_type); + } + + return FALSE; +} + +static void +image_drag_data_received_cb (GtkWidget *widget, + GdkDragContext *context, + gint x, gint y, + GtkSelectionData *selection_data, + guint info, guint time, EContactListEditor *editor) +{ + char *target_type; + gboolean changed = FALSE; + gboolean handled = FALSE; + + target_type = gdk_atom_name (selection_data->target); + + printf ("target_type == %s\n", target_type); + + if (!strcmp (target_type, URI_LIST_TYPE)) { + GnomeVFSResult result; + GnomeVFSHandle *handle; + char *uri; + char *nl = strstr (selection_data->data, "\r\n"); + char *buf = NULL; + GnomeVFSFileInfo info; + + if (nl) + uri = g_strndup (selection_data->data, nl - (char*)selection_data->data); + else + uri = g_strdup (selection_data->data); + + printf ("uri == %s\n", uri); + + result = gnome_vfs_open (&handle, uri, GNOME_VFS_OPEN_READ); + if (result == GNOME_VFS_OK) { + result = gnome_vfs_get_file_info_from_handle (handle, &info, GNOME_VFS_FILE_INFO_DEFAULT); + if (result == GNOME_VFS_OK) { + GnomeVFSFileSize num_left; + GnomeVFSFileSize num_read; + GnomeVFSFileSize total_read; + + printf ("file size = %d\n", (int)info.size); + buf = g_malloc (info.size); + + num_left = info.size; + total_read = 0; + + while ((result = gnome_vfs_read (handle, buf + total_read, num_left, &num_read)) == GNOME_VFS_OK) { + num_left -= num_read; + total_read += num_read; + } + + printf ("read %d bytes\n", (int)total_read); + if (set_image_from_data (editor, buf, total_read)) { + changed = TRUE; + handled = TRUE; + g_free (editor->image_buf); + editor->image_buf = buf; + editor->image_buf_size = total_read; + } + else { + /* XXX we should pop up a + warning dialog here */ + g_free (buf); + } + } + + gnome_vfs_close (handle); + } + else { + printf ("gnome_vfs_open failed (%s)\n", gnome_vfs_result_to_string (result)); + } + + g_free (uri); + + if (changed) { + editor->changed = TRUE; + command_state_changed (editor); + } + } + + gtk_drag_finish (context, handled, FALSE, time); +} + static void command_state_changed (EContactListEditor *editor) { @@ -926,48 +1180,43 @@ command_state_changed (EContactListEditor *editor) static void extract_info(EContactListEditor *editor) { - ECard *card = editor->card; - if (card) { + EContact *contact = editor->contact; + if (contact) { int i; - EList *email_list; - EIterator *email_iter; + GList *email_list; char *string = gtk_editable_get_chars(GTK_EDITABLE (editor->list_name_entry), 0, -1); - if (string && *string) - g_object_set (card, - "file_as", string, - "full_name", string, - NULL); + if (string && *string) { + e_contact_set (contact, E_CONTACT_FILE_AS, string); + e_contact_set (contact, E_CONTACT_FULL_NAME, string); + } g_free (string); - - g_object_set (card, - "list", GINT_TO_POINTER (TRUE), - "list_show_addresses", - GINT_TO_POINTER (!gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON(editor->visible_addrs_checkbutton))), - NULL); - - g_object_get (card, - "email", &email_list, - NULL); - - /* clear the email list */ - email_iter = e_list_get_iterator (email_list); - e_iterator_last (email_iter); - while (e_iterator_is_valid (E_ITERATOR (email_iter))) { - e_iterator_delete (E_ITERATOR (email_iter)); - } - g_object_unref (email_iter); + e_contact_set (contact, E_CONTACT_IS_LIST, GINT_TO_POINTER (TRUE)); + e_contact_set (contact, E_CONTACT_LIST_SHOW_ADDRESSES, + GINT_TO_POINTER (!gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON(editor->visible_addrs_checkbutton)))); + email_list = NULL; /* then refill it from the contact list model */ for (i = 0; i < e_table_model_row_count (editor->model); i ++) { - const EDestination *dest = e_contact_list_model_get_destination (E_CONTACT_LIST_MODEL (editor->model), i); - gchar *dest_xml = e_destination_export (dest); - if (dest_xml) { - e_list_append (email_list, dest_xml); - } - g_free (dest_xml); + const EABDestination *dest = e_contact_list_model_get_destination (E_CONTACT_LIST_MODEL (editor->model), i); + gchar *dest_xml = eab_destination_export (dest); + if (dest_xml) + email_list = g_list_append (email_list, dest_xml); + } + + e_contact_set (contact, E_CONTACT_EMAIL, email_list); + + /* XXX free email_list? */ + + if (editor->image_buf) { + EContactPhoto photo; + + photo.data = editor->image_buf; + photo.length = editor->image_buf_size; + + e_contact_set (contact, E_CONTACT_LOGO, &photo); } g_object_unref (email_list); } @@ -976,19 +1225,18 @@ extract_info(EContactListEditor *editor) static void fill_in_info(EContactListEditor *editor) { - if (editor->card) { + if (editor->contact) { + EContactPhoto *photo; char *file_as; gboolean show_addresses = FALSE; gboolean is_evolution_list = FALSE; - EList *email_list; - EIterator *email_iter; + GList *email_list; + GList *iter; - g_object_get (editor->card, - "file_as", &file_as, - "email", &email_list, - "list", &is_evolution_list, - "list_show_addresses", &show_addresses, - NULL); + file_as = e_contact_get_const (editor->contact, E_CONTACT_FILE_AS); + email_list = e_contact_get (editor->contact, E_CONTACT_EMAIL); + is_evolution_list = GPOINTER_TO_INT (e_contact_get (editor->contact, E_CONTACT_IS_LIST)); + show_addresses = GPOINTER_TO_INT (e_contact_get (editor->contact, E_CONTACT_LIST_SHOW_ADDRESSES)); gtk_editable_delete_text (GTK_EDITABLE (editor->list_name_entry), 0, -1); if (file_as) { @@ -1001,20 +1249,24 @@ fill_in_info(EContactListEditor *editor) e_contact_list_model_remove_all (E_CONTACT_LIST_MODEL (editor->model)); - email_iter = e_list_get_iterator (email_list); - - while (e_iterator_is_valid (email_iter)) { - const char *dest_xml = e_iterator_get (email_iter); - EDestination *dest; + for (iter = email_list; iter; iter = iter->next) { + char *dest_xml = iter->data; + EABDestination *dest; /* g_message ("incoming xml: [%s]", dest_xml); */ - dest = e_destination_import (dest_xml); + dest = eab_destination_import (dest_xml); if (dest != NULL) { e_contact_list_model_add_destination (E_CONTACT_LIST_MODEL (editor->model), dest); } + } + + /* XXX free email_list */ - e_iterator_next (email_iter); + photo = e_contact_get (editor->contact, E_CONTACT_LOGO); + if (photo) { + set_image_from_data (editor, photo->data, photo->length); + e_contact_photo_free (photo); } g_object_unref (email_list); } diff --git a/addressbook/gui/contact-list-editor/e-contact-list-editor.h b/addressbook/gui/contact-list-editor/e-contact-list-editor.h index 184145a0f7..62334c17bf 100644 --- a/addressbook/gui/contact-list-editor/e-contact-list-editor.h +++ b/addressbook/gui/contact-list-editor/e-contact-list-editor.h @@ -26,9 +26,8 @@ #include #include -#include "addressbook/backend/ebook/e-book.h" -#include "addressbook/backend/ebook/e-card.h" -#include "addressbook/backend/ebook/e-card-simple.h" +#include "addressbook/backend/ebook/e-book-async.h" +#include "addressbook/backend/ebook/e-contact.h" G_BEGIN_DECLS @@ -48,7 +47,7 @@ struct _EContactListEditor /* item specific fields */ EBook *book; - ECard *card; + EContact *contact; /* UI handler */ BonoboUIComponent *uic; @@ -62,12 +61,19 @@ struct _EContactListEditor GtkWidget *list_name_entry; GtkWidget *add_button; GtkWidget *remove_button; + GtkWidget *list_image_button; GtkWidget *visible_addrs_checkbutton; + GtkWidget *list_image; + int list_image_width; + int list_image_height; - /* Whether we are editing a new card or an existing one */ + char *image_buf; + int image_buf_size; + + /* Whether we are editing a new contact or an existing one */ guint is_new_list : 1; - /* Whether the card has been changed since bringing up the contact editor */ + /* Whether the contact has been changed since bringing up the contact editor */ guint changed : 1; /* Whether the contact editor will accept modifications */ @@ -83,14 +89,14 @@ struct _EContactListEditorClass /* Notification signals */ - void (* list_added) (EContactListEditor *cle, EBookStatus status, ECard *card); - void (* list_modified) (EContactListEditor *cle, EBookStatus status, ECard *card); - void (* list_deleted) (EContactListEditor *cle, EBookStatus status, ECard *card); + void (* list_added) (EContactListEditor *cle, EBookStatus status, EContact *contact); + void (* list_modified) (EContactListEditor *cle, EBookStatus status, EContact *contact); + void (* list_deleted) (EContactListEditor *cle, EBookStatus status, EContact *contact); void (* editor_closed) (EContactListEditor *cle); }; EContactListEditor *e_contact_list_editor_new (EBook *book, - ECard *list_card, + EContact *list_contact, gboolean is_new_list, gboolean editable); GType e_contact_list_editor_get_type (void); diff --git a/addressbook/gui/contact-list-editor/e-contact-list-model.c b/addressbook/gui/contact-list-editor/e-contact-list-model.c index 89354aaece..80bc29b7a9 100644 --- a/addressbook/gui/contact-list-editor/e-contact-list-model.c +++ b/addressbook/gui/contact-list-editor/e-contact-list-model.c @@ -30,7 +30,7 @@ contact_list_value_at (ETableModel *etc, int col, int row) { EContactListModel *model = E_CONTACT_LIST_MODEL (etc); - return (void *) e_destination_get_textrep (model->data[row], TRUE); + return (void *) eab_destination_get_textrep (model->data[row], TRUE); } /* This function sets the value at a particular point in our ETableModel. */ @@ -127,7 +127,7 @@ e_contact_list_model_init (GtkObject *object) model->data_alloc = 10; model->data_count = 0; - model->data = g_new (EDestination*, model->data_alloc); + model->data = g_new (EABDestination*, model->data_alloc); } GType @@ -172,16 +172,16 @@ e_contact_list_model_new () } void -e_contact_list_model_add_destination (EContactListModel *model, EDestination *dest) +e_contact_list_model_add_destination (EContactListModel *model, EABDestination *dest) { g_return_if_fail (E_IS_CONTACT_LIST_MODEL (model)); - g_return_if_fail (E_IS_DESTINATION (dest)); + g_return_if_fail (EAB_IS_DESTINATION (dest)); e_table_model_pre_change (E_TABLE_MODEL (model)); if (model->data_count + 1 >= model->data_alloc) { model->data_alloc *= 2; - model->data = g_renew (EDestination*, model->data, model->data_alloc); + model->data = g_renew (EABDestination*, model->data, model->data_alloc); } model->data[model->data_count ++] = dest; @@ -194,28 +194,28 @@ void e_contact_list_model_add_email (EContactListModel *model, const char *email) { - EDestination *new_dest; + EABDestination *new_dest; g_return_if_fail (E_IS_CONTACT_LIST_MODEL (model)); g_return_if_fail (email != NULL); - new_dest = e_destination_new (); - e_destination_set_email (new_dest, email); + new_dest = eab_destination_new (); + eab_destination_set_email (new_dest, email); e_contact_list_model_add_destination (model, new_dest); } void -e_contact_list_model_add_card (EContactListModel *model, - ECardSimple *simple) +e_contact_list_model_add_contact (EContactListModel *model, + EContact *contact) { - EDestination *new_dest; + EABDestination *new_dest; g_return_if_fail (E_IS_CONTACT_LIST_MODEL (model)); - g_return_if_fail (E_IS_CARD_SIMPLE (simple)); + g_return_if_fail (E_IS_CONTACT (contact)); - new_dest = e_destination_new (); - e_destination_set_card (new_dest, simple->card, 0); /* Hard-wired for default e-mail */ + new_dest = eab_destination_new (); + eab_destination_set_contact (new_dest, contact, 0); /* Hard-wired for default e-mail */ e_contact_list_model_add_destination (model, new_dest); } @@ -229,7 +229,7 @@ e_contact_list_model_remove_row (EContactListModel *model, int row) e_table_model_pre_change (E_TABLE_MODEL (model)); g_object_unref (model->data[row]); - memmove (model->data + row, model->data + row + 1, sizeof (EDestination*) * (model->data_count - row - 1)); + memmove (model->data + row, model->data + row + 1, sizeof (EABDestination*) * (model->data_count - row - 1)); model->data_count --; e_table_model_row_deleted (E_TABLE_MODEL (model), row); @@ -255,7 +255,7 @@ e_contact_list_model_remove_all (EContactListModel *model) } -const EDestination * +const EABDestination * e_contact_list_model_get_destination (EContactListModel *model, int row) { g_return_val_if_fail (E_IS_CONTACT_LIST_MODEL (model), NULL); diff --git a/addressbook/gui/contact-list-editor/e-contact-list-model.h b/addressbook/gui/contact-list-editor/e-contact-list-model.h index bb07d83544..92d3d9bc60 100644 --- a/addressbook/gui/contact-list-editor/e-contact-list-model.h +++ b/addressbook/gui/contact-list-editor/e-contact-list-model.h @@ -4,10 +4,9 @@ #include #include -#include "addressbook/backend/ebook/e-book.h" -#include "addressbook/backend/ebook/e-book-view.h" -#include "addressbook/backend/ebook/e-card-simple.h" -#include "addressbook/backend/ebook/e-destination.h" +#include "addressbook/backend/ebook/e-book-async.h" +#include "addressbook/backend/ebook/e-contact.h" +#include "addressbook/util/eab-destination.h" G_BEGIN_DECLS @@ -23,7 +22,7 @@ typedef struct _EContactListModelClass EContactListModelClass; struct _EContactListModel { ETableModel parent; - EDestination **data; + EABDestination **data; int data_count; int data_alloc; }; @@ -38,14 +37,14 @@ GType e_contact_list_model_get_type (void); void e_contact_list_model_construct (EContactListModel *model); ETableModel *e_contact_list_model_new (void); -void e_contact_list_model_add_destination (EContactListModel *model, EDestination *dest); +void e_contact_list_model_add_destination (EContactListModel *model, EABDestination *dest); void e_contact_list_model_add_email (EContactListModel *model, const char *email); -void e_contact_list_model_add_card (EContactListModel *model, ECardSimple *simple); +void e_contact_list_model_add_contact (EContactListModel *model, EContact *contact); void e_contact_list_model_remove_row (EContactListModel *model, int row); void e_contact_list_model_remove_all (EContactListModel *model); -const EDestination *e_contact_list_model_get_destination (EContactListModel *model, int row); +const EABDestination *e_contact_list_model_get_destination (EContactListModel *model, int row); G_END_DECLS diff --git a/addressbook/gui/merging/.cvsignore b/addressbook/gui/merging/.cvsignore index d6c55c7345..b6fa83ca4c 100644 --- a/addressbook/gui/merging/.cvsignore +++ b/addressbook/gui/merging/.cvsignore @@ -5,3 +5,4 @@ Makefile Makefile.in *.lo *.la +*.gladep diff --git a/addressbook/gui/merging/Makefile.am b/addressbook/gui/merging/Makefile.am index f30edd5745..4627f30594 100644 --- a/addressbook/gui/merging/Makefile.am +++ b/addressbook/gui/merging/Makefile.am @@ -1,7 +1,8 @@ INCLUDES = \ - -DG_LOG_DOMAIN=\"e-card-gui\" \ + -DG_LOG_DOMAIN=\"eab-contact-merging\" \ -DEVOLUTION_GLADEDIR=\""$(gladedir)"\" \ -I$(top_srcdir) \ + -I$(top_srcdir)/addressbook \ -I$(top_srcdir)/addressbook/backend \ -I$(top_builddir)/addressbook/backend \ -DG_DISABLE_DEPRECATED \ @@ -11,15 +12,17 @@ INCLUDES = \ $(EVOLUTION_ADDRESSBOOK_CFLAGS) noinst_LTLIBRARIES = \ - libecardmerging.la + libeabbookmerging.la -libecardmerging_la_SOURCES = \ - e-card-merging.c \ - e-card-merging.h +libeabbookmerging_la_SOURCES = \ + eab-contact-compare.c \ + eab-contact-compare.h \ + eab-contact-merging.c \ + eab-contact-merging.h -glade_DATA = e-card-duplicate-detected.glade \ - e-card-merging-book-commit-duplicate-detected.glade +glade_DATA = eab-contact-duplicate-detected.glade \ + eab-contact-commit-duplicate-detected.glade EXTRA_DIST = \ $(glade_DATA) diff --git a/addressbook/gui/merging/e-card-duplicate-detected.glade b/addressbook/gui/merging/e-card-duplicate-detected.glade deleted file mode 100644 index 5c287cd163..0000000000 --- a/addressbook/gui/merging/e-card-duplicate-detected.glade +++ /dev/null @@ -1,212 +0,0 @@ - - - - - - - 6 - True - Duplicate Contact Detected - GTK_WINDOW_TOPLEVEL - GTK_WIN_POS_NONE - False - True - False - True - - - - True - False - 6 - - - - True - GTK_BUTTONBOX_END - - - - True - True - True - gtk-cancel - True - GTK_RELIEF_NORMAL - 1 - - - - - - True - True - True - gtk-add - True - GTK_RELIEF_NORMAL - 0 - - - - - 0 - False - True - GTK_PACK_END - - - - - - 6 - True - 5 - 2 - False - 6 - 6 - - - - True - e_card_merging_create_old_card - 0 - 0 - Fri, 08 Jun 2001 01:33:22 GMT - - - 1 - 2 - 4 - 5 - - - - - - True - The name or email address of this contact already exists -in this folder. Would you like to add it anyway? - False - False - GTK_JUSTIFY_LEFT - False - False - 0 - 0.5 - 0 - 0 - - - 1 - 2 - 0 - 1 - fill - - - - - - True - Original Contact: - False - False - GTK_JUSTIFY_CENTER - False - False - 0 - 0.5 - 0 - 0 - - - 1 - 2 - 3 - 4 - fill - - - - - - True - New Contact: - False - False - GTK_JUSTIFY_CENTER - False - False - 0 - 0.5 - 0 - 0 - - - 1 - 2 - 1 - 2 - fill - - - - - - - True - e_card_merging_create_old_card - 0 - 0 - Fri, 08 Jun 2001 01:33:22 GMT - - - 1 - 2 - 2 - 3 - - - - - - True - 0.5 - 0 - 1 - 0 - - - - True - e_create_image_widget - malehead.png - 0 - 0 - Fri, 08 Jun 2001 00:18:39 GMT - - - - - 0 - 1 - 0 - 5 - fill - fill - - - - - 0 - True - True - - - - - - - diff --git a/addressbook/gui/merging/e-card-merging-book-commit-duplicate-detected.glade b/addressbook/gui/merging/e-card-merging-book-commit-duplicate-detected.glade deleted file mode 100644 index f7cfd259e5..0000000000 --- a/addressbook/gui/merging/e-card-merging-book-commit-duplicate-detected.glade +++ /dev/null @@ -1,212 +0,0 @@ - - - - - - - 6 - True - Duplicate Contact Detected - GTK_WINDOW_TOPLEVEL - GTK_WIN_POS_NONE - False - True - False - True - - - - True - False - 6 - - - - True - GTK_BUTTONBOX_END - - - - True - True - True - gtk-cancel - True - GTK_RELIEF_NORMAL - 1 - - - - - - True - True - True - gtk-add - True - GTK_RELIEF_NORMAL - 0 - - - - - 0 - False - True - GTK_PACK_END - - - - - - 6 - True - 5 - 2 - False - 6 - 6 - - - - True - e_card_merging_create_old_card - 0 - 0 - Fri, 08 Jun 2001 01:33:22 GMT - - - 1 - 2 - 4 - 5 - - - - - - True - The changed email or name of this contact already -exists in this folder. Would you like to add it anyway? - False - False - GTK_JUSTIFY_LEFT - False - False - 0 - 0.5 - 0 - 0 - - - 1 - 2 - 0 - 1 - fill - - - - - - True - Conflicting Contact: - False - False - GTK_JUSTIFY_CENTER - False - False - 0 - 0.5 - 0 - 0 - - - 1 - 2 - 3 - 4 - fill - - - - - - True - Changed Contact: - False - False - GTK_JUSTIFY_CENTER - False - False - 0 - 0.5 - 0 - 0 - - - 1 - 2 - 1 - 2 - fill - - - - - - - True - e_card_merging_create_old_card - 0 - 0 - Fri, 08 Jun 2001 01:33:22 GMT - - - 1 - 2 - 2 - 3 - - - - - - True - 0.5 - 0 - 1 - 0 - - - - True - e_create_image_widget - malehead.png - 0 - 0 - Fri, 08 Jun 2001 00:18:39 GMT - - - - - 0 - 1 - 0 - 5 - fill - fill - - - - - 0 - True - True - - - - - - - diff --git a/addressbook/gui/merging/e-card-merging.c b/addressbook/gui/merging/e-card-merging.c deleted file mode 100644 index f2322e772c..0000000000 --- a/addressbook/gui/merging/e-card-merging.c +++ /dev/null @@ -1,198 +0,0 @@ -/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ -/* - * Code for checking for duplicates when doing ECard work. - * - * Author: - * Christopher James Lahey - * - * Copyright 2001, Ximian, Inc. - */ - -#include - -#include "e-card-merging.h" -#include -#include -#include -#include "addressbook/gui/widgets/e-minicard-widget.h" - -typedef enum { - E_CARD_MERGING_ADD, - E_CARD_MERGING_COMMIT -} ECardMergingOpType; - -typedef struct { - ECardMergingOpType op; - EBook *book; - ECard *card; - EBookIdCallback id_cb; - EBookCallback cb; - gpointer closure; -} ECardMergingLookup; - -static void -free_lookup (ECardMergingLookup *lookup) -{ - g_object_unref (lookup->book); - g_object_unref (lookup->card); - - g_free (lookup); -} - -static void -final_id_cb (EBook *book, EBookStatus status, const char *id, gpointer closure) -{ - ECardMergingLookup *lookup = closure; - - if (lookup->id_cb) - lookup->id_cb (lookup->book, status, id, lookup->closure); - - free_lookup (lookup); -} - -static void -final_cb (EBook *book, EBookStatus status, gpointer closure) -{ - ECardMergingLookup *lookup = closure; - - if (lookup->cb) - lookup->cb (lookup->book, status, lookup->closure); - - free_lookup (lookup); -} - -static void -doit (ECardMergingLookup *lookup) -{ - if (lookup->op == E_CARD_MERGING_ADD) - e_book_add_card (lookup->book, lookup->card, final_id_cb, lookup); - else if (lookup->op == E_CARD_MERGING_COMMIT) - e_book_commit_card (lookup->book, lookup->card, final_cb, lookup); -} - -static void -cancelit (ECardMergingLookup *lookup) -{ - if (lookup->op == E_CARD_MERGING_ADD) { - if (lookup->id_cb) - final_id_cb (lookup->book, E_BOOK_STATUS_CANCELLED, NULL, lookup); - } else if (lookup->op == E_CARD_MERGING_COMMIT) { - if (lookup->cb) - final_cb (lookup->book, E_BOOK_STATUS_CANCELLED, lookup); - } -} - -static void -response (GtkWidget *dialog, int response, ECardMergingLookup *lookup) -{ - gtk_widget_destroy (dialog); - - switch (response) { - case 0: - doit (lookup); - break; - case 1: - cancelit (lookup); - break; - } -} - -static void -match_query_callback (ECard *card, ECard *match, ECardMatchType type, gpointer closure) -{ - ECardMergingLookup *lookup = closure; - - if ((gint) type <= (gint) E_CARD_MATCH_VAGUE) { - doit (lookup); - } else { - GladeXML *ui; - - GtkWidget *widget; - - if (lookup->op == E_CARD_MERGING_ADD) - ui = glade_xml_new (EVOLUTION_GLADEDIR "/e-card-duplicate-detected.glade", NULL, NULL); - else if (lookup->op == E_CARD_MERGING_COMMIT) - ui = glade_xml_new (EVOLUTION_GLADEDIR "/e-card-merging-book-commit-duplicate-detected.glade", NULL, NULL); - else { - doit (lookup); - return; - } - - widget = glade_xml_get_widget (ui, "custom-old-card"); - g_object_set (widget, - "card", match, - NULL); - - widget = glade_xml_get_widget (ui, "custom-new-card"); - g_object_set (widget, - "card", card, - NULL); - - widget = glade_xml_get_widget (ui, "dialog-duplicate-contact"); - - g_signal_connect (widget, "response", - G_CALLBACK (response), lookup); - - gtk_widget_show_all (widget); - } -} - -gboolean -e_card_merging_book_add_card (EBook *book, - ECard *card, - EBookIdCallback cb, - gpointer closure) -{ - ECardMergingLookup *lookup; - - lookup = g_new (ECardMergingLookup, 1); - - lookup->op = E_CARD_MERGING_ADD; - lookup->book = g_object_ref (book); - lookup->card = g_object_ref (card); - lookup->id_cb = cb; - lookup->closure = closure; - - e_card_locate_match_full (book, card, NULL, match_query_callback, lookup); - - return TRUE; -} - -gboolean -e_card_merging_book_commit_card (EBook *book, - ECard *card, - EBookCallback cb, - gpointer closure) -{ - ECardMergingLookup *lookup; - GList *avoid; - - lookup = g_new (ECardMergingLookup, 1); - - lookup->op = E_CARD_MERGING_COMMIT; - lookup->book = g_object_ref (book); - lookup->card = g_object_ref (card); - lookup->cb = cb; - lookup->closure = closure; - - avoid = g_list_append (NULL, card); - - e_card_locate_match_full (book, card, avoid, match_query_callback, lookup); - - g_list_free (avoid); - - return TRUE; -} - -GtkWidget * -e_card_merging_create_old_card(gchar *name, - gchar *string1, gchar *string2, - gint int1, gint int2); - -GtkWidget * -e_card_merging_create_old_card(gchar *name, - gchar *string1, gchar *string2, - gint int1, gint int2) -{ - return e_minicard_widget_new (); -} diff --git a/addressbook/gui/merging/e-card-merging.h b/addressbook/gui/merging/e-card-merging.h deleted file mode 100644 index 8ea1f9f018..0000000000 --- a/addressbook/gui/merging/e-card-merging.h +++ /dev/null @@ -1,29 +0,0 @@ -/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ -/* - * The Evolution addressbook client object. - * - * Author: - * Christopher James Lahey - * - * Copyright 2001, Ximian, Inc. - */ - -#ifndef __E_CARD_MERGING_H__ -#define __E_CARD_MERGING_H__ - -#include - -G_BEGIN_DECLS - -gboolean e_card_merging_book_add_card (EBook *book, - ECard *card, - EBookIdCallback cb, - gpointer closure); -gboolean e_card_merging_book_commit_card (EBook *book, - ECard *card, - EBookCallback cb, - gpointer closure); - -G_END_DECLS - -#endif /* ! __E_CARD_MERGING_H__ */ diff --git a/addressbook/gui/merging/eab-contact-commit-duplicate-detected.glade b/addressbook/gui/merging/eab-contact-commit-duplicate-detected.glade new file mode 100644 index 0000000000..789c465d92 --- /dev/null +++ b/addressbook/gui/merging/eab-contact-commit-duplicate-detected.glade @@ -0,0 +1,212 @@ + + + + + + + 6 + True + Duplicate Contact Detected + GTK_WINDOW_TOPLEVEL + GTK_WIN_POS_NONE + False + True + False + True + + + + True + False + 6 + + + + True + GTK_BUTTONBOX_END + + + + True + True + True + gtk-cancel + True + GTK_RELIEF_NORMAL + 1 + + + + + + True + True + True + gtk-add + True + GTK_RELIEF_NORMAL + 0 + + + + + 0 + False + True + GTK_PACK_END + + + + + + 6 + True + 5 + 2 + False + 6 + 6 + + + + True + _eab_contact_merging_create_contact_display + 0 + 0 + Sun, 05 Oct 2003 03:54:20 GMT + + + 1 + 2 + 4 + 5 + + + + + + True + The changed email or name of this contact already +exists in this folder. Would you like to add it anyway? + False + False + GTK_JUSTIFY_LEFT + False + False + 0 + 0.5 + 0 + 0 + + + 1 + 2 + 0 + 1 + fill + + + + + + True + Conflicting Contact: + False + False + GTK_JUSTIFY_CENTER + False + False + 0 + 0.5 + 0 + 0 + + + 1 + 2 + 3 + 4 + fill + + + + + + True + Changed Contact: + False + False + GTK_JUSTIFY_CENTER + False + False + 0 + 0.5 + 0 + 0 + + + 1 + 2 + 1 + 2 + fill + + + + + + + True + _eab_contact_merging_create_contact_display + 0 + 0 + Sun, 05 Oct 2003 03:53:42 GMT + + + 1 + 2 + 2 + 3 + + + + + + True + 0.5 + 0 + 1 + 0 + + + + True + e_create_image_widget + malehead.png + 0 + 0 + Fri, 08 Jun 2001 00:18:39 GMT + + + + + 0 + 1 + 0 + 5 + fill + fill + + + + + 0 + True + True + + + + + + + diff --git a/addressbook/gui/merging/eab-contact-compare.c b/addressbook/gui/merging/eab-contact-compare.c new file mode 100644 index 0000000000..409b1bce81 --- /dev/null +++ b/addressbook/gui/merging/eab-contact-compare.c @@ -0,0 +1,736 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ + +/* + * eab-contact-compare.c + * + * Copyright (C) 2001, 2002, 2003 Ximian, Inc. + * + * Authors: Jon Trowbridge + * Chris Toshok + */ + +/* + * This program is free software; you can redistribute it and/or + * modify it under the terms of version 2 of the GNU General Public + * License as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + * USA. + */ + +#include +#include +#include +#include "util/eab-book-util.h" +#include "eab-contact-compare.h" + +/* This is an "optimistic" combiner: the best of the two outcomes is + selected. */ +static EABContactMatchType +combine_comparisons (EABContactMatchType prev, + EABContactMatchType new_info) +{ + if (new_info == EAB_CONTACT_MATCH_NOT_APPLICABLE) + return prev; + return (EABContactMatchType) MAX ((gint) prev, (gint) new_info); +} + + +/*** Name comparisons ***/ + +/* This *so* doesn't belong here... at least not implemented in a + sucky way like this. But it can be fixed later. */ + +/* This is very Anglocentric. */ +static gchar *name_synonyms[][2] = { + { "jon", "john" }, /* Ah, the hacker's perogative */ + { "joseph", "joe" }, + { "robert", "bob" }, + { "gene", "jean" }, + { "jesse", "jessie" }, + { "ian", "iain" }, + { "richard", "dick" }, + { "william", "bill" }, + { "william", "will" }, + { "anthony", "tony" }, + { "michael", "mike" }, + { "eric", "erik" }, + { "elizabeth", "liz" }, + { "jeff", "geoff" }, + { "jeff", "geoffrey" }, + { "tom", "thomas" }, + { "dave", "david" }, + { "jim", "james" }, + { "abigal", "abby" }, + { "amanda", "amy" }, + { "amanda", "manda" }, + { "jennifer", "jenny" }, + { "christopher", "chris" }, + { "rebecca", "becca" }, + { "rebecca", "becky" }, + { "anderson", "andersen" }, + { "johnson", "johnsen" }, + /* We could go on and on... */ + /* We should add soundex here. */ + { NULL, NULL } +}; + +static gboolean +name_fragment_match (const gchar *a, const gchar *b, gboolean strict) +{ + gint len; + + if (!(a && b && *a && *b)) + return FALSE; + + /* If we are in 'strict' mode, b must match the beginning of a. + So "Robert", "Rob" would match, but "Robert", "Robbie" wouldn't. + + If strict is FALSE, it is sufficient for the strings to share + some leading characters. In this case, "Robert" and "Robbie" + would match, as would "Dave" and "Dan". */ + + if (strict) { + len = g_utf8_strlen (b, -1); + } else { + len = MIN (g_utf8_strlen (a, -1), g_utf8_strlen (b, -1)); + } + + return !e_utf8_casefold_collate_len (a, b, len); +} + +static gboolean +name_fragment_match_with_synonyms (const gchar *a, const gchar *b, gboolean strict) +{ + gint i; + + if (!(a && b && *a && *b)) + return FALSE; + + if (name_fragment_match (a, b, strict)) + return TRUE; + + /* Check for nicknames. Yes, the linear search blows. */ + for (i=0; name_synonyms[i][0]; ++i) { + + if (!e_utf8_casefold_collate (name_synonyms[i][0], a) + && !e_utf8_casefold_collate (name_synonyms[i][1], b)) + return TRUE; + + if (!e_utf8_casefold_collate (name_synonyms[i][0], b) + && !e_utf8_casefold_collate (name_synonyms[i][1], a)) + return TRUE; + } + + return FALSE; +} + +EABContactMatchType +eab_contact_compare_name_to_string (EContact *contact, const gchar *str) +{ + return eab_contact_compare_name_to_string_full (contact, str, FALSE, NULL, NULL, NULL); +} + +EABContactMatchType +eab_contact_compare_name_to_string_full (EContact *contact, const gchar *str, gboolean allow_partial_matches, + gint *matched_parts_out, EABContactMatchPart *first_matched_part_out, gint *matched_character_count_out) +{ + gchar **namev, **givenv = NULL, **addv = NULL, **familyv = NULL; + + gint matched_parts = EAB_CONTACT_MATCH_PART_NONE; + EABContactMatchPart first_matched_part = EAB_CONTACT_MATCH_PART_NONE; + EABContactMatchPart this_part_match = EAB_CONTACT_MATCH_PART_NOT_APPLICABLE; + EABContactMatchType match_type; + EContactName *contact_name; + + gint match_count = 0, matched_character_count = 0, fragment_count; + gint i, j; + gchar *str_cpy, *s; + + g_return_val_if_fail (E_IS_CONTACT (contact), EAB_CONTACT_MATCH_NOT_APPLICABLE); + + if (!e_contact_get_const (contact, E_CONTACT_FULL_NAME)) + return EAB_CONTACT_MATCH_NOT_APPLICABLE; + if (str == NULL) + return EAB_CONTACT_MATCH_NOT_APPLICABLE; + + str_cpy = s = g_strdup (str); + while (*s) { + if (*s == ',' || *s == '"') + *s = ' '; + ++s; + } + namev = g_strsplit (str_cpy, " ", 0); + g_free (str_cpy); + + contact_name = e_contact_get (contact, E_CONTACT_NAME); + + if (contact_name->given) + givenv = g_strsplit (contact_name->given, " ", 0); + if (contact_name->additional) + addv = g_strsplit (contact_name->additional, " ", 0); + if (contact_name->family) + familyv = g_strsplit (contact_name->family, " ", 0); + + e_contact_name_free (contact_name); + + fragment_count = 0; + for (i = 0; givenv && givenv[i]; ++i) + ++fragment_count; + for (i = 0; addv && addv[i]; ++i) + ++fragment_count; + for (i = 0; familyv && familyv[i]; ++i) + ++fragment_count; + + for (i = 0; namev[i] && this_part_match != EAB_CONTACT_MATCH_PART_NONE; ++i) { + + if (*namev[i]) { + + this_part_match = EAB_CONTACT_MATCH_PART_NONE; + + /* When we are allowing partials, we are strict about the matches we allow. + Does this make sense? Not really, but it does the right thing for the purposes + of completion. */ + + if (givenv && this_part_match == EAB_CONTACT_MATCH_PART_NONE) { + for (j = 0; givenv[j]; ++j) { + if (name_fragment_match_with_synonyms (givenv[j], namev[i], allow_partial_matches)) { + + this_part_match = EAB_CONTACT_MATCH_PART_GIVEN_NAME; + + /* We remove a piece of a name once it has been matched against, so + that "john john" won't match "john doe". */ + g_free (givenv[j]); + givenv[j] = g_strdup (""); + break; + } + } + } + + if (addv && this_part_match == EAB_CONTACT_MATCH_PART_NONE) { + for (j = 0; addv[j]; ++j) { + if (name_fragment_match_with_synonyms (addv[j], namev[i], allow_partial_matches)) { + + this_part_match = EAB_CONTACT_MATCH_PART_ADDITIONAL_NAME; + + g_free (addv[j]); + addv[j] = g_strdup (""); + break; + } + } + } + + if (familyv && this_part_match == EAB_CONTACT_MATCH_PART_NONE) { + for (j = 0; familyv[j]; ++j) { + if (allow_partial_matches ? name_fragment_match_with_synonyms (familyv[j], namev[i], allow_partial_matches) + : !e_utf8_casefold_collate (familyv[j], namev[i])) { + + this_part_match = EAB_CONTACT_MATCH_PART_FAMILY_NAME; + + g_free (familyv[j]); + familyv[j] = g_strdup (""); + break; + } + } + } + + if (this_part_match != EAB_CONTACT_MATCH_PART_NONE) { + ++match_count; + matched_character_count += g_utf8_strlen (namev[i], -1); + matched_parts |= this_part_match; + if (first_matched_part == EAB_CONTACT_MATCH_PART_NONE) + first_matched_part = this_part_match; + } + } + } + + match_type = EAB_CONTACT_MATCH_NONE; + + if (this_part_match != EAB_CONTACT_MATCH_PART_NONE) { + + if (match_count > 0) + match_type = EAB_CONTACT_MATCH_VAGUE; + + if (fragment_count == match_count) { + + match_type = EAB_CONTACT_MATCH_EXACT; + + } else if (fragment_count == match_count + 1) { + + match_type = EAB_CONTACT_MATCH_PARTIAL; + + } + } + + if (matched_parts_out) + *matched_parts_out = matched_parts; + if (first_matched_part_out) + *first_matched_part_out = first_matched_part; + if (matched_character_count_out) + *matched_character_count_out = matched_character_count; + + g_strfreev (namev); + g_strfreev (givenv); + g_strfreev (addv); + g_strfreev (familyv); + + return match_type; +} + +EABContactMatchType +eab_contact_compare_name (EContact *contact1, EContact *contact2) +{ + EContactName *a, *b; + gint matches=0, possible=0; + gboolean given_match = FALSE, additional_match = FALSE, family_match = FALSE; + + g_return_val_if_fail (E_IS_CONTACT (contact1), EAB_CONTACT_MATCH_NOT_APPLICABLE); + g_return_val_if_fail (E_IS_CONTACT (contact2), EAB_CONTACT_MATCH_NOT_APPLICABLE); + + a = e_contact_get (contact1, E_CONTACT_NAME); + b = e_contact_get (contact2, E_CONTACT_NAME); + + if (a == NULL || b == NULL) + return EAB_CONTACT_MATCH_NOT_APPLICABLE; + + if (a->given && b->given) { + ++possible; + if (name_fragment_match_with_synonyms (a->given, b->given, FALSE /* both inputs are complete */)) { + ++matches; + given_match = TRUE; + } + } + + if (a->additional && b->additional) { + ++possible; + if (name_fragment_match_with_synonyms (a->additional, b->additional, FALSE /* both inputs are complete */)) { + ++matches; + additional_match = TRUE; + } + } + + if (a->family && b->family) { + ++possible; + /* We don't allow "loose matching" (i.e. John vs. Jon) on family names */ + if (! e_utf8_casefold_collate (a->family, b->family)) { + ++matches; + family_match = TRUE; + } + } + + e_contact_name_free (a); + e_contact_name_free (b); + + /* Now look at the # of matches and try to intelligently map + an EAB_CONTACT_MATCH_* type to it. Special consideration is given + to family-name matches. */ + + if (possible == 0) + return EAB_CONTACT_MATCH_NOT_APPLICABLE; + + if (possible == 1) + return family_match ? EAB_CONTACT_MATCH_VAGUE : EAB_CONTACT_MATCH_NONE; + + if (possible == matches) + return family_match ? EAB_CONTACT_MATCH_EXACT : EAB_CONTACT_MATCH_PARTIAL; + + if (possible == matches+1) + return family_match ? EAB_CONTACT_MATCH_VAGUE : EAB_CONTACT_MATCH_NONE; + + return EAB_CONTACT_MATCH_NONE; +} + + +/*** Nickname Comparisons ***/ + +EABContactMatchType +eab_contact_compare_nickname (EContact *contact1, EContact *contact2) +{ + g_return_val_if_fail (contact1 && E_IS_CONTACT (contact1), EAB_CONTACT_MATCH_NOT_APPLICABLE); + g_return_val_if_fail (contact2 && E_IS_CONTACT (contact2), EAB_CONTACT_MATCH_NOT_APPLICABLE); + + return EAB_CONTACT_MATCH_NOT_APPLICABLE; +} + + + +/*** E-mail Comparisons ***/ + +static gboolean +match_email_username (const gchar *addr1, const gchar *addr2) +{ + gint c1, c2; + if (addr1 == NULL || addr2 == NULL) + return FALSE; + + while (*addr1 && *addr2 && *addr1 != '@' && *addr2 != '@') { + c1 = isupper (*addr1) ? tolower (*addr1) : *addr1; + c2 = isupper (*addr2) ? tolower (*addr2) : *addr2; + if (c1 != c2) + return FALSE; + ++addr1; + ++addr2; + } + + return *addr1 == *addr2; +} + +static gboolean +match_email_hostname (const gchar *addr1, const gchar *addr2) +{ + gint c1, c2; + gboolean seen_at1, seen_at2; + if (addr1 == NULL || addr2 == NULL) + return FALSE; + + /* Walk to the end of each string. */ + seen_at1 = FALSE; + if (*addr1) { + while (*addr1) { + if (*addr1 == '@') + seen_at1 = TRUE; + ++addr1; + } + --addr1; + } + + seen_at2 = FALSE; + if (*addr2) { + while (*addr2) { + if (*addr2 == '@') + seen_at2 = TRUE; + ++addr2; + } + --addr2; + } + + if (!seen_at1 && !seen_at2) + return TRUE; + if (!seen_at1 || !seen_at2) + return FALSE; + + while (*addr1 != '@' && *addr2 != '@') { + c1 = isupper (*addr1) ? tolower (*addr1) : *addr1; + c2 = isupper (*addr2) ? tolower (*addr2) : *addr2; + if (c1 != c2) + return FALSE; + --addr1; + --addr2; + } + + /* This will match bob@foo.ximian.com and bob@ximian.com */ + return *addr1 == '.' || *addr2 == '.'; +} + +static EABContactMatchType +compare_email_addresses (const gchar *addr1, const gchar *addr2) +{ + if (addr1 == NULL || *addr1 == 0 || + addr2 == NULL || *addr2 == 0) + return EAB_CONTACT_MATCH_NOT_APPLICABLE; + + if (match_email_username (addr1, addr2)) + return match_email_hostname (addr1, addr2) ? EAB_CONTACT_MATCH_EXACT : EAB_CONTACT_MATCH_VAGUE; + + return EAB_CONTACT_MATCH_NONE; +} + +EABContactMatchType +eab_contact_compare_email (EContact *contact1, EContact *contact2) +{ + EABContactMatchType match = EAB_CONTACT_MATCH_NOT_APPLICABLE; + GList *contact1_email, *contact2_email; + GList *i1, *i2; + + g_return_val_if_fail (contact1 && E_IS_CONTACT (contact1), EAB_CONTACT_MATCH_NOT_APPLICABLE); + g_return_val_if_fail (contact2 && E_IS_CONTACT (contact2), EAB_CONTACT_MATCH_NOT_APPLICABLE); + + contact1_email = e_contact_get (contact1, E_CONTACT_EMAIL); + contact2_email = e_contact_get (contact2, E_CONTACT_EMAIL); + + if (contact1_email == NULL || contact2_email == NULL) { + g_list_foreach (contact1_email, (GFunc)g_free, NULL); + g_list_free (contact1_email); + + g_list_foreach (contact2_email, (GFunc)g_free, NULL); + g_list_free (contact2_email); + return EAB_CONTACT_MATCH_NOT_APPLICABLE; + } + + i1 = contact1_email; + + /* Do pairwise-comparisons on all of the e-mail addresses. If + we find an exact match, there is no reason to keep + checking. */ + while (i1 && match != EAB_CONTACT_MATCH_EXACT) { + char *addr1 = (char *) i1->data; + + i2 = contact2_email; + while (i2 && match != EAB_CONTACT_MATCH_EXACT) { + char *addr2 = (char *) i2->data; + + match = combine_comparisons (match, compare_email_addresses (addr1, addr2)); + + i2 = i2->next; + } + + i1 = i1->next; + } + + g_list_foreach (contact1_email, (GFunc)g_free, NULL); + g_list_free (contact1_email); + + g_list_foreach (contact2_email, (GFunc)g_free, NULL); + g_list_free (contact2_email); + + return match; +} + +EABContactMatchType +eab_contact_compare_address (EContact *contact1, EContact *contact2) +{ + g_return_val_if_fail (contact1 && E_IS_CONTACT (contact1), EAB_CONTACT_MATCH_NOT_APPLICABLE); + g_return_val_if_fail (contact2 && E_IS_CONTACT (contact2), EAB_CONTACT_MATCH_NOT_APPLICABLE); + + /* Unimplemented */ + + return EAB_CONTACT_MATCH_NOT_APPLICABLE; +} + +EABContactMatchType +eab_contact_compare_telephone (EContact *contact1, EContact *contact2) +{ + g_return_val_if_fail (contact1 && E_IS_CONTACT (contact1), EAB_CONTACT_MATCH_NOT_APPLICABLE); + g_return_val_if_fail (contact2 && E_IS_CONTACT (contact2), EAB_CONTACT_MATCH_NOT_APPLICABLE); + + /* Unimplemented */ + + return EAB_CONTACT_MATCH_NOT_APPLICABLE; +} + +EABContactMatchType +eab_contact_compare (EContact *contact1, EContact *contact2) +{ + EABContactMatchType result; + + g_return_val_if_fail (contact1 && E_IS_CONTACT (contact1), EAB_CONTACT_MATCH_NOT_APPLICABLE); + g_return_val_if_fail (contact2 && E_IS_CONTACT (contact2), EAB_CONTACT_MATCH_NOT_APPLICABLE); + + result = EAB_CONTACT_MATCH_NONE; + result = combine_comparisons (result, eab_contact_compare_name (contact1, contact2)); + result = combine_comparisons (result, eab_contact_compare_nickname (contact1, contact2)); + result = combine_comparisons (result, eab_contact_compare_email (contact1, contact2)); + result = combine_comparisons (result, eab_contact_compare_address (contact1, contact2)); + result = combine_comparisons (result, eab_contact_compare_telephone (contact1, contact2)); + + return result; +} + +typedef struct _MatchSearchInfo MatchSearchInfo; +struct _MatchSearchInfo { + EContact *contact; + GList *avoid; + EABContactMatchQueryCallback cb; + gpointer closure; +}; + +static void +match_search_info_free (MatchSearchInfo *info) +{ + if (info) { + g_object_unref (info->contact); + + /* This should already have been deallocated, but just in case... */ + if (info->avoid) { + g_list_foreach (info->avoid, (GFunc) g_object_unref, NULL); + g_list_free (info->avoid); + info->avoid = NULL; + } + + g_free (info); + } +} + +static void +query_cb (EBook *book, EBookStatus status, GList *contacts, gpointer closure) +{ + /* XXX we need to free contacts */ + MatchSearchInfo *info = (MatchSearchInfo *) closure; + EABContactMatchType best_match = EAB_CONTACT_MATCH_NONE; + EContact *best_contact = NULL; + GList *remaining_contacts = NULL; + const GList *i; + + if (status != E_BOOK_ERROR_OK) { + info->cb (info->contact, NULL, EAB_CONTACT_MATCH_NONE, info->closure); + match_search_info_free (info); + return; + } + + /* remove the contacts we're to avoid from the list, if they're present */ + for (i = contacts; i != NULL; i = g_list_next (i)) { + EContact *this_contact = E_CONTACT (i->data); + GList *iterator; + gboolean avoid = FALSE; + for (iterator = info->avoid; iterator; iterator = iterator->next) { + if (!strcmp (e_contact_get_const (iterator->data, E_CONTACT_UID), + e_contact_get_const (this_contact, E_CONTACT_UID))) { + avoid = TRUE; + break; + } + } + if (!avoid) + remaining_contacts = g_list_prepend (remaining_contacts, this_contact); + } + + remaining_contacts = g_list_reverse (remaining_contacts); + + for (i = remaining_contacts; i != NULL; i = g_list_next (i)) { + EContact *this_contact = E_CONTACT (i->data); + EABContactMatchType this_match = eab_contact_compare (info->contact, this_contact); + if ((gint)this_match > (gint)best_match) { + best_match = this_match; + best_contact = this_contact; + } + } + + g_list_free (remaining_contacts); + + info->cb (info->contact, best_contact, best_match, info->closure); + match_search_info_free (info); +} + +#define MAX_QUERY_PARTS 10 +static void +use_common_book_cb (EBook *book, gpointer closure) +{ + MatchSearchInfo *info = (MatchSearchInfo *) closure; + EContact *contact = info->contact; + EContactName *contact_name; + GList *contact_email; + gchar *query_parts[MAX_QUERY_PARTS]; + gint p=0; + gchar *query, *qj; + int i; + + if (book == NULL) { + info->cb (info->contact, NULL, EAB_CONTACT_MATCH_NONE, info->closure); + match_search_info_free (info); + return; + } + + contact_name = e_contact_get (contact, E_CONTACT_NAME); + if (contact_name) { + if (contact_name->given && *contact_name->given) + query_parts[p++] = g_strdup_printf ("(contains \"full_name\" \"%s\")", contact_name->given); + + if (contact_name->additional && *contact_name->additional) + query_parts[p++] = g_strdup_printf ("(contains \"full_name\" \"%s\")", contact_name->additional); + + if (contact_name->family && *contact_name->family) + query_parts[p++] = g_strdup_printf ("(contains \"full_name\" \"%s\")", contact_name->family); + + e_contact_name_free (contact_name); + } + + contact_email = e_contact_get (contact, E_CONTACT_EMAIL); + if (contact_email) { + GList *iter; + for (iter = contact_email; iter && p < MAX_QUERY_PARTS; iter = iter->next) { + gchar *addr = g_strdup (iter->data); + if (addr && *addr) { + gchar *s = addr; + while (*s) { + if (*s == '@') { + *s = '\0'; + break; + } + ++s; + } + query_parts[p++] = g_strdup_printf ("(beginswith \"email\" \"%s\")", addr); + g_free (addr); + } + } + } + g_list_foreach (contact_email, (GFunc)g_free, NULL); + g_list_free (contact_email); + + + /* Build up our full query from the parts. */ + query_parts[p] = NULL; + qj = g_strjoinv (" ", query_parts); + for(i = 0; query_parts[i] != NULL; i++) + g_free(query_parts[i]); + if (p > 0) { + query = g_strdup_printf ("(or %s)", qj); + g_free (qj); + } else { + query = qj; + } + + if (query && *query) + e_book_async_get_contacts (book, query, query_cb, info); + else + query_cb (book, E_BOOK_ERROR_OK, NULL, info); + + g_free (query); +} + +void +eab_contact_locate_match (EContact *contact, EABContactMatchQueryCallback cb, gpointer closure) +{ + MatchSearchInfo *info; + + g_return_if_fail (contact && E_IS_CONTACT (contact)); + g_return_if_fail (cb != NULL); + + info = g_new (MatchSearchInfo, 1); + info->contact = contact; + g_object_ref (contact); + info->cb = cb; + info->closure = closure; + info->avoid = NULL; + + addressbook_load_default_book (use_common_book_cb, info); +} + +/** + * e_contact_locate_match_full: + * @book: The book to look in. If this is NULL, use the default + * addressbook. + * @contact: The contact to compare to. + * @avoid: A list of contacts to not match. These will not show up in the search. + * @cb: The function to call. + * @closure: The closure to add to the call. + * + * Look for the best match and return it using the EABContactMatchQueryCallback. + **/ +void +eab_contact_locate_match_full (EBook *book, EContact *contact, GList *avoid, EABContactMatchQueryCallback cb, gpointer closure) +{ + MatchSearchInfo *info; + + g_return_if_fail (contact && E_IS_CONTACT (contact)); + g_return_if_fail (cb != NULL); + + info = g_new (MatchSearchInfo, 1); + info->contact = contact; + g_object_ref (contact); + info->cb = cb; + info->closure = closure; + info->avoid = g_list_copy (avoid); + g_list_foreach (info->avoid, (GFunc) g_object_ref, NULL); + + if (book) + use_common_book_cb (book, info); + else + addressbook_load_default_book (use_common_book_cb, info); +} + diff --git a/addressbook/gui/merging/eab-contact-compare.h b/addressbook/gui/merging/eab-contact-compare.h new file mode 100644 index 0000000000..07a9cd7e35 --- /dev/null +++ b/addressbook/gui/merging/eab-contact-compare.h @@ -0,0 +1,73 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ + +/* + * eab-contact-compare.h + * + * Copyright (C) 2001,2002,2003 Ximian, Inc. + * + * Authors: Jon Trowbridge + * Chris Toshok + */ + +/* + * This program is free software; you can redistribute it and/or + * modify it under the terms of version 2 of the GNU General Public + * License as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + * USA. + */ + +#ifndef __EAB_CONTACT_COMPARE_H__ +#define __EAB_CONTACT_COMPARE_H__ + +#include "ebook/e-book.h" +#include "ebook/e-contact.h" + +typedef enum { + EAB_CONTACT_MATCH_NOT_APPLICABLE = 0, + EAB_CONTACT_MATCH_NONE = 1, + EAB_CONTACT_MATCH_VAGUE = 2, + EAB_CONTACT_MATCH_PARTIAL = 3, + EAB_CONTACT_MATCH_EXACT = 4 +} EABContactMatchType; + +typedef enum { + EAB_CONTACT_MATCH_PART_NOT_APPLICABLE = -1, + EAB_CONTACT_MATCH_PART_NONE = 0, + EAB_CONTACT_MATCH_PART_GIVEN_NAME = 1<<0, + EAB_CONTACT_MATCH_PART_ADDITIONAL_NAME = 1<<2, + EAB_CONTACT_MATCH_PART_FAMILY_NAME = 1<<3 +} EABContactMatchPart; + +typedef void (*EABContactMatchQueryCallback) (EContact *contact, EContact *match, EABContactMatchType type, gpointer closure); + +EABContactMatchType eab_contact_compare_name_to_string (EContact *contact, const gchar *str); + +EABContactMatchType eab_contact_compare_name_to_string_full (EContact *contact, const gchar *str, + gboolean allow_partial_matches, + gint *matched_parts, EABContactMatchPart *first_matched_part, + gint *matched_character_count); + +EABContactMatchType eab_contact_compare_name (EContact *contact1, EContact *contact2); +EABContactMatchType eab_contact_compare_nickname (EContact *contact1, EContact *contact2); +EABContactMatchType eab_contact_compare_email (EContact *contact1, EContact *contact2); +EABContactMatchType eab_contact_compare_address (EContact *contact1, EContact *contact2); +EABContactMatchType eab_contact_compare_telephone (EContact *contact1, EContact *contact2); + +EABContactMatchType eab_contact_compare (EContact *contact1, EContact *contact2); + +void eab_contact_locate_match (EContact *contact, EABContactMatchQueryCallback cb, gpointer closure); +void eab_contact_locate_match_full (EBook *book, EContact *contact, GList *avoid, EABContactMatchQueryCallback cb, gpointer closure); + + + +#endif /* __E_CONTACT_COMPARE_H__ */ + diff --git a/addressbook/gui/merging/eab-contact-duplicate-detected.glade b/addressbook/gui/merging/eab-contact-duplicate-detected.glade new file mode 100644 index 0000000000..c44547fb92 --- /dev/null +++ b/addressbook/gui/merging/eab-contact-duplicate-detected.glade @@ -0,0 +1,212 @@ + + + + + + + 6 + True + Duplicate Contact Detected + GTK_WINDOW_TOPLEVEL + GTK_WIN_POS_NONE + False + True + False + True + + + + True + False + 6 + + + + True + GTK_BUTTONBOX_END + + + + True + True + True + gtk-cancel + True + GTK_RELIEF_NORMAL + 1 + + + + + + True + True + True + gtk-add + True + GTK_RELIEF_NORMAL + 0 + + + + + 0 + False + True + GTK_PACK_END + + + + + + 6 + True + 5 + 2 + False + 6 + 6 + + + + True + _eab_contact_merging_create_contact_display + 0 + 0 + Sun, 05 Oct 2003 03:55:10 GMT + + + 1 + 2 + 4 + 5 + + + + + + True + The name or email address of this contact already exists +in this folder. Would you like to add it anyway? + False + False + GTK_JUSTIFY_LEFT + False + False + 0 + 0.5 + 0 + 0 + + + 1 + 2 + 0 + 1 + fill + + + + + + True + Original Contact: + False + False + GTK_JUSTIFY_CENTER + False + False + 0 + 0.5 + 0 + 0 + + + 1 + 2 + 3 + 4 + fill + + + + + + True + New Contact: + False + False + GTK_JUSTIFY_CENTER + False + False + 0 + 0.5 + 0 + 0 + + + 1 + 2 + 1 + 2 + fill + + + + + + + True + _eab_contact_merging_create_contact_display + 0 + 0 + Sun, 05 Oct 2003 03:54:50 GMT + + + 1 + 2 + 2 + 3 + + + + + + True + 0.5 + 0 + 1 + 0 + + + + True + e_create_image_widget + malehead.png + 0 + 0 + Fri, 08 Jun 2001 00:18:39 GMT + + + + + 0 + 1 + 0 + 5 + fill + fill + + + + + 0 + True + True + + + + + + + diff --git a/addressbook/gui/merging/eab-contact-merging.c b/addressbook/gui/merging/eab-contact-merging.c new file mode 100644 index 0000000000..38a3c188b2 --- /dev/null +++ b/addressbook/gui/merging/eab-contact-merging.c @@ -0,0 +1,197 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ +/* + * Code for checking for duplicates when doing EContact work. + * + * Authors: + * Christopher James Lahey + * Chris Toshok + * + * Copyright (C) 2001, 2002, 2003, Ximian, Inc. + */ + +#include + +#include "eab-contact-merging.h" +#include "eab-contact-compare.h" +#include +#include +#include "addressbook/gui/widgets/eab-contact-display.h" + +typedef enum { + E_CONTACT_MERGING_ADD, + E_CONTACT_MERGING_COMMIT +} EContactMergingOpType; + +typedef struct { + EContactMergingOpType op; + EBook *book; + EContact *contact; + EBookIdCallback id_cb; + EBookCallback cb; + gpointer closure; +} EContactMergingLookup; + +static void +free_lookup (EContactMergingLookup *lookup) +{ + g_object_unref (lookup->book); + g_object_unref (lookup->contact); + + g_free (lookup); +} + +static void +final_id_cb (EBook *book, EBookStatus status, const char *id, gpointer closure) +{ + EContactMergingLookup *lookup = closure; + + if (lookup->id_cb) + lookup->id_cb (lookup->book, status, id, lookup->closure); + + free_lookup (lookup); +} + +static void +final_cb (EBook *book, EBookStatus status, gpointer closure) +{ + EContactMergingLookup *lookup = closure; + + if (lookup->cb) + lookup->cb (lookup->book, status, lookup->closure); + + free_lookup (lookup); +} + +static void +doit (EContactMergingLookup *lookup) +{ + if (lookup->op == E_CONTACT_MERGING_ADD) + e_book_async_add_contact (lookup->book, lookup->contact, final_id_cb, lookup); + else if (lookup->op == E_CONTACT_MERGING_COMMIT) + e_book_async_commit_contact (lookup->book, lookup->contact, final_cb, lookup); +} + +static void +cancelit (EContactMergingLookup *lookup) +{ + if (lookup->op == E_CONTACT_MERGING_ADD) { + if (lookup->id_cb) + final_id_cb (lookup->book, E_BOOK_ERROR_CANCELLED, NULL, lookup); + } else if (lookup->op == E_CONTACT_MERGING_COMMIT) { + if (lookup->cb) + final_cb (lookup->book, E_BOOK_ERROR_CANCELLED, lookup); + } +} + +static void +response (GtkWidget *dialog, int response, EContactMergingLookup *lookup) +{ + gtk_widget_destroy (dialog); + + switch (response) { + case 0: + doit (lookup); + break; + case 1: + cancelit (lookup); + break; + } +} + +static void +match_query_callback (EContact *contact, EContact *match, EABContactMatchType type, gpointer closure) +{ + EContactMergingLookup *lookup = closure; + + if ((gint) type <= (gint) EAB_CONTACT_MATCH_VAGUE) { + doit (lookup); + } else { + GladeXML *ui; + + GtkWidget *widget; + + if (lookup->op == E_CONTACT_MERGING_ADD) + ui = glade_xml_new (EVOLUTION_GLADEDIR "/eab-contact-duplicate-detected.glade", NULL, NULL); + else if (lookup->op == E_CONTACT_MERGING_COMMIT) + ui = glade_xml_new (EVOLUTION_GLADEDIR "/eab-contact-merging-commit-duplicate-detected.glade", NULL, NULL); + else { + doit (lookup); + return; + } + + widget = glade_xml_get_widget (ui, "custom-old-contact"); + eab_contact_display_render (EAB_CONTACT_DISPLAY (widget), + match, EAB_CONTACT_DISPLAY_RENDER_COMPACT); + + widget = glade_xml_get_widget (ui, "custom-new-contact"); + eab_contact_display_render (EAB_CONTACT_DISPLAY (widget), + contact, EAB_CONTACT_DISPLAY_RENDER_COMPACT); + + widget = glade_xml_get_widget (ui, "dialog-duplicate-contact"); + + g_signal_connect (widget, "response", + G_CALLBACK (response), lookup); + + gtk_widget_show_all (widget); + } +} + +gboolean +eab_merging_book_add_contact (EBook *book, + EContact *contact, + EBookIdCallback cb, + gpointer closure) +{ + EContactMergingLookup *lookup; + + lookup = g_new (EContactMergingLookup, 1); + + lookup->op = E_CONTACT_MERGING_ADD; + lookup->book = g_object_ref (book); + lookup->contact = g_object_ref (contact); + lookup->id_cb = cb; + lookup->closure = closure; + + eab_contact_locate_match_full (book, contact, NULL, match_query_callback, lookup); + + return TRUE; +} + +gboolean +eab_merging_book_commit_contact (EBook *book, + EContact *contact, + EBookCallback cb, + gpointer closure) +{ + EContactMergingLookup *lookup; + GList *avoid; + + lookup = g_new (EContactMergingLookup, 1); + + lookup->op = E_CONTACT_MERGING_COMMIT; + lookup->book = g_object_ref (book); + lookup->contact = g_object_ref (contact); + lookup->cb = cb; + lookup->closure = closure; + + avoid = g_list_append (NULL, contact); + + eab_contact_locate_match_full (book, contact, avoid, match_query_callback, lookup); + + g_list_free (avoid); + + return TRUE; +} + +GtkWidget * +_eab_contact_merging_create_contact_display(gchar *name, + gchar *string1, gchar *string2, + gint int1, gint int2); + +GtkWidget * +_eab_contact_merging_create_contact_display(gchar *name, + gchar *string1, gchar *string2, + gint int1, gint int2) +{ + return eab_contact_display_new(); +} diff --git a/addressbook/gui/merging/eab-contact-merging.h b/addressbook/gui/merging/eab-contact-merging.h new file mode 100644 index 0000000000..6011263f31 --- /dev/null +++ b/addressbook/gui/merging/eab-contact-merging.h @@ -0,0 +1,30 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ +/* + * The Evolution addressbook client object. + * + * Authors: + * Christopher James Lahey + * Chris Toshok + * + * Copyright (C) 2001, 2002, 2003 Ximian, Inc. + */ + +#ifndef __E_CONTACT_MERGING_H__ +#define __E_CONTACT_MERGING_H__ + +#include + +G_BEGIN_DECLS + +gboolean eab_merging_book_add_contact (EBook *book, + EContact *contact, + EBookIdCallback cb, + gpointer closure); +gboolean eab_merging_book_commit_contact (EBook *book, + EContact *contact, + EBookCallback cb, + gpointer closure); + +G_END_DECLS + +#endif /* ! __EAB_CONTACT_MERGING_H__ */ diff --git a/addressbook/gui/search/e-addressbook-search-dialog.c b/addressbook/gui/search/e-addressbook-search-dialog.c index eefd170a73..a8621bf5a7 100644 --- a/addressbook/gui/search/e-addressbook-search-dialog.c +++ b/addressbook/gui/search/e-addressbook-search-dialog.c @@ -30,23 +30,23 @@ #include "e-addressbook-search-dialog.h" -static void e_addressbook_search_dialog_init (EAddressbookSearchDialog *widget); -static void e_addressbook_search_dialog_class_init (EAddressbookSearchDialogClass *klass); -static void e_addressbook_search_dialog_dispose (GObject *object); +static void eab_search_dialog_init (EABSearchDialog *widget); +static void eab_search_dialog_class_init (EABSearchDialogClass *klass); +static void eab_search_dialog_dispose (GObject *object); static GtkDialog *parent_class = NULL; #define PARENT_TYPE GTK_TYPE_DIALOG -E_MAKE_TYPE (e_addressbook_search_dialog, - "EAddressbookSearchDialog", - EAddressbookSearchDialog, - e_addressbook_search_dialog_class_init, - e_addressbook_search_dialog_init, +E_MAKE_TYPE (eab_search_dialog, + "EABSearchDialog", + EABSearchDialog, + eab_search_dialog_class_init, + eab_search_dialog_init, PARENT_TYPE) static void -e_addressbook_search_dialog_class_init (EAddressbookSearchDialogClass *klass) +eab_search_dialog_class_init (EABSearchDialogClass *klass) { GObjectClass *object_class; @@ -54,11 +54,11 @@ e_addressbook_search_dialog_class_init (EAddressbookSearchDialogClass *klass) parent_class = g_type_class_ref (PARENT_TYPE); - object_class->dispose = e_addressbook_search_dialog_dispose; + object_class->dispose = eab_search_dialog_dispose; } static GtkWidget * -get_widget (EAddressbookSearchDialog *view) +get_widget (EABSearchDialog *view) { FilterPart *part; @@ -79,7 +79,7 @@ get_widget (EAddressbookSearchDialog *view) } static char * -get_query (EAddressbookSearchDialog *view) +get_query (EABSearchDialog *view) { GString *out = g_string_new(""); char *ret; @@ -92,7 +92,7 @@ get_query (EAddressbookSearchDialog *view) } static void -dialog_response (GtkWidget *widget, int response_id, EAddressbookSearchDialog *dialog) +dialog_response (GtkWidget *widget, int response_id, EABSearchDialog *dialog) { char *query; @@ -108,7 +108,7 @@ dialog_response (GtkWidget *widget, int response_id, EAddressbookSearchDialog *d } static void -e_addressbook_search_dialog_init (EAddressbookSearchDialog *view) +eab_search_dialog_init (EABSearchDialog *view) { GtkDialog *dialog = GTK_DIALOG (view); @@ -131,19 +131,19 @@ e_addressbook_search_dialog_init (EAddressbookSearchDialog *view) } GtkWidget * -e_addressbook_search_dialog_new (EAddressbookView *addr_view) +eab_search_dialog_new (EABView *addr_view) { - EAddressbookSearchDialog *view = g_object_new (E_ADDRESSBOOK_SEARCH_DIALOG_TYPE, NULL); + EABSearchDialog *view = g_object_new (EAB_SEARCH_DIALOG_TYPE, NULL); view->view = addr_view; return GTK_WIDGET(view); } static void -e_addressbook_search_dialog_dispose (GObject *object) +eab_search_dialog_dispose (GObject *object) { - EAddressbookSearchDialog *view; + EABSearchDialog *view; - view = E_ADDRESSBOOK_SEARCH_DIALOG (object); + view = EAB_SEARCH_DIALOG (object); if (view->context) { g_object_unref(view->context); diff --git a/addressbook/gui/search/e-addressbook-search-dialog.h b/addressbook/gui/search/e-addressbook-search-dialog.h index 4be0050ca0..ef501766ea 100644 --- a/addressbook/gui/search/e-addressbook-search-dialog.h +++ b/addressbook/gui/search/e-addressbook-search-dialog.h @@ -17,8 +17,9 @@ * Free Software Foundation, Inc., 59 Temple Place - Suite 330, * Boston, MA 02111-1307, USA. */ -#ifndef __E_ADDRESSBOOK_SEARCH_DIALOG_H__ -#define __E_ADDRESSBOOK_SEARCH_DIALOG_H__ + +#ifndef __EAB_SEARCH_DIALOG_H__ +#define __EAB_SEARCH_DIALOG_H__ #include @@ -29,37 +30,37 @@ G_BEGIN_DECLS -#define E_ADDRESSBOOK_SEARCH_DIALOG_TYPE (e_addressbook_search_dialog_get_type ()) -#define E_ADDRESSBOOK_SEARCH_DIALOG(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), E_ADDRESSBOOK_SEARCH_DIALOG_TYPE, EAddressbookSearchDialog)) -#define E_ADDRESSBOOK_SEARCH_DIALOG_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), E_ADDRESSBOOK_SEARCH_DIALOG_TYPE, EAddressbookSearchDialogClass)) -#define E_IS_ADDRESSBOOK_SEARCH_DIALOG(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), E_ADDRESSBOOK_SEARCH_DIALOG_TYPE)) -#define E_IS_ADDRESSBOOK_SEARCH_DIALOG_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((obj), E_ADDRESSBOOK_SEARCH_DIALOG_TYPE)) +#define EAB_SEARCH_DIALOG_TYPE (eab_search_dialog_get_type ()) +#define EAB_SEARCH_DIALOG(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), EAB_SEARCH_DIALOG_TYPE, EABSearchDialog)) +#define EAB_SEARCH_DIALOG_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), EAB_SEARCH_DIALOG_TYPE, EABSearchDialogClass)) +#define E_IS_ADDRESSBOOK_SEARCH_DIALOG(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), EAB_SEARCH_DIALOG_TYPE)) +#define E_IS_ADDRESSBOOK_SEARCH_DIALOG_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((obj), EAB_SEARCH_DIALOG_TYPE)) -typedef struct _EAddressbookSearchDialog EAddressbookSearchDialog; -typedef struct _EAddressbookSearchDialogClass EAddressbookSearchDialogClass; +typedef struct _EABSearchDialog EABSearchDialog; +typedef struct _EABSearchDialogClass EABSearchDialogClass; -struct _EAddressbookSearchDialog +struct _EABSearchDialog { GtkDialog parent; GtkWidget *search; - EAddressbookView *view; + EABView *view; RuleContext *context; FilterRule *rule; }; -struct _EAddressbookSearchDialogClass +struct _EABSearchDialogClass { GtkDialogClass parent_class; }; -GType e_addressbook_search_dialog_get_type (void); +GType eab_search_dialog_get_type (void); -GtkWidget *e_addressbook_search_dialog_new (EAddressbookView *view); +GtkWidget *eab_search_dialog_new (EABView *view); G_END_DECLS -#endif /* __E_ADDRESSBOOK_SEARCH_DIALOG_H__ */ +#endif /* __EAB_SEARCH_DIALOG_H__ */ diff --git a/addressbook/gui/widgets/.cvsignore b/addressbook/gui/widgets/.cvsignore index d3b9ac4305..b67f65e6c3 100644 --- a/addressbook/gui/widgets/.cvsignore +++ b/addressbook/gui/widgets/.cvsignore @@ -10,8 +10,8 @@ minicard-test minicard-view-test minicard-widget-test reflow-test -e-addressbook-marshal.c -e-addressbook-marshal.h +eab-marshal.c +eab-marshal.h Evolution-Composer-stubs.c Evolution-Composer-skels.c Evolution-Composer-common.c diff --git a/addressbook/gui/widgets/Makefile.am b/addressbook/gui/widgets/Makefile.am index 2185d10764..ce441cbafb 100644 --- a/addressbook/gui/widgets/Makefile.am +++ b/addressbook/gui/widgets/Makefile.am @@ -1,9 +1,10 @@ INCLUDES = \ - -DG_LOG_DOMAIN=\"e-minicard\" \ + -DG_LOG_DOMAIN=\"eab-widgets\" \ -DEVOLUTION_ETSPECDIR=\""$(etspecdir)"\" \ -DEVOLUTION_IMAGESDIR=\""$(imagesdir)"\" \ -DEVOLUTION_GALVIEWSDIR=\""$(viewsdir)"\" \ -I$(top_srcdir) \ + -I$(top_srcdir)/addressbook \ -I$(top_srcdir)/addressbook/backend \ -I$(top_builddir)/addressbook/backend \ -I$(top_srcdir)/addressbook/gui/contact-editor \ @@ -35,37 +36,39 @@ CORBA_SOURCE_C = $(CORBA_COMPOSER_SOURCE_C) CORBA_SOURCE = $(CORBA_SOURCE_H) $(CORBA_SOURCE_C) noinst_LTLIBRARIES = \ - libeminicard.la + libeabwidgets.la -libeminicard_la_SOURCES = \ +libeabwidgets_la_SOURCES = \ $(CORBA_SOURCE) \ - e-addressbook-marshal.c \ + eab-contact-display.c \ + eab-contact-display.h \ + eab-gui-util.c \ + eab-gui-util.h \ + eab-popup-control.c \ + eab-popup-control.h \ + eab-vcard-control.c \ + eab-vcard-control.h \ + eab-marshal.c \ + e-minicard.c \ + e-minicard.h \ + e-minicard-label.c \ + e-minicard-label.h \ + e-minicard-view.c \ + e-minicard-view.h \ + e-minicard-view-widget.c \ + e-minicard-view-widget.h \ e-addressbook-reflow-adapter.c \ e-addressbook-reflow-adapter.h \ e-addressbook-table-adapter.c \ e-addressbook-table-adapter.h \ e-addressbook-model.c \ e-addressbook-model.h \ - e-addressbook-util.c \ - e-addressbook-util.h \ e-addressbook-view.c \ e-addressbook-view.h \ - e-minicard-control.c \ - e-minicard-control.h \ - e-minicard-label.c \ - e-minicard-label.h \ - e-minicard-view-widget.c \ - e-minicard-view-widget.h \ - e-minicard-view.c \ - e-minicard-view.h \ - e-minicard-widget.c \ - e-minicard-widget.h \ - e-minicard.c \ - e-minicard.h \ - gal-view-factory-minicard.c \ - gal-view-factory-minicard.h \ gal-view-minicard.c \ - gal-view-minicard.h + gal-view-minicard.h \ + gal-view-factory-minicard.c \ + gal-view-factory-minicard.h #TREEVIEW_SOURCES= e-addressbook-treeview-adapter.c \ # e-addressbook-treeview-adapter.h \ @@ -74,7 +77,7 @@ libeminicard_la_SOURCES = \ # gal-view-treeview.c \ # gal-view-treeview.h -MARSHAL_GENERATED = e-addressbook-marshal.c e-addressbook-marshal.h +MARSHAL_GENERATED = eab-marshal.c eab-marshal.h @EVO_MARSHAL_RULE@ BUILT_SOURCES = $(CORBA_SOURCE) $(MARSHAL_GENERATED) @@ -83,74 +86,8 @@ CLEANFILES = $(BUILT_SOURCES) dist-hook: cd $(distdir); rm -f $(BUILT_SOURCES) -#noinst_PROGRAMS = \ -# minicard-widget-test \ -# minicard-label-test \ -# minicard-test -## reflow-test -## minicard-view-test -# -#minicard_label_test_SOURCES = \ -# test-minicard-label.c -# -#minicard_label_test_LDADD = \ -# libeminicard.a \ -# $(EVOLUTION_ADDRESSBOOK_LIBS) \ -# $(top_builddir)/e-util/libeutil.la -# -#minicard_test_SOURCES = \ -# test-minicard.c -# -#minicard_test_LDADD = \ -# libeminicard.a \ -# $(top_builddir)/addressbook/backend/ebook/libebook.la \ -# $(top_builddir)/addressbook/gui/contact-editor/libecontacteditor.a \ -# $(top_builddir)/addressbook/gui/contact-list-editor/libecontactlisteditor.a \ -# $(top_builddir)/addressbook/printing/libecontactprint.a \ -# $(top_builddir)/addressbook/gui/merging/libecardmerging.a \ -# $(top_builddir)/widgets/misc/libemiscwidgets.la \ -# $(top_builddir)/addressbook/gui/component/select-names/libeselectnames.la \ -# $(EVOLUTION_ADDRESSBOOK_LIBS) \ -# libeminicard.a -# -#reflow_test_SOURCES = \ -# test-reflow.c -# -#reflow_test_LDADD = \ -# libeminicard.a \ -# $(top_builddir)/addressbook/backend/ebook/libebook.la \ -# $(top_builddir)/addressbook/contact-editor/libecontacteditor.a \ -# $(top_builddir)/addressbook/printing/libecontactprint.a \ -# $(top_builddir)/widgets/misc/libemiscwidgets.la \ -# $(EVOLUTION_ADDRESSBOOK_LIBS) - -#minicard_view_test_SOURCES = \ -# test-minicard-view.c - -#minicard_view_test_LDADD = \ -# $(EVOLUTION_ADDRESSBOOK_LIBS) -# libeminicard.a \ -# $(top_builddir)/addressbook/backend/ebook/libebook.la \ -# $(top_builddir)/addressbook/contact-editor/libecontacteditor.a \ -# $(top_builddir)/addressbook/printing/libecontactprint.a \ -# $(top_builddir)/widgets/misc/libemiscwidgets.la -# -#minicard_widget_test_SOURCES = \ -# e-minicard-widget-test.c -# -#minicard_widget_test_LDADD = \ -# libeminicard.a \ -# $(top_builddir)/addressbook/backend/ebook/libebook.la \ -# $(top_builddir)/addressbook/gui/contact-editor/libecontacteditor.a \ -# $(top_builddir)/addressbook/gui/contact-list-editor/libecontactlisteditor.a \ -# $(top_builddir)/addressbook/gui/component/select-names/libeselectnames.la \ -# $(top_builddir)/addressbook/printing/libecontactprint.a \ -# $(top_builddir)/widgets/misc/libemiscwidgets.la \ -# $(top_builddir)/addressbook/gui/merging/libecardmerging.a \ -# $(EVOLUTION_ADDRESSBOOK_LIBS) - etspec_DATA= e-addressbook-view.etspec EXTRA_DIST = \ $(etspec_DATA) \ - e-addressbook-marshal.list + eab-marshal.list diff --git a/addressbook/gui/widgets/e-addressbook-marshal.list b/addressbook/gui/widgets/e-addressbook-marshal.list deleted file mode 100644 index 2b34707dbb..0000000000 --- a/addressbook/gui/widgets/e-addressbook-marshal.list +++ /dev/null @@ -1,11 +0,0 @@ -INT:POINTER -NONE:NONE -NONE:BOOL -NONE:POINTER -NONE:OBJECT -NONE:ENUM -NONE:INT,INT -NONE:INT -NONE:UINT -NONE:DOUBLE -INT:POINTER diff --git a/addressbook/gui/widgets/e-addressbook-model.c b/addressbook/gui/widgets/e-addressbook-model.c index 10af915ecf..e8a1e76a38 100644 --- a/addressbook/gui/widgets/e-addressbook-model.c +++ b/addressbook/gui/widgets/e-addressbook-model.c @@ -8,25 +8,24 @@ */ #include -#include "e-addressbook-marshal.h" +#include "eab-marshal.h" #include "e-addressbook-model.h" #include #include #include #include #include -#include "e-addressbook-util.h" -#include "e-addressbook-marshal.h" +#include "eab-gui-util.h" #define PARENT_TYPE G_TYPE_OBJECT static GObjectClass *parent_class; /* - * EAddressbookModel callbacks + * EABModel callbacks * These are the callbacks that define the behavior of our custom model. */ -static void e_addressbook_model_set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec); -static void e_addressbook_model_get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec); +static void eab_model_set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec); +static void eab_model_get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec); enum { @@ -42,21 +41,19 @@ enum { SEARCH_STARTED, SEARCH_RESULT, FOLDER_BAR_MESSAGE, - CARD_ADDED, - CARD_REMOVED, - CARD_CHANGED, + CONTACT_ADDED, + CONTACT_REMOVED, + CONTACT_CHANGED, MODEL_CHANGED, STOP_STATE_CHANGED, BACKEND_DIED, LAST_SIGNAL }; -#define COLS (E_CARD_SIMPLE_FIELD_LAST) - -static guint e_addressbook_model_signals [LAST_SIGNAL] = {0, }; +static guint eab_model_signals [LAST_SIGNAL] = {0, }; static void -free_data (EAddressbookModel *model) +free_data (EABModel *model) { if (model->data) { int i; @@ -73,17 +70,17 @@ free_data (EAddressbookModel *model) } static void -remove_book_view(EAddressbookModel *model) +remove_book_view(EABModel *model) { - if (model->book_view && model->create_card_id) + if (model->book_view && model->create_contact_id) g_signal_handler_disconnect (model->book_view, - model->create_card_id); - if (model->book_view && model->remove_card_id) + model->create_contact_id); + if (model->book_view && model->remove_contact_id) g_signal_handler_disconnect (model->book_view, - model->remove_card_id); - if (model->book_view && model->modify_card_id) + model->remove_contact_id); + if (model->book_view && model->modify_contact_id) g_signal_handler_disconnect (model->book_view, - model->modify_card_id); + model->modify_contact_id); if (model->book_view && model->status_message_id) g_signal_handler_disconnect (model->book_view, model->status_message_id); @@ -91,9 +88,9 @@ remove_book_view(EAddressbookModel *model) g_signal_handler_disconnect (model->book_view, model->sequence_complete_id); - model->create_card_id = 0; - model->remove_card_id = 0; - model->modify_card_id = 0; + model->create_contact_id = 0; + model->remove_contact_id = 0; + model->modify_contact_id = 0; model->status_message_id = 0; model->sequence_complete_id = 0; @@ -109,12 +106,7 @@ remove_book_view(EAddressbookModel *model) static void addressbook_dispose(GObject *object) { - EAddressbookModel *model = E_ADDRESSBOOK_MODEL(object); - - if (model->get_view_idle) { - g_source_remove(model->get_view_idle); - model->get_view_idle = 0; - } + EABModel *model = EAB_MODEL(object); remove_book_view(model); free_data (model); @@ -135,7 +127,7 @@ addressbook_dispose(GObject *object) } if (model->query) { - g_free (model->query); + e_book_query_unref (model->query); model->query = NULL; } @@ -144,7 +136,7 @@ addressbook_dispose(GObject *object) } static void -update_folder_bar_message (EAddressbookModel *model) +update_folder_bar_message (EABModel *model) { int count; char *message; @@ -153,67 +145,68 @@ update_folder_bar_message (EAddressbookModel *model) switch (count) { case 0: - message = g_strdup (_("No cards")); + message = g_strdup (_("No contacts")); break; case 1: - message = g_strdup (_("1 card")); + message = g_strdup (_("1 contact")); break; default: - message = g_strdup_printf (_("%d cards"), count); + message = g_strdup_printf (_("%d contacts"), count); break; } g_signal_emit (model, - e_addressbook_model_signals [FOLDER_BAR_MESSAGE], 0, + eab_model_signals [FOLDER_BAR_MESSAGE], 0, message); g_free (message); } static void -create_card(EBookView *book_view, - const GList *cards, - EAddressbookModel *model) +create_contact(EBookView *book_view, + const GList *contacts, + EABModel *model) { int old_count = model->data_count; - int length = g_list_length ((GList *)cards); + int length = g_list_length ((GList *)contacts); if (model->data_count + length > model->allocated_count) { while (model->data_count + length > model->allocated_count) model->allocated_count = model->allocated_count * 2 + 1; - model->data = g_renew(ECard *, model->data, model->allocated_count); + model->data = g_renew(EContact *, model->data, model->allocated_count); } - for ( ; cards; cards = cards->next) { - model->data[model->data_count++] = cards->data; - g_object_ref (cards->data); + for ( ; contacts; contacts = contacts->next) { + model->data[model->data_count++] = contacts->data; + g_object_ref (contacts->data); } g_signal_emit (model, - e_addressbook_model_signals [CARD_ADDED], 0, + eab_model_signals [CONTACT_ADDED], 0, old_count, model->data_count - old_count); update_folder_bar_message (model); } static void -remove_card(EBookView *book_view, - GList *ids, - EAddressbookModel *model) +remove_contact(EBookView *book_view, + GList *ids, + EABModel *model) { + /* XXX we should keep a hash around instead of this O(n*m) loop */ int i = 0; GList *l; for (l = ids; l; l = l->next) { char *id = l->data; for ( i = 0; i < model->data_count; i++) { - if ( !strcmp(e_card_get_id(model->data[i]), id) ) { + if ( !strcmp(e_contact_get_const (model->data[i], E_CONTACT_UID), id) ) { g_object_unref (model->data[i]); - memmove(model->data + i, model->data + i + 1, (model->data_count - i - 1) * sizeof (ECard *)); + memmove(model->data + i, model->data + i + 1, (model->data_count - i - 1) * sizeof (EContact *)); model->data_count--; g_signal_emit (model, - e_addressbook_model_signals [CARD_REMOVED], 0, + eab_model_signals [CONTACT_REMOVED], 0, i); break; @@ -225,18 +218,19 @@ remove_card(EBookView *book_view, } static void -modify_card(EBookView *book_view, - const GList *cards, - EAddressbookModel *model) +modify_contact(EBookView *book_view, + const GList *contacts, + EABModel *model) { - for ( ; cards; cards = cards->next) { + for ( ; contacts; contacts = contacts->next) { int i; for ( i = 0; i < model->data_count; i++) { - if ( !strcmp(e_card_get_id(model->data[i]), e_card_get_id(E_CARD(cards->data))) ) { + if ( !strcmp(e_contact_get_const(model->data[i], E_CONTACT_UID), + e_contact_get_const(E_CONTACT(contacts->data), E_CONTACT_UID)) ) { g_object_unref (model->data[i]); - model->data[i] = e_card_duplicate(E_CARD(cards->data)); + model->data[i] = e_contact_duplicate(E_CONTACT(contacts->data)); g_signal_emit (model, - e_addressbook_model_signals [CARD_CHANGED], 0, + eab_model_signals [CONTACT_CHANGED], 0, i); break; } @@ -247,57 +241,57 @@ modify_card(EBookView *book_view, static void status_message (EBookView *book_view, char* status, - EAddressbookModel *model) + EABModel *model) { g_signal_emit (model, - e_addressbook_model_signals [STATUS_MESSAGE], 0, + eab_model_signals [STATUS_MESSAGE], 0, status); } static void sequence_complete (EBookView *book_view, EBookViewStatus status, - EAddressbookModel *model) + EABModel *model) { model->search_in_progress = FALSE; status_message (book_view, NULL, model); g_signal_emit (model, - e_addressbook_model_signals [SEARCH_RESULT], 0, + eab_model_signals [SEARCH_RESULT], 0, status); g_signal_emit (model, - e_addressbook_model_signals [STOP_STATE_CHANGED], 0); + eab_model_signals [STOP_STATE_CHANGED], 0); } static void writable_status (EBook *book, gboolean writable, - EAddressbookModel *model) + EABModel *model) { if (!model->editable_set) { model->editable = writable; g_signal_emit (model, - e_addressbook_model_signals [WRITABLE_STATUS], 0, + eab_model_signals [WRITABLE_STATUS], 0, writable); } } static void backend_died (EBook *book, - EAddressbookModel *model) + EABModel *model) { g_signal_emit (model, - e_addressbook_model_signals [BACKEND_DIED], 0); + eab_model_signals [BACKEND_DIED], 0); } static void -e_addressbook_model_class_init (GObjectClass *object_class) +eab_model_class_init (GObjectClass *object_class) { parent_class = g_type_class_ref (PARENT_TYPE); object_class->dispose = addressbook_dispose; - object_class->set_property = e_addressbook_model_set_property; - object_class->get_property = e_addressbook_model_get_property; + object_class->set_property = eab_model_set_property; + object_class->get_property = eab_model_get_property; g_object_class_install_property (object_class, PROP_BOOK, g_param_spec_object ("book", @@ -320,119 +314,118 @@ e_addressbook_model_class_init (GObjectClass *object_class) FALSE, G_PARAM_READWRITE)); - e_addressbook_model_signals [WRITABLE_STATUS] = + eab_model_signals [WRITABLE_STATUS] = g_signal_new ("writable_status", G_OBJECT_CLASS_TYPE (object_class), G_SIGNAL_RUN_LAST, - G_STRUCT_OFFSET (EAddressbookModelClass, writable_status), + G_STRUCT_OFFSET (EABModelClass, writable_status), NULL, NULL, - e_addressbook_marshal_NONE__BOOL, + eab_marshal_NONE__BOOL, G_TYPE_NONE, 1, G_TYPE_BOOLEAN); - e_addressbook_model_signals [STATUS_MESSAGE] = + eab_model_signals [STATUS_MESSAGE] = g_signal_new ("status_message", G_OBJECT_CLASS_TYPE (object_class), G_SIGNAL_RUN_LAST, - G_STRUCT_OFFSET (EAddressbookModelClass, status_message), + G_STRUCT_OFFSET (EABModelClass, status_message), NULL, NULL, - e_addressbook_marshal_NONE__POINTER, + eab_marshal_NONE__POINTER, G_TYPE_NONE, 1, G_TYPE_POINTER); - e_addressbook_model_signals [SEARCH_STARTED] = + eab_model_signals [SEARCH_STARTED] = g_signal_new ("search_started", G_OBJECT_CLASS_TYPE (object_class), G_SIGNAL_RUN_LAST, - G_STRUCT_OFFSET (EAddressbookModelClass, search_started), + G_STRUCT_OFFSET (EABModelClass, search_started), NULL, NULL, - e_addressbook_marshal_NONE__NONE, + eab_marshal_NONE__NONE, G_TYPE_NONE, 0); - e_addressbook_model_signals [SEARCH_RESULT] = + eab_model_signals [SEARCH_RESULT] = g_signal_new ("search_result", G_OBJECT_CLASS_TYPE (object_class), G_SIGNAL_RUN_LAST, - G_STRUCT_OFFSET (EAddressbookModelClass, search_result), + G_STRUCT_OFFSET (EABModelClass, search_result), NULL, NULL, - e_addressbook_marshal_NONE__INT, + eab_marshal_NONE__INT, G_TYPE_NONE, 1, G_TYPE_INT); - e_addressbook_model_signals [FOLDER_BAR_MESSAGE] = + eab_model_signals [FOLDER_BAR_MESSAGE] = g_signal_new ("folder_bar_message", G_OBJECT_CLASS_TYPE (object_class), G_SIGNAL_RUN_LAST, - G_STRUCT_OFFSET (EAddressbookModelClass, folder_bar_message), + G_STRUCT_OFFSET (EABModelClass, folder_bar_message), NULL, NULL, - e_addressbook_marshal_NONE__POINTER, + eab_marshal_NONE__POINTER, G_TYPE_NONE, 1, G_TYPE_POINTER); - e_addressbook_model_signals [CARD_ADDED] = - g_signal_new ("card_added", + eab_model_signals [CONTACT_ADDED] = + g_signal_new ("contact_added", G_OBJECT_CLASS_TYPE (object_class), G_SIGNAL_RUN_LAST, - G_STRUCT_OFFSET (EAddressbookModelClass, card_added), + G_STRUCT_OFFSET (EABModelClass, contact_added), NULL, NULL, - e_addressbook_marshal_NONE__INT_INT, + eab_marshal_NONE__INT_INT, G_TYPE_NONE, 2, G_TYPE_INT, G_TYPE_INT); - e_addressbook_model_signals [CARD_REMOVED] = - g_signal_new ("card_removed", + eab_model_signals [CONTACT_REMOVED] = + g_signal_new ("contact_removed", G_OBJECT_CLASS_TYPE (object_class), G_SIGNAL_RUN_LAST, - G_STRUCT_OFFSET (EAddressbookModelClass, card_removed), + G_STRUCT_OFFSET (EABModelClass, contact_removed), NULL, NULL, - e_addressbook_marshal_NONE__INT, + eab_marshal_NONE__INT, G_TYPE_NONE, 1, G_TYPE_INT); - e_addressbook_model_signals [CARD_CHANGED] = - g_signal_new ("card_changed", + eab_model_signals [CONTACT_CHANGED] = + g_signal_new ("contact_changed", G_OBJECT_CLASS_TYPE (object_class), G_SIGNAL_RUN_LAST, - G_STRUCT_OFFSET (EAddressbookModelClass, card_changed), + G_STRUCT_OFFSET (EABModelClass, contact_changed), NULL, NULL, - e_addressbook_marshal_NONE__INT, + eab_marshal_NONE__INT, G_TYPE_NONE, 1, G_TYPE_INT); - e_addressbook_model_signals [MODEL_CHANGED] = + eab_model_signals [MODEL_CHANGED] = g_signal_new ("model_changed", G_OBJECT_CLASS_TYPE (object_class), G_SIGNAL_RUN_LAST, - G_STRUCT_OFFSET (EAddressbookModelClass, model_changed), + G_STRUCT_OFFSET (EABModelClass, model_changed), NULL, NULL, - e_addressbook_marshal_NONE__NONE, + eab_marshal_NONE__NONE, G_TYPE_NONE, 0); - e_addressbook_model_signals [STOP_STATE_CHANGED] = + eab_model_signals [STOP_STATE_CHANGED] = g_signal_new ("stop_state_changed", G_OBJECT_CLASS_TYPE (object_class), G_SIGNAL_RUN_LAST, - G_STRUCT_OFFSET (EAddressbookModelClass, stop_state_changed), + G_STRUCT_OFFSET (EABModelClass, stop_state_changed), NULL, NULL, - e_addressbook_marshal_NONE__NONE, + eab_marshal_NONE__NONE, G_TYPE_NONE, 0); - e_addressbook_model_signals [BACKEND_DIED] = + eab_model_signals [BACKEND_DIED] = g_signal_new ("backend_died", G_OBJECT_CLASS_TYPE (object_class), G_SIGNAL_RUN_LAST, - G_STRUCT_OFFSET (EAddressbookModelClass, backend_died), + G_STRUCT_OFFSET (EABModelClass, backend_died), NULL, NULL, - e_addressbook_marshal_NONE__NONE, + eab_marshal_NONE__NONE, G_TYPE_NONE, 0); } static void -e_addressbook_model_init (GObject *object) +eab_model_init (GObject *object) { - EAddressbookModel *model = E_ADDRESSBOOK_MODEL(object); + EABModel *model = EAB_MODEL(object); model->book = NULL; - model->query = g_strdup("(contains \"x-evolution-any-field\" \"\")"); + model->query = e_book_query_any_field_contains (""); model->book_view = NULL; - model->get_view_idle = 0; - model->create_card_id = 0; - model->remove_card_id = 0; - model->modify_card_id = 0; + model->create_contact_id = 0; + model->remove_contact_id = 0; + model->modify_contact_id = 0; model->status_message_id = 0; model->writable_status_id = 0; model->backend_died_id = 0; @@ -449,30 +442,28 @@ e_addressbook_model_init (GObject *object) static void book_view_loaded (EBook *book, EBookStatus status, EBookView *book_view, gpointer closure) { - EAddressbookModel *model = closure; + EABModel *model = closure; - remove_book_view(model); - - if (status != E_BOOK_STATUS_SUCCESS) { - e_addressbook_error_dialog (_("Error getting book view"), status); + if (status != E_BOOK_ERROR_OK) { + eab_error_dialog (_("Error getting book view"), status); return; } model->book_view = book_view; if (model->book_view) g_object_ref (model->book_view); - model->create_card_id = g_signal_connect(model->book_view, - "card_added", - G_CALLBACK (create_card), - model); - model->remove_card_id = g_signal_connect(model->book_view, - "card_removed", - G_CALLBACK (remove_card), - model); - model->modify_card_id = g_signal_connect(model->book_view, - "card_changed", - G_CALLBACK(modify_card), - model); + model->create_contact_id = g_signal_connect(model->book_view, + "contacts_added", + G_CALLBACK (create_contact), + model); + model->remove_contact_id = g_signal_connect(model->book_view, + "contacts_removed", + G_CALLBACK (remove_contact), + model); + model->modify_contact_id = g_signal_connect(model->book_view, + "contacts_changed", + G_CALLBACK(modify_contact), + model); model->status_message_id = g_signal_connect(model->book_view, "status_message", G_CALLBACK(status_message), @@ -482,70 +473,65 @@ book_view_loaded (EBook *book, EBookStatus status, EBookView *book_view, gpointe G_CALLBACK(sequence_complete), model); - free_data (model); - model->search_in_progress = TRUE; g_signal_emit (model, - e_addressbook_model_signals [MODEL_CHANGED], 0); + eab_model_signals [MODEL_CHANGED], 0); g_signal_emit (model, - e_addressbook_model_signals [SEARCH_STARTED], 0); + eab_model_signals [SEARCH_STARTED], 0); g_signal_emit (model, - e_addressbook_model_signals [STOP_STATE_CHANGED], 0); + eab_model_signals [STOP_STATE_CHANGED], 0); + + e_book_view_start (model->book_view); } -static gboolean -get_view (EAddressbookModel *model) +static void +get_view (EABModel *model) { + gboolean success; + if (model->book && model->query) { + char *query_string = e_book_query_to_string (model->query); + + remove_book_view(model); + free_data (model); + if (model->first_get_view) { + model->first_get_view = FALSE; + if (e_book_check_static_capability (model->book, "do-initial-query")) { - e_book_get_book_view (model->book, model->query, book_view_loaded, model); + success = e_book_async_get_book_view (model->book, query_string, book_view_loaded, model); } else { - remove_book_view(model); - free_data (model); g_signal_emit (model, - e_addressbook_model_signals [MODEL_CHANGED], 0); + eab_model_signals [MODEL_CHANGED], 0); g_signal_emit (model, - e_addressbook_model_signals [STOP_STATE_CHANGED], 0); + eab_model_signals [STOP_STATE_CHANGED], 0); + g_free (query_string); + return; } - model->first_get_view = FALSE; } else - e_book_get_book_view (model->book, model->query, book_view_loaded, model); - } + success = e_book_async_get_book_view (model->book, query_string, book_view_loaded, model); - model->get_view_idle = 0; - return FALSE; -} - -ECard * -e_addressbook_model_get_card(EAddressbookModel *model, - int row) -{ - if (model->data && 0 <= row && row < model->data_count) { - ECard *card; - card = e_card_duplicate (model->data[row]); - return card; + g_free (query_string); } - return NULL; } -const ECard * -e_addressbook_model_peek_card(EAddressbookModel *model, - int row) +EContact * +eab_model_get_contact(EABModel *model, + int row) { if (model->data && 0 <= row && row < model->data_count) { - return model->data[row]; + return e_contact_duplicate (model->data[row]); } return NULL; } static void -e_addressbook_model_set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec) +eab_model_set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec) { - EAddressbookModel *model; + EABModel *model; - model = E_ADDRESSBOOK_MODEL (object); + model = EAB_MODEL (object); switch (prop_id){ case PROP_BOOK: @@ -564,10 +550,11 @@ e_addressbook_model_set_property (GObject *object, guint prop_id, const GValue * } model->book = E_BOOK(g_value_get_object (value)); if (model->book) { + if (!model->editable_set) + model->editable = e_book_is_writable (model->book); model->first_get_view = TRUE; g_object_ref (model->book); - if (model->get_view_idle == 0) - model->get_view_idle = g_idle_add((GSourceFunc)get_view, model); + get_view (model); g_signal_connect (model->book, "writable_status", G_CALLBACK (writable_status), model); @@ -578,10 +565,9 @@ e_addressbook_model_set_property (GObject *object, guint prop_id, const GValue * break; case PROP_QUERY: if (model->query) - g_free(model->query); - model->query = g_strdup(g_value_get_string (value)); - if (model->get_view_idle == 0) - model->get_view_idle = g_idle_add((GSourceFunc)get_view, model); + e_book_query_unref (model->query); + model->query = e_book_query_from_string (g_value_get_string (value)); + get_view (model); break; case PROP_EDITABLE: model->editable = g_value_get_boolean (value); @@ -594,21 +580,23 @@ e_addressbook_model_set_property (GObject *object, guint prop_id, const GValue * } static void -e_addressbook_model_get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec) +eab_model_get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec) { - EAddressbookModel *e_addressbook_model; + EABModel *eab_model; - e_addressbook_model = E_ADDRESSBOOK_MODEL (object); + eab_model = EAB_MODEL (object); switch (prop_id) { case PROP_BOOK: - g_value_set_object (value, e_addressbook_model->book); + g_value_set_object (value, eab_model->book); break; - case PROP_QUERY: - g_value_set_string (value, g_strdup(e_addressbook_model->query)); + case PROP_QUERY: { + char *query_string = e_book_query_to_string (eab_model->query); + g_value_set_string (value, query_string); break; + } case PROP_EDITABLE: - g_value_set_boolean (value, e_addressbook_model->editable); + g_value_set_boolean (value, eab_model->editable); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); @@ -617,81 +605,81 @@ e_addressbook_model_get_property (GObject *object, guint prop_id, GValue *value, } GType -e_addressbook_model_get_type (void) +eab_model_get_type (void) { static GType type = 0; if (!type) { static const GTypeInfo info = { - sizeof (EAddressbookModelClass), + sizeof (EABModelClass), NULL, /* base_init */ NULL, /* base_finalize */ - (GClassInitFunc) e_addressbook_model_class_init, + (GClassInitFunc) eab_model_class_init, NULL, /* class_finalize */ NULL, /* class_data */ - sizeof (EAddressbookModel), + sizeof (EABModel), 0, /* n_preallocs */ - (GInstanceInitFunc) e_addressbook_model_init, + (GInstanceInitFunc) eab_model_init, }; - type = g_type_register_static (PARENT_TYPE, "EAddressbookModel", &info, 0); + type = g_type_register_static (PARENT_TYPE, "EABModel", &info, 0); } return type; } -EAddressbookModel* -e_addressbook_model_new (void) +EABModel* +eab_model_new (void) { - EAddressbookModel *et; + EABModel *et; - et = g_object_new (E_TYPE_ADDRESSBOOK_MODEL, NULL); + et = g_object_new (EAB_TYPE_MODEL, NULL); return et; } -void e_addressbook_model_stop (EAddressbookModel *model) +void eab_model_stop (EABModel *model) { remove_book_view(model); g_signal_emit (model, - e_addressbook_model_signals [STOP_STATE_CHANGED], 0); + eab_model_signals [STOP_STATE_CHANGED], 0); g_signal_emit (model, - e_addressbook_model_signals [STATUS_MESSAGE], 0, + eab_model_signals [STATUS_MESSAGE], 0, "Search Interrupted."); } gboolean -e_addressbook_model_can_stop (EAddressbookModel *model) +eab_model_can_stop (EABModel *model) { return model->search_in_progress; } void -e_addressbook_model_force_folder_bar_message (EAddressbookModel *model) +eab_model_force_folder_bar_message (EABModel *model) { update_folder_bar_message (model); } int -e_addressbook_model_card_count (EAddressbookModel *model) +eab_model_contact_count (EABModel *model) { return model->data_count; } -ECard * -e_addressbook_model_card_at (EAddressbookModel *model, int index) +const EContact * +eab_model_contact_at (EABModel *model, int index) { return model->data[index]; } gboolean -e_addressbook_model_editable (EAddressbookModel *model) +eab_model_editable (EABModel *model) { return model->editable; } EBook * -e_addressbook_model_get_ebook (EAddressbookModel *model) +eab_model_get_ebook (EABModel *model) { return model->book; } diff --git a/addressbook/gui/widgets/e-addressbook-model.h b/addressbook/gui/widgets/e-addressbook-model.h index 57cfe6f729..35f9d0e87f 100644 --- a/addressbook/gui/widgets/e-addressbook-model.h +++ b/addressbook/gui/widgets/e-addressbook-model.h @@ -1,37 +1,34 @@ /* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ -#ifndef _E_ADDRESSBOOK_MODEL_H_ -#define _E_ADDRESSBOOK_MODEL_H_ +#ifndef _EAB_MODEL_H_ +#define _EAB_MODEL_H_ #include #include -#include "addressbook/backend/ebook/e-book.h" +#include "addressbook/backend/ebook/e-book-async.h" #include "addressbook/backend/ebook/e-book-view.h" -#include "addressbook/backend/ebook/e-card-simple.h" -#define E_TYPE_ADDRESSBOOK_MODEL (e_addressbook_model_get_type ()) -#define E_ADDRESSBOOK_MODEL(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), E_TYPE_ADDRESSBOOK_MODEL, EAddressbookModel)) -#define E_ADDRESSBOOK_MODEL_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), E_TYPE_ADDRESSBOOK_MODEL, EAddressbookModelClass)) -#define E_IS_ADDRESSBOOK_MODEL(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), E_TYPE_ADDRESSBOOK_MODEL)) -#define E_IS_ADDRESSBOOK_MODEL_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), E_TYPE_ADDRESSBOOK_MODEL)) +#define EAB_TYPE_MODEL (eab_model_get_type ()) +#define EAB_MODEL(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), EAB_TYPE_MODEL, EABModel)) +#define EAB_MODEL_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), EAB_TYPE_MODEL, EABModelClass)) +#define E_IS_ADDRESSBOOK_MODEL(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), EAB_TYPE_MODEL)) +#define E_IS_ADDRESSBOOK_MODEL_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), EAB_TYPE_MODEL)) -typedef struct _EAddressbookModel EAddressbookModel; -typedef struct _EAddressbookModelClass EAddressbookModelClass; +typedef struct _EABModel EABModel; +typedef struct _EABModelClass EABModelClass; -struct _EAddressbookModel { +struct _EABModel { GObject parent; /* item specific fields */ EBook *book; - char *query; + EBookQuery *query; EBookView *book_view; - int get_view_idle; - - ECard **data; + EContact **data; int data_count; int allocated_count; - int create_card_id, remove_card_id, modify_card_id; + int create_contact_id, remove_contact_id, modify_contact_id; int status_message_id, writable_status_id, sequence_complete_id; int backend_died_id; @@ -42,44 +39,42 @@ struct _EAddressbookModel { }; -struct _EAddressbookModelClass { +struct _EABModelClass { GObjectClass parent_class; /* * Signals */ - void (*writable_status) (EAddressbookModel *model, gboolean writable); - void (*search_started) (EAddressbookModel *model); - void (*search_result) (EAddressbookModel *model, EBookViewStatus status); - void (*status_message) (EAddressbookModel *model, const gchar *message); - void (*folder_bar_message) (EAddressbookModel *model, const gchar *message); - void (*card_added) (EAddressbookModel *model, gint index, gint count); - void (*card_removed) (EAddressbookModel *model, gint index); - void (*card_changed) (EAddressbookModel *model, gint index); - void (*model_changed) (EAddressbookModel *model); - void (*stop_state_changed) (EAddressbookModel *model); - void (*backend_died) (EAddressbookModel *model); + void (*writable_status) (EABModel *model, gboolean writable); + void (*search_started) (EABModel *model); + void (*search_result) (EABModel *model, EBookViewStatus status); + void (*status_message) (EABModel *model, const gchar *message); + void (*folder_bar_message) (EABModel *model, const gchar *message); + void (*contact_added) (EABModel *model, gint index, gint count); + void (*contact_removed) (EABModel *model, gint index); + void (*contact_changed) (EABModel *model, gint index); + void (*model_changed) (EABModel *model); + void (*stop_state_changed) (EABModel *model); + void (*backend_died) (EABModel *model); }; -GType e_addressbook_model_get_type (void); -EAddressbookModel *e_addressbook_model_new (void); +GType eab_model_get_type (void); +EABModel *eab_model_new (void); /* Returns object with ref count of 1. */ -ECard *e_addressbook_model_get_card (EAddressbookModel *model, - int row); -const ECard *e_addressbook_model_peek_card (EAddressbookModel *model, - int row); -EBook *e_addressbook_model_get_ebook (EAddressbookModel *model); +EContact *eab_model_get_contact (EABModel *model, + int row); +EBook *eab_model_get_ebook (EABModel *model); -void e_addressbook_model_stop (EAddressbookModel *model); -gboolean e_addressbook_model_can_stop (EAddressbookModel *model); +void eab_model_stop (EABModel *model); +gboolean eab_model_can_stop (EABModel *model); -void e_addressbook_model_force_folder_bar_message (EAddressbookModel *model); +void eab_model_force_folder_bar_message (EABModel *model); -int e_addressbook_model_card_count (EAddressbookModel *model); -ECard *e_addressbook_model_card_at (EAddressbookModel *model, - int index); -gboolean e_addressbook_model_editable (EAddressbookModel *model); +int eab_model_contact_count (EABModel *model); +const EContact *eab_model_contact_at (EABModel *model, + int index); +gboolean eab_model_editable (EABModel *model); -#endif /* _E_ADDRESSBOOK_MODEL_H_ */ +#endif /* _EAB_MODEL_H_ */ diff --git a/addressbook/gui/widgets/e-addressbook-reflow-adapter.c b/addressbook/gui/widgets/e-addressbook-reflow-adapter.c index a4cb9364b5..cf1667fec5 100644 --- a/addressbook/gui/widgets/e-addressbook-reflow-adapter.c +++ b/addressbook/gui/widgets/e-addressbook-reflow-adapter.c @@ -5,26 +5,25 @@ #include #include -#include "e-addressbook-marshal.h" +#include "eab-marshal.h" #include "e-addressbook-reflow-adapter.h" #include "e-addressbook-model.h" #include "e-addressbook-view.h" -#include "e-addressbook-util.h" +#include "eab-gui-util.h" #include "e-minicard.h" #include #include -#include "e-contact-save-as.h" #include "addressbook/printing/e-contact-print.h" #include "addressbook/printing/e-contact-print-envelope.h" struct _EAddressbookReflowAdapterPrivate { - EAddressbookModel *model; + EABModel *model; gboolean loading; - int create_card_id, remove_card_id, modify_card_id, model_changed_id; + int create_contact_id, remove_contact_id, modify_contact_id, model_changed_id; int search_started_id, search_result_id; }; @@ -53,15 +52,15 @@ unlink_model(EAddressbookReflowAdapter *adapter) { EAddressbookReflowAdapterPrivate *priv = adapter->priv; - if (priv->model && priv->create_card_id) + if (priv->model && priv->create_contact_id) g_signal_handler_disconnect (priv->model, - priv->create_card_id); - if (priv->model && priv->remove_card_id) + priv->create_contact_id); + if (priv->model && priv->remove_contact_id) g_signal_handler_disconnect (priv->model, - priv->remove_card_id); - if (priv->model && priv->modify_card_id) + priv->remove_contact_id); + if (priv->model && priv->modify_contact_id) g_signal_handler_disconnect (priv->model, - priv->modify_card_id); + priv->modify_contact_id); if (priv->model && priv->model_changed_id) g_signal_handler_disconnect (priv->model, priv->model_changed_id); @@ -72,9 +71,9 @@ unlink_model(EAddressbookReflowAdapter *adapter) g_signal_handler_disconnect (priv->model, priv->search_result_id); - priv->create_card_id = 0; - priv->remove_card_id = 0; - priv->modify_card_id = 0; + priv->create_contact_id = 0; + priv->remove_contact_id = 0; + priv->modify_contact_id = 0; priv->model_changed_id = 0; priv->search_started_id = 0; priv->search_result_id = 0; @@ -104,20 +103,6 @@ addressbook_dispose(GObject *object) EAddressbookReflowAdapter *adapter = E_ADDRESSBOOK_REFLOW_ADAPTER(object); unlink_model (adapter); - - if (G_OBJECT_CLASS (parent_class)->dispose) - (* G_OBJECT_CLASS (parent_class)->dispose) (object); -} - -static void -addressbook_finalize(GObject *object) -{ - EAddressbookReflowAdapter *adapter = E_ADDRESSBOOK_REFLOW_ADAPTER(object); - - g_free (adapter->priv); - - if (G_OBJECT_CLASS (parent_class)->finalize) - (* G_OBJECT_CLASS (parent_class)->finalize) (object); } static void @@ -132,37 +117,37 @@ addressbook_count (EReflowModel *erm) EAddressbookReflowAdapter *adapter = E_ADDRESSBOOK_REFLOW_ADAPTER(erm); EAddressbookReflowAdapterPrivate *priv = adapter->priv; - return e_addressbook_model_card_count (priv->model); + return eab_model_contact_count (priv->model); } -/* This function returns the height of the minicard in question */ +/* This function returns the height of the minicontact in question */ static int addressbook_height (EReflowModel *erm, int i, GnomeCanvasGroup *parent) { EAddressbookReflowAdapter *adapter = E_ADDRESSBOOK_REFLOW_ADAPTER(erm); EAddressbookReflowAdapterPrivate *priv = adapter->priv; - ECardSimpleField field; + EContactField field; int count = 0; char *string; - ECardSimple *simple = e_card_simple_new (e_addressbook_model_card_at (priv->model, i)); + EContact *contact = (EContact*)eab_model_contact_at (priv->model, i); PangoLayout *layout = gtk_widget_create_pango_layout (GTK_WIDGET (GNOME_CANVAS_ITEM (parent)->canvas), ""); int height; - string = e_card_simple_get(simple, E_CARD_SIMPLE_FIELD_FILE_AS); + string = e_contact_get(contact, E_CONTACT_FILE_AS); height = text_height (layout, string ? string : "") + 10.0; g_free(string); - for(field = E_CARD_SIMPLE_FIELD_FULL_NAME; field != E_CARD_SIMPLE_FIELD_LAST_SIMPLE_STRING && count < 5; field++) { + for(field = E_CONTACT_FULL_NAME; field != E_CONTACT_LAST_SIMPLE_STRING && count < 5; field++) { - if (field == E_CARD_SIMPLE_FIELD_FAMILY_NAME) + if (field == E_CONTACT_FAMILY_NAME || field == E_CONTACT_GIVEN_NAME) continue; - string = e_card_simple_get(simple, field); + string = e_contact_get(contact, field); if (string && *string) { int this_height; int field_text_height; - this_height = text_height (layout, e_card_simple_get_name(simple, field)); + this_height = text_height (layout, e_contact_pretty_name(field)); field_text_height = text_height (layout, string); if (this_height < field_text_height) @@ -177,7 +162,6 @@ addressbook_height (EReflowModel *erm, int i, GnomeCanvasGroup *parent) } height += 2; - g_object_unref (simple); g_object_unref (layout); return height; @@ -188,30 +172,31 @@ addressbook_compare (EReflowModel *erm, int n1, int n2) { EAddressbookReflowAdapter *adapter = E_ADDRESSBOOK_REFLOW_ADAPTER(erm); EAddressbookReflowAdapterPrivate *priv = adapter->priv; - ECard *card1, *card2; + EContact *contact1, *contact2; if (priv->loading) { return n1-n2; } else { - card1 = e_addressbook_model_card_at (priv->model, n1); - card2 = e_addressbook_model_card_at (priv->model, n2); + contact1 = (EContact*)eab_model_contact_at (priv->model, n1); + contact2 = (EContact*)eab_model_contact_at (priv->model, n2); - if (card1 && card2) { - char *file_as1, *file_as2; - file_as1 = card1->file_as; - file_as2 = card2->file_as; + if (contact1 && contact2) { + const char *file_as1, *file_as2; + file_as1 = e_contact_get_const (contact1, E_CONTACT_FILE_AS); + file_as2 = e_contact_get_const (contact2, E_CONTACT_FILE_AS); if (file_as1 && file_as2) return g_utf8_collate(file_as1, file_as2); if (file_as1) return -1; if (file_as2) return 1; - return strcmp(e_card_get_id(card1), e_card_get_id(card2)); + return strcmp(e_contact_get_const (contact1, E_CONTACT_UID), + e_contact_get_const (contact2, E_CONTACT_UID)); } - if (card1) + if (contact1) return -1; - if (card2) + if (contact2) return 1; return 0; } @@ -238,8 +223,8 @@ addressbook_incarnate (EReflowModel *erm, int i, GnomeCanvasGroup *parent) item = gnome_canvas_item_new(parent, e_minicard_get_type(), - "card", e_addressbook_model_card_at (priv->model, i), - "editable", e_addressbook_model_editable (priv->model), + "contact", eab_model_contact_at (priv->model, i), + "editable", eab_model_editable (priv->model), NULL); #if 0 @@ -260,14 +245,14 @@ addressbook_reincarnate (EReflowModel *erm, int i, GnomeCanvasItem *item) EAddressbookReflowAdapterPrivate *priv = adapter->priv; gnome_canvas_item_set(item, - "card", e_addressbook_model_card_at (priv->model, i), + "contact", eab_model_contact_at (priv->model, i), NULL); } static void -create_card (EAddressbookModel *model, - gint index, gint count, - EAddressbookReflowAdapter *adapter) +create_contact (EABModel *model, + gint index, gint count, + EAddressbookReflowAdapter *adapter) { e_reflow_model_items_inserted (E_REFLOW_MODEL (adapter), index, @@ -275,30 +260,30 @@ create_card (EAddressbookModel *model, } static void -remove_card (EAddressbookModel *model, - gint index, - EAddressbookReflowAdapter *adapter) +remove_contact (EABModel *model, + gint index, + EAddressbookReflowAdapter *adapter) { e_reflow_model_item_removed (E_REFLOW_MODEL (adapter), index); } static void -modify_card (EAddressbookModel *model, - gint index, - EAddressbookReflowAdapter *adapter) +modify_contact (EABModel *model, + gint index, + EAddressbookReflowAdapter *adapter) { e_reflow_model_item_changed (E_REFLOW_MODEL (adapter), index); } static void -model_changed (EAddressbookModel *model, +model_changed (EABModel *model, EAddressbookReflowAdapter *adapter) { e_reflow_model_changed (E_REFLOW_MODEL (adapter)); } static void -search_started (EAddressbookModel *model, +search_started (EABModel *model, EAddressbookReflowAdapter *adapter) { EAddressbookReflowAdapterPrivate *priv = adapter->priv; @@ -307,7 +292,7 @@ search_started (EAddressbookModel *model, } static void -search_result (EAddressbookModel *model, +search_result (EABModel *model, EBookViewStatus status, EAddressbookReflowAdapter *adapter) { @@ -387,7 +372,6 @@ e_addressbook_reflow_adapter_class_init (GObjectClass *object_class) object_class->set_property = addressbook_set_property; object_class->get_property = addressbook_get_property; object_class->dispose = addressbook_dispose; - object_class->finalize = addressbook_finalize; g_object_class_install_property (object_class, PROP_BOOK, g_param_spec_object ("book", @@ -414,7 +398,7 @@ e_addressbook_reflow_adapter_class_init (GObjectClass *object_class) g_param_spec_object ("model", _("Model"), /*_( */"XXX blurb" /*)*/, - E_TYPE_ADDRESSBOOK_MODEL, + EAB_TYPE_MODEL, G_PARAM_READABLE)); e_addressbook_reflow_adapter_signals [DRAG_BEGIN] = @@ -423,7 +407,7 @@ e_addressbook_reflow_adapter_class_init (GObjectClass *object_class) G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (EAddressbookReflowAdapterClass, drag_begin), NULL, NULL, - e_addressbook_marshal_INT__POINTER, + eab_marshal_INT__POINTER, G_TYPE_INT, 1, G_TYPE_POINTER); model_class->set_width = addressbook_set_width; @@ -443,9 +427,9 @@ e_addressbook_reflow_adapter_init (GtkObject *object) priv = adapter->priv = g_new0 (EAddressbookReflowAdapterPrivate, 1); priv->loading = FALSE; - priv->create_card_id = 0; - priv->remove_card_id = 0; - priv->modify_card_id = 0; + priv->create_contact_id = 0; + priv->remove_contact_id = 0; + priv->modify_contact_id = 0; priv->model_changed_id = 0; priv->search_started_id = 0; priv->search_result_id = 0; @@ -477,24 +461,24 @@ e_addressbook_reflow_adapter_get_type (void) void e_addressbook_reflow_adapter_construct (EAddressbookReflowAdapter *adapter, - EAddressbookModel *model) + EABModel *model) { EAddressbookReflowAdapterPrivate *priv = adapter->priv; priv->model = model; g_object_ref (priv->model); - priv->create_card_id = g_signal_connect(priv->model, - "card_added", - G_CALLBACK(create_card), + priv->create_contact_id = g_signal_connect(priv->model, + "contact_added", + G_CALLBACK(create_contact), adapter); - priv->remove_card_id = g_signal_connect(priv->model, - "card_removed", - G_CALLBACK(remove_card), + priv->remove_contact_id = g_signal_connect(priv->model, + "contact_removed", + G_CALLBACK(remove_contact), adapter); - priv->modify_card_id = g_signal_connect(priv->model, - "card_changed", - G_CALLBACK(modify_card), + priv->modify_contact_id = g_signal_connect(priv->model, + "contact_changed", + G_CALLBACK(modify_contact), adapter); priv->model_changed_id = g_signal_connect(priv->model, "model_changed", @@ -511,7 +495,7 @@ e_addressbook_reflow_adapter_construct (EAddressbookReflowAdapter *adapter, } EReflowModel * -e_addressbook_reflow_adapter_new (EAddressbookModel *model) +e_addressbook_reflow_adapter_new (EABModel *model) { EAddressbookReflowAdapter *et; @@ -523,11 +507,11 @@ e_addressbook_reflow_adapter_new (EAddressbookModel *model) } -ECard * -e_addressbook_reflow_adapter_get_card (EAddressbookReflowAdapter *adapter, - int index) +EContact * +e_addressbook_reflow_adapter_get_contact (EAddressbookReflowAdapter *adapter, + int index) { EAddressbookReflowAdapterPrivate *priv = adapter->priv; - return e_addressbook_model_get_card (priv->model, index); + return eab_model_get_contact (priv->model, index); } diff --git a/addressbook/gui/widgets/e-addressbook-reflow-adapter.h b/addressbook/gui/widgets/e-addressbook-reflow-adapter.h index 4bf131bc5c..9ba7d2cf2d 100644 --- a/addressbook/gui/widgets/e-addressbook-reflow-adapter.h +++ b/addressbook/gui/widgets/e-addressbook-reflow-adapter.h @@ -3,11 +3,8 @@ #define _E_ADDRESSBOOK_REFLOW_ADAPTER_H_ #include -#include #include "e-addressbook-model.h" -#include "addressbook/backend/ebook/e-book.h" -#include "addressbook/backend/ebook/e-book-view.h" -#include "addressbook/backend/ebook/e-card.h" +#include "addressbook/backend/ebook/e-contact.h" #define E_TYPE_ADDRESSBOOK_REFLOW_ADAPTER (e_addressbook_reflow_adapter_get_type ()) #define E_ADDRESSBOOK_REFLOW_ADAPTER(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), E_TYPE_ADDRESSBOOK_REFLOW_ADAPTER, EAddressbookReflowAdapter)) @@ -38,10 +35,10 @@ struct _EAddressbookReflowAdapterClass { GType e_addressbook_reflow_adapter_get_type (void); void e_addressbook_reflow_adapter_construct (EAddressbookReflowAdapter *adapter, - EAddressbookModel *model); -EReflowModel *e_addressbook_reflow_adapter_new (EAddressbookModel *model); + EABModel *model); +EReflowModel *e_addressbook_reflow_adapter_new (EABModel *model); /* Returns object with ref count of 1. */ -ECard *e_addressbook_reflow_adapter_get_card (EAddressbookReflowAdapter *adapter, +EContact *e_addressbook_reflow_adapter_get_contact (EAddressbookReflowAdapter *adapter, int index); #endif /* _E_ADDRESSBOOK_REFLOW_ADAPTER_H_ */ diff --git a/addressbook/gui/widgets/e-addressbook-table-adapter.c b/addressbook/gui/widgets/e-addressbook-table-adapter.c index 6a9e06da54..eb01b9b079 100644 --- a/addressbook/gui/widgets/e-addressbook-table-adapter.c +++ b/addressbook/gui/widgets/e-addressbook-table-adapter.c @@ -3,87 +3,52 @@ #include #include "e-addressbook-model.h" #include "e-addressbook-table-adapter.h" -#include "e-card-merging.h" -#include "e-addressbook-util.h" -#include "ebook/e-destination.h" +#include "eab-gui-util.h" +#include "util/eab-destination.h" #include #include #include #include struct _EAddressbookTableAdapterPrivate { - EAddressbookModel *model; + EABModel *model; - ECardSimple **simples; - int count; - - int create_card_id, remove_card_id, modify_card_id, model_changed_id; + int create_contact_id, remove_contact_id, modify_contact_id, model_changed_id; }; #define PARENT_TYPE e_table_model_get_type() static ETableModelClass *parent_class; -#define COLS (E_CARD_SIMPLE_FIELD_LAST) +#define COLS (E_CONTACT_FIELD_LAST) static void unlink_model(EAddressbookTableAdapter *adapter) { EAddressbookTableAdapterPrivate *priv = adapter->priv; - int i; g_signal_handler_disconnect (priv->model, - priv->create_card_id); + priv->create_contact_id); g_signal_handler_disconnect (priv->model, - priv->remove_card_id); + priv->remove_contact_id); g_signal_handler_disconnect (priv->model, - priv->modify_card_id); + priv->modify_contact_id); g_signal_handler_disconnect (priv->model, priv->model_changed_id); - priv->create_card_id = 0; - priv->remove_card_id = 0; - priv->modify_card_id = 0; + priv->create_contact_id = 0; + priv->remove_contact_id = 0; + priv->modify_contact_id = 0; priv->model_changed_id = 0; - /* free up the existing mapping if there is one */ - if (priv->simples) { - for (i = 0; i < priv->count; i ++) - g_object_unref (priv->simples[i]); - g_free (priv->simples); - priv->simples = NULL; - } - g_object_unref (priv->model); priv->model = NULL; } -static void -build_simple_mapping(EAddressbookTableAdapter *adapter) -{ - EAddressbookTableAdapterPrivate *priv = adapter->priv; - int i; - - /* free up the existing mapping if there is one */ - if (priv->simples) { - for (i = 0; i < priv->count; i ++) - g_object_unref (priv->simples[i]); - g_free (priv->simples); - } - - /* build up our mapping to ECardSimple*'s */ - priv->count = e_addressbook_model_card_count (priv->model); - priv->simples = g_new (ECardSimple*, priv->count); - for (i = 0; i < priv->count; i ++) { - priv->simples[i] = e_card_simple_new (e_addressbook_model_card_at (priv->model, i)); - g_object_ref (priv->simples[i]); - } -} - static void addressbook_dispose(GObject *object) { - EAddressbookTableAdapter *adapter = E_ADDRESSBOOK_TABLE_ADAPTER(object); + EAddressbookTableAdapter *adapter = EAB_TABLE_ADAPTER(object); if (adapter->priv) { unlink_model(adapter); @@ -107,30 +72,30 @@ addressbook_col_count (ETableModel *etc) static int addressbook_row_count (ETableModel *etc) { - EAddressbookTableAdapter *adapter = E_ADDRESSBOOK_TABLE_ADAPTER(etc); + EAddressbookTableAdapter *adapter = EAB_TABLE_ADAPTER(etc); EAddressbookTableAdapterPrivate *priv = adapter->priv; - return e_addressbook_model_card_count (priv->model); + return eab_model_contact_count (priv->model); } /* This function returns the value at a particular point in our ETableModel. */ static void * addressbook_value_at (ETableModel *etc, int col, int row) { - EAddressbookTableAdapter *adapter = E_ADDRESSBOOK_TABLE_ADAPTER(etc); + EAddressbookTableAdapter *adapter = EAB_TABLE_ADAPTER(etc); EAddressbookTableAdapterPrivate *priv = adapter->priv; const char *value; - if ( col >= COLS || row >= e_addressbook_model_card_count (priv->model) ) + if ( col >= COLS || row >= eab_model_contact_count (priv->model) ) return NULL; - value = e_card_simple_get_const(priv->simples[row], col); + value = e_contact_get_const((EContact*)eab_model_contact_at (priv->model, row), col); if (value && !strncmp (value, "priv; - if (e_addressbook_model_editable (priv->model)) { + if (eab_model_editable (priv->model)) { ECard *card; - if ( col >= COLS|| row >= e_addressbook_model_card_count (priv->model) ) + if ( col >= COLS|| row >= eab_model_card_count (priv->model) ) return; e_table_model_pre_change(etc); @@ -167,29 +136,31 @@ addressbook_set_value_at (ETableModel *etc, int col, int row, const void *val) "card", &card, NULL); - e_card_merging_book_commit_card(e_addressbook_model_get_ebook(priv->model), + e_card_merging_book_commit_card(eab_model_get_ebook(priv->model), card, card_modified_cb, NULL); g_object_unref (card); /* XXX do we need this? shouldn't the commit_card generate a changed signal? */ e_table_model_cell_changed(etc, col, row); } +#endif } /* This function returns whether a particular cell is editable. */ static gboolean addressbook_is_cell_editable (ETableModel *etc, int col, int row) { - EAddressbookTableAdapter *adapter = E_ADDRESSBOOK_TABLE_ADAPTER(etc); +#if 0 + EAddressbookTableAdapter *adapter = EAB_TABLE_ADAPTER(etc); EAddressbookTableAdapterPrivate *priv = adapter->priv; ECard *card; - if (row >= 0 && row < e_addressbook_model_card_count (priv->model)) - card = e_addressbook_model_card_at (priv->model, row); + if (row >= 0 && row < eab_model_card_count (priv->model)) + card = eab_model_card_at (priv->model, row); else card = NULL; - if (!e_addressbook_model_editable(priv->model)) + if (!eab_model_editable(priv->model)) return FALSE; else if (card && e_card_evolution_list (card)) /* we only allow editing of the name and file as for @@ -197,12 +168,16 @@ addressbook_is_cell_editable (ETableModel *etc, int col, int row) return col == E_CARD_SIMPLE_FIELD_FULL_NAME || col == E_CARD_SIMPLE_FIELD_FILE_AS; else return col < E_CARD_SIMPLE_FIELD_LAST_SIMPLE_STRING; +#else + return FALSE; +#endif } static void addressbook_append_row (ETableModel *etm, ETableModel *source, gint row) { - EAddressbookTableAdapter *adapter = E_ADDRESSBOOK_TABLE_ADAPTER(etm); +#if 0 + EAddressbookTableAdapter *adapter = EAB_TABLE_ADAPTER(etm); EAddressbookTableAdapterPrivate *priv = adapter->priv; ECard *card; ECardSimple *simple; @@ -216,9 +191,10 @@ addressbook_append_row (ETableModel *etm, ETableModel *source, gint row) e_card_simple_set(simple, col, val); } e_card_simple_sync_card(simple); - e_card_merging_book_add_card (e_addressbook_model_get_ebook (priv->model), card, NULL, NULL); + e_card_merging_book_add_card (eab_model_get_ebook (priv->model), card, NULL, NULL); g_object_unref (simple); g_object_unref (card); +#endif } /* This function duplicates the value passed to it. */ @@ -254,7 +230,7 @@ addressbook_value_to_string (ETableModel *etc, int col, const void *value) } static void -e_addressbook_table_adapter_class_init (GObjectClass *object_class) +eab_table_adapter_class_init (GObjectClass *object_class) { ETableModelClass *model_class = (ETableModelClass *) object_class; @@ -276,82 +252,57 @@ e_addressbook_table_adapter_class_init (GObjectClass *object_class) } static void -e_addressbook_table_adapter_init (GObject *object) +eab_table_adapter_init (GObject *object) { - EAddressbookTableAdapter *adapter = E_ADDRESSBOOK_TABLE_ADAPTER(object); + EAddressbookTableAdapter *adapter = EAB_TABLE_ADAPTER(object); EAddressbookTableAdapterPrivate *priv; priv = adapter->priv = g_new0 (EAddressbookTableAdapterPrivate, 1); - priv->create_card_id = 0; - priv->remove_card_id = 0; - priv->modify_card_id = 0; + priv->create_contact_id = 0; + priv->remove_contact_id = 0; + priv->modify_contact_id = 0; priv->model_changed_id = 0; - priv->simples = NULL; - priv->count = 0; } static void -create_card (EAddressbookModel *model, - gint index, gint count, - EAddressbookTableAdapter *adapter) +create_contact (EABModel *model, + gint index, gint count, + EAddressbookTableAdapter *adapter) { - EAddressbookTableAdapterPrivate *priv = adapter->priv; - int i; - - priv->count += count; - priv->simples = g_renew(ECardSimple *, priv->simples, priv->count); - memmove (priv->simples + index + count, priv->simples + index, (priv->count - index - count) * sizeof (ECardSimple *)); - e_table_model_pre_change (E_TABLE_MODEL (adapter)); - for (i = 0; i < count; i ++) { - priv->simples[index + i] = e_card_simple_new (e_addressbook_model_card_at (priv->model, index + i)); - } e_table_model_rows_inserted (E_TABLE_MODEL (adapter), index, count); } static void -remove_card (EAddressbookModel *model, - gint index, - EAddressbookTableAdapter *adapter) +remove_contact (EABModel *model, + gint index, + EAddressbookTableAdapter *adapter) { - EAddressbookTableAdapterPrivate *priv = adapter->priv; - e_table_model_pre_change (E_TABLE_MODEL (adapter)); - - g_object_unref (priv->simples[index]); - memmove (priv->simples + index, priv->simples + index + 1, (priv->count - index - 1) * sizeof (ECardSimple *)); - priv->count --; e_table_model_rows_deleted (E_TABLE_MODEL (adapter), index, 1); } static void -modify_card (EAddressbookModel *model, - gint index, - EAddressbookTableAdapter *adapter) +modify_contact (EABModel *model, + gint index, + EAddressbookTableAdapter *adapter) { - EAddressbookTableAdapterPrivate *priv = adapter->priv; - e_table_model_pre_change (E_TABLE_MODEL (adapter)); - - g_object_unref (priv->simples[index]); - priv->simples[index] = e_card_simple_new (e_addressbook_model_card_at (priv->model, index)); - g_object_ref (priv->simples[index]); e_table_model_row_changed (E_TABLE_MODEL (adapter), index); } static void -model_changed (EAddressbookModel *model, +model_changed (EABModel *model, EAddressbookTableAdapter *adapter) { e_table_model_pre_change (E_TABLE_MODEL (adapter)); - build_simple_mapping (adapter); e_table_model_changed (E_TABLE_MODEL (adapter)); } GType -e_addressbook_table_adapter_get_type (void) +eab_table_adapter_get_type (void) { static GType type = 0; @@ -360,12 +311,12 @@ e_addressbook_table_adapter_get_type (void) sizeof (EAddressbookTableAdapterClass), NULL, /* base_init */ NULL, /* base_finalize */ - (GClassInitFunc) e_addressbook_table_adapter_class_init, + (GClassInitFunc) eab_table_adapter_class_init, NULL, /* class_finalize */ NULL, /* class_data */ sizeof (EAddressbookTableAdapter), 0, /* n_preallocs */ - (GInstanceInitFunc) e_addressbook_table_adapter_init, + (GInstanceInitFunc) eab_table_adapter_init, }; type = g_type_register_static (PARENT_TYPE, "EAddressbookTableAdapter", &info, 0); @@ -375,42 +326,40 @@ e_addressbook_table_adapter_get_type (void) } void -e_addressbook_table_adapter_construct (EAddressbookTableAdapter *adapter, - EAddressbookModel *model) +eab_table_adapter_construct (EAddressbookTableAdapter *adapter, + EABModel *model) { EAddressbookTableAdapterPrivate *priv = adapter->priv; priv->model = model; g_object_ref (priv->model); - priv->create_card_id = g_signal_connect(priv->model, - "card_added", - G_CALLBACK(create_card), - adapter); - priv->remove_card_id = g_signal_connect(priv->model, - "card_removed", - G_CALLBACK(remove_card), - adapter); - priv->modify_card_id = g_signal_connect(priv->model, - "card_changed", - G_CALLBACK(modify_card), - adapter); + priv->create_contact_id = g_signal_connect(priv->model, + "contact_added", + G_CALLBACK(create_contact), + adapter); + priv->remove_contact_id = g_signal_connect(priv->model, + "contact_removed", + G_CALLBACK(remove_contact), + adapter); + priv->modify_contact_id = g_signal_connect(priv->model, + "contact_changed", + G_CALLBACK(modify_contact), + adapter); priv->model_changed_id = g_signal_connect(priv->model, "model_changed", G_CALLBACK(model_changed), adapter); - - build_simple_mapping (adapter); } ETableModel * -e_addressbook_table_adapter_new (EAddressbookModel *model) +eab_table_adapter_new (EABModel *model) { EAddressbookTableAdapter *et; - et = g_object_new(E_TYPE_ADDRESSBOOK_TABLE_ADAPTER, NULL); + et = g_object_new(E_TYPE_AB_TABLE_ADAPTER, NULL); - e_addressbook_table_adapter_construct (et, model); + eab_table_adapter_construct (et, model); return E_TABLE_MODEL(et); } diff --git a/addressbook/gui/widgets/e-addressbook-table-adapter.h b/addressbook/gui/widgets/e-addressbook-table-adapter.h index df66e1dce9..6f4bfd2960 100644 --- a/addressbook/gui/widgets/e-addressbook-table-adapter.h +++ b/addressbook/gui/widgets/e-addressbook-table-adapter.h @@ -1,24 +1,16 @@ /* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ -#ifndef _E_ADDRESSBOOK_TABLE_ADAPTER_H_ -#define _E_ADDRESSBOOK_TABLE_ADAPTER_H_ +#ifndef _EAB_TABLE_ADAPTER_H_ +#define _EAB_TABLE_ADAPTER_H_ #include #include "addressbook/backend/ebook/e-book.h" #include "addressbook/backend/ebook/e-book-view.h" -#include "addressbook/backend/ebook/e-card-simple.h" -#define E_TYPE_ADDRESSBOOK_TABLE_ADAPTER (e_addressbook_table_adapter_get_type ()) -#define E_ADDRESSBOOK_TABLE_ADAPTER(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), E_TYPE_ADDRESSBOOK_TABLE_ADAPTER, EAddressbookTableAdapter)) -#define E_ADDRESSBOOK_TABLE_ADAPTER_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), E_TYPE_ADDRESSBOOK_TABLE_ADAPTER, EAddressbookTableAdapterClass)) -#define E_IS_ADDRESSBOOK_TABLE_ADAPTER(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), E_TYPE_ADDRESSBOOK_TABLE_ADAPTER)) -#define E_IS_ADDRESSBOOK_TABLE_ADAPTER_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), E_TYPE_ADDRESSBOOK_TABLE_ADAPTER)) - -/* Virtual Column list: - 0 Email - 1 Full Name - 2 Street - 3 Phone -*/ +#define E_TYPE_AB_TABLE_ADAPTER (eab_table_adapter_get_type ()) +#define EAB_TABLE_ADAPTER(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), E_TYPE_AB_TABLE_ADAPTER, EAddressbookTableAdapter)) +#define EAB_TABLE_ADAPTER_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), E_TYPE_AB_TABLE_ADAPTER, EAddressbookTableAdapterClass)) +#define E_IS_ADDRESSBOOK_TABLE_ADAPTER(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), E_TYPE_AB_TABLE_ADAPTER)) +#define E_IS_ADDRESSBOOK_TABLE_ADAPTER_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), E_TYPE_AB_TABLE_ADAPTER)) typedef struct _EAddressbookTableAdapter EAddressbookTableAdapter; typedef struct _EAddressbookTableAdapterPrivate EAddressbookTableAdapterPrivate; @@ -36,9 +28,9 @@ struct _EAddressbookTableAdapterClass { }; -GType e_addressbook_table_adapter_get_type (void); -void e_addressbook_table_adapter_construct (EAddressbookTableAdapter *adapter, - EAddressbookModel *model); -ETableModel *e_addressbook_table_adapter_new (EAddressbookModel *model); +GType eab_table_adapter_get_type (void); +void eab_table_adapter_construct (EAddressbookTableAdapter *adapter, + EABModel *model); +ETableModel *eab_table_adapter_new (EABModel *model); -#endif /* _E_ADDRESSBOOK_TABLE_ADAPTER_H_ */ +#endif /* _EAB_TABLE_ADAPTER_H_ */ diff --git a/addressbook/gui/widgets/e-addressbook-treeview-adapter.c b/addressbook/gui/widgets/e-addressbook-treeview-adapter.c index ab1a559f0c..592f9d2b03 100644 --- a/addressbook/gui/widgets/e-addressbook-treeview-adapter.c +++ b/addressbook/gui/widgets/e-addressbook-treeview-adapter.c @@ -4,7 +4,7 @@ #include "e-addressbook-model.h" #include "e-addressbook-treeview-adapter.h" #include "e-card-merging.h" -#include "e-addressbook-util.h" +#include "eab-gui-util.h" #include #include #include @@ -380,10 +380,10 @@ adapter_get_value (GtkTreeModel *tree_model, v = e_card_simple_get_const(simple, column); if (v && !strncmp (v, " - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of version 2 of the GNU General Public - * License as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public - * License along with this library; if not, write to the - * Free Software Foundation, Inc., 59 Temple Place - Suite 330, - * Boston, MA 02111-1307, USA. - */ - -#include -#include "e-addressbook-util.h" -#include "ebook/e-destination.h" - -#include -#include - -#include "e-card-merging.h" -#include -#include - -void -e_addressbook_error_dialog (const gchar *msg, EBookStatus status) -{ - static char *status_to_string[] = { - N_("Success"), - N_("Unknown error"), - N_("Repository offline"), - N_("Permission denied"), - N_("Card not found"), - N_("Card ID already exists"), - N_("Protocol not supported"), - N_("Cancelled"), - N_("Authentication Failed"), - N_("Authentication Required"), - N_("TLS not Available"), - N_("Addressbook does not exist"), - N_("Other error") - }; - char *error_msg; - GtkWidget *dialog; - - error_msg = g_strdup_printf ("%s: %s", msg, _(status_to_string [status])); - - dialog = gtk_message_dialog_new (NULL, 0, GTK_MESSAGE_ERROR, GTK_BUTTONS_OK, - error_msg); - - g_signal_connect (dialog, "response", G_CALLBACK (gtk_widget_destroy), NULL); - - gtk_widget_show (dialog); - - g_free (error_msg); -} - -gint -e_addressbook_prompt_save_dialog (GtkWindow *parent) -{ - GtkWidget *dialog; - gint response; - - dialog = gtk_message_dialog_new (parent, - (GtkDialogFlags)0, - GTK_MESSAGE_QUESTION, - GTK_BUTTONS_NONE, - _("Do you want to save changes?")); - gtk_dialog_add_buttons (GTK_DIALOG (dialog), - _("_Discard"), GTK_RESPONSE_NO, - GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL, - GTK_STOCK_SAVE, GTK_RESPONSE_YES, - NULL); - - gtk_dialog_set_default_response (GTK_DIALOG (dialog), GTK_RESPONSE_YES); - - response = gtk_dialog_run (GTK_DIALOG (dialog)); - - gtk_widget_destroy (dialog); - - return response; -} - -static void -added_cb (EBook* book, EBookStatus status, const char *id, - gboolean is_list) -{ - if (status != E_BOOK_STATUS_SUCCESS) { - e_addressbook_error_dialog (is_list ? _("Error adding list") : _("Error adding card"), status); - } -} - -static void -modified_cb (EBook* book, EBookStatus status, - gboolean is_list) -{ - if (status != E_BOOK_STATUS_SUCCESS) { - e_addressbook_error_dialog (is_list ? _("Error modifying list") : _("Error modifying card"), - status); - } -} - -static void -deleted_cb (EBook* book, EBookStatus status, - gboolean is_list) -{ - if (status != E_BOOK_STATUS_SUCCESS) { - e_addressbook_error_dialog (is_list ? _("Error removing list") : _("Error removing card"), - status); - } -} - -static void -editor_closed_cb (GtkObject *editor, gpointer data) -{ - g_object_unref (editor); -} - -EContactEditor * -e_addressbook_show_contact_editor (EBook *book, ECard *card, - gboolean is_new_card, - gboolean editable) -{ - EContactEditor *ce; - - ce = e_contact_editor_new (book, card, is_new_card, editable); - - g_signal_connect (ce, "card_added", - G_CALLBACK (added_cb), GINT_TO_POINTER (FALSE)); - g_signal_connect (ce, "card_modified", - G_CALLBACK (modified_cb), GINT_TO_POINTER (FALSE)); - g_signal_connect (ce, "card_deleted", - G_CALLBACK (deleted_cb), GINT_TO_POINTER (FALSE)); - g_signal_connect (ce, "editor_closed", - G_CALLBACK (editor_closed_cb), NULL); - - return ce; -} - -EContactListEditor * -e_addressbook_show_contact_list_editor (EBook *book, ECard *card, - gboolean is_new_card, - gboolean editable) -{ - EContactListEditor *ce; - - ce = e_contact_list_editor_new (book, card, is_new_card, editable); - - g_signal_connect (ce, "list_added", - G_CALLBACK (added_cb), GINT_TO_POINTER (TRUE)); - g_signal_connect (ce, "list_modified", - G_CALLBACK (modified_cb), GINT_TO_POINTER (TRUE)); - g_signal_connect (ce, "list_deleted", - G_CALLBACK (deleted_cb), GINT_TO_POINTER (TRUE)); - g_signal_connect (ce, "editor_closed", - G_CALLBACK (editor_closed_cb), GINT_TO_POINTER (TRUE)); - - e_contact_list_editor_show (ce); - - return ce; -} - -static void -view_cards (EBook *book, GList *list, gboolean editable) -{ - for (; list; list = list->next) { - ECard *card = list->data; - if (e_card_evolution_list (card)) - e_addressbook_show_contact_list_editor (book, card, FALSE, editable); - else - e_addressbook_show_contact_editor (book, card, FALSE, editable); - } -} - -void -e_addressbook_show_multiple_cards (EBook *book, - GList *list, - gboolean editable) -{ - if (list) { - int length = g_list_length (list); - if (length > 5) { - GtkWidget *dialog; - gint response; - - dialog = gtk_message_dialog_new (NULL, - 0, - GTK_MESSAGE_QUESTION, - GTK_BUTTONS_YES_NO, - _("Opening %d cards will open %d new windows as well.\n" - "Do you really want to display all of these cards?"), - length, - length); - - response = gtk_dialog_run (GTK_DIALOG (dialog)); - gtk_widget_destroy (dialog); - if (response == GTK_RESPONSE_YES) - view_cards (book, list, editable); - } else { - view_cards (book, list, editable); - } - } -} - - - -typedef struct CardCopyProcess_ CardCopyProcess; - -typedef void (*CardCopyDone) (CardCopyProcess *process); - -struct CardCopyProcess_ { - int count; - GList *cards; - EBook *source; - EBook *destination; - CardCopyDone done_cb; -}; - -static void -card_deleted_cb (EBook* book, EBookStatus status, gpointer user_data) -{ - if (status != E_BOOK_STATUS_SUCCESS) { - e_addressbook_error_dialog (_("Error removing card"), status); - } -} - -static void -do_delete (gpointer data, gpointer user_data) -{ - EBook *book = user_data; - ECard *card = data; - - e_book_remove_card(book, card, card_deleted_cb, NULL); -} - -static void -delete_cards (CardCopyProcess *process) -{ - g_list_foreach (process->cards, - do_delete, - process->source); -} - -static void -process_unref (CardCopyProcess *process) -{ - process->count --; - if (process->count == 0) { - if (process->done_cb) { - process->done_cb (process); - } - e_free_object_list(process->cards); - g_object_unref (process->source); - g_object_unref (process->destination); - g_free (process); - } -} - -static void -card_added_cb (EBook* book, EBookStatus status, const char *id, gpointer user_data) -{ - CardCopyProcess *process = user_data; - - if (status != E_BOOK_STATUS_SUCCESS) { - e_addressbook_error_dialog (_("Error adding card"), status); - } else { - process_unref (process); - } -} - -static void -do_copy (gpointer data, gpointer user_data) -{ - EBook *book; - ECard *card; - CardCopyProcess *process; - - process = user_data; - card = data; - - book = process->destination; - - process->count ++; - e_book_add_card(book, card, card_added_cb, process); -} - -static void -got_book_cb (EBook *book, gpointer closure) -{ - CardCopyProcess *process; - process = closure; - if (book) { - process->destination = book; - g_object_ref (book); - g_list_foreach (process->cards, - do_copy, - process); - } - process_unref (process); -} - -extern EvolutionShellClient *global_shell_client; - -void -e_addressbook_transfer_cards (EBook *source, GList *cards /* adopted */, gboolean delete_from_source, GtkWindow *parent_window) -{ - const char *allowed_types[] = { "contacts/*", NULL }; - GNOME_Evolution_Folder *folder; - static char *last_uri = NULL; - CardCopyProcess *process; - char *desc; - - if (cards == NULL) - return; - - if (last_uri == NULL) - last_uri = g_strdup (""); - - if (cards->next == NULL) { - if (delete_from_source) - desc = _("Move card to"); - else - desc = _("Copy card to"); - } else { - if (delete_from_source) - desc = _("Move cards to"); - else - desc = _("Copy cards to"); - } - - evolution_shell_client_user_select_folder (global_shell_client, - parent_window, - desc, last_uri, allowed_types, - &folder); - if (!folder) - return; - - if (strcmp (last_uri, folder->evolutionUri) != 0) { - g_free (last_uri); - last_uri = g_strdup (folder->evolutionUri); - } - - process = g_new (CardCopyProcess, 1); - process->count = 1; - process->source = source; - g_object_ref (source); - process->cards = cards; - process->destination = NULL; - - if (delete_from_source) - process->done_cb = delete_cards; - else - process->done_cb = NULL; - - e_book_use_address_book_by_uri (folder->physicalUri, got_book_cb, process); - - CORBA_free (folder); -} - -#include - -#define COMPOSER_OAFID "OAFIID:GNOME_Evolution_Mail_Composer" - -void -e_addressbook_send_card_list (GList *cards, EAddressbookDisposition disposition) -{ - GNOME_Evolution_Composer composer_server; - CORBA_Environment ev; - - if (cards == NULL) - return; - - CORBA_exception_init (&ev); - - composer_server = bonobo_activation_activate_from_id (COMPOSER_OAFID, 0, NULL, &ev); - - if (disposition == E_ADDRESSBOOK_DISPOSITION_AS_TO) { - GNOME_Evolution_Composer_RecipientList *to_list, *cc_list, *bcc_list; - CORBA_char *subject; - int to_i, bcc_i; - GList *iter; - gint to_length = 0, bcc_length = 0; - - /* Figure out how many addresses of each kind we have. */ - for (iter = cards; iter != NULL; iter = g_list_next (iter)) { - ECard *card = E_CARD (iter->data); - if (e_card_evolution_list (card)) { - gint len = card->email ? e_list_length (card->email) : 0; - if (e_card_evolution_list_show_addresses (card)) - to_length += len; - else - bcc_length += len; - } else { - if (card->email != NULL) - ++to_length; - } - } - - /* Now I have to make a CORBA sequences that represents a recipient list with - the right number of entries, for the cards. */ - to_list = GNOME_Evolution_Composer_RecipientList__alloc (); - to_list->_maximum = to_length; - to_list->_length = to_length; - if (to_length > 0) { - to_list->_buffer = CORBA_sequence_GNOME_Evolution_Composer_Recipient_allocbuf (to_length); - } - - cc_list = GNOME_Evolution_Composer_RecipientList__alloc (); - cc_list->_maximum = cc_list->_length = 0; - - bcc_list = GNOME_Evolution_Composer_RecipientList__alloc (); - bcc_list->_maximum = bcc_length; - bcc_list->_length = bcc_length; - if (bcc_length > 0) { - bcc_list->_buffer = CORBA_sequence_GNOME_Evolution_Composer_Recipient_allocbuf (bcc_length); - } - - to_i = 0; - bcc_i = 0; - while (cards != NULL) { - ECard *card = cards->data; - EIterator *iterator; - gchar *name, *addr; - gboolean is_list, is_hidden, free_name_addr; - GNOME_Evolution_Composer_Recipient *recipient; - - if (card->email != NULL) { - - is_list = e_card_evolution_list (card); - is_hidden = is_list && !e_card_evolution_list_show_addresses (card); - - for (iterator = e_list_get_iterator (card->email); e_iterator_is_valid (iterator); e_iterator_next (iterator)) { - - if (is_hidden) { - recipient = &(bcc_list->_buffer[bcc_i]); - ++bcc_i; - } else { - recipient = &(to_list->_buffer[to_i]); - ++to_i; - } - - name = ""; - addr = ""; - free_name_addr = FALSE; - if (e_iterator_is_valid (iterator)) { - - if (is_list) { - /* We need to decode the list entries, which are XMLified EDestinations. */ - EDestination *dest = e_destination_import (e_iterator_get (iterator)); - if (dest != NULL) { - name = g_strdup (e_destination_get_name (dest)); - addr = g_strdup (e_destination_get_email (dest)); - free_name_addr = TRUE; - g_object_unref (dest); - } - - } else { /* is just a plain old card */ - if (card->name) - name = e_card_name_to_string (card->name); - addr = g_strdup ((char *) e_iterator_get (iterator)); - free_name_addr = TRUE; - } - } - - recipient->name = CORBA_string_dup (name ? name : ""); - recipient->address = CORBA_string_dup (addr ? addr : ""); - - if (free_name_addr) { - g_free ((gchar *) name); - g_free ((gchar *) addr); - } - - /* If this isn't a list, we quit after the first (i.e. the default) address. */ - if (!is_list) - break; - - } - g_object_unref (iterator); - } - - cards = g_list_next (cards); - } - - subject = CORBA_string_dup (""); - - GNOME_Evolution_Composer_setHeaders (composer_server, "", to_list, cc_list, bcc_list, subject, &ev); - if (ev._major != CORBA_NO_EXCEPTION) { - g_printerr ("gui/e-meeting-edit.c: I couldn't set the composer headers via CORBA! Aagh.\n"); - CORBA_exception_free (&ev); - return; - } - - CORBA_free (to_list); - CORBA_free (cc_list); - CORBA_free (bcc_list); - CORBA_free (subject); - } else if (disposition == E_ADDRESSBOOK_DISPOSITION_AS_ATTACHMENT) { - CORBA_char *content_type, *filename, *description; - GNOME_Evolution_Composer_AttachmentData *attach_data; - CORBA_boolean show_inline; - char *tempstr; - - GNOME_Evolution_Composer_RecipientList *to_list, *cc_list, *bcc_list; - CORBA_char *subject; - - content_type = CORBA_string_dup ("text/x-vcard"); - filename = CORBA_string_dup (""); - - if (cards->next) { - description = CORBA_string_dup (_("Multiple VCards")); - } else { - char *file_as; - - g_object_get(cards->data, - "file_as", &file_as, - NULL); - - tempstr = g_strdup_printf (_("VCard for %s"), file_as); - description = CORBA_string_dup (tempstr); - g_free (tempstr); - g_free (file_as); - } - - show_inline = FALSE; - - tempstr = e_card_list_get_vcard (cards); - attach_data = GNOME_Evolution_Composer_AttachmentData__alloc(); - attach_data->_maximum = attach_data->_length = strlen (tempstr); - attach_data->_buffer = CORBA_sequence_CORBA_char_allocbuf (attach_data->_length); - memcpy(attach_data->_buffer, tempstr, attach_data->_length); - g_free (tempstr); - - GNOME_Evolution_Composer_attachData (composer_server, - content_type, filename, description, - show_inline, attach_data, - &ev); - - if (ev._major != CORBA_NO_EXCEPTION) { - g_printerr ("gui/e-meeting-edit.c: I couldn't attach data to the composer via CORBA! Aagh.\n"); - CORBA_exception_free (&ev); - return; - } - - CORBA_free (content_type); - CORBA_free (filename); - CORBA_free (description); - CORBA_free (attach_data); - - to_list = GNOME_Evolution_Composer_RecipientList__alloc (); - to_list->_maximum = to_list->_length = 0; - - cc_list = GNOME_Evolution_Composer_RecipientList__alloc (); - cc_list->_maximum = cc_list->_length = 0; - - bcc_list = GNOME_Evolution_Composer_RecipientList__alloc (); - bcc_list->_maximum = bcc_list->_length = 0; - - if (!cards || cards->next) { - subject = CORBA_string_dup ("Contact information"); - } else { - ECard *card = cards->data; - const gchar *tempstr2; - - tempstr2 = NULL; - g_object_get(card, - "file_as", &tempstr2, - NULL); - if (!tempstr2 || !*tempstr2) { - g_free (tempstr2); - g_object_get(card, - "full_name", &tempstr2, - NULL); - } if (!tempstr2 || !*tempstr2) { - g_free (tempstr2); - g_object_get(card, - "org", &tempstr2, - NULL); - } if (!tempstr2 || !*tempstr2) { - EList *list; - EIterator *iterator; - g_object_get(card, - "email", &list, - NULL); - iterator = e_list_get_iterator (list); - if (e_iterator_is_valid (iterator)) { - tempstr2 = e_iterator_get (iterator); - } - g_object_unref (iterator); - g_object_unref (list); - } - - if (!tempstr2 || !*tempstr2) - tempstr = g_strdup_printf ("Contact information"); - else - tempstr = g_strdup_printf ("Contact information for %s", tempstr2); - subject = CORBA_string_dup (tempstr); - g_free (tempstr2); - g_free (tempstr); - } - - GNOME_Evolution_Composer_setHeaders (composer_server, "", to_list, cc_list, bcc_list, subject, &ev); - - CORBA_free (to_list); - CORBA_free (cc_list); - CORBA_free (bcc_list); - CORBA_free (subject); - } - - GNOME_Evolution_Composer_show (composer_server, &ev); - - if (ev._major != CORBA_NO_EXCEPTION) { - g_printerr ("gui/e-meeting-edit.c: I couldn't show the composer via CORBA! Aagh.\n"); - CORBA_exception_free (&ev); - return; - } - - CORBA_exception_free (&ev); -} - -void -e_addressbook_send_card (ECard *card, EAddressbookDisposition disposition) -{ - GList *list; - list = g_list_prepend (NULL, card); - e_addressbook_send_card_list (list, disposition); - g_list_free (list); -} - diff --git a/addressbook/gui/widgets/e-addressbook-util.h b/addressbook/gui/widgets/e-addressbook-util.h deleted file mode 100644 index e6ea3ab73b..0000000000 --- a/addressbook/gui/widgets/e-addressbook-util.h +++ /dev/null @@ -1,65 +0,0 @@ -/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ -/* e-addressbook-util.h - * Copyright (C) 2001 Ximian, Inc. - * Author: Chris Toshok - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of version 2 of the GNU General Public - * License as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public - * License along with this library; if not, write to the - * Free Software Foundation, Inc., 59 Temple Place - Suite 330, - * Boston, MA 02111-1307, USA. - */ -#ifndef __E_ADDRESSBOOK_UTIL_H__ -#define __E_ADDRESSBOOK_UTIL_H__ - -#include "addressbook/backend/ebook/e-book.h" -#include "addressbook/gui/contact-editor/e-contact-editor.h" -#include "addressbook/gui/contact-list-editor/e-contact-list-editor.h" - -#ifdef __cplusplus -extern "C" { -#pragma } -#endif /* __cplusplus */ - -void e_addressbook_error_dialog (const gchar *msg, - EBookStatus status); -gint e_addressbook_prompt_save_dialog (GtkWindow *parent); -EContactEditor *e_addressbook_show_contact_editor (EBook *book, - ECard *card, - gboolean is_new_card, - gboolean editable); -EContactListEditor *e_addressbook_show_contact_list_editor (EBook *book, - ECard *card, - gboolean is_new_card, - gboolean editable); -void e_addressbook_show_multiple_cards (EBook *book, - GList *list, - gboolean editable); -void e_addressbook_transfer_cards (EBook *source, - GList *cards, /* adopted */ - gboolean delete_from_source, - GtkWindow *parent_window); - -typedef enum { - E_ADDRESSBOOK_DISPOSITION_AS_ATTACHMENT, - E_ADDRESSBOOK_DISPOSITION_AS_TO, -} EAddressbookDisposition; - -void e_addressbook_send_card (ECard *card, - EAddressbookDisposition disposition); -void e_addressbook_send_card_list (GList *cards, - EAddressbookDisposition disposition); - -#ifdef __cplusplus -} -#endif /* __cplusplus */ - -#endif /* __E_ADDRESSBOOK_UTIL_H__ */ diff --git a/addressbook/gui/widgets/e-addressbook-view.c b/addressbook/gui/widgets/e-addressbook-view.c index 08710c71b5..4c5976717f 100644 --- a/addressbook/gui/widgets/e-addressbook-view.c +++ b/addressbook/gui/widgets/e-addressbook-view.c @@ -43,26 +43,24 @@ #include "addressbook/printing/e-contact-print.h" #include "addressbook/printing/e-contact-print-envelope.h" -#include "gal-view-factory-minicard.h" -#include "gal-view-minicard.h" #ifdef WITH_ADDRESSBOOK_VIEW_TREEVIEW #include #include "gal-view-factory-treeview.h" #include "gal-view-treeview.h" #endif +#include "gal-view-minicard.h" +#include "gal-view-factory-minicard.h" -#include "e-addressbook-marshal.h" +#include "eab-marshal.h" #include "e-addressbook-view.h" #include "e-addressbook-model.h" -#include "e-addressbook-util.h" +#include "eab-gui-util.h" +#include "util/eab-book-util.h" #include "e-addressbook-table-adapter.h" #ifdef WITH_ADDRESSBOOK_VIEW_TREEVIEW #include "e-addressbook-treeview-adapter.h" #endif -#include "e-addressbook-reflow-adapter.h" -#include "e-minicard-view-widget.h" -#include "e-contact-save-as.h" -#include "e-card-merging.h" +#include "eab-contact-merging.h" #include "e-contact-editor.h" #include @@ -76,33 +74,33 @@ #define d(x) -static void e_addressbook_view_init (EAddressbookView *card); -static void e_addressbook_view_class_init (EAddressbookViewClass *klass); +static void eab_view_init (EABView *card); +static void eab_view_class_init (EABViewClass *klass); -static void e_addressbook_view_set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec); -static void e_addressbook_view_get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec); +static void eab_view_set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec); +static void eab_view_get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec); -static void e_addressbook_view_dispose (GObject *object); -static void change_view_type (EAddressbookView *view, EAddressbookViewType view_type); +static void eab_view_dispose (GObject *object); +static void change_view_type (EABView *view, EABViewType view_type); -static void status_message (GtkObject *object, const gchar *status, EAddressbookView *eav); -static void search_result (GtkObject *object, EBookViewStatus status, EAddressbookView *eav); -static void folder_bar_message (GtkObject *object, const gchar *status, EAddressbookView *eav); -static void stop_state_changed (GtkObject *object, EAddressbookView *eav); -static void writable_status (GtkObject *object, gboolean writable, EAddressbookView *eav); -static void backend_died (GtkObject *object, EAddressbookView *eav); -static void command_state_change (EAddressbookView *eav); -static void alphabet_state_change (EAddressbookView *eav, gunichar letter); +static void status_message (GtkObject *object, const gchar *status, EABView *eav); +static void search_result (GtkObject *object, EBookViewStatus status, EABView *eav); +static void folder_bar_message (GtkObject *object, const gchar *status, EABView *eav); +static void stop_state_changed (GtkObject *object, EABView *eav); +static void writable_status (GtkObject *object, gboolean writable, EABView *eav); +static void backend_died (GtkObject *object, EABView *eav); +static void command_state_change (EABView *eav); static void selection_clear_event (GtkWidget *invisible, GdkEventSelection *event, - EAddressbookView *view); + EABView *view); static void selection_received (GtkWidget *invisible, GtkSelectionData *selection_data, - guint time, EAddressbookView *view); + guint time, EABView *view); static void selection_get (GtkWidget *invisible, GtkSelectionData *selection_data, - guint info, guint time_stamp, EAddressbookView *view); + guint info, guint time_stamp, EABView *view); static void invisible_destroyed (gpointer data, GObject *where_object_was); -static GtkTableClass *parent_class = NULL; +#define PARENT_TYPE GTK_TYPE_EVENT_BOX +static GtkEventBoxClass *parent_class = NULL; /* The arguments we take */ enum { @@ -117,7 +115,6 @@ enum { SEARCH_RESULT, FOLDER_BAR_MESSAGE, COMMAND_STATE_CHANGE, - ALPHABET_STATE_CHANGE, LAST_SIGNAL }; @@ -130,38 +127,38 @@ static GtkTargetEntry drag_types[] = { }; static const int num_drag_types = sizeof (drag_types) / sizeof (drag_types[0]); -static guint e_addressbook_view_signals [LAST_SIGNAL] = {0, }; +static guint eab_view_signals [LAST_SIGNAL] = {0, }; static GdkAtom clipboard_atom = GDK_NONE; static GalViewCollection *collection = NULL; GType -e_addressbook_view_get_type (void) +eab_view_get_type (void) { static GType type = 0; if (!type) { static const GTypeInfo info = { - sizeof (EAddressbookViewClass), + sizeof (EABViewClass), NULL, /* base_init */ NULL, /* base_finalize */ - (GClassInitFunc) e_addressbook_view_class_init, + (GClassInitFunc) eab_view_class_init, NULL, /* class_finalize */ NULL, /* class_data */ - sizeof (EAddressbookView), + sizeof (EABView), 0, /* n_preallocs */ - (GInstanceInitFunc) e_addressbook_view_init, + (GInstanceInitFunc) eab_view_init, }; - type = g_type_register_static (GTK_TYPE_TABLE, "EAddressbookView", &info, 0); + type = g_type_register_static (PARENT_TYPE, "EABView", &info, 0); } return type; } static void -e_addressbook_view_class_init (EAddressbookViewClass *klass) +eab_view_class_init (EABViewClass *klass) { GObjectClass *object_class; GtkWidgetClass *widget_class; @@ -169,11 +166,11 @@ e_addressbook_view_class_init (EAddressbookViewClass *klass) object_class = G_OBJECT_CLASS(klass); widget_class = GTK_WIDGET_CLASS(klass); - parent_class = gtk_type_class (gtk_table_get_type ()); + parent_class = gtk_type_class (PARENT_TYPE); - object_class->set_property = e_addressbook_view_set_property; - object_class->get_property = e_addressbook_view_get_property; - object_class->dispose = e_addressbook_view_dispose; + object_class->set_property = eab_view_set_property; + object_class->get_property = eab_view_get_property; + object_class->dispose = eab_view_dispose; g_object_class_install_property (object_class, PROP_BOOK, g_param_spec_object ("book", @@ -193,137 +190,78 @@ e_addressbook_view_class_init (EAddressbookViewClass *klass) g_param_spec_int ("type", _("Type"), /*_( */"XXX blurb" /*)*/, - E_ADDRESSBOOK_VIEW_NONE, -#ifdef WITH_ADDRESSBOOK_VIEW_TREEVIEW - E_ADDRESSBOOK_VIEW_TREEVIEW, -#else - E_ADDRESSBOOK_VIEW_MINICARD, -#endif - E_ADDRESSBOOK_VIEW_NONE, + EAB_VIEW_NONE, + EAB_VIEW_TABLE, + EAB_VIEW_NONE, G_PARAM_READWRITE)); - e_addressbook_view_signals [STATUS_MESSAGE] = + eab_view_signals [STATUS_MESSAGE] = g_signal_new ("status_message", G_OBJECT_CLASS_TYPE (object_class), G_SIGNAL_RUN_LAST, - G_STRUCT_OFFSET (EAddressbookViewClass, status_message), + G_STRUCT_OFFSET (EABViewClass, status_message), NULL, NULL, - e_addressbook_marshal_NONE__POINTER, + eab_marshal_NONE__POINTER, G_TYPE_NONE, 1, G_TYPE_POINTER); - e_addressbook_view_signals [SEARCH_RESULT] = + eab_view_signals [SEARCH_RESULT] = g_signal_new ("search_result", G_OBJECT_CLASS_TYPE (object_class), G_SIGNAL_RUN_LAST, - G_STRUCT_OFFSET (EAddressbookViewClass, search_result), + G_STRUCT_OFFSET (EABViewClass, search_result), NULL, NULL, - e_addressbook_marshal_NONE__INT, + eab_marshal_NONE__INT, G_TYPE_NONE, 1, G_TYPE_INT); - e_addressbook_view_signals [FOLDER_BAR_MESSAGE] = + eab_view_signals [FOLDER_BAR_MESSAGE] = g_signal_new ("folder_bar_message", G_OBJECT_CLASS_TYPE (object_class), G_SIGNAL_RUN_LAST, - G_STRUCT_OFFSET (EAddressbookViewClass, folder_bar_message), + G_STRUCT_OFFSET (EABViewClass, folder_bar_message), NULL, NULL, - e_addressbook_marshal_NONE__POINTER, + eab_marshal_NONE__POINTER, G_TYPE_NONE, 1, G_TYPE_POINTER); - e_addressbook_view_signals [COMMAND_STATE_CHANGE] = + eab_view_signals [COMMAND_STATE_CHANGE] = g_signal_new ("command_state_change", G_OBJECT_CLASS_TYPE (object_class), G_SIGNAL_RUN_LAST, - G_STRUCT_OFFSET (EAddressbookViewClass, command_state_change), + G_STRUCT_OFFSET (EABViewClass, command_state_change), NULL, NULL, - e_addressbook_marshal_NONE__NONE, + eab_marshal_NONE__NONE, G_TYPE_NONE, 0); - e_addressbook_view_signals [ALPHABET_STATE_CHANGE] = - g_signal_new ("alphabet_state_change", - G_OBJECT_CLASS_TYPE (object_class), - G_SIGNAL_RUN_LAST, - G_STRUCT_OFFSET (EAddressbookViewClass, alphabet_state_change), - NULL, NULL, - e_addressbook_marshal_NONE__UINT, - G_TYPE_NONE, 1, G_TYPE_UINT); - - if (!clipboard_atom) clipboard_atom = gdk_atom_intern ("CLIPBOARD", FALSE); } static void -e_addressbook_view_init (EAddressbookView *eav) +eab_view_init (EABView *eav) { - eav->view_type = E_ADDRESSBOOK_VIEW_NONE; - - eav->model = e_addressbook_model_new (); - - g_signal_connect (eav->model, - "status_message", - G_CALLBACK (status_message), - eav); - - g_signal_connect (eav->model, - "search_result", - G_CALLBACK (search_result), - eav); - - g_signal_connect (eav->model, - "folder_bar_message", - G_CALLBACK (folder_bar_message), - eav); - - g_signal_connect (eav->model, - "stop_state_changed", - G_CALLBACK (stop_state_changed), - eav); - - g_signal_connect (eav->model, - "writable_status", - G_CALLBACK (writable_status), - eav); - - g_signal_connect (eav->model, - "backend_died", - G_CALLBACK (backend_died), - eav); - - eav->editable = FALSE; - eav->book = NULL; - eav->query = g_strdup (SHOW_ALL_SEARCH); + eav->view_type = EAB_VIEW_NONE; + eav->model = NULL; eav->object = NULL; eav->widget = NULL; + eav->scrolled = NULL; + eav->contact_display = NULL; eav->view_instance = NULL; eav->view_menus = NULL; + eav->current_view = NULL; eav->uic = NULL; - eav->current_alphabet_widget = NULL; - eav->invisible = gtk_invisible_new (); + eav->book = NULL; + eav->query = NULL; - gtk_selection_add_target (eav->invisible, - clipboard_atom, - GDK_SELECTION_TYPE_STRING, - 0); - - g_signal_connect (eav->invisible, "selection_get", - G_CALLBACK (selection_get), - eav); - g_signal_connect (eav->invisible, "selection_clear_event", - G_CALLBACK (selection_clear_event), - eav); - g_signal_connect (eav->invisible, "selection_received", - G_CALLBACK (selection_received), - eav); - g_object_weak_ref (G_OBJECT (eav->invisible), invisible_destroyed, eav); + eav->invisible = NULL; + eav->clipboard_contacts = NULL; } static void -e_addressbook_view_dispose (GObject *object) +eab_view_dispose (GObject *object) { - EAddressbookView *eav = E_ADDRESSBOOK_VIEW(object); + EABView *eav = EAB_VIEW(object); if (eav->model) { g_signal_handlers_disconnect_matched (eav->model, @@ -356,10 +294,10 @@ e_addressbook_view_dispose (GObject *object) eav->view_menus = NULL; } - if (eav->clipboard_cards) { - g_list_foreach (eav->clipboard_cards, (GFunc)g_object_unref, NULL); - g_list_free (eav->clipboard_cards); - eav->clipboard_cards = NULL; + if (eav->clipboard_contacts) { + g_list_foreach (eav->clipboard_contacts, (GFunc)g_object_unref, NULL); + g_list_free (eav->clipboard_contacts); + eav->clipboard_contacts = NULL; } if (eav->invisible) { @@ -372,14 +310,77 @@ e_addressbook_view_dispose (GObject *object) } GtkWidget* -e_addressbook_view_new (void) -{ - GtkWidget *widget = GTK_WIDGET (g_object_new (E_TYPE_ADDRESSBOOK_VIEW, NULL)); +eab_view_new (void) +{ + GtkWidget *widget = GTK_WIDGET (g_object_new (E_TYPE_AB_VIEW, NULL)); + EABView *eav = EAB_VIEW (widget); + + /* create our model */ + eav->model = eab_model_new (); + + g_signal_connect (eav->model, "status_message", + G_CALLBACK (status_message), eav); + g_signal_connect (eav->model, "search_result", + G_CALLBACK (search_result), eav); + g_signal_connect (eav->model, "folder_bar_message", + G_CALLBACK (folder_bar_message), eav); + g_signal_connect (eav->model, "stop_state_changed", + G_CALLBACK (stop_state_changed), eav); + g_signal_connect (eav->model, "writable_status", + G_CALLBACK (writable_status), eav); + g_signal_connect (eav->model, "backend_died", + G_CALLBACK (backend_died), eav); + + eav->editable = FALSE; + eav->query = g_strdup (SHOW_ALL_SEARCH); + + /* create the paned window and contact display */ + eav->paned = gtk_vpaned_new (); + gtk_container_add (GTK_CONTAINER (eav), eav->paned); + + eav->widget = gtk_label_new ("empty label here"); + gtk_container_add (GTK_CONTAINER (eav->paned), eav->widget); + gtk_widget_show (eav->widget); + + eav->scrolled = gtk_scrolled_window_new (NULL, NULL); + gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (eav->scrolled), GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC); + gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (eav->scrolled), GTK_SHADOW_IN); + eav->contact_display = eab_contact_display_new (); + + gtk_scrolled_window_add_with_viewport (GTK_SCROLLED_WINDOW (eav->scrolled), eav->contact_display); + gtk_widget_show (eav->contact_display); + + gtk_container_add (GTK_CONTAINER (eav->paned), eav->scrolled); + gtk_widget_show (eav->scrolled); + gtk_widget_show (eav->paned); + + /* XXX hack */ + gtk_paned_set_position (GTK_PANED (eav->paned), 144); + + /* gtk selection crap */ + eav->invisible = gtk_invisible_new (); + + gtk_selection_add_target (eav->invisible, + clipboard_atom, + GDK_SELECTION_TYPE_STRING, + 0); + + g_signal_connect (eav->invisible, "selection_get", + G_CALLBACK (selection_get), + eav); + g_signal_connect (eav->invisible, "selection_clear_event", + G_CALLBACK (selection_clear_event), + eav); + g_signal_connect (eav->invisible, "selection_received", + G_CALLBACK (selection_received), + eav); + g_object_weak_ref (G_OBJECT (eav->invisible), invisible_destroyed, eav); + return widget; } static void -writable_status (GtkObject *object, gboolean writable, EAddressbookView *eav) +writable_status (GtkObject *object, gboolean writable, EABView *eav) { eav->editable = writable; command_state_change (eav); @@ -412,7 +413,7 @@ init_collection (void) gal_view_collection_add_factory (collection, factory); g_object_unref (factory); - factory = gal_view_factory_minicard_new (); + factory = gal_view_factory_minicard_new(); gal_view_collection_add_factory (collection, factory); g_object_unref (factory); @@ -431,17 +432,18 @@ display_view(GalViewInstance *instance, GalView *view, gpointer data) { - EAddressbookView *address_view = data; + EABView *address_view = data; if (GAL_IS_VIEW_ETABLE(view)) { - change_view_type (address_view, E_ADDRESSBOOK_VIEW_TABLE); + change_view_type (address_view, EAB_VIEW_TABLE); gal_view_etable_attach_table (GAL_VIEW_ETABLE(view), e_table_scrolled_get_table(E_TABLE_SCROLLED(address_view->widget))); - } else if (GAL_IS_VIEW_MINICARD(view)) { - change_view_type (address_view, E_ADDRESSBOOK_VIEW_MINICARD); - gal_view_minicard_attach (GAL_VIEW_MINICARD(view), E_MINICARD_VIEW_WIDGET (address_view->object)); + } + else if (GAL_IS_VIEW_MINICARD(view)) { + change_view_type (address_view, EAB_VIEW_MINICARD); + gal_view_minicard_attach (GAL_VIEW_MINICARD (view), E_MINICARD_VIEW_WIDGET (address_view->object)); } #ifdef WITH_ADDRESSBOOK_VIEW_TREEVIEW else if (GAL_IS_VIEW_TREEVIEW (view)) { - change_view_type (address_view, E_ADDRESSBOOK_VIEW_TREEVIEW); + change_view_type (address_view, EAB_VIEW_TREEVIEW); gal_view_treeview_attach (GAL_VIEW_TREEVIEW(view), GTK_TREE_VIEW (address_view->object)); } #endif @@ -449,7 +451,7 @@ display_view(GalViewInstance *instance, } static void -setup_menus (EAddressbookView *view) +setup_menus (EABView *view) { if (view->book && view->view_instance == NULL) { init_collection (); @@ -468,9 +470,9 @@ setup_menus (EAddressbookView *view) } static void -e_addressbook_view_set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec) +eab_view_set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec) { - EAddressbookView *eav = E_ADDRESSBOOK_VIEW(object); + EABView *eav = EAB_VIEW(object); switch (prop_id){ case PROP_BOOK: @@ -509,12 +511,6 @@ e_addressbook_view_set_property (GObject *object, guint prop_id, const GValue *v g_object_set(eav->model, "query", eav->query, NULL); - if (eav->current_alphabet_widget != NULL) { - GtkWidget *current = eav->current_alphabet_widget; - - eav->current_alphabet_widget = NULL; - gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (current), FALSE); - } break; case PROP_TYPE: change_view_type(eav, g_value_get_int (value)); @@ -526,9 +522,9 @@ e_addressbook_view_set_property (GObject *object, guint prop_id, const GValue *v } static void -e_addressbook_view_get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec) +eab_view_get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec) { - EAddressbookView *eav = E_ADDRESSBOOK_VIEW(object); + EABView *eav = EAB_VIEW(object); switch (prop_id) { case PROP_BOOK: @@ -550,44 +546,43 @@ e_addressbook_view_get_property (GObject *object, guint prop_id, GValue *value, } static ESelectionModel* -get_selection_model (EAddressbookView *view) +get_selection_model (EABView *view) { - if (view->view_type == E_ADDRESSBOOK_VIEW_MINICARD) - return e_minicard_view_widget_get_selection_model (E_MINICARD_VIEW_WIDGET(view->object)); - else if (view->view_type == E_ADDRESSBOOK_VIEW_TABLE) + if (view->view_type == EAB_VIEW_TABLE) return e_table_get_selection_model (e_table_scrolled_get_table (E_TABLE_SCROLLED(view->widget))); + else if (view->view_type == EAB_VIEW_MINICARD) + return e_minicard_view_widget_get_selection_model (E_MINICARD_VIEW_WIDGET(view->object)); #ifdef WITH_ADDRESSBOOK_VIEW_TREEVIEW - else if (view->view_type == E_ADDRESSBOOK_VIEW_TREEVIEW) { + else if (view->view_type == EAB_VIEW_TREEVIEW) return e_treeview_get_selection_model (GTK_TREE_VIEW (view->object)); - } #endif g_return_val_if_reached (NULL); } /* Popup menu stuff */ typedef struct { - EAddressbookView *view; + EABView *view; EPopupMenu *submenu; gpointer closure; -} CardAndBook; +} ContactAndBook; static ESelectionModel* -card_and_book_get_selection_model (CardAndBook *card_and_book) +contact_and_book_get_selection_model (ContactAndBook *contact_and_book) { - return get_selection_model (card_and_book->view); + return get_selection_model (contact_and_book->view); } static void -card_and_book_free (CardAndBook *card_and_book) +contact_and_book_free (ContactAndBook *contact_and_book) { - EAddressbookView *view = card_and_book->view; + EABView *view = contact_and_book->view; ESelectionModel *selection; - if (card_and_book->submenu) + if (contact_and_book->submenu) gal_view_instance_free_popup_menu (view->view_instance, - card_and_book->submenu); + contact_and_book->submenu); - selection = card_and_book_get_selection_model (card_and_book); + selection = contact_and_book_get_selection_model (contact_and_book); if (selection) e_selection_model_right_click_up(selection); @@ -595,33 +590,33 @@ card_and_book_free (CardAndBook *card_and_book) } static void -get_card_list_1(gint model_row, - gpointer closure) +get_contact_list_1(gint model_row, + gpointer closure) { - CardAndBook *card_and_book; + ContactAndBook *contact_and_book; GList **list; - EAddressbookView *view; - ECard *card; + EABView *view; + EContact *contact; - card_and_book = closure; - list = card_and_book->closure; - view = card_and_book->view; + contact_and_book = closure; + list = contact_and_book->closure; + view = contact_and_book->view; - card = e_addressbook_model_get_card(view->model, model_row); - *list = g_list_prepend(*list, card); + contact = eab_model_get_contact(view->model, model_row); + *list = g_list_prepend(*list, contact); } static GList * -get_card_list (CardAndBook *card_and_book) +get_contact_list (ContactAndBook *contact_and_book) { GList *list = NULL; ESelectionModel *selection; - selection = card_and_book_get_selection_model (card_and_book); + selection = contact_and_book_get_selection_model (contact_and_book); if (selection) { - card_and_book->closure = &list; - e_selection_model_foreach (selection, get_card_list_1, card_and_book); + contact_and_book->closure = &list; + e_selection_model_foreach (selection, get_contact_list_1, contact_and_book); } return list; @@ -631,135 +626,134 @@ static void has_email_address_1(gint model_row, gpointer closure) { - CardAndBook *card_and_book; + ContactAndBook *contact_and_book; gboolean *has_email; - EAddressbookView *view; - const ECard *card; - EList *email; + EABView *view; + const EContact *contact; + GList *email; - card_and_book = closure; - has_email = card_and_book->closure; - view = card_and_book->view; + contact_and_book = closure; + has_email = contact_and_book->closure; + view = contact_and_book->view; if (*has_email) return; - card = e_addressbook_model_peek_card(view->model, model_row); + contact = eab_model_contact_at(view->model, model_row); - g_object_get (G_OBJECT (card), - "email", &email, - NULL); + email = e_contact_get (E_CONTACT (contact), E_CONTACT_EMAIL); - if (e_list_length (email) > 0) + if (g_list_length (email) > 0) *has_email = TRUE; - g_object_unref (email); + g_list_foreach (email, (GFunc)g_free, NULL); + g_list_free (email); } static gboolean -get_has_email_address (CardAndBook *card_and_book) +get_has_email_address (ContactAndBook *contact_and_book) { ESelectionModel *selection; gboolean has_email = FALSE; - selection = card_and_book_get_selection_model (card_and_book); + selection = contact_and_book_get_selection_model (contact_and_book); if (selection) { - card_and_book->closure = &has_email; - e_selection_model_foreach (selection, has_email_address_1, card_and_book); + contact_and_book->closure = &has_email; + e_selection_model_foreach (selection, has_email_address_1, contact_and_book); } return has_email; } static void -save_as (GtkWidget *widget, CardAndBook *card_and_book) +save_as (GtkWidget *widget, ContactAndBook *contact_and_book) { - GList *cards = get_card_list (card_and_book); - if (cards) { - e_contact_list_save_as(_("Save as VCard"), cards, NULL); - e_free_object_list(cards); + GList *contacts = get_contact_list (contact_and_book); + if (contacts) { + eab_contact_list_save(_("Save as VCard"), contacts, NULL); + e_free_object_list(contacts); } } static void -send_as (GtkWidget *widget, CardAndBook *card_and_book) +send_as (GtkWidget *widget, ContactAndBook *contact_and_book) { - GList *cards = get_card_list (card_and_book); - if (cards) { - e_addressbook_send_card_list(cards, E_ADDRESSBOOK_DISPOSITION_AS_ATTACHMENT); - e_free_object_list(cards); + GList *contacts = get_contact_list (contact_and_book); + if (contacts) { + eab_send_contact_list(contacts, EAB_DISPOSITION_AS_ATTACHMENT); + e_free_object_list(contacts); } } static void -send_to (GtkWidget *widget, CardAndBook *card_and_book) +send_to (GtkWidget *widget, ContactAndBook *contact_and_book) { - GList *cards = get_card_list (card_and_book); + GList *contacts = get_contact_list (contact_and_book); - if (cards) { - e_addressbook_send_card_list(cards, E_ADDRESSBOOK_DISPOSITION_AS_TO); - e_free_object_list(cards); + if (contacts) { + eab_send_contact_list(contacts, EAB_DISPOSITION_AS_TO); + e_free_object_list(contacts); } } static void -print (GtkWidget *widget, CardAndBook *card_and_book) +print (GtkWidget *widget, ContactAndBook *contact_and_book) { - GList *cards = get_card_list (card_and_book); - if (cards) { - if (cards->next) - gtk_widget_show(e_contact_print_card_list_dialog_new(cards)); + GList *contacts = get_contact_list (contact_and_book); + if (contacts) { + if (contacts->next) + gtk_widget_show(e_contact_print_contact_list_dialog_new(contacts)); else - gtk_widget_show(e_contact_print_card_dialog_new(cards->data)); - e_free_object_list(cards); + gtk_widget_show(e_contact_print_contact_dialog_new(contacts->data)); + e_free_object_list(contacts); } } #if 0 /* Envelope printing is disabled for Evolution 1.0. */ static void -print_envelope (GtkWidget *widget, CardAndBook *card_and_book) +print_envelope (GtkWidget *widget, ContactAndBook *contact_and_book) { - GList *cards = get_card_list (card_and_book); + GList *cards = get_card_list (contact_and_book); if (cards) { - gtk_widget_show(e_contact_list_print_envelope_dialog_new(card_and_book->card)); + gtk_widget_show(e_contact_list_print_envelope_dialog_new(contact_and_book->card)); e_free_object_list(cards); } } #endif static void -copy (GtkWidget *widget, CardAndBook *card_and_book) +copy (GtkWidget *widget, ContactAndBook *contact_and_book) { - e_addressbook_view_copy (card_and_book->view); + eab_view_copy (contact_and_book->view); } static void -paste (GtkWidget *widget, CardAndBook *card_and_book) +paste (GtkWidget *widget, ContactAndBook *contact_and_book) { - e_addressbook_view_paste (card_and_book->view); + eab_view_paste (contact_and_book->view); } static void -cut (GtkWidget *widget, CardAndBook *card_and_book) +cut (GtkWidget *widget, ContactAndBook *contact_and_book) { - e_addressbook_view_cut (card_and_book->view); + eab_view_cut (contact_and_book->view); } static void -delete (GtkWidget *widget, CardAndBook *card_and_book) +delete (GtkWidget *widget, ContactAndBook *contact_and_book) { - if (e_contact_editor_confirm_delete(GTK_WINDOW(gtk_widget_get_toplevel(card_and_book->view->widget)))) { + if (e_contact_editor_confirm_delete(GTK_WINDOW(gtk_widget_get_toplevel(contact_and_book->view->widget)))) { EBook *book; - GList *list = get_card_list(card_and_book); + GList *list = get_contact_list(contact_and_book); GList *iterator; gboolean bulk_remove = FALSE; - bulk_remove = e_book_check_static_capability (card_and_book->view->model->book, + bulk_remove = e_book_check_static_capability (contact_and_book->view->model->book, "bulk-remove"); - g_object_get(card_and_book->view->model, + g_object_get(contact_and_book->view->model, "book", &book, NULL); @@ -767,26 +761,28 @@ delete (GtkWidget *widget, CardAndBook *card_and_book) GList *ids = NULL; for (iterator = list; iterator; iterator = iterator->next) { - ECard *card = iterator->data; - ids = g_list_prepend (ids, (char*)e_card_get_id (card)); + EContact *contact = iterator->data; + ids = g_list_prepend (ids, (char*)e_contact_get_const (contact, E_CONTACT_UID)); } /* Remove the cards all at once. */ - e_book_remove_cards (book, - ids, - NULL, - NULL); + /* XXX no callback specified... ugh */ + e_book_async_remove_contacts (book, + ids, + NULL, + NULL); g_list_free (ids); } else { for (iterator = list; iterator; iterator = iterator->next) { - ECard *card = iterator->data; + EContact *contact = iterator->data; /* Remove the card. */ - e_book_remove_card (book, - card, - NULL, - NULL); + /* XXX no callback specified... ugh */ + e_book_async_remove_contact (book, + e_contact_get_const (contact, E_CONTACT_UID), + NULL, + NULL); } } e_free_object_list(list); @@ -795,56 +791,55 @@ delete (GtkWidget *widget, CardAndBook *card_and_book) } static void -copy_to_folder (GtkWidget *widget, CardAndBook *card_and_book) +copy_to_folder (GtkWidget *widget, ContactAndBook *contact_and_book) { - e_addressbook_view_copy_to_folder (card_and_book->view); + eab_view_copy_to_folder (contact_and_book->view); } static void -move_to_folder (GtkWidget *widget, CardAndBook *card_and_book) +move_to_folder (GtkWidget *widget, ContactAndBook *contact_and_book) { - e_addressbook_view_move_to_folder (card_and_book->view); + eab_view_move_to_folder (contact_and_book->view); } static void -free_popup_info (GtkWidget *w, CardAndBook *card_and_book) +free_popup_info (GtkWidget *w, ContactAndBook *contact_and_book) { - card_and_book_free (card_and_book); + contact_and_book_free (contact_and_book); } static void -new_card (GtkWidget *widget, CardAndBook *card_and_book) +new_card (GtkWidget *widget, ContactAndBook *contact_and_book) { EBook *book; - ECard *card; + EContact *contact = e_contact_new(); - g_object_get(card_and_book->view->model, + g_object_get(contact_and_book->view->model, "book", &book, NULL); - e_addressbook_show_contact_editor (book, card = e_card_new(""), TRUE, TRUE); - g_object_unref(book); - g_object_unref(card); + eab_show_contact_editor (book, contact, TRUE, TRUE); + g_object_unref (book); + g_object_unref (contact); } static void -new_list (GtkWidget *widget, CardAndBook *card_and_book) +new_list (GtkWidget *widget, ContactAndBook *contact_and_book) { EBook *book; - ECard *card; + EContact *contact = e_contact_new (); - g_object_get(card_and_book->view->model, + g_object_get(contact_and_book->view->model, "book", &book, NULL); - - e_addressbook_show_contact_list_editor (book, card = e_card_new(""), TRUE, TRUE); + eab_show_contact_list_editor (book, contact, TRUE, TRUE); g_object_unref(book); - g_object_unref(card); + g_object_unref(contact); } #if 0 static void -sources (GtkWidget *widget, CardAndBook *card_and_book) +sources (GtkWidget *widget, ContactAndBook *contact_and_book) { BonoboControl *control; GNOME_Evolution_ShellView shell_view; @@ -874,9 +869,9 @@ sources (GtkWidget *widget, CardAndBook *card_and_book) #define POPUP_NOEMAIL_MASK 0x4 static void -do_popup_menu(EAddressbookView *view, GdkEvent *event) +do_popup_menu(EABView *view, GdkEvent *event) { - CardAndBook *card_and_book; + ContactAndBook *contact_and_book; GtkMenu *popup; EPopupMenu *submenu = NULL; ESelectionModel *selection_model; @@ -921,308 +916,62 @@ do_popup_menu(EAddressbookView *view, GdkEvent *event) E_POPUP_TERMINATOR }; - card_and_book = g_new(CardAndBook, 1); - card_and_book->view = view; - card_and_book->submenu = submenu; + contact_and_book = g_new(ContactAndBook, 1); + contact_and_book->view = view; + contact_and_book->submenu = submenu; - g_object_ref (card_and_book->view); + g_object_ref (contact_and_book->view); - selection_model = card_and_book_get_selection_model (card_and_book); + selection_model = contact_and_book_get_selection_model (contact_and_book); if (selection_model) selection = e_selection_model_selected_count (selection_model) > 0; popup = e_popup_menu_create (menu, 0, - (e_addressbook_model_editable (view->model) ? 0 : POPUP_READONLY_MASK) + + (eab_model_editable (view->model) ? 0 : POPUP_READONLY_MASK) + (selection ? 0 : POPUP_NOSELECTION_MASK) + - (get_has_email_address (card_and_book) ? 0 : POPUP_NOEMAIL_MASK), - card_and_book); + (get_has_email_address (contact_and_book) ? 0 : POPUP_NOEMAIL_MASK), + contact_and_book); g_signal_connect (popup, "selection-done", - G_CALLBACK (free_popup_info), card_and_book); + G_CALLBACK (free_popup_info), contact_and_book); e_popup_menu (popup, event); } - -/* Minicard view stuff */ - -/* Translators: put here a list of labels you want to see on buttons in - addressbook. You may use any character to separate labels but it must - also be placed at the begining ot the string */ -const char *button_labels = N_(",123,a,b,c,d,e,f,g,h,i,j,k,l,m,n,o,p,q,r,s,t,u,v,w,x,y,z"); -/* Translators: put here a list of characters that correspond to buttons - in addressbook. You may use any character to separate labels but it - must also be placed at the begining ot the string. - Use lower case letters if possible. */ -const char *button_letters = N_(",0,a,b,c,d,e,f,g,h,i,j,k,l,m,n,o,p,q,r,s,t,u,v,w,x,y,z"); - -typedef struct { - EAddressbookView *view; - GtkWidget *button; - GtkWidget *vbox; - gchar *letters; -} LetterClosure; - -static char ** -e_utf8_split (const char *utf8_str, gunichar delim) -{ - GSList *str_list = NULL, *sl; - int n = 0; - const char *str, *s; - char **str_array; - - g_return_val_if_fail (utf8_str != NULL, NULL); - - str = utf8_str; - while (*str != '\0') { - int len; - char *new_str; - - for (s = str; *s != '\0' && g_utf8_get_char (s) != delim; s = g_utf8_next_char (s)) - ; - len = s - str; - new_str = g_new (char, len + 1); - if (len > 0) { - memcpy (new_str, str, len); - } - new_str[len] = '\0'; - str_list = g_slist_prepend (str_list, new_str); - n++; - if (*s != '\0') { - str = g_utf8_next_char (s); - } else { - str = s; - } - } - - str_array = g_new (char *, n + 1); - str_array[n--] = NULL; - for (sl = str_list; sl != NULL; sl = sl->next) { - str_array[n--] = sl->data; - } - g_slist_free (str_list); - - return str_array; -} - static void -jump_to_letters (EAddressbookView *view, gchar* l) -{ - char *query; - char *s; - char buf[6 + 1]; - - if (g_unichar_isdigit (g_utf8_get_char(l))) { - const char *letters = _(button_letters); - char **letter_v; - GString *gstr; - char **p; - - letter_v = e_utf8_split (g_utf8_next_char (letters), - g_utf8_get_char (letters)); - g_assert (letter_v != NULL && letter_v[0] != NULL); - gstr = g_string_new ("(not (or "); - for (p = letter_v + 1; *p != NULL; p++) { - for (s = *p; *s != '\0'; s = g_utf8_next_char (s)) { - buf [g_unichar_to_utf8 (g_utf8_get_char(s), buf)] = '\0'; - g_string_append_printf (gstr, "(beginswith \"file_as\" \"%s\")", buf); - } - } - g_string_append (gstr, "))"); - query = gstr->str; - g_strfreev (letter_v); - g_string_free (gstr, FALSE); - } else { - GString *gstr; - - gstr = g_string_new ("(or "); - - for (s = l; *s != '\0'; s = g_utf8_next_char (s)) { - buf [g_unichar_to_utf8 (g_utf8_get_char(s), buf)] = '\0'; - g_string_append_printf (gstr, "(beginswith \"file_as\" \"%s\")", buf); - } - - g_string_append (gstr, ")"); - query = gstr->str; - g_string_free (gstr, FALSE); - } - g_object_set (view, - "query", query, - NULL); - g_free (query); -} - -static void -button_toggled(GtkWidget *button, LetterClosure *closure) +render_contact (int row, EABView *view) { - EAddressbookView *view = closure->view; - - if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (button))) { - GtkWidget *current = view->current_alphabet_widget; + EContact *contact = eab_model_get_contact (view->model, row); - view->current_alphabet_widget = NULL; - if (current && current != button) - gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (current), FALSE); - jump_to_letters (view, closure->letters); - view->current_alphabet_widget = button; - alphabet_state_change (view, g_utf8_get_char(closure->letters)); - } else { - if (view->current_alphabet_widget != NULL && - view->current_alphabet_widget == button) { - view->current_alphabet_widget = NULL; - g_object_set (view, - "query", NULL, - NULL); - alphabet_state_change (view, 0); - } - } + eab_contact_display_render (EAB_CONTACT_DISPLAY (view->contact_display), contact, + EAB_CONTACT_DISPLAY_RENDER_NORMAL); } static void -free_closure(gpointer data, GObject *where_object_was) +selection_changed (GObject *o, EABView *view) { - GtkWidget *button = GTK_WIDGET (where_object_was); - LetterClosure *closure = data; - if (button != NULL && - button == closure->view->current_alphabet_widget) { - closure->view->current_alphabet_widget = NULL; - } - g_free (closure->letters); - g_free (closure); -} - -static GtkWidget * -create_alphabet (EAddressbookView *view) -{ - GtkWidget *widget, *viewport, *vbox; - const char *labels, *letters; - char **label_v, **letter_v; - char **pl, **pc; - gunichar sep; - - widget = gtk_scrolled_window_new (NULL, NULL); - gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (widget), - GTK_POLICY_NEVER, GTK_POLICY_AUTOMATIC); - - viewport = gtk_viewport_new (NULL, NULL); - gtk_container_add (GTK_CONTAINER (widget), viewport); - gtk_container_set_border_width (GTK_CONTAINER (viewport), 4); - gtk_viewport_set_shadow_type (GTK_VIEWPORT (viewport), GTK_SHADOW_NONE); - - vbox = gtk_vbox_new (FALSE, 4); - gtk_container_add (GTK_CONTAINER (viewport), vbox); - - labels = _(button_labels); - sep = g_utf8_get_char (labels); - label_v = e_utf8_split (g_utf8_next_char (labels), sep); - letters = _(button_letters); - sep = g_utf8_get_char (letters); - letter_v = e_utf8_split (g_utf8_next_char (letters), sep); - g_assert (label_v != NULL && letter_v != NULL); - for (pl = label_v, pc = letter_v; *pl != NULL && *pc != NULL; pl++, pc++) { - GtkWidget *button; - LetterClosure *closure; - char *label; - - label = *pl; - button = gtk_toggle_button_new_with_label (label); - gtk_box_pack_start (GTK_BOX (vbox), button, FALSE, FALSE, 0); - - closure = g_new (LetterClosure, 1); - closure->view = view; - closure->letters = g_strdup (*pc); - closure->button = button; - closure->vbox = vbox; - g_signal_connect(button, "toggled", - G_CALLBACK (button_toggled), closure); - g_object_weak_ref (G_OBJECT (button), free_closure, closure); - - } - g_strfreev (label_v); - g_strfreev (letter_v); - - gtk_widget_show_all (widget); - - return widget; -} + ESelectionModel *selection_model; -static void -selection_changed (GObject *o, EAddressbookView *view) -{ command_state_change (view); -} - -static void -minicard_right_click (EMinicardView *minicard_view_item, GdkEvent *event, EAddressbookView *view) -{ - do_popup_menu(view, event); -} - -static void -create_minicard_view (EAddressbookView *view) -{ - GtkWidget *scrolled_window; - GtkWidget *alphabet; - GtkWidget *minicard_view; - GtkWidget *minicard_hbox; - EAddressbookReflowAdapter *adapter; - - gtk_widget_push_colormap (gdk_rgb_get_cmap ()); - - minicard_hbox = gtk_hbox_new(FALSE, 0); - - adapter = E_ADDRESSBOOK_REFLOW_ADAPTER(e_addressbook_reflow_adapter_new (view->model)); - minicard_view = e_minicard_view_widget_new(adapter); - - /* A hack */ - g_object_set_data (G_OBJECT (adapter), "view", view); - - g_signal_connect(minicard_view, "selection_change", - G_CALLBACK(selection_changed), view); - - g_signal_connect(minicard_view, "right_click", - G_CALLBACK(minicard_right_click), view); - - - view->object = G_OBJECT(minicard_view); - view->widget = minicard_hbox; - - scrolled_window = gtk_scrolled_window_new (NULL, NULL); - gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolled_window), - GTK_POLICY_AUTOMATIC, - GTK_POLICY_AUTOMATIC); - - gtk_container_add (GTK_CONTAINER (scrolled_window), minicard_view); - - gtk_box_pack_start(GTK_BOX(minicard_hbox), scrolled_window, TRUE, TRUE, 0); - - alphabet = create_alphabet(view); - if (alphabet) - gtk_box_pack_start(GTK_BOX(minicard_hbox), alphabet, FALSE, FALSE, 0); - - gtk_table_attach(GTK_TABLE(view), minicard_hbox, - 0, 1, - 0, 1, - GTK_FILL | GTK_EXPAND, GTK_FILL | GTK_EXPAND, - 0, 0); - - gtk_widget_show_all( GTK_WIDGET(minicard_hbox) ); - - gtk_widget_pop_colormap (); - - e_reflow_model_changed (E_REFLOW_MODEL (adapter)); + selection_model = get_selection_model (view); - g_object_unref (adapter); + if (e_selection_model_selected_count (selection_model) == 1) + e_selection_model_foreach (selection_model, + (EForeachFunc)render_contact, view); + else + eab_contact_display_render (EAB_CONTACT_DISPLAY (view->contact_display), NULL, + EAB_CONTACT_DISPLAY_RENDER_NORMAL); + } static void -table_double_click(ETableScrolled *table, gint row, gint col, GdkEvent *event, EAddressbookView *view) +table_double_click(ETableScrolled *table, gint row, gint col, GdkEvent *event, EABView *view) { if (E_IS_ADDRESSBOOK_TABLE_ADAPTER(view->object)) { - EAddressbookModel *model = view->model; - ECard *card = e_addressbook_model_get_card(model, row); + EABModel *model = view->model; + EContact *contact = eab_model_get_contact (model, row); EBook *book; g_object_get(model, @@ -1231,25 +980,25 @@ table_double_click(ETableScrolled *table, gint row, gint col, GdkEvent *event, E g_assert (E_IS_BOOK (book)); - if (e_card_evolution_list (card)) - e_addressbook_show_contact_list_editor (book, card, FALSE, view->editable); + if (e_contact_get (contact, E_CONTACT_IS_LIST)) + eab_show_contact_list_editor (book, contact, FALSE, view->editable); else - e_addressbook_show_contact_editor (book, card, FALSE, view->editable); + eab_show_contact_editor (book, contact, FALSE, view->editable); g_object_unref (book); - g_object_unref (card); + g_object_unref (contact); } } static gint -table_right_click(ETableScrolled *table, gint row, gint col, GdkEvent *event, EAddressbookView *view) +table_right_click(ETableScrolled *table, gint row, gint col, GdkEvent *event, EABView *view) { do_popup_menu(view, event); return TRUE; } static gint -table_white_space_event(ETableScrolled *table, GdkEvent *event, EAddressbookView *view) +table_white_space_event(ETableScrolled *table, GdkEvent *event, EABView *view) { if (event->type == GDK_BUTTON_PRESS && ((GdkEventButton *)event)->button == 3) { do_popup_menu(view, event); @@ -1269,7 +1018,7 @@ table_drag_data_get (ETable *table, guint time, gpointer user_data) { - EAddressbookView *view = user_data; + EABView *view = user_data; if (!E_IS_ADDRESSBOOK_TABLE_ADAPTER(view->object)) return; @@ -1278,7 +1027,7 @@ table_drag_data_get (ETable *table, case DND_TARGET_TYPE_VCARD: { char *value; - value = e_card_get_vcard(view->model->data[row]); + value = e_vcard_to_string (E_VCARD (view->model->data[row]), EVC_FORMAT_VCARD_30); gtk_selection_data_set (selection_data, selection_data->target, @@ -1290,68 +1039,62 @@ table_drag_data_get (ETable *table, } static void -emit_status_message (EAddressbookView *eav, const gchar *status) +emit_status_message (EABView *eav, const gchar *status) { g_signal_emit (eav, - e_addressbook_view_signals [STATUS_MESSAGE], 0, + eab_view_signals [STATUS_MESSAGE], 0, status); } static void -emit_search_result (EAddressbookView *eav, EBookViewStatus status) +emit_search_result (EABView *eav, EBookViewStatus status) { g_signal_emit (eav, - e_addressbook_view_signals [SEARCH_RESULT], 0, + eab_view_signals [SEARCH_RESULT], 0, status); } static void -emit_folder_bar_message (EAddressbookView *eav, const gchar *message) +emit_folder_bar_message (EABView *eav, const gchar *message) { g_signal_emit (eav, - e_addressbook_view_signals [FOLDER_BAR_MESSAGE], 0, + eab_view_signals [FOLDER_BAR_MESSAGE], 0, message); } static void -status_message (GtkObject *object, const gchar *status, EAddressbookView *eav) +status_message (GtkObject *object, const gchar *status, EABView *eav) { emit_status_message (eav, status); } static void -search_result (GtkObject *object, EBookViewStatus status, EAddressbookView *eav) +search_result (GtkObject *object, EBookViewStatus status, EABView *eav) { emit_search_result (eav, status); } static void -folder_bar_message (GtkObject *object, const gchar *status, EAddressbookView *eav) +folder_bar_message (GtkObject *object, const gchar *status, EABView *eav) { emit_folder_bar_message (eav, status); } static void -stop_state_changed (GtkObject *object, EAddressbookView *eav) +stop_state_changed (GtkObject *object, EABView *eav) { command_state_change (eav); } static void -command_state_change (EAddressbookView *eav) +command_state_change (EABView *eav) { /* Reffing during emission is unnecessary. Gtk automatically refs during an emission. */ - g_signal_emit (eav, e_addressbook_view_signals [COMMAND_STATE_CHANGE], 0); + g_signal_emit (eav, eab_view_signals [COMMAND_STATE_CHANGE], 0); } static void -alphabet_state_change (EAddressbookView *eav, gunichar letter) -{ - g_signal_emit (eav, e_addressbook_view_signals [ALPHABET_STATE_CHANGE], 0, letter); -} - -static void -backend_died (GtkObject *object, EAddressbookView *eav) +backend_died (GtkObject *object, EABView *eav) { char *message = g_strdup_printf (_("The addressbook backend for\n%s\nhas crashed. " "You will have to restart Evolution in order " @@ -1362,12 +1105,52 @@ backend_died (GtkObject *object, EAddressbookView *eav) } static void -create_table_view (EAddressbookView *view) +minicard_right_click (EMinicardView *minicard_view_item, GdkEvent *event, EABView *view) +{ + do_popup_menu(view, event); +} + +static void +create_minicard_view (EABView *view) +{ + GtkWidget *scrolled_window; + GtkWidget *minicard_view; + EAddressbookReflowAdapter *adapter; + + adapter = E_ADDRESSBOOK_REFLOW_ADAPTER(e_addressbook_reflow_adapter_new (view->model)); + minicard_view = e_minicard_view_widget_new(adapter); + + g_signal_connect(minicard_view, "selection_change", + G_CALLBACK(selection_changed), view); + + g_signal_connect(minicard_view, "right_click", + G_CALLBACK(minicard_right_click), view); + + scrolled_window = gtk_scrolled_window_new (NULL, NULL); + gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolled_window), + GTK_POLICY_AUTOMATIC, + GTK_POLICY_AUTOMATIC); + + view->object = G_OBJECT(minicard_view); + view->widget = scrolled_window; + + gtk_container_add (GTK_CONTAINER (scrolled_window), minicard_view); + gtk_widget_show (minicard_view); + + gtk_widget_show_all( GTK_WIDGET(scrolled_window) ); + + gtk_paned_add1 (GTK_PANED (view->paned), scrolled_window); + + e_reflow_model_changed (E_REFLOW_MODEL (adapter)); +} + +static void +create_table_view (EABView *view) { ETableModel *adapter; GtkWidget *table; - adapter = e_addressbook_table_adapter_new(view->model); + adapter = eab_table_adapter_new(view->model); /* Here we create the table. We give it the three pieces of the table we've created, the header, the model, and the @@ -1395,11 +1178,7 @@ create_table_view (EAddressbookView *view) G_CALLBACK (table_drag_data_get), view); - gtk_table_attach(GTK_TABLE(view), table, - 0, 1, - 0, 1, - GTK_FILL | GTK_EXPAND, GTK_FILL | GTK_EXPAND, - 0, 0); + gtk_paned_add1 (GTK_PANED (view->paned), table); gtk_widget_show( GTK_WIDGET(table) ); } @@ -1408,11 +1187,11 @@ create_table_view (EAddressbookView *view) static void treeview_row_activated(GtkTreeView *treeview, GtkTreePath *path, GtkTreeViewColumn *column, - EAddressbookView *view) + EABView *view) { - EAddressbookModel *model = view->model; + EABModel *model = view->model; int row = gtk_tree_path_get_indices (path)[0]; - ECard *card = e_addressbook_model_get_card(model, row); + ECard *card = eab_model_get_card(model, row); EBook *book; g_object_get(model, @@ -1422,16 +1201,16 @@ treeview_row_activated(GtkTreeView *treeview, g_assert (E_IS_BOOK (book)); if (e_card_evolution_list (card)) - e_addressbook_show_contact_list_editor (book, card, FALSE, view->editable); + eab_show_contact_list_editor (book, card, FALSE, view->editable); else - e_addressbook_show_contact_editor (book, card, FALSE, view->editable); + eab_show_contact_editor (book, card, FALSE, view->editable); g_object_unref (book); g_object_unref (card); } static void -create_treeview_view (EAddressbookView *view) +create_treeview_view (EABView *view) { GtkTreeModel *adapter; ECardSimple *simple; @@ -1441,7 +1220,7 @@ create_treeview_view (EAddressbookView *view) simple = e_card_simple_new(NULL); - adapter = e_addressbook_treeview_adapter_new(view->model); + adapter = eab_treeview_adapter_new(view->model); scrolled = gtk_scrolled_window_new (NULL, NULL); treeview = gtk_tree_view_new_with_model (adapter); @@ -1490,11 +1269,7 @@ create_treeview_view (EAddressbookView *view) g_signal_connect(e_treeview_get_selection_model (GTK_TREE_VIEW (treeview)), "selection_changed", G_CALLBACK(selection_changed), view); - gtk_table_attach(GTK_TABLE(view), scrolled, - 0, 1, - 0, 1, - GTK_FILL | GTK_EXPAND, GTK_FILL | GTK_EXPAND, - 0, 0); + gtk_paned_add1 (GTK_PANED (view->paned), scrolled); gtk_widget_show( GTK_WIDGET(scrolled) ); @@ -1503,26 +1278,27 @@ create_treeview_view (EAddressbookView *view) #endif static void -change_view_type (EAddressbookView *view, EAddressbookViewType view_type) +change_view_type (EABView *view, EABViewType view_type) { if (view_type == view->view_type) return; if (view->widget) { + gtk_container_remove (GTK_CONTAINER (view->paned), view->widget); gtk_widget_destroy (view->widget); view->widget = NULL; } view->object = NULL; switch (view_type) { - case E_ADDRESSBOOK_VIEW_MINICARD: - create_minicard_view (view); - break; - case E_ADDRESSBOOK_VIEW_TABLE: + case EAB_VIEW_TABLE: create_table_view (view); break; + case EAB_VIEW_MINICARD: + create_minicard_view (view); + break; #ifdef WITH_ADDRESSBOOK_VIEW_TREEVIEW - case E_ADDRESSBOOK_VIEW_TREEVIEW: + case EAB_VIEW_TREEVIEW: create_treeview_view (view); break; #endif @@ -1614,7 +1390,7 @@ e_contact_print_button(GtkDialog *dialog, gint response, gpointer data) } void -e_addressbook_view_setup_menus (EAddressbookView *view, +eab_view_setup_menus (EABView *view, BonoboUIComponent *uic) { @@ -1631,7 +1407,7 @@ e_addressbook_view_setup_menus (EAddressbookView *view, } /** - * e_addressbook_view_discard_menus: + * eab_view_discard_menus: * @view: An addressbook view. * * Makes an addressbook view discard its GAL view menus and its views instance @@ -1639,7 +1415,7 @@ e_addressbook_view_setup_menus (EAddressbookView *view, * deactivated. **/ void -e_addressbook_view_discard_menus (EAddressbookView *view) +eab_view_discard_menus (EABView *view) { g_return_if_fail (view != NULL); g_return_if_fail (E_IS_ADDRESSBOOK_VIEW (view)); @@ -1661,9 +1437,9 @@ e_addressbook_view_discard_menus (EAddressbookView *view) } void -e_addressbook_view_print(EAddressbookView *view) +eab_view_print(EABView *view) { - if (view->view_type == E_ADDRESSBOOK_VIEW_MINICARD) { + if (view->view_type == EAB_VIEW_MINICARD) { char *query; EBook *book; GtkWidget *print; @@ -1673,12 +1449,10 @@ e_addressbook_view_print(EAddressbookView *view) "book", &book, NULL); print = e_contact_print_dialog_new(book, query); - - g_object_unref(book); g_free(query); gtk_widget_show_all(print); } - else if (view->view_type == E_ADDRESSBOOK_VIEW_TABLE) { + else if (view->view_type == EAB_VIEW_TABLE) { GtkWidget *dialog; EPrintable *printable; ETable *etable; @@ -1709,16 +1483,16 @@ e_addressbook_view_print(EAddressbookView *view) gtk_widget_show(dialog); } #ifdef WITH_ADDRESSBOOK_VIEW_TREEVIEW - else if (view->view_type == E_ADDRESSBOOK_VIEW_TREEVIEW) { + else if (view->view_type == EAB_VIEW_TREEVIEW) { /* XXX */ } #endif } void -e_addressbook_view_print_preview(EAddressbookView *view) +eab_view_print_preview(EABView *view) { - if (view->view_type == E_ADDRESSBOOK_VIEW_MINICARD) { + if (view->view_type == EAB_VIEW_MINICARD) { char *query; EBook *book; @@ -1727,10 +1501,9 @@ e_addressbook_view_print_preview(EAddressbookView *view) "book", &book, NULL); e_contact_print_preview(book, query); - g_object_unref(book); g_free(query); } - else if (view->view_type == E_ADDRESSBOOK_VIEW_TABLE) { + else if (view->view_type == EAB_VIEW_TABLE) { EPrintable *printable; ETable *etable; GnomePrintJob *master; @@ -1769,27 +1542,27 @@ e_addressbook_view_print_preview(EAddressbookView *view) g_object_unref (printable); } #ifdef WITH_ADDRESSBOOK_VIEW_TREEVIEW - else if (view->view_type == E_ADDRESSBOOK_VIEW_TREEVIEW) { + else if (view->view_type == EAB_VIEW_TREEVIEW) { /* XXX */ } #endif } void -e_addressbook_view_delete_selection(EAddressbookView *view) +eab_view_delete_selection(EABView *view) { - CardAndBook card_and_book; + ContactAndBook contact_and_book; - memset (&card_and_book, 0, sizeof (card_and_book)); - card_and_book.view = view; + memset (&contact_and_book, 0, sizeof (contact_and_book)); + contact_and_book.view = view; - delete (GTK_WIDGET (view), &card_and_book); + delete (GTK_WIDGET (view), &contact_and_book); } static void invisible_destroyed (gpointer data, GObject *where_object_was) { - EAddressbookView *view = data; + EABView *view = data; view->invisible = NULL; } @@ -1798,11 +1571,11 @@ selection_get (GtkWidget *invisible, GtkSelectionData *selection_data, guint info, guint time_stamp, - EAddressbookView *view) + EABView *view) { char *value; - value = e_card_list_get_vcard(view->clipboard_cards); + value = eab_contact_list_to_string (view->clipboard_contacts); gtk_selection_data_set (selection_data, GDK_SELECTION_TYPE_STRING, 8, value, strlen (value)); @@ -1812,12 +1585,12 @@ selection_get (GtkWidget *invisible, static void selection_clear_event (GtkWidget *invisible, GdkEventSelection *event, - EAddressbookView *view) + EABView *view) { - if (view->clipboard_cards) { - g_list_foreach (view->clipboard_cards, (GFunc)g_object_unref, NULL); - g_list_free (view->clipboard_cards); - view->clipboard_cards = NULL; + if (view->clipboard_contacts) { + g_list_foreach (view->clipboard_contacts, (GFunc)g_object_unref, NULL); + g_list_free (view->clipboard_contacts); + view->clipboard_contacts = NULL; } } @@ -1825,27 +1598,25 @@ static void selection_received (GtkWidget *invisible, GtkSelectionData *selection_data, guint time, - EAddressbookView *view) + EABView *view) { if (selection_data->length < 0 || selection_data->type != GDK_SELECTION_TYPE_STRING) { return; } else { /* XXX make sure selection_data->data = \0 terminated */ - GList *card_list = e_card_load_cards_from_string_with_default_charset (selection_data->data, "ISO-8859-1"); + GList *contact_list = eab_contact_list_from_string (selection_data->data); GList *l; - if (!card_list /* it wasn't a vcard list */) - return; - - for (l = card_list; l; l = l->next) { - ECard *card = l->data; + for (l = contact_list; l; l = l->next) { + EContact *contact = l->data; - e_card_merging_book_add_card (view->book, card, NULL /* XXX */, NULL); + /* XXX NULL for a callback /sigh */ + eab_merging_book_add_contact (view->book, contact, NULL /* XXX */, NULL); } - g_list_foreach (card_list, (GFunc)g_object_unref, NULL); - g_list_free (card_list); + g_list_foreach (contact_list, (GFunc)g_object_unref, NULL); + g_list_free (contact_list); } } @@ -1857,7 +1628,7 @@ add_to_list (int model_row, gpointer closure) } static GList * -get_selected_cards (EAddressbookView *view) +get_selected_contacts (EABView *view) { GList *list; GList *iterator; @@ -1867,66 +1638,64 @@ get_selected_cards (EAddressbookView *view) e_selection_model_foreach (selection, add_to_list, &list); for (iterator = list; iterator; iterator = iterator->next) { - iterator->data = e_addressbook_model_card_at (view->model, GPOINTER_TO_INT (iterator->data)); - if (iterator->data) - g_object_ref (iterator->data); + iterator->data = eab_model_get_contact (view->model, GPOINTER_TO_INT (iterator->data)); } list = g_list_reverse (list); return list; } void -e_addressbook_view_save_as (EAddressbookView *view) +eab_view_save_as (EABView *view) { - GList *list = get_selected_cards (view); + GList *list = get_selected_contacts (view); if (list) - e_contact_list_save_as (_("Save as VCard"), list, NULL); + eab_contact_list_save (_("Save as VCard"), list, NULL); e_free_object_list(list); } void -e_addressbook_view_view (EAddressbookView *view) +eab_view_view (EABView *view) { - GList *list = get_selected_cards (view); - e_addressbook_show_multiple_cards (view->book, list, view->editable); + GList *list = get_selected_contacts (view); + eab_show_multiple_contacts (view->book, list, view->editable); e_free_object_list(list); } void -e_addressbook_view_send (EAddressbookView *view) +eab_view_send (EABView *view) { - GList *list = get_selected_cards (view); + GList *list = get_selected_contacts (view); if (list) - e_addressbook_send_card_list (list, E_ADDRESSBOOK_DISPOSITION_AS_ATTACHMENT); + eab_send_contact_list (list, EAB_DISPOSITION_AS_ATTACHMENT); e_free_object_list(list); } void -e_addressbook_view_send_to (EAddressbookView *view) +eab_view_send_to (EABView *view) { - GList *list = get_selected_cards (view); + GList *list = get_selected_contacts (view); if (list) - e_addressbook_send_card_list (list, E_ADDRESSBOOK_DISPOSITION_AS_TO); + eab_send_contact_list (list, EAB_DISPOSITION_AS_TO); e_free_object_list(list); } void -e_addressbook_view_cut (EAddressbookView *view) +eab_view_cut (EABView *view) { - e_addressbook_view_copy (view); - e_addressbook_view_delete_selection (view); + eab_view_copy (view); + eab_view_delete_selection (view); } void -e_addressbook_view_copy (EAddressbookView *view) +eab_view_copy (EABView *view) { - view->clipboard_cards = get_selected_cards (view); + view->clipboard_contacts = get_selected_contacts (view); gtk_selection_owner_set (view->invisible, clipboard_atom, GDK_CURRENT_TIME); } void -e_addressbook_view_paste (EAddressbookView *view) +eab_view_paste (EABView *view) { gtk_selection_convert (view->invisible, clipboard_atom, GDK_SELECTION_TYPE_STRING, @@ -1934,7 +1703,7 @@ e_addressbook_view_paste (EAddressbookView *view) } void -e_addressbook_view_select_all (EAddressbookView *view) +eab_view_select_all (EABView *view) { ESelectionModel *model = get_selection_model (view); @@ -1944,7 +1713,7 @@ e_addressbook_view_select_all (EAddressbookView *view) } void -e_addressbook_view_show_all(EAddressbookView *view) +eab_view_show_all(EABView *view) { g_object_set(view, "query", NULL, @@ -1952,44 +1721,44 @@ e_addressbook_view_show_all(EAddressbookView *view) } void -e_addressbook_view_stop(EAddressbookView *view) +eab_view_stop(EABView *view) { if (view) - e_addressbook_model_stop (view->model); + eab_model_stop (view->model); } static void -view_transfer_cards (EAddressbookView *view, gboolean delete_from_source) +view_transfer_contacts (EABView *view, gboolean delete_from_source) { EBook *book; - GList *cards; + GList *contacts; GtkWindow *parent_window; g_object_get(view->model, "book", &book, NULL); - cards = get_selected_cards (view); + contacts = get_selected_contacts (view); parent_window = GTK_WINDOW (gtk_widget_get_toplevel (GTK_WIDGET (view))); - e_addressbook_transfer_cards (book, cards, delete_from_source, parent_window); + eab_transfer_contacts (book, contacts, delete_from_source, parent_window); g_object_unref(book); } void -e_addressbook_view_copy_to_folder (EAddressbookView *view) +eab_view_copy_to_folder (EABView *view) { - view_transfer_cards (view, FALSE); + view_transfer_contacts (view, FALSE); } void -e_addressbook_view_move_to_folder (EAddressbookView *view) +eab_view_move_to_folder (EABView *view) { - view_transfer_cards (view, TRUE); + view_transfer_contacts (view, TRUE); } static gboolean -e_addressbook_view_selection_nonempty (EAddressbookView *view) +eab_view_selection_nonempty (EABView *view) { ESelectionModel *selection_model; @@ -2001,85 +1770,85 @@ e_addressbook_view_selection_nonempty (EAddressbookView *view) } gboolean -e_addressbook_view_can_create (EAddressbookView *view) +eab_view_can_create (EABView *view) { - return view ? e_addressbook_model_editable (view->model) : FALSE; + return view ? eab_model_editable (view->model) : FALSE; } gboolean -e_addressbook_view_can_print (EAddressbookView *view) +eab_view_can_print (EABView *view) { - return view && view->model ? e_addressbook_model_card_count (view->model) : FALSE; + return view && view->model ? eab_model_contact_count (view->model) : FALSE; } gboolean -e_addressbook_view_can_save_as (EAddressbookView *view) +eab_view_can_save_as (EABView *view) { - return view ? e_addressbook_view_selection_nonempty (view) : FALSE; + return view ? eab_view_selection_nonempty (view) : FALSE; } gboolean -e_addressbook_view_can_view (EAddressbookView *view) +eab_view_can_view (EABView *view) { - return view ? e_addressbook_view_selection_nonempty (view) : FALSE; + return view ? eab_view_selection_nonempty (view) : FALSE; } gboolean -e_addressbook_view_can_send (EAddressbookView *view) +eab_view_can_send (EABView *view) { - return view ? e_addressbook_view_selection_nonempty (view) : FALSE; + return view ? eab_view_selection_nonempty (view) : FALSE; } gboolean -e_addressbook_view_can_send_to (EAddressbookView *view) +eab_view_can_send_to (EABView *view) { - return view ? e_addressbook_view_selection_nonempty (view) : FALSE; + return view ? eab_view_selection_nonempty (view) : FALSE; } gboolean -e_addressbook_view_can_delete (EAddressbookView *view) +eab_view_can_delete (EABView *view) { - return view ? e_addressbook_view_selection_nonempty (view) && e_addressbook_model_editable (view->model) : FALSE; + return view ? eab_view_selection_nonempty (view) && eab_model_editable (view->model) : FALSE; } gboolean -e_addressbook_view_can_cut (EAddressbookView *view) +eab_view_can_cut (EABView *view) { - return view ? e_addressbook_view_selection_nonempty (view) && e_addressbook_model_editable (view->model) : FALSE; + return view ? eab_view_selection_nonempty (view) && eab_model_editable (view->model) : FALSE; } gboolean -e_addressbook_view_can_copy (EAddressbookView *view) +eab_view_can_copy (EABView *view) { - return view ? e_addressbook_view_selection_nonempty (view) : FALSE; + return view ? eab_view_selection_nonempty (view) : FALSE; } gboolean -e_addressbook_view_can_paste (EAddressbookView *view) +eab_view_can_paste (EABView *view) { - return view ? e_addressbook_model_editable (view->model) : FALSE; + return view ? eab_model_editable (view->model) : FALSE; } gboolean -e_addressbook_view_can_select_all (EAddressbookView *view) +eab_view_can_select_all (EABView *view) { - return view ? e_addressbook_model_card_count (view->model) != 0 : FALSE; + return view ? eab_model_contact_count (view->model) != 0 : FALSE; } gboolean -e_addressbook_view_can_stop (EAddressbookView *view) +eab_view_can_stop (EABView *view) { - return view ? e_addressbook_model_can_stop (view->model) : FALSE; + return view ? eab_model_can_stop (view->model) : FALSE; } gboolean -e_addressbook_view_can_copy_to_folder (EAddressbookView *view) +eab_view_can_copy_to_folder (EABView *view) { - return view ? e_addressbook_view_selection_nonempty (view) : FALSE; + return view ? eab_view_selection_nonempty (view) : FALSE; } gboolean -e_addressbook_view_can_move_to_folder (EAddressbookView *view) +eab_view_can_move_to_folder (EABView *view) { - return view ? e_addressbook_view_selection_nonempty (view) && e_addressbook_model_editable (view->model) : FALSE; + return view ? eab_view_selection_nonempty (view) && eab_model_editable (view->model) : FALSE; } diff --git a/addressbook/gui/widgets/e-addressbook-view.etspec b/addressbook/gui/widgets/e-addressbook-view.etspec index a0a0015d75..812a88b060 100644 --- a/addressbook/gui/widgets/e-addressbook-view.etspec +++ b/addressbook/gui/widgets/e-addressbook-view.etspec @@ -1,14 +1,17 @@ - - - + + + + + + + + - - - - - - + + + + + + + diff --git a/addressbook/gui/widgets/e-addressbook-view.h b/addressbook/gui/widgets/e-addressbook-view.h index dbf32811d8..1573f682ed 100644 --- a/addressbook/gui/widgets/e-addressbook-view.h +++ b/addressbook/gui/widgets/e-addressbook-view.h @@ -17,22 +17,20 @@ * Free Software Foundation, Inc., 59 Temple Place - Suite 330, * Boston, MA 02111-1307, USA. */ -#ifndef __E_ADDRESSBOOK_VIEW_H__ -#define __E_ADDRESSBOOK_VIEW_H__ +#ifndef __EAB_VIEW_H__ +#define __EAB_VIEW_H__ -#include +#include #include #include #include "e-addressbook-model.h" +#include "eab-contact-display.h" #include "widgets/menus/gal-view-menus.h" #include "addressbook/backend/ebook/e-book.h" -#ifdef __cplusplus -extern "C" { -#pragma } -#endif /* __cplusplus */ +G_BEGIN_DECLS -/* EAddressbookView - A card displaying information about a contact. +/* EABView - A card displaying information about a contact. * * The following arguments are available: * @@ -40,36 +38,36 @@ extern "C" { * -------------------------------------------------------------------------------- */ -#define E_TYPE_ADDRESSBOOK_VIEW (e_addressbook_view_get_type ()) -#define E_ADDRESSBOOK_VIEW(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), E_TYPE_ADDRESSBOOK_VIEW, EAddressbookView)) -#define E_ADDRESSBOOK_VIEW_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), E_TYPE_ADDRESSBOOK_VIEW, EAddressbookViewClass)) -#define E_IS_ADDRESSBOOK_VIEW(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), E_TYPE_ADDRESSBOOK_VIEW)) -#define E_IS_ADDRESSBOOK_VIEW_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((obj), E_TYPE_ADDRESSBOOK_VIEW)) +#define E_TYPE_AB_VIEW (eab_view_get_type ()) +#define EAB_VIEW(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), E_TYPE_AB_VIEW, EABView)) +#define EAB_VIEW_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), E_TYPE_AB_VIEW, EABViewClass)) +#define E_IS_ADDRESSBOOK_VIEW(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), E_TYPE_AB_VIEW)) +#define E_IS_ADDRESSBOOK_VIEW_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((obj), E_TYPE_AB_VIEW)) typedef enum { - E_ADDRESSBOOK_VIEW_NONE, /* initialized to this */ - E_ADDRESSBOOK_VIEW_TABLE, - E_ADDRESSBOOK_VIEW_MINICARD + EAB_VIEW_NONE, /* initialized to this */ + EAB_VIEW_MINICARD, + EAB_VIEW_TABLE, #ifdef WITH_ADDRESSBOOK_VIEW_TREEVIEW - ,E_ADDRESSBOOK_VIEW_TREEVIEW + ,EAB_VIEW_TREEVIEW #endif -} EAddressbookViewType; +} EABViewType; -typedef struct _EAddressbookView EAddressbookView; -typedef struct _EAddressbookViewClass EAddressbookViewClass; +typedef struct _EABView EABView; +typedef struct _EABViewClass EABViewClass; -struct _EAddressbookView +struct _EABView { - GtkTable parent; + GtkEventBox parent; /* item specific fields */ - EAddressbookViewType view_type; + EABViewType view_type; - EAddressbookModel *model; + EABModel *model; GtkWidget *invisible; - GList *clipboard_cards; + GList *clipboard_contacts; EBook *book; char *query; @@ -77,9 +75,10 @@ struct _EAddressbookView GObject *object; GtkWidget *widget; - GtkWidget *current_alphabet_widget; - GtkWidget *vbox; + GtkWidget *scrolled; + GtkWidget *contact_display; + GtkWidget *paned; /* Menus handler and the view instance */ GalViewInstance *view_instance; @@ -88,62 +87,58 @@ struct _EAddressbookView BonoboUIComponent *uic; }; -struct _EAddressbookViewClass +struct _EABViewClass { - GtkTableClass parent_class; + GtkEventBoxClass parent_class; /* * Signals */ - void (*status_message) (EAddressbookView *view, const gchar *message); - void (*search_result) (EAddressbookView *view, EBookViewStatus status); - void (*folder_bar_message) (EAddressbookView *view, const gchar *message); - void (*command_state_change) (EAddressbookView *view); - void (*alphabet_state_change) (EAddressbookView *view, gunichar letter); + void (*status_message) (EABView *view, const gchar *message); + void (*search_result) (EABView *view, EBookViewStatus status); + void (*folder_bar_message) (EABView *view, const gchar *message); + void (*command_state_change) (EABView *view); }; -GtkWidget *e_addressbook_view_new (void); -GType e_addressbook_view_get_type (void); - -void e_addressbook_view_setup_menus (EAddressbookView *view, - BonoboUIComponent *uic); - -void e_addressbook_view_discard_menus (EAddressbookView *view); - -void e_addressbook_view_save_as (EAddressbookView *view); -void e_addressbook_view_view (EAddressbookView *view); -void e_addressbook_view_send (EAddressbookView *view); -void e_addressbook_view_send_to (EAddressbookView *view); -void e_addressbook_view_print (EAddressbookView *view); -void e_addressbook_view_print_preview (EAddressbookView *view); -void e_addressbook_view_delete_selection (EAddressbookView *view); -void e_addressbook_view_cut (EAddressbookView *view); -void e_addressbook_view_copy (EAddressbookView *view); -void e_addressbook_view_paste (EAddressbookView *view); -void e_addressbook_view_select_all (EAddressbookView *view); -void e_addressbook_view_show_all (EAddressbookView *view); -void e_addressbook_view_stop (EAddressbookView *view); -void e_addressbook_view_copy_to_folder (EAddressbookView *view); -void e_addressbook_view_move_to_folder (EAddressbookView *view); - -gboolean e_addressbook_view_can_create (EAddressbookView *view); -gboolean e_addressbook_view_can_print (EAddressbookView *view); -gboolean e_addressbook_view_can_save_as (EAddressbookView *view); -gboolean e_addressbook_view_can_view (EAddressbookView *view); -gboolean e_addressbook_view_can_send (EAddressbookView *view); -gboolean e_addressbook_view_can_send_to (EAddressbookView *view); -gboolean e_addressbook_view_can_delete (EAddressbookView *view); -gboolean e_addressbook_view_can_cut (EAddressbookView *view); -gboolean e_addressbook_view_can_copy (EAddressbookView *view); -gboolean e_addressbook_view_can_paste (EAddressbookView *view); -gboolean e_addressbook_view_can_select_all (EAddressbookView *view); -gboolean e_addressbook_view_can_stop (EAddressbookView *view); -gboolean e_addressbook_view_can_copy_to_folder (EAddressbookView *view); -gboolean e_addressbook_view_can_move_to_folder (EAddressbookView *view); - -#ifdef __cplusplus -} -#endif /* __cplusplus */ - - -#endif /* __E_ADDRESSBOOK_VIEW_H__ */ +GtkWidget *eab_view_new (void); +GType eab_view_get_type (void); + +void eab_view_setup_menus (EABView *view, + BonoboUIComponent *uic); + +void eab_view_discard_menus (EABView *view); + +void eab_view_save_as (EABView *view); +void eab_view_view (EABView *view); +void eab_view_send (EABView *view); +void eab_view_send_to (EABView *view); +void eab_view_print (EABView *view); +void eab_view_print_preview (EABView *view); +void eab_view_delete_selection (EABView *view); +void eab_view_cut (EABView *view); +void eab_view_copy (EABView *view); +void eab_view_paste (EABView *view); +void eab_view_select_all (EABView *view); +void eab_view_show_all (EABView *view); +void eab_view_stop (EABView *view); +void eab_view_copy_to_folder (EABView *view); +void eab_view_move_to_folder (EABView *view); + +gboolean eab_view_can_create (EABView *view); +gboolean eab_view_can_print (EABView *view); +gboolean eab_view_can_save_as (EABView *view); +gboolean eab_view_can_view (EABView *view); +gboolean eab_view_can_send (EABView *view); +gboolean eab_view_can_send_to (EABView *view); +gboolean eab_view_can_delete (EABView *view); +gboolean eab_view_can_cut (EABView *view); +gboolean eab_view_can_copy (EABView *view); +gboolean eab_view_can_paste (EABView *view); +gboolean eab_view_can_select_all (EABView *view); +gboolean eab_view_can_stop (EABView *view); +gboolean eab_view_can_copy_to_folder (EABView *view); +gboolean eab_view_can_move_to_folder (EABView *view); + +G_END_DECLS; + +#endif /* __EAB_VIEW_H__ */ diff --git a/addressbook/gui/widgets/e-minicard-control.c b/addressbook/gui/widgets/e-minicard-control.c deleted file mode 100644 index 7cbcfb028a..0000000000 --- a/addressbook/gui/widgets/e-minicard-control.c +++ /dev/null @@ -1,357 +0,0 @@ -/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ -/* - * e-minicard-control.c - * - * Copyright (C) 1999, 2000, 2001, 2002, Ximian, Inc. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of version 2 of the GNU General Public - * License as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public - * License along with this program; if not, write to the - * Free Software Foundation, Inc., 59 Temple Place - Suite 330, - * Boston, MA 02111-1307, USA. - * - * Authors: - * Chris Lahey - */ - -#include -#include - -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include - -#include "e-minicard-control.h" -#include "e-minicard-widget.h" -#include "e-card-merging.h" - -typedef struct { - EMinicardWidget *minicard; - GList *card_list; - GtkWidget *label; -} EMinicardControl; - -#define MINICARD_CONTROL_ID "OAFIID:GNOME_Evolution_Addressbook_MiniCard_Control" - - -#if 0 -enum { - PROP_RUNNING -} MyArgs; - -#define RUNNING_KEY "Clock::Running" - -static void -get_prop (BonoboPropertyBag *bag, - BonoboArg *arg, - guint arg_id, - CORBA_Environment *ev, - gpointer user_data) -{ - GObject *clock = user_data; - - switch (arg_id) { - - case PROP_RUNNING: - { - gboolean b = GPOINTER_TO_UINT (g_object_get_data (clock, RUNNING_KEY)); - BONOBO_ARG_SET_BOOLEAN (arg, b); - break; - } - - default: - g_warning ("Unhandled arg %d", arg_id); - break; - } -} - -static void -set_prop (BonoboPropertyBag *bag, - const BonoboArg *arg, - guint arg_id, - CORBA_Environment *ev, - gpointer user_data) -{ - GtkClock *clock = user_data; - - switch (arg_id) { - - case PROP_RUNNING: - { - guint i; - - i = BONOBO_ARG_GET_BOOLEAN (arg); - - if (i) - gtk_clock_start (clock); - else - gtk_clock_stop (clock); - - g_object_set_data (clock, RUNNING_KEY, - GUINT_TO_POINTER (i)); - break; - } - - default: - g_warning ("Unhandled arg %d", arg_id); - break; - } -} -#endif - -/* - * Bonobo::PersistStream - * - * These two functions implement the Bonobo::PersistStream load and - * save methods which allow data to be loaded into and out of the - * BonoboObject. - */ -static char * -stream_read (Bonobo_Stream stream) -{ - Bonobo_Stream_iobuf *buffer; - CORBA_Environment ev; - char *data = NULL; - gint length = 0; - - CORBA_exception_init (&ev); - do { -#define READ_CHUNK_SIZE 65536 - Bonobo_Stream_read (stream, READ_CHUNK_SIZE, - &buffer, &ev); - - if (ev._major != CORBA_NO_EXCEPTION) { - CORBA_exception_free (&ev); - return NULL; - } - - if (buffer->_length <= 0) - break; - - data = g_realloc (data, length + buffer->_length + 1); - - memcpy (data + length, buffer->_buffer, buffer->_length); - - length += buffer->_length; - - CORBA_free (buffer); - } while (1); - - CORBA_free (buffer); - CORBA_exception_free (&ev); - - if (data) - data[length] = '\0'; - else - data = g_strdup(""); - - return data; -} /* stream_read */ - -/* - * This function implements the Bonobo::PersistStream:load method. - */ -static void -pstream_load (BonoboPersistStream *ps, const Bonobo_Stream stream, - Bonobo_Persist_ContentType type, void *data, - CORBA_Environment *ev) -{ - GList *list; - char *vcard; - EMinicardControl *minicard_control = data; - - if (type && g_ascii_strcasecmp (type, "text/vCard") != 0 && - g_ascii_strcasecmp (type, "text/x-vCard") != 0) { - CORBA_exception_set (ev, CORBA_USER_EXCEPTION, - ex_Bonobo_Persist_WrongDataType, NULL); - return; - } - - if ((vcard = stream_read (stream)) == NULL) { - CORBA_exception_set (ev, CORBA_USER_EXCEPTION, - ex_Bonobo_Persist_FileNotFound, NULL); - return; - } - - e_free_object_list (minicard_control->card_list); - list = e_card_load_cards_from_string_with_default_charset(vcard, "ISO-8859-1"); - g_free(vcard); - minicard_control->card_list = list; - if (list) - g_object_set(minicard_control->minicard, - "card", list->data, - NULL); - if (list && list->next) { - char *message; - int length = g_list_length (list) - 1; - if (length > 1) { - message = g_strdup_printf (_("and %d other cards."), length); - } else { - message = g_strdup_printf (_("and one other card.")); - } - gtk_label_set_text (GTK_LABEL (minicard_control->label), message); - g_free (message); - gtk_widget_show (minicard_control->label); - } else { - gtk_widget_hide (minicard_control->label); - } -} /* pstream_load */ - -/* - * This function implements the Bonobo::PersistStream:save method. - */ -static void -pstream_save (BonoboPersistStream *ps, const Bonobo_Stream stream, - Bonobo_Persist_ContentType type, void *data, - CORBA_Environment *ev) -{ - EMinicardControl *minicard_control = data; - char *vcard; - int length; - - if (type && g_ascii_strcasecmp (type, "text/vCard") != 0 && - g_ascii_strcasecmp (type, "text/x-vCard") != 0) { - CORBA_exception_set (ev, CORBA_USER_EXCEPTION, - ex_Bonobo_Persist_WrongDataType, NULL); - return; - } - - vcard = e_card_list_get_vcard(minicard_control->card_list); - length = strlen (vcard); - bonobo_stream_client_write (stream, vcard, length, ev); - g_free (vcard); -} /* pstream_save */ - -static Bonobo_Persist_ContentTypeList * -pstream_get_content_types (BonoboPersistStream *ps, void *closure, - CORBA_Environment *ev) -{ - return bonobo_persist_generate_content_types (2, "text/vCard", "text/x-vCard"); -} - -static void -book_open_cb (EBook *book, EBookStatus status, gpointer closure) -{ - GList *list = closure; - if (status == E_BOOK_STATUS_SUCCESS) { - GList *p; - for (p = list; p; p = p->next) { - e_card_merging_book_add_card(book, p->data, NULL, NULL); - } - } - if (book) - g_object_unref (book); - e_free_object_list (list); -} - -static void -save_in_addressbook(GtkWidget *button, gpointer data) -{ - EMinicardControl *minicard_control = data; - GList *list, *p; - EBook *book; - - book = e_book_new (); - - list = g_list_copy (minicard_control->card_list); - - for (p = list; p; p = p->next) - g_object_ref (p->data); - - addressbook_load_default_book (book, book_open_cb, list); -} - -static void -free_struct (gpointer data, GObject *where_object_was) -{ - EMinicardControl *minicard_control = data; - e_free_object_list (minicard_control->card_list); - g_free (minicard_control); -} - -BonoboControl * -e_minicard_control_new (void) -{ -#if 0 - BonoboPropertyBag *pb; -#endif - BonoboControl *control; - BonoboPersistStream *stream; - GtkWidget *minicard; - GtkWidget *button; - GtkWidget *label; - GtkWidget *vbox; - - EMinicardControl *minicard_control = g_new (EMinicardControl, 1); - - - minicard_control->card_list = NULL; - minicard_control->minicard = NULL; - minicard_control->label = NULL; - - /* Create the control. */ - - minicard = e_minicard_widget_new (); - gtk_widget_show (minicard); - minicard_control->minicard = E_MINICARD_WIDGET (minicard); - - /* This is intentionally not shown. */ - label = gtk_label_new (""); - minicard_control->label = label; - - button = gtk_button_new_with_label(_("Save in addressbook")); - g_signal_connect (button, "clicked", - G_CALLBACK (save_in_addressbook), minicard_control); - gtk_widget_show (button); - - vbox = gtk_vbox_new(FALSE, 0); - gtk_box_pack_start(GTK_BOX(vbox), minicard, TRUE, TRUE, 0); - gtk_box_pack_start(GTK_BOX(vbox), label, FALSE, FALSE, 0); - gtk_box_pack_start(GTK_BOX(vbox), button, FALSE, FALSE, 0); - gtk_widget_show (vbox); - - control = bonobo_control_new (vbox); - - g_object_weak_ref (G_OBJECT (control), free_struct, minicard_control); - - stream = bonobo_persist_stream_new (pstream_load, pstream_save, - pstream_get_content_types, - MINICARD_CONTROL_ID, - minicard_control); - -#if 0 - /* Create the properties. */ - pb = bonobo_property_bag_new (get_prop, set_prop, clock); - bonobo_control_set_properties (control, pb); - - bonobo_property_bag_add (pb, "running", PROP_RUNNING, - BONOBO_ARG_BOOLEAN, NULL, - "Whether or not the clock is running", 0); -#endif - - if (stream == NULL) { - bonobo_object_unref (BONOBO_OBJECT (control)); - return NULL; - } - - bonobo_object_add_interface (BONOBO_OBJECT (control), - BONOBO_OBJECT (stream)); - - return control; -} diff --git a/addressbook/gui/widgets/e-minicard-control.h b/addressbook/gui/widgets/e-minicard-control.h deleted file mode 100644 index bc0d934384..0000000000 --- a/addressbook/gui/widgets/e-minicard-control.h +++ /dev/null @@ -1,8 +0,0 @@ -#ifndef __E_MINICARD_CONTROL_H__ -#define __E_MINICARD_CONTROL_H__ - -#include - -BonoboControl *e_minicard_control_new (void); - -#endif /* __E_MINICARD_CONTROL_H__ */ diff --git a/addressbook/gui/widgets/e-minicard-label.c b/addressbook/gui/widgets/e-minicard-label.c index 607170aea4..31935164d7 100644 --- a/addressbook/gui/widgets/e-minicard-label.c +++ b/addressbook/gui/widgets/e-minicard-label.c @@ -22,7 +22,7 @@ #include #include "e-minicard-label.h" -#include "e-addressbook-marshal.h" +#include "eab-marshal.h" #include #include @@ -172,7 +172,7 @@ e_minicard_label_class_init (EMinicardLabelClass *klass) G_SIGNAL_RUN_FIRST, G_STRUCT_OFFSET (EMinicardLabelClass, style_set), NULL, NULL, - e_addressbook_marshal_VOID__OBJECT, + eab_marshal_VOID__OBJECT, G_TYPE_NONE, 1, GTK_TYPE_STYLE); diff --git a/addressbook/gui/widgets/e-minicard-view-widget.c b/addressbook/gui/widgets/e-minicard-view-widget.c index c90a581975..ff1bdc1f06 100644 --- a/addressbook/gui/widgets/e-minicard-view-widget.c +++ b/addressbook/gui/widgets/e-minicard-view-widget.c @@ -26,7 +26,7 @@ #include #include -#include "e-addressbook-marshal.h" +#include "eab-marshal.h" #include "e-minicard-view-widget.h" static void e_minicard_view_widget_init (EMinicardViewWidget *widget); @@ -38,7 +38,6 @@ static void e_minicard_view_widget_reflow (ECanvas *canvas); static void e_minicard_view_widget_size_allocate (GtkWidget *widget, GtkAllocation *allocation); static void e_minicard_view_widget_style_set (GtkWidget *widget, GtkStyle *previous_style); static void e_minicard_view_widget_realize (GtkWidget *widget); -static gboolean e_minicard_view_widget_real_focus_in_event (GtkWidget *widget, GdkEventFocus *event); static ECanvasClass *parent_class = NULL; @@ -135,7 +134,7 @@ e_minicard_view_widget_class_init (EMinicardViewWidgetClass *klass) G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (EMinicardViewWidgetClass, selection_change), NULL, NULL, - e_addressbook_marshal_NONE__NONE, + eab_marshal_NONE__NONE, G_TYPE_NONE, 0); signals [COLUMN_WIDTH_CHANGED] = @@ -144,7 +143,7 @@ e_minicard_view_widget_class_init (EMinicardViewWidgetClass *klass) G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (EMinicardViewWidgetClass, column_width_changed), NULL, NULL, - e_addressbook_marshal_NONE__DOUBLE, + eab_marshal_NONE__DOUBLE, G_TYPE_NONE, 1, G_TYPE_DOUBLE); signals [RIGHT_CLICK] = @@ -153,42 +152,18 @@ e_minicard_view_widget_class_init (EMinicardViewWidgetClass *klass) G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (EMinicardViewWidgetClass, right_click), NULL, NULL, - e_addressbook_marshal_INT__POINTER, + eab_marshal_INT__POINTER, G_TYPE_INT, 1, G_TYPE_POINTER); widget_class->style_set = e_minicard_view_widget_style_set; widget_class->realize = e_minicard_view_widget_realize; widget_class->size_allocate = e_minicard_view_widget_size_allocate; - widget_class->focus_in_event = e_minicard_view_widget_real_focus_in_event; canvas_class->reflow = e_minicard_view_widget_reflow; klass->selection_change = NULL; klass->column_width_changed = NULL; klass->right_click = NULL; - -} - -static gboolean -e_minicard_view_widget_real_focus_in_event(GtkWidget *widget, GdkEventFocus *event) -{ - GnomeCanvas *canvas; - EMinicardViewWidget *view; - - canvas = GNOME_CANVAS (widget); - view = E_MINICARD_VIEW_WIDGET(widget); - - if (!canvas->focused_item) { - EReflow *reflow = E_REFLOW (view->emv); - if (reflow->count) { - int unsorted = e_sorter_sorted_to_model (E_SORTER (reflow->sorter), 0); - - if (unsorted != -1) - canvas->focused_item = reflow->items [unsorted]; - } - } - - return GTK_WIDGET_CLASS(parent_class)->focus_in_event (widget, event); } static void @@ -325,6 +300,18 @@ selection_change (ESelectionModel *esm, EMinicardViewWidget *widget) signals [SELECTION_CHANGE], 0); } +static void +selection_row_change (ESelectionModel *esm, int row, EMinicardViewWidget *widget) +{ + gboolean selected = e_selection_model_is_row_selected (esm, row); + + /* we only handle the selected case here */ + if (!selected) + return; + + selection_change (esm, widget); +} + static void column_width_changed (ESelectionModel *esm, double width, EMinicardViewWidget *widget) { @@ -356,6 +343,7 @@ e_minicard_view_widget_style_set (GtkWidget *widget, GtkStyle *previous_style) GTK_WIDGET_CLASS(parent_class)->style_set (widget, previous_style); } + static void e_minicard_view_widget_realize (GtkWidget *widget) { @@ -379,6 +367,9 @@ e_minicard_view_widget_realize (GtkWidget *widget) g_signal_connect (E_REFLOW(view->emv)->selection, "selection_changed", G_CALLBACK (selection_change), view); + g_signal_connect (E_REFLOW(view->emv)->selection, + "selection_row_changed", + G_CALLBACK (selection_row_change), view); g_signal_connect (view->emv, "column_width_changed", G_CALLBACK (column_width_changed), view); diff --git a/addressbook/gui/widgets/e-minicard-view.c b/addressbook/gui/widgets/e-minicard-view.c index 18c4049e65..3c588c9ef2 100644 --- a/addressbook/gui/widgets/e-minicard-view.c +++ b/addressbook/gui/widgets/e-minicard-view.c @@ -23,9 +23,10 @@ #include "e-minicard-view.h" -#include "e-addressbook-util.h" +#include "eab-gui-util.h" +#include "eab-marshal.h" +#include "util/eab-book-util.h" -#include "e-addressbook-marshal.h" #include #include #include @@ -83,7 +84,7 @@ e_minicard_view_drag_data_get(GtkWidget *widget, case DND_TARGET_TYPE_VCARD_LIST: { char *value; - value = e_card_list_get_vcard(view->drag_list); + value = eab_contact_list_to_string (view->drag_list); gtk_selection_data_set (selection_data, selection_data->target, @@ -149,7 +150,7 @@ set_empty_message (EMinicardView *view) } static void -writable_status_change (EAddressbookModel *model, gboolean writable, EMinicardView *view) +writable_status_change (EABModel *model, gboolean writable, EMinicardView *view) { set_empty_message (view); } @@ -177,13 +178,12 @@ e_minicard_view_set_property (GObject *object, case PROP_ADAPTER: if (view->adapter) { if (view->writable_status_id) { - EAddressbookModel *model; + EABModel *model; g_object_get (view->adapter, "model", &model, NULL); if (model) { g_signal_handler_disconnect (model, view->writable_status_id); - g_object_unref (model); } } @@ -197,7 +197,7 @@ e_minicard_view_set_property (GObject *object, "model", view->adapter, NULL); if (view->adapter) { - EAddressbookModel *model; + EABModel *model; g_object_get (view->adapter, "model", &model, NULL); @@ -277,13 +277,12 @@ e_minicard_view_dispose (GObject *object) if (view->adapter) { if (view->writable_status_id) { - EAddressbookModel *model; + EABModel *model; g_object_get (view->adapter, "model", &model, NULL); if (model) { g_signal_handler_disconnect (model, view->writable_status_id); - g_object_unref (model); } } @@ -323,10 +322,8 @@ e_minicard_view_event (GnomeCanvasItem *item, GdkEvent *event) EBook *book; g_object_get(view, "book", &book, NULL); - if (book && E_IS_BOOK (book)) { - e_addressbook_show_contact_editor (book, e_card_new(""), TRUE, editable); - g_object_unref (book); - } + if (book && E_IS_BOOK (book)) + eab_show_contact_editor (book, e_contact_new(), TRUE, editable); } return TRUE; } @@ -391,7 +388,7 @@ static void do_remove (int i, gpointer user_data) { EBook *book; - ECard *card; + EContact *contact; ViewCbClosure *viewcbclosure = user_data; EMinicardView *view = viewcbclosure->view; EBookCallback cb = viewcbclosure->cb; @@ -401,12 +398,11 @@ do_remove (int i, gpointer user_data) "book", &book, NULL); - card = e_addressbook_reflow_adapter_get_card (view->adapter, i); + contact = e_addressbook_reflow_adapter_get_contact (view->adapter, i); - e_book_remove_card(book, card, cb, closure); + e_book_async_remove_contact(book, contact, cb, closure); - g_object_unref (card); - g_object_unref (book); + g_object_unref (contact); } #if 0 @@ -425,13 +421,13 @@ compare_to_utf_str (EMinicard *card, const char *utf_str) g_object_get(card->card, "file_as", &file_as, NULL); - if (file_as) { - int cmp = g_utf8_strcasecmp (file_as, utf_str); - g_free (file_as); - return cmp; - } + if (file_as) + return g_utf8_strcasecmp (file_as, utf_str); + else + return 0; + } else { + return 0; } - return 0; } #endif @@ -486,7 +482,7 @@ e_minicard_view_class_init (EMinicardViewClass *klass) G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (EMinicardViewClass, right_click), NULL, NULL, - e_addressbook_marshal_INT__POINTER, + eab_marshal_INT__POINTER, G_TYPE_INT, 1, G_TYPE_POINTER); item_class->event = e_minicard_view_event; @@ -567,7 +563,7 @@ static void add_to_list (int index, gpointer closure) { ModelAndList *mal = closure; - mal->list = g_list_prepend (mal->list, e_addressbook_reflow_adapter_get_card (mal->adapter, index)); + mal->list = g_list_prepend (mal->list, e_addressbook_reflow_adapter_get_contact (mal->adapter, index)); } GList * diff --git a/addressbook/gui/widgets/e-minicard-widget-test.c b/addressbook/gui/widgets/e-minicard-widget-test.c deleted file mode 100644 index 9a8d27d21c..0000000000 --- a/addressbook/gui/widgets/e-minicard-widget-test.c +++ /dev/null @@ -1,117 +0,0 @@ -/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ -/* test-minicard.c - * - * Copyright (C) 2000 Ximian, Inc. - * Author: Chris Lahey - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of version 2 of the GNU General Public - * License as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public - * License along with this program; if not, write to the - * Free Software Foundation, Inc., 59 Temple Place - Suite 330, - * Boston, MA 02111-1307, USA. - * - */ - -#define TEST_VCARD \ -"BEGIN:VCARD -" \ -"FN:Nat -" \ -"N:Friedman;Nat;D;Mr. -" \ -"ORG:Ximian, Inc. -" \ -"TITLE:Head Geek -" \ -"ROLE:Programmer/Executive -" \ -"BDAY:1977-08-06 -" \ -"TEL;WORK:617 679 1984 -" \ -"TEL;CELL:123 456 7890 -" \ -"EMAIL;INTERNET:nat@nat.org -" \ -"EMAIL;INTERNET:nat@ximian.com -" \ -"ADR;WORK;POSTAL:P.O. Box 101;;;Any Town;CA;91921-1234; -" \ -"ADR;HOME;POSTAL;INTL:P.O. Box 202;;;Any Town 2;MI;12344-4321;USA -" \ -"END:VCARD -" \ -" -" - -#include "config.h" -#include -#include -#include -#include "e-minicard-widget.h" - -/* This is a horrible thing to do, but it is just a test. */ - -static void destroy_callback(gpointer data, GObject *where_object_was) -{ - exit(0); -} - -#if 0 -static void about_callback( GtkWidget *widget, gpointer data ) -{ - - const gchar *authors[] = - { - "Christopher James Lahey ", - NULL - }; - - GtkWidget *about = - gnome_about_new ( _( "Minicard Widget Test" ), VERSION, - _( "Copyright (C) 2000, Ximian, Inc." ), - authors, - _( "This should test the minicard widget" ), - NULL); - gtk_widget_show (about); -} -#endif - -int main( int argc, char *argv[] ) -{ - GtkWidget *app; - GtkWidget *minicard; - ECard *card; - - /* bindtextdomain (PACKAGE, GNOMELOCALEDIR); - textdomain (PACKAGE);*/ - - gnome_init( "Minicard Widget Test", VERSION, argc, argv); - app = gnome_app_new("Minicard Widget Test", NULL); - - minicard = e_minicard_widget_new(); - card = e_card_new(TEST_VCARD); - g_object_set(minicard, - "card", card, - NULL); - - gnome_app_set_contents( GNOME_APP( app ), minicard ); - - /* Connect the signals */ - g_object_weak_ref (app, destroy_callback, app); - - gtk_widget_show_all( app ); - - gtk_main(); - - /* Not reached. */ - return 0; -} diff --git a/addressbook/gui/widgets/e-minicard-widget.c b/addressbook/gui/widgets/e-minicard-widget.c deleted file mode 100644 index e8f33673c3..0000000000 --- a/addressbook/gui/widgets/e-minicard-widget.c +++ /dev/null @@ -1,264 +0,0 @@ -/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ -/* - * e-table-field-chooser.c - * Copyright (C) 2000 Ximian, Inc. - * Author: Chris Lahey - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of version 2 of the GNU General Public - * License as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public - * License along with this library; if not, write to the - * Free Software Foundation, Inc., 59 Temple Place - Suite 330, - * Boston, MA 02111-1307, USA. - */ - -#include -#include -#include -#include "e-minicard-widget.h" -#include "e-minicard.h" - -static void e_minicard_widget_init (EMinicardWidget *card); -static void e_minicard_widget_class_init (EMinicardWidgetClass *klass); -static void e_minicard_widget_set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec); -static void e_minicard_widget_get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec); -static void e_minicard_widget_dispose (GObject *object); -static void e_minicard_widget_size_request (GtkWidget *widget, GtkRequisition *requisition); -static void e_minicard_widget_size_allocate (GtkWidget *widget, GtkAllocation *allocation); -static void e_minicard_widget_reflow (ECanvas *canvas); - -static ECanvasClass *parent_class = NULL; - -/* The arguments we take */ -enum { - PROP_0, - PROP_CARD, -}; - -GType -e_minicard_widget_get_type (void) -{ - static GType type = 0; - - if (!type) { - static const GTypeInfo info = { - sizeof (EMinicardWidgetClass), - NULL, /* base_init */ - NULL, /* base_finalize */ - (GClassInitFunc) e_minicard_widget_class_init, - NULL, /* class_finalize */ - NULL, /* class_data */ - sizeof (EMinicardWidget), - 0, /* n_preallocs */ - (GInstanceInitFunc) e_minicard_widget_init, - }; - - type = g_type_register_static (e_canvas_get_type (), "EMinicardWidget", &info, 0); - } - - return type; -} - -static void -e_minicard_widget_class_init (EMinicardWidgetClass *klass) -{ - GObjectClass *object_class; - GtkWidgetClass *widget_class; - ECanvasClass *ecanvas_class; - - object_class = G_OBJECT_CLASS(klass); - widget_class = GTK_WIDGET_CLASS(klass); - ecanvas_class = E_CANVAS_CLASS(klass); - - parent_class = g_type_class_peek_parent (klass); - - object_class->set_property = e_minicard_widget_set_property; - object_class->get_property = e_minicard_widget_get_property; - object_class->dispose = e_minicard_widget_dispose; - - widget_class->size_request = e_minicard_widget_size_request; - widget_class->size_allocate = e_minicard_widget_size_allocate; - - ecanvas_class->reflow = e_minicard_widget_reflow; - - g_object_class_install_property (object_class, PROP_CARD, - g_param_spec_object ("card", - _("Card"), - /*_( */"XXX blurb" /*)*/, - E_TYPE_CARD, - G_PARAM_READWRITE)); -} - -static void -e_minicard_widget_size_request(GtkWidget *widget, GtkRequisition *requisition) -{ - double height; - EMinicardWidget *emw = E_MINICARD_WIDGET(widget); - g_object_get(emw->item, - "height", &height, - NULL); - if (height <= 0) - height = 1; - widget->requisition.height = height; - widget->requisition.width = 200; - requisition->height = height; - requisition->width = 200; -} - -static void -e_minicard_widget_size_allocate(GtkWidget *widget, GtkAllocation *allocation) -{ - double height; - EMinicardWidget *emw = E_MINICARD_WIDGET(widget); - gnome_canvas_item_set( emw->item, - "width", (double) allocation->width, - NULL ); - g_object_get(emw->item, - "height", &height, - NULL); - height = MAX(height, allocation->height); - gnome_canvas_set_scroll_region(GNOME_CANVAS( emw ), 0, 0, allocation->width - 1, height - 1); - gnome_canvas_item_set( emw->rect, - "x2", (double) allocation->width, - "y2", (double) height, - NULL ); - if (GTK_WIDGET_CLASS(parent_class)->size_allocate) - GTK_WIDGET_CLASS(parent_class)->size_allocate(widget, allocation); -} - -static void e_minicard_widget_reflow(ECanvas *canvas) -{ - double height; - EMinicardWidget *emw = E_MINICARD_WIDGET(canvas); - g_object_get(emw->item, - "height", &height, - NULL); - - height = MAX(height, GTK_WIDGET(emw)->allocation.height); - - gnome_canvas_set_scroll_region (GNOME_CANVAS(emw), 0, 0, GTK_WIDGET(emw)->allocation.width - 1, height - 1); - gnome_canvas_item_set( emw->rect, - "x2", (double) GTK_WIDGET(emw)->allocation.width, - "y2", (double) height, - NULL ); - - gtk_widget_queue_resize(GTK_WIDGET(canvas)); -} - -static void -e_minicard_widget_init (EMinicardWidget *emw) -{ - emw->rect = gnome_canvas_item_new(gnome_canvas_root(GNOME_CANVAS(emw)), - gnome_canvas_rect_get_type(), - "x1", (double) 0, - "y1", (double) 0, - "x2", (double) 100, - "y2", (double) 100, - "fill_color", "white", - NULL ); - - emw->item = gnome_canvas_item_new(gnome_canvas_root(GNOME_CANVAS(emw)), - e_minicard_get_type(), - "width", (double) 100, - NULL ); - -#if PENDING_PORT_WORK - /* XXX this crashes since the canvas has no h/v adjustments. */ - gnome_canvas_set_scroll_region ( GNOME_CANVAS( emw ), - 0, 0, - 100, 100 ); -#endif - emw->card = NULL; -} - -static void -e_minicard_widget_dispose (GObject *object) -{ - EMinicardWidget *emw = E_MINICARD_WIDGET(object); - - if (emw->card) { - g_object_unref (emw->card); - emw->card = NULL; - } - - if (G_OBJECT_CLASS(parent_class)->dispose) - G_OBJECT_CLASS(parent_class)->dispose(object); -} - -GtkWidget* -e_minicard_widget_new (void) -{ - GtkWidget *widget = GTK_WIDGET (g_object_new (E_TYPE_MINICARD_WIDGET, NULL)); - return widget; -} - -static void -e_minicard_widget_set_property (GObject *object, - guint prop_id, - const GValue *value, - GParamSpec *pspec) -{ - EMinicardWidget *emw = E_MINICARD_WIDGET(object); - gpointer ptr; - - switch (prop_id){ - case PROP_CARD: - ptr = g_value_get_object (value); - e_minicard_widget_set_card (emw, ptr ? E_CARD (ptr) : NULL); - break; - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); - break; - } -} - -static void -e_minicard_widget_get_property (GObject *object, - guint prop_id, - GValue *value, - GParamSpec *pspec) -{ - EMinicardWidget *emw = E_MINICARD_WIDGET(object); - - switch (prop_id) { - case PROP_CARD: - if (emw->card) - g_value_set_object (value, emw->card); - else - g_value_set_object (value, NULL); - break; - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); - break; - } -} - -void -e_minicard_widget_set_card (EMinicardWidget *emw, ECard *card) -{ - g_return_if_fail (emw && E_IS_MINICARD_WIDGET (emw)); - g_return_if_fail (card == NULL || E_IS_CARD (card)); - - if (card != emw->card) { - - if (emw->card) - g_object_unref (emw->card); - - emw->card = card; - - if (emw->card) - g_object_ref (emw->card); - - if (emw->item) - g_object_set (emw->item, - "card", emw->card, - NULL); - } -} diff --git a/addressbook/gui/widgets/e-minicard-widget.h b/addressbook/gui/widgets/e-minicard-widget.h deleted file mode 100644 index 829ad8f77d..0000000000 --- a/addressbook/gui/widgets/e-minicard-widget.h +++ /dev/null @@ -1,76 +0,0 @@ -/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ -/* e-minicard-widget.h - * Copyright (C) 2000 Ximian, Inc. - * Author: Chris Lahey - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of version 2 of the GNU General Public - * License as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public - * License along with this library; if not, write to the - * Free Software Foundation, Inc., 59 Temple Place - Suite 330, - * Boston, MA 02111-1307, USA. - */ -#ifndef __E_MINICARD_WIDGET_H__ -#define __E_MINICARD_WIDGET_H__ - -#include -#include "addressbook/backend/ebook/e-card.h" - -#ifdef __cplusplus -extern "C" { -#pragma } -#endif /* __cplusplus */ - -/* EMinicardWidget - A card displaying information about a contact. - * - * The following arguments are available: - * - * name type read/write description - * -------------------------------------------------------------------------------- - */ - -#define E_TYPE_MINICARD_WIDGET (e_minicard_widget_get_type ()) -#define E_MINICARD_WIDGET(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), E_TYPE_MINICARD_WIDGET, EMinicardWidget)) -#define E_MINICARD_WIDGET_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), E_TYPE_MINICARD_WIDGET, EMinicardWidgetClass)) -#define E_IS_MINICARD_WIDGET(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), E_TYPE_MINICARD_WIDGET)) -#define E_IS_MINICARD_WIDGET_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((obj), E_TYPE_MINICARD_WIDGET)) - - -typedef struct _EMinicardWidget EMinicardWidget; -typedef struct _EMinicardWidgetClass EMinicardWidgetClass; - -struct _EMinicardWidget -{ - ECanvas parent; - - /* item specific fields */ - GnomeCanvasItem *item; - - GnomeCanvasItem *rect; - ECard *card; -}; - -struct _EMinicardWidgetClass -{ - ECanvasClass parent_class; -}; - - -GtkWidget *e_minicard_widget_new(void); -GType e_minicard_widget_get_type (void); - -void e_minicard_widget_set_card (EMinicardWidget *, ECard *); - -#ifdef __cplusplus -} -#endif /* __cplusplus */ - - -#endif /* __E_MINICARD_WIDGET_H__ */ diff --git a/addressbook/gui/widgets/e-minicard.c b/addressbook/gui/widgets/e-minicard.c index 7ce6d2f518..f9aa893dc3 100644 --- a/addressbook/gui/widgets/e-minicard.c +++ b/addressbook/gui/widgets/e-minicard.c @@ -33,14 +33,13 @@ #include #include #include "addressbook/backend/ebook/e-book.h" -#include "e-addressbook-marshal.h" -#include "e-addressbook-util.h" +#include "eab-marshal.h" +#include "eab-gui-util.h" #include "e-minicard.h" #include "e-minicard-label.h" #include "e-minicard-view.h" #include "e-contact-editor.h" -#include "e-card-merging.h" -#include "ebook/e-destination.h" +#include "util/eab-destination.h" static void e_minicard_init (EMinicard *card); static void e_minicard_class_init (EMinicardClass *klass); @@ -64,7 +63,7 @@ static GnomeCanvasGroupClass *parent_class = NULL; typedef struct _EMinicardField EMinicardField; struct _EMinicardField { - ECardSimpleField field; + EContactField field; GnomeCanvasItem *label; }; @@ -90,7 +89,7 @@ enum { PROP_SELECTED, PROP_HAS_CURSOR, PROP_EDITABLE, - PROP_CARD + PROP_CONTACT }; enum { @@ -185,11 +184,11 @@ e_minicard_class_init (EMinicardClass *klass) FALSE, G_PARAM_READWRITE)); - g_object_class_install_property (object_class, PROP_CARD, - g_param_spec_object ("card", - _("Card"), + g_object_class_install_property (object_class, PROP_CONTACT, + g_param_spec_object ("contact", + _("Contact"), /*_( */"XXX blurb" /*)*/, - E_TYPE_CARD, + E_TYPE_CONTACT, G_PARAM_READWRITE)); e_minicard_signals [SELECTED] = @@ -198,7 +197,7 @@ e_minicard_class_init (EMinicardClass *klass) G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (EMinicardClass, selected), NULL, NULL, - e_addressbook_marshal_INT__POINTER, + eab_marshal_INT__POINTER, G_TYPE_INT, 1, G_TYPE_POINTER); e_minicard_signals [DRAG_BEGIN] = @@ -207,7 +206,7 @@ e_minicard_class_init (EMinicardClass *klass) G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (EMinicardClass, drag_begin), NULL, NULL, - e_addressbook_marshal_INT__POINTER, + eab_marshal_INT__POINTER, G_TYPE_INT, 1, G_TYPE_POINTER); e_minicard_signals [STYLE_SET] = @@ -216,7 +215,7 @@ e_minicard_class_init (EMinicardClass *klass) G_SIGNAL_RUN_FIRST, G_STRUCT_OFFSET (EMinicardClass, style_set), NULL, NULL, - e_addressbook_marshal_VOID__OBJECT, + eab_marshal_VOID__OBJECT, G_TYPE_NONE, 1, GTK_TYPE_STYLE); @@ -231,7 +230,6 @@ e_minicard_class_init (EMinicardClass *klass) static void e_minicard_init (EMinicard *minicard) { - /* minicard->card = NULL;*/ minicard->rect = NULL; minicard->fields = NULL; minicard->width = 10; @@ -241,8 +239,7 @@ e_minicard_init (EMinicard *minicard) minicard->editable = FALSE; minicard->has_cursor = FALSE; - minicard->card = NULL; - minicard->simple = e_card_simple_new(NULL); + minicard->contact = NULL; minicard->list_icon_pixbuf = gdk_pixbuf_new_from_file (EVOLUTION_IMAGESDIR "/" LIST_ICON_FILENAME, NULL); minicard->list_icon_size = gdk_pixbuf_get_height (minicard->list_icon_pixbuf); @@ -344,15 +341,12 @@ e_minicard_set_property (GObject *object, guint prop_id, const GValue *value, G if (e_minicard->has_cursor != g_value_get_boolean (value)) set_has_cursor (e_minicard, g_value_get_boolean (value)); break; - case PROP_CARD: - if (e_minicard->card) - g_object_unref (e_minicard->card); - e_minicard->card = E_CARD(g_value_get_object (value)); - if (e_minicard->card) - g_object_ref (e_minicard->card); - g_object_set(e_minicard->simple, - "card", e_minicard->card, - NULL); + case PROP_CONTACT: + if (e_minicard->contact) + g_object_unref (e_minicard->contact); + e_minicard->contact = E_CONTACT(g_value_get_object (value)); + if (e_minicard->contact) + g_object_ref (e_minicard->contact); remodel(e_minicard); e_canvas_item_request_reflow(item); e_minicard->changed = FALSE; @@ -389,9 +383,8 @@ e_minicard_get_property (GObject *object, guint prop_id, GValue *value, GParamS case PROP_EDITABLE: g_value_set_boolean (value, e_minicard->editable); break; - case PROP_CARD: - e_card_simple_sync_card(e_minicard->simple); - g_value_set_object (value, e_minicard->card); + case PROP_CONTACT: + g_value_set_object (value, e_minicard->contact); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); @@ -436,10 +429,8 @@ e_minicard_finalize (GObject *object) e_minicard = E_MINICARD (object); - if (e_minicard->card) - g_object_unref (e_minicard->card); - if (e_minicard->simple) - g_object_unref (e_minicard->simple); + if (e_minicard->contact) + g_object_unref (e_minicard->contact); if (G_OBJECT_CLASS (parent_class)->finalize) (* G_OBJECT_CLASS (parent_class)->finalize) (object); @@ -523,14 +514,6 @@ e_minicard_unrealize (GnomeCanvasItem *item) (* GNOME_CANVAS_ITEM_CLASS(parent_class)->unrealize) (item); } -static void -card_modified_cb (EBook* book, EBookStatus status, gpointer user_data) -{ - d(g_print ("%s: %s(): a card was modified\n", __FILE__, G_GNUC_FUNCTION)); - if (status != E_BOOK_STATUS_SUCCESS) - e_addressbook_error_dialog (_("Error modifying card"), status); -} - /* Callback used when the contact editor is closed */ static void editor_closed_cb (GtkObject *editor, gpointer data) @@ -560,35 +543,8 @@ e_minicard_event (GnomeCanvasItem *item, GdkEvent *event) if (!e_minicard->selected) { e_minicard_selected(e_minicard, event); } - } else { - EBook *book = NULL; - - if (e_minicard->changed) { - - e_card_simple_sync_card(e_minicard->simple); - - if (E_IS_MINICARD_VIEW(GNOME_CANVAS_ITEM(e_minicard)->parent)) { - - g_object_get(GNOME_CANVAS_ITEM(e_minicard)->parent, - "book", &book, - NULL); - - } - - if (book) { - - /* Add the card in the contact editor to our ebook */ - e_card_merging_book_commit_card (book, - e_minicard->card, - card_modified_cb, - NULL); - g_object_unref(book); - } else { - remodel(e_minicard); - e_canvas_item_request_reflow(GNOME_CANVAS_ITEM(e_minicard)); - } - e_minicard->changed = FALSE; - } + } + else { e_minicard->has_focus = FALSE; } } @@ -651,7 +607,7 @@ e_minicard_event (GnomeCanvasItem *item, GdkEvent *event) case GDK_2BUTTON_PRESS: if (event->button.button == 1 && E_IS_MINICARD_VIEW(item->parent)) { if (e_minicard->editor) { - if (e_card_evolution_list (e_minicard->card)) + if (GPOINTER_TO_INT (e_contact_get (e_minicard->contact, E_CONTACT_IS_LIST))) e_contact_list_editor_raise (E_CONTACT_LIST_EDITOR(e_minicard->editor)); else e_contact_editor_raise(E_CONTACT_EDITOR(e_minicard->editor)); @@ -664,14 +620,14 @@ e_minicard_event (GnomeCanvasItem *item, GdkEvent *event) } if (book != NULL) { - if (e_card_evolution_list (e_minicard->card)) { - EContactListEditor *editor = e_addressbook_show_contact_list_editor (book, e_minicard->card, - FALSE, e_minicard->editable); + if (e_contact_get (e_minicard->contact, E_CONTACT_IS_LIST)) { + EContactListEditor *editor = eab_show_contact_list_editor (book, e_minicard->contact, + FALSE, e_minicard->editable); e_minicard->editor = G_OBJECT (editor); } else { - EContactEditor *editor = e_addressbook_show_contact_editor (book, e_minicard->card, - FALSE, e_minicard->editable); + EContactEditor *editor = eab_show_contact_editor (book, e_minicard->contact, + FALSE, e_minicard->editable); e_minicard->editor = G_OBJECT (editor); } g_object_ref (e_minicard->editor); @@ -685,36 +641,6 @@ e_minicard_event (GnomeCanvasItem *item, GdkEvent *event) return TRUE; } break; - case GDK_KEY_PRESS: - if (event->key.keyval == GDK_Tab || - event->key.keyval == GDK_KP_Tab || - event->key.keyval == GDK_ISO_Left_Tab) { - GList *list; - for (list = e_minicard->fields; list; list = list->next) { - EMinicardField *field = E_MINICARD_FIELD(list->data); - GnomeCanvasItem *item = field->label; - EFocus has_focus; - g_object_get(item, - "has_focus", &has_focus, - NULL); - if (has_focus != E_FOCUS_NONE) { - if (event->key.state & GDK_SHIFT_MASK) - list = list->prev; - else - list = list->next; - if (list) { - EMinicardField *field = E_MINICARD_FIELD(list->data); - GnomeCanvasItem *item = field->label; - gnome_canvas_item_set(item, - "has_focus", (event->key.state & GDK_SHIFT_MASK) ? E_FOCUS_END : E_FOCUS_START, - NULL); - return 1; - } else { - return 0; - } - } - } - } default: break; } @@ -729,11 +655,12 @@ static void e_minicard_resize_children( EMinicard *e_minicard ) { GList *list; - + gboolean is_list = GPOINTER_TO_INT (e_contact_get (e_minicard->contact, E_CONTACT_IS_LIST)); + if (e_minicard->header_text) { gnome_canvas_item_set( e_minicard->header_text, "width", ((double) e_minicard->width - 12 - - (e_card_evolution_list (e_minicard->card) ? e_minicard->list_icon_size : 0.0)), + - (is_list ? e_minicard->list_icon_size : 0.0)), NULL ); } if (e_minicard->list_icon) { @@ -749,79 +676,24 @@ e_minicard_resize_children( EMinicard *e_minicard ) } static void -field_changed (EText *text, EMinicard *e_minicard) -{ - ECardSimpleType type; - char *string; - char *new_string; - gboolean is_list = FALSE; - - type = GPOINTER_TO_INT - (g_object_get_data(G_OBJECT(text), - "EMinicard:field")); - g_object_get(text, - "text", &string, - NULL); - - /* - * If the card is coresponding with a contact list and the field be - * changed is e-mail address, should wrap it before write it back. - */ - new_string = (char*)e_card_simple_get_const (e_minicard->simple, - E_CARD_SIMPLE_FIELD_IS_LIST); - - is_list = (NULL != new_string); - - if (is_list && (E_CARD_SIMPLE_FIELD_EMAIL == type || - E_CARD_SIMPLE_FIELD_EMAIL_2 == type || - E_CARD_SIMPLE_FIELD_EMAIL_3 == type)) { - if (string && *string) { - EDestination *dest = e_destination_new (); - if (dest != NULL){ - e_destination_set_email (dest, string); - new_string = e_destination_export(dest); - g_free(string); - string=new_string; - g_object_unref (dest); - } - } - } - - e_card_simple_set(e_minicard->simple, - type, - string); - g_free(string); - e_minicard->changed = TRUE; -} - -static void -field_activated (EText *text, EMinicard *e_minicard) -{ - e_text_stop_editing (text); - e_canvas_item_grab_focus (GNOME_CANVAS_ITEM (e_minicard), FALSE); -} - -static void -add_field (EMinicard *e_minicard, ECardSimpleField field, gdouble left_width) +add_field (EMinicard *e_minicard, EContactField field, gdouble left_width) { GnomeCanvasItem *new_item; GnomeCanvasGroup *group; - ECardSimpleType type; EMinicardField *minicard_field; char *name; char *string; group = GNOME_CANVAS_GROUP( e_minicard ); - type = e_card_simple_type(e_minicard->simple, field); - name = g_strdup_printf("%s:", e_card_simple_get_name(e_minicard->simple, field)); - string = e_card_simple_get(e_minicard->simple, field); + name = g_strdup_printf("%s:", e_contact_pretty_name (field)); + string = e_contact_get (e_minicard->contact, field); /* Magically convert embedded XML into an address. */ if (!strncmp (string, "editable, + "editable", FALSE, NULL ); - g_signal_connect(E_MINICARD_LABEL(new_item)->field, - "changed", G_CALLBACK (field_changed), e_minicard); - g_signal_connect(E_MINICARD_LABEL(new_item)->field, - "activate", G_CALLBACK (field_activated), e_minicard); +#if notyet g_object_set(E_MINICARD_LABEL(new_item)->field, - "allow_newlines", e_card_simple_get_allow_newlines (e_minicard->simple, field), + "allow_newlines", e_card_simple_get_allow_newlines (e_minicard->contact, field), NULL); +#endif g_object_set_data(G_OBJECT (E_MINICARD_LABEL(new_item)->field), "EMinicard:field", GINT_TO_POINTER(field)); @@ -861,14 +731,18 @@ static int get_left_width(EMinicard *e_minicard) { gchar *name; - ECardSimpleField field; + EContactField field; int width = -1; PangoLayout *layout; layout = gtk_widget_create_pango_layout (GTK_WIDGET (GNOME_CANVAS_ITEM (e_minicard)->canvas), ""); - for(field = E_CARD_SIMPLE_FIELD_FULL_NAME; field != E_CARD_SIMPLE_FIELD_LAST; field++) { + for(field = E_CONTACT_FULL_NAME; field != E_CONTACT_LAST_SIMPLE_STRING; field++) { int this_width; - name = g_strdup_printf("%s:", e_card_simple_get_name(e_minicard->simple, field)); + + if (field == E_CONTACT_FAMILY_NAME || field == E_CONTACT_GIVEN_NAME) + continue; + + name = g_strdup_printf("%s:", e_contact_pretty_name (field)); pango_layout_set_text (layout, name, -1); pango_layout_get_pixel_size (layout, &this_width, NULL); if (width < this_width) @@ -885,46 +759,47 @@ remodel( EMinicard *e_minicard ) int count = 0; if ( !(GTK_OBJECT_FLAGS( e_minicard ) & GNOME_CANVAS_ITEM_REALIZED) ) return; - if (e_minicard->simple) { - ECardSimpleField field; + if (e_minicard->contact) { + EContactField field; GList *list; char *file_as; int left_width = -1; if (e_minicard->header_text) { - file_as = e_card_simple_get(e_minicard->simple, E_CARD_SIMPLE_FIELD_FILE_AS); - gnome_canvas_item_set( e_minicard->header_text, + file_as = e_contact_get (e_minicard->contact, E_CONTACT_FILE_AS); + gnome_canvas_item_set (e_minicard->header_text, "text", file_as ? file_as : "", NULL ); g_free(file_as); } - if (e_minicard->card && e_card_evolution_list (e_minicard->card) ) { + if (e_minicard->contact && e_contact_get (e_minicard->contact, E_CONTACT_IS_LIST)) gnome_canvas_item_show (e_minicard->list_icon); - } - else { + else gnome_canvas_item_hide (e_minicard->list_icon); - } list = e_minicard->fields; e_minicard->fields = NULL; - for(field = E_CARD_SIMPLE_FIELD_FULL_NAME; field != E_CARD_SIMPLE_FIELD_LAST_SIMPLE_STRING && count < 5; field++) { + for(field = E_CONTACT_FULL_NAME; field != E_CONTACT_LAST_SIMPLE_STRING && count < 5; field++) { EMinicardField *minicard_field = NULL; + if (field == E_CONTACT_FAMILY_NAME || field == E_CONTACT_GIVEN_NAME) + continue; + if (list) minicard_field = list->data; if (minicard_field && minicard_field->field == field) { GList *this_list = list; char *string; - string = e_card_simple_get(e_minicard->simple, field); + string = e_contact_get(e_minicard->contact, field); if (string && *string) { /* Magically convert embedded XML into an address. */ if (!strncmp (string, "simple, field); + string = e_contact_get(e_minicard->contact, field); if (string && *string) { add_field(e_minicard, field, left_width); count++; @@ -1013,8 +888,8 @@ e_minicard_get_card_id (EMinicard *minicard) g_return_val_if_fail(minicard != NULL, NULL); g_return_val_if_fail(E_IS_MINICARD(minicard), NULL); - if (minicard->card) { - return e_card_get_id(minicard->card); + if (minicard->contact) { + return e_contact_get_const (minicard->contact, E_CONTACT_UID); } else { return ""; } @@ -1030,13 +905,12 @@ e_minicard_compare (EMinicard *minicard1, EMinicard *minicard2) g_return_val_if_fail(minicard2 != NULL, 0); g_return_val_if_fail(E_IS_MINICARD(minicard2), 0); - if (minicard1->card && minicard2->card) { + if (minicard1->contact && minicard2->contact) { char *file_as1, *file_as2; - - g_object_get(minicard1->card, + g_object_get(minicard1->contact, "file_as", &file_as1, NULL); - g_object_get(minicard2->card, + g_object_get(minicard2->contact, "file_as", &file_as2, NULL); diff --git a/addressbook/gui/widgets/e-minicard.h b/addressbook/gui/widgets/e-minicard.h index ac0f82e46c..e4673fe4d9 100644 --- a/addressbook/gui/widgets/e-minicard.h +++ b/addressbook/gui/widgets/e-minicard.h @@ -23,8 +23,7 @@ #include #include "addressbook/gui/contact-editor/e-contact-editor.h" #include -#include "addressbook/backend/ebook/e-card.h" -#include "addressbook/backend/ebook/e-card-simple.h" +#include "addressbook/backend/ebook/e-contact.h" #ifdef __cplusplus extern "C" { @@ -63,8 +62,7 @@ struct _EMinicard GnomeCanvasGroup parent; /* item specific fields */ - ECard *card; - ECardSimple *simple; + EContact *contact; GnomeCanvasItem *rect; GnomeCanvasItem *header_rect; diff --git a/addressbook/gui/widgets/eab-contact-display.c b/addressbook/gui/widgets/eab-contact-display.c new file mode 100644 index 0000000000..3de6eac380 --- /dev/null +++ b/addressbook/gui/widgets/eab-contact-display.c @@ -0,0 +1,486 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ +/* + * Authors: Chris Toshok + * + * Copyright (C) 2003 Ximian, Inc. (www.ximian.com) + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Street #330, Boston, MA 02111-1307, USA. + * + */ + +#include "eab-contact-display.h" + +#include "e-util/e-html-utils.h" +#include "util/eab-destination.h" + +#include +#include +#include +#include +#include + +#define PARENT_TYPE (gtk_vbox_get_type ()) + +struct _EABContactDisplayPrivate { + GtkHTML *html; + EContact *contact; +}; + + +#define HTML_HEADER "\n\n" \ + "\n\n\n" + +#define MAX_COMPACT_IMAGE_DIMENSION 48 + +static void +on_url_requested (GtkHTML *html, const char *url, GtkHTMLStream *handle, + EABContactDisplay *display) +{ + printf ("on_url_requested (%s)\n", url); + if (!strcmp (url, "internal-contact-photo:")) { + EContactPhoto *photo; + + photo = e_contact_get (display->priv->contact, E_CONTACT_PHOTO); + if (!photo) + photo = e_contact_get (display->priv->contact, E_CONTACT_LOGO); + + printf ("writing a photo of length %d\n", photo->length); + + gtk_html_stream_write (handle, photo->data, photo->length); + + gtk_html_end (html, handle, GTK_HTML_STREAM_OK); + } +} + +static void +on_link_clicked (GtkHTML *html, const char *url, EABContactDisplay *display) +{ + GError *err = NULL; + + gnome_url_show (url, &err); + + if (err) { + g_warning ("gnome_url_show: %s", err->message); + g_error_free (err); + } +} + +static void +render_address (GtkHTMLStream *html_stream, EContact *contact, const char *html_label, EContactField adr_field, EContactField label_field) +{ + EContactAddress *adr; + const char *label; + + label = e_contact_get_const (contact, label_field); + if (label) { + char *html = e_text_to_html (label, E_TEXT_TO_HTML_CONVERT_NL); + + gtk_html_stream_printf (html_stream, "
"); + gtk_html_stream_printf (html_stream, "%s: %s
", html_label, html); + + gtk_html_stream_printf (html_stream, "%s", _("Map It")); + gtk_html_stream_printf (html_stream, "
"); + g_free (html); + return; + } + + adr = e_contact_get (contact, adr_field); + if (adr && + (adr->po || adr->ext || adr->street || adr->locality || adr->region || adr->code || adr->country)) { + + gtk_html_stream_printf (html_stream, "
"); + gtk_html_stream_printf (html_stream, "%s: ", html_label); + + if (adr->po && *adr->po) gtk_html_stream_printf (html_stream, "%s
", adr->po); + if (adr->ext && *adr->ext) gtk_html_stream_printf (html_stream, "%s
", adr->ext); + if (adr->street && *adr->street) gtk_html_stream_printf (html_stream, "%s
", adr->street); + if (adr->locality && *adr->locality) gtk_html_stream_printf (html_stream, "%s
", adr->locality); + if (adr->region && *adr->region) gtk_html_stream_printf (html_stream, "%s
", adr->region); + if (adr->code && *adr->code) gtk_html_stream_printf (html_stream, "%s
", adr->code); + if (adr->country && *adr->country) gtk_html_stream_printf (html_stream, "%s
", adr->country); + + gtk_html_stream_printf (html_stream, "%s", _("Map It")); + gtk_html_stream_printf (html_stream, "
"); + } + if (adr) + e_contact_address_free (adr); +} + +static void +render_string (GtkHTMLStream *html_stream, EContact *contact, const char *html_label, EContactField field) +{ + const char *str; + + str = e_contact_get_const (contact, field); + + if (str && *str) { + char *html = e_text_to_html (str, 0); + gtk_html_stream_printf (html_stream, "%s: %s
", html_label, str); + g_free (html); + } +} + +static void +render_url (GtkHTMLStream *html_stream, EContact *contact, const char *html_label, EContactField field) +{ + const char *str; + str = e_contact_get_const (contact, field); + if (str && *str) { + char *html = e_text_to_html (str, E_TEXT_TO_HTML_CONVERT_URLS); + gtk_html_stream_printf (html_stream, "%s: %s
", + html_label, html); + g_free (html); + } +} + +static void +eab_contact_display_render_normal (EABContactDisplay *display, EContact *contact) +{ + GtkHTMLStream *html_stream; + + if (display->priv->contact) + g_object_unref (display->priv->contact); + display->priv->contact = contact; + if (display->priv->contact) + g_object_ref (display->priv->contact); + + html_stream = gtk_html_begin (display->priv->html); + gtk_html_stream_write (html_stream, HTML_HEADER, sizeof (HTML_HEADER) - 1); + gtk_html_stream_write (html_stream, "\n", 7); + + if (contact) { + char *str, *html; + EContactPhoto *photo; + + gtk_html_stream_printf (html_stream, "
"); + photo = e_contact_get (contact, E_CONTACT_PHOTO); + if (!photo) + photo = e_contact_get (contact, E_CONTACT_LOGO); + if (photo) { + gtk_html_stream_printf (html_stream, ""); + e_contact_photo_free (photo); + } + + gtk_html_stream_printf (html_stream, "\n"); + + str = e_contact_get_const (contact, E_CONTACT_FILE_AS); + if (str) { + html = e_text_to_html (str, 0); + gtk_html_stream_printf (html_stream, "

%s

", html); + g_free (html); + } + else { + str = e_contact_get_const (contact, E_CONTACT_FULL_NAME); + if (str) { + html = e_text_to_html (str, 0); + gtk_html_stream_printf (html_stream, "

%s

", html); + g_free (html); + } + } + + if (e_contact_get (contact, E_CONTACT_IS_LIST)) { + GList *email_list; + GList *l; + + gtk_html_stream_printf (html_stream, "
"); + gtk_html_stream_printf (html_stream, "%s: ", _("List Members")); + + email_list = e_contact_get (contact, E_CONTACT_EMAIL); + for (l = email_list; l; l = l->next) { + EABDestination *dest = eab_destination_import (l->data); + if (dest) { + const char *textrep = eab_destination_get_textrep (dest, TRUE); + char *html = e_text_to_html (textrep, 0); + gtk_html_stream_printf (html_stream, "%s
", html); + g_free (html); + g_object_unref (dest); + } + } + gtk_html_stream_printf (html_stream, "
"); + } + else { + render_string (html_stream, contact, _("Job Title"), E_CONTACT_TITLE); + + render_string (html_stream, contact, _("Email"), E_CONTACT_EMAIL_1); + render_string (html_stream, contact, _("Email"), E_CONTACT_EMAIL_2); + render_string (html_stream, contact, _("Email"), E_CONTACT_EMAIL_3); + + + render_address (html_stream, contact, _("Home Address"), E_CONTACT_ADDRESS_HOME, E_CONTACT_ADDRESS_LABEL_HOME); + render_address (html_stream, contact, _("Work Address"), E_CONTACT_ADDRESS_WORK, E_CONTACT_ADDRESS_LABEL_WORK); + render_address (html_stream, contact, _("Other Address"), E_CONTACT_ADDRESS_OTHER, E_CONTACT_ADDRESS_LABEL_OTHER); + + gtk_html_stream_printf (html_stream, "
"); + + render_url (html_stream, contact, _("Home page"), E_CONTACT_HOMEPAGE_URL); + render_url (html_stream, contact, _("Blog"), E_CONTACT_BLOG_URL); + + } + + gtk_html_stream_printf (html_stream, "
\n"); + } + + gtk_html_stream_write (html_stream, "\n", 15); + gtk_html_end (display->priv->html, html_stream, GTK_HTML_STREAM_OK); +} + +static void +eab_contact_display_render_compact (EABContactDisplay *display, EContact *contact) +{ + GtkHTMLStream *html_stream; + + if (display->priv->contact) + g_object_unref (display->priv->contact); + display->priv->contact = contact; + if (display->priv->contact) + g_object_ref (display->priv->contact); + + html_stream = gtk_html_begin (display->priv->html); + gtk_html_stream_write (html_stream, HTML_HEADER, sizeof (HTML_HEADER) - 1); + gtk_html_stream_write (html_stream, "\n", 7); + + if (contact) { + char *str, *html; + EContactPhoto *photo; + + gtk_html_stream_printf (html_stream, + "" + "
" + "" + "
" + "" + "
"); + + photo = e_contact_get (contact, E_CONTACT_PHOTO); + if (!photo) + photo = e_contact_get (contact, E_CONTACT_LOGO); + if (photo) { + int calced_width = MAX_COMPACT_IMAGE_DIMENSION, calced_height = MAX_COMPACT_IMAGE_DIMENSION; + GdkPixbufLoader *loader = gdk_pixbuf_loader_new (); + GdkPixbuf *pixbuf; + + /* figure out if we need to downscale the + image here. we don't scale the pixbuf + itself, just insert width/height tags in + the html */ + gdk_pixbuf_loader_write (loader, photo->data, photo->length, NULL); + pixbuf = gdk_pixbuf_loader_get_pixbuf (loader); + gdk_pixbuf_loader_close (loader, NULL); + g_object_unref (loader); + if (pixbuf) { + int max_dimension = gdk_pixbuf_get_height (pixbuf); + if (max_dimension < gdk_pixbuf_get_width (pixbuf)) + max_dimension = gdk_pixbuf_get_width (pixbuf); + + calced_width = (float)gdk_pixbuf_get_width (pixbuf) / max_dimension * MAX_COMPACT_IMAGE_DIMENSION; + calced_height = (float)gdk_pixbuf_get_height (pixbuf) / max_dimension * MAX_COMPACT_IMAGE_DIMENSION; + + calced_width = MIN (calced_width, MAX_COMPACT_IMAGE_DIMENSION); + calced_height = MIN (calced_height, MAX_COMPACT_IMAGE_DIMENSION); + } + + gdk_pixbuf_unref (pixbuf); + gtk_html_stream_printf (html_stream, "", + calced_width, calced_height); + e_contact_photo_free (photo); + } + + gtk_html_stream_printf (html_stream, "\n"); + + str = e_contact_get_const (contact, E_CONTACT_FILE_AS); + if (str) { + html = e_text_to_html (str, 0); + gtk_html_stream_printf (html_stream, "%s", html); + g_free (html); + } + else { + str = e_contact_get_const (contact, E_CONTACT_FULL_NAME); + if (str) { + html = e_text_to_html (str, 0); + gtk_html_stream_printf (html_stream, "%s", html); + g_free (html); + } + } + + gtk_html_stream_write (html_stream, "
", 4); + + if (e_contact_get (contact, E_CONTACT_IS_LIST)) { + GList *email_list; + GList *l; + + gtk_html_stream_printf (html_stream, "
"); + gtk_html_stream_printf (html_stream, "%s: ", _("List Members")); + + email_list = e_contact_get (contact, E_CONTACT_EMAIL); + for (l = email_list; l; l = l->next) { + EABDestination *dest = eab_destination_import (l->data); + if (dest) { + const char *textrep = eab_destination_get_textrep (dest, TRUE); + char *html = e_text_to_html (textrep, 0); + gtk_html_stream_printf (html_stream, "%s, ", html); + g_free (html); + g_object_unref (dest); + } + } + gtk_html_stream_printf (html_stream, "
"); + } + else { + gboolean comma = FALSE; + str = e_contact_get_const (contact, E_CONTACT_TITLE); + if (str) { + html = e_text_to_html (str, 0); + gtk_html_stream_printf (html_stream, "%s: %s
", _("Job Title"), str); + g_free (html); + } + + gtk_html_stream_printf (html_stream, "%s: ", _("Email")); + str = e_contact_get_const (contact, E_CONTACT_EMAIL_1); + if (str) { + html = e_text_to_html (str, 0); + gtk_html_stream_printf (html_stream, "%s", str); + g_free (html); + comma = TRUE; + } + str = e_contact_get_const (contact, E_CONTACT_EMAIL_2); + if (str) { + html = e_text_to_html (str, 0); + gtk_html_stream_printf (html_stream, "%s%s", comma ? ", " : "", str); + g_free (html); + comma = TRUE; + } + str = e_contact_get_const (contact, E_CONTACT_EMAIL_3); + if (str) { + html = e_text_to_html (str, 0); + gtk_html_stream_printf (html_stream, "%s%s", comma ? ", " : "", str); + g_free (html); + } + gtk_html_stream_write (html_stream, "
", 4); + + str = e_contact_get_const (contact, E_CONTACT_HOMEPAGE_URL); + if (str) { + html = e_text_to_html (str, E_TEXT_TO_HTML_CONVERT_URLS); + gtk_html_stream_printf (html_stream, "%s: %s
", + _("Home page"), html); + g_free (html); + } + + str = e_contact_get_const (contact, E_CONTACT_BLOG_URL); + if (str) { + html = e_text_to_html (str, E_TEXT_TO_HTML_CONVERT_URLS); + gtk_html_stream_printf (html_stream, "%s: %s
", + _("Blog"), html); + } + } + + gtk_html_stream_printf (html_stream, "
\n"); + } + + gtk_html_stream_write (html_stream, "\n", 15); + gtk_html_end (display->priv->html, html_stream, GTK_HTML_STREAM_OK); +} + +void +eab_contact_display_render (EABContactDisplay *display, EContact *contact, + EABContactDisplayRenderMode mode) +{ + switch (mode) { + case EAB_CONTACT_DISPLAY_RENDER_NORMAL: + eab_contact_display_render_normal (display, contact); + break; + case EAB_CONTACT_DISPLAY_RENDER_COMPACT: + eab_contact_display_render_compact (display, contact); + break; + } +} + +GtkWidget* +eab_contact_display_new (void) +{ + EABContactDisplay *display; + + display = g_object_new (EAB_TYPE_CONTACT_DISPLAY, NULL); + + display->priv = g_new0 (EABContactDisplayPrivate, 1); + + display->priv->html = GTK_HTML (gtk_html_new ()); + + gtk_html_set_default_content_type (display->priv->html, "text/html; charset=utf-8"); + + gtk_html_set_editable (display->priv->html, FALSE); + + + g_signal_connect (display->priv->html, "url_requested", + G_CALLBACK (on_url_requested), + display); + g_signal_connect (display->priv->html, "link_clicked", + G_CALLBACK (on_link_clicked), + display); +#if 0 + g_signal_connect (display->priv->html, "object_requested", + G_CALLBACK (on_object_requested), + mail_display); + g_signal_connect (display->priv->html, "button_press_event", + G_CALLBACK (html_button_press_event), mail_display); + g_signal_connect (display->priv->html, "motion_notify_event", + G_CALLBACK (html_motion_notify_event), mail_display); + g_signal_connect (display->priv->html, "enter_notify_event", + G_CALLBACK (html_enter_notify_event), mail_display); + g_signal_connect (display->priv->html, "iframe_created", + G_CALLBACK (html_iframe_created), mail_display); + g_signal_connect (display->priv->html, "on_url", + G_CALLBACK (html_on_url), mail_display); +#endif + + gtk_box_pack_start_defaults (GTK_BOX (display), GTK_WIDGET (display->priv->html)); + gtk_widget_show (GTK_WIDGET (display->priv->html)); + + return GTK_WIDGET (display); +} + + +static void +eab_contact_display_init (GObject *object) +{ +} + +static void +eab_contact_display_class_init (GtkObjectClass *object_class) +{ + // object_class->destroy = mail_display_destroy; +} + +GType +eab_contact_display_get_type (void) +{ + static GType type = 0; + + if (!type) { + static const GTypeInfo info = { + sizeof (EABContactDisplayClass), + NULL, /* base_init */ + NULL, /* base_finalize */ + (GClassInitFunc) eab_contact_display_class_init, + NULL, /* class_finalize */ + NULL, /* class_data */ + sizeof (EABContactDisplay), + 0, /* n_preallocs */ + (GInstanceInitFunc) eab_contact_display_init, + }; + + type = g_type_register_static (PARENT_TYPE, "EABContactDisplay", &info, 0); + } + + return type; +} diff --git a/addressbook/gui/widgets/eab-contact-display.h b/addressbook/gui/widgets/eab-contact-display.h new file mode 100644 index 0000000000..83bad9ae64 --- /dev/null +++ b/addressbook/gui/widgets/eab-contact-display.h @@ -0,0 +1,61 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ +/* + * Authors: Chris Toshok + * + * Copyright 2003 Ximian, Inc. (www.ximian.com) + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Street #330, Boston, MA 02111-1307, USA. + * + */ + +#ifndef _EAB_CONTACT_DISPLAY_H_ +#define _EAB_CONTACT_DISPLAY_H_ + +#include +#include +#include + +#define EAB_TYPE_CONTACT_DISPLAY (eab_contact_display_get_type ()) +#define EAB_CONTACT_DISPLAY(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), EAB_TYPE_CONTACT_DISPLAY, EABContactDisplay)) +#define EAB_CONTACT_DISPLAY_CLASS(k) (G_TYPE_CHECK_CLASS_CAST ((k), EAB_TYPE_CONTACT_DISPLAY, EABContactDisplayClass)) +#define IS_EAB_CONTACT_DISPLAY(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), EAB_TYPE_CONTACT_DISPLAY)) +#define IS_EAB_CONTACT_DISPLAY_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), EAB_TYPE_CONTACT_DISPLAY)) + +typedef struct _EABContactDisplay EABContactDisplay; +typedef struct _EABContactDisplayPrivate EABContactDisplayPrivate; +typedef struct _EABContactDisplayClass EABContactDisplayClass; + +typedef enum { + EAB_CONTACT_DISPLAY_RENDER_NORMAL, /* for use in the preview pane */ + EAB_CONTACT_DISPLAY_RENDER_COMPACT /* for use with embedded vcards (e.g, the EABVCardControl) */ +} EABContactDisplayRenderMode; + +struct _EABContactDisplay { + GtkVBox parent; + + EABContactDisplayPrivate *priv; +}; + +struct _EABContactDisplayClass { + GtkVBoxClass parent_class; +}; + +GtkType eab_contact_display_get_type (void); +GtkWidget * eab_contact_display_new (void); + +void eab_contact_display_render (EABContactDisplay *display, EContact *contact, + EABContactDisplayRenderMode render_mode); + +#endif /* _EAB_CONTACT_DISPLAY_H_ */ diff --git a/addressbook/gui/widgets/eab-gui-util.c b/addressbook/gui/widgets/eab-gui-util.c new file mode 100644 index 0000000000..666bc976f2 --- /dev/null +++ b/addressbook/gui/widgets/eab-gui-util.c @@ -0,0 +1,823 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ +/* + * e-table-field-chooser.c + * Copyright (C) 2001 Ximian, Inc. + * Author: Chris Toshok + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of version 2 of the GNU General Public + * License as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#include + +#include +#include +#include +#include + +#include +#include "eab-gui-util.h" +#include "util/eab-book-util.h" +#include "util/eab-destination.h" + +#include + +#include + +#include "addressbook/gui/contact-editor/e-contact-editor.h" +#include "addressbook/gui/contact-list-editor/e-contact-list-editor.h" + +void +eab_error_dialog (const gchar *msg, EBookStatus status) +{ + static char *status_to_string[] = { + N_("Success"), + N_("Unknown error"), + N_("Repository offline"), + N_("Permission denied"), + N_("Contact not found"), + N_("Contact ID already exists"), + N_("Protocol not supported"), + N_("Cancelled"), + N_("Authentication Failed"), + N_("Authentication Required"), + N_("TLS not Available"), + N_("Addressbook does not exist"), + N_("Other error") + }; + char *error_msg; + GtkWidget *dialog; + + error_msg = g_strdup_printf ("%s: %s", msg, _(status_to_string [status])); + + dialog = gtk_message_dialog_new (NULL, 0, GTK_MESSAGE_ERROR, GTK_BUTTONS_OK, + error_msg); + + g_signal_connect (dialog, "response", G_CALLBACK (gtk_widget_destroy), NULL); + + gtk_widget_show (dialog); + + g_free (error_msg); +} + +gint +eab_prompt_save_dialog (GtkWindow *parent) +{ + GtkWidget *dialog; + gint response; + + dialog = gtk_message_dialog_new (parent, + (GtkDialogFlags)0, + GTK_MESSAGE_QUESTION, + GTK_BUTTONS_NONE, + _("Do you want to save changes?")); + gtk_dialog_add_buttons (GTK_DIALOG (dialog), + _("_Discard"), GTK_RESPONSE_NO, + GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL, + GTK_STOCK_SAVE, GTK_RESPONSE_YES, + NULL); + + gtk_dialog_set_default_response (GTK_DIALOG (dialog), GTK_RESPONSE_YES); + + response = gtk_dialog_run (GTK_DIALOG (dialog)); + + gtk_widget_destroy (dialog); + + return response; +} + +static void +added_cb (EBook* book, EBookStatus status, const char *id, + gboolean is_list) +{ + if (status != E_BOOK_ERROR_OK) { + eab_error_dialog (is_list ? _("Error adding list") : _("Error adding contact"), status); + } +} + +static void +modified_cb (EBook* book, EBookStatus status, + gboolean is_list) +{ + if (status != E_BOOK_ERROR_OK) { + eab_error_dialog (is_list ? _("Error modifying list") : _("Error modifying contact"), + status); + } +} + +static void +deleted_cb (EBook* book, EBookStatus status, + gboolean is_list) +{ + if (status != E_BOOK_ERROR_OK) { + eab_error_dialog (is_list ? _("Error removing list") : _("Error removing contact"), + status); + } +} + +static void +editor_closed_cb (GtkObject *editor, gpointer data) +{ + g_object_unref (editor); +} + +EContactEditor * +eab_show_contact_editor (EBook *book, EContact *contact, + gboolean is_new_contact, + gboolean editable) +{ + EContactEditor *ce; + + ce = e_contact_editor_new (book, contact, is_new_contact, editable); + + g_signal_connect (ce, "contact_added", + G_CALLBACK (added_cb), GINT_TO_POINTER (FALSE)); + g_signal_connect (ce, "contact_modified", + G_CALLBACK (modified_cb), GINT_TO_POINTER (FALSE)); + g_signal_connect (ce, "contact_deleted", + G_CALLBACK (deleted_cb), GINT_TO_POINTER (FALSE)); + g_signal_connect (ce, "editor_closed", + G_CALLBACK (editor_closed_cb), NULL); + + return ce; +} + +EContactListEditor * +eab_show_contact_list_editor (EBook *book, EContact *contact, + gboolean is_new_contact, + gboolean editable) +{ + EContactListEditor *ce; + + ce = e_contact_list_editor_new (book, contact, is_new_contact, editable); + + g_signal_connect (ce, "list_added", + G_CALLBACK (added_cb), GINT_TO_POINTER (TRUE)); + g_signal_connect (ce, "list_modified", + G_CALLBACK (modified_cb), GINT_TO_POINTER (TRUE)); + g_signal_connect (ce, "list_deleted", + G_CALLBACK (deleted_cb), GINT_TO_POINTER (TRUE)); + g_signal_connect (ce, "editor_closed", + G_CALLBACK (editor_closed_cb), GINT_TO_POINTER (TRUE)); + + e_contact_list_editor_show (ce); + + return ce; +} + +static void +view_contacts (EBook *book, GList *list, gboolean editable) +{ + for (; list; list = list->next) { + EContact *contact = list->data; + if (e_contact_get (contact, E_CONTACT_IS_LIST)) + eab_show_contact_list_editor (book, contact, FALSE, editable); + else + eab_show_contact_editor (book, contact, FALSE, editable); + } +} + +void +eab_show_multiple_contacts (EBook *book, + GList *list, + gboolean editable) +{ + if (list) { + int length = g_list_length (list); + if (length > 5) { + GtkWidget *dialog; + gint response; + + dialog = gtk_message_dialog_new (NULL, + 0, + GTK_MESSAGE_QUESTION, + GTK_BUTTONS_YES_NO, + _("Opening %d contacts will open %d new windows as well.\n" + "Do you really want to display all of these contacts?"), + length, + length); + + response = gtk_dialog_run (GTK_DIALOG (dialog)); + gtk_widget_destroy (dialog); + if (response == GTK_RESPONSE_YES) + view_contacts (book, list, editable); + } else { + view_contacts (book, list, editable); + } + } +} + + +static gint +file_exists(GtkFileSelection *filesel, const char *filename) +{ + GtkWidget *dialog; + gint response; + + dialog = gtk_message_dialog_new (GTK_WINDOW (filesel), + 0, + GTK_MESSAGE_QUESTION, + GTK_BUTTONS_NONE, + _("%s already exists\nDo you want to overwrite it?"), filename); + + gtk_dialog_add_buttons (GTK_DIALOG (dialog), + GTK_STOCK_CANCEL, GTK_RESPONSE_REJECT, + _("Overwrite"), GTK_RESPONSE_ACCEPT, + NULL); + + response = gtk_dialog_run (GTK_DIALOG (dialog)); + gtk_widget_destroy (dialog); + return response; +} + +typedef struct { + GtkFileSelection *filesel; + char *vcard; +} SaveAsInfo; + +static void +save_it(GtkWidget *widget, SaveAsInfo *info) +{ + gint error = 0; + gint response = 0; + + const char *filename = gtk_file_selection_get_filename (info->filesel); + + error = e_write_file (filename, info->vcard, O_WRONLY | O_CREAT | O_EXCL | O_TRUNC); + + if (error == EEXIST) { + response = file_exists(info->filesel, filename); + switch (response) { + case GTK_RESPONSE_ACCEPT : /* Overwrite */ + e_write_file(filename, info->vcard, O_WRONLY | O_CREAT | O_TRUNC); + break; + case GTK_RESPONSE_REJECT : /* cancel */ + return; + } + } else if (error != 0) { + GtkWidget *dialog; + char *str; + + str = g_strdup_printf (_("Error saving %s: %s"), filename, strerror(errno)); + dialog = gtk_message_dialog_new (GTK_WINDOW (info->filesel), + GTK_DIALOG_DESTROY_WITH_PARENT, + GTK_MESSAGE_ERROR, + GTK_BUTTONS_OK, + str); + g_free (str); + + gtk_widget_show (dialog); + + return; + } + + gtk_widget_destroy(GTK_WIDGET(info->filesel)); +} + +static void +close_it(GtkWidget *widget, SaveAsInfo *info) +{ + gtk_widget_destroy (GTK_WIDGET (info->filesel)); +} + +static void +destroy_it(void *data, GObject *where_the_object_was) +{ + SaveAsInfo *info = data; + g_free (info->vcard); + g_free (info); +} + +static char * +make_safe_filename (const char *prefix, char *name) +{ + char *safe, *p; + + if (!name) { + /* This is a filename. Translators take note. */ + name = _("card.vcf"); + } + + p = strrchr (name, '/'); + if (p) + safe = g_strdup_printf ("%s%s%s", prefix, p, ".vcf"); + else + safe = g_strdup_printf ("%s/%s%s", prefix, name, ".vcf"); + + p = strrchr (safe, '/') + 1; + if (p) + e_filename_make_safe (p); + + return safe; +} + +void +eab_contact_save (char *title, EContact *contact, GtkWindow *parent_window) +{ + GtkFileSelection *filesel; + char *file; + char *name; + SaveAsInfo *info = g_new(SaveAsInfo, 1); + + filesel = GTK_FILE_SELECTION(gtk_file_selection_new(title)); + + name = e_contact_get (contact, E_CONTACT_FILE_AS); + file = make_safe_filename (g_get_home_dir(), name); + gtk_file_selection_set_filename (filesel, file); + g_free (file); + + info->filesel = filesel; + info->vcard = e_vcard_to_string (E_VCARD (contact), EVC_FORMAT_VCARD_30); + + g_signal_connect(filesel->ok_button, "clicked", + G_CALLBACK (save_it), info); + g_signal_connect(filesel->cancel_button, "clicked", + G_CALLBACK (close_it), info); + g_object_weak_ref (G_OBJECT (filesel), destroy_it, info); + + if (parent_window) { + gtk_window_set_transient_for (GTK_WINDOW (filesel), + parent_window); + gtk_window_set_modal (GTK_WINDOW (filesel), TRUE); + } + + gtk_widget_show(GTK_WIDGET(filesel)); +} + +void +eab_contact_list_save (char *title, GList *list, GtkWindow *parent_window) +{ + GtkFileSelection *filesel; + SaveAsInfo *info = g_new(SaveAsInfo, 1); + + filesel = GTK_FILE_SELECTION(gtk_file_selection_new(title)); + + /* This is a filename. Translators take note. */ + if (list && list->data && list->next == NULL) { + char *name, *file; + name = e_contact_get (E_CONTACT (list->data), E_CONTACT_FILE_AS); + if (!name) + name = e_contact_get (E_CONTACT (list->data), E_CONTACT_FULL_NAME); + + file = make_safe_filename (g_get_home_dir(), name); + gtk_file_selection_set_filename (filesel, file); + g_free (file); + } else { + char *file; + file = make_safe_filename (g_get_home_dir(), _("list")); + gtk_file_selection_set_filename (filesel, file); + g_free (file); + } + + info->filesel = filesel; + info->vcard = eab_contact_list_to_string (list); + + g_signal_connect(filesel->ok_button, "clicked", + G_CALLBACK (save_it), info); + g_signal_connect(filesel->cancel_button, "clicked", + G_CALLBACK (close_it), info); + g_object_weak_ref (G_OBJECT (filesel), destroy_it, info); + + if (parent_window) { + gtk_window_set_transient_for (GTK_WINDOW (filesel), + parent_window); + gtk_window_set_modal (GTK_WINDOW (filesel), TRUE); + } + + gtk_widget_show(GTK_WIDGET(filesel)); +} + +typedef struct ContactCopyProcess_ ContactCopyProcess; + +typedef void (*ContactCopyDone) (ContactCopyProcess *process); + +struct ContactCopyProcess_ { + int count; + GList *contacts; + EBook *source; + EBook *destination; + ContactCopyDone done_cb; +}; + +static void +contact_deleted_cb (EBook* book, EBookStatus status, gpointer user_data) +{ + if (status != E_BOOK_ERROR_OK) { + eab_error_dialog (_("Error removing contact"), status); + } +} + +static void +do_delete (gpointer data, gpointer user_data) +{ + EBook *book = user_data; + EContact *contact = data; + + e_book_async_remove_contact(book, contact, contact_deleted_cb, NULL); +} + +static void +delete_contacts (ContactCopyProcess *process) +{ + g_list_foreach (process->contacts, + do_delete, + process->source); +} + +static void +process_unref (ContactCopyProcess *process) +{ + process->count --; + if (process->count == 0) { + if (process->done_cb) { + process->done_cb (process); + } + e_free_object_list(process->contacts); + g_object_unref (process->source); + g_object_unref (process->destination); + g_free (process); + } +} + +static void +contact_added_cb (EBook* book, EBookStatus status, const char *id, gpointer user_data) +{ + ContactCopyProcess *process = user_data; + + if (status != E_BOOK_ERROR_OK) { + eab_error_dialog (_("Error adding contact"), status); + } else { + process_unref (process); + } +} + +static void +do_copy (gpointer data, gpointer user_data) +{ + EBook *book; + EContact *contact; + ContactCopyProcess *process; + + process = user_data; + contact = data; + + book = process->destination; + + process->count ++; + e_book_async_add_contact(book, contact, contact_added_cb, process); +} + +static void +got_book_cb (EBook *book, EBookStatus status, gpointer closure) +{ + ContactCopyProcess *process; + process = closure; + if (status == E_BOOK_ERROR_OK) { + process->destination = book; + g_object_ref (book); + g_list_foreach (process->contacts, + do_copy, + process); + } + process_unref (process); +} + +void +eab_transfer_contacts (EBook *source, GList *contacts /* adopted */, gboolean delete_from_source, GtkWindow *parent_window) +{ + EBook *dest; + const char *allowed_types[] = { "contacts/*", NULL }; + GNOME_Evolution_Folder *folder; + static char *last_uri = NULL; + ContactCopyProcess *process; + char *desc; + + if (contacts == NULL) + return; + + if (last_uri == NULL) + last_uri = g_strdup (""); + + if (contacts->next == NULL) { + if (delete_from_source) + desc = _("Move contact to"); + else + desc = _("Copy contact to"); + } else { + if (delete_from_source) + desc = _("Move contacts to"); + else + desc = _("Copy contacts to"); + } + +#if 0 /* EPFIXME */ + evolution_shell_client_user_select_folder (global_shell_client, + parent_window, + desc, last_uri, allowed_types, + &folder); +#else + folder = NULL; +#endif + + if (!folder) + return; + + if (strcmp (last_uri, folder->evolutionUri) != 0) { + g_free (last_uri); + last_uri = g_strdup (folder->evolutionUri); + } + + process = g_new (ContactCopyProcess, 1); + process->count = 1; + process->source = source; + g_object_ref (source); + process->contacts = contacts; + process->destination = NULL; + + if (delete_from_source) + process->done_cb = delete_contacts; + else + process->done_cb = NULL; + + dest = e_book_new (); + e_book_async_load_uri (dest, folder->physicalUri, got_book_cb, process); + + CORBA_free (folder); +} + +#include + +#define COMPOSER_OAFID "OAFIID:GNOME_Evolution_Mail_Composer" + +void +eab_send_contact_list (GList *contacts, EABDisposition disposition) +{ +#if notyet + GNOME_Evolution_Composer composer_server; + CORBA_Environment ev; + + if (contacts == NULL) + return; + + CORBA_exception_init (&ev); + + composer_server = bonobo_activation_activate_from_id (COMPOSER_OAFID, 0, NULL, &ev); + + if (disposition == EAB_DISPOSITION_AS_TO) { + GNOME_Evolution_Composer_RecipientList *to_list, *cc_list, *bcc_list; + CORBA_char *subject; + int to_i, bcc_i; + GList *iter; + gint to_length = 0, bcc_length = 0; + + /* Figure out how many addresses of each kind we have. */ + for (iter = contacts; iter != NULL; iter = g_list_next (iter)) { + EContact *contact = E_CONTACT (iter->data); + if (e_contact_get (contact, E_CONTACT_IS_LIST)) { + gint len = card->email ? e_list_length (card->email) : 0; + if (e_card_evolution_list_show_addresses (card)) + to_length += len; + else + bcc_length += len; + } else { + if (card->email != NULL) + ++to_length; + } + } + + /* Now I have to make a CORBA sequences that represents a recipient list with + the right number of entries, for the cards. */ + to_list = GNOME_Evolution_Composer_RecipientList__alloc (); + to_list->_maximum = to_length; + to_list->_length = to_length; + if (to_length > 0) { + to_list->_buffer = CORBA_sequence_GNOME_Evolution_Composer_Recipient_allocbuf (to_length); + } + + cc_list = GNOME_Evolution_Composer_RecipientList__alloc (); + cc_list->_maximum = cc_list->_length = 0; + + bcc_list = GNOME_Evolution_Composer_RecipientList__alloc (); + bcc_list->_maximum = bcc_length; + bcc_list->_length = bcc_length; + if (bcc_length > 0) { + bcc_list->_buffer = CORBA_sequence_GNOME_Evolution_Composer_Recipient_allocbuf (bcc_length); + } + + to_i = 0; + bcc_i = 0; + while (cards != NULL) { + ECard *card = cards->data; + EIterator *iterator; + gchar *name, *addr; + gboolean is_list, is_hidden, free_name_addr; + GNOME_Evolution_Composer_Recipient *recipient; + + if (card->email != NULL) { + + is_list = e_card_evolution_list (card); + is_hidden = is_list && !e_card_evolution_list_show_addresses (card); + + for (iterator = e_list_get_iterator (card->email); e_iterator_is_valid (iterator); e_iterator_next (iterator)) { + + if (is_hidden) { + recipient = &(bcc_list->_buffer[bcc_i]); + ++bcc_i; + } else { + recipient = &(to_list->_buffer[to_i]); + ++to_i; + } + + name = ""; + addr = ""; + free_name_addr = FALSE; + if (e_iterator_is_valid (iterator)) { + + if (is_list) { + /* We need to decode the list entries, which are XMLified EABDestinations. */ + EABDestination *dest = eab_destination_import (e_iterator_get (iterator)); + if (dest != NULL) { + name = g_strdup (eab_destination_get_name (dest)); + addr = g_strdup (eab_destination_get_email (dest)); + free_name_addr = TRUE; + g_object_unref (dest); + } + + } else { /* is just a plain old card */ + if (card->name) + name = e_card_name_to_string (card->name); + addr = g_strdup ((char *) e_iterator_get (iterator)); + free_name_addr = TRUE; + } + } + + recipient->name = CORBA_string_dup (name ? name : ""); + recipient->address = CORBA_string_dup (addr ? addr : ""); + + if (free_name_addr) { + g_free ((gchar *) name); + g_free ((gchar *) addr); + } + + /* If this isn't a list, we quit after the first (i.e. the default) address. */ + if (!is_list) + break; + + } + g_object_unref (iterator); + } + + cards = g_list_next (cards); + } + + subject = CORBA_string_dup (""); + + GNOME_Evolution_Composer_setHeaders (composer_server, "", to_list, cc_list, bcc_list, subject, &ev); + if (ev._major != CORBA_NO_EXCEPTION) { + g_printerr ("gui/e-meeting-edit.c: I couldn't set the composer headers via CORBA! Aagh.\n"); + CORBA_exception_free (&ev); + return; + } + + CORBA_free (to_list); + CORBA_free (cc_list); + CORBA_free (bcc_list); + CORBA_free (subject); + } else if (disposition == EAB_DISPOSITION_AS_ATTACHMENT) { + CORBA_char *content_type, *filename, *description; + GNOME_Evolution_Composer_AttachmentData *attach_data; + CORBA_boolean show_inline; + char *tempstr; + + GNOME_Evolution_Composer_RecipientList *to_list, *cc_list, *bcc_list; + CORBA_char *subject; + + content_type = CORBA_string_dup ("text/x-vcard"); + filename = CORBA_string_dup (""); + + if (cards->next) { + description = CORBA_string_dup (_("Multiple VCards")); + } else { + char *file_as; + + g_object_get(cards->data, + "file_as", &file_as, + NULL); + + tempstr = g_strdup_printf (_("VCard for %s"), file_as); + description = CORBA_string_dup (tempstr); + g_free (tempstr); + } + + show_inline = FALSE; + + tempstr = eab_contact_list_to_string (cards); + attach_data = GNOME_Evolution_Composer_AttachmentData__alloc(); + attach_data->_maximum = attach_data->_length = strlen (tempstr); + attach_data->_buffer = CORBA_sequence_CORBA_char_allocbuf (attach_data->_length); + strcpy (attach_data->_buffer, tempstr); + g_free (tempstr); + + GNOME_Evolution_Composer_attachData (composer_server, + content_type, filename, description, + show_inline, attach_data, + &ev); + + if (ev._major != CORBA_NO_EXCEPTION) { + g_printerr ("gui/e-meeting-edit.c: I couldn't attach data to the composer via CORBA! Aagh.\n"); + CORBA_exception_free (&ev); + return; + } + + CORBA_free (content_type); + CORBA_free (filename); + CORBA_free (description); + CORBA_free (attach_data); + + to_list = GNOME_Evolution_Composer_RecipientList__alloc (); + to_list->_maximum = to_list->_length = 0; + + cc_list = GNOME_Evolution_Composer_RecipientList__alloc (); + cc_list->_maximum = cc_list->_length = 0; + + bcc_list = GNOME_Evolution_Composer_RecipientList__alloc (); + bcc_list->_maximum = bcc_list->_length = 0; + + if (!cards || cards->next) { + subject = CORBA_string_dup ("Contact information"); + } else { + ECard *card = cards->data; + const gchar *tempstr2; + + tempstr2 = NULL; + g_object_get(card, + "file_as", &tempstr2, + NULL); + if (!tempstr2 || !*tempstr2) + g_object_get(card, + "full_name", &tempstr2, + NULL); + if (!tempstr2 || !*tempstr2) + g_object_get(card, + "org", &tempstr2, + NULL); + if (!tempstr2 || !*tempstr2) { + EList *list; + EIterator *iterator; + g_object_get(card, + "email", &list, + NULL); + iterator = e_list_get_iterator (list); + if (e_iterator_is_valid (iterator)) { + tempstr2 = e_iterator_get (iterator); + } + g_object_unref (iterator); + } + + if (!tempstr2 || !*tempstr2) + tempstr = g_strdup_printf ("Contact information"); + else + tempstr = g_strdup_printf ("Contact information for %s", tempstr2); + subject = CORBA_string_dup (tempstr); + g_free (tempstr); + } + + GNOME_Evolution_Composer_setHeaders (composer_server, "", to_list, cc_list, bcc_list, subject, &ev); + + CORBA_free (to_list); + CORBA_free (cc_list); + CORBA_free (bcc_list); + CORBA_free (subject); + } + + GNOME_Evolution_Composer_show (composer_server, &ev); + + if (ev._major != CORBA_NO_EXCEPTION) { + g_printerr ("gui/e-meeting-edit.c: I couldn't show the composer via CORBA! Aagh.\n"); + CORBA_exception_free (&ev); + return; + } + + CORBA_exception_free (&ev); +#endif +} + +void +eab_send_contact (EContact *contact, EABDisposition disposition) +{ + GList *list; + list = g_list_prepend (NULL, contact); + eab_send_contact_list (list, disposition); + g_list_free (list); +} diff --git a/addressbook/gui/widgets/eab-gui-util.h b/addressbook/gui/widgets/eab-gui-util.h new file mode 100644 index 0000000000..71a80bc7a6 --- /dev/null +++ b/addressbook/gui/widgets/eab-gui-util.h @@ -0,0 +1,70 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ +/* eab-gui-util.h + * Copyright (C) 2001-2003 Ximian, Inc. + * Author: Chris Toshok + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of version 2 of the GNU General Public + * License as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ +#ifndef __E_ADDRESSBOOK_UTIL_H__ +#define __E_ADDRESSBOOK_UTIL_H__ + +#include +#include "addressbook/backend/ebook/e-book.h" +#include "addressbook/gui/contact-editor/e-contact-editor.h" +#include "addressbook/gui/contact-list-editor/e-contact-list-editor.h" + +G_BEGIN_DECLS + +void eab_error_dialog (const gchar *msg, + EBookStatus status); +gint eab_prompt_save_dialog (GtkWindow *parent); + +EContactEditor *eab_show_contact_editor (EBook *book, + EContact *contact, + gboolean is_new_contact, + gboolean editable); +EContactListEditor *eab_show_contact_list_editor (EBook *book, + EContact *contact, + gboolean is_new_contact, + gboolean editable); +void eab_show_multiple_contacts (EBook *book, + GList *list, + gboolean editable); +void eab_transfer_contacts (EBook *source, + GList *contacts, /* adopted */ + gboolean delete_from_source, + GtkWindow *parent_window); + +void eab_contact_save (char *title, + EContact *contact, + GtkWindow *parent_window); + +void eab_contact_list_save (char *title, + GList *list, + GtkWindow *parent_window); + +typedef enum { + EAB_DISPOSITION_AS_ATTACHMENT, + EAB_DISPOSITION_AS_TO, +} EABDisposition; + +void eab_send_contact (EContact *contact, + EABDisposition disposition); +void eab_send_contact_list (GList *contacts, + EABDisposition disposition); + +G_END_DECLS + +#endif /* __E_ADDRESSBOOK_UTIL_H__ */ diff --git a/addressbook/gui/widgets/eab-marshal.list b/addressbook/gui/widgets/eab-marshal.list new file mode 100644 index 0000000000..2b34707dbb --- /dev/null +++ b/addressbook/gui/widgets/eab-marshal.list @@ -0,0 +1,11 @@ +INT:POINTER +NONE:NONE +NONE:BOOL +NONE:POINTER +NONE:OBJECT +NONE:ENUM +NONE:INT,INT +NONE:INT +NONE:UINT +NONE:DOUBLE +INT:POINTER diff --git a/addressbook/gui/widgets/eab-popup-control.c b/addressbook/gui/widgets/eab-popup-control.c new file mode 100644 index 0000000000..e2d0299d6e --- /dev/null +++ b/addressbook/gui/widgets/eab-popup-control.c @@ -0,0 +1,1236 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ + +/* + * eab-popup-control.c + * + * Copyright (C) 2001-2003, Ximian, Inc. + * + * Authors: Jon Trowbridge + * Chris Toshok + */ + +/* + * This program is free software; you can redistribute it and/or + * modify it under the terms of version 2 of the GNU General Public + * License as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + * USA. + */ + +/* + * This file is too big and this widget is too complicated. Forgive me. + */ + +#include +#include +#include "addressbook.h" +#include "eab-popup-control.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "e-util/e-gui-utils.h" + +static void eab_popup_control_set_name (EABPopupControl *pop, const gchar *name); +static void eab_popup_control_set_email (EABPopupControl *pop, const gchar *email); + +/* + * Some general scaffolding for our widgets. Think of this as a really, really + * lame implementation of a wizard (...which is still somewhat more general that + * we really need it to be). + */ + +typedef struct _MiniWizard MiniWizard; +struct _MiniWizard { + GtkWidget *body; + + GtkWidget *vbox; + GtkWidget *ok_button; + GtkWidget *cancel_button; + + void (*ok_cb) (MiniWizard *, gpointer); + void (*cleanup_cb) (gpointer); + gpointer closure; + + void (*destroy_cb) (MiniWizard *, gpointer); + gpointer destroy_closure; +}; + +static void +mini_wizard_container_add (MiniWizard *wiz, GtkWidget *w) +{ + GList *iter = gtk_container_get_children (GTK_CONTAINER (wiz->vbox)); + while (iter != NULL) { + GtkWidget *oldw = (GtkWidget *) iter->data; + iter = g_list_next (iter); + gtk_container_remove (GTK_CONTAINER (wiz->vbox), oldw); + } + gtk_container_add (GTK_CONTAINER (wiz->vbox), w); +} + +static void +mini_wizard_destroy (MiniWizard *wiz) +{ + if (wiz->cleanup_cb) + wiz->cleanup_cb (wiz->closure); + wiz->cleanup_cb = NULL; + + if (wiz->destroy_cb) + wiz->destroy_cb (wiz, wiz->destroy_closure); +} + +static void +mini_wizard_ok_cb (GtkWidget *b, gpointer closure) +{ + MiniWizard *wiz = (MiniWizard *) closure; + + gpointer old_closure = wiz->closure; + void (*old_cleanup) (gpointer) = wiz->cleanup_cb; + + wiz->cleanup_cb = NULL; + + if (wiz->ok_cb) + wiz->ok_cb (wiz, wiz->closure); + + if (old_cleanup) + old_cleanup (old_closure); + +} + +static void +mini_wizard_cancel_cb (GtkWidget *b, gpointer closure) +{ + mini_wizard_destroy ((MiniWizard *) closure); +} + +static void +mini_wizard_destroy_cb (gpointer closure, GObject *where_object_was) +{ + MiniWizard *wiz = (MiniWizard *) closure; + if (wiz->cleanup_cb) + wiz->cleanup_cb (wiz->closure); + g_free (wiz); +} + +static MiniWizard * +mini_wizard_new (void) +{ + MiniWizard *wiz = g_new (MiniWizard, 1); + GtkWidget *bbox; + + wiz->body = gtk_vbox_new (FALSE, 2); + wiz->vbox = gtk_vbox_new (FALSE, 2); + wiz->ok_button = gtk_button_new_from_stock (GTK_STOCK_OK); + wiz->cancel_button = gtk_button_new_from_stock (GTK_STOCK_CANCEL); + + wiz->ok_cb = NULL; + wiz->cleanup_cb = NULL; + wiz->closure = NULL; + + wiz->destroy_cb = NULL; + wiz->destroy_closure = NULL; + + bbox = gtk_hbutton_box_new (); + gtk_button_box_set_layout (GTK_BUTTON_BOX (bbox), + GTK_BUTTONBOX_END); + + gtk_box_pack_start (GTK_BOX (bbox), wiz->cancel_button, FALSE, TRUE, 0); + gtk_box_pack_start (GTK_BOX (bbox), wiz->ok_button, FALSE, TRUE, 0); + + gtk_box_set_spacing (GTK_BOX (bbox), + 10 /* ugh */); + + gtk_box_pack_start (GTK_BOX (wiz->body), wiz->vbox, TRUE, TRUE, 2); + gtk_box_pack_start (GTK_BOX (wiz->body), gtk_hseparator_new (), FALSE, TRUE, 2); + gtk_box_pack_start (GTK_BOX (wiz->body), bbox, FALSE, TRUE, 2); + + gtk_widget_show_all (wiz->body); + + g_signal_connect (wiz->ok_button, + "clicked", + G_CALLBACK (mini_wizard_ok_cb), + wiz); + g_signal_connect (wiz->cancel_button, + "clicked", + G_CALLBACK (mini_wizard_cancel_cb), + wiz); + + g_object_weak_ref (G_OBJECT (wiz->body), + mini_wizard_destroy_cb, + wiz); + + return wiz; + +} + + + +/* + * This is the code for the UI thingie that lets you manipulate the e-mail + * addresses (and *only* the e-mail addresses) associated with an existing + * contact. + */ + +#define EMPTY_ENTRY N_("(none)") + +typedef struct _EMailMenu EMailMenu; +struct _EMailMenu { + GtkWidget *option_menu; + GList *options; + gchar *current_selection; +}; + +static void +email_menu_free (EMailMenu *menu) +{ + if (menu == NULL) + return; + + g_list_foreach (menu->options, (GFunc) g_free, NULL); + g_list_free (menu->options); + g_free (menu); +} + +static EMailMenu * +email_menu_new (void) +{ + EMailMenu *menu = g_new (EMailMenu, 1); + + menu->option_menu = gtk_option_menu_new (); + menu->options = NULL; + menu->current_selection = NULL; + + gtk_option_menu_set_menu (GTK_OPTION_MENU (menu->option_menu), gtk_menu_new ()); + + return menu; +} + +static void +menu_activate_cb (GtkWidget *w, gpointer closure) +{ + EMailMenu *menu = (EMailMenu *) closure; + gchar *addr = (gchar *) g_object_get_data (G_OBJECT (w), "addr"); + + menu->current_selection = addr; +} + +static void +email_menu_add_option (EMailMenu *menu, char *addr) +{ + GtkWidget *menu_item; + + g_return_if_fail (menu != NULL); + if (addr == NULL) + return; + + menu->options = g_list_append (menu->options, addr); + + menu_item = gtk_menu_item_new_with_label (addr); + g_object_set_data (G_OBJECT (menu_item), "addr", addr); + gtk_widget_show_all (menu_item); + gtk_menu_shell_append (GTK_MENU_SHELL (gtk_option_menu_get_menu (GTK_OPTION_MENU (menu->option_menu))), menu_item); + + g_signal_connect (menu_item, + "activate", + G_CALLBACK (menu_activate_cb), + menu); +} + +static void +email_menu_add_options_from_contact (EMailMenu *menu, EContact *contact, const gchar *extra_addr) +{ + g_return_if_fail (contact && E_IS_CONTACT (contact)); + + /* If any of these three e-mail fields are NULL, email_menu_add_option will just + return without doing anything. */ + email_menu_add_option (menu, e_contact_get (contact, E_CONTACT_EMAIL_1)); + email_menu_add_option (menu, e_contact_get (contact, E_CONTACT_EMAIL_2)); + email_menu_add_option (menu, e_contact_get (contact, E_CONTACT_EMAIL_3)); + email_menu_add_option (menu, g_strdup (extra_addr)); + email_menu_add_option (menu, EMPTY_ENTRY); +} + +static void +email_menu_set_option (EMailMenu *menu, const gchar *addr) +{ + guint count = 0; + GList *iter; + + g_return_if_fail (menu != NULL); + + if (addr == NULL) { + email_menu_set_option (menu, EMPTY_ENTRY); + return; + } + + iter = menu->options; + while (iter && strcmp (addr, (gchar *) iter->data)) { + ++count; + iter = g_list_next (iter); + } + + if (iter) { + gtk_option_menu_set_history (GTK_OPTION_MENU (menu->option_menu), count); + menu->current_selection = (gchar *) iter->data; + } +} + +#ifdef UNDEFINED_FUNCTIONS_SHOULD_PLEASE_BE_INCLUDED +static void +email_menu_unset_option (EMailMenu *menu, const gchar *addr) +{ + GList *iter; + + g_return_if_fail (menu != NULL); + g_return_if_fail (addr != NULL); + + if (menu->current_selection == NULL || strcmp (addr, menu->current_selection)) + return; + + iter = menu->options; + while (iter && strcmp (addr, (gchar *) iter->data)) { + iter = g_list_next (iter); + } + if (iter) { + iter = g_list_next (iter); + if (iter) { + email_menu_set_option (menu, (gchar *) iter->data); + } else { + email_menu_set_option (menu, EMPTY_ENTRY); + } + } +} +#endif + + + +typedef struct _EMailTable EMailTable; +struct _EMailTable { + GtkWidget *table; + EContact *contact; + EMailMenu *primary; + EMailMenu *email2; + EMailMenu *email3; +}; + +static void +email_table_cleanup_cb (gpointer closure) +{ + EMailTable *et = (EMailTable *) closure; + + if (et == NULL) + return; + + g_object_unref (et->contact); + email_menu_free (et->primary); + email_menu_free (et->email2); + email_menu_free (et->email3); + + g_free (et); +} + +static void +email_table_from_contact (EMailTable *et) +{ + g_return_if_fail (et != NULL); + + email_menu_set_option (et->primary, e_contact_get_const (et->contact, E_CONTACT_EMAIL_1)); + email_menu_set_option (et->email2, e_contact_get_const (et->contact, E_CONTACT_EMAIL_2)); + email_menu_set_option (et->email3, e_contact_get_const (et->contact, E_CONTACT_EMAIL_3)); +} + +static void +email_table_to_contact (EMailTable *et) +{ + gchar *curr; + + g_return_if_fail (et != NULL); + + curr = et->primary->current_selection; + if (curr && !strcmp (curr, _(EMPTY_ENTRY))) + curr = NULL; + e_contact_set (et->contact, E_CONTACT_EMAIL_1, curr); + + curr = et->email2->current_selection; + if (curr && !strcmp (curr, _(EMPTY_ENTRY))) + curr = NULL; + e_contact_set (et->contact, E_CONTACT_EMAIL_2, curr); + + curr = et->email3->current_selection; + if (curr && !strcmp (curr, _(EMPTY_ENTRY))) + curr = NULL; + e_contact_set (et->contact, E_CONTACT_EMAIL_3, curr); +} + +static void +email_table_save_contact_cb (EBook *book, EBookStatus status, gpointer closure) +{ + EContact *contact = E_CONTACT (closure); + + if (status == E_BOOK_ERROR_OK) { + e_book_async_commit_contact (book, contact, NULL, NULL); + } + if (book) + g_object_unref (book); + g_object_unref (contact); +} + +static void +email_table_ok_cb (MiniWizard *wiz, gpointer closure) +{ + EMailTable *et = (EMailTable *) closure; + + email_table_to_contact (et); + + g_object_ref (et->contact); + + addressbook_load_default_book (email_table_save_contact_cb, et->contact); + + mini_wizard_destroy (wiz); +} + +static void +email_table_init (MiniWizard *wiz, EContact *contact, const gchar *extra_address) +{ + EMailTable *et; + + gchar *name_str; + gint xpad, ypad; + GtkAttachOptions label_x_opts, label_y_opts; + GtkAttachOptions menu_x_opts, menu_y_opts; + + g_return_if_fail (contact && E_IS_CONTACT (contact)); + + et = g_new (EMailTable, 1); + + et->contact = contact; + g_object_ref (et->contact); + + et->table = gtk_table_new (4, 2, FALSE); + + et->primary = email_menu_new (); + et->email2 = email_menu_new (); + et->email3 = email_menu_new (); + + email_menu_add_options_from_contact (et->primary, et->contact, extra_address); + email_menu_add_options_from_contact (et->email2, et->contact, extra_address); + email_menu_add_options_from_contact (et->email3, et->contact, extra_address); + + email_table_from_contact (et); + + label_x_opts = GTK_FILL; + label_y_opts = GTK_FILL; + menu_x_opts = GTK_EXPAND | GTK_FILL; + menu_y_opts = GTK_EXPAND | GTK_FILL; + xpad = 3; + ypad = 3; + + name_str = e_contact_get (et->contact, E_CONTACT_FULL_NAME); + gtk_table_attach (GTK_TABLE (et->table), + gtk_label_new (name_str), + 0, 2, 0, 1, + label_x_opts, label_y_opts, xpad, ypad); + g_free (name_str); + + gtk_table_attach (GTK_TABLE (et->table), + gtk_label_new (_("Primary Email")), + 0, 1, 1, 2, + label_x_opts, label_y_opts, xpad, ypad); + + gtk_table_attach (GTK_TABLE (et->table), + et->primary->option_menu, + 1, 2, 1, 2, + menu_x_opts, menu_y_opts, xpad, ypad); + + gtk_table_attach (GTK_TABLE (et->table), + gtk_label_new (_("Email 2")), + 0, 1, 2, 3, + label_x_opts, label_y_opts, xpad, ypad); + + gtk_table_attach (GTK_TABLE (et->table), + et->email2->option_menu, + 1, 2, 2, 3, + menu_x_opts, menu_y_opts, xpad, ypad); + + gtk_table_attach (GTK_TABLE (et->table), + gtk_label_new (_("Email 3")), + 0, 1, 3, 4, + label_x_opts, label_y_opts, xpad, ypad); + + gtk_table_attach (GTK_TABLE (et->table), + et->email3->option_menu, + 1, 2, 3, 4, + menu_x_opts, menu_y_opts, xpad, ypad); + + gtk_widget_show_all (et->primary->option_menu); + gtk_widget_show_all (et->email2->option_menu); + gtk_widget_show_all (et->email3->option_menu); + + gtk_widget_show_all (et->table); + mini_wizard_container_add (wiz, et->table); + wiz->ok_cb = email_table_ok_cb; + wiz->cleanup_cb = email_table_cleanup_cb; + wiz->closure = et; +} + +/* + * This code is for the little UI thing that lets you pick from a set of contacts + * and decide which one you want to add the e-mail address to. + */ + +typedef struct _ContactPicker ContactPicker; +struct _ContactPicker { + GtkWidget *body; + GtkWidget *list; + GtkListStore *model; + GList *contacts; + gchar *new_name; + gchar *new_email; + + EContact *current_contact; +}; + +enum { + COLUMN_ACTION, + COLUMN_CONTACT +}; + +static void +contact_picker_selection_changed (GtkTreeSelection *selection, gpointer closure) +{ + MiniWizard *wiz = (MiniWizard *) closure; + ContactPicker *pick = (ContactPicker *) wiz->closure; + gboolean selected; + GtkTreeIter iter; + + selected = gtk_tree_selection_get_selected (selection, NULL, &iter); + + gtk_widget_set_sensitive (wiz->ok_button, selected); + + if (selected) { + gtk_tree_model_get (GTK_TREE_MODEL (pick->model), &iter, + COLUMN_CONTACT, &pick->current_contact, + -1); + } + else { + pick->current_contact = NULL; + } +} + +static void +contact_picker_ok_cb (MiniWizard *wiz, gpointer closure) +{ + ContactPicker *pick = (ContactPicker *) closure; + + if (pick->current_contact == NULL) { + e_contact_quick_add (pick->new_name, pick->new_email, NULL, NULL); + mini_wizard_destroy (wiz); + } else { + email_table_init (wiz, pick->current_contact, pick->new_email); + } +} + +static void +contact_picker_cleanup_cb (gpointer closure) +{ + ContactPicker *pick = (ContactPicker *) closure; + + g_list_foreach (pick->contacts, (GFunc) g_object_unref, NULL); + g_list_free (pick->contacts); + + g_free (pick->new_name); + g_free (pick->new_email); +} + +static void +free_str (gpointer data, + GObject *where_the_object_was) +{ + g_free (data); +} + +static void +contact_picker_init (MiniWizard *wiz, const GList *contacts, const gchar *new_name, const gchar *new_email) +{ + ContactPicker *pick; + gchar *str; + GtkWidget *w; + GtkTreeIter iter; + + pick = g_new (ContactPicker, 1); + + pick->body = gtk_vbox_new (FALSE, 2); + + pick->model = gtk_list_store_new (2, G_TYPE_STRING, G_TYPE_POINTER); + + pick->list = gtk_tree_view_new_with_model (GTK_TREE_MODEL (pick->model)); + + gtk_tree_view_set_headers_visible (GTK_TREE_VIEW (pick->list), TRUE); + + gtk_tree_view_insert_column_with_attributes (GTK_TREE_VIEW (pick->list), + COLUMN_ACTION, + _("Select an Action"), + gtk_cell_renderer_text_new (), + "text", COLUMN_ACTION, + NULL); + + gtk_tree_selection_set_mode (gtk_tree_view_get_selection (GTK_TREE_VIEW (pick->list)), + GTK_SELECTION_SINGLE); + + str = g_strdup_printf (_("Create a new contact \"%s\""), new_name); + gtk_list_store_append (pick->model, &iter); + gtk_list_store_set (pick->model, &iter, + COLUMN_ACTION, str, + COLUMN_CONTACT, NULL, + -1); + g_object_weak_ref (G_OBJECT (pick->model), free_str, str); + + pick->contacts = NULL; + while (contacts) { + EContact *contact = (EContact *) contacts->data; + gchar *name_str = e_contact_get (contact, E_CONTACT_FULL_NAME); + + pick->contacts = g_list_append (pick->contacts, contact); + g_object_ref (contact); + + str = g_strdup_printf (_("Add address to existing contact \"%s\""), name_str); + gtk_list_store_append (pick->model, &iter); + gtk_list_store_set (pick->model, &iter, + COLUMN_ACTION, str, + COLUMN_CONTACT, contact, + -1); + g_free (name_str); + + g_object_weak_ref (G_OBJECT (pick->model), free_str, str); + + contacts = g_list_next (contacts); + } + + pick->new_name = g_strdup (new_name); + pick->new_email = g_strdup (new_email); + + pick->current_contact = NULL; + gtk_widget_set_sensitive (wiz->ok_button, FALSE); + + /* Connect some signals & callbacks */ + + wiz->ok_cb = contact_picker_ok_cb; + wiz->cleanup_cb = contact_picker_cleanup_cb; + + g_signal_connect (gtk_tree_view_get_selection (GTK_TREE_VIEW (pick->list)), + "changed", G_CALLBACK (contact_picker_selection_changed), + wiz); + + /* Build our widget */ + + w = gtk_label_new (new_email); + gtk_box_pack_start (GTK_BOX (pick->body), w, FALSE, TRUE, 3); + + gtk_box_pack_start (GTK_BOX (pick->body), pick->list, TRUE, TRUE, 2); + gtk_widget_show_all (pick->body); + + + /* Put it in our mini-wizard */ + + wiz->closure = pick; + mini_wizard_container_add (wiz, pick->body); +} + +/* ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** */ + +/* + * The code for the actual EABPopupControl widget begins here. + */ + +/* ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** */ + + +static GtkObjectClass *parent_class; + +static void eab_popup_control_dispose (GObject *); +static void eab_popup_control_query (EABPopupControl *); + + +static void +eab_popup_control_class_init (EABPopupControlClass *klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS (klass); + + parent_class = g_type_class_peek_parent (klass); + + object_class->dispose = eab_popup_control_dispose; +} + +static void +eab_popup_control_init (EABPopupControl *pop) +{ + pop->transitory = TRUE; +} + +static void +eab_popup_control_cleanup (EABPopupControl *pop) +{ + if (pop->contact) { + g_object_unref (pop->contact); + pop->contact = NULL; + } + + if (pop->scheduled_refresh) { + g_source_remove (pop->scheduled_refresh); + pop->scheduled_refresh = 0; + } + + if (pop->query_tag) { +#if notyet + e_book_simple_query_cancel (pop->book, pop->query_tag); +#endif + pop->query_tag = 0; + } + + if (pop->book) { + g_object_unref (pop->book); + pop->book = NULL; + } + + g_free (pop->name); + pop->name = NULL; + + g_free (pop->email); + pop->email = NULL; +} + +static void +eab_popup_control_dispose (GObject *obj) +{ + EABPopupControl *pop = EAB_POPUP_CONTROL (obj); + + eab_popup_control_cleanup (pop); + + if (G_OBJECT_CLASS (parent_class)->dispose) + G_OBJECT_CLASS (parent_class)->dispose (obj); +} + +GType +eab_popup_control_get_type (void) +{ + static GType pop_type = 0; + + if (!pop_type) { + static const GTypeInfo pop_info = { + sizeof (EABPopupControlClass), + NULL, /* base_init */ + NULL, /* base_finalize */ + (GClassInitFunc) eab_popup_control_class_init, + NULL, /* class_finalize */ + NULL, /* class_data */ + sizeof (EABPopupControl), + 0, /* n_preallocs */ + (GInstanceInitFunc) eab_popup_control_init, + }; + + pop_type = g_type_register_static (gtk_event_box_get_type (), "EABPopupControl", &pop_info, 0); + } + + return pop_type; +} + +static void +eab_popup_control_refresh_names (EABPopupControl *pop) +{ + if (pop->name_widget) { + if (pop->name && *pop->name) { + gtk_label_set_text (GTK_LABEL (pop->name_widget), pop->name); + gtk_widget_show (pop->name_widget); + } else { + gtk_widget_hide (pop->name_widget); + } + } + + if (pop->email_widget) { + if (pop->email && *pop->email) { + gtk_label_set_text (GTK_LABEL (pop->email_widget), pop->email); + gtk_widget_show (pop->email_widget); + } else { + gtk_widget_hide (pop->email_widget); + } + } + + eab_popup_control_query (pop); +} + +static gint +refresh_timeout_cb (gpointer ptr) +{ + EABPopupControl *pop = EAB_POPUP_CONTROL (ptr); + eab_popup_control_refresh_names (pop); + pop->scheduled_refresh = 0; + return 0; +} + +static void +eab_popup_control_schedule_refresh (EABPopupControl *pop) +{ + if (pop->scheduled_refresh == 0) + pop->scheduled_refresh = g_timeout_add (20, refresh_timeout_cb, pop); +} + +/* If we are handed something of the form "Foo ", + do the right thing. */ +static gboolean +eab_popup_control_set_free_form (EABPopupControl *pop, const gchar *txt) +{ + gchar *lt, *gt = NULL; + + g_return_val_if_fail (pop && EAB_IS_POPUP_CONTROL (pop), FALSE); + + if (txt == NULL) + return FALSE; + + lt = strchr (txt, '<'); + if (lt) + gt = strchr (txt, '>'); + + if (lt && gt && lt+1 < gt) { + gchar *name = g_strndup (txt, lt-txt); + gchar *email = g_strndup (lt+1, gt-lt-1); + eab_popup_control_set_name (pop, name); + eab_popup_control_set_email (pop, email); + + return TRUE; + } + + return FALSE; +} + +static void +eab_popup_control_set_name (EABPopupControl *pop, const gchar *name) +{ + g_return_if_fail (pop && EAB_IS_POPUP_CONTROL (pop)); + + /* We only allow the name to be set once. */ + if (pop->name) + return; + + if (!eab_popup_control_set_free_form (pop, name)) { + pop->name = g_strdup (name); + if (pop->name) + g_strstrip (pop->name); + } + + eab_popup_control_schedule_refresh (pop); +} + +static void +eab_popup_control_set_email (EABPopupControl *pop, const gchar *email) +{ + g_return_if_fail (pop && EAB_IS_POPUP_CONTROL (pop)); + + /* We only allow the e-mail to be set once. */ + if (pop->email) + return; + + if (!eab_popup_control_set_free_form (pop, email)) { + pop->email = g_strdup (email); + if (pop->email) + g_strstrip (pop->email); + } + + eab_popup_control_schedule_refresh (pop); +} + +void +eab_popup_control_construct (EABPopupControl *pop) +{ + GtkWidget *vbox, *name_holder; + GdkColor color = { 0x0, 0xffff, 0xffff, 0xffff }; + + g_return_if_fail (pop && EAB_IS_POPUP_CONTROL (pop)); + + pop->main_vbox = gtk_vbox_new (FALSE, 0); + + /* Build Generic View */ + + name_holder = gtk_event_box_new (); + vbox = gtk_vbox_new (FALSE, 2); + pop->name_widget = gtk_label_new (""); + pop->email_widget = gtk_label_new (""); + + gtk_box_pack_start (GTK_BOX (vbox), pop->name_widget, TRUE, TRUE, 2); + gtk_box_pack_start (GTK_BOX (vbox), pop->email_widget, TRUE, TRUE, 2); + gtk_container_add (GTK_CONTAINER (name_holder), GTK_WIDGET (vbox)); + + if (gdk_colormap_alloc_color (gtk_widget_get_colormap (GTK_WIDGET (name_holder)), &color, FALSE, TRUE)) { + GtkStyle *style = gtk_style_copy (gtk_widget_get_style (GTK_WIDGET (name_holder))); + style->bg[0] = color; + gtk_widget_set_style (GTK_WIDGET (name_holder), style); + g_object_unref (style); + } + + pop->generic_view = gtk_frame_new (NULL); + gtk_container_add (GTK_CONTAINER (pop->generic_view), name_holder); + gtk_box_pack_start (GTK_BOX (pop->main_vbox), pop->generic_view, TRUE, TRUE, 0); + gtk_widget_show_all (pop->generic_view); + + pop->query_msg = gtk_label_new (_("Querying Addressbook...")); + gtk_box_pack_start (GTK_BOX (pop->main_vbox), pop->query_msg, TRUE, TRUE, 0); + gtk_widget_show (pop->query_msg); + + /* Build ContactDisplay */ + pop->contact_display = eab_contact_display_new (); + gtk_box_pack_start (GTK_BOX (pop->main_vbox), pop->contact_display, TRUE, TRUE, 0); + + + /* Final assembly */ + + gtk_container_add (GTK_CONTAINER (pop), pop->main_vbox); + gtk_widget_show (pop->main_vbox); + + gtk_container_set_border_width (GTK_CONTAINER (vbox), 3); + gtk_container_set_border_width (GTK_CONTAINER (pop), 2); +} + +static GtkWidget * +eab_popup_new (void) +{ + EABPopupControl *pop = g_object_new (EAB_TYPE_POPUP_CONTROL, NULL); + eab_popup_control_construct (pop); + return GTK_WIDGET (pop); +} + +static void +emit_event (EABPopupControl *pop, const char *event) +{ + if (pop->es) { + BonoboArg *arg; + + arg = bonobo_arg_new (BONOBO_ARG_BOOLEAN); + BONOBO_ARG_SET_BOOLEAN (arg, TRUE); + bonobo_event_source_notify_listeners_full (pop->es, + "GNOME/Evolution/Addressbook/AddressPopup", + "Event", + event, + arg, NULL); + bonobo_arg_release (arg); + } +} + +static void +contact_editor_cb (EBook *book, EBookStatus status, gpointer closure) +{ + if (status == E_BOOK_ERROR_OK) { + EABPopupControl *pop = EAB_POPUP_CONTROL (closure); + EContactEditor *ce = eab_show_contact_editor (book, pop->contact, FALSE, TRUE); + eab_popup_control_cleanup (pop); + emit_event (pop, "Destroy"); + e_contact_editor_raise (ce); + } + + if (book) + g_object_unref (book); +} + +static void +edit_contact_info_cb (GtkWidget *button, EABPopupControl *pop) +{ + emit_event (pop, "Hide"); + + addressbook_load_default_book (contact_editor_cb, pop); +} + +static void +eab_popup_control_display_contact (EABPopupControl *pop, EContact *contact) +{ + GtkWidget *b; + + g_return_if_fail (pop && EAB_IS_POPUP_CONTROL (pop)); + g_return_if_fail (contact && E_IS_CONTACT (contact)); + g_return_if_fail (pop->contact == NULL); + + pop->contact = contact; + g_object_ref (pop->contact); + + eab_contact_display_render (EAB_CONTACT_DISPLAY (pop->contact_display), + contact, + EAB_CONTACT_DISPLAY_RENDER_COMPACT); + gtk_widget_show (pop->contact_display); + gtk_widget_hide (pop->generic_view); + + b = gtk_button_new_with_label (_("Edit Contact Info")); + gtk_box_pack_start (GTK_BOX (pop->main_vbox), b, TRUE, TRUE, 0); + g_signal_connect (b, + "clicked", + G_CALLBACK (edit_contact_info_cb), + pop); + gtk_widget_show (b); +} + +static void +add_contacts_cb (GtkWidget *button, EABPopupControl *pop) +{ + if (pop->email && *pop->email) { + if (pop->name && *pop->name) + e_contact_quick_add (pop->name, pop->email, NULL, NULL); + else + e_contact_quick_add_free_form (pop->email, NULL, NULL); + + } + eab_popup_control_cleanup (pop); + emit_event (pop, "Destroy"); +} + +static void +eab_popup_control_no_matches (EABPopupControl *pop) +{ + GtkWidget *b; + + g_return_if_fail (pop && EAB_IS_POPUP_CONTROL (pop)); + + b = e_button_new_with_stock_icon (_("Add to Contacts"), "gtk-add"); + + gtk_box_pack_start (GTK_BOX (pop->main_vbox), b, TRUE, TRUE, 0); + g_signal_connect (b, + "clicked", + G_CALLBACK (add_contacts_cb), + pop); + gtk_widget_show (b); +} + +static void +wizard_destroy_cb (MiniWizard *wiz, gpointer closure) +{ + gtk_widget_destroy (GTK_WIDGET (closure)); +} + +static void +eab_popup_control_ambiguous_email_add (EABPopupControl *pop, const GList *contacts) +{ + MiniWizard *wiz = mini_wizard_new (); + GtkWidget *win = gtk_window_new (GTK_WINDOW_TOPLEVEL); + + wiz->destroy_cb = wizard_destroy_cb; + wiz->destroy_closure = win; + + gtk_window_set_title (GTK_WINDOW (win), _("Merge E-Mail Address")); + gtk_window_set_position (GTK_WINDOW (win), GTK_WIN_POS_MOUSE); + + contact_picker_init (wiz, contacts, pop->name, pop->email); + + eab_popup_control_cleanup (pop); + emit_event (pop, "Destroy"); + + gtk_container_add (GTK_CONTAINER (win), wiz->body); + gtk_widget_show_all (win); +} + +static void +eab_popup_control_multiple_matches (EABPopupControl *pop, const GList *contacts) +{ + pop->multiple_matches = TRUE; + + eab_popup_control_ambiguous_email_add (pop, contacts); +} + +/** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** **/ + +/* + * Addressbook Query Fun + */ + +static void +name_only_query_cb (EBook *book, EBookStatus status, GList *contacts, gpointer closure) +{ + EABPopupControl *pop; + + if (status != E_BOOK_ERROR_OK) + return; + + pop = EAB_POPUP_CONTROL (closure); + + pop->query_tag = 0; + + if (contacts == NULL) { + eab_popup_control_no_matches (pop); + } else { + eab_popup_control_ambiguous_email_add (pop, contacts); + g_list_foreach (contacts, (GFunc)g_object_unref, NULL); + g_list_free (contacts); + } +} + +static void +query_cb (EBook *book, EBookStatus status, GList *contacts, gpointer closure) +{ + EABPopupControl *pop; + + if (status != E_BOOK_ERROR_OK) + return; + + pop = EAB_POPUP_CONTROL (closure); + + pop->query_tag = 0; + gtk_widget_hide (pop->query_msg); + + if (contacts == NULL) { + + /* Do a name-only query if: + (1) The name is non-empty. + (2) The e-mail is also non-empty (so that the query we just did wasn't actually a name-only query. + */ + if (pop->name && *pop->name && pop->email && *pop->email) { + pop->query_tag = eab_name_and_email_query (book, pop->name, NULL, name_only_query_cb, pop); + } else { + eab_popup_control_no_matches (pop); + } + + } else { + if (g_list_length ((GList *) contacts) == 1) + eab_popup_control_display_contact (pop, E_CONTACT (contacts->data)); + else + eab_popup_control_multiple_matches (pop, contacts); + + g_list_foreach (contacts, (GFunc)g_object_unref, NULL); + g_list_free (contacts); + } +} + +static void +start_query (EBook *book, EBookStatus status, gpointer closure) +{ + EABPopupControl *pop = EAB_POPUP_CONTROL (closure); + + if (status != E_BOOK_ERROR_OK) { + eab_popup_control_no_matches (pop); + if (book) + g_object_unref (book); + return; + } + +#if notyet + if (pop->query_tag) + e_book_simple_query_cancel (book, pop->query_tag); +#endif + + if (pop->book != book) { + g_object_ref (book); + if (pop->book) + g_object_unref (pop->book); + pop->book = book; + } + + pop->query_tag = eab_name_and_email_query (book, pop->name, pop->email, query_cb, pop); + + g_object_unref (pop); +} + +static void +eab_popup_control_query (EABPopupControl *pop) +{ + g_return_if_fail (pop && EAB_IS_POPUP_CONTROL (pop)); + + g_object_ref (pop); + + addressbook_load_default_book (start_query, pop); +} + +/** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** **/ + +enum { + PROPERTY_NAME, + PROPERTY_EMAIL, + PROPERTY_TRANSITORY +}; + +static void +set_prop (BonoboPropertyBag *bag, const BonoboArg *arg, guint arg_id, CORBA_Environment *ev, gpointer user_data) +{ + EABPopupControl *pop = EAB_POPUP_CONTROL (user_data); + + switch (arg_id) { + + case PROPERTY_NAME: + eab_popup_control_set_name (pop, BONOBO_ARG_GET_STRING (arg)); + break; + + case PROPERTY_EMAIL: + eab_popup_control_set_email (pop, BONOBO_ARG_GET_STRING (arg)); + break; + + default: + g_assert_not_reached (); + } +} + +static void +get_prop (BonoboPropertyBag *bag, BonoboArg *arg, guint arg_id, CORBA_Environment *ev, gpointer user_data) +{ + EABPopupControl *pop = EAB_POPUP_CONTROL (user_data); + + switch (arg_id) { + + case PROPERTY_NAME: + BONOBO_ARG_SET_STRING (arg, pop->name); + break; + + case PROPERTY_EMAIL: + BONOBO_ARG_SET_STRING (arg, pop->email); + break; + + case PROPERTY_TRANSITORY: + BONOBO_ARG_SET_BOOLEAN (arg, pop->transitory); + break; + + default: + g_assert_not_reached (); + } +} + +BonoboControl * +eab_popup_control_new (void) +{ + BonoboControl *control; + BonoboPropertyBag *bag; + EABPopupControl *addy; + GtkWidget *w; + + w = eab_popup_new (); + addy = EAB_POPUP_CONTROL (w); + + control = bonobo_control_new (w); + gtk_widget_show (w); + + bag = bonobo_property_bag_new (get_prop, set_prop, w); + bonobo_property_bag_add (bag, "name", PROPERTY_NAME, + BONOBO_ARG_STRING, NULL, NULL, + BONOBO_PROPERTY_WRITEABLE | BONOBO_PROPERTY_READABLE); + + bonobo_property_bag_add (bag, "email", PROPERTY_EMAIL, + BONOBO_ARG_STRING, NULL, NULL, + BONOBO_PROPERTY_WRITEABLE | BONOBO_PROPERTY_READABLE); + + bonobo_property_bag_add (bag, "transitory", PROPERTY_TRANSITORY, + BONOBO_ARG_BOOLEAN, NULL, NULL, + BONOBO_PROPERTY_READABLE); + + bonobo_control_set_properties (control, bonobo_object_corba_objref (BONOBO_OBJECT (bag)), NULL); + bonobo_object_unref (BONOBO_OBJECT (bag)); + + addy->es = bonobo_event_source_new (); + bonobo_object_add_interface (BONOBO_OBJECT (control), + BONOBO_OBJECT (addy->es)); + + return control; +} diff --git a/addressbook/gui/widgets/eab-popup-control.h b/addressbook/gui/widgets/eab-popup-control.h new file mode 100644 index 0000000000..4d223f02cb --- /dev/null +++ b/addressbook/gui/widgets/eab-popup-control.h @@ -0,0 +1,85 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ + +/* + * eab-popup-control.h + * + * Copyright (C) 2001-2003, Ximian, Inc. + * + * Authors: Jon Trowbridge + * Chris Toshok + */ + +/* + * This program is free software; you can redistribute it and/or + * modify it under the terms of version 2 of the GNU General Public + * License as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + * USA. + */ + +#ifndef __EAB_POPUP_CONTROL_H__ +#define __EAB_POPUP_CONTROL_H__ + +#include +#include +#include +#include + +G_BEGIN_DECLS + +#define EAB_TYPE_POPUP_CONTROL (eab_popup_control_get_type ()) +#define EAB_POPUP_CONTROL(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), EAB_TYPE_POPUP_CONTROL, EABPopupControl)) +#define EAB_POPUP_CONTROL_CLASS(k) (G_TYPE_CHECK_CLASS_CAST ((k), EAB_TYPE_POPUP_CONTROL, EABPopupControlClass)) +#define EAB_IS_POPUP_CONTROL(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), EAB_TYPE_POPUP_CONTROL)) +#define EAB_IS_POPUP_CONTROL_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), EAB_TYPE_POPUP_CONTROL)) + +typedef struct _EABPopupControl EABPopupControl; +typedef struct _EABPopupControlClass EABPopupControlClass; + +struct _EABPopupControl { + GtkEventBox parent; + + gchar *name; + gchar *email; + + GtkWidget *name_widget; + GtkWidget *email_widget; + GtkWidget *query_msg; + + GtkWidget *main_vbox; + GtkWidget *generic_view; + GtkWidget *contact_display; + + gboolean transitory; + + guint scheduled_refresh; + EBook *book; + guint query_tag; + gboolean multiple_matches; + EContact *contact; + + BonoboEventSource *es; +}; + +struct _EABPopupControlClass { + GtkEventBoxClass parent_class; +}; + +GType eab_popup_control_get_type (void); + +void eab_popup_control_construct (EABPopupControl *); + +BonoboControl *eab_popup_control_new (void); + +G_END_DECLS + +#endif /* __EAB_POPUP_CONTROL_H__ */ + diff --git a/addressbook/gui/widgets/eab-vcard-control.c b/addressbook/gui/widgets/eab-vcard-control.c new file mode 100644 index 0000000000..82c5fd6032 --- /dev/null +++ b/addressbook/gui/widgets/eab-vcard-control.c @@ -0,0 +1,310 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ +/* + * eab-vcard-control.c + * + * Copyright (C) 1999, 2000, 2001, 2002, 2003, Ximian, Inc. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of version 2 of the GNU General Public + * License as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public + * License along with this program; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + * + * Authors: + * Chris Lahey + * Chris Toshok + */ + +#include +#include + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include "eab-vcard-control.h" +#include "eab-contact-merging.h" + +typedef struct { + EABContactDisplay *display; + GList *card_list; + GtkWidget *label; + EABContactDisplayRenderMode render_mode; +} EABVCardControl; + +#define VCARD_CONTROL_ID "OAFIID:GNOME_Evolution_Addressbook_VCard_Control" + +/* + * Bonobo::PersistStream + * + * These two functions implement the Bonobo::PersistStream load and + * save methods which allow data to be loaded into and out of the + * BonoboObject. + */ +static char * +stream_read (Bonobo_Stream stream) +{ + Bonobo_Stream_iobuf *buffer; + CORBA_Environment ev; + char *data = NULL; + gint length = 0; + + CORBA_exception_init (&ev); + do { +#define READ_CHUNK_SIZE 65536 + Bonobo_Stream_read (stream, READ_CHUNK_SIZE, + &buffer, &ev); + + if (ev._major != CORBA_NO_EXCEPTION) { + CORBA_exception_free (&ev); + return NULL; + } + + if (buffer->_length <= 0) + break; + + data = g_realloc (data, length + buffer->_length + 1); + + memcpy (data + length, buffer->_buffer, buffer->_length); + + length += buffer->_length; + + CORBA_free (buffer); + } while (1); + + CORBA_free (buffer); + CORBA_exception_free (&ev); + + if (data) + data[length] = '\0'; + else + data = g_strdup(""); + + return data; +} /* stream_read */ + +/* + * This function implements the Bonobo::PersistStream:load method. + */ +static void +pstream_load (BonoboPersistStream *ps, const Bonobo_Stream stream, + Bonobo_Persist_ContentType type, void *data, + CORBA_Environment *ev) +{ + GList *list; + char *vcard; + EABVCardControl *vcard_control = data; + + if (type && g_ascii_strcasecmp (type, "text/vCard") != 0 && + g_ascii_strcasecmp (type, "text/x-vCard") != 0) { + CORBA_exception_set (ev, CORBA_USER_EXCEPTION, + ex_Bonobo_Persist_WrongDataType, NULL); + return; + } + + if ((vcard = stream_read (stream)) == NULL) { + CORBA_exception_set (ev, CORBA_USER_EXCEPTION, + ex_Bonobo_Persist_FileNotFound, NULL); + return; + } + + e_free_object_list (vcard_control->card_list); + list = eab_contact_list_from_string (vcard); + g_free(vcard); + vcard_control->card_list = list; + if (list) { + eab_contact_display_render (vcard_control->display, E_CONTACT (list->data), + vcard_control->render_mode); + } + if (list && list->next) { + char *message; + int length = g_list_length (list) - 1; + if (length > 1) { + message = g_strdup_printf (_("and %d other contacts."), length); + } else { + message = g_strdup_printf (_("and one other contact.")); + } + gtk_label_set_text (GTK_LABEL (vcard_control->label), message); + g_free (message); + gtk_widget_show (vcard_control->label); + } else { + gtk_widget_hide (vcard_control->label); + } +} /* pstream_load */ + +/* + * This function implements the Bonobo::PersistStream:save method. + */ +static void +pstream_save (BonoboPersistStream *ps, const Bonobo_Stream stream, + Bonobo_Persist_ContentType type, void *data, + CORBA_Environment *ev) +{ + EABVCardControl *vcard_control = data; + char *vcard; + int length; + + if (type && g_ascii_strcasecmp (type, "text/vCard") != 0 && + g_ascii_strcasecmp (type, "text/x-vCard") != 0) { + CORBA_exception_set (ev, CORBA_USER_EXCEPTION, + ex_Bonobo_Persist_WrongDataType, NULL); + return; + } + + vcard = eab_contact_list_to_string (vcard_control->card_list); + length = strlen (vcard); + bonobo_stream_client_write (stream, vcard, length, ev); + g_free (vcard); +} /* pstream_save */ + +static Bonobo_Persist_ContentTypeList * +pstream_get_content_types (BonoboPersistStream *ps, void *closure, + CORBA_Environment *ev) +{ + return bonobo_persist_generate_content_types (2, "text/vCard", "text/x-vCard"); +} + +static void +book_open_cb (EBook *book, EBookStatus status, gpointer closure) +{ + GList *list = closure; + if (status == E_BOOK_ERROR_OK) { + GList *p; + for (p = list; p; p = p->next) { + /* XXX argh, more passing of NULL's for callbacks */ + eab_merging_book_add_contact (book, E_CONTACT (p->data), NULL, NULL); + } + } + if (book) + g_object_unref (book); + e_free_object_list (list); +} + +static void +save_in_addressbook(GtkWidget *button, gpointer data) +{ + EABVCardControl *vcard_control = data; + GList *list, *p; + + list = g_list_copy (vcard_control->card_list); + + for (p = list; p; p = p->next) + g_object_ref (p->data); + + addressbook_load_default_book (book_open_cb, list); +} + +static void +toggle_full_vcard(GtkWidget *button, gpointer data) +{ + EABVCardControl *vcard_control = data; + char *label; + + if (!vcard_control->card_list) + return; + + if (vcard_control->render_mode == EAB_CONTACT_DISPLAY_RENDER_NORMAL) { + vcard_control->render_mode = EAB_CONTACT_DISPLAY_RENDER_COMPACT; + label = _("Show Full VCard"); + } + else { + vcard_control->render_mode = EAB_CONTACT_DISPLAY_RENDER_NORMAL; + label = _("Show Compact VCard"); + } + + gtk_button_set_label (GTK_BUTTON (button), label); + eab_contact_display_render (vcard_control->display, E_CONTACT (vcard_control->card_list->data), + vcard_control->render_mode); +} + +static void +free_struct (gpointer data, GObject *where_object_was) +{ + EABVCardControl *vcard_control = data; + e_free_object_list (vcard_control->card_list); + g_free (vcard_control); +} + +BonoboControl * +eab_vcard_control_new (void) +{ + BonoboControl *control; + BonoboPersistStream *stream; + GtkWidget *display; + GtkWidget *button1, *button2; + GtkWidget *label; + GtkWidget *table; + + EABVCardControl *vcard_control = g_new (EABVCardControl, 1); + + printf ("inside eab_vcard_control_new\n"); + + vcard_control->card_list = NULL; + vcard_control->display = NULL; + vcard_control->label = NULL; + + vcard_control->render_mode = EAB_CONTACT_DISPLAY_RENDER_COMPACT; + + /* Create the control. */ + + display = eab_contact_display_new (); + gtk_widget_show (display); + vcard_control->display = EAB_CONTACT_DISPLAY (display); + + /* This is intentionally not shown. */ + label = gtk_label_new (""); + vcard_control->label = label; + + button1 = gtk_button_new_with_label(_("Show Full VCard")); + g_signal_connect (button1, "clicked", + G_CALLBACK (toggle_full_vcard), vcard_control); + gtk_widget_show (button1); + + button2 = gtk_button_new_with_label(_("Save in addressbook")); + g_signal_connect (button2, "clicked", + G_CALLBACK (save_in_addressbook), vcard_control); + gtk_widget_show (button2); + + table = gtk_table_new (6, 6, FALSE); + gtk_table_attach (GTK_TABLE (table), display, 0, 6, 3, 6, GTK_EXPAND | GTK_FILL, GTK_EXPAND | GTK_FILL, 0, 0); + gtk_table_attach (GTK_TABLE (table), label, 0, 3, 2, 3, GTK_FILL, 0, 0, 0); + gtk_table_attach (GTK_TABLE (table), button1, 0, 1, 1, 2, 0, 0, 0, 0); + gtk_table_attach (GTK_TABLE (table), button2, 1, 2, 1, 2, 0, 0, 0, 0); + gtk_widget_show (table); + + control = bonobo_control_new (table); + + g_object_weak_ref (G_OBJECT (control), free_struct, vcard_control); + + stream = bonobo_persist_stream_new (pstream_load, pstream_save, + pstream_get_content_types, + VCARD_CONTROL_ID, + vcard_control); + + if (stream == NULL) { + bonobo_object_unref (BONOBO_OBJECT (control)); + return NULL; + } + + bonobo_object_add_interface (BONOBO_OBJECT (control), + BONOBO_OBJECT (stream)); + + return control; +} diff --git a/addressbook/gui/widgets/eab-vcard-control.h b/addressbook/gui/widgets/eab-vcard-control.h new file mode 100644 index 0000000000..5f6643c1ca --- /dev/null +++ b/addressbook/gui/widgets/eab-vcard-control.h @@ -0,0 +1,8 @@ +#ifndef __EAB_VCARD_CONTROL_H__ +#define __EAB_VCARD_CONTROL_H__ + +#include + +BonoboControl *eab_vcard_control_new (void); + +#endif /* __EAB_VCARD_CONTROL_H__ */ diff --git a/addressbook/gui/widgets/test-minicard-label.c b/addressbook/gui/widgets/test-minicard-label.c deleted file mode 100644 index c109497628..0000000000 --- a/addressbook/gui/widgets/test-minicard-label.c +++ /dev/null @@ -1,129 +0,0 @@ -/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ -/* test-minicard-label.c - * - * Copyright (C) 2000 Ximian, Inc. - * Author: Chris Lahey - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of version 2 of the GNU General Public - * License as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public - * License along with this program; if not, write to the - * Free Software Foundation, Inc., 59 Temple Place - Suite 330, - * Boston, MA 02111-1307, USA. - */ - -#include "config.h" - -#include -#include -#include -#include -#include -#include "e-minicard-label.h" - -/* This is a horrible thing to do, but it is just a test. */ -GnomeCanvasItem *label; -GnomeCanvasItem *rect; - -static void destroy_callback(gpointer data, GObject *where_object_was) -{ - exit(0); -} - -static void allocate_callback(GtkWidget *canvas, GtkAllocation *allocation, gpointer data) -{ - gnome_canvas_set_scroll_region(GNOME_CANVAS( canvas ), 0, 0, allocation->width, allocation->height ); - gnome_canvas_item_set( label, - "width", (double) allocation->width, - "height", (double) allocation->height, - NULL ); - gnome_canvas_item_set( rect, - "x2", (double) allocation->width, - "y2", (double) allocation->height, - NULL ); -} - -#if 0 -static void about_callback( GtkWidget *widget, gpointer data ) -{ - - const gchar *authors[] = - { - "Christopher James Lahey ", - NULL - }; - - GtkWidget *about = - gnome_about_new ( _( "Minicard Label Test" ), VERSION, - _( "Copyright (C) 2000, Ximian, Inc." ), - authors, - _( "This should test the minicard label canvas item" ), - NULL); - gtk_widget_show (about); -} -#endif - -static void button_press_callback( GtkWidget *widget, gpointer data ) -{ - gnome_canvas_item_grab_focus( label ); -} - -int main( int argc, char *argv[] ) -{ - GtkWidget *app; - GtkWidget *canvas; - - /* bindtextdomain (PACKAGE, GNOMELOCALEDIR); - textdomain (PACKAGE);*/ - - gnome_init( "Minicard Label Test", VERSION, argc, argv); - app = gnome_app_new("Minicard Label Test", NULL); - - canvas = e_canvas_new(); - rect = gnome_canvas_item_new( gnome_canvas_root( GNOME_CANVAS( canvas ) ), - gnome_canvas_rect_get_type(), - "x1", (double) 0, - "y1", (double) 0, - "x2", (double) 100, - "y2", (double) 100, - "fill_color", "white", - NULL ); - label = e_minicard_label_new(gnome_canvas_root( GNOME_CANVAS( canvas ) )); - gnome_canvas_item_set( label, - "width", (double) 100, - "height", (double) 100, - "fieldname", "Full Name:", - "field", "Christopher James Lahey", - NULL ); - gnome_canvas_set_scroll_region ( GNOME_CANVAS( canvas ), - 0, 0, - 100, 100 ); - - gnome_app_set_contents( GNOME_APP( app ), canvas ); - - - /* Connect the signals */ - g_object_weak_ref (app, destroy_callback, app); - - g_signal_connect( canvas , "size_allocate", - G_CALLBACK ( allocate_callback ), - ( gpointer ) app ); - - g_signal_connect( canvas , "button_press_event", - G_CALLBACK ( button_press_callback ), - ( gpointer ) app ); - - gtk_widget_show_all( app ); - - gtk_main(); - - /* Not reached. */ - return 0; -} diff --git a/addressbook/gui/widgets/test-minicard-view.c b/addressbook/gui/widgets/test-minicard-view.c deleted file mode 100644 index 14ede54208..0000000000 --- a/addressbook/gui/widgets/test-minicard-view.c +++ /dev/null @@ -1,203 +0,0 @@ -/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ -/* test-reflow.c - * - * Copyright (C) 2000 Ximian, Inc. - * Author: Chris Lahey - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of version 2 of the GNU General Public - * License as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public - * License along with this program; if not, write to the - * Free Software Foundation, Inc., 59 Temple Place - Suite 330, - * Boston, MA 02111-1307, USA. - */ - -#include "config.h" - -#include -#include -#include "e-minicard-view.h" - -/* This is a horrible thing to do, but it is just a test. */ -GnomeCanvasItem *reflow; -GnomeCanvasItem *rect; -GtkAllocation last_alloc; - -CORBA_Environment ev; -CORBA_ORB orb; - -static void -init_bonobo (int argc, char **argv) -{ - - gnome_CORBA_init_with_popt_table ( - "Reflow Test", VERSION, - &argc, argv, NULL, 0, NULL, GNORBA_INIT_SERVER_FUNC, &ev); - - orb = gnome_CORBA_ORB (); - - if (bonobo_init (orb, NULL, NULL) == FALSE) - g_error (_("Could not initialize Bonobo")); - -} - -static void destroy_callback(gpointer data, GObject *where_object_was) -{ - exit(0); -} - -static void allocate_callback(GtkWidget *canvas, GtkAllocation *allocation, gpointer data) -{ - double width; - last_alloc = *allocation; - gnome_canvas_item_set( reflow, - "height", (double) allocation->height, - NULL ); - gnome_canvas_item_set( reflow, - "minimum_width", (double) allocation->width, - NULL ); - g_object_get(reflow, - "width", &width, - NULL); - width = MAX(width, allocation->width); - gnome_canvas_set_scroll_region(GNOME_CANVAS( canvas ), 0, 0, width, allocation->height ); - gnome_canvas_item_set( rect, - "x2", (double) width, - "y2", (double) allocation->height, - NULL ); -} - -static void resize(GnomeCanvas *canvas, gpointer data) -{ - double width; - g_object_get(reflow, - "width", &width, - NULL); - width = MAX(width, last_alloc.width); - gnome_canvas_set_scroll_region(canvas , 0, 0, width, last_alloc.height ); - gnome_canvas_item_set( rect, - "x2", (double) width, - "y2", (double) last_alloc.height, - NULL ); -} - -#if 0 -static void about_callback( GtkWidget *widget, gpointer data ) -{ - - const gchar *authors[] = - { - "Christopher James Lahey ", - NULL - }; - - GtkWidget *about = - gnome_about_new ( _( "Reflow Test" ), VERSION, - _( "Copyright (C) 2000, Ximian, Inc." ), - authors, - _( "This should test the reflow canvas item" ), - NULL); - gtk_widget_show (about); -} -#endif - -static void -book_open_cb (EBook *book, EBookStatus status, gpointer closure) -{ - if (status == E_BOOK_STATUS_SUCCESS) - gnome_canvas_item_set(reflow, - "book", book, - NULL); -} - -static gboolean -ebook_create (gpointer data) -{ - EBook *book; - - book = e_book_new (); - - if (!book) { - printf ("%s: %s(): Couldn't create EBook, bailing.\n", - __FILE__, - G_GNUC_FUNCTION); - return FALSE; - } - - - e_book_load_uri (book, "file:/tmp/test.db", book_open_cb, NULL); - - return FALSE; -} - -int main( int argc, char *argv[] ) -{ - GtkWidget *app; - GtkWidget *canvas; - GtkWidget *vbox; - GtkWidget *scrollbar; - - /* bindtextdomain (PACKAGE, GNOMELOCALEDIR); - textdomain (PACKAGE);*/ - - CORBA_exception_init (&ev); - init_bonobo (argc, argv); - - app = gnome_app_new("Reflow Test", NULL); - - vbox = gtk_vbox_new(FALSE, 0); - - canvas = e_canvas_new(); - rect = gnome_canvas_item_new( gnome_canvas_root( GNOME_CANVAS( canvas ) ), - gnome_canvas_rect_get_type(), - "x1", (double) 0, - "y1", (double) 0, - "x2", (double) 100, - "y2", (double) 100, - "fill_color", "white", - NULL ); - reflow = gnome_canvas_item_new( gnome_canvas_root( GNOME_CANVAS( canvas ) ), - e_minicard_view_get_type(), - "height", (double) 100, - "minimum_width", (double) 100, - NULL ); - g_signal_connect( canvas, "reflow", - G_CALLBACK ( resize ), - ( gpointer ) app); - - gnome_canvas_set_scroll_region ( GNOME_CANVAS( canvas ), - 0, 0, - 100, 100 ); - - gtk_box_pack_start(GTK_BOX(vbox), canvas, TRUE, TRUE, 0); - - scrollbar = gtk_hscrollbar_new(gtk_layout_get_hadjustment(GTK_LAYOUT(canvas))); - - gtk_box_pack_start(GTK_BOX(vbox), scrollbar, FALSE, FALSE, 0); - - gnome_app_set_contents( GNOME_APP( app ), vbox ); - - /* Connect the signals */ - g_object_weak_ref (app, destroy_callback, app); - - g_signal_connect( canvas, "size_allocate", - G_CALLBACK ( allocate_callback ), - ( gpointer ) app ); - - gtk_widget_show_all( app ); - gdk_window_set_back_pixmap( GTK_LAYOUT(canvas)->bin_window, NULL, FALSE); - - g_idle_add (ebook_create, NULL); - - bonobo_main (); - - /* Not reached. */ - return 0; -} diff --git a/addressbook/gui/widgets/test-minicard.c b/addressbook/gui/widgets/test-minicard.c deleted file mode 100644 index 822362d972..0000000000 --- a/addressbook/gui/widgets/test-minicard.c +++ /dev/null @@ -1,120 +0,0 @@ -/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ -/* test-minicard.c - * - * Copyright (C) 2000 Ximian, Inc. - * Author: Chris Lahey - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of version 2 of the GNU General Public - * License as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public - * License along with this program; if not, write to the - * Free Software Foundation, Inc., 59 Temple Place - Suite 330, - * Boston, MA 02111-1307, USA. - * - */ - -#include "config.h" - -#include -#include -#include -#include - -#include "e-minicard.h" - -/* This is a horrible thing to do, but it is just a test. */ -GnomeCanvasItem *card; -GnomeCanvasItem *rect; - -static void destroy_callback(gpointer data, GObject *where_object_was) -{ - exit(0); -} - -static void allocate_callback(GtkWidget *canvas, GtkAllocation *allocation, gpointer data) -{ - gnome_canvas_set_scroll_region(GNOME_CANVAS( canvas ), 0, 0, allocation->width, allocation->height ); - gnome_canvas_item_set( card, - "width", (double) allocation->width, - NULL ); - gnome_canvas_item_set( rect, - "x2", (double) allocation->width, - "y2", (double) allocation->height, - NULL ); -} - -#if 0 -static void about_callback( GtkWidget *widget, gpointer data ) -{ - - const gchar *authors[] = - { - "Christopher James Lahey ", - NULL - }; - - GtkWidget *about = - gnome_about_new ( _( "Minicard Test" ), VERSION, - _( "Copyright (C) 2000, Ximian, Inc." ), - authors, - _( "This should test the minicard canvas item" ), - NULL); - gtk_widget_show (about); -} -#endif - -int main( int argc, char *argv[] ) -{ - GtkWidget *app; - GtkWidget *canvas; - int i; - - /* bindtextdomain (PACKAGE, GNOMELOCALEDIR); - textdomain (PACKAGE);*/ - - gnome_init( "Minicard Test", VERSION, argc, argv); - app = gnome_app_new("Minicard Test", NULL); - - canvas = gnome_canvas_new(); - rect = gnome_canvas_item_new( gnome_canvas_root( GNOME_CANVAS( canvas ) ), - gnome_canvas_rect_get_type(), - "x1", (double) 0, - "y1", (double) 0, - "x2", (double) 100, - "y2", (double) 100, - "fill_color", "white", - NULL ); - for ( i = 0; i < 1; i++ ) - { - card = gnome_canvas_item_new( gnome_canvas_root( GNOME_CANVAS( canvas ) ), - e_minicard_get_type(), - "width", (double) 100, - NULL ); - } - gnome_canvas_set_scroll_region ( GNOME_CANVAS( canvas ), - 0, 0, - 100, 100 ); - - gnome_app_set_contents( GNOME_APP( app ), canvas ); - - /* Connect the signals */ - g_object_weak_ref (app, destroy_callback, app); - - g_signal_connect( canvas, "size_allocate", - G_CALLBACK( allocate_callback ), - ( gpointer ) app ); - - gtk_widget_show_all( app ); - - gtk_main(); - - /* Not reached. */ - return 0; -} diff --git a/addressbook/printing/Makefile.am b/addressbook/printing/Makefile.am index b28d841ec2..f9e9661890 100644 --- a/addressbook/printing/Makefile.am +++ b/addressbook/printing/Makefile.am @@ -38,16 +38,18 @@ contact_print_test_SOURCES = \ test-print.c contact_print_test_LDADD = \ - $(top_builddir)/addressbook/backend/ebook/libebook.la \ libecontactprint.la \ + $(top_builddir)/addressbook/util/libeabutil.la \ + $(top_builddir)/addressbook/backend/ebook/libebook.la \ $(EVOLUTION_ADDRESSBOOK_LIBS) contact_print_style_editor_test_SOURCES = \ test-contact-print-style-editor.c contact_print_style_editor_test_LDADD = \ - $(top_builddir)/addressbook/backend/ebook/libebook.la \ libecontactprint.la \ + $(top_builddir)/addressbook/util/libeabutil.la \ + $(top_builddir)/addressbook/backend/ebook/libebook.la \ $(EVOLUTION_ADDRESSBOOK_LIBS) diff --git a/addressbook/printing/e-contact-print-envelope.c b/addressbook/printing/e-contact-print-envelope.c index 93916744da..c7bd68163f 100644 --- a/addressbook/printing/e-contact-print-envelope.c +++ b/addressbook/printing/e-contact-print-envelope.c @@ -29,8 +29,6 @@ #include #include #include -#include "addressbook/backend/ebook/e-card.h" -#include "addressbook/backend/ebook/e-card-simple.h" #define ENVELOPE_HEIGHT (72.0 * 4.0) #define ENVELOPE_WIDTH (72.0 * 9.5) @@ -131,9 +129,8 @@ e_contact_print_envelope_close(GnomeDialog *dialog, gpointer data) } static void -ecpe_print(GnomePrintContext *pc, ECard *ecard, gboolean as_return) +ecpe_print(GnomePrintContext *pc, EContact *contact, gboolean as_return) { - ECardSimple *card = e_card_simple_new(ecard); char *address; EcpeLine *linelist; double x; @@ -144,7 +141,7 @@ ecpe_print(GnomePrintContext *pc, ECard *ecard, gboolean as_return) gnome_print_rotate(pc, 90); gnome_print_translate(pc, 72.0 * 11.0 - ENVELOPE_WIDTH, -72.0 * 8.5 + (72.0 * 8.5 - ENVELOPE_HEIGHT) / 2); - address = e_card_simple_get(card, E_CARD_SIMPLE_FIELD_ADDRESS_BUSINESS); + address = e_contact_get(contact, E_CONTACT_ADDRESS_LABEL_WORK); linelist = ecpe_break(address); if (as_return) font = gnome_font_find ("Sans", 9); @@ -166,8 +163,6 @@ ecpe_print(GnomePrintContext *pc, ECard *ecard, gboolean as_return) gnome_print_showpage(pc); gnome_print_context_close(pc); - - g_object_unref(card); } static void @@ -176,10 +171,10 @@ e_contact_print_envelope_button(GnomeDialog *dialog, gint button, gpointer data) GnomePrintJob *master; GnomePrintContext *pc; GnomePrintConfig *config; - ECard *card = NULL; + EContact *contact = NULL; GtkWidget *preview; - card = g_object_get_data(G_OBJECT(dialog), "card"); + contact = g_object_get_data(G_OBJECT(dialog), "contact"); switch( button ) { case GNOME_PRINT_DIALOG_RESPONSE_PRINT: @@ -187,7 +182,7 @@ e_contact_print_envelope_button(GnomeDialog *dialog, gint button, gpointer data) master = gnome_print_job_new (config); pc = gnome_print_job_get_context( master ); - ecpe_print(pc, card, FALSE); + ecpe_print(pc, contact, FALSE); gnome_print_job_print(master); gnome_dialog_close(dialog); @@ -197,27 +192,27 @@ e_contact_print_envelope_button(GnomeDialog *dialog, gint button, gpointer data) master = gnome_print_job_new (config); pc = gnome_print_job_get_context( master ); - ecpe_print(pc, card, FALSE); + ecpe_print(pc, contact, FALSE); preview = GTK_WIDGET(gnome_print_job_preview_new(master, "Print Preview")); gtk_widget_show_all(preview); break; case GNOME_PRINT_DIALOG_RESPONSE_CANCEL: - g_object_unref(card); + g_object_unref(contact); gnome_dialog_close(dialog); break; } } GtkWidget * -e_contact_print_envelope_dialog_new(ECard *card) +e_contact_print_envelope_dialog_new(EContact *contact) { GtkWidget *dialog; dialog = gnome_print_dialog_new(NULL, _("Print envelope"), GNOME_PRINT_DIALOG_COPIES); - card = e_card_duplicate(card); - g_object_set_data(G_OBJECT(dialog), "card", card); + contact = e_contact_duplicate(contact); + g_object_set_data(G_OBJECT(dialog), "contact", contact); g_signal_connect(dialog, "clicked", G_CALLBACK(e_contact_print_envelope_button), NULL); g_signal_connect(dialog, @@ -230,15 +225,15 @@ GtkWidget * e_contact_print_envelope_list_dialog_new(GList *list) { GtkWidget *dialog; - ECard *card; + EContact *contact; if (list == NULL) return NULL; dialog = gnome_print_dialog_new(NULL, _("Print envelope"), GNOME_PRINT_DIALOG_COPIES); - card = e_card_duplicate(list->data); - g_object_set_data(G_OBJECT(dialog), "card", card); + contact = e_contact_duplicate(list->data); + g_object_set_data(G_OBJECT(dialog), "contact", contact); g_signal_connect(dialog, "clicked", G_CALLBACK(e_contact_print_envelope_button), NULL); g_signal_connect(dialog, diff --git a/addressbook/printing/e-contact-print-envelope.h b/addressbook/printing/e-contact-print-envelope.h index 4302c4c5d7..d9e24b1794 100644 --- a/addressbook/printing/e-contact-print-envelope.h +++ b/addressbook/printing/e-contact-print-envelope.h @@ -22,11 +22,11 @@ #ifndef E_CONTACT_PRINT_ENVELOPE_H #define E_CONTACT_PRINT_ENVELOPE_H -#include +#include #include #include "e-contact-print-types.h" -GtkWidget *e_contact_print_envelope_dialog_new(ECard *card); +GtkWidget *e_contact_print_envelope_dialog_new(EContact *contact); GtkWidget *e_contact_print_envelope_list_dialog_new(GList *list); #endif /* E_CONTACT_PRINT_ENVELOPE_H */ diff --git a/addressbook/printing/e-contact-print.c b/addressbook/printing/e-contact-print.c index 81698ddb10..0aa2e67900 100644 --- a/addressbook/printing/e-contact-print.c +++ b/addressbook/printing/e-contact-print.c @@ -38,10 +38,9 @@ #include #include #include -#include -#include -#include -#include +#include +#include +#include #define SCALE 5 #define HYPHEN_PIXELS 20 @@ -70,7 +69,7 @@ struct _EContactPrintContext EBook *book; gchar *query; - GList *cards; + GList *contacts; }; static gint @@ -274,7 +273,7 @@ e_contact_output(GnomePrintContext *pc, GnomeFont *font, double x, double y, dou } static gdouble -e_contact_text_height(GnomePrintContext *pc, GnomeFont *font, double width, gchar *text) +e_contact_text_height(GnomePrintContext *pc, GnomeFont *font, double width, const gchar *text) { int line_count = e_contact_divide_text(pc, font, width, text, NULL); return line_count * (gnome_font_get_ascender(font) + gnome_font_get_descender(font)) + @@ -402,12 +401,12 @@ e_contact_start_new_page(EContactPrintContext *ctxt) } static double -e_contact_get_card_size(ECardSimple *simple, EContactPrintContext *ctxt) +e_contact_get_contact_size(EContact *contact, EContactPrintContext *ctxt) { gdouble height = 0; gdouble page_width = 72 * (ctxt->style->page_width - ctxt->style->left_margin - ctxt->style->right_margin); gdouble column_width; - char *file_as; + const char *file_as; gint field; if ( ctxt->style->letter_tabs ) page_width -= e_contact_get_letter_tab_width(ctxt); @@ -417,22 +416,20 @@ e_contact_get_card_size(ECardSimple *simple, EContactPrintContext *ctxt) height += gnome_font_get_size (ctxt->style->headings_font) * .2; - g_object_get(simple->card, - "file_as", &file_as, - NULL); + file_as = e_contact_get_const (contact, E_CONTACT_FILE_AS); + height += e_contact_text_height(ctxt->pc, ctxt->style->headings_font, column_width - 4, file_as); - g_free (file_as); height += gnome_font_get_size (ctxt->style->headings_font) * .2; height += gnome_font_get_size (ctxt->style->headings_font) * .2; - for(field = E_CARD_SIMPLE_FIELD_FULL_NAME; field != E_CARD_SIMPLE_FIELD_LAST_SIMPLE_STRING; field++) { + for(field = E_CONTACT_FILE_AS; field != E_CONTACT_LAST_SIMPLE_STRING; field++) { char *string; - string = e_card_simple_get(simple, field); + string = e_contact_get(contact, field); if (string && *string) { double xoff = 0; - xoff += gnome_font_get_width_utf8(ctxt->style->body_font, e_card_simple_get_name(simple, field)); + xoff += gnome_font_get_width_utf8(ctxt->style->body_font, e_contact_pretty_name (field)); xoff += gnome_font_get_width_utf8(ctxt->style->body_font, ": "); height += e_contact_text_height(ctxt->pc, ctxt->style->body_font, column_width - xoff, string); height += .2 * gnome_font_get_size (ctxt->style->body_font); @@ -447,7 +444,7 @@ e_contact_get_card_size(ECardSimple *simple, EContactPrintContext *ctxt) static void -e_contact_print_card (ECardSimple *simple, EContactPrintContext *ctxt) +e_contact_print_contact (EContact *contact, EContactPrintContext *ctxt) { gdouble page_width = 72 * (ctxt->style->page_width - ctxt->style->left_margin - ctxt->style->right_margin); gdouble column_width; @@ -463,9 +460,7 @@ e_contact_print_card (ECardSimple *simple, EContactPrintContext *ctxt) ctxt->y -= gnome_font_get_size (ctxt->style->headings_font) * .2; ctxt->y -= gnome_font_get_size (ctxt->style->headings_font) * .2; - g_object_get(simple->card, - "file_as", &file_as, - NULL); + file_as = e_contact_get (contact, E_CONTACT_FILE_AS); if (ctxt->style->print_using_grey) e_contact_rectangle(ctxt->pc, ctxt->x, ctxt->y + gnome_font_get_size (ctxt->style->headings_font) * .3, ctxt->x + column_width, ctxt->y - e_contact_text_height(ctxt->pc, ctxt->style->headings_font, column_width - 4, file_as) - gnome_font_get_size (ctxt->style->headings_font) * .3, .85, .85, .85); e_contact_output(ctxt->pc, ctxt->style->headings_font, ctxt->x + 2, ctxt->y, column_width - 4, file_as); @@ -475,14 +470,14 @@ e_contact_print_card (ECardSimple *simple, EContactPrintContext *ctxt) ctxt->y -= gnome_font_get_size (ctxt->style->headings_font) * .2; ctxt->y -= gnome_font_get_size (ctxt->style->headings_font) * .2; - for(field = E_CARD_SIMPLE_FIELD_FULL_NAME; field != E_CARD_SIMPLE_FIELD_LAST_SIMPLE_STRING; field++) { + for(field = E_CONTACT_FILE_AS; field != E_CONTACT_LAST_SIMPLE_STRING; field++) { char *string; - string = e_card_simple_get(simple, field); + string = e_contact_get(contact, field); if (string && !strncmp (string, "pc, ctxt->style->body_font, ctxt->x + xoff, ctxt->y, -1, e_card_simple_get_name(simple, field)); - xoff += gnome_font_get_width_utf8(ctxt->style->body_font, e_card_simple_get_name(simple, field)); + e_contact_output(ctxt->pc, ctxt->style->body_font, ctxt->x + xoff, ctxt->y, -1, e_contact_pretty_name (field)); + xoff += gnome_font_get_width_utf8(ctxt->style->body_font, e_contact_pretty_name (field)); e_contact_output(ctxt->pc, ctxt->style->body_font, ctxt->x + xoff, ctxt->y, -1, ": "); xoff += gnome_font_get_width_utf8(ctxt->style->body_font, ": "); e_contact_output(ctxt->pc, ctxt->style->body_font, ctxt->x + xoff, ctxt->y, column_width - xoff, string); @@ -526,7 +521,7 @@ e_contact_start_new_column (EContactPrintContext *ctxt) static void complete_sequence(EBookView *book_view, EBookViewStatus status, EContactPrintContext *ctxt) { - GList *cards = ctxt->cards; + GList *contacts = ctxt->contacts; gdouble page_width = 72 * (ctxt->style->page_width - ctxt->style->left_margin - ctxt->style->right_margin); @@ -541,15 +536,13 @@ complete_sequence(EBookView *book_view, EBookViewStatus status, EContactPrintCon gnome_print_beginpage (ctxt->pc, NULL); - for(; cards; cards = cards->next) { - ECard *card = cards->data; - ECardSimple *simple = e_card_simple_new(card); + for(; contacts; contacts = contacts->next) { + EContact *contact = contacts->data; guchar *file_as; gchar *letter_str = NULL; - g_object_get(card, - "file_as", &file_as, - NULL); + file_as = e_contact_get (contact, E_CONTACT_FILE_AS); + if (file_as != NULL) { letter_str = g_strndup (file_as, g_utf8_next_char (file_as) - (gchar *) file_as); } @@ -559,13 +552,13 @@ complete_sequence(EBookView *book_view, EBookViewStatus status, EContactPrintCon if (ctxt->style->sections_start_new_page && ! ctxt->first_contact) { e_contact_start_new_page(ctxt); } - else if ((!ctxt->first_contact) && (ctxt->y - e_contact_get_letter_heading_height(ctxt) - e_contact_get_card_size(simple, ctxt) < ctxt->style->bottom_margin * 72)) + else if ((!ctxt->first_contact) && (ctxt->y - e_contact_get_letter_heading_height(ctxt) - e_contact_get_contact_size(contact, ctxt) < ctxt->style->bottom_margin * 72)) e_contact_start_new_column(ctxt); if ( ctxt->style->letter_headings ) e_contact_print_letter_heading(ctxt, ctxt->character); ctxt->first_section = FALSE; } - else if ( (!ctxt->first_contact) && (ctxt->y - e_contact_get_card_size(simple, ctxt) < ctxt->style->bottom_margin * 72)) { + else if ( (!ctxt->first_contact) && (ctxt->y - e_contact_get_contact_size(contact, ctxt) < ctxt->style->bottom_margin * 72)) { e_contact_start_new_column(ctxt); if ( ctxt->style->letter_headings ) e_contact_print_letter_heading(ctxt, ctxt->character); @@ -574,9 +567,8 @@ complete_sequence(EBookView *book_view, EBookViewStatus status, EContactPrintCon ctxt->last_char_on_page = toupper(*file_as); if ( ctxt->last_char_on_page < ctxt->first_char_on_page ) ctxt->first_char_on_page = ctxt->last_char_on_page; - e_contact_print_card(simple, ctxt); + e_contact_print_contact(contact, ctxt); ctxt->first_contact = FALSE; - g_object_unref(simple); } ctxt->last_char_on_page = 'Z'; if ( ctxt->style->letter_tabs ) @@ -598,8 +590,8 @@ complete_sequence(EBookView *book_view, EBookViewStatus status, EContactPrintCon if (ctxt->book) g_object_unref(ctxt->book); g_free(ctxt->query); - g_list_foreach(ctxt->cards, (GFunc) g_object_unref, NULL); - g_list_free(ctxt->cards); + g_list_foreach(ctxt->contacts, (GFunc) g_object_unref, NULL); + g_list_free(ctxt->contacts); g_object_unref(ctxt->style->headings_font); g_object_unref(ctxt->style->body_font); g_object_unref(ctxt->style->header_font); @@ -611,41 +603,32 @@ complete_sequence(EBookView *book_view, EBookViewStatus status, EContactPrintCon } static int -card_compare (ECard *card1, ECard *card2) { - int cmp = 0; - - if (card1 && card2) { - char *file_as1, *file_as2; - - g_object_get(card1, - "file_as", &file_as1, - NULL); - g_object_get(card2, - "file_as", &file_as2, - NULL); - if (file_as1 && file_as2) - cmp = g_utf8_collate(file_as1, file_as2); - else if (file_as1) - cmp = -1; - else if (file_as2) - cmp = 1; - else - cmp = strcmp(e_card_get_id(card1), e_card_get_id(card2)); - - g_free (file_as2); - g_free (file_as1); +contact_compare (EContact *contact1, EContact *contact2) +{ + if (contact1 && contact2) { + const char *file_as1, *file_as2; + file_as1 = e_contact_get_const (contact1, E_CONTACT_FILE_AS); + file_as2 = e_contact_get_const (contact2, E_CONTACT_FILE_AS); + if (file_as1 && file_as2) + return g_utf8_collate(file_as1, file_as2); + if (file_as1) + return -1; + if (file_as2) + return 1; + return strcmp(e_contact_get_const(contact1, E_CONTACT_UID), e_contact_get_const(contact2, E_CONTACT_UID)); + } else { + return 0; } - return cmp; } static void -create_card(EBookView *book_view, const GList *cards, EContactPrintContext *ctxt) +create_contact(EBookView *book_view, const GList *contacts, EContactPrintContext *ctxt) { - for(; cards; cards = cards->next) { - ECard *card = cards->data; - g_object_ref(card); - ctxt->cards = g_list_insert_sorted(ctxt->cards, card, (GCompareFunc) card_compare); + for(; contacts; contacts = contacts->next) { + EContact *contact = contacts->data; + g_object_ref(contact); + ctxt->contacts = g_list_insert_sorted(ctxt->contacts, contact, (GCompareFunc) contact_compare); } } @@ -655,169 +638,31 @@ book_view_loaded (EBook *book, EBookStatus status, EBookView *book_view, EContac g_object_ref(book_view); g_signal_connect(book_view, - "card_added", - G_CALLBACK(create_card), + "contacts_added", + G_CALLBACK(create_contact), ctxt); g_signal_connect(book_view, "sequence_complete", G_CALLBACK(complete_sequence), ctxt); -} - -static void -e_contact_do_print_cards (EBook *book, char *query, EContactPrintContext *ctxt) -{ - e_book_get_book_view(book, query, (EBookBookViewCallback) book_view_loaded, ctxt); -} - -#if 0 -static double -e_contact_get_phone_list_size(ECardSimple *simple, EContactPrintContext *ctxt) -{ - double height = 0; - int field; - - height += gnome_font_get_size (ctxt->style->headings_font) * .2; - - height += gnome_font_get_size (ctxt->style->headings_font) * .2; - - for(field = E_CARD_SIMPLE_FIELD_FULL_NAME; field != E_CARD_SIMPLE_FIELD_LAST_SIMPLE_STRING; field++) { - char *string; - string = e_card_simple_get(simple, field); - if (string && *string) { - if ( 1 ) /* field is a phone field. */ { - gchar *field = string; - height += e_contact_text_height(ctxt->pc, ctxt->style->body_font, 100, field); - height += .2 * gnome_font_get_size (ctxt->style->body_font); - } - } - g_free(string); - } - height += gnome_font_get_size (ctxt->style->headings_font) * .4; - return height; -} - - -static void -e_contact_print_phone_list (ECard *card, EContactPrintContext *ctxt) -{ - gdouble page_width = 72 * (ctxt->style->page_width - ctxt->style->left_margin - ctxt->style->right_margin); - gdouble column_width; - double xoff, dotwidth; - int dotcount; - char *dots; - int i; - char *file_as; - if ( ctxt->style->letter_tabs ) - page_width -= e_contact_get_letter_tab_width(ctxt); - column_width = (page_width + 18) / ctxt->style->num_columns - 18; - - gnome_print_gsave(ctxt->pc); - - ctxt->y -= gnome_font_get_size (ctxt->style->headings_font) * .2; - ctxt->y -= gnome_font_get_size (ctxt->style->headings_font) * .2; - e_contact_output(ctxt->pc, ctxt->style->body_font, ctxt->x, ctxt->y, -1, e_card_get_string_fileas(card)); - - xoff = column_width - 9 * gnome_font_get_size (ctxt->style->body_font); - dotwidth = xoff - - gnome_font_get_width_utf8(ctxt->style->body_font, e_card_get_string_fileas(card)) - - gnome_font_get_width_utf8(ctxt->style->body_font, " "); - dotcount = dotwidth / gnome_font_get_width(ctxt->style->body_font, '.'); - dots = g_new(gchar, dotcount + 1); - for (i = 0; i < dotcount; i++) - dots[i] = '.'; - dots[dotcount] = 0; - e_contact_output(ctxt->pc, ctxt->style->body_font, ctxt->x + xoff - dotcount * gnome_font_get_width(ctxt->style->body_font, '.'), ctxt->y, -1, dots); - g_free(dots); - - for(; shown_fields; shown_fields = g_list_next(shown_fields)) { - if ( 1 ) /* field is a phone field. */ { - gchar *field = e_card_get_string(card, shown_fields->data); - e_contact_output(ctxt->pc, ctxt->style->body_font, ctxt->x + xoff, ctxt->y, -1, shown_fields->data); - e_contact_output(ctxt->pc, ctxt->style->body_font, - ctxt->x + column_width - gnome_font_get_width_utf8(ctxt->style->body_font, - field), - ctxt->y, - -1, - field); - ctxt->y -= e_contact_text_height(ctxt->pc, ctxt->style->body_font, 100, field); - ctxt->y -= .2 * gnome_font_get_size (ctxt->style->body_font); - } - } - ctxt->y -= gnome_font_get_size (ctxt->style->headings_font) * .4; - gnome_print_grestore(ctxt->pc); + e_book_view_start (book_view); } static void -e_contact_do_print_phone_list (EBook *book, char *query, EContactPrintContext *ctxt) +e_contact_do_print_contacts (EBook *book, char *query, EContactPrintContext *ctxt) { - ECard *card = NULL; - int i; - gdouble page_width = 72 * (ctxt->style->page_width - ctxt->style->left_margin - ctxt->style->right_margin); - gdouble column_width; - ctxt->first_contact = TRUE; - ctxt->character = NULL; - ctxt->y = (ctxt->style->page_height - ctxt->style->top_margin) * 72; - ctxt->x = (ctxt->style->left_margin) * 72; - if ( ctxt->style->letter_tabs ) - page_width -= e_contact_get_letter_tab_width(ctxt); - - ctxt->first_char_on_page = 'A' - 1; - - column_width = (page_width + 18) / ctxt->style->num_columns - 18; - /* - for(card = e_book_get_first(book); card; card = e_book_get_next(book)) { - */ - for (i=0; i < 30; i++) { - guchar *file_as = e_card_get_string_fileas(card); - if ( file_as && (!character || *character != tolower(*file_as)) ) { - if (ctxt->style->sections_start_new_page && ! first_contact) { - e_contact_start_new_page(ctxt); - } - else if ((!first_contact) && (ctxt->y - e_contact_get_letter_heading_height(ctxt) - e_contact_get_phone_list_size(card, ctxt, shown_fields) < ctxt->style->bottom_margin * 72)) - e_contact_start_new_column(ctxt); - if (!character) - character = g_strdup(" "); - *character = tolower(*file_as); - if ( ctxt->style->letter_headings ) - e_contact_print_letter_heading(ctxt, character); - ctxt->first_section = FALSE; - } - else if ( (!first_contact) && (ctxt->y - e_contact_get_card_size(card, ctxt, shown_fields) < ctxt->style->bottom_margin * 72)) { - e_contact_start_new_column(ctxt); - if ( ctxt->style->letter_headings ) - e_contact_print_letter_heading(ctxt, character); - } - ctxt->last_char_on_page = toupper(*file_as); - if ( ctxt->last_char_on_page < ctxt->first_char_on_page ) - ctxt->first_char_on_page = ctxt->last_char_on_page; - e_contact_print_phone_list(card, ctxt, shown_fields); - first_contact = FALSE; - g_free (file_as); - } - ctxt->last_char_on_page = 'Z'; - if ( ctxt->style->letter_tabs ) - e_contact_print_letter_tab(ctxt); - gnome_print_showpage(ctxt->pc); - gnome_print_context_close(ctxt->pc); - g_free(character); + e_book_async_get_book_view(book, query, (EBookBookViewCallback) book_view_loaded, ctxt); } -#endif static void e_contact_do_print (EBook *book, char *query, EContactPrintContext *ctxt) { switch ( ctxt->style->type ) { case E_CONTACT_PRINT_TYPE_CARDS: - e_contact_do_print_cards( book, query, ctxt); + e_contact_do_print_contacts( book, query, ctxt); break; -#if 0 - case E_CONTACT_PRINT_TYPE_PHONE_LIST: - e_contact_do_print_phone_list( book, query, ctxt ); - break; -#endif default: break; } @@ -1027,8 +872,8 @@ e_contact_print_response(GtkWidget *dialog, gint response_id, gpointer data) gboolean uses_list = GPOINTER_TO_INT(g_object_get_data(G_OBJECT(dialog), "uses_list")); EBook *book = NULL; char *query = NULL; - ECard *card = NULL; - GList *card_list = NULL; + EContact *contact = NULL; + GList *contact_list = NULL; gdouble font_size; @@ -1037,10 +882,10 @@ e_contact_print_response(GtkWidget *dialog, gint response_id, gpointer data) query = g_object_get_data(G_OBJECT(dialog), "query"); } else if (uses_list) { - card_list = g_object_get_data(G_OBJECT(dialog), "card_list"); + contact_list = g_object_get_data(G_OBJECT(dialog), "contact_list"); } else { - card = g_object_get_data(G_OBJECT(dialog), "card"); + contact = g_object_get_data(G_OBJECT(dialog), "contact"); } switch( response_id ) { case GNOME_PRINT_DIALOG_RESPONSE_PRINT: @@ -1075,16 +920,16 @@ e_contact_print_response(GtkWidget *dialog, gint response_id, gpointer data) ctxt->book = book; ctxt->query = query; if (uses_book) { - ctxt->cards = NULL; + ctxt->contacts = NULL; e_contact_do_print(book, ctxt->query, ctxt); } else if (uses_list) { - ctxt->cards = card_list; - complete_sequence(NULL, E_BOOK_VIEW_STATUS_SUCCESS, ctxt); + ctxt->contacts = contact_list; + complete_sequence(NULL, E_BOOK_VIEW_STATUS_OK, ctxt); } else { - ctxt->cards = g_list_append(NULL, card); - complete_sequence(NULL, E_BOOK_VIEW_STATUS_SUCCESS, ctxt); + ctxt->contacts = g_list_append(NULL, contact); + complete_sequence(NULL, E_BOOK_VIEW_STATUS_OK, ctxt); } gtk_widget_destroy (dialog); break; @@ -1119,28 +964,28 @@ e_contact_print_response(GtkWidget *dialog, gint response_id, gpointer data) ctxt->book = book; ctxt->query = g_strdup(query); if (uses_book) { - ctxt->cards = NULL; + ctxt->contacts = NULL; g_object_ref(book); e_contact_do_print(book, ctxt->query, ctxt); } else if (uses_list) { - ctxt->cards = g_list_copy (card_list); - g_list_foreach (ctxt->cards, (GFunc)g_object_ref, NULL); - complete_sequence(NULL, E_BOOK_VIEW_STATUS_SUCCESS, ctxt); + ctxt->contacts = g_list_copy (contact_list); + g_list_foreach (ctxt->contacts, (GFunc)g_object_ref, NULL); + complete_sequence(NULL, E_BOOK_VIEW_STATUS_OK, ctxt); } else { - ctxt->cards = g_list_append(NULL, card); - g_object_ref(card); - complete_sequence(NULL, E_BOOK_VIEW_STATUS_SUCCESS, ctxt); + ctxt->contacts = g_list_append(NULL, contact); + g_object_ref(contact); + complete_sequence(NULL, E_BOOK_VIEW_STATUS_OK, ctxt); } break; case GNOME_PRINT_DIALOG_RESPONSE_CANCEL: if (uses_book) g_object_unref(book); else if (uses_list) - e_free_object_list (card_list); + e_free_object_list (contact_list); else - g_object_unref(card); + g_object_unref(contact); g_free(query); gtk_widget_destroy (dialog); g_free(style); @@ -1155,7 +1000,7 @@ e_contact_print_dialog_new(EBook *book, char *query) GtkWidget *dialog; - dialog = gnome_print_dialog_new(NULL, _("Print cards"), GNOME_PRINT_DIALOG_RANGE | GNOME_PRINT_DIALOG_COPIES); + dialog = gnome_print_dialog_new(NULL, _("Print contacts"), GNOME_PRINT_DIALOG_RANGE | GNOME_PRINT_DIALOG_COPIES); gnome_print_dialog_construct_range_any(GNOME_PRINT_DIALOG(dialog), GNOME_PRINT_RANGE_ALL | GNOME_PRINT_RANGE_SELECTION, NULL, NULL, NULL); @@ -1211,20 +1056,20 @@ e_contact_print_preview(EBook *book, char *query) #endif ctxt->book = book; ctxt->query = g_strdup(query); - ctxt->cards = NULL; + ctxt->contacts = NULL; g_object_ref(book); e_contact_do_print(book, ctxt->query, ctxt); } GtkWidget * -e_contact_print_card_dialog_new(ECard *card) +e_contact_print_contact_dialog_new(EContact *contact) { GtkWidget *dialog; - dialog = gnome_print_dialog_new(NULL, _("Print card"), GNOME_PRINT_DIALOG_COPIES); + dialog = gnome_print_dialog_new(NULL, _("Print contact"), GNOME_PRINT_DIALOG_COPIES); - card = e_card_duplicate(card); - g_object_set_data(G_OBJECT(dialog), "card", card); + contact = e_contact_duplicate(contact); + g_object_set_data(G_OBJECT(dialog), "contact", contact); g_object_set_data(G_OBJECT(dialog), "uses_list", GINT_TO_POINTER (FALSE)); g_object_set_data(G_OBJECT(dialog), "uses_book", GINT_TO_POINTER (FALSE)); g_signal_connect(dialog, @@ -1235,22 +1080,22 @@ e_contact_print_card_dialog_new(ECard *card) } GtkWidget * -e_contact_print_card_list_dialog_new(GList *list) +e_contact_print_contact_list_dialog_new(GList *list) { GtkWidget *dialog; - ECard *card; GList *copied_list; + GList *l; if (list == NULL) return NULL; copied_list = g_list_copy (list); - g_list_foreach (copied_list, (GFunc)g_object_ref, NULL); + for (l = copied_list; l; l = l->next) + l->data = e_contact_duplicate (E_CONTACT (l->data)); - dialog = gnome_print_dialog_new(NULL, _("Print card"), GNOME_PRINT_DIALOG_COPIES); + dialog = gnome_print_dialog_new(NULL, _("Print contact"), GNOME_PRINT_DIALOG_COPIES); - card = e_card_duplicate(list->data); - g_object_set_data(G_OBJECT(dialog), "card_list", copied_list); + g_object_set_data(G_OBJECT(dialog), "contact_list", copied_list); g_object_set_data(G_OBJECT(dialog), "uses_list", GINT_TO_POINTER (TRUE)); g_object_set_data(G_OBJECT(dialog), "uses_book", GINT_TO_POINTER (FALSE)); g_signal_connect(dialog, diff --git a/addressbook/printing/e-contact-print.h b/addressbook/printing/e-contact-print.h index 12f13f4573..8c2fbb6acb 100644 --- a/addressbook/printing/e-contact-print.h +++ b/addressbook/printing/e-contact-print.h @@ -25,12 +25,12 @@ #include #include #include -#include +#include #include "e-contact-print-types.h" GtkWidget *e_contact_print_dialog_new(EBook *book, char *query); void e_contact_print_preview(EBook *book, char *query); -GtkWidget *e_contact_print_card_dialog_new(ECard *card); -GtkWidget *e_contact_print_card_list_dialog_new(GList *list); +GtkWidget *e_contact_print_contact_dialog_new(EContact *card); +GtkWidget *e_contact_print_contact_list_dialog_new(GList *list); #endif /* E_CONTACT_PRINT_H */ diff --git a/addressbook/tools/Makefile.am b/addressbook/tools/Makefile.am index 79a1c746ad..c9e082603e 100644 --- a/addressbook/tools/Makefile.am +++ b/addressbook/tools/Makefile.am @@ -1,6 +1,12 @@ +privlibexec_SCRIPTS = \ + csv2vcard \ + evolution-addressbook-clean + bin_PROGRAMS = \ evolution-addressbook-export +noinst_PROGRAMS= evolution-addressbook-abuse + INCLUDES = \ -DG_LOG_DOMAIN=\"evolution-addressbook-tools\" \ -I$(top_srcdir) \ @@ -23,11 +29,22 @@ evolution_addressbook_export_SOURCES = \ evolution-addressbook-export.h evolution_addressbook_export_LDADD = \ - $(GNOME_FULL_LIBS) \ $(top_builddir)/addressbook/backend/ebook/libebook.la \ - $(top_builddir)/widgets/menus/libmenus.la \ - $(top_builddir)/camel/libcamel.la \ - $(top_builddir)/libversit/libversit.la \ $(top_builddir)/e-util/ename/libename.la \ $(top_builddir)/e-util/libeutil.la +evolution_addressbook_abuse_LDADD = \ + $(top_builddir)/addressbook/backend/ebook/libebook.la \ + $(top_builddir)/e-util/ename/libename.la \ + $(top_builddir)/e-util/libeutil.la + +EXTRA_DIST = $(privlibexec_SCRIPTS) \ + evolution-addressbook-clean.in + +CLEANFILES= evolution-addressbook-clean + +evolution-addressbook-clean: evolution-addressbook-clean.in Makefile +## Use sed and then mv to avoid problems if the user interrupts. + sed -e 's?\@EVOLUTION_TOOLSDIR\@?$(privlibexecdir)?g' \ + < $(srcdir)/evolution-addressbook-clean.in > evolution-addressbook-clean.tmp \ + && mv evolution-addressbook-clean.tmp evolution-addressbook-clean diff --git a/addressbook/tools/csv2vcard b/addressbook/tools/csv2vcard new file mode 100755 index 0000000000..b968fbd9c3 --- /dev/null +++ b/addressbook/tools/csv2vcard @@ -0,0 +1,236 @@ +#!/usr/bin/perl -w +# +# cvs2vcard - Script to convert Outlook CSV files into VCard files +# suitable to be imported into Evolution. +# +# Copyright (C) 2001 Ximian, Inc. +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of version 2 of the GNU General Public +# License as published by the Free Software Foundation. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# General Public License for more details. +# +# You should have received a copy of the GNU General Public +# License along with this program; if not, write to the +# Free Software Foundation, Inc., 59 Temple Place - Suite 330, +# Boston, MA 02111-1307, USA. +# +# Author: Michael MacDonald +# + +use strict; +use diagnostics; +use Text::ParseWords; + +sub usage +{ + print STDERR << "--EndOfUsage"; + +Takes a CSV-formatted list of contacts from Outlook and attempts to +convert it into a list of VCards suitable for import into Evolution. + +Usage: $0 [infile outfile] + +--EndOfUsage + + exit; +} + +sub is_recognized_format +{ + my $line = shift; + + # Making some assumptions here... Prolly OK. + return $line =~ /(First Name|Middle Name|Last Name)/; +} + +sub map_columns +{ + my $line = shift; + + my @names = parse_line(',', 0, $line); + + my $ctr = 0; + my %fieldmap = map { $_ => $ctr++ } @names; + + return %fieldmap; +} + +sub build_vcard_attr_from_def +{ + my ($def, $fields, $map) = @_; + + # Valid chars for lookup (from Outlook CSV) are + # A-Za-z0-9_-'/ + # Valid chars for formatting of attr are + # \s,| + my @lookup = map { s/=0A$//; s/[^\w\s\-'\/]//; $_; } split /[\s,]*\|[\s,]*/, $def; + + foreach my $el (@lookup) { + unless (defined($map->{ $el })) { + print STDERR "$el is undefined\n"; + next; + } + if (defined($fields->[$map->{ $el }])) { + unless ($fields->[$map->{ $el }] =~ /(^$|0\/0\/00)/) { + $def =~ s/$el/$fields->[$map->{ $el }]/; + } else { + $def =~ s/((?<=\|)\s*)?$el(\s*?(?=\|))?(=0A)?,?//; + } + } else { + $def =~ s/((?<=\|)\s*)?$el(\s*?(?=\|))?(=0A)?,?//; + } + } + # Get rid of field delimiters + $def =~ s/\|//g; + # Snip off any trailing semicolons or whitespace + $def =~ s/[\s;]*$//; + + return $def; +} + +sub build_vcard_from_line { + my ($line, %map) = @_; + my %vcard; + + my @fields = parse_line(',', 0, $line); + + my %vcard_def = ( FN => 'Title |First Name |Middle Name |Last Name |Suffix', + N => 'Last Name| Suffix|;First Name|;Middle Name|;Title', + 'ADR;WORK' => 'PO Box|;Business Street 2|;Business Street|;Business City|;Business State|;Business Postal Code|;Business Country', + 'LABEL;QUOTED-PRINTABLE;WORK' => 'PO Box |Business Street=0A|Business Street 2=0A|Business City,| Business State| Business Postal Code=0A|Business Country', + 'TEL;WORK;VOICE' => 'Business Phone', + 'TEL;WORK;VOICE2' => 'Business Phone 2', + 'TEL;WORK;FAX' => 'Business Fax', + 'TEL;WORK;COMPANY' => 'Company Main Phone', + 'ADR;HOME' => ';Home Street 2|;Home Street|;Home City|;Home State|;Home Postal Code|;Home Country', + 'LABEL;QUOTED-PRINTABLE;HOME' => 'Home Street=0A|Home Street 2=0A|Home City,| Home State| Home Postal Code=0A|Home Country', + 'TEL;HOME;VOICE' => 'Home Phone', + 'TEL;HOME;VOICE2' => 'Home Phone 2', + 'TEL;HOME;FAX' => 'Home Fax', + 'ADR;POSTAL' => ';Other Street 2|;Other Street|;Other City|;Other State|;Other Postal Code|;Other Country', + 'LABEL;QUOTED-PRINTABLE;POSTAL' => 'Other Street=0A|Other Street 2=0A|Other City,| Other State| Other Postal Code=0A|Other Country', + 'TEL;VOICE' => 'Other Phone', + 'TEL;FAX' => 'Other Fax', + 'TEL;CELL' => 'Mobile Phone', + 'TEL;CAR' => 'Car Phone', + 'TEL;PAGER' => 'Pager', + 'TEL;PREF' => 'Primary Phone', + 'TEL;ISDN' => 'ISDN', + 'TEL;X-EVOLUTION-CALLBACK' => 'Callback', + 'TEL;X-EVOLUTION-TTYTDD' => 'TTY/TDD Phone', + 'TEL;X-EVOLUTION-TELEX' => 'Telex', + 'TEL;X-EVOLUTION-RADIO' => 'Radio Phone', + 'EMAIL;INTERNET' => 'E-mail Address', + 'EMAIL;INTERNET2' => 'E-mail 2 Address', + 'EMAIL;INTERNET3' => 'E-mail 3 Address', + ORG => 'Company|;Department', + TITLE => 'Job Title', + ROLE => 'Profession', + 'X-EVOLUTION-ASSISTANT' => "Assistant's Name", + 'TEL;X-EVOLUTION-ASSISTANT' => "Assistant's Phone", + 'X-EVOLUTION-SPOUSE' => 'Spouse', + 'X-EVOLUTION-ANNIVERSARY' => 'Anniversary', + 'X-EVOLUTION-MANAGER' => "Manager's Name", + 'X-EVOLUTION-OFFICE' => 'Office Location', + BDAY => 'Birthday', + NOTE => 'Notes', + FBURL => 'Internet Free Busy', + URL => 'Web Page', + ); + + foreach my $key (keys(%vcard_def)) { + my $attr = build_vcard_attr_from_def($vcard_def{ $key }, \@fields, \%map); + if (defined($attr)) { + $vcard{ $key } = $attr unless ($attr =~ /^$/); + } + } + + return %vcard; +} + +sub print_vcard_to_fh +{ + my ($fh, %vcard) = @_; + + print $fh "BEGIN:VCARD\n"; + foreach my $key (keys(%vcard)) { + # Dirty hack because Evolution's vcard stores multiple email addrs + # with same sttribute, hence key collision. Bleah. + # Ugh! Same deal for multiple phones... (eg. bus. phone) + # + # And finally, while we're special-casing... Outlook exports dates + # differently, so munge 'em if we find 'em. + if ($key =~ /EMAIL;INTERNET/o) { + (my $temp = $key) =~ s/\d$//; + print $fh "$temp:$vcard{ $key }\n"; + } elsif ($key =~ /TEL;(HOME|WORK)/o) { + (my $temp = $key) =~ s/\d$//; + print $fh "$temp:$vcard{ $key }\n"; + } elsif ($key =~ /(BDAY|X\-EVOLUTION\-ANNIVERSARY)/o) { + my $temp = $vcard{ $key }; + if ($temp =~ /(\d\d)\/(\d\d)\/(\d\d)/) { + # Y2k !! MS Didn't learn anything. + # Hope no one was born before 1915 + if ((1900 + $3) < 1915) { + print $fh "$key:20$3-$1-$2\n"; + } else { + print $fh "$key:19$3-$1-$2\n"; + } + } else { + # Something's funky... Just delete the attribute + print STDERR "Couldn't figure out what to do with $key:$vcard{ $key }\n"; + delete($vcard{ $key }); + } + } else { + print $fh "$key:$vcard{ $key }\n"; + } + } + print $fh "END:VCARD\n\n"; +} + +my $in = $ARGV[0]; +my $out = $ARGV[1]; + +usage() unless(defined($in) && defined($out)); + +open (IN, $in) + or die "Can't open($in): $!\n"; + +open (OUT, ">$out") + or die "Can't open($out): $!\n"; + +my $linectr = 0; +my %map; + +while (my $line = ) { + $line =~ s/\r//g; + $line =~ s/\n$//; + if ($linectr == 0) { + $linectr++; + usage() unless is_recognized_format($line); + %map = map_columns($line); + #if ($line =~ /\r\n$/) { + # print STDERR "Apparenlty found DOS-style EOL indicators...\n"; + $/ = "\r\n"; + #} + } else { + $linectr++; + while ($line =~ /^(("([^"]|\n|"")*")?,)*"([^"]|\n|"")*$/) { + my $temp = $line; + $line = ; + $line =~ s/\r//g; + $line =~ s/\n$//; + $line = "$temp $line"; + } + my %vcard = build_vcard_from_line($line, %map); + print_vcard_to_fh(\*OUT, %vcard); + } +} + +close(IN); +close(OUT); diff --git a/addressbook/tools/evolution-addressbook-abuse.c b/addressbook/tools/evolution-addressbook-abuse.c new file mode 100644 index 0000000000..7801ed7e9d --- /dev/null +++ b/addressbook/tools/evolution-addressbook-abuse.c @@ -0,0 +1,127 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ + +#include + +#include +#include + +#include +#include + +static int contacts_to_add_total = 1000; +static int contacts_to_add = 50; +static int call_count = 0; + +static gchar * +make_random_string (void) +{ + const gchar *elements = " abcdefghijklmnopqrstuvwxyz1234567890 ABCDEFGHIJKLMNOPQRSTUVWXYZ"; + gint len = strlen (elements); + gint i, N = 5 + (random () % 10); + gchar *str = g_malloc (N+1); + + for (i = 0; i < N; ++i) { + str[i] = elements[random () % len]; + } + str[i] = '\0'; + + return str; +} + +static gchar * +make_random_vcard (void) +{ + gchar *fa = make_random_string (); + gchar *name = make_random_string (); + gchar *email = make_random_string (); + gchar *org = make_random_string (); + + gchar *vcard; + + vcard = g_strdup_printf ("BEGIN:VCARD\n" + "X-EVOLUTION-FILE-AS:%s\n" + "N:%s\n" + "EMAIL;INTERNET:%s\n" + "ORG:%s\n" + "END:VCARD", + fa, name, email, org); + g_free (fa); + g_free (name); + g_free (email); + g_free (org); + + return vcard; +} + +/* ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** */ + +static void +add_cb (EBook *book, EBookStatus status, const char *id, gpointer closure) +{ + switch (status) { + case E_BOOK_ERROR_OK: + --contacts_to_add_total; + g_message ("succesful add! (%d remaining)", contacts_to_add_total); + if (contacts_to_add_total <= 0) + g_main_loop_quit (NULL); + break; + default: + g_message ("something went wrong..."); + g_main_loop_quit (NULL); + break; + } +} + +static void +use_addressbook (EBook *book, EBookStatus status, gpointer closure) +{ + gint i; + + if (book == NULL || status != E_BOOK_ERROR_OK) + g_error (_("Error loading default addressbook.")); + + for (i = 0; i < contacts_to_add; ++i) { + gchar *vcard = make_random_vcard (); + EContact *contact = e_contact_new_from_vcard (vcard); + g_message ("adding %d", i); + e_book_async_add_contact (book, contact, add_cb, NULL); + g_free (vcard); + g_object_unref (contact); + } + + g_object_unref (book); +} + +static gint +abuse_timeout (gpointer foo) +{ + e_book_async_get_default_addressbook (use_addressbook, NULL); + + ++call_count; + g_message ("timeout!"); + return call_count < contacts_to_add_total / contacts_to_add; +} + +int +main (int argc, char *argv[]) +{ + if (getenv ("ABUSE_THE_WOMBAT") == NULL) { + g_print ("You probably don't want to use this program.\n" + "It isn't very nice.\n"); + exit(0); + } + + bindtextdomain (GETTEXT_PACKAGE, EVOLUTION_LOCALEDIR); + textdomain (GETTEXT_PACKAGE); + + gnome_program_init ("evolution-addressbook-abuse", VERSION, + LIBGNOMEUI_MODULE, argc, argv, + GNOME_PROGRAM_STANDARD_PROPERTIES, + NULL); + + g_timeout_add (20, abuse_timeout, NULL); + + bonobo_main (); + + return 0; +} diff --git a/addressbook/tools/evolution-addressbook-clean.in b/addressbook/tools/evolution-addressbook-clean.in new file mode 100644 index 0000000000..b7ee7ba167 --- /dev/null +++ b/addressbook/tools/evolution-addressbook-clean.in @@ -0,0 +1,24 @@ +#! /usr/bin/perl -w + +sub do_system +{ + my ($command) = @_; + system ($command); + if ($? != 0) { + die "Command failed: $command"; + } +} + +$filename = `@EVOLUTION_TOOLSDIR@/evolution-addressbook-export`; +if ($? != 0) { + $! = $?; + die $!; +} + +$HOME = $ENV{"HOME"}; + +system ("@EVOLUTION_TOOLSDIR@/killev"); +do_system ("/bin/mv ${HOME}/evolution/local/Contacts/addressbook.db ${HOME}/evolution/local/Contacts/addressbook-backup.db"); +do_system ("@EVOLUTION_TOOLSDIR@/evolution-addressbook-import --input-file $filename"); +do_system ("/bin/rm $filename"); + diff --git a/addressbook/tools/evolution-addressbook-import.c b/addressbook/tools/evolution-addressbook-import.c new file mode 100644 index 0000000000..28871efd96 --- /dev/null +++ b/addressbook/tools/evolution-addressbook-import.c @@ -0,0 +1,90 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ + +#include + +#include +#include +#include +#include + +static int exec_ref_count = 0; + +static void +ref_executable (void) +{ + exec_ref_count ++; +} + +static void +unref_executable (void) +{ + exec_ref_count --; + if (exec_ref_count == 0) + g_main_loop_quit (0); +} + +static void +add_cb (EBook *book, EBookStatus status, const char *id, gpointer closure) +{ + switch (status) { + case E_BOOK_ERROR_OK: + unref_executable (); + break; + default: + g_main_loop_quit (NULL); + break; + } +} + +static void +use_addressbook (EBook *book, gpointer closure) +{ + GList *cards, *list; + char *filename = closure; + + if (book == NULL) + g_error (_("Error loading default addressbook.")); + + cards = e_card_load_cards_from_file (filename); + + ref_executable (); + + for (list = cards; list; list = list->next) { + ref_executable (); + e_book_add_card (book, list->data, add_cb, closure); + } + sync(); + + unref_executable (); +} + +int +main (int argc, char *argv[]) +{ + char *filename = NULL; + + struct poptOption options[] = { + { "input-file", '\0', POPT_ARG_STRING, &filename, 0, N_("Input File"), NULL }, + POPT_AUTOHELP + { NULL, '\0', 0, NULL, 0, NULL, NULL } + }; + + bindtextdomain (GETTEXT_PACKAGE, EVOLUTION_LOCALEDIR); + textdomain (GETTEXT_PACKAGE); + + gnome_program_init ("evolution-addressbook-import", VERSION, + LIBGNOMEUI_MODULE, argc, argv, + GNOME_PROGRAM_STANDARD_PROPERTIES, + GNOME_PARAM_POPT_TABLE, options, + NULL); + + if (filename == NULL) { + g_error (_("No filename provided.")); + } + + e_book_async_get_default_addressbook (use_addressbook, filename); + + bonobo_main (); + + return 0; +} diff --git a/addressbook/util/.cvsignore b/addressbook/util/.cvsignore new file mode 100644 index 0000000000..6205c6f3ab --- /dev/null +++ b/addressbook/util/.cvsignore @@ -0,0 +1,4 @@ +Makefile +Makefile.in +eab-marshal.c +eab-marshal.h diff --git a/addressbook/util/Makefile.am b/addressbook/util/Makefile.am new file mode 100644 index 0000000000..51b6e7fc28 --- /dev/null +++ b/addressbook/util/Makefile.am @@ -0,0 +1,41 @@ +INCLUDES = \ + -DPREFIX=\"$(prefix)\" \ + -DSYSCONFDIR=\"$(sysconfdir)\" \ + -DDATADIR=\"$(datadir)\" \ + -DLIBDIR=\"$(libdir)\" \ + -DG_LOG_DOMAIN=\"EBook\" \ + -I$(top_srcdir) \ + -I$(top_srcdir)/camel \ + -I$(top_srcdir)/addressbook/backend \ + -I$(top_srcdir)/addressbook/ename \ + -I$(top_builddir)/addressbook/backend \ + -I$(top_builddir)/addressbook/ename \ + -I$(top_builddir)/shell \ + -I$(top_srcdir)/shell \ + -DG_DISABLE_DEPRECATED \ + -DLIBGNOME_DISABLE_DEPRECATED \ + $(EVOLUTION_ADDRESSBOOK_CFLAGS) + +noinst_LTLIBRARIES = libeabutil.la + +libeabutil_la_SOURCES = \ + eab-marshal.c \ + eab-destination.c \ + eab-destination.h \ + eab-book-util.c \ + eab-book-util.h + +libeabutil_la_LIBADD = \ + $(top_builddir)/addressbook/backend/ebook/libebook.la \ + $(top_builddir)/camel/libcamel.la \ + $(top_builddir)/e-util/ename/libename.la \ + $(top_builddir)/e-util/libeutil.la + +MARSHAL_GENERATED = eab-marshal.c eab-marshal.h +@EVO_MARSHAL_RULE@ + +BUILT_SOURCES = $(MARSHAL_GENERATED) +CLEANFILES = $(BUILT_SOURCES) + +dist-hook: + cd $(distdir); rm -f $(BUILT_SOURCES) diff --git a/addressbook/util/eab-book-util.c b/addressbook/util/eab-book-util.c new file mode 100644 index 0000000000..2c80d6f8a1 --- /dev/null +++ b/addressbook/util/eab-book-util.c @@ -0,0 +1,293 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ + +/* + * eab-util.c + * + * Copyright (C) 2001-2003 Ximian, Inc. + * + * Authors: Jon Trowbridge + * Chris Toshok + */ + +/* + * This program is free software; you can redistribute it and/or + * modify it under the terms of version 2 of the GNU General Public + * License as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + * USA. + */ + +#include +#include "eab-book-util.h" + +#include +#include +#include +#include + +EConfigListener * +eab_get_config_database () +{ + static EConfigListener *config_db; + + if (config_db == NULL) + config_db = e_config_listener_new (); + + return config_db; +} + +/* + * + * Specialized Queries + * + */ + +guint +eab_name_and_email_query (EBook *book, + const gchar *name, + const gchar *email, + EBookContactsCallback cb, + gpointer closure) +{ + gchar *email_query=NULL, *name_query=NULL, *query; + guint tag; + + g_return_val_if_fail (book && E_IS_BOOK (book), 0); + g_return_val_if_fail (cb != NULL, 0); + + if (name && !*name) + name = NULL; + if (email && !*email) + email = NULL; + + if (name == NULL && email == NULL) + return 0; + + /* Build our e-mail query. + * We only query against the username part of the address, to avoid not matching + * fred@foo.com and fred@mail.foo.com. While their may be namespace collisions + * in the usernames of everyone out there, it shouldn't be that bad. (Famous last words.) + */ + if (email) { + const gchar *t = email; + while (*t && *t != '@') + ++t; + if (*t == '@') { + email_query = g_strdup_printf ("(beginswith \"email\" \"%.*s@\")", t-email, email); + + } else { + email_query = g_strdup_printf ("(beginswith \"email\" \"%s\")", email); + } + } + + /* Build our name query. + * We only do name-query stuff if we don't have an e-mail address. Our basic assumption + * is that the username part of the email is good enough to keep the amount of stuff returned + * in the query relatively small. + */ + if (name && !email) + name_query = g_strdup_printf ("(or (beginswith \"file_as\" \"%s\") (beginswith \"full_name\" \"%s\"))", name, name); + + /* Assemble our e-mail & name queries */ + if (email_query && name_query) { + query = g_strdup_printf ("(and %s %s)", email_query, name_query); + } else if (email_query) { + query = email_query; + email_query = NULL; + } else if (name_query) { + query = name_query; + name_query = NULL; + } else + return 0; + + tag = e_book_async_get_contacts (book, query, cb, closure); + + g_free (email_query); + g_free (name_query); + g_free (query); + + return tag; +} + +/* + * Simple nickname query + */ +guint +eab_nickname_query (EBook *book, + const char *nickname, + EBookContactsCallback cb, + gpointer closure) +{ + gchar *query; + guint retval; + + g_return_val_if_fail (E_IS_BOOK (book), 0); + g_return_val_if_fail (nickname != NULL, 0); + + /* The empty-string case shouldn't generate a warning. */ + if (! *nickname) + return 0; + + query = g_strdup_printf ("(is \"nickname\" \"%s\")", nickname); + + retval = e_book_async_get_contacts (book, query, cb, closure); + + g_free (query); + + return retval; +} + +GList* +eab_contact_list_from_string (const char *str) +{ + GList *contacts = NULL; + GString *gstr = g_string_new (""); + char *p = (char*)str; + char *q; + char *blank_line; + + while (*p) { + if (*p != '\r') g_string_append_c (gstr, *p); + + p++; + } + + p = g_string_free (gstr, FALSE); + q = p; + do { + char *temp; + + blank_line = strstr (q, "\n\n"); + if (blank_line) { + temp = g_strndup (q, blank_line - q); + } + else { + temp = g_strdup (q); + } + + contacts = g_list_append (contacts, e_contact_new_from_vcard (temp)); + + g_free (temp); + + if (blank_line) + q = blank_line + 2; + else + q = NULL; + } while (blank_line); + + g_free (p); + + return contacts; +} + +char* +eab_contact_list_to_string (GList *contacts) +{ + GString *str = g_string_new (""); + GList *l; + + for (l = contacts; l; l = l->next) { + EContact *contact = l->data; + char *vcard_str = e_vcard_to_string (E_VCARD (contact), EVC_FORMAT_VCARD_30); + + g_string_append (str, vcard_str); + if (l->next) + g_string_append (str, "\r\n"); + } + + return g_string_free (str, FALSE); +} + +#if notyet +/* + * Convenience routine to check for addresses in the local address book. + */ + +typedef struct _HaveAddressInfo HaveAddressInfo; +struct _HaveAddressInfo { + gchar *email; + EBookHaveAddressCallback cb; + gpointer closure; +}; + +static void +have_address_query_cb (EBook *book, EBookSimpleQueryStatus status, const GList *contacts, gpointer closure) +{ + HaveAddressInfo *info = (HaveAddressInfo *) closure; + + info->cb (book, + info->email, + contacts && (status == E_BOOK_ERROR_OK) ? E_CONTACT (contacts->data) : NULL, + info->closure); + + g_free (info->email); + g_free (info); +} + +static void +have_address_book_open_cb (EBook *book, gpointer closure) +{ + HaveAddressInfo *info = (HaveAddressInfo *) closure; + + if (book) { + + e_book_name_and_email_query (book, NULL, info->email, have_address_query_cb, info); + + } else { + + info->cb (NULL, info->email, NULL, info->closure); + + g_free (info->email); + g_free (info); + + } +} + +void +eab_query_address_default (const gchar *email, + EABHaveAddressCallback cb, + gpointer closure) +{ + HaveAddressInfo *info; + + g_return_if_fail (email != NULL); + g_return_if_fail (cb != NULL); + + info = g_new0 (HaveAddressInfo, 1); + info->email = g_strdup (email); + info->cb = cb; + info->closure = closure; + + e_book_use_default_book (have_address_book_open_cb, info); +} +#endif + +/* bad place for this i know. */ +int +e_utf8_casefold_collate_len (const gchar *str1, const gchar *str2, int len) +{ + gchar *s1 = g_utf8_casefold(str1, len); + gchar *s2 = g_utf8_casefold(str2, len); + int rv; + + rv = g_utf8_collate (s1, s2); + + g_free (s1); + g_free (s2); + + return rv; +} + +int +e_utf8_casefold_collate (const gchar *str1, const gchar *str2) +{ + return e_utf8_casefold_collate_len (str1, str2, -1); +} diff --git a/addressbook/util/eab-book-util.h b/addressbook/util/eab-book-util.h new file mode 100644 index 0000000000..be5451b795 --- /dev/null +++ b/addressbook/util/eab-book-util.h @@ -0,0 +1,69 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ + +/* + * e-book-util.h + * + * Copyright (C) 2001-2003 Ximian, Inc. + * + * Authors: Jon Trowbridge + * Chris Toshok + */ + +/* + * This program is free software; you can redistribute it and/or + * modify it under the terms of version 2 of the GNU General Public + * License as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + * USA. + */ + +#ifndef __EAB_UTIL_H__ +#define __EAB_UTIL_H__ + +#include "ebook/e-book-async.h" +#include "e-util/e-config-listener.h" +#include +#include + +G_BEGIN_DECLS + +typedef void (*EABHaveAddressCallback) (EBook *book, const gchar *addr, EContact *contact, gpointer closure); + +/* config database interface. */ +EConfigListener *eab_get_config_database (void); + +/* Specialized Name/Email Queries */ +guint eab_name_and_email_query (EBook *book, + const char *name, + const char *email, + EBookContactsCallback cb, + gpointer closure); +guint eab_nickname_query (EBook *book, + const char *nickname, + EBookContactsCallback cb, + gpointer closure); + +GList *eab_contact_list_from_string (const char *str); +char *eab_contact_list_to_string (GList *contacts); + +/* Returns the EContact associated to email in the callback, + or NULL if no match is found in the default address book. */ +void eab_query_address_default (const gchar *email, + EABHaveAddressCallback cb, + gpointer closure); + +int e_utf8_casefold_collate_len (const gchar *str1, const gchar *str2, int len); +int e_utf8_casefold_collate (const gchar *str1, const gchar *str2); + +G_END_DECLS + +#endif /* __EAB_UTIL_H__ */ + diff --git a/addressbook/util/eab-destination.c b/addressbook/util/eab-destination.c new file mode 100644 index 0000000000..d83ad8563a --- /dev/null +++ b/addressbook/util/eab-destination.c @@ -0,0 +1,1569 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ + +/* + * eab-destination.c + * + * Copyright (C) 2001-2003 Ximian, Inc. + * + * Authors: Jon Trowbridge + * Chris Toshok + */ + +/* + * This program is free software; you can redistribute it and/or + * modify it under the terms of version 2 of the GNU General Public + * License as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + * USA. + */ + +#include +#include "eab-destination.h" + +#include +#include +#include +#include "ebook/e-book.h" +#include "eab-marshal.h" +#include "eab-book-util.h" +#include + +#include +#include +#include + +#define d(x) + +enum { + CHANGED, + CONTACT_LOADED, + LAST_SIGNAL +}; + +guint eab_destination_signals[LAST_SIGNAL] = { 0 }; + +struct _EABDestinationPrivate { + gchar *raw; + + gchar *book_uri; + gchar *uid; + EContact *contact; + gint email_num; + + gchar *name; + gchar *email; + gchar *addr; + gchar *textrep; + + GList *list_dests; + + guint html_mail_override : 1; + guint wants_html_mail : 1; + + guint show_addresses : 1; + + guint contact_loaded : 1; + guint cannot_load : 1; + guint auto_recipient : 1; + guint pending_contact_load; + + guint pending_change : 1; + + EBook *book; + + gint freeze_count; +}; + +static void eab_destination_clear_contact (EABDestination *); +static void eab_destination_clear_strings (EABDestination *); + +/* the following prototypes were in e-destination.h, but weren't used + by anything in evolution... let's make them private for now. */ +static gboolean eab_destination_is_valid (const EABDestination *); +static void eab_destination_set_contact_uid (EABDestination *, const gchar *uid, gint email_num); +static void eab_destination_set_book_uri (EABDestination *, const gchar *uri); +static gboolean eab_destination_from_contact (const EABDestination *); +static const gchar *eab_destination_get_book_uri (const EABDestination *); +static const gchar *eab_destination_get_contact_uid (const EABDestination *); +static xmlNodePtr eab_destination_xml_encode (const EABDestination *dest); +static gboolean eab_destination_xml_decode (EABDestination *dest, xmlNodePtr node); + +static GObjectClass *parent_class; + +static void +eab_destination_dispose (GObject *obj) +{ + EABDestination *dest = EAB_DESTINATION (obj); + + if (dest->priv) { + eab_destination_clear (dest); + + if (dest->priv->book) + g_object_unref (dest->priv->book); + + g_free (dest->priv); + dest->priv = NULL; + } + + if (G_OBJECT_CLASS (parent_class)->dispose) + (* G_OBJECT_CLASS (parent_class)->dispose) (obj); +} + +static void +eab_destination_class_init (EABDestinationClass *klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS (klass); + + parent_class = g_type_class_ref (G_TYPE_OBJECT); + + object_class->dispose = eab_destination_dispose; + + eab_destination_signals[CHANGED] = + g_signal_new ("changed", + G_OBJECT_CLASS_TYPE (object_class), + G_SIGNAL_RUN_LAST, + G_STRUCT_OFFSET (EABDestinationClass, changed), + NULL, NULL, + eab_marshal_NONE__NONE, + G_TYPE_NONE, 0); + + eab_destination_signals[CONTACT_LOADED] = + g_signal_new ("contact_loaded", + G_OBJECT_CLASS_TYPE (object_class), + G_SIGNAL_RUN_LAST, + G_STRUCT_OFFSET (EABDestinationClass, contact_loaded), + NULL, NULL, + eab_marshal_NONE__NONE, + G_TYPE_NONE, 0); +} + +static void +eab_destination_init (EABDestination *dest) +{ + dest->priv = g_new0 (struct _EABDestinationPrivate, 1); + + dest->priv->cannot_load = FALSE; + dest->priv->auto_recipient = FALSE; + dest->priv->pending_contact_load = 0; +} + +GType +eab_destination_get_type (void) +{ + static GType dest_type = 0; + + if (!dest_type) { + GTypeInfo dest_info = { + sizeof (EABDestinationClass), + NULL, /* base_class_init */ + NULL, /* base_class_finalize */ + (GClassInitFunc) eab_destination_class_init, + NULL, /* class_finalize */ + NULL, /* class_data */ + sizeof (EABDestination), + 0, /* n_preallocs */ + (GInstanceInitFunc) eab_destination_init + }; + + dest_type = g_type_register_static (G_TYPE_OBJECT, "EABDestination", &dest_info, 0); + } + + return dest_type; +} + +EABDestination * +eab_destination_new (void) +{ + return g_object_new (EAB_TYPE_DESTINATION, NULL); +} + +static void +eab_destination_freeze (EABDestination *dest) +{ + g_return_if_fail (EAB_IS_DESTINATION (dest)); + g_return_if_fail (dest->priv->freeze_count >= 0); + + dest->priv->freeze_count++; +} + +static void +eab_destination_thaw (EABDestination *dest) +{ + g_return_if_fail (EAB_IS_DESTINATION (dest)); + g_return_if_fail (dest->priv->freeze_count > 0); + + dest->priv->freeze_count--; + if (dest->priv->freeze_count == 0 && dest->priv->pending_change) + eab_destination_changed (dest); +} + +void +eab_destination_changed (EABDestination *dest) +{ + if (dest->priv->freeze_count == 0) { + g_signal_emit (dest, eab_destination_signals[CHANGED], 0); + dest->priv->pending_change = FALSE; + dest->priv->cannot_load = FALSE; + + } else { + dest->priv->pending_change = TRUE; + } +} + +EABDestination * +eab_destination_copy (const EABDestination *dest) +{ + EABDestination *new_dest; + GList *iter; + + g_return_val_if_fail (dest && EAB_IS_DESTINATION (dest), NULL); + + new_dest = eab_destination_new (); + + new_dest->priv->book_uri = g_strdup (dest->priv->book_uri); + new_dest->priv->uid = g_strdup (dest->priv->uid); + new_dest->priv->name = g_strdup (dest->priv->name); + new_dest->priv->email = g_strdup (dest->priv->email); + new_dest->priv->addr = g_strdup (dest->priv->addr); + new_dest->priv->email_num = dest->priv->email_num; + + new_dest->priv->contact = dest->priv->contact; + if (new_dest->priv->contact) + g_object_ref (new_dest->priv->contact); + + new_dest->priv->html_mail_override = dest->priv->html_mail_override; + new_dest->priv->wants_html_mail = dest->priv->wants_html_mail; + + for (iter = dest->priv->list_dests; iter != NULL; iter = g_list_next (iter)) { + new_dest->priv->list_dests = g_list_append (new_dest->priv->list_dests, + eab_destination_copy (EAB_DESTINATION (iter->data))); + } + + return new_dest; +} + +static void +eab_destination_clear_contact (EABDestination *dest) +{ + g_free (dest->priv->book_uri); + dest->priv->book_uri = NULL; + g_free (dest->priv->uid); + dest->priv->uid = NULL; + + dest->priv->contact = NULL; + dest->priv->email_num = -1; + + g_list_foreach (dest->priv->list_dests, (GFunc) g_object_unref, NULL); + g_list_free (dest->priv->list_dests); + dest->priv->list_dests = NULL; + + dest->priv->cannot_load = FALSE; + + eab_destination_cancel_contact_load (dest); + + eab_destination_changed (dest); +} + +static void +eab_destination_clear_strings (EABDestination *dest) +{ + g_free (dest->priv->raw); + dest->priv->raw = NULL; + + g_free (dest->priv->name); + dest->priv->name = NULL; + + g_free (dest->priv->email); + dest->priv->email = NULL; + + g_free (dest->priv->addr); + dest->priv->addr = NULL; + + g_free (dest->priv->textrep); + dest->priv->textrep = NULL; + + eab_destination_changed (dest); +} + +void +eab_destination_clear (EABDestination *dest) +{ + g_return_if_fail (dest && EAB_IS_DESTINATION (dest)); + + eab_destination_freeze (dest); + + eab_destination_clear_contact (dest); + eab_destination_clear_strings (dest); + + eab_destination_thaw (dest); +} + +static gboolean +nonempty (const gchar *s) +{ + gunichar c; + while (*s) { + c = g_utf8_get_char (s); + if (!g_unichar_isspace (c)) + return TRUE; + s = g_utf8_next_char (s); + } + return FALSE; +} + +gboolean +eab_destination_is_empty (const EABDestination *dest) + +{ + struct _EABDestinationPrivate *p; + + g_return_val_if_fail (EAB_IS_DESTINATION (dest), TRUE); + + p = dest->priv; + + return !(p->contact != NULL + || (p->book_uri && *p->book_uri) + || (p->uid && *p->uid) + || (p->raw && nonempty (p->raw)) + || (p->name && nonempty (p->name)) + || (p->email && nonempty (p->email)) + || (p->addr && nonempty (p->addr)) + || (p->list_dests != NULL)); +} + +gboolean +eab_destination_is_valid (const EABDestination *dest) +{ + const char *email; + + g_return_val_if_fail (EAB_IS_DESTINATION (dest), FALSE); + + if (eab_destination_from_contact (dest)) + return TRUE; + + email = eab_destination_get_email (dest); + + /* FIXME: if we really wanted to get fancy here, we could + check to make sure that the address was valid according to + rfc822's addr-spec grammar. */ + + return email && *email && strchr (email, '@'); +} + +gboolean +eab_destination_equal (const EABDestination *a, const EABDestination *b) +{ + const struct _EABDestinationPrivate *pa, *pb; + const char *na, *nb; + + g_return_val_if_fail (EAB_IS_DESTINATION (a), FALSE); + g_return_val_if_fail (EAB_IS_DESTINATION (b), FALSE); + + if (a == b) + return TRUE; + + pa = a->priv; + pb = b->priv; + + /* Check equality of contacts. */ + if (pa->contact || pb->contact) { + if (! (pa->contact && pb->contact)) + return FALSE; + + if (pa->contact == pb->contact || !strcmp (e_contact_get_const (pa->contact, E_CONTACT_UID), + e_contact_get_const (pb->contact, E_CONTACT_UID))) + return TRUE; + + return FALSE; + } + + /* Just in case name returns NULL */ + na = eab_destination_get_name (a); + nb = eab_destination_get_name (b); + if ((na || nb) && !(na && nb && ! e_utf8_casefold_collate (na, nb))) + return FALSE; + + if (!g_ascii_strcasecmp (eab_destination_get_email (a), eab_destination_get_email (b))) + return TRUE; + else + return FALSE; +} + +void +eab_destination_set_contact (EABDestination *dest, EContact *contact, gint email_num) +{ + g_return_if_fail (dest && EAB_IS_DESTINATION (dest)); + g_return_if_fail (contact && E_IS_CONTACT (contact)); + + if (dest->priv->contact != contact || dest->priv->email_num != email_num) { + /* We have to freeze/thaw around these operations so that the 'changed' + signals don't cause the EABDestination's internal state to be altered + before we can finish setting ->contact && ->email_num. */ + eab_destination_freeze (dest); + eab_destination_clear (dest); + + dest->priv->contact = contact; + g_object_ref (dest->priv->contact); + + dest->priv->email_num = email_num; + + eab_destination_changed (dest); + eab_destination_thaw (dest); + } +} + +static void +eab_destination_set_book_uri (EABDestination *dest, const gchar *uri) +{ + g_return_if_fail (dest && EAB_IS_DESTINATION (dest)); + g_return_if_fail (uri != NULL); + + if (dest->priv->book_uri == NULL || strcmp (dest->priv->book_uri, uri)) { + g_free (dest->priv->book_uri); + dest->priv->book_uri = g_strdup (uri); + + eab_destination_changed (dest); + } +} + +void +eab_destination_set_contact_uid (EABDestination *dest, const gchar *uid, gint email_num) +{ + g_return_if_fail (dest && EAB_IS_DESTINATION (dest)); + g_return_if_fail (uid != NULL); + + if (dest->priv->uid == NULL + || strcmp (dest->priv->uid, uid) + || dest->priv->email_num != email_num) { + + g_free (dest->priv->uid); + dest->priv->uid = g_strdup (uid); + dest->priv->email_num = email_num; + + /* If we already have a contact, remove it unless it's uid matches the one + we just set. */ + if (dest->priv->contact && strcmp (uid, + e_contact_get_const (dest->priv->contact, E_CONTACT_UID))) { + g_object_unref (dest->priv->contact); + dest->priv->contact = NULL; + } + + eab_destination_changed (dest); + } +} + +void +eab_destination_set_name (EABDestination *dest, const gchar *name) +{ + gboolean changed = FALSE; + + g_return_if_fail (EAB_IS_DESTINATION (dest)); + + if (name == NULL) { + if (dest->priv->name != NULL) { + g_free (dest->priv->name); + dest->priv->name = NULL; + changed = TRUE; + } + } else if (dest->priv->name == NULL || strcmp (dest->priv->name, name)) { + g_free (dest->priv->name); + dest->priv->name = g_strdup (name); + changed = TRUE; + } + + if (changed) { + g_free (dest->priv->addr); + dest->priv->addr = NULL; + g_free (dest->priv->textrep); + dest->priv->textrep = NULL; + eab_destination_changed (dest); + } +} + +void +eab_destination_set_email (EABDestination *dest, const gchar *email) +{ + gboolean changed = FALSE; + + g_return_if_fail (EAB_IS_DESTINATION (dest)); + + if (email == NULL) { + if (dest->priv->email != NULL) { + g_free (dest->priv->addr); + dest->priv->addr = NULL; + changed = TRUE; + } + } else if (dest->priv->email == NULL || strcmp (dest->priv->email, email)) { + g_free (dest->priv->email); + dest->priv->email = g_strdup (email); + changed = TRUE; + } + + if (changed) { + g_free (dest->priv->addr); + dest->priv->addr = NULL; + g_free (dest->priv->textrep); + dest->priv->textrep = NULL; + eab_destination_changed (dest); + } +} + +void +eab_destination_set_html_mail_pref (EABDestination *dest, gboolean x) +{ + g_return_if_fail (dest && EAB_IS_DESTINATION (dest)); + + dest->priv->html_mail_override = TRUE; + if (dest->priv->wants_html_mail != x) { + dest->priv->wants_html_mail = x; + eab_destination_changed (dest); + } +} + +gboolean +eab_destination_contains_contact (const EABDestination *dest) +{ + g_return_val_if_fail (dest && EAB_IS_DESTINATION (dest), FALSE); + return dest->priv->contact != NULL; +} + +gboolean +eab_destination_from_contact (const EABDestination *dest) +{ + g_return_val_if_fail (dest && EAB_IS_DESTINATION (dest), FALSE); + return dest->priv->contact != NULL || dest->priv->book_uri != NULL || dest->priv->uid != NULL; +} + +gboolean +eab_destination_is_auto_recipient (const EABDestination *dest) +{ + g_return_val_if_fail (dest && EAB_IS_DESTINATION (dest), FALSE); + + return dest->priv->auto_recipient; +} + +void +eab_destination_set_auto_recipient (EABDestination *dest, gboolean value) +{ + g_return_if_fail (dest && EAB_IS_DESTINATION (dest)); + + dest->priv->auto_recipient = value; +} + +typedef struct _UseContact UseContact; +struct _UseContact { + EABDestination *dest; + EABDestinationContactCallback cb; + gpointer closure; +}; + +static void +use_contact_cb (EContact *contact, gpointer closure) +{ + UseContact *uc = (UseContact *) closure; + + if (contact != NULL && uc->dest->priv->contact == NULL) { + uc->dest->priv->contact = contact; + g_object_ref (uc->dest->priv->contact); + eab_destination_changed (uc->dest); + } + + if (uc->cb) { + uc->cb (uc->dest, uc->dest->priv->contact, uc->closure); + } + + /* We held a copy of the destination during the callback. */ + g_object_unref (uc->dest); + g_free (uc); +} + +void +eab_destination_use_contact (EABDestination *dest, EABDestinationContactCallback cb, gpointer closure) +{ + g_return_if_fail (dest && EAB_IS_DESTINATION (dest)); + + if (dest->priv->contact != NULL) { + if (cb) + cb (dest, dest->priv->contact, closure); + } else if (dest->priv->book_uri != NULL && dest->priv->uid != NULL) { + UseContact *uc = g_new (UseContact, 1); + + uc->dest = dest; + /* Hold a reference to the destination during the callback. */ + g_object_ref (uc->dest); + uc->cb = cb; + uc->closure = closure; +#if notyet + e_contact_load_uri (dest->priv->book_uri, dest->priv->uid, use_contact_cb, uc); +#endif + } else { + if (cb) + cb (dest, NULL, closure); + } +} + +EContact * +eab_destination_get_contact (const EABDestination *dest) +{ + g_return_val_if_fail (dest && EAB_IS_DESTINATION (dest), NULL); + + return dest->priv->contact; +} + +const gchar * +eab_destination_get_contact_uid (const EABDestination *dest) +{ + g_return_val_if_fail (dest && EAB_IS_DESTINATION (dest), NULL); + + if (dest->priv->uid) + return dest->priv->uid; + + if (dest->priv->contact) + return e_contact_get_const (dest->priv->contact, E_CONTACT_UID); + + return NULL; +} + +const gchar * +eab_destination_get_book_uri (const EABDestination *dest) +{ + g_return_val_if_fail (dest && EAB_IS_DESTINATION (dest), NULL); + + return dest->priv->book_uri; +} + +gint +eab_destination_get_email_num (const EABDestination *dest) +{ + g_return_val_if_fail (dest && EAB_IS_DESTINATION (dest), -1); + + if (dest->priv->contact == NULL && (dest->priv->book_uri == NULL || dest->priv->uid == NULL)) + return -1; + + return dest->priv->email_num; +} + +const gchar * +eab_destination_get_name (const EABDestination *dest) +{ + struct _EABDestinationPrivate *priv; + + g_return_val_if_fail (dest && EAB_IS_DESTINATION (dest), NULL); + + priv = (struct _EABDestinationPrivate *)dest->priv; /* cast out const */ + + if (priv->name == NULL) { + if (priv->contact != NULL) { + priv->name = e_contact_get (priv->contact, E_CONTACT_FULL_NAME); + + if (priv->name == NULL || *priv->name == '\0') { + g_free (priv->name); + priv->name = e_contact_get (priv->contact, E_CONTACT_FILE_AS); + } + + if (priv->name == NULL || *priv->name == '\0') { + g_free (priv->name); + if (e_contact_get (priv->contact, E_CONTACT_IS_LIST)) + priv->name = g_strdup (_("Unnamed List")); + else + priv->name = g_strdup (eab_destination_get_email (dest)); + } + } else if (priv->raw != NULL) { + CamelInternetAddress *addr = camel_internet_address_new (); + + if (camel_address_unformat (CAMEL_ADDRESS (addr), priv->raw)) { + const char *camel_name = NULL; + + camel_internet_address_get (addr, 0, &camel_name, NULL); + priv->name = g_strdup (camel_name); + } + + camel_object_unref (CAMEL_OBJECT (addr)); + } + } + + return priv->name; +} + +const gchar * +eab_destination_get_email (const EABDestination *dest) +{ + struct _EABDestinationPrivate *priv; + + g_return_val_if_fail (dest && EAB_IS_DESTINATION (dest), NULL); + + priv = (struct _EABDestinationPrivate *)dest->priv; /* cast out const */ + + if (priv->email == NULL) { + if (priv->contact != NULL) { + /* Pull the address out of the card. */ + GList *email = e_contact_get (priv->contact, E_CONTACT_EMAIL); + if (email) { + char *e = g_list_nth_data (email, priv->email_num); + + if (e) + priv->email = g_strdup (e); + } + if (email) { + g_list_foreach (email, (GFunc)g_free, NULL); + g_list_free (email); + } + + } else if (priv->raw != NULL) { + CamelInternetAddress *addr = camel_internet_address_new (); + + if (camel_address_unformat (CAMEL_ADDRESS (addr), priv->raw)) { + const gchar *camel_email = NULL; + camel_internet_address_get (addr, 0, NULL, &camel_email); + priv->email = g_strdup (camel_email); + } + + camel_object_unref (CAMEL_OBJECT (addr)); + } + + /* Force e-mail to be non-null... */ + if (priv->email == NULL) { + priv->email = g_strdup (""); + } + } + + return priv->email; +} + +const gchar * +eab_destination_get_address (const EABDestination *dest) +{ + struct _EABDestinationPrivate *priv; + + g_return_val_if_fail (dest && EAB_IS_DESTINATION (dest), NULL); + + priv = (struct _EABDestinationPrivate *)dest->priv; /* cast out const */ + + if (priv->addr == NULL) { + CamelInternetAddress *addr = camel_internet_address_new (); + + if (eab_destination_is_evolution_list (dest)) { + GList *iter = dest->priv->list_dests; + + while (iter) { + EABDestination *list_dest = EAB_DESTINATION (iter->data); + + if (!eab_destination_is_empty (list_dest)) { + camel_internet_address_add (addr, + eab_destination_get_name (list_dest), + eab_destination_get_email (list_dest)); + } + iter = g_list_next (iter); + } + + priv->addr = camel_address_encode (CAMEL_ADDRESS (addr)); + } else if (priv->raw) { + + if (camel_address_unformat (CAMEL_ADDRESS (addr), priv->raw)) { + priv->addr = camel_address_encode (CAMEL_ADDRESS (addr)); + } + } else { + camel_internet_address_add (addr, + eab_destination_get_name (dest), + eab_destination_get_email (dest)); + + priv->addr = camel_address_encode (CAMEL_ADDRESS (addr)); + } + + camel_object_unref (CAMEL_OBJECT (addr)); + } + + return priv->addr; +} + +void +eab_destination_set_raw (EABDestination *dest, const gchar *raw) +{ + g_return_if_fail (EAB_IS_DESTINATION (dest)); + g_return_if_fail (raw != NULL); + + if (dest->priv->raw == NULL || strcmp (dest->priv->raw, raw)) { + eab_destination_freeze (dest); + + eab_destination_clear (dest); + dest->priv->raw = g_strdup (raw); + eab_destination_changed (dest); + + eab_destination_thaw (dest); + } +} + +const gchar * +eab_destination_get_textrep (const EABDestination *dest, gboolean include_email) +{ + const char *name, *email; + + g_return_val_if_fail (dest && EAB_IS_DESTINATION (dest), NULL); + + if (dest->priv->raw) + return dest->priv->raw; + + name = eab_destination_get_name (dest); + email = eab_destination_get_email (dest); + + if (eab_destination_from_contact (dest) && name != NULL && (!include_email || !email || !*email)) + return name; + + /* Make sure that our address gets quoted properly */ + if (name && email && dest->priv->textrep == NULL) { + CamelInternetAddress *addr = camel_internet_address_new (); + + camel_internet_address_add (addr, name, email); + g_free (dest->priv->textrep); + dest->priv->textrep = camel_address_format (CAMEL_ADDRESS (addr)); + camel_object_unref (CAMEL_OBJECT (addr)); + } + + if (dest->priv->textrep != NULL) + return dest->priv->textrep; + + if (email) + return email; + + return ""; +} + +gboolean +eab_destination_is_evolution_list (const EABDestination *dest) +{ + g_return_val_if_fail (dest && EAB_IS_DESTINATION (dest), FALSE); + + if (dest->priv->list_dests == NULL + && dest->priv->contact != NULL + && e_contact_get (dest->priv->contact, E_CONTACT_IS_LIST)) { + GList *email = e_contact_get (dest->priv->contact, E_CONTACT_EMAIL); + if (email) { + GList *iter; + for (iter = email; iter; iter = iter->next) { + EABDestination *list_dest = eab_destination_import ((char *) iter->data); + + if (list_dest) + dest->priv->list_dests = g_list_append (dest->priv->list_dests, list_dest); + } + } + } + + return dest->priv->list_dests != NULL; +} + +gboolean +eab_destination_list_show_addresses (const EABDestination *dest) +{ + g_return_val_if_fail (EAB_IS_DESTINATION (dest), FALSE); + + if (dest->priv->contact != NULL) + return GPOINTER_TO_UINT (e_contact_get (dest->priv->contact, E_CONTACT_LIST_SHOW_ADDRESSES)); + + return dest->priv->show_addresses; +} + +gboolean +eab_destination_get_html_mail_pref (const EABDestination *dest) +{ + g_return_val_if_fail (dest && EAB_IS_DESTINATION (dest), FALSE); + + if (dest->priv->html_mail_override || dest->priv->contact == NULL) + return dest->priv->wants_html_mail; + + return e_contact_get (dest->priv->contact, E_CONTACT_WANTS_HTML) ? TRUE : FALSE; +} + +static void +set_book (EABDestination *dest, EBook *book) +{ + if (dest->priv->book && dest->priv->book != book) { + g_object_unref (dest->priv->book); + } + + dest->priv->book = book; + + if (book) + g_object_ref (book); +} + +static void +name_and_email_cb (EBook *book, EBookStatus status, GList *contacts, gpointer closure) +{ + EABDestination *dest = EAB_DESTINATION (closure); + + if (status == E_BOOK_ERROR_OK && g_list_length ((GList *) contacts) == 1) { + EContact *contact = E_CONTACT (contacts->data); + const char *email = eab_destination_get_email (dest); + int email_num = 0; + +#if notyet + if (eab_destination_is_valid (dest) && email && *email) { + email_num = e_contact_email_find_number (contact, eab_destination_get_email (dest)); + } +#endif + + if (email_num >= 0) { + const char *book_uri; + + book_uri = e_book_get_uri (book); + + dest->priv->contact_loaded = TRUE; + eab_destination_set_contact (dest, contact, email_num); + eab_destination_set_book_uri (dest, book_uri); + g_signal_emit (dest, eab_destination_signals[CONTACT_LOADED], 0); + } + } + + if (!dest->priv->contact_loaded) + dest->priv->cannot_load = TRUE; + + g_object_unref (dest); /* drop the reference held by the query */ +} + + +static void +nickname_cb (EBook *book, EBookStatus status, GList *contacts, gpointer closure) +{ + EABDestination *dest = EAB_DESTINATION (closure); + + if (status == E_BOOK_ERROR_OK) { + if (g_list_length ((GList *) contacts) == 1) { + const char *book_uri; + + book_uri = e_book_get_uri (book); + + dest->priv->contact_loaded = TRUE; + eab_destination_set_contact (dest, E_CONTACT (contacts->data), 0); /* Uses primary e-mail by default. */ + eab_destination_set_book_uri (dest, book_uri); + g_signal_emit (dest, eab_destination_signals[CONTACT_LOADED], 0); + + g_object_unref (dest); /* drop the reference held by the query */ + + } else { + /* We can only end up here if we don't look at all like an e-mail address, so + we do a name-only query on the textrep */ + + eab_name_and_email_query (book, + eab_destination_get_textrep (dest, FALSE), + NULL, + name_and_email_cb, + dest); + } + } else { + /* Something went wrong with the query: drop our ref to the destination and return. */ + g_object_unref (dest); + } +} + +static void +launch_load_contact_query (EABDestination *dest) +{ + if (! eab_destination_is_valid (dest)) { + /* If it doesn't look like an e-mail address, see if it is a nickname. */ + eab_nickname_query (dest->priv->book, + eab_destination_get_textrep (dest, FALSE), + nickname_cb, + dest); + + } else { + eab_name_and_email_query (dest->priv->book, + eab_destination_get_name (dest), + eab_destination_get_email (dest), + name_and_email_cb, + dest); + } +} + +void +eab_destination_load_contact (EABDestination *dest, EBook *book) +{ + g_return_if_fail (EAB_IS_DESTINATION (dest)); + g_return_if_fail (book == NULL || E_IS_BOOK (book)); + + if (eab_destination_is_evolution_list (dest)) + return; + + if (eab_destination_contains_contact (dest)) + return; + + if (dest->priv->cannot_load) + return; + + eab_destination_cancel_contact_load (dest); + + set_book (dest, book); + + /* Handle the case of an EABDestination containing a contact URL */ + if (eab_destination_contains_contact (dest)) { + eab_destination_use_contact (dest, NULL, NULL); + return; + } + + /* We hold a reference to ourselves until our query is complete. */ + g_object_ref (dest); + launch_load_contact_query (dest); +} + +static int +do_load_delayed (gpointer ptr) +{ + EABDestination *dest = EAB_DESTINATION (ptr); + + eab_destination_load_contact (dest, dest->priv->book); + return FALSE; +} + +void +eab_destination_load_contact_delayed (EABDestination *dest, EBook *book, gint delay) +{ + g_return_if_fail (EAB_IS_DESTINATION (dest)); + g_return_if_fail (book == NULL || E_IS_BOOK (book)); + + if (delay < 0) + delay = 500; + + eab_destination_cancel_contact_load (dest); + + set_book (dest, book); + + dest->priv->pending_contact_load = g_timeout_add (delay, do_load_delayed, dest); +} + +void +eab_destination_cancel_contact_load (EABDestination *dest) +{ + g_return_if_fail (EAB_IS_DESTINATION (dest)); + + if (dest->priv->pending_contact_load) { + g_source_remove (dest->priv->pending_contact_load); + dest->priv->pending_contact_load = 0; + } +} + +gboolean +eab_destination_unload_contact (EABDestination *dest) +{ + char *email; + + g_return_val_if_fail (EAB_IS_DESTINATION (dest), FALSE); + + if (!eab_destination_contains_contact (dest)) + return FALSE; + + email = g_strdup (eab_destination_get_email (dest)); + + if (email == NULL) + return FALSE; + + eab_destination_freeze (dest); + eab_destination_clear (dest); + eab_destination_set_raw (dest, email); + g_free (email); + eab_destination_thaw (dest); + + return TRUE; +} + +/* + * Destination import/export + */ + +gchar * +eab_destination_get_address_textv (EABDestination **destv) +{ + int i, j, len = 0; + char **strv; + char *str; + + g_return_val_if_fail (destv, NULL); + + /* Q: Please tell me this is only for assertion + reasons. If this is considered to be ok behavior then you + shouldn't use g_return's. Just a reminder ;-) + + A: Yes, this is just an assertion. (Though it does find the + length of the vector in the process...) + */ + while (destv[len]) { + g_return_val_if_fail (EAB_IS_DESTINATION (destv[len]), NULL); + len++; + } + + strv = g_new0 (char *, len + 1); + for (i = 0, j = 0; destv[i]; i++) { + if (!eab_destination_is_empty (destv[i])) { + const char *addr = eab_destination_get_address (destv[i]); + strv[j++] = addr ? (char *) addr : ""; + } + } + + str = g_strjoinv (", ", strv); + + g_free (strv); + + return str; +} + +xmlNodePtr +eab_destination_xml_encode (const EABDestination *dest) +{ + xmlNodePtr dest_node; + const char *str; + + g_return_val_if_fail (dest && EAB_IS_DESTINATION (dest), NULL); + + dest_node = xmlNewNode (NULL, "destination"); + + str = eab_destination_get_name (dest); + if (str) + xmlNewTextChild (dest_node, NULL, "name", str); + + if (!eab_destination_is_evolution_list (dest)) { + str = eab_destination_get_email (dest); + if (str) + xmlNewTextChild (dest_node, NULL, "email", str); + } else { + GList *iter = dest->priv->list_dests; + + while (iter) { + EABDestination *list_dest = EAB_DESTINATION (iter->data); + xmlNodePtr list_node = xmlNewNode (NULL, "list_entry"); + + str = eab_destination_get_name (list_dest); + if (str) + xmlNewTextChild (list_node, NULL, "name", str); + + str = eab_destination_get_email (list_dest); + if (str) + xmlNewTextChild (list_node, NULL, "email", str); + + xmlAddChild (dest_node, list_node); + + iter = g_list_next (iter); + } + + xmlNewProp (dest_node, "is_list", "yes"); + xmlNewProp (dest_node, "show_addresses", + eab_destination_list_show_addresses (dest) ? "yes" : "no"); + } + + str = eab_destination_get_book_uri (dest); + if (str) { + xmlNewTextChild (dest_node, NULL, "book_uri", str); + } + + str = eab_destination_get_contact_uid (dest); + if (str) { + char buf[16]; + + xmlNodePtr uri_node = xmlNewTextChild (dest_node, NULL, "card_uid", str); + g_snprintf (buf, 16, "%d", eab_destination_get_email_num (dest)); + xmlNewProp (uri_node, "email_num", buf); + } + + xmlNewProp (dest_node, "html_mail", eab_destination_get_html_mail_pref (dest) ? "yes" : "no"); + + xmlNewProp (dest_node, "auto_recipient", + eab_destination_is_auto_recipient (dest) ? "yes" : "no"); + + return dest_node; +} + +gboolean +eab_destination_xml_decode (EABDestination *dest, xmlNodePtr node) +{ + char *name = NULL, *email = NULL, *book_uri = NULL, *card_uid = NULL; + gboolean is_list = FALSE, show_addr = FALSE, auto_recip = FALSE; + gboolean html_mail = FALSE; + GList *list_dests = NULL; + int email_num = -1; + char *tmp; + + g_return_val_if_fail (dest && EAB_IS_DESTINATION (dest), FALSE); + g_return_val_if_fail (node != NULL, FALSE); + + if (strcmp (node->name, "destination")) + return FALSE; + + tmp = xmlGetProp (node, "html_mail"); + if (tmp) { + html_mail = !strcmp (tmp, "yes"); + xmlFree (tmp); + } + + tmp = xmlGetProp (node, "is_list"); + if (tmp) { + is_list = !strcmp (tmp, "yes"); + xmlFree (tmp); + } + + tmp = xmlGetProp (node, "show_addresses"); + if (tmp) { + show_addr = !strcmp (tmp, "yes"); + xmlFree (tmp); + } + + tmp = xmlGetProp (node, "auto_recipient"); + if (tmp) { + auto_recip = !strcmp (tmp, "yes"); + xmlFree (tmp); + } + + node = node->xmlChildrenNode; + while (node) { + if (!strcmp (node->name, "name")) { + tmp = xmlNodeGetContent (node); + g_free (name); + name = g_strdup (tmp); + xmlFree (tmp); + } else if (!is_list && !strcmp (node->name, "email")) { + tmp = xmlNodeGetContent (node); + g_free (email); + email = g_strdup (tmp); + xmlFree (tmp); + } else if (is_list && !strcmp (node->name, "list_entry")) { + xmlNodePtr subnode = node->xmlChildrenNode; + char *list_name = NULL, *list_email = NULL; + + while (subnode) { + if (!strcmp (subnode->name, "name")) { + tmp = xmlNodeGetContent (subnode); + g_free (list_name); + list_name = g_strdup (tmp); + xmlFree (tmp); + } else if (!strcmp (subnode->name, "email")) { + tmp = xmlNodeGetContent (subnode); + g_free (list_email); + list_email = g_strdup (tmp); + xmlFree (tmp); + } + + subnode = subnode->next; + } + + if (list_name || list_email) { + EABDestination *list_dest = eab_destination_new (); + + if (list_name) + eab_destination_set_name (list_dest, list_name); + if (list_email) + eab_destination_set_email (list_dest, list_email); + + g_free (list_name); + g_free (list_email); + + list_dests = g_list_append (list_dests, list_dest); + } + } else if (!strcmp (node->name, "book_uri")) { + tmp = xmlNodeGetContent (node); + g_free (book_uri); + book_uri = g_strdup (tmp); + xmlFree (tmp); + } else if (!strcmp (node->name, "card_uid")) { + tmp = xmlNodeGetContent (node); + g_free (card_uid); + card_uid = g_strdup (tmp); + xmlFree (tmp); + + tmp = xmlGetProp (node, "email_num"); + email_num = atoi (tmp); + xmlFree (tmp); + } + + node = node->next; + } + + eab_destination_freeze (dest); + + eab_destination_clear (dest); + + if (name) { + eab_destination_set_name (dest, name); + g_free (name); + } + if (email) { + eab_destination_set_email (dest, email); + g_free (email); + } + if (book_uri) { + eab_destination_set_book_uri (dest, book_uri); + g_free (book_uri); + } + if (card_uid) { + eab_destination_set_contact_uid (dest, card_uid, email_num); + g_free (card_uid); + } + if (list_dests) + dest->priv->list_dests = list_dests; + + dest->priv->html_mail_override = TRUE; + dest->priv->wants_html_mail = html_mail; + + dest->priv->show_addresses = show_addr; + + dest->priv->auto_recipient = auto_recip; + + eab_destination_thaw (dest); + + return TRUE; +} + +/* FIXME: Make utf-8 safe */ +static gchar * +null_terminate_and_remove_extra_whitespace (xmlChar *xml_in, gint size) +{ + gboolean skip_white = FALSE; + char *xml, *r, *w; + + if (xml_in == NULL || size <= 0) + return NULL; + + xml = g_strndup (xml_in, size); + r = w = xml; + + while (*r) { + if (*r == '\n' || *r == '\r') { + skip_white = TRUE; + } else { + gboolean is_space = isspace (*r); + + *w = *r; + + if (!(skip_white && is_space)) + w++; + if (!is_space) + skip_white = FALSE; + } + r++; + } + + *w = '\0'; + + return xml; +} + +gchar * +eab_destination_export (const EABDestination *dest) +{ + xmlNodePtr dest_node; + xmlDocPtr dest_doc; + xmlChar *buffer = NULL; + int size = -1; + char *str; + + g_return_val_if_fail (dest && EAB_IS_DESTINATION (dest), NULL); + + dest_node = eab_destination_xml_encode (dest); + if (dest_node == NULL) + return NULL; + + dest_doc = xmlNewDoc (XML_DEFAULT_VERSION); + xmlDocSetRootElement (dest_doc, dest_node); + + xmlDocDumpMemory (dest_doc, &buffer, &size); + xmlFreeDoc (dest_doc); + + str = null_terminate_and_remove_extra_whitespace (buffer, size); + xmlFree (buffer); + + return str; +} + +EABDestination * +eab_destination_import (const gchar *str) +{ + EABDestination *dest = NULL; + xmlDocPtr dest_doc; + + if (!(str && *str)) + return NULL; + + dest_doc = xmlParseMemory ((char *) str, strlen (str)); + if (dest_doc && dest_doc->xmlRootNode) { + dest = eab_destination_new (); + if (! eab_destination_xml_decode (dest, dest_doc->xmlRootNode)) { + g_object_unref (dest); + dest = NULL; + } + } + xmlFreeDoc (dest_doc); + + return dest; +} + +gchar * +eab_destination_exportv (EABDestination **destv) +{ + xmlDocPtr destv_doc; + xmlNodePtr destv_node; + xmlChar *buffer = NULL; + int i, size = -1; + char *str; + + if (destv == NULL || *destv == NULL) + return NULL; + + destv_doc = xmlNewDoc (XML_DEFAULT_VERSION); + destv_node = xmlNewNode (NULL, "destinations"); + xmlDocSetRootElement (destv_doc, destv_node); + + for (i = 0; destv[i]; i++) { + if (! eab_destination_is_empty (destv[i])) { + xmlNodePtr dest_node = eab_destination_xml_encode (destv[i]); + if (dest_node) + xmlAddChild (destv_node, dest_node); + } + } + + xmlDocDumpMemory (destv_doc, &buffer, &size); + xmlFreeDoc (destv_doc); + + str = null_terminate_and_remove_extra_whitespace (buffer, size); + xmlFree (buffer); + + return str; +} + +EABDestination ** +eab_destination_importv (const gchar *str) +{ + GPtrArray *dest_array = NULL; + xmlDocPtr destv_doc; + xmlNodePtr node; + EABDestination **destv = NULL; + + if (!(str && *str)) + return NULL; + + destv_doc = xmlParseMemory ((char *)str, strlen (str)); + if (destv_doc == NULL) + return NULL; + + node = destv_doc->xmlRootNode; + + if (strcmp (node->name, "destinations")) + goto finished; + + node = node->xmlChildrenNode; + + dest_array = g_ptr_array_new (); + + while (node) { + EABDestination *dest; + + dest = eab_destination_new (); + if (eab_destination_xml_decode (dest, node) && !eab_destination_is_empty (dest)) { + g_ptr_array_add (dest_array, dest); + } else { + g_object_unref (dest); + } + + node = node->next; + } + + /* we need destv to be NULL terminated */ + g_ptr_array_add (dest_array, NULL); + + destv = (EABDestination **) dest_array->pdata; + g_ptr_array_free (dest_array, FALSE); + + finished: + xmlFreeDoc (destv_doc); + + return destv; +} + +EABDestination ** +eab_destination_list_to_vector_sized (GList *list, int n) +{ + EABDestination **destv; + int i = 0; + + if (n == -1) + n = g_list_length (list); + + if (n == 0) + return NULL; + + destv = g_new (EABDestination *, n + 1); + while (list != NULL && i < n) { + destv[i] = EAB_DESTINATION (list->data); + list->data = NULL; + i++; + list = g_list_next (list); + } + destv[i] = NULL; + + return destv; +} + +EABDestination ** +eab_destination_list_to_vector (GList *list) +{ + return eab_destination_list_to_vector_sized (list, -1); +} + +void +eab_destination_freev (EABDestination **destv) +{ + int i; + + if (destv) { + for (i = 0; destv[i] != NULL; ++i) { + g_object_unref (destv[i]); + } + g_free (destv); + } + +} + +#if notyet +static void +touch_cb (EBook *book, const gchar *addr, ECard *card, gpointer closure) +{ + if (book != NULL && card != NULL) { + e_card_touch (card); + d(g_message ("Use score for \"%s\" is now %f", addr, e_card_get_use_score (card))); + e_book_commit_card (book, card, NULL, NULL); + } +} +#endif + +void +eab_destination_touch (EABDestination *dest) +{ +#if notyet + const char *email; + + g_return_if_fail (dest && EAB_IS_DESTINATION (dest)); + + if (!eab_destination_is_auto_recipient (dest)) { + email = eab_destination_get_email (dest); + + if (email) + e_book_query_address_default (email, touch_cb, NULL); + } +#endif +} + +void +eab_destination_touchv (EABDestination **destv) +{ +#if notyet + int i; + + g_return_if_fail (destv != NULL); + + for (i = 0; destv[i] != NULL; ++i) { + eab_destination_touch (destv[i]); + } +#endif +} diff --git a/addressbook/util/eab-destination.h b/addressbook/util/eab-destination.h new file mode 100644 index 0000000000..452d893e44 --- /dev/null +++ b/addressbook/util/eab-destination.h @@ -0,0 +1,128 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ + +/* + * eab-destination.h + * + * Copyright (C) 2001-2003 Ximian, Inc. + * + * Authors: Jon Trowbridge + * Chris Toshok + */ + +/* + * This program is free software; you can redistribute it and/or + * modify it under the terms of version 2 of the GNU General Public + * License as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + * USA. + */ + +#ifndef __E_DESTINATION_H__ +#define __E_DESTINATION_H__ + +#include +#include +#include +#include +#include + +#define EAB_TYPE_DESTINATION (eab_destination_get_type ()) +#define EAB_DESTINATION(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), EAB_TYPE_DESTINATION, EABDestination)) +#define EAB_DESTINATION_CLASS(k) (G_TYPE_CHECK_CLASS_CAST ((k), EAB_TYPE_DESTINATION, EABDestinationClass)) +#define EAB_IS_DESTINATION(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), EAB_TYPE_DESTINATION)) +#define EAB_IS_DESTINATION_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), EAB_TYPE_DESTINATION)) +#define EAB_DESTINATION_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), EAB_TYPE_DESTINATION, EABDestinationClass)) + +typedef struct _EABDestination EABDestination; +typedef struct _EABDestinationClass EABDestinationClass; + +typedef void (*EABDestinationContactCallback) (EABDestination *dest, EContact *contact, gpointer closure); + +struct _EABDestinationPrivate; + +struct _EABDestination { + GObject object; + + struct _EABDestinationPrivate *priv; +}; + +struct _EABDestinationClass { + GObjectClass parent_class; + + void (*changed) (EABDestination *dest); + void (*contact_loaded) (EABDestination *dest); +}; + +GType eab_destination_get_type (void); + + +EABDestination *eab_destination_new (void); +void eab_destination_changed (EABDestination *); +EABDestination *eab_destination_copy (const EABDestination *); +void eab_destination_clear (EABDestination *); + +gboolean eab_destination_is_empty (const EABDestination *); +gboolean eab_destination_equal (const EABDestination *a, const EABDestination *b); + +void eab_destination_set_contact (EABDestination *, EContact *contact, gint email_num); + +void eab_destination_set_name (EABDestination *, const gchar *name); +void eab_destination_set_email (EABDestination *, const gchar *email); + +void eab_destination_set_html_mail_pref (EABDestination *, gboolean); + +gboolean eab_destination_contains_contact (const EABDestination *); + +gboolean eab_destination_is_auto_recipient (const EABDestination *); +void eab_destination_set_auto_recipient (EABDestination *, gboolean value); + +void eab_destination_use_contact (EABDestination *, EABDestinationContactCallback cb, gpointer closure); + +EContact *eab_destination_get_contact (const EABDestination *); +gint eab_destination_get_email_num (const EABDestination *); + +const gchar *eab_destination_get_name (const EABDestination *); /* "Jane Smith" */ +const gchar *eab_destination_get_email (const EABDestination *); /* "jane@assbarn.com" */ +const gchar *eab_destination_get_address (const EABDestination *);; /* "Jane Smith " (or a comma-sep set of such for a list) */ + +void eab_destination_set_raw (EABDestination *, const gchar *free_form_string); +const gchar *eab_destination_get_textrep (const EABDestination *, gboolean include_email); /* "Jane Smith" or "jane@assbarn.com" */ + +gboolean eab_destination_is_evolution_list (const EABDestination *); +gboolean eab_destination_list_show_addresses (const EABDestination *); + +/* If true, they want HTML mail. */ +gboolean eab_destination_get_html_mail_pref (const EABDestination *); + +void eab_destination_load_contact (EABDestination *, EBook *); +void eab_destination_load_contact_delayed (EABDestination *, EBook *, gint delay); /* delay < 0: "default" */ +void eab_destination_cancel_contact_load (EABDestination *); +gboolean eab_destination_unload_contact (EABDestination *); + +gchar *eab_destination_get_address_textv (EABDestination **); + +gchar *eab_destination_export (const EABDestination *); +EABDestination *eab_destination_import (const gchar *str); + +gchar *eab_destination_exportv (EABDestination **); +EABDestination **eab_destination_importv (const gchar *str); + +EABDestination **eab_destination_list_to_vector_sized (GList *, int n); +EABDestination **eab_destination_list_to_vector (GList *); + +void eab_destination_freev (EABDestination **); + +void eab_destination_touch (EABDestination *); +void eab_destination_touchv (EABDestination **); + + +#endif /* __EAB_DESTINATION_H__ */ + diff --git a/addressbook/util/eab-marshal.list b/addressbook/util/eab-marshal.list new file mode 100644 index 0000000000..680ea039a3 --- /dev/null +++ b/addressbook/util/eab-marshal.list @@ -0,0 +1,5 @@ +NONE:NONE +NONE:BOOL +NONE:POINTER +NONE:STRING +NONE:INT diff --git a/calendar/ChangeLog b/calendar/ChangeLog index 0d6fb57dfe..023e9f7ecd 100644 --- a/calendar/ChangeLog +++ b/calendar/ChangeLog @@ -1,9 +1,239 @@ -2003-10-17 Jeffrey Stedfast +2003-10-21 Rodrigo Moya - * conduits/calendar/Makefile.am: Fixed for libical changes. + * gui/calendar-component.c (calendar_component_init): fixed + a leak caused by only freeing 'base_uri' in some cases. + +2003-10-21 JP Rosevear + + * gui/control-factory.c (get_prop): fix parse error + (set_prop): gnome_calendar_open was renamed + + * conduits/todo/todo-conduit.c (start_calendar_server): adapt to + the cal_client_new changes and the lack of a default calendar + routine + (pre_sync): don't have to pass a type for the default object any + more + + * conduits/calendar/calendar-conduit.c (start_calendar_server): + adapt to the cal_client_new changes and the lack of a default + calendar routine + (pre_sync): don't have to pass a type for the default object any + more + + * cal-client/cal-client.c (cal_client_open_async): add FIXME + comment + +2003-10-21 Rodrigo Moya + + * pcs/cal-backend-file.c: store recurrences per object. + (free_object): free correctly the CalBackendFileObject's + contained in 'priv->comp_uid_hash'. + (lookup_component, check_dup_uid, add_component, remove_component, + match_object_sexp): + adapted to changes in comp_uid_hash. + +2003-10-20 Rodrigo Moya + + * gui/gnome-cal.[ch] (gnome_calendar_add_event_uri): renamed + from gnome_calendar_open. + + * gui/calendar-component.c (load_uri_for_source): call + gnome_calendar_add_event_uri instead of setting the URI property on + the Bonobo control. + +2003-10-17 Rodrigo Moya + + * gui/migration.c (process_calendar_dir): process subfolders. + +2003-10-17 Rodrigo Moya + + * gui/migration.[ch] (migrate_old_calendars): new function. + + * gui/calendar-component.c (calendar_component_init): call + the above function to migrate from old setups. + + * gui/Makefile.am: added new files. + +2003-10-17 Jeffrey Stedfast + + * conduits/calendar/Makefile.am: Fixed for libical build changes. * conduits/todo/Makefile.am: Same. +2003-10-17 Rodrigo Moya + + * gui/e-cal-view.c (on_print): call + e_cal_view_get_visible_time_range, not the gnome_calendar_ + version. + (e_cal_view_new_appointment_for, e_cal_view_new_appointment, + e_cal_view_edit_appointment): new functions. + + * gui/gnome-cal.[ch] (gnome_calendar_new_appointment_for, + gnome_calendar_new_appointment, gnome_calendar_edit_object): + removed these functions, now available in e-cal-view. + + * gui/calendar-commands.c: + * gui/e-day-view.c: + * gui/e-week-view-event-item.c: + * gui/e-week-view.c: replaced calls to gnome_calendar_* with + e_cal_view_* equivalents. + +2003-10-17 Rodrigo Moya + + * gui/e-cal-view.[ch] (e_cal_view_get_default_category): + (e_cal_view_set_default_category): new functions. + (e_cal_view_destroy): free the default_category field. + + * gui/e-day-view.[ch] (e_day_view_set_default_category): + removed obsolete function. + (e_day_view_init, e_day_view_destroy, e_day_view_do_key_press): + use the ECalView's default_category. + + * gui/e-week-view.[ch] (e_week_view_set_default_category): + removed obsolete function. + (e_week_view_init, e_week_view_destroy, e_week_view_do_key_press): + use the ECalView's default_category. + + * gui/gnome-cal.c (gnome_calendar_set_query): set the query + also on the list view by using the priv->views array. + (search_bar_category_changed_cb, gnome_calendar_set_default_client): + use the priv->views array. + (gnome_calendar_get_calendar_model): return the model for the + current view widget. + (gnome_calendar_open): removed tasks opening code. + +2003-10-16 Rodrigo Moya + + * gui/dialogs/new-calendar.c (new_calendar_dialog): if the user + presses Cancel, just terminate. + +2003-10-16 Rodrigo Moya + + * gui/calendar-component.c (calendar_component_init): create + directories for the newly-created calendars. + + * gui/dialogs/new-calendar.c (create_new_source_with_group): use + e_mkdir_hier instead of mkdir. + +2003-10-16 Rodrigo Moya + + * gui/calendar-component.c (calendar_component_init): if no groups + are present in the configuration, create the "On This Computer" + group and the "Personal" and "Work" calendars on it. + + * gui/dialogs/new-calendar.c (new_calendar_dialog): moved the + source creation... + (create_new_source_with_group): ...here, and made the code create + the directory for the new calendar. + +2003-10-15 Hans Petter Jansson + + * gui/e-select-names-editable.c (e_selct_names_editable_get_address): + EDestination -> EABDestination. + + * gui/gnome-cal.c (setup_widgets): evolution_dir -> ".evolution". + +2003-10-15 Rodrigo Moya + + * gui/e-select-names-editable.c (e_select_names_editable_get_address): + use EABDestination instead of EDestination. + + * gui/gnome-cal.c (gnome_calendar_open): disabled tasks opening code. + +2003-10-15 Rodrigo Moya + + * gui/e-meeting-list-view.c: adapted to new addressbook API. + + * gui/e-meeting-store.c: adapted to new addressbook API. + (find_zone): fixed usage of icalcomponent where an icalproperty + is expected. + (refresh_busy_periods): fixed call to cal_client_get_free_busy(). + + * gui/e-meeting-time-sel.c (e_meeting_time_selector_construct): + added missing variable. + +2003-10-15 Jeffrey Stedfast + + * gui/dialogs/meeting-page.c: #include + +2003-10-15 Rodrigo Moya + + * gui/e-meeting-list-view.c (start_addressbook_server): + updated to new addressbook API. + (book_open_cb): removed unneeded function, since we load + the local addressbook synchronously. + +2003-10-15 Rodrigo Moya + + * pcs/Makefile.am: added missing header directories. + + * pcs/cal-factory.h: include , not . + + * gui/dialogs/meeting-page.c: added missing headers. + (meeting_page_construct): free 'backend_address' as returned + by cal_client_get_cal_address(). Removed code to create the + meeting model's ETable not removed with the merge. + + * gui/e-meeting-list-view.c: updated addressbook headers. + + * gui/gnome-cal.h: added missing ',' in the GnomeCalendarViewType + enum. + +2003-10-14 Rodrigo Moya + + * gui/e-day-view.c (e_day_view_update_query): dont set status + messages here, already set in e_cal_view_update_query. + (update_query): removed this function. + (e_day_view_recalc_day_starts): call e_day_view_update_query, + not update_query. + + * gui/e-week-view.c (e_week_view_update_query): dont set status + messages here, already set in e_cal_view_update_query. + + * gui/gnome-cal.c (adjust_query_for_view): new function to adjust + the query for the visible time range on a given view. + (gnome_calendar_set_query): call adjust_query_for_view for each + one of the views. + +2003-10-14 Rodrigo Moya + + * gui/e-cal-view.c (e_cal_view_init): connect to signals on the + model we create here, so that we get notifications for changes. + + * gui/gnome-cal.c (gnome_calendar_set_query): set the query + on all models. + (gnome_calendar_open): update the date navigator query. + +2003-10-14 Rodrigo Moya + + * pcs/cal.c (cal_notify_timezone_requested): never send NULL + strings to ORBit. + + * gui/e-cal-view.c (e_cal_view_create_popup_menu): removed + unneeded variables. Also, fixed a typo that was making the + menu options be disabled when they should be enabled. + +2003-10-13 Rodrigo Moya + + * gui/e-cal-model.[ch] (e_cal_model_get_client_for_uri): new function. + + * gui/gnome-cal.[ch] (gnome_calendar_set_default_client): new function. + + * gui/calendar-component.c (primary_source_selection_changed_callback): + set the default client on the calendar view to be the primary + selection on the source list. + +2003-10-13 Rodrigo Moya + + * gui/dialogs/new-calendar.c (new_calendar_dialog): set a default group + on the calendar group option menu and create the source if all checks + are passed. + +2003-10-12 Rodrigo Moya + + * gui/dialogs/new-calendar.c (new_calendar_dialog): set up widgets + loaded from the Glade file. + 2003-10-10 Hans Petter Jansson * gui/Makefile.am (etspec_DATA): Add e-cal-list-view.etspec. @@ -44,6 +274,66 @@ * gui/e-cal-list-view.[ch]: Implement ECalListView, subclassing ECalView. +2003-10-10 Rodrigo Moya + + * gui/dialogs/new-calendar.[ch]: added new widget, which implements + the dialog to create new calendars. + + * gui/dialogs/new-calendar.glade: basic mockup of the dialog. + + * gui/dialogs/Makefile.am: added new files. + + * gui/calendar-commands.c (file_new_calendar_cb): open the new calendar + dialog to allow user to create a new cal. + +2003-10-10 Rodrigo Moya + + * gui/control-factory.c (calendar_properties_init): pass the + BonoboControl to get_prop/set_prop. + (get_prop): obtain the GnomeCalendar from the control. + (set_prop): ditto, and when the URI property is changed, + sensitize the UI as approppriate. + + * gui/calendar-commands.c (calendar_control_sensitize_calendar_commands): + made this function public. + + * gui/calendar-commands.h: added new prototype. + +2003-10-10 Rodrigo Moya + + * gui/calendar-commands.c (file_new_calendar_cb, + file_new_appointment_cb, file_new_event_cb, file_new_meeting_cb, + file_new_task_cb): callbacks for "New..." verbs. + (sensitize_calendar_commands): sensitize new verbs, and made it + sensitize correctly based on the set of clients currently loaded. + (sensitize_taskpad_commands): likewise. + +2003-10-09 Hans Petter Jansson + + * gui/e-cal-model.c (get_classification): Adapt to libical API changes. + (ecm_set_value_at): Break after each case, so we don't set the passed value + in more than one field. + +2003-10-09 Rodrigo Moya + + * gui/e-cal-view.c (e_cal_view_delete_selected_occurrence): + * cal-client/cal-client.c (cal_client_remove_object): added missing + argument when calling cal_client_remove_object_with_mod(). + +2003-10-09 Rodrigo Moya + + * idl/evolution-calendar.idl: added missing 'rid' argument to the + removeObject method. + + * cal-client/cal-client.c (cal_client_remove_object_with_mod): + * pcs/cal-backend.h: + * pcs/cal-backend.c (cal_backend_remove_object): + * pcs/cal-backend-sync.h: + * pcs/cal-backend-sync.c (cal_backend_sync_remove_object, + _cal_backend_remove_object): + * pcs/cal-backend-file.c (cal_backend_file_remove_object): + * pcs/cal.c (impl_cal_removeObject): adapted to changes in IDL. + 2003-10-09 Jeffrey Stedfast * cal-client/Makefile.am: INCLUDE path fixes for changes made to @@ -84,58 +374,1110 @@ 2003-10-08 Harry Lu - * gui/dialogs/alarm-options.glade: Make repeat-quantity and - repeat-value of alarm option dialog numeric only. + * gui/dialogs/alarm-options.glade: Make repeat-quantity and + repeat-value of alarm option dialog numeric only. + + * gui/dialogs/task-details-page.glade: Make percent-complete of + task details dialog numeric only. + +2003-10-08 Chris Toshok + + * gui/dialogs/e-delegate-dialog.c (e_delegate_dialog_construct): + EDestination => EABDestination, and e_destination => + eab_destination. + (e_delegate_dialog_get_delegate): same. + (e_delegate_dialog_get_delegate_name): same. + + * gui/dialogs/comp-editor-util.c: remove unnecessary #include of + e-destination.h. + + * gui/dialogs/alarm-options.c (alarm_to_malarm_widgets): + EDestination => EABDestination, and e_destination => + eab_destination. + (malarm_widgets_to_alarm): same. + + * gui/e-meeting-model.c (book_open_cb): track change to error + return codes. + (start_addressbook_server): use + e_book_async_get_default_addressbook. + (contacts_cb): rename cursor_cb to this, as we no longer get + passed a cursur, and we don't need to check the email address + since the query is now "is" instead of "contains". + (refresh_busy_periods): use an "is" query, and use + e_book_async_get_contacts instead of getting a CardCursor. + (process_section): this takes an EABDestination** instead of a + SimpleCardList*, which is gone. + (select_names_ok_cb): get "destinations" instead of + "simple_card_list". + +2003-10-08 Rodrigo Moya + + * cal-client/cal-client.c (cal_client_is_read_only): fixed + documentation comments. + + * gui/calendar-commands.c (sensitize_calendar_commands): figure + out read-only menu items to disable based on the currently + selected object's CalClient. + +2003-10-08 Rodrigo Moya + + * cal-client/cal-client.c: set better error m,essages on the + E_CALENDAR_CHECK_STATUS macro. + (cal_client_get_error_message): new function. + + * cal-client/cal-client.h: added new prototype. + + * gui/dialogs/comp-editor.c (save_comp): use the GError argument + for the cal_client_create/_modify_object calls, and display the + error message coming from the backend. + + * gui/comp-util.c (cal_comp_is_on_server): likewise. + +2003-10-07 Dan Winship + + * idl/evolution-calendar.idl (getDefaultObject): Remove the "type" + arg; the backend knows what type it is + + * pcs/cal.c (impl_Cal_getDefaultObject): Likewise + + * pcs/cal-backend.c (cal_backend_get_default_object): Likewise + + * pcs/cal-backend-sync.c (cal_backend_sync_get_default_object, + _cal_backend_get_default_object): Likewise + + * pcs/cal-backend-file.c (cal_backend_file_get_default_object): + Likewise. (Use cal_backend_get_kind() instead.) + + * cal-client/cal-client.c (cal_client_get_default_object): + Likewise + + * gui/comp-util.c (cal_comp_event_new_with_defaults, + cal_comp_task_new_with_defaults): Update calls to + cal_client_get_default_object(). + + * pcs/cal-backend-sync.c (_cal_backend_get_static_capabilities): + Use the right cal notification + +2003-10-07 Rodrigo Moya + + * gui/e-cal-model.c (e_cal_model_create_component_with_defaults): + dont clone NULL icalcomponent's. + +2003-10-07 Rodrigo Moya + + * gui/e-cal-model.c (e_cal_model_get_default_client): make sure we + always return a default client, if possible, since we rely on having + a default client in many places. + + * gui/e-day-view.c (e_day_view_do_key_press): dont create event if + e_cal_model_create_component_with_defaults returns NULL. + + * gui/e-week-view.c (e_week_view_do_key_press): dont create event if + e_cal_model_create_component_with_defaults returns NULL. + +2003-10-06 Rodrigo Moya + + * gui/e-cal-model.c (e_cal_model_create_component_with_defaults): + make sure the component has always an UID. + + * gui/e-day-view.c (e_day_view_find_event_from_uid): + * gui/e-week-view.c (e_week_view_find_event_from_uid): check + pointers passed to strcmp(). + +2003-10-06 Rodrigo Moya + + * gui/gnome-cal.c (gnome_calendar_open): added missing call to + cal_client_open(). + + * cal-client/cal-client.c (cal_client_new): fixed documentation + comments. + (cal_client_open): emit CAL_OPENED signal with appropriate status codes. + (open_sync): dont emit CAL_OPENED signal, it's already emitted in + cal_client_open(). + +2003-10-06 Rodrigo Moya + + * gui/comp-editor-factory.c (open_client): + * gui/gnome-cal.c (gnome_calendar_open, gnome_calendar_construct): + * gui/calendar-offline-handler.c (backend_go_offline, backend_go_online, + calendar_offline_handler_init): adapted to changes in cal_client and + manage GError's returned by cal_client_open. + + * gui/e-itip-control.c: dont run anymore sub event loops. + (start_calendar_server): use synchronous interface for opening calendars. + (start_default_server): renamed it from *_async. + (start_calendar_server_cb): removed unneeded function. + (object_requested_cb): use sync interface. + + * gui/e-tasks.c (e_tasks_construct): dont create the CalClient here. + (e_tasks_open): do it here, where we've got all the info needed. + + * importers/icalendar-importer.c (update_single_object): killed warning. + (ical_importer_new, vcal_importer_new): don't create CalClient's here. + (load_file_fn): create them here. + (vcal_load_file_fn): and here. + (gnome_calendar_import_data_fn): fixed usage of cal_client_*. + + * */*: integrated JP's changes for synchronous open's in cal_client + and one model per view instead of one model for all views. + +2003-10-02 Rodrigo Moya + + * cal-client/cal-client.c (cal_client_modify_object): return FALSE + if the icalcomponent is NULL. + + * gui/e-day-view.c (e_day_view_finish_resize): commit sequence on + CalComponent after changing start/end dates. + +2003-10-01 Rodrigo Moya + + * gui/e-day-view.c (process_component): + * gui/e-week-view.c (process_component): expand recurrences here. + +2003-09-30 Rodrigo Moya + + * pcs/cal-backend-file.c (match_recurrence_sexp): removed. + (match_object_sexp): dont expand recurrences here. + +2003-09-30 Mike Kestner + + * cal-util/cal-util-marshal.list : new VOID:STRING,STRING,STRING + * gui/Makefile.am : build the new view/store/renderer/editable + * gui/e-select-names-renderer.* : new completion cell renderer + * gui/e-select-names-editable.* : new completion cell editable + * gui/e-meeting-model.* : killed. code reused in list-view/store + * gui/e-meeting-store.* : port of EMeetingModel to GtkTreeModel + * gui/e-meeting-list-view.* : GtkTreeView subclass for attendee lists + * gui/e-meeting-time-sel.c : Use the new store/view + * gui/e-meeting-time-sel-item.c : Use the new store/view + * gui/dialogs/Makefile.am : don't install the etspec anymore. + * gui/dialogs/event-editor.c : Use the new store/view. + * gui/dialogs/meeting-page.c : Use the new store/view. + * gui/dialogs/shedule-page.c : Use the new store/view. + * gui/dialogs/task-editor.c : Use the new store/view. + +2003-09-29 JP Rosevear + + * conduits/todo/Makefile.am: link to libical-evolution + + * conduits/calendar/Makefile.am: ditto + +2003-09-26 JP Rosevear + + * pcs/cal-backend.c (cal_backend_class_init): remove cal_added + signal + +2003-09-26 JP Rosevear + + * pcs/cal.h: add protos + + * pcs/cal.c (cal_get_backend): accessor + (cal_get_listener): ditto + + * pcs/cal-factory.c (impl_CalFactory_getCal): update to new + routine name + + * pcs/cal-backend.h: add protos + + * pcs/cal-backend.c (cal_backend_init): init client mutex + (cal_backend_finalize): destroy client mutex + (cal_destroy_cb): just remove the client + (listener_died_cb): remove the client, the listener died so it + can't really do anything + (last_client_gone): signal the last client gone + (cal_backend_add_client): add a client with locking and listen for + the death of the listener + (cal_backend_remove_client): remove client + +2003-09-26 Rodrigo Moya + + * pcs/cal-backend-sync.c (_cal_backend_create_object): only free the + returned UID if it's not NULL. + + * pcs/cal.c (cal_notify_object_created): dont send NULL strings to + ORBit code. + +2003-09-26 Rodrigo Moya + + * gui/comp-util.c (cal_comp_is_on_server): free the icalcomponent + returned from cal_client_get_object, and return TRUE if we find + the component on the backend. + + * gui/e-day-view.c (process_component): + * gui/e-week-view.c (process_component): added missing case, so that + we also display recurrent meetings starting before the time range and + ending after the time range. + + * cal-client/cal-listener.c (impl_notifyReadOnly): pass the + 'read_only' argument to the signal callback correctly (a gboolean + not a 'gboolean *'). + + * gui/comp-editor-factory.c (resolve_pending_requests): removed + the g_assert on 'oc->pending != NULL', since there are now cases + (local calendar) where we get to call this function (cal_opened_cb) + with no pending requests yet. + +2003-09-25 JP Rosevear + + * gui/calendar-commands.c (publish_freebusy_cmd): adapt to new + get_free_busy api + + * conduits/calendar/calendar-conduit.c (post_sync): ditto + (pre_sync): ditto + + * conduits/todo/todo-conduit.c (pre_sync): ditto + (post_sync): ditto + + * gui/e-meeting-model.c (refresh_busy_periods): ditto + + * gui/e-itip-control.c (send_freebusy): ditto + + * gui/e-cal-view.c (on_publish): ditto + + * cal-client/cal-listener.h: add signals + + * cal-client/cal-listener.c (build_change_list): move here from + cal-client.c + (impl_notifyChanges): implement + (build_free_busy_list): util to create the GList of free busy + objects + (impl_notifyFreeBusy): implement + (cal_listener_class_init): set free busy and changes epv methods, + add signals + + * cal-client/cal-client.h: update protos + + * cal-client/cal-client.c (cal_get_changes_cb): get changes call + back + (cal_get_free_busy_cb): get free busy call back + (cal_client_init): listen for free busy and changes signals + (cal_client_get_changes): convert to new threaded sync api + (cal_client_get_free_busy): ditto + + * pcs/cal.h: add protos + + * pcs/cal.c: remove dead type conversion function + (impl_Cal_getChanges): implement by just calling, no return stuff + (impl_Cal_getFreeBusy): ditto + (cal_notify_changes): do getChanges callback + (cal_notify_free_busy): do getFreeBusy callback + + * pcs/cal-backend.h: update protos, vmethods + + * pcs/cal-backend.c (cal_backend_get_free_busy): call through + (cal_backend_get_changes): ditto + + * pcs/cal-backend-sync.h: add vmethods, protos + + * pcs/cal-backend-sync.c (cal_backend_sync_get_changes): call + through + (cal_backend_sync_get_free_busy): ditto + (_cal_backend_get_changes): backend implementation, notify + (_cal_backend_get_free_busy): ditto + (cal_backend_sync_class_init): set free busy and changes + implementations + + * pcs/cal-backend-file.c (cal_backend_file_get_free_busy): convert + to sync backend method + (cal_backend_file_compute_changes_foreach_key): remove from the + hash here + (cal_backend_file_compute_changes): no need to build the sequence + here + (cal_backend_file_get_changes): convert to sync backend method + (cal_backend_file_class_init): set sync backend methods for free + busy and changes + + * idl/evolution-calendar.idl: convert getChanges and getFreeBusy + to new async api + +2003-09-25 JP Rosevear + + * pcs/cal-backend.h: remove dead result enums + + * pcs/cal-backend.c: fix comments + + * idl/evolution-calendar.idl: remove dead exceptions + +2003-09-25 JP Rosevear + + * pcs/cal.c (cal_notify_default_object): send back the empty + string if the object is NULL + (cal_notify_object): ditto + +2003-09-25 JP Rosevear + + * gui/comp-editor-factory.c (edit_existing): convert to api + changes + + * conduits/todo/todo-conduit.c (local_record_from_uid): ditto + (pre_sync): ditto + + * conduits/calendar/calendar-conduit.c (local_record_from_uid): + ditto + (pre_sync): ditto + + * importers/icalendar-importer.c (update_single_object): ditto + + * gui/dialogs/comp-editor.c (obj_updated_cb): ditto + + * gui/e-itip-control.c (get_real_item): ditto + (find_server): ditto + + * gui/comp-util.c (cal_comp_is_on_server): ditto + (cal_comp_event_new_with_defaults): ditto + (cal_comp_task_new_with_defaults): ditto + + * cal-client/cal-listener.h: add signals + + * cal-client/cal-listener.c (impl_notifyDefaultObjectRequested): + implement + (impl_notifyObjectRequested): ditto + (cal_listener_class_init): set above epv implementations, add signals + + * cal-client/cal-client.h: update protos + + * cal-client/cal-client.c (cal_default_object_requested_cb): get + default object callback + (cal_object_requested_cb): get object callback + (cal_client_init): listen for get and get default object signals + (cal_client_get_default_object): convert to new sync api + (cal_client_get_object): ditto + + * pcs/cal.h: add protos + + * pcs/cal.c (impl_Cal_getDefaultObject): just call the backend, it + does the notification now + (impl_Cal_getObject): ditto + (cal_notify_default_object): do getDefaultObject response + (cal_notify_object): do getObject response + + * pcs/cal-backend.h: remove vmethods, protos + + * pcs/cal-backend.c: remove a couple of dead functions + (cal_backend_class_init): get_object_component is no longer a + vmethod + (cal_backend_get_default_object): call through + (cal_backend_get_object): ditto + + * pcs/cal-backend-sync.h: add protos, vmethods + + * pcs/cal-backend-sync.c (cal_backend_sync_get_default_object): + call through + (cal_backend_sync_get_object): ditto + (_cal_backend_discard_alarm): pass correct params to + cal_notify_discard_alarm + (_cal_backend_get_default_object): call through and notify + (_cal_backend_get_object): ditto + (cal_backend_sync_class_init): set backend implementations + + * pcs/cal-backend-file.c (cal_backend_file_get_default_object): + convert to sync backend method + (cal_backend_file_get_object): ditto + (cal_backend_file_compute_changes_foreach_key): just look up the + component rather than using the backend vmethod + (cal_backend_file_remove_object): return valid sync status codes + (cal_backend_file_class_init): move get_object, get_default_object + to sync class + + * idl/evolution-calendar.idl: convert getObject and + getDefaultObject to new async idl + +2003-09-25 JP Rosevear + + * pcs/cal.c (impl_Cal_discardAlarm): just call the backend + function, it does the notification + (cal_notify_alarm_discarded): notify of discard alarm call + + * pcs/cal-backend.h: update proto + + * pcs/cal-backend.c (cal_backend_discard_alarm): call through + + * pcs/cal-backend-sync.h: add proto, vmethod + + * pcs/cal-backend-sync.c (cal_backend_sync_discard_alarm): call + through + (_cal_backend_discard_alarm): call through and notify + (cal_backend_sync_class_init): set discard alarm implementation + + * pcs/cal-backend-file.c (cal_backend_file_discard_alarm): match + sync backend vmethod + (cal_backend_file_class_init): set alarm vmethod implementation + + * idl/evolution-calendar.idl: switch discardAlarm to new api + + * gui/alarm-notify/alarm-queue.c (remove_queued_alarm): match new + api + + * cal-client/cal-listener.h: add signal + + * cal-client/cal-listener.c (impl_notifyAlarmDiscarded): implement + (cal_listener_class_init): add alarm, send, receive epv functions, + alarm signal + + * cal-client/cal-client.h: update proto + + * cal-client/cal-client.c (cal_alarm_discarded_cb): discardAlarm + callback + (cal_client_init): listen to discard alarm signal + (cal_client_discard_alarm): implement with new threaded sync api + +2003-09-25 JP Rosevear + + * idl/evolution-calendar.idl: remove unused user exceptions + +2003-09-24 Rodrigo Moya + + * pcs/cal-backend-util.[ch] (cal_backend_util_fill_alarm_instances_seq): + removed unneeded function. + +2003-09-24 JP Rosevear + + * conduits/*/*.c: adjust to new timezone api calls + + * gui/*.c: ditto + + * gui/dialogs/*.c: ditto + + * cal-client/cal-listener.h: add new signals + + * cal-client/cal-listener.c (convert_status): convert invalid + object as well + (impl_notifyTimezoneRequested): implement + (impl_notifyDefaultTimezoneSet): ditto + (cal_listener_class_init): set epv implementations for timezone + functions + (cal_listener_class_init): create timezone response signals + + * cal-client/cal-client.h: update protos + + * cal-client/cal-client.c: fix return values all over the place + (cal_get_timezone_cb): getTimezone response + (cal_query_cb): setDefaultTimezone response + (cal_client_init): listen for new response signals + (cal_client_get_timezone): implement using new thread sync api + (cal_client_ensure_timezone_on_server): use add timezone call + (cal_client_set_default_timezone): oimplement using new thread sync + api + + * cal-client/cal-client-types.h: add invalid object status code + + * idl/evolution-calendar.idl: getQuery no longer raises any user + exceptions, remove dead types and exceptions + +2003-09-24 JP Rosevear + + * pcs/cal.h: new protos + + * pcs/cal.c (impl_Cal_getTimezone): call backend implementation + (impl_Cal_addTimezone): ditto + (impl_Cal_setDefaultTimezone): ditto + (cal_class_init): set epv implementations of timezone functions + (cal_notify_timezone_requested): notify of get timezone response + (cal_notify_default_timezone_set): notify of default timezone + being set + + * pcs/cal-backend.h: new vmethods, protos + + * pcs/cal-backend.c (cal_backend_class_init): init new timezone + vmethods + (cal_backend_get_timezone): call through + (cal_backend_set_default_timezone): ditto + (cal_backend_add_timezone): ditto + (cal_backend_internal_get_default_timezone): ditto + (cal_backend_internal_get_timezone): ditto + + * pcs/cal-backend-sync.h: add vmethods, protos + + * pcs/cal-backend-sync.c (cal_backend_sync_get_timezone): call + through + (cal_backend_sync_set_default_timezone): ditto + (_cal_backend_set_default_timezone): call through and notify + (_cal_backend_get_timezone): ditto + (cal_backend_sync_class_init): set backend implementations for new + funcs + + * pcs/cal-backend-object-sexp.c (func_occur_in_time_range): get + time_t values based on the zone + + * pcs/cal-backend-file.c: reorg so we don't have to prototype + everything + (cal_backend_file_get_timezone): implement the sync backend way + (cal_backend_file_add_timezone): ditto + (cal_backend_file_set_default_timezone): ditto + (cal_backend_file_internal_get_default_timezone): internal method, + for sexp comparison + (cal_backend_file_internal_get_timezone): ditto + + * idl/evolution-calendar.idl: convert timezone routines to async + api + +2003-09-23 Rodrigo Moya + + * pcs/cal-backend-object-sexp.c (func_occur_in_time_range): dont expand + recurrences, since they are supposed to be expanded in the backends. + (instance_occur_cb, resolve_tzid): removed unneeded functions. + + * pcs/cal-backend-file.c (cal_backend_file_add_timezone): guard against + adding the timezone if it's already there. + +2003-09-23 JP Rosevear + + * pcs/cal.c (cal_notify_object_created): notify with the object, + not the uid + + * gui/e-cal-model.c (add_new_client): don't listen for + non-existent signal + +2003-09-23 JP Rosevear + + * cal-client/cal-client.h: remove dead proto + +2003-09-23 JP Rosevear + + * cal-client/cal-client.h: remove send result enum + + * gui/itip-utils.c (comp_server_send): use the new send_objects + routine + +2003-09-23 JP Rosevear + + * cal-client/cal-client.h: remove send result enum + +2003-09-23 JP Rosevear + + * cal-client/cal-client.h: remove enum, protos + + * cal-client/cal-client.c: remove remove status enum typing + +2003-09-23 Rodrigo Moya + + * importers/icalendar-importer.c (update_objects): new function + to manage the update of components, taking into account + VTIMEZONE components. + (process_item_fn, gnome_calendar_import_data_fn): use + update_objects instead of cal_client_update_objects. + +2003-09-23 JP Rosevear + + * pcs/cal.h: update proto + + * pcs/cal.c (impl_Cal_addTimezone): just call add_timezone, it + does the notification + (cal_notify_object_created): only notify the query if the object + matches + (cal_notify_object_removed): ditto + + * pcs/cal-backend.h: update proto, vmethod + + * pcs/cal-backend.c (cal_backend_add_timezone): returns void + + * pcs/cal-backend-sync.h: update proto, vmethod + + * pcs/cal-backend-sync.c (cal_backend_sync_remove_object): add the + object as an out param + (_cal_backend_remove_object): get the object and pass it in the + notification + + * pcs/cal-backend-file.c (cal_backend_file_create_object): kill + cal_backend_file_update_objects call, its more efficient to create + the comp ourselves; stamp the creation time, add the component to + the toplevel + (cal_backend_file_modify_object): kill the + cal_backend_file_update_objects call, add the component to the + toplevel + (cal_backend_file_remove_object): pass back the object when + removing + +2003-09-23 JP Rosevear + + * cal-client/cal-query.c (cal_query_finalize): disconnect the + signal handlers + + * cal-client/cal-client.c (cal_client_get_query): unref the + listener when done + +2003-09-23 Rodrigo Moya + + * gui/e-cal-view.c (selection_received): add VTIMEZONE components + contained in the clipboard data to the backend. + +2003-09-22 JP Rosevear + + * gui/dialogs/comp-editor.c (save_comp): modify and create instead + of update, simplify mod code + +2003-09-22 JP Rosevear + + * gui/e-day-view.c (e_day_view_finish_long_event_resize): modify + the object instead of update, simplify the instance handling + (e_day_view_finish_resize): ditto + (e_day_view_on_top_canvas_drag_data_received): ditto + (e_day_view_on_main_canvas_drag_data_received): ditto + +2003-09-22 Rodrigo Moya + + * cal-client/cal-client.c (cal_client_get_alarms_in_range): use + 'has-alarms' function in the search expression. + + * pcs/cal-backend-object-sexp.c (func_has_alarms): new SExp function. + +2003-09-22 JP Rosevear + + * gui/e-day-view.c (e_day_view_on_editing_stopped): create the + object if its not on the server or modify it if it is + + * gui/e-week-view.c (e_week_view_on_editing_stopped): we return if + there is no text and it *not* on the server + +2003-09-22 JP Rosevear + + * gui/e-week-view.c (e_week_view_on_editing_stopped): create the + object if its not on the server or modify it if it is + +2003-09-22 JP Rosevear + + * gui/gnome-cal.h: remove proto + + * gui/gnome-cal.c: remove gnome_calendar_unrecur_selection + + * gui/e-week-view.h: remove proto + + * gui/e-week-view.c: remove e_week_view_unrecur_appointment + + * gui/e-day-view.h: remove proto + + * gui/e-day-view.c: remove e_day_view_unrecur_appointment + + * gui/e-cal-view.c: remove on_unrecur_appointment (this is handled + better via recurrence id's now) + +2003-09-22 JP Rosevear + + * gui/e-itip-control.c (update_attendee_status): ifdef out, leave + temporarily for reference, but otherwise it shouldn't be needed + (update_item): switch to using receive objects + (ok_clicked_cb): update item when receiving a reply + + * gui/e-calendar-table.c (selection_received): switch to using + create object from update_objects + + * gui/e-cal-view.c (selection_received_add_event): util routine to + prevent duplication + (selection_received): use above + + * gui/e-cal-model.c (ecm_set_value_at): switch to using modify + object from update_objects + (ecm_append_row): switch to using create object from + update_objects + + * gui/e-cal-model-calendar.c (ecmc_set_value_at): switch to using + modify object from update_objects + + * gui/e-cal-model-tasks.c (ecmt_set_value_at): ditto + +2003-09-22 Hans Petter Jansson + + * cal-util/Makefile.am (libical_util_la_LIBADD): + libical.la -> libical-evolution.la + + * importers/Makefile.am (libevolution_calendar_importers_la_LIBADD): + libicalvcal.la -> libicalvcal-evolution.la + + +2003-09-19 Rodrigo Moya + + * idl/evolution-calendar.idl: removed getAlarmsInRange and + getAlarmsForObject methods. + + * pcs/cal.c (impl_Cal_getAlarmsInRange, impl_Cal_getAlarmsForObject): + removed unneeded CORBA methods. + (cal_class_init): dont set removed methods in the epv. + + * pcs/cal-backend.[ch]: removed get_alarms_in_range and + get_alarms_for_object virtual methods. + (cal_backend_get_alarms_in_range, cal_backend_get_alarms_for_object): + removed. + (cal_backend_class_init): dont set removed virtual methods. + + * pcs/cal-backend-file.c (cal_backend_file_get_alarms_in_range, + cal_backend_file_get_alarms_for_object): removed. + (cal_backend_file_class_init): dont set removed virtual methods. + +2003-09-19 Rodrigo Moya + + * cal-client/cal-client.c (cal_client_get_alarms_in_range): changed + to use queries. + (build_component_alarms_list): create the alarm list from a list + of iCalendar strings. + (build_alarm_instance_list): removed. + (cal_client_get_alarms_for_object): dont call the CORBA methods, + just get alarms by itself. + +2003-09-18 Rodrigo Moya + + * cal-client/cal-listener.[ch]: added "add_timezone" signal. + (impl_notifyTimezoneAdded): implemented new CalListener method. + (cal_listener_class_init): create "add_timezone" signal for the class. + + * cal-client/cal-client.[ch] (cal_client_add_timezone): new function. + (cal_client_init): connect to "add_timezone" signal on the + CalListener. + (cal_add_timezone_cb): callback for the "add_timezone" signal. + +2003-09-18 Rodrigo Moya + + * idl/evolution-calendar.idl: added 'notifyTimezoneAdded' method + to the Calendar::Listener interface. + + * pcs/cal-backend-sync.[ch] (cal_backend_sync_add_timezone): + (_cal_backend_add_timezone): new functions for the new virtual + method implementation. + + * pcs/cal.[ch] (cal_notify_timezone_added): new function. + + * pcs/cal-backend-file.c (cal_backend_add_timezone): converted to + return a CalBackendSyncStatus. + (cal_backend_file_class_init): the 'add_timezone' method we implement + is the one in the CalBackendSync class. + (cancel_receive_object): added missing 'return'. + (free_cal_component): removed unused function. + +2003-09-17 Rodrigo Moya + + * pcs/cal-backend-file.c (cal_backend_add_timezone): added new + virtual method implementation. + + * pcs/cal.c (impl_Cal_addTimezone): check return value from + cal_backend_add_timezone, and set an exception if an error is + returned. + +2003-09-16 Rodrigo Moya + + * idl/evolution-calendar.idl: added addTimezone method. + + * pcs/cal.c (impl_Cal_addTimezone): implemented new method. + (cal_class_init): set new method on the epv. + + * pcs/cal-backend.[ch]: added 'add_timezone' virtual method. + (cal_backend_add_timezone): implemented new virtual method. + + * pcs/cal-backend-file.c (cal_backend_file_modify_object): it's + cal_component_get_as_string, not cal_component_as_string. + + * cal-client/cal-client.c (cal_client_ensure_timezone_on_server): + dont use anymore updateObjects method, use addTimezone instead. + +2003-09-16 Rodrigo Moya + + * conduits/todo/Makefile.am: removed libwombat reference. + +2003-09-15 Rodrigo Moya + + * pcs/cal-backend-file.c (cal_backend_file_create_object): return + the UID of the added object. + (cal_backend_file_remove_object): ditto for old_object. + +2003-09-15 JP Rosevear + + * conduits/todo/todo-conduit.c (replace_record): switch to modify + object + (add_record): switch to using create object + + * conduits/calendar/calendar-conduit.c (process_multi_day): switch + to using create object + (add_record): switch to using create object + (replace_record): switch to modify object + + * cal-client/cal-listener.h: add signals + + * cal-client/cal-listener.c (impl_notifyObjectsReceived): + implement listener method + (build_object_list): ditto + (cal_listener_class_init): create receive_objects and send_objects + signals + + * cal-client/cal-client.h: add, update protos + + * cal-client/cal-client.c (cal_objects_received_cb): + receive_objects callback + (cal_objects_sent_cb): send_objects callback + (cal_client_init): listen for above signals + (cal_client_create_object): pass back uid + (cal_client_receive_objects): implement + (cal_client_send_objects): ditto + + * idl/evolution-calendar.idl: add receive/send objects methods and + yank updateObjects + + * pcs/cal.h: add protos + + * pcs/cal.c (impl_Cal_receiveObjects): implement + (impl_Cal_sendObjects): ditto + (cal_class_init): add epv methods + (cal_notify_objects_received): notify of objects received call, + updating queries + (cal_notify_objects_sent): notify of objects sent + + * pcs/cal-backend.h: remove proto + + * pcs/cal-backend.c (cal_backend_class_init): remove obj_updated + signal + (cal_backend_class_init): init vmethods properly + (cal_backend_receive_objects): call through + (cal_backend_send_objects): ditto + + * pcs/cal-backend-sync.h: add protos, vmethods + + * pcs/cal-backend-sync.c (cal_backend_sync_receive_objects): call + through + (cal_backend_sync_send_objects): ditto + (_cal_backend_receive_objects): call backend method and notify + (_cal_backend_send_objects): ditto + (cal_backend_sync_class_init): override send/receive object + vmethods + + * pcs/cal-backend-file.c (cal_backend_file_class_init): set + remove/send objects sync vmethods + (cal_backend_file_create_object): remove call to dead method + (cal_backend_file_remove_object): ditto + (cal_backend_file_modify_object): ditto + (cancel_received_object): cancel an object + (check_tzids): check we have all the tzid's for the object + (cal_backend_file_receive_objects): receive a bunch of objects via + itip + (cal_backend_file_send_objects): skeleton implementation + +2003-09-15 Rodrigo Moya + + * idl/evolution-calendar.idl: added InvalidObject CallStatus. + + * pcs/cal-backend-file.c (cal_backend_file_create_object): implemented. + (cal_backend_file_modify_object): implemented. + +2003-09-15 Harry Lu + + * gui/apps_evolution_calendar.schemas: change last_notification_time's + type from string to int. + +2003-09-12 Bolian Yin + + * e-week-view.c (e_week_view_focus): make jump button focusable + (e_week_view_on_jump_button_event): key_press and focus event for jump button + (e_week_view_jump_to_button_item): new function, jump to the day view. + (e_week_view_is_jump_button_visible): new function. + + +2003-09-12 Rodrigo Moya + + * pcs/cal.c (cal_notify_cal_address, cal_notify_alarm_email_address, + cal_notify_ldap_attribute, cal_notify_static_capability): + make sure we always notify listeners, regardless of whether the + string is empty or not. + + * cal-client/cal-client.c (check_capability): guard against using + NULL strings with strstr. + +2003-09-12 JP Rosevear + + * cal-client/client-test.c (cal_opened_cb): listen for other query + signals + + * cal-client/cal-listener.h: add signals + + * cal-client/cal-listener.c (impl_notifyObjectCreated): implement + (impl_notifyObjectModified): implement + (cal_listener_class_init): assign epv implementations + (cal_listener_class_init): add create/modify object signals + + * cal-client/cal-client.h: add protos + + * cal-client/cal-client.c (cal_object_created_cb): object created + callback + (cal_object_modified_cb): object modified callback + (cal_client_init): listen for create/modify object signals from + the listener + (cal_client_create_object): call the create object method + (cal_client_modify_object): call the modify object method + + * cal-client/client-test.c (cal_opened_cb): listen for all the + query signals, tidy + +2003-09-12 JP Rosevear + + * pcs/cal.c (impl_Cal_createObject): implement + (impl_Cal_modifyObject): ditto + (cal_class_init): set epv methods for create/modify + + * pcs/cal-backend.h: add protos, vmethod + + * pcs/cal-backend.c (cal_backend_class_init): init new vmethods + (cal_backend_create_object): call through + (cal_backend_modify_object): ditto + + * pcs/cal-backend-sync.h: add protos, vmethods + + * pcs/cal-backend-sync.c (cal_backend_sync_create_object): call + through + (cal_backend_sync_modify_object): ditto + (_cal_backend_create_object): create object and notify + (_cal_backend_modify_object): modify object and notify + + * pcs/cal-backend-file.c (cal_backend_file_create_object): + skeleton routine for creating objects + (cal_backend_file_modify_object): ditto for modifying + + * idl/evolution-calendar.idl: add createObject and modifyObject + calls + +2003-09-12 JP Rosevear + + * pcs/cal.c (cal_notify_object_removed): its uid, not uids + +2003-09-12 JP Rosevear + + * pcs/query.h: add protos + + * pcs/query.c (query_object_matches): use the sexp to check for a + match + (query_notify_objects_added_1): notify of one object added to + query + (query_notify_objects_modified_1): ditto for modification + (query_notify_objects_removed_1): ditto for removal + + * pcs/cal.h: add protos + + * pcs/cal.c (cal_notify_object_created): notify of object creation + (cal_notify_object_modified): notify of object modification + (cal_notify_object_removed): use the _1 routines + + * pcs/cal-backend-file.c (match_recurrence_sexp): this returns a + boolean + (cal_backend_file_update_objects): don't signal removals here now + + * idl/evolution-calendar.idl: add object created and modified + responses + + +2003-09-11 JP Rosevear + + * pcs/cal.h: update proto + + * pcs/cal.c (cal_notify_object_removed): notify relevant queries + of removal + + * pcs/cal-backend.c (cal_backend_get_queries): ref the list before + passing it back + + * pcs/cal-backend-sync.c (_cal_backend_remove_object): pass uid to + notification + +2003-09-11 JP Rosevear + + * pcs/cal-backend-file.c (match_recurrence_sexp): don't unref the + component + + * cal-client/client-test.c (cal_opened_cb): listen to objects + added signal + (objects_added_cb): print the object uid + +2003-09-11 JP Rosevear + + * pcs/cal-backend-object-sexp.c (cal_backend_object_sexp_text): + return the base text + +2003-09-11 JP Rosevear + + * gui/gnome-cal.c (update_query): fix c/p typo + +2003-09-11 JP Rosevear + + * gui/gnome-cal.c (update_query): start the query + + * gui/e-cal-model.c (update_query_for_client): ditto + + * cal-client/client-test.c (cal_opened_cb): ditto + +2003-09-11 JP Rosevear + + * cal-client/cal-query.h: add proto + + * cal-client/cal-query.c (cal_query_start): start the query + +2003-09-11 JP Rosevear + + * gui/dialogs/delete-error.c (delete_error_dialog): accept GError + and base error messages on that + + * gui/dialogs/delete-error.h: update proto + + * gui/e-tasks.c (e_tasks_delete_completed): pass extra param to + cal_client_remove_object + + * conduits/todo/todo-conduit.c (delete_record): ditto + + * conduits/calendar/calendar-conduit.c (process_multi_day): ditto + (delete_record): ditto + + * gui/gnome-cal.c (gnome_calendar_purge): ditto + + * gui/dialogs/comp-editor.c (delete_comp): ditto + + * gui/e-cal-view.c (e_cal_view_cut_clipboard): pass the error to + delete_error_dialog + (delete_event): ditto + (e_cal_view_delete_selected_occurrence): ditto + + * gui/e-itip-control.c (remove_item): ditto + + * gui/e-calendar-table.c (delete_selected_components): ditto + + * cal-client/cal-listener.h: add signal - * gui/dialogs/task-details-page.glade: Make percent-complete of - task details dialog numeric only. + * cal-client/cal-listener.c (impl_notifyObjectRemoved): implement + (cal_listener_class_init): set object removed implementation and + create signal -2003-09-30 Mike Kestner + * cal-client/cal-client.h: update protos - * cal-util/cal-util-marshal.list : new VOID:STRING,STRING,STRING - * gui/Makefile.am : build the new view/store/renderer/editable - * gui/e-select-names-renderer.* : new completion cell renderer - * gui/e-select-names-editable.* : new completion cell editable - * gui/e-meeting-model.* : killed. code reused in list-view/store - * gui/e-meeting-store.* : port of EMeetingModel to GtkTreeModel - * gui/e-meeting-list-view.* : GtkTreeView subclass for attendee lists - * gui/e-meeting-time-sel.c : Use the new store/view - * gui/e-meeting-time-sel-item.c : Use the new store/view - * gui/dialogs/Makefile.am : don't install the etspec anymore. - * gui/dialogs/event-editor.c : Use the new store/view. - * gui/dialogs/meeting-page.c : Use the new store/view. - * gui/dialogs/shedule-page.c : Use the new store/view. - * gui/dialogs/task-editor.c : Use the new store/view. + * cal-client/cal-client.c (cal_object_removed_cb): object removal + callback + (cal_client_init): listen for object removal signal + (cal_client_remove_object_with_mod): make call synchronous + (cal_client_remove_object): pass new params -2003-09-29 JP Rosevear + * pcs/cal.h: add proto - * conduits/todo/Makefile.am: link to libical-evolution + * pcs/cal.c (impl_Cal_removeObject): just call the backend + function + (cal_notify_object_removed): notify of removal - * conduits/calendar/Makefile.am: ditto - -2003-09-22 Hans Petter Jansson + * pcs/cal-backend.h: remove and update protos, remove signal - * cal-util/Makefile.am (libical_util_la_LIBADD): - libical.la -> libical-evolution.la + * pcs/cal-backend.c (cal_backend_class_init): kill obj_removed + signal + (cal_backend_remove_object): there is no return value now - * importers/Makefile.am (libevolution_calendar_importers_la_LIBADD): - libicalvcal.la -> libicalvcal-evolution.la + * pcs/cal-backend-sync.h: add vmethod, proto -2003-09-16 Rodrigo Moya + * pcs/cal-backend-sync.c (cal_backend_sync_remove_object): call + through + (_cal_backend_remove_object): remove the object and then do the + notification - * conduits/todo/Makefile.am: removed libwombat reference. + * pcs/cal-backend-file.c (cal_backend_file_class_init): remove + object is not part of the sync class + (cal_backend_file_update_objects): there is no more removed signal + (cal_backend_file_remove_object): return sync status codes -2003-09-15 Harry Lu + * idl/evolution-calendar.idl: make removeObject oneway and and a + notification method in the listener - * gui/apps_evolution_calendar.schemas: change last_notification_time's - type from string to int. +2003-09-11 Rodrigo Moya -2003-09-12 Bolian Yin + * pcs/query.[ch] (query_get_text): new function. + (query_get_object_sexp): new function. - * e-week-view.c (e_week_view_focus): make jump button focusable - (e_week_view_on_jump_button_event): key_press and focus event for jump button - (e_week_view_jump_to_button_item): new function, jump to the day view. - (e_week_view_is_jump_button_visible): new function. + * pcs/cal-backend-file.c (cal_backend_file_start_query): implemented. 2003-09-11 Hans Petter Jansson @@ -193,12 +1535,279 @@ Statically link with wombat. Fix ETodo conduit. (Mdk bug #5348) + +2003-09-10 JP Rosevear + + * pcs/cal.h: update proto + + * pcs/cal.c (impl_Cal_getObjectList): just call the backend, it + will do the notification now + (cal_notify_object_list): the list is a list of strings + + * pcs/cal-backend.h: update vmethod, proto + + * pcs/cal-backend.c (cal_backend_get_object_list): call through + + * pcs/cal-backend-sync.h: add proto, vmethod + + * pcs/cal-backend-sync.c (cal_backend_sync_get_object_list): call + through + (_cal_backend_get_object_list): get the list of objects from the + sync backend and do the notification + (cal_backend_sync_class_init): set vmethod implementation + + * pcs/cal-backend-file.c (cal_backend_file_class_init): the get + object list call is now part of the sync backend + (cal_backend_file_get_object_list): return a status and put the + object list in the passed in param + +2003-09-10 JP Rosevear + + * pcs/cal-backend.c (cal_backend_finalize): unref the elist + (cal_backend_init): init the query elist + +2003-09-10 JP Rosevear + + * gui/gnome-cal.c (dn_query_objects_added_cb): match new query + signals - just tag here + (dn_query_objects_modified_cb): always retag + (dn_query_objects_removed_cb): ditto + (update_query): connect to new signals + (gnome_calendar_destroy): we don't keep a list of expunging + queries + (gnome_calendar_purge): no need to do the + expunge async, just get the object list immediately + + * gui/e-tasks.c (e_tasks_delete_completed): no need to do the + expunge async, just get the object list immediately + + * gui/e-cal-model.c (query_objects_added_cb): callback for objects + added to the query + (query_objects_modified_cb): ditto for modifications + (query_objects_removed_cb): ditto for removed + (query_progress_cb): progress of the query + (query_done_cb): query is done + (update_query_for_client): connect to the new signals + + * cal-client/client-test.c (cal_opened_cb): run a query + + * cal-client/cal-query.c: we are given the listener now - listen + for signals from the listener and emit signals matching the api + changes + + * cal-client/query-listener.[hc]: rewrite to match new query + listener methods and emit signals rather than using function + callbacks + + * cal-client/cal-marshal.list: add to marshallers + + * cal-client/cal-listener.h: add query signal + + * cal-client/cal-listener.c (impl_notifyQuery): implement + (cal_listener_class_init): set notifyQuery method + (cal_listener_class_init): add query signal + + * cal-client/cal-client.h: update protos + + * cal-client/cal-client.c (cal_query_cb): handle response to + getQuery + (cal_client_init): listen for query signal + (cal_client_get_query): get a query from the calendar + + * pcs/query.h: update protos + + * pcs/query.c: rewrite to implement the query start method and + provide notification calls + + * pcs/cal.h: add proto + + * pcs/cal.c (impl_Cal_getQuery): re-implement so the backend + doesn't create the query for us + (cal_notify_query): respond with the query + + * pcs/cal-factory.c: re-order includes + + * pcs/cal-common.h: add types + + * pcs/cal-backend.h: update protos, vmethods + + * pcs/cal-backend.c (cal_backend_class_init): init start_query + vmethod + (cal_backend_finalize): free mutex + (cal_backend_start_query): call through + (cal_backend_add_query): add a query to the list the backend is + running + (cal_backend_get_queries): get the query list + + * pcs/cal-backend-object-sexp.h: add proto + + * pcs/cal-backend-file.c (cal_backend_file_start_query): skeleton + for new backend implementation + + * pcs/Makefile.am: don't build dead files + + * idl/evolution-calendar.idl: make the getQuery call async, make + the query listener calls oneway and match the addressbook + +2003-09-09 Rodrigo Moya + + * pcs/cal-backend-file.c (cal_backend_file_get_object_component): + added case for getting the individual recurrences if 'rid' is + not NULL, + +2003-09-09 Rodrigo Moya + + * pcs/cal-backend-file.c (match_object_sexp): expand recurrences + for recurrent objects. + (match_recurrence_sexp): add the recurrences that match the query + expression to the object list. + +2003-09-08 Rodrigo Moya + + * pcs/cal-backend-file.c: don't store all recurrences in the + private structure. + +2003-09-04 Rodrigo Moya + + * gui/e-day-view.c (process_component): + * gui/e-week-view.c (process_component): dont expand recurrences, + since they are now expanded by the backends. + +2003-09-02 JP Rosevear + + * gui/tasks-control.c (sensitize_commands): adapt to cal-client + threaded sync api changes + + * gui/itip-utils.c (itip_organizer_is_user): ditto + + * gui/gnome-cal.c (gnome_calendar_purge): ditto + + * gui/e-meeting-model.c (process_section): ditto + + * gui/e-calendar-table.c (e_calendar_table_show_popup_menu): ditto + + * gui/e-cal-view.c (e_cal_view_create_popup_menu): ditto + + * gui/calendar-commands.c (sensitize_calendar_commands): ditto + (sensitize_taskpad_commands): ditto + + * gui/dialogs/task-editor.c (set_menu_sens): ditto + + * gui/dialogs/meeting-page.c (meeting_page_construct): ditto + + * gui/dialogs/event-editor.c (set_menu_sens): ditto + + * gui/dialogs/alarm-page.c (add_clicked_cb): ditto + + * conduits/calendar/calendar-conduit.c (pre_sync): convert to + cal_client api changes + + * conduits/todo/todo-conduit.c (pre_sync): ditto + + * cal-client/client-test.c (list_uids): match new error handling + + * cal-client/cal-marshal.list: marshallers + + * cal-client/cal-listener.[hc]: emit signals for corba listener + callbacks - start with is_read_only, get_static_capabilities, + get_cal_address, get_ldap_attribute, open, remove and object_list + + * cal-client/cal-client.h: move the status enum away from here, + update protos to new thread sync api standard + + * cal-client/cal-client.c: the listener emits signals instead of + using callback functions now and we return booleans + GError in + outs for results + (e_calendar_error_quark): for GError handling + (cal_read_only_cb): handle listener op callback + (cal_cal_address_cb): ditto + (cal_alarm_address_cb): ditto + (cal_ldap_attribute_cb): ditto + (cal_static_capabilities_cb): ditto + (cal_opened_cb): ditto + (cal_removed_cb): ditto + (cal_object_list_cb): ditto + + * cal-client/cal-client-types.h: add GError stuff + + * cal-client/Makefile.am: build glib marshal stuff + + * pcs/query.c (backend_opened_cb): comment out some break + temporarily + + * pcs/cal.h: add protos + + * pcs/cal.c (impl_Cal_open): just call the backend method, it will + handle the notification + (impl_Cal_remove): ditto + (impl_Cal_isReadOnly): ditto + (impl_Cal_getCalAddress): ditto + (impl_Cal_getAlarmEmailAddress): ditto + (impl_Cal_getLdapAttribute): ditto + (impl_Cal_getStaticCapabilities): ditto + (impl_Cal_getObjectList): simplify + (cal_new): set poa to be threaded + (cal_notify_read_only): notification utils + (cal_notify_cal_address): ditto + (cal_notify_alarm_email_address): ditto + (cal_notify_ldap_attribute): ditto + (cal_notify_static_capabilities): ditto + (cal_notify_open): ditto + (cal_notify_remove): ditto + (cal_notify_object_list): ditto + + * pcs/cal-factory.c (impl_CalFactory_getCal): dup the key and the + object + (cal_factory_new): set poa to be threaded + + * pcs/cal-backend.h: update vmethods and protos + + * pcs/cal-backend.c (cal_backend_get_cal_address): we no longer + return anything - the callee is responsible for notification + (cal_backend_get_alarm_email_address): ditto + (cal_backend_get_ldap_attribute): ditto + (cal_backend_get_static_capabilities): ditto + (cal_backend_open): ditto + (cal_backend_remove): ditto + + * pcs/cal-backend-file.h: update inheritance + + * pcs/cal-backend-file.c: inherit from CalBackendSync and make + is_read_only, get_static_capabilities, get_cal_address, get_ldap_attribute, open and + remove match + + * pcs/Makefile.am: build new files + +2003-09-02 JP Rosevear + + * idl/evolution-calendar.idl: make all listener callbacks one ways + +2003-09-02 Rodrigo Moya + + * pcs/cal-backend-file.c (match_recurrence_sexp, match_object_sexp): + new callbacks for g_hash_table_foreach in get_object_list. + (cal_backend_file_get_object_list): don't use the priv->comp list + to check the components, use the hash table, which contains all + the recurrences already expanded. + (add_component): only expand recurrences for recurrent components. + 2003-09-01 Andrew Wu - * gui/e-day-view.c: - (e_day_view_change_event_end_time_up): - (e_day_view_change_event_end_time_down): - Use "ctrl+shift+alt+Up/Down" to change the end time of the editing event. + * gui/e-day-view.c: + (e_day_view_change_event_end_time_up): + (e_day_view_change_event_end_time_down): Use + "ctrl+shift+alt+Up/Down" to change the end time of the editing + event. + +2003-08-29 Rodrigo Moya + + * pcs/cal-backend-file.c (lookup_component): take into account the 'rid' + argument. + (get_rid_string): new function to convert the recurrence ID to string. + (add_recurrence_to_object): callback for cal_recur_generate_instances. + (add_component): expand recurrences and g_strdup the hash's key. + (free_cal_component): free also the hash's key. + 2003-08-28 Hans Petter Jansson * gui/alarm-notify/alarm-queue.c (tray_icon_blink_cb) @@ -243,6 +1852,72 @@ * gui/alarm-notify/alarm-notify.c (AlarmNotify_removeCalendar): set the initial value of lc_ptr and orig_str_ptr to NULL to avoid crash. + +2003-08-26 Rodrigo Moya + + * idl/evolution-calendar.idl: QueryListener::notifyObjUpdated now gets + a sequence of CalObj's. + + * pcs/query.c (add_component): send the whole object to the listener, + not just the UID. Improved the way the listeners are notified, by allocating + a CORBA sequence to be used for all listeners, not one for each. + (match_component): pass the CalComponent to add_component, not only the UID. + (start_cached_query_cb): send the whole object to the listener. + + * cal-client/cal-query.[ch]: changed argument names for "obj_updated" + signal. + (obj_updated_cb): pass the calobj's, not uid's. + + * gui/e-tasks.c (query_obj_updated_cb): + * gui/gnome-cal.c (dn_query_obj_updated_cb, purging_obj_updated_cb): + * gui/e-cal-model.c (query_obj_updated_cb): we now get the object's + string representation instead of the UID. + +2003-08-25 Rodrigo Moya + + * cal-client/cal-client.c (cal_client_get_object): added a 'rid' argument + to match the IDL method. + + * conduits/calendar/calendar-conduit.c (local_record_from_uid): + * conduits/todo/todo-conduit.c (local_record_from_uid): + * gui/comp-editor-factory.c (edit_existing): + * gui/comp-util.c (cal_comp_is_on_server): + * gui/e-cal-model.c (query_obj_updated_cb): + * gui/e-itip-control.c (find_server, get_real_item, update_attendee_status): + * gui/gnome-cal.c (dn_query_obj_updated_cb, purging_obj_updated_cb): + * gui/dialogs/comp-editor.c (obj_updated_cb): adapted to changes in + cal_client_get_object(). + +2003-08-23 Rodrigo Moya + + * pcs/query-backend.c (object_updated_cb): + * pcs/cal-backend.c (cal_backend_get_type_by_uid): use 'rid' parameter + where appropriate. + + * pcs/cal-backend-file.c (check_dup_uid): removed unused variables. + (cal_backend_file_compute_changes_foreach_key): pass a NULL 'rid' + to cal_backend_get_object(). + (lookup_component): get a 'rid' argument also. + (cal_backend_file_cancel_object, cal_backend_file_remove_object): + pass correct number of parameters to lookup_component(). + +2003-08-22 Rodrigo Moya + + * idl/evolution-calendar.idl: use UID/RID pairs to identify objects. + + * pcs/cal.c (impl_Cal_getObject): added 'rid' parameter. + + * pcs/cal-backend.c (cal_backend_get_object): added 'rid' parameter. + (cal_backend_get_object_component): ditto. + (get_object): ditto. + + * pcs/cal-backend-file.c (cal_backend_file_get_object_component): + added 'rid' parameter. + (lookup_component): added 'rid' parameter and made it search for the + recurrence when that parameter is not NULL. + (cal_backend_file_get_alarms_for_object, cal_backend_file_update_object): + adapted to changes in lookup_component(). + 2003-08-22 Frederic Crozat * gui/alarm-notify/notify-main.c: (main): @@ -300,6 +1975,111 @@ (gnome_calendar_get_search_bar_widget), (gnome_calendar_get_view_notebook_widget): new functions + +2003-08-20 Rodrigo Moya + + * pcs/query-backend.c (foreach_uid_cb): use the icalcomponent + to call icalcomponent_get_uid, not the string. + +2003-08-20 Rodrigo Moya + + * pcs/cal-backend-file.c: store objects by UID and RID. + (free_object): new function to free the CalBackendFileObject structure. + (cal_backend_file_dispose): use free_object callback to remove the + objects in the comp_uid_hash. + (lookup_component): search correctly the component in the new hash + table organizarion. + (check_dup_uid): ditto. + (add_component): ditto. + (remove_component): ditto. + +2003-08-19 JP Rosevear + + * gui/gnome-cal.c (setup_widgets): set up models here + (gnome_calendar_construct): not here + + * conduits/calendar/calendar-conduit.c + (e_calendar_context_destroy): we have a list of calcomponents + rather than uids now + (process_multi_day): build a list of components rather than uids + (pre_sync): use get_object_list instead of getting uids + (for_each): create local records from calcomponents + + * conduits/todo/todo-conduit.c: as above + + * gui/print.c (instance_cb): mark as true if we found an instance + (print_month_small): see if atleast one instance exists in a + slight different way + + * cal-client/client-test.c (list_uids): use get_object_list + + * cal-client/cal-listener.h: update protos + + * cal-client/cal-listener.c (cal_listener_class_init): set object + list callback implementation + (impl_notifyObjectListRequested): implement + (cal_listener_construct): take object list callback function + (cal_listener_new): ditto + + * cal-client/cal-client.h: update protos, add status + + * cal-client/cal-client.c (e_calendar_new_op): create new op + (e_calendar_get_op): retrieve current op + (e_calendar_free_op): free the op + (e_calendar_remove_op): clear current op + (cal_client_init): create new mutex + (cal_client_finalize): destroy mutex + (build_object_list): build list of icalcomponents + (cal_object_list_cb): handle getObjectList response + (real_open_calendar): pass extra listener arg + (cal_client_get_object_list): implement using thread safe mutex + locking + (cal_client_get_object_list_as_comp): return calcomponents instead + of icalcomponents + (cal_client_generate_instances): just get the object list - no + need to make it atomic since get_object_list is already atomic + + * pcs/query.c (query_finalize): free new sexp class + (parse_sexp): use new sexp class + (match_component): ditto + + * pcs/query-backend.c (foreach_uid_cb): use icalcomponent to + extract uid + (query_backend_new): get all objects using object list call + + * pcs/cal.c (impl_Cal_getObjectList): implement + (cal_class_init): adjust for idl method changes + + * pcs/cal-backend.h: update vmethods, add proto + + * pcs/cal-backend.c (cal_backend_class_init): remove get_uids and + get_objects_in_range vmethods, add get_object_list vmethod + (cal_backend_get_object_list): call through to vmethod implementation + + * pcs/cal-backend-object-sexp.[hc]: nice class to represent a sexp + and search cal components + + * pcs/cal-backend-file.c (cal_backend_file_class_init): remove + get_uids and get_objects_in_range calls and set get_object_list + call + (cal_backend_file_get_object_list): implement + (create_user_free_busy): use sexp ops to implement + (cal_backend_file_compute_changes): just iterate over the + component list rather than fetching uids + + * pcs/Makefile.am: build new files + + * idl/evolution-calendar.idl: make opening a oneway call, add + getObjectList call, remove getUIDS and getObjectsInRange call - + both can be done with getObjectList; make listener callbacks + oneway + +2003-08-19 Rodrigo Moya + + * gui/gnome-cal.c (gnome_calendar_purge): don't leak the client list. + (gnome_calendar_destroy): disconnect from all callbacks on all + loaded clients. + 2003-08-19 Rodrigo Moya * gui/e-cal-model-tasks.c (ecmt_get_color_for_component): use @@ -321,6 +2101,51 @@ * gui/e-week-view.c (e_week_view_add_event, e_week_view_do_key_press): same as e-day-view.c +2003-08-18 Ettore Perazzoli + + * gui/calendar-component.c (impl_createControls): Oops, pass + [NULL, NULL] to gtk_scrolled_window_new(). + +2003-08-18 Ettore Perazzoli + + * gui/main.c (factory): Ref the object from + calendar_component_peek() before returning it. + +2003-08-17 Ettore Perazzoli + + * gui/control-factory.h: #include . + + * gui/Makefile.am (libevolution_calendar_la_LIBADD): Link to + libeutil. + + * gui/e-calendar-table.c (e_calendar_table_set_status_message): + Don't use the global_shell_client. + + * gui/main.c (factory): Call calendar_component_peek() for the + GNOME_Evolution_Calendar_Component OAFIID. + + * gui/GNOME_Evolution_Calendar.server.in.in: Set up the + GNOME_Evolution_Calendar_Component server and rename + GNOME_Evolution_Calendar_Factory to + GNOME_Evolution_Calendar_Factory_2. + * gui/main.c: Updated IDs accordingly. + + * gui/e-meeting-time-sel.c (e_meeting_time_selector_construct): + Use calendar_component_peek_config_directory() instead of + evolution_dir. + * gui/gnome-cal.c (setup_widgets): Likewise. + (gnome_calendar_destroy): Likewise. + * gui/dialogs/meeting-page.c (meeting_page_construct): Likewise. + + * gui/gnome-cal.c (gnome_calendar_open): #if 0 some code for + figuring out where the task list is. + + * gui/calendar-component.c: New file. + * gui/calendar-component.h: New file. + + * gui/itip-utils.c (itip_addresses_get): Unref the GConf client + from gconf_client_get_default. + 2003-08-15 Rodrigo Moya * gui/e-cal-model.c (ecm_get_color_for_component): use tigert's @@ -339,16 +2164,6 @@ cal_client_open_calendar(), since the "cal_opened_cb" signal is now emitted within it. -2003-08-14 Rodrigo Moya - - * gui/e-cal-model.c (e_cal_model_create_component_with_defaults): - use the default client to call cal_comp_*_new_with_defaults, and - if no client is available, just create an empty icalcomponent. - - * gui/e-cal-view.c (e_cal_view_init): create an empty model. - - * gui/e-week-view.c (e_week_view_add_event): use the event's client. - 2003-08-14 Rodrigo Moya * gui/e-cal-model.[ch] (e_cal_model_free_component_data): new @@ -367,6 +2182,46 @@ e_week_view_update_event_cb, e_week_view_remove_event_cb, e_week_view_free_events): same as EDayView. +2003-08-14 Rodrigo Moya + + * gui/e-cal-model.c (e_cal_model_create_component_with_defaults): + use the default client to call cal_comp_*_new_with_defaults, and + if no client is available, just create an empty icalcomponent. + + * gui/e-cal-view.c (e_cal_view_init): create an empty model. + + * gui/e-week-view.c (e_week_view_add_event): use the event's client. + +2003-08-13 Rodrigo Moya + + * gui/gnome-cal.c (gnome_calendar_open): unref the client if there + is an error. + (update_query): set status bar messages for progress. + (update_query_timeout): re-enabled. + (client_cal_opened_cb): install timeout handler for the query updates. + + * gui/e-cal-view.c (e_cal_view_set_model): connect to all appropriate + signals on the model, to be called for every change. + (model_row_changed_cb, model_rows_changed_cb): new model callbacks. + + * gui/e-week-view-event-item.c (e_week_view_event_item_draw): colorize + the background for multiple days events. + +2003-08-13 Rodrigo Moya + + * gui/e-cal-model.c (ecm_append_row, ecm_get_color_for_component): + * gui/e-cal-model-tasks.c (ecmt_get_color_for_component): merged + missing bith from calendar-views-with-model branch. + +2003-08-13 JP Rosevear + + * cal-client/cal-client.c (real_open_calendar): set the priv->cal + pointer in a slightly different spot so we have it in the call + back + + * gui/e-cal-model.c (e_cal_model_get_client_list): merge this in + properly + 2003-08-13 Rodrigo Moya * gui/e-cal-model.c (ecm_get_color_for_component): assign the colors @@ -393,7 +2248,170 @@ * gui/e-week-view-event-item.c (e_week_view_event_item_draw): colorize the background for multiple days events. + +2003-08-13 JP Rosevear + + * cal-client/client-test.c (create_client): there is no more + object updated signal + + * cal-client/cal-listener.c: clean up comment + + * cal-client/cal-client.c (cal_client_class_init): remove + obj_updated and obj_removed signals + + * cal-client/cal-client.h: ditto + +2003-08-12 JP Rosevear + + * pcs/cal-backend.h: remove get_uri vmethod + + * pcs/cal-backend.c (cal_backend_class_init): remove get_uri + vmethod init + + * pcs/cal-backend-file.c (cal_backend_file_class_init): no longer + a get uri vmethod + (cal_backend_file_get_uri): remove implementation of above + +2003-08-12 JP Rosevear + + * cal-client/client-test.c (main): use tmp uris + + * cal-client/cal-listener.h: update protos + + * cal-client/cal-listener.c (cal_listener_init): init removed + function + (cal_listener_finalize): clear removed function + (impl_notifyCalOpened): take file status + (impl_notifyCalRemoved): implement + (cal_listener_construct): take remove function arg + (cal_listener_new): ditto + + * cal-client/cal-client.h: update protos, add remove status + + * cal-client/cal-client.c + (cal_client_remove_status_enum_get_type): add remove status type + (cal_client_class_init): add removed signal + (cal_opened_cb): can no longer get unsupported exception here + (cal_removed_cb): emit removed status + (real_open_calendar): pass removed callback function to listener + (get_fall_back_uri): no longer append tasks.ics or calendar.ics + (cal_client_remove_calendar): new c wrapper for corba function - + calendar must be open currently + + * pcs/query.c (backend_opened_cb): only disconnect the open + callback + (backend_removed_cb): handle calendar removal + (query_construct): listen for remove signal as well + + * pcs/cal.h: cal no longer takes uri during construction + + * pcs/cal.c (backend_to_listener_status): convert backend to corba + status code + (impl_Cal_open): backend open no longer takes uri, use above to + send back status + (impl_Cal_remove): implement + (cal_construct): we no longer track the uri + (cal_finalize): ditto + (cal_class_init): set remove epv method + + * pcs/cal-factory.c (impl_CalFactory_getCal): instantiate backend + with uri and kind properties + + * pcs/cal-backend.h: list file status enum, add protos + + * pcs/cal-backend.c (cal_backend_set_property): implement object + properties + (cal_backend_get_property): ditto + (cal_backend_class_init): add properties vmethods and uri, kind + properties, removed signal + (cal_backend_get_uri): don't get the uri from the backend + (cal_backend_get_kind): get the kind from the backend + (cal_backend_open): adapt to new open call, no uri passed in + (cal_backend_remove): call through to remove implementation + (cal_backend_opened): use new file status + (cal_backend_removed): emit removed signal + + * pcs/cal-backend-file.h: update protos + + * pcs/cal-backend-file.c (cal_backend_file_class_init): override + remove vmethod + (cal_backend_file_init): default file name to calendar.ics + (cal_backend_file_set_file_name): accessor for filename tacked on + to uri + (cal_backend_file_get_file_name): ditto + (open_cal): return "file" type status codes + (create_cal): ditto + (get_uri_string): construct the full uri string + (cal_backend_file_open): use above + (cal_backend_file_remove): implement + + * pcs/cal-backend-file-todos.c (cal_backend_file_todos_init): set + the file name to tasks.ics + + * pcs/cal-backend-file-events.c (cal_backend_file_events_init): + set the file name to calendar.ics + + * cal-util/cal-util.c (cal_util_expand_uri): just return a copy of + the uri now + + * idl/evolution-calendar.idl: convert OpenStatus to FileStatus so + remove() can use it as well + + * gui/gnome-cal.c (gnome_calendar_open): just open the default + folder in all cases + +2003-08-12 Rodrigo Moya + + * cal-util/cal-util.[ch] (cal_util_component_has_alarms): new function. + + * gui/gnome-cal.[ch]: + * gui/goto.c: + * gui/itip-bonobo-control.c: + * gui/print.c: + * gui/e-week-view.[ch]: + * gui/e-day-view.[ch]: lots of fixes to make all compile with no + warnings. + +2003-08-12 Rodrigo Moya + + * cal-util/cal-util.[ch] (cal_util_component_has_organizer): + new function. + + * gui/e-day-view-main-item.c: + * gui/e-day-view-top-item.c: + * gui/e-week-view-event-item.c: + * gui/e-week-view.c: adaptated to changes in ECalViewEvent. + + * gui/e-cal-model.[ch] (e_cal_model_get_client_list): new function. + (ecm_append_row): fixed usage of icalcomponent variable. + + * gui/e-cal-view.c (e_cal_view_class_init): removed unused variable. + (selection_received): use default client for pasting from clipboard. + (e_cal_view_cut_clipboard): cut the appointment from its client. + (e_cal_view_copy_clipboard, delete_event, on_save_as, om_print_event, + e_cal_view_delete_selected_occurrence, on_meeting, on_forward, + e_cal_view_create_popup_menu): adapted to changes in ECalViewEvent. + (e_cal_view_delete_selected_event, e_cal_view_delete_selected_events): + pass the ECalViewEvent to delete_event, so that it knows which + CalClient to use. + (on_edit_appointment): pass CalClient and icalcomponent to + gnome_calendar_edit_object. + (on_publish): publish F/B info for all the clients currently loaded + in the view. + (setup_popup_icons): added missing argument to gtk_image_new_from_stock. + + * gui/calendar-commands.c (publish_freebusy_cmd): publish F/B info + for all the clients currently loaded in the view. + (sensitize_calendar_commands): use icalcomponent functions. + * gui/e-day-view.c: + * gui/comp-editor-factory.c (impl_editExisting): + * gui/calendar-offline-handler.c (backend_cal_opened_online): + * gui/e-alarm-list.c (e_alarm_list_finalize): + * gui/e-cal-model-tasks.c (ecmt_get_color_for_component): + * gui/e-date-time-list.c (e_date_time_list_finalize): + * gui/control-factory.c (get_prop): fixed warnings. + 2003-08-12 Hans Petter Jansson * gui/calendar-offline-handler.c (impl_dispose): Chain. Prevent @@ -799,6 +2817,27 @@ * cal-client/cal-client-multi.[ch]: * cal-client/Makefile.am: removed obsolete code. +2003-07-30 Ettore Perazzoli + + * gui/main.c (factory): Do not depend on global_shell_client being + not NULL for creating the calendar preferences dialog. + + * gui/e-itip-control.c (show_current): Don't call get_servers + anymore [to be fixed]. + (get_servers): #if 0ed out. + (object_requested_cb): Don't create the folder selector button. + + * gui/e-cal-view.c (e_cal_view_set_status_message): Don't create + an activity client. + + * gui/calendar-model.c (calendar_model_set_status_message): Don't + create an activity client. + + * gui/calendar-component.c: Removed global variable + global_shell_client. + (owner_set_cb): Don't set global_shell_client. + (owner_unset_cb): Don't set it here either. + 2003-07-29 Rodrigo Moya Fixes all "alarm daemon doesn't start with session" diff --git a/calendar/cal-client/.cvsignore b/calendar/cal-client/.cvsignore index 1537e6e01d..f2aa4f92ae 100644 --- a/calendar/cal-client/.cvsignore +++ b/calendar/cal-client/.cvsignore @@ -10,6 +10,8 @@ evolution-calendar.h evolution-calendar-common.lo evolution-calendar-skels.lo evolution-calendar-stubs.lo +cal-marshal.c +cal-marshal.h *.lo *.la client-test diff --git a/calendar/cal-client/Makefile.am b/calendar/cal-client/Makefile.am index 5e48e7db23..5f8b5a3cf1 100644 --- a/calendar/cal-client/Makefile.am +++ b/calendar/cal-client/Makefile.am @@ -38,6 +38,8 @@ libcal_clientincludedir = $(privincludedir)/cal-client libcal_client_la_SOURCES = \ $(CORBA_GENERATED_C) \ cal-client-types.c \ + cal-marshal.c \ + cal--marshal.h \ cal-client.c \ cal-listener.c \ cal-listener.h \ @@ -72,7 +74,10 @@ client_test_LDADD = \ libcal-client.la \ $(EVOLUTION_CALENDAR_LIBS) -BUILT_SOURCES = $(CORBA_GENERATED) +MARSHAL_GENERATED = cal-marshal.c cal-marshal.h +@EVO_MARSHAL_RULE@ + +BUILT_SOURCES = $(CORBA_GENERATED) $(MARSHAL_GENERATED) CLEANFILES = $(BUILT_SOURCES) dist-hook: diff --git a/calendar/cal-client/cal-client-types.h b/calendar/cal-client/cal-client-types.h index c160a1fa94..925628337b 100644 --- a/calendar/cal-client/cal-client-types.h +++ b/calendar/cal-client/cal-client-types.h @@ -29,6 +29,10 @@ G_BEGIN_DECLS +#define E_CALENDAR_ERROR e_calendar_error_quark() + +GQuark e_calendar_error_quark (void) G_GNUC_CONST; + typedef enum { CAL_CLIENT_CHANGE_ADDED = 1 << 0, CAL_CLIENT_CHANGE_MODIFIED = 1 << 1, @@ -41,6 +45,28 @@ typedef struct CalClientChangeType type; } CalClientChange; +typedef enum { + E_CALENDAR_STATUS_OK, + E_CALENDAR_STATUS_INVALID_ARG, + E_CALENDAR_STATUS_BUSY, + E_CALENDAR_STATUS_REPOSITORY_OFFLINE, + E_CALENDAR_STATUS_NO_SUCH_CALENDAR, + E_CALENDAR_STATUS_OBJECT_NOT_FOUND, + E_CALENDAR_STATUS_INVALID_OBJECT, + E_CALENDAR_STATUS_URI_NOT_LOADED, + E_CALENDAR_STATUS_URI_ALREADY_LOADED, + E_CALENDAR_STATUS_PERMISSION_DENIED, + E_CALENDAR_STATUS_CARD_NOT_FOUND, + E_CALENDAR_STATUS_CARD_ID_ALREADY_EXISTS, + E_CALENDAR_STATUS_PROTOCOL_NOT_SUPPORTED, + E_CALENDAR_STATUS_CANCELLED, + E_CALENDAR_STATUS_COULD_NOT_CANCEL, + E_CALENDAR_STATUS_AUTHENTICATION_FAILED, + E_CALENDAR_STATUS_AUTHENTICATION_REQUIRED, + E_CALENDAR_STATUS_CORBA_EXCEPTION, + E_CALENDAR_STATUS_OTHER_ERROR +} ECalendarStatus; + void cal_client_change_list_free (GList *list); G_END_DECLS diff --git a/calendar/cal-client/cal-client.c b/calendar/cal-client/cal-client.c index e40d405120..95efdd6d5d 100644 --- a/calendar/cal-client/cal-client.c +++ b/calendar/cal-client/cal-client.c @@ -22,20 +22,39 @@ #include #endif +#include #include #include #include +#include #include #include "e-util/e-component-listener.h" #include "e-util/e-config-listener.h" +#include "e-util/e-url.h" +#include "e-util/e-msgport.h" #include "cal-util/cal-util-marshal.h" -#include "cal-client-types.h" +#include "cal-util/timeutil.h" #include "cal-client.h" #include "cal-listener.h" +#include "query-listener.h" +typedef struct { + EMutex *mutex; + pthread_cond_t cond; + ECalendarStatus status; + + char *uid; + GList *list; + gboolean bool; + char *string; + + CalQuery *query; + QueryListener *listener; +} ECalendarOp; + /* Private part of the CalClient structure */ struct _CalClientPrivate { /* Load state to avoid multiple loads */ @@ -45,7 +64,12 @@ struct _CalClientPrivate { * NULL if we are not loaded. */ char *uri; + CalObjType type; + + ECalendarOp *current_op; + EMutex *mutex; + /* Email address associated with this calendar, or NULL */ char *cal_address; char *alarm_email_address; @@ -85,8 +109,6 @@ struct _CalClientPrivate { enum { CAL_OPENED, CAL_SET_MODE, - OBJ_UPDATED, - OBJ_REMOVED, BACKEND_ERROR, CATEGORIES_CHANGED, FORGET_PASSWORD, @@ -94,10 +116,6 @@ enum { LAST_SIGNAL }; -static void cal_client_class_init (CalClientClass *klass); -static void cal_client_init (CalClient *client, CalClientClass *klass); -static void cal_client_finalize (GObject *object); - static void cal_client_get_object_timezones_cb (icalparameter *param, void *data); @@ -105,36 +123,28 @@ static guint cal_client_signals[LAST_SIGNAL]; static GObjectClass *parent_class; +#define E_CALENDAR_CHECK_STATUS(status,error) G_STMT_START{ \ + if ((status) == E_CALENDAR_STATUS_OK) { \ + return TRUE; \ + } \ + else { \ + const char *msg; \ + msg = cal_client_get_error_message ((status)); \ + g_set_error ((error), E_CALENDAR_ERROR, (status), msg, (status)); \ + return FALSE; \ + } }G_STMT_END + -/** - * cal_client_get_type: - * - * Registers the #CalClient class if necessary, and returns the type ID assigned - * to it. - * - * Return value: The type ID of the #CalClient class. - **/ -GType -cal_client_get_type (void) +/* Error quark */ +GQuark +e_calendar_error_quark (void) { - static GType cal_client_type = 0; - - if (!cal_client_type) { - static GTypeInfo info = { - sizeof (CalClientClass), - (GBaseInitFunc) NULL, - (GBaseFinalizeFunc) NULL, - (GClassInitFunc) cal_client_class_init, - NULL, NULL, - sizeof (CalClient), - 0, - (GInstanceInitFunc) cal_client_init - }; - cal_client_type = g_type_register_static (G_TYPE_OBJECT, "CalClient", &info, 0); - } + static GQuark q = 0; + if (q == 0) + q = g_quark_from_static_string ("e-calendar-error-quark"); - return cal_client_type; + return q; } GType @@ -198,118 +208,48 @@ cal_mode_enum_get_type (void) return cal_mode_enum_type; } -/* Class initialization function for the calendar client */ -static void -cal_client_class_init (CalClientClass *klass) -{ - GObjectClass *object_class; +/* EBookOp calls */ - object_class = (GObjectClass *) klass; +static ECalendarOp* +e_calendar_new_op (CalClient *client) +{ + ECalendarOp *op = g_new0 (ECalendarOp, 1); - parent_class = g_type_class_peek_parent (klass); + op->mutex = e_mutex_new (E_MUTEX_SIMPLE); + pthread_cond_init (&op->cond, 0); - cal_client_signals[CAL_OPENED] = - g_signal_new ("cal_opened", - G_TYPE_FROM_CLASS (klass), - G_SIGNAL_RUN_FIRST, - G_STRUCT_OFFSET (CalClientClass, cal_opened), - NULL, NULL, - g_cclosure_marshal_VOID__ENUM, - G_TYPE_NONE, 1, - CAL_CLIENT_OPEN_STATUS_ENUM_TYPE); - cal_client_signals[CAL_SET_MODE] = - g_signal_new ("cal_set_mode", - G_TYPE_FROM_CLASS (klass), - G_SIGNAL_RUN_FIRST, - G_STRUCT_OFFSET (CalClientClass, cal_set_mode), - NULL, NULL, - cal_util_marshal_VOID__ENUM_ENUM, - G_TYPE_NONE, 2, - CAL_CLIENT_SET_MODE_STATUS_ENUM_TYPE, - CAL_MODE_ENUM_TYPE); - cal_client_signals[OBJ_UPDATED] = - g_signal_new ("obj_updated", - G_TYPE_FROM_CLASS (klass), - G_SIGNAL_RUN_FIRST, - G_STRUCT_OFFSET (CalClientClass, obj_updated), - NULL, NULL, - g_cclosure_marshal_VOID__STRING, - G_TYPE_NONE, 1, - G_TYPE_STRING); - cal_client_signals[OBJ_REMOVED] = - g_signal_new ("obj_removed", - G_TYPE_FROM_CLASS (klass), - G_SIGNAL_RUN_FIRST, - G_STRUCT_OFFSET (CalClientClass, obj_removed), - NULL, NULL, - g_cclosure_marshal_VOID__STRING, - G_TYPE_NONE, 1, - G_TYPE_STRING); - cal_client_signals[BACKEND_ERROR] = - g_signal_new ("backend_error", - G_TYPE_FROM_CLASS (klass), - G_SIGNAL_RUN_FIRST, - G_STRUCT_OFFSET (CalClientClass, backend_error), - NULL, NULL, - g_cclosure_marshal_VOID__STRING, - G_TYPE_NONE, 1, - G_TYPE_STRING); - cal_client_signals[CATEGORIES_CHANGED] = - g_signal_new ("categories_changed", - G_TYPE_FROM_CLASS (klass), - G_SIGNAL_RUN_FIRST, - G_STRUCT_OFFSET (CalClientClass, categories_changed), - NULL, NULL, - g_cclosure_marshal_VOID__POINTER, - G_TYPE_NONE, 1, - G_TYPE_POINTER); - cal_client_signals[FORGET_PASSWORD] = - g_signal_new ("forget_password", - G_TYPE_FROM_CLASS (klass), - G_SIGNAL_RUN_FIRST, - G_STRUCT_OFFSET (CalClientClass, forget_password), - NULL, NULL, - g_cclosure_marshal_VOID__STRING, - G_TYPE_NONE, 1, - G_TYPE_STRING); - cal_client_signals[BACKEND_DIED] = - g_signal_new ("backend_died", - G_TYPE_FROM_CLASS (klass), - G_SIGNAL_RUN_FIRST, - G_STRUCT_OFFSET (CalClientClass, backend_died), - NULL, NULL, - g_cclosure_marshal_VOID__VOID, - G_TYPE_NONE, 0); + client->priv->current_op = op; - klass->cal_opened = NULL; - klass->obj_updated = NULL; - klass->obj_removed = NULL; - klass->categories_changed = NULL; - klass->forget_password = NULL; - klass->backend_died = NULL; + return op; +} - object_class->finalize = cal_client_finalize; +static ECalendarOp* +e_calendar_get_op (CalClient *client) +{ + if (!client->priv->current_op) { + g_warning (G_STRLOC ": Unexpected response"); + return NULL; + } + + return client->priv->current_op; } -/* Object initialization function for the calendar client */ static void -cal_client_init (CalClient *client, CalClientClass *klass) +e_calendar_free_op (ECalendarOp *op) { - CalClientPrivate *priv; + /* XXX more stuff here */ + pthread_cond_destroy (&op->cond); + e_mutex_destroy (op->mutex); + g_free (op); +} - priv = g_new0 (CalClientPrivate, 1); - client->priv = priv; +static void +e_calendar_remove_op (CalClient *client, ECalendarOp *op) +{ + if (client->priv->current_op != op) + g_warning (G_STRLOC ": Cannot remove op, it's not current"); - priv->load_state = CAL_CLIENT_LOAD_NOT_LOADED; - priv->uri = NULL; - priv->cal_address = NULL; - priv->alarm_email_address = NULL; - priv->ldap_attribute = NULL; - priv->capabilities = FALSE; - priv->factories = NULL; - priv->timezones = g_hash_table_new (g_str_hash, g_str_equal); - priv->default_zone = icaltimezone_get_utc_timezone (); - priv->comp_listener = NULL; + client->priv->current_op = NULL; } /* Gets rid of the factories that a client knows about */ @@ -364,7 +304,7 @@ destroy_cal (CalClient *client) CORBA_exception_init (&ev); result = CORBA_Object_is_nil (priv->cal, &ev); if (BONOBO_EX (&ev)) { - g_message ("destroy_cal(): could not see if the " + g_message (G_STRLOC ": could not see if the " "calendar client interface object was nil"); priv->cal = CORBA_OBJECT_NIL; CORBA_exception_free (&ev); @@ -375,19 +315,7 @@ destroy_cal (CalClient *client) if (result) return; - CORBA_exception_init (&ev); - GNOME_Evolution_Calendar_Cal_unref (priv->cal, &ev); - if (BONOBO_EX (&ev)) - g_message ("destroy_cal(): could not unref the calendar client interface object"); - - CORBA_exception_free (&ev); - - CORBA_exception_init (&ev); - CORBA_Object_release (priv->cal, &ev); - if (BONOBO_EX (&ev)) - g_message ("destroy_cal(): could not release the calendar client interface object"); - - CORBA_exception_free (&ev); + bonobo_object_release_unref (priv->cal, NULL); priv->cal = CORBA_OBJECT_NIL; } @@ -400,184 +328,541 @@ free_timezone (gpointer key, gpointer value, gpointer data) icaltimezone_free (value, TRUE); } -/* Finalize handler for the calendar client */ + + static void -cal_client_finalize (GObject *object) +backend_died_cb (EComponentListener *cl, gpointer user_data) { - CalClient *client; CalClientPrivate *priv; + CalClient *client = (CalClient *) user_data; - g_return_if_fail (object != NULL); - g_return_if_fail (IS_CAL_CLIENT (object)); + g_return_if_fail (IS_CAL_CLIENT (client)); - client = CAL_CLIENT (object); priv = client->priv; + priv->load_state = CAL_CLIENT_LOAD_NOT_LOADED; + g_signal_emit (G_OBJECT (client), cal_client_signals[BACKEND_DIED], 0); +} - if (priv->listener) { - cal_listener_stop_notification (priv->listener); - bonobo_object_unref (priv->listener); - priv->listener = NULL; - } - - if (priv->comp_listener) { - g_signal_handlers_disconnect_matched (G_OBJECT (priv->comp_listener), - G_SIGNAL_MATCH_DATA, - 0, 0, NULL, NULL, - client); - g_object_unref (G_OBJECT (priv->comp_listener)); - priv->comp_listener = NULL; - } +/* Signal handlers for the listener's signals */ +/* Handle the cal_opened notification from the listener */ - destroy_factories (client); - destroy_cal (client); +static void +cal_read_only_cb (CalListener *listener, ECalendarStatus status, gboolean read_only, gpointer data) +{ + CalClient *client = data; + ECalendarOp *op; - priv->load_state = CAL_CLIENT_LOAD_NOT_LOADED; + op = e_calendar_get_op (client); - if (priv->uri) { - g_free (priv->uri); - priv->uri = NULL; + if (op == NULL) { + g_warning (G_STRLOC ": Cannot find operation "); + return; } - if (priv->cal_address) { - g_free (priv->cal_address); - priv->cal_address = NULL; - } - if (priv->alarm_email_address) { - g_free (priv->alarm_email_address); - priv->alarm_email_address = NULL; - } - if (priv->ldap_attribute) { - g_free (priv->ldap_attribute); - priv->ldap_attribute = NULL; - } - if (priv->capabilities) { - g_free (priv->capabilities); - priv->capabilities = NULL; - } + e_mutex_lock (op->mutex); - g_hash_table_foreach (priv->timezones, free_timezone, NULL); - g_hash_table_destroy (priv->timezones); - priv->timezones = NULL; + op->status = status; + op->bool = read_only; - g_free (priv); - client->priv = NULL; + pthread_cond_signal (&op->cond); - if (G_OBJECT_CLASS (parent_class)->finalize) - (* G_OBJECT_CLASS (parent_class)->finalize) (object); + e_mutex_unlock (op->mutex); } - - static void -backend_died_cb (EComponentListener *cl, gpointer user_data) +cal_cal_address_cb (CalListener *listener, ECalendarStatus status, const char *address, gpointer data) { - CalClientPrivate *priv; - CalClient *client = (CalClient *) user_data; + CalClient *client = data; + ECalendarOp *op; - g_return_if_fail (IS_CAL_CLIENT (client)); + op = e_calendar_get_op (client); - priv = client->priv; - priv->load_state = CAL_CLIENT_LOAD_NOT_LOADED; - g_signal_emit (G_OBJECT (client), cal_client_signals[BACKEND_DIED], 0); + if (op == NULL) { + g_warning (G_STRLOC ": Cannot find operation "); + return; + } + + e_mutex_lock (op->mutex); + + op->status = status; + op->string = g_strdup (address); + + pthread_cond_signal (&op->cond); + + e_mutex_unlock (op->mutex); } -/* Signal handlers for the listener's signals */ -/* Handle the cal_opened notification from the listener */ static void -cal_opened_cb (CalListener *listener, - GNOME_Evolution_Calendar_Listener_OpenStatus status, - GNOME_Evolution_Calendar_Cal cal, - gpointer data) +cal_alarm_address_cb (CalListener *listener, ECalendarStatus status, const char *address, gpointer data) { - CalClient *client; - CalClientPrivate *priv; - CORBA_Environment ev; - GNOME_Evolution_Calendar_Cal cal_copy; - CalClientOpenStatus client_status; + CalClient *client = data; + ECalendarOp *op; - client = CAL_CLIENT (data); - priv = client->priv; + op = e_calendar_get_op (client); - g_assert (priv->load_state == CAL_CLIENT_LOAD_LOADING); - g_assert (priv->uri != NULL); + if (op == NULL) { + g_warning (G_STRLOC ": Cannot find operation "); + return; + } - client_status = CAL_CLIENT_OPEN_ERROR; + e_mutex_lock (op->mutex); - switch (status) { - case GNOME_Evolution_Calendar_Listener_SUCCESS: - CORBA_exception_init (&ev); - cal_copy = CORBA_Object_duplicate (cal, &ev); - if (BONOBO_EX (&ev)) { - g_message ("cal_opened_cb(): could not duplicate the " - "calendar client interface"); - CORBA_exception_free (&ev); - goto error; - } - CORBA_exception_free (&ev); + op->status = status; + op->string = g_strdup (address); - priv->cal = cal_copy; - priv->load_state = CAL_CLIENT_LOAD_LOADED; + pthread_cond_signal (&op->cond); + + e_mutex_unlock (op->mutex); +} - client_status = CAL_CLIENT_OPEN_SUCCESS; +static void +cal_ldap_attribute_cb (CalListener *listener, ECalendarStatus status, const char *attribute, gpointer data) +{ + CalClient *client = data; + ECalendarOp *op; - /* setup component listener */ - priv->comp_listener = e_component_listener_new (priv->cal); - g_signal_connect (G_OBJECT (priv->comp_listener), "component_died", - G_CALLBACK (backend_died_cb), client); - goto out; + op = e_calendar_get_op (client); - case GNOME_Evolution_Calendar_Listener_ERROR: - client_status = CAL_CLIENT_OPEN_ERROR; - goto error; + if (op == NULL) { + g_warning (G_STRLOC ": Cannot find operation "); + return; + } - case GNOME_Evolution_Calendar_Listener_NOT_FOUND: - client_status = CAL_CLIENT_OPEN_NOT_FOUND; - goto error; + e_mutex_lock (op->mutex); - case GNOME_Evolution_Calendar_Listener_METHOD_NOT_SUPPORTED: - client_status = CAL_CLIENT_OPEN_METHOD_NOT_SUPPORTED; - goto error; + op->status = status; + op->string = g_strdup (attribute); - case GNOME_Evolution_Calendar_Listener_PERMISSION_DENIED : - client_status = CAL_CLIENT_OPEN_PERMISSION_DENIED; - goto error; + pthread_cond_signal (&op->cond); - default: - g_assert_not_reached (); + e_mutex_unlock (op->mutex); +} + +static void +cal_static_capabilities_cb (CalListener *listener, ECalendarStatus status, const char *capabilities, gpointer data) +{ + CalClient *client = data; + ECalendarOp *op; + + op = e_calendar_get_op (client); + + if (op == NULL) { + g_warning (G_STRLOC ": Cannot find operation "); + return; } - error: + e_mutex_lock (op->mutex); - bonobo_object_unref (BONOBO_OBJECT (priv->listener)); - priv->listener = NULL; + op->status = status; + op->string = g_strdup (capabilities); - /* We free the priv->uri and set the priv->load_state until after the - * "cal_opened" signal has been emitted so that handlers will be able to - * access this information. - */ + pthread_cond_signal (&op->cond); - out: + e_mutex_unlock (op->mutex); +} - /* We are *not* inside a signal handler (this is just a simple callback - * called from the listener), so there is not a temporary reference to - * the client object. We ref() so that we can safely emit our own - * signal and clean up. - */ +static void +cal_opened_cb (CalListener *listener, ECalendarStatus status, gpointer data) +{ + CalClient *client = data; + ECalendarOp *op; - g_object_ref (G_OBJECT (client)); + op = e_calendar_get_op (client); - g_signal_emit (G_OBJECT (client), cal_client_signals[CAL_OPENED], - 0, client_status); + if (op == NULL) { + g_warning (G_STRLOC ": Cannot find operation "); + return; + } - if (client_status != CAL_CLIENT_OPEN_SUCCESS) { - priv->load_state = CAL_CLIENT_LOAD_NOT_LOADED; - g_free (priv->uri); - priv->uri = NULL; + e_mutex_lock (op->mutex); + + op->status = status; + + pthread_cond_signal (&op->cond); + + e_mutex_unlock (op->mutex); +} + +static void +cal_removed_cb (CalListener *listener, ECalendarStatus status, gpointer data) +{ + CalClient *client = data; + ECalendarOp *op; + + op = e_calendar_get_op (client); + + if (op == NULL) { + g_warning (G_STRLOC ": Cannot find operation "); + return; } - g_assert (priv->load_state != CAL_CLIENT_LOAD_LOADING); + e_mutex_lock (op->mutex); - g_object_unref (G_OBJECT (client)); + op->status = status; + + pthread_cond_signal (&op->cond); + + e_mutex_unlock (op->mutex); +} + +static void +cal_object_created_cb (CalListener *listener, ECalendarStatus status, const char *uid, gpointer data) +{ + CalClient *client = data; + ECalendarOp *op; + + op = e_calendar_get_op (client); + + if (op == NULL) { + g_warning (G_STRLOC ": Cannot find operation "); + return; + } + + e_mutex_lock (op->mutex); + + op->status = status; + op->uid = g_strdup (uid); + + pthread_cond_signal (&op->cond); + + e_mutex_unlock (op->mutex); +} + +static void +cal_object_modified_cb (CalListener *listener, ECalendarStatus status, gpointer data) +{ + CalClient *client = data; + ECalendarOp *op; + + op = e_calendar_get_op (client); + + if (op == NULL) { + g_warning (G_STRLOC ": Cannot find operation "); + return; + } + + e_mutex_lock (op->mutex); + + op->status = status; + + pthread_cond_signal (&op->cond); + + e_mutex_unlock (op->mutex); +} + +static void +cal_object_removed_cb (CalListener *listener, ECalendarStatus status, gpointer data) +{ + CalClient *client = data; + ECalendarOp *op; + + op = e_calendar_get_op (client); + + if (op == NULL) { + g_warning (G_STRLOC ": Cannot find operation "); + return; + } + + e_mutex_lock (op->mutex); + + op->status = status; + + pthread_cond_signal (&op->cond); + + e_mutex_unlock (op->mutex); +} + +static void +cal_alarm_discarded_cb (CalListener *listener, ECalendarStatus status, gpointer data) +{ + CalClient *client = data; + ECalendarOp *op; + + op = e_calendar_get_op (client); + + if (op == NULL) { + g_warning (G_STRLOC ": Cannot find operation "); + return; + } + + e_mutex_lock (op->mutex); + + op->status = status; + + pthread_cond_signal (&op->cond); + + e_mutex_unlock (op->mutex); +} + +static void +cal_objects_received_cb (CalListener *listener, ECalendarStatus status, gpointer data) +{ + CalClient *client = data; + ECalendarOp *op; + + op = e_calendar_get_op (client); + + if (op == NULL) { + g_warning (G_STRLOC ": Cannot find operation "); + return; + } + + e_mutex_lock (op->mutex); + + op->status = status; + + pthread_cond_signal (&op->cond); + + e_mutex_unlock (op->mutex); +} + +static void +cal_objects_sent_cb (CalListener *listener, ECalendarStatus status, gpointer data) +{ + CalClient *client = data; + ECalendarOp *op; + + op = e_calendar_get_op (client); + + if (op == NULL) { + g_warning (G_STRLOC ": Cannot find operation "); + return; + } + + e_mutex_lock (op->mutex); + + op->status = status; + + pthread_cond_signal (&op->cond); + + e_mutex_unlock (op->mutex); +} + +static void +cal_default_object_requested_cb (CalListener *listener, ECalendarStatus status, const char *object, gpointer data) +{ + CalClient *client = data; + ECalendarOp *op; + + op = e_calendar_get_op (client); + + if (op == NULL) { + g_warning (G_STRLOC ": Cannot find operation "); + return; + } + + e_mutex_lock (op->mutex); + + op->status = status; + op->string = g_strdup (object); + + pthread_cond_signal (&op->cond); + + e_mutex_unlock (op->mutex); +} + +static void +cal_object_requested_cb (CalListener *listener, ECalendarStatus status, const char *object, gpointer data) +{ + CalClient *client = data; + ECalendarOp *op; + + op = e_calendar_get_op (client); + + if (op == NULL) { + g_warning (G_STRLOC ": Cannot find operation "); + return; + } + + e_mutex_lock (op->mutex); + + op->status = status; + op->string = g_strdup (object); + + pthread_cond_signal (&op->cond); + + e_mutex_unlock (op->mutex); +} + +static void +cal_object_list_cb (CalListener *listener, ECalendarStatus status, GList *objects, gpointer data) +{ + CalClient *client = data; + ECalendarOp *op; + GList *l; + + op = e_calendar_get_op (client); + + if (op == NULL) { + g_warning (G_STRLOC ": Cannot find operation "); + return; + } + + e_mutex_lock (op->mutex); + + op->status = status; + op->list = g_list_copy (objects); + + for (l = op->list; l; l = l->next) + l->data = icalcomponent_new_clone (l->data); + + pthread_cond_signal (&op->cond); + + e_mutex_unlock (op->mutex); +} + +static void +cal_get_timezone_cb (CalListener *listener, ECalendarStatus status, const char *object, gpointer data) +{ + CalClient *client = data; + ECalendarOp *op; + + op = e_calendar_get_op (client); + + if (op == NULL) { + g_warning (G_STRLOC ": Cannot find operation "); + return; + } + + e_mutex_lock (op->mutex); + + op->status = status; + op->string = g_strdup (object); + + pthread_cond_signal (&op->cond); + + e_mutex_unlock (op->mutex); + +} + +static void +cal_add_timezone_cb (CalListener *listener, ECalendarStatus status, const char *tzid, gpointer data) +{ + CalClient *client = data; + ECalendarOp *op; + + op = e_calendar_get_op (client); + + if (op == NULL) { + g_warning (G_STRLOC ": Cannot find operation "); + return; + } + + e_mutex_lock (op->mutex); + + op->status = status; + op->uid = g_strdup (tzid); + + pthread_cond_signal (&op->cond); + + e_mutex_unlock (op->mutex); + +} + +static void +cal_set_default_timezone_cb (CalListener *listener, ECalendarStatus status, gpointer data) +{ + CalClient *client = data; + ECalendarOp *op; + + op = e_calendar_get_op (client); + + if (op == NULL) { + g_warning (G_STRLOC ": Cannot find operation "); + return; + } + + e_mutex_lock (op->mutex); + + op->status = status; + + pthread_cond_signal (&op->cond); + + e_mutex_unlock (op->mutex); +} + +static void +cal_get_changes_cb (CalListener *listener, ECalendarStatus status, GList *changes, gpointer data) +{ + CalClient *client = data; + ECalendarOp *op; + GList *l; + + op = e_calendar_get_op (client); + + if (op == NULL) { + g_warning (G_STRLOC ": Cannot find operation "); + return; + } + + e_mutex_lock (op->mutex); + + op->status = status; + op->list = g_list_copy (changes); + + for (l = op->list; l; l = l->next) { + CalClientChange *ccc = l->data, *new_ccc; + + new_ccc = g_new (CalClientChange, 1); + new_ccc->comp = cal_component_clone (ccc->comp); + new_ccc->type = ccc->type; + + l->data = new_ccc; + } + + pthread_cond_signal (&op->cond); + + e_mutex_unlock (op->mutex); +} + +static void +cal_get_free_busy_cb (CalListener *listener, ECalendarStatus status, GList *freebusy, gpointer data) +{ + CalClient *client = data; + ECalendarOp *op; + GList *l; + + op = e_calendar_get_op (client); + + if (op == NULL) { + g_warning (G_STRLOC ": Cannot find operation "); + return; + } + + e_mutex_lock (op->mutex); + + op->status = status; + op->list = g_list_copy (freebusy); + + for (l = op->list; l; l = l->next) + l->data = cal_component_clone (l->data); + + pthread_cond_signal (&op->cond); + + e_mutex_unlock (op->mutex); +} + +static void +cal_query_cb (CalListener *listener, ECalendarStatus status, GNOME_Evolution_Calendar_Query query, gpointer data) +{ + CalClient *client = data; + ECalendarOp *op; + + op = e_calendar_get_op (client); + + if (op == NULL) { + g_warning (G_STRLOC ": Cannot find operation "); + return; + } + + e_mutex_lock (op->mutex); + + op->status = status; + op->query = cal_query_new (query, op->listener, client); + + pthread_cond_signal (&op->cond); + + e_mutex_unlock (op->mutex); } /* Handle the cal_set_mode notification from the listener */ @@ -624,26 +909,6 @@ cal_set_mode_cb (CalListener *listener, g_object_unref (G_OBJECT (client)); } -/* Handle the obj_updated signal from the listener */ -static void -obj_updated_cb (CalListener *listener, const CORBA_char *uid, gpointer data) -{ - CalClient *client; - - client = CAL_CLIENT (data); - g_signal_emit (G_OBJECT (client), cal_client_signals[OBJ_UPDATED], 0, uid); -} - -/* Handle the obj_removed signal from the listener */ -static void -obj_removed_cb (CalListener *listener, const CORBA_char *uid, gpointer data) -{ - CalClient *client; - - client = CAL_CLIENT (data); - g_signal_emit (G_OBJECT (client), cal_client_signals[OBJ_REMOVED], 0, uid); -} - /* Handle the error_occurred signal from the listener */ static void backend_error_cb (CalListener *listener, const char *message, gpointer data) @@ -678,97 +943,343 @@ categories_changed_cb (CalListener *listener, const GNOME_Evolution_Calendar_Str -static GList * -get_factories (void) +static gboolean +get_factories (const char *str_uri, GList **factories) { - GList *factories = NULL; GNOME_Evolution_Calendar_CalFactory factory; Bonobo_ServerInfoList *servers; - CORBA_Environment ev; + EUri *uri; + char *query; int i; - CORBA_exception_init (&ev); - servers = bonobo_activation_query ("repo_ids.has ('IDL:GNOME/Evolution/Calendar/CalFactory:1.0')", NULL, &ev); - if (ev._major != CORBA_NO_EXCEPTION) { - g_message ("Cannot perform OAF query for Calendar servers."); - CORBA_exception_free (&ev); - return NULL; + /* Determine the protocol and query for factory supporting that */ + uri = e_uri_new (str_uri); + if (!uri) { + g_warning (G_STRLOC ": Invalid uri string"); + + return FALSE; } - if (servers->_length == 0) - g_warning ("No Calendar servers installed."); + query = g_strdup_printf ("repo_ids.has ('IDL:GNOME/Evolution/Calendar/CalFactory:1.0')" + " AND calendar:supported_protocols.has ('%s')", uri->protocol); + + + servers = bonobo_activation_query (query, NULL, NULL); + + g_free (query); + e_uri_free (uri); + if (!servers) { + g_warning (G_STRLOC ": Unable to query for calendar factories"); + + return FALSE; + } + + /* Try to activate the servers for the protocol */ for (i = 0; i < servers->_length; i++) { const Bonobo_ServerInfo *info; info = servers->_buffer + i; - factory = (GNOME_Evolution_Calendar_CalFactory) - bonobo_activation_activate_from_id (info->iid, 0, NULL, &ev); - if (BONOBO_EX (&ev)) { -#if 0 - g_warning ("cal_client_construct: Could not activate calendar server %s", info->iid); - CORBA_free (servers); - CORBA_exception_free (&ev); - return NULL; -#endif - } + g_message (G_STRLOC ": Activating calendar factory (%s)", info->iid); + factory = bonobo_activation_activate_from_id (info->iid, 0, NULL, NULL); + + if (factory == CORBA_OBJECT_NIL) + g_warning (G_STRLOC ": Could not activate calendar factory (%s)", info->iid); else - factories = g_list_prepend (factories, factory); + *factories = g_list_append (*factories, factory); } CORBA_free (servers); - CORBA_exception_free (&ev); - return factories; + + return TRUE; } -/** - * cal_client_construct: - * @client: A calendar client. - * - * Constructs a calendar client object by contacting all available - * calendar factories. +/* Object initialization function for the calendar client */ +static void +cal_client_init (CalClient *client, CalClientClass *klass) +{ + CalClientPrivate *priv; + + priv = g_new0 (CalClientPrivate, 1); + client->priv = priv; + + priv->load_state = CAL_CLIENT_LOAD_NOT_LOADED; + priv->uri = NULL; + priv->mutex = e_mutex_new (E_MUTEX_REC); + priv->listener = cal_listener_new (cal_set_mode_cb, + backend_error_cb, + categories_changed_cb, + client); + + priv->cal_address = NULL; + priv->alarm_email_address = NULL; + priv->ldap_attribute = NULL; + priv->capabilities = FALSE; + priv->factories = NULL; + priv->timezones = g_hash_table_new (g_str_hash, g_str_equal); + priv->default_zone = icaltimezone_get_utc_timezone (); + priv->comp_listener = NULL; + + g_signal_connect (G_OBJECT (priv->listener), "read_only", G_CALLBACK (cal_read_only_cb), client); + g_signal_connect (G_OBJECT (priv->listener), "cal_address", G_CALLBACK (cal_cal_address_cb), client); + g_signal_connect (G_OBJECT (priv->listener), "alarm_address", G_CALLBACK (cal_alarm_address_cb), client); + g_signal_connect (G_OBJECT (priv->listener), "ldap_attribute", G_CALLBACK (cal_ldap_attribute_cb), client); + g_signal_connect (G_OBJECT (priv->listener), "static_capabilities", G_CALLBACK (cal_static_capabilities_cb), client); + g_signal_connect (G_OBJECT (priv->listener), "open", G_CALLBACK (cal_opened_cb), client); + g_signal_connect (G_OBJECT (priv->listener), "remove", G_CALLBACK (cal_removed_cb), client); + g_signal_connect (G_OBJECT (priv->listener), "create_object", G_CALLBACK (cal_object_created_cb), client); + g_signal_connect (G_OBJECT (priv->listener), "modify_object", G_CALLBACK (cal_object_modified_cb), client); + g_signal_connect (G_OBJECT (priv->listener), "remove_object", G_CALLBACK (cal_object_removed_cb), client); + g_signal_connect (G_OBJECT (priv->listener), "discard_alarm", G_CALLBACK (cal_alarm_discarded_cb), client); + g_signal_connect (G_OBJECT (priv->listener), "receive_objects", G_CALLBACK (cal_objects_received_cb), client); + g_signal_connect (G_OBJECT (priv->listener), "send_objects", G_CALLBACK (cal_objects_sent_cb), client); + g_signal_connect (G_OBJECT (priv->listener), "default_object", G_CALLBACK (cal_default_object_requested_cb), client); + g_signal_connect (G_OBJECT (priv->listener), "object", G_CALLBACK (cal_object_requested_cb), client); + g_signal_connect (G_OBJECT (priv->listener), "object_list", G_CALLBACK (cal_object_list_cb), client); + g_signal_connect (G_OBJECT (priv->listener), "get_timezone", G_CALLBACK (cal_get_timezone_cb), client); + g_signal_connect (G_OBJECT (priv->listener), "add_timezone", G_CALLBACK (cal_add_timezone_cb), client); + g_signal_connect (G_OBJECT (priv->listener), "set_default_timezone", G_CALLBACK (cal_set_default_timezone_cb), client); + g_signal_connect (G_OBJECT (priv->listener), "get_changes", G_CALLBACK (cal_get_changes_cb), client); + g_signal_connect (G_OBJECT (priv->listener), "get_free_busy", G_CALLBACK (cal_get_free_busy_cb), client); + g_signal_connect (G_OBJECT (priv->listener), "query", G_CALLBACK (cal_query_cb), client); +} + +/* Finalize handler for the calendar client */ +static void +cal_client_finalize (GObject *object) +{ + CalClient *client; + CalClientPrivate *priv; + + g_return_if_fail (object != NULL); + g_return_if_fail (IS_CAL_CLIENT (object)); + + client = CAL_CLIENT (object); + priv = client->priv; + + if (priv->listener) { + cal_listener_stop_notification (priv->listener); + bonobo_object_unref (priv->listener); + priv->listener = NULL; + } + + if (priv->comp_listener) { + g_signal_handlers_disconnect_matched (G_OBJECT (priv->comp_listener), + G_SIGNAL_MATCH_DATA, + 0, 0, NULL, NULL, + client); + g_object_unref (G_OBJECT (priv->comp_listener)); + priv->comp_listener = NULL; + } + + destroy_factories (client); + destroy_cal (client); + + priv->load_state = CAL_CLIENT_LOAD_NOT_LOADED; + + if (priv->uri) { + g_free (priv->uri); + priv->uri = NULL; + } + + if (priv->mutex) { + e_mutex_destroy (priv->mutex); + priv->mutex = NULL; + } + + if (priv->cal_address) { + g_free (priv->cal_address); + priv->cal_address = NULL; + } + if (priv->alarm_email_address) { + g_free (priv->alarm_email_address); + priv->alarm_email_address = NULL; + } + if (priv->ldap_attribute) { + g_free (priv->ldap_attribute); + priv->ldap_attribute = NULL; + } + if (priv->capabilities) { + g_free (priv->capabilities); + priv->capabilities = NULL; + } + + g_hash_table_foreach (priv->timezones, free_timezone, NULL); + g_hash_table_destroy (priv->timezones); + priv->timezones = NULL; + + g_free (priv); + client->priv = NULL; + + if (G_OBJECT_CLASS (parent_class)->finalize) + (* G_OBJECT_CLASS (parent_class)->finalize) (object); +} + +/* Class initialization function for the calendar client */ +static void +cal_client_class_init (CalClientClass *klass) +{ + GObjectClass *object_class; + + object_class = (GObjectClass *) klass; + + parent_class = g_type_class_peek_parent (klass); + + cal_client_signals[CAL_OPENED] = + g_signal_new ("cal_opened", + G_TYPE_FROM_CLASS (klass), + G_SIGNAL_RUN_FIRST, + G_STRUCT_OFFSET (CalClientClass, cal_opened), + NULL, NULL, + g_cclosure_marshal_VOID__ENUM, + G_TYPE_NONE, 1, + CAL_CLIENT_OPEN_STATUS_ENUM_TYPE); + cal_client_signals[CAL_SET_MODE] = + g_signal_new ("cal_set_mode", + G_TYPE_FROM_CLASS (klass), + G_SIGNAL_RUN_FIRST, + G_STRUCT_OFFSET (CalClientClass, cal_set_mode), + NULL, NULL, + cal_util_marshal_VOID__ENUM_ENUM, + G_TYPE_NONE, 2, + CAL_CLIENT_SET_MODE_STATUS_ENUM_TYPE, + CAL_MODE_ENUM_TYPE); + cal_client_signals[BACKEND_ERROR] = + g_signal_new ("backend_error", + G_TYPE_FROM_CLASS (klass), + G_SIGNAL_RUN_FIRST, + G_STRUCT_OFFSET (CalClientClass, backend_error), + NULL, NULL, + g_cclosure_marshal_VOID__STRING, + G_TYPE_NONE, 1, + G_TYPE_STRING); + cal_client_signals[CATEGORIES_CHANGED] = + g_signal_new ("categories_changed", + G_TYPE_FROM_CLASS (klass), + G_SIGNAL_RUN_FIRST, + G_STRUCT_OFFSET (CalClientClass, categories_changed), + NULL, NULL, + g_cclosure_marshal_VOID__POINTER, + G_TYPE_NONE, 1, + G_TYPE_POINTER); + cal_client_signals[FORGET_PASSWORD] = + g_signal_new ("forget_password", + G_TYPE_FROM_CLASS (klass), + G_SIGNAL_RUN_FIRST, + G_STRUCT_OFFSET (CalClientClass, forget_password), + NULL, NULL, + g_cclosure_marshal_VOID__STRING, + G_TYPE_NONE, 1, + G_TYPE_STRING); + cal_client_signals[BACKEND_DIED] = + g_signal_new ("backend_died", + G_TYPE_FROM_CLASS (klass), + G_SIGNAL_RUN_FIRST, + G_STRUCT_OFFSET (CalClientClass, backend_died), + NULL, NULL, + g_cclosure_marshal_VOID__VOID, + G_TYPE_NONE, 0); + + klass->cal_opened = NULL; + klass->categories_changed = NULL; + klass->forget_password = NULL; + klass->backend_died = NULL; + + object_class->finalize = cal_client_finalize; +} + +/** + * cal_client_get_type: * - * Return value: The same object as the @client argument, or NULL if the - * calendar factory could not be contacted. + * Registers the #CalClient class if necessary, and returns the type ID assigned + * to it. + * + * Return value: The type ID of the #CalClient class. **/ -CalClient * -cal_client_construct (CalClient *client) +GType +cal_client_get_type (void) { - CalClientPrivate *priv; + static GType cal_client_type = 0; - g_return_val_if_fail (client != NULL, NULL); - g_return_val_if_fail (IS_CAL_CLIENT (client), NULL); + if (!cal_client_type) { + static GTypeInfo info = { + sizeof (CalClientClass), + (GBaseInitFunc) NULL, + (GBaseFinalizeFunc) NULL, + (GClassInitFunc) cal_client_class_init, + NULL, NULL, + sizeof (CalClient), + 0, + (GInstanceInitFunc) cal_client_init + }; + cal_client_type = g_type_register_static (G_TYPE_OBJECT, "CalClient", &info, 0); + } + return cal_client_type; +} + + +static gboolean +fetch_corba_cal (CalClient *client, const char *str_uri, CalObjType type) +{ + CalClientPrivate *priv; + GList *f; + CORBA_Environment ev; + priv = client->priv; - priv->factories = get_factories (); + g_return_val_if_fail (priv->load_state == CAL_CLIENT_LOAD_NOT_LOADED, FALSE); + g_assert (priv->uri == NULL); - return client; + g_return_val_if_fail (str_uri != NULL, FALSE); + + if (!get_factories (str_uri, &priv->factories)) + return FALSE; + + priv->uri = g_strdup (str_uri); + priv->type = type; + + for (f = priv->factories; f; f = f->next) { + GNOME_Evolution_Calendar_Cal cal; + + CORBA_exception_init (&ev); + + cal = GNOME_Evolution_Calendar_CalFactory_getCal (f->data, priv->uri, priv->type, + BONOBO_OBJREF (priv->listener), &ev); + if (BONOBO_EX (&ev)) + continue; + + priv->cal = cal; + + return TRUE; + } + + return FALSE; } /** * cal_client_new: * * Creates a new calendar client. It should be initialized by calling - * cal_client_open_calendar(). + * cal_client_open(). * * Return value: A newly-created calendar client, or NULL if the client could * not be constructed because it could not contact the calendar server. **/ CalClient * -cal_client_new (void) +cal_client_new (const char *uri, CalObjType type) { CalClient *client; client = g_object_new (CAL_CLIENT_TYPE, NULL); - if (!cal_client_construct (client)) { - g_message ("cal_client_new(): could not construct the calendar client"); - g_object_unref (G_OBJECT (client)); + if (!fetch_corba_cal (client, uri, type)) { + g_object_unref (client); + return NULL; } - + return client; } @@ -800,175 +1311,183 @@ cal_client_set_auth_func (CalClient *client, CalClientAuthFunc func, gpointer da client->priv->auth_user_data = data; } -static gboolean -real_open_calendar (CalClient *client, const char *str_uri, gboolean only_if_exists, gboolean *supported) +/** + * cal_client_open + * @client: A calendar client. + * @str_uri: URI of calendar to open. + * @only_if_exists: FALSE if the calendar should be opened even if there + * was no storage for it, i.e. to create a new calendar or load an existing + * one if it already exists. TRUE if it should only try to load calendars + * that already exist. + * + * Makes a calendar client initiate a request to open a calendar. The calendar + * client will emit the "cal_opened" signal when the response from the server is + * received. + * + * Return value: TRUE on success, FALSE on failure to issue the open request. + **/ +gboolean +cal_client_open (CalClient *client, gboolean only_if_exists, GError **error) { CalClientPrivate *priv; - GNOME_Evolution_Calendar_Listener corba_listener; - int unsupported; - GList *f; CORBA_Environment ev; + ECalendarStatus status; + ECalendarOp *our_op; - priv = client->priv; - g_return_val_if_fail (priv->load_state == CAL_CLIENT_LOAD_NOT_LOADED, FALSE); - g_assert (priv->uri == NULL); + g_return_val_if_fail (client != NULL, FALSE); + g_return_val_if_fail (IS_CAL_CLIENT (client), FALSE); - g_return_val_if_fail (str_uri != NULL, FALSE); + priv = client->priv; + + e_mutex_lock (client->priv->mutex); - priv->listener = cal_listener_new (cal_opened_cb, - cal_set_mode_cb, - obj_updated_cb, - obj_removed_cb, - backend_error_cb, - categories_changed_cb, - client); - if (!priv->listener) { - g_message ("cal_client_open_calendar(): could not create the listener"); - return FALSE; + if (client->priv->current_op != NULL) { + e_mutex_unlock (client->priv->mutex); + E_CALENDAR_CHECK_STATUS (E_CALENDAR_STATUS_BUSY, error); } - corba_listener = (GNOME_Evolution_Calendar_Listener) (BONOBO_OBJREF (priv->listener)); + our_op = e_calendar_new_op (client); - priv->load_state = CAL_CLIENT_LOAD_LOADING; - priv->uri = g_strdup (str_uri); + e_mutex_lock (our_op->mutex); - unsupported = 0; - for (f = priv->factories; f; f = f->next) { - CORBA_exception_init (&ev); + e_mutex_unlock (client->priv->mutex); - GNOME_Evolution_Calendar_CalFactory_open (f->data, str_uri, - only_if_exists, - corba_listener, &ev); - if (!BONOBO_EX (&ev)) { - if (supported != NULL) - *supported = TRUE; - return TRUE; - } + CORBA_exception_init (&ev); + + priv->load_state = CAL_CLIENT_LOAD_LOADING; + + GNOME_Evolution_Calendar_Cal_open (priv->cal, only_if_exists, &ev); + if (BONOBO_EX (&ev)) { + e_calendar_remove_op (client, our_op); + e_mutex_unlock (our_op->mutex); + e_calendar_free_op (our_op); - if (BONOBO_USER_EX (&ev, ex_GNOME_Evolution_Calendar_CalFactory_UnsupportedMethod)) - unsupported++; CORBA_exception_free (&ev); + + g_warning (G_STRLOC ": Unable to contact backend"); + + g_signal_emit (G_OBJECT (client), cal_client_signals[CAL_OPENED], 0, + E_CALENDAR_STATUS_CORBA_EXCEPTION); + E_CALENDAR_CHECK_STATUS (E_CALENDAR_STATUS_CORBA_EXCEPTION, error); } - if (supported != NULL) { - if (unsupported == g_list_length (priv->factories)) - *supported = FALSE; - else - *supported = TRUE; - } + CORBA_exception_free (&ev); + + /* wait for something to happen (both cancellation and a + successful response will notity us via our cv */ + e_mutex_cond_wait (&our_op->cond, our_op->mutex); + + status = our_op->status; - bonobo_object_unref (BONOBO_OBJECT (priv->listener)); - priv->listener = NULL; - priv->load_state = CAL_CLIENT_LOAD_NOT_LOADED; - g_free (priv->uri); - priv->uri = NULL; + e_calendar_remove_op (client, our_op); + e_mutex_unlock (our_op->mutex); + e_calendar_free_op (our_op); - return FALSE; + if (status == E_CALENDAR_STATUS_OK) + priv->load_state = CAL_CLIENT_LOAD_LOADED; + else + priv->load_state = CAL_CLIENT_LOAD_NOT_LOADED; + + g_signal_emit (G_OBJECT (client), cal_client_signals[CAL_OPENED], 0, status); + E_CALENDAR_CHECK_STATUS (status, error); } -/** - * cal_client_open_calendar: - * @client: A calendar client. - * @str_uri: URI of calendar to open. - * @only_if_exists: FALSE if the calendar should be opened even if there - * was no storage for it, i.e. to create a new calendar or load an existing - * one if it already exists. TRUE if it should only try to load calendars - * that already exist. - * - * Makes a calendar client initiate a request to open a calendar. The calendar - * client will emit the "cal_opened" signal when the response from the server is - * received. - * - * Return value: TRUE on success, FALSE on failure to issue the open request. - **/ -gboolean -cal_client_open_calendar (CalClient *client, const char *str_uri, gboolean only_if_exists) +typedef struct { + CalClient *client; + + gboolean exists; +} CalClientAsyncData; + +static gboolean +open_async (gpointer data) { - g_return_val_if_fail (client != NULL, FALSE); - g_return_val_if_fail (IS_CAL_CLIENT (client), FALSE); + CalClientAsyncData *ccad = data; + GError *error = NULL; - return real_open_calendar (client, str_uri, only_if_exists, NULL); -} + cal_client_open (ccad->client, ccad->exists, &error); -static char * -get_fall_back_uri (gboolean tasks) -{ - if (tasks) - return g_concat_dir_and_file (g_get_home_dir (), - "evolution/local/" - "Tasks/tasks.ics"); - else - return g_concat_dir_and_file (g_get_home_dir (), - "evolution/local/" - "Calendar/calendar.ics"); + g_clear_error (&error); + + g_object_unref (ccad); + g_free (ccad); + + return FALSE; } -static char * -get_default_uri (gboolean tasks) +void +cal_client_open_async (CalClient *client, gboolean only_if_exists) { - EConfigListener *db; - char *uri; - - db = e_config_listener_new (); + CalClientAsyncData *ccad; - if (tasks) - uri = e_config_listener_get_string (db, "/apps/evolution/shell/default_folders/tasks_uri"); - else - uri = e_config_listener_get_string (db, "/apps/evolution/shell/default_folders/calendar_uri"); - g_object_unref (G_OBJECT (db)); + g_return_if_fail (client != NULL); + g_return_if_fail (IS_CAL_CLIENT (client)); - if (!uri || *uri == '\0') - uri = get_fall_back_uri (tasks); - else - uri = cal_util_expand_uri (uri, tasks); - - return uri; + ccad = g_new0 (CalClientAsyncData, 1); + ccad->client = g_object_ref (client); + ccad->exists = only_if_exists; + + /* FIXME This should really spawn a new thread */ + g_idle_add (open_async, ccad); } -gboolean -cal_client_open_default_calendar (CalClient *client, gboolean only_if_exists) +gboolean +cal_client_remove_calendar (CalClient *client, GError **error) { - char *default_uri, *fall_back; - gboolean result, supported; - + CalClientPrivate *priv; + CORBA_Environment ev; + ECalendarStatus status; + ECalendarOp *our_op; + g_return_val_if_fail (client != NULL, FALSE); g_return_val_if_fail (IS_CAL_CLIENT (client), FALSE); - default_uri = get_default_uri (FALSE); - fall_back = get_fall_back_uri (FALSE); + priv = client->priv; - result = real_open_calendar (client, default_uri, only_if_exists, &supported); - if (!supported && strcmp (fall_back, default_uri)) - result = real_open_calendar (client, fall_back, only_if_exists, NULL); + e_mutex_lock (client->priv->mutex); - g_free (default_uri); - g_free (fall_back); - - return result; -} + if (client->priv->current_op != NULL) { + e_mutex_unlock (client->priv->mutex); + E_CALENDAR_CHECK_STATUS (E_CALENDAR_STATUS_BUSY, error); + } -gboolean -cal_client_open_default_tasks (CalClient *client, gboolean only_if_exists) -{ - char *default_uri, *fall_back; - gboolean result, supported; + our_op = e_calendar_new_op (client); - g_return_val_if_fail (client != NULL, FALSE); - g_return_val_if_fail (IS_CAL_CLIENT (client), FALSE); + e_mutex_lock (our_op->mutex); + + e_mutex_unlock (client->priv->mutex); + + + CORBA_exception_init (&ev); + + GNOME_Evolution_Calendar_Cal_remove (priv->cal, &ev); + if (BONOBO_EX (&ev)) { + e_calendar_remove_op (client, our_op); + e_mutex_unlock (our_op->mutex); + e_calendar_free_op (our_op); - default_uri = get_default_uri (TRUE); - fall_back = get_fall_back_uri (TRUE); + CORBA_exception_free (&ev); + + g_warning (G_STRLOC ": Unable to contact backend"); + + E_CALENDAR_CHECK_STATUS (E_CALENDAR_STATUS_CORBA_EXCEPTION, error); + } - result = real_open_calendar (client, default_uri, only_if_exists, &supported); - if (!supported && strcmp (fall_back, default_uri)) - result = real_open_calendar (client, fall_back, only_if_exists, NULL); + CORBA_exception_free (&ev); + + /* wait for something to happen (both cancellation and a + successful response will notity us via our cv */ + e_mutex_cond_wait (&our_op->cond, our_op->mutex); - g_free (default_uri); - g_free (fall_back); + status = our_op->status; + + e_calendar_remove_op (client, our_op); + e_mutex_unlock (our_op->mutex); + e_calendar_free_op (our_op); - return result; + E_CALENDAR_CHECK_STATUS (status, error); } +#if 0 /* Builds an URI list out of a CORBA string sequence */ static GList * build_uri_list (GNOME_Evolution_Calendar_StringSeq *seq) @@ -981,6 +1500,7 @@ build_uri_list (GNOME_Evolution_Calendar_StringSeq *seq) return uris; } +#endif /** * cal_client_uri_list: @@ -993,6 +1513,7 @@ build_uri_list (GNOME_Evolution_Calendar_StringSeq *seq) GList * cal_client_uri_list (CalClient *client, CalMode mode) { +#if 0 CalClientPrivate *priv; GNOME_Evolution_Calendar_StringSeq *uri_seq; GList *uris = NULL; @@ -1026,8 +1547,12 @@ cal_client_uri_list (CalClient *client, CalMode mode) } return uris; +#endif + + return NULL; } + /** * cal_client_get_load_state: * @client: A calendar client. @@ -1076,33 +1601,72 @@ cal_client_get_uri (CalClient *client) * @client: A calendar client. * * Queries whether the calendar client can perform modifications - * on the calendar or not. + * on the calendar or not. Whether the backend is read only or not + * is specified, on exit, in the @read_only argument. * - * Return value: TRUE if the calendar is read-only, FALSE otherwise. + * Return value: TRUE if the call was successful, FALSE if there was an error. */ gboolean -cal_client_is_read_only (CalClient *client) +cal_client_is_read_only (CalClient *client, gboolean *read_only, GError **error) { CalClientPrivate *priv; CORBA_Environment ev; - CORBA_boolean read_only; - + ECalendarStatus status; + ECalendarOp *our_op; + g_return_val_if_fail (client != NULL, FALSE); g_return_val_if_fail (IS_CAL_CLIENT (client), FALSE); priv = client->priv; + + e_mutex_lock (client->priv->mutex); + + if (client->priv->load_state != CAL_CLIENT_LOAD_LOADED) { + e_mutex_unlock (client->priv->mutex); + E_CALENDAR_CHECK_STATUS (E_CALENDAR_STATUS_URI_NOT_LOADED, error); + } + + if (client->priv->current_op != NULL) { + e_mutex_unlock (client->priv->mutex); + E_CALENDAR_CHECK_STATUS (E_CALENDAR_STATUS_BUSY, error); + } + + our_op = e_calendar_new_op (client); + + e_mutex_lock (our_op->mutex); + + e_mutex_unlock (client->priv->mutex); - if (priv->load_state != CAL_CLIENT_LOAD_LOADED) - return FALSE; CORBA_exception_init (&ev); - read_only = GNOME_Evolution_Calendar_Cal_isReadOnly (priv->cal, &ev); + + GNOME_Evolution_Calendar_Cal_isReadOnly (priv->cal, &ev); if (BONOBO_EX (&ev)) { - g_message ("cal_client_is_read_only: could not call isReadOnly method"); + e_calendar_remove_op (client, our_op); + e_mutex_unlock (our_op->mutex); + e_calendar_free_op (our_op); + + CORBA_exception_free (&ev); + + g_warning (G_STRLOC ": Unable to contact backend"); + + E_CALENDAR_CHECK_STATUS (E_CALENDAR_STATUS_CORBA_EXCEPTION, error); } + CORBA_exception_free (&ev); - return read_only; + /* wait for something to happen (both cancellation and a + successful response will notity us via our cv */ + e_mutex_cond_wait (&our_op->cond, our_op->mutex); + + status = our_op->status; + *read_only = our_op->bool; + + e_calendar_remove_op (client, our_op); + e_mutex_unlock (our_op->mutex); + e_calendar_free_op (our_op); + + return status; } /** @@ -1115,119 +1679,269 @@ cal_client_is_read_only (CalClient *client) * is loaded or being loaded, or %NULL if the client has not started a * load request yet or the calendar has no associated email address. **/ -const char * -cal_client_get_cal_address (CalClient *client) +gboolean +cal_client_get_cal_address (CalClient *client, char **cal_address, GError **error) { CalClientPrivate *priv; - - g_return_val_if_fail (client != NULL, NULL); - g_return_val_if_fail (IS_CAL_CLIENT (client), NULL); + CORBA_Environment ev; + ECalendarStatus status; + ECalendarOp *our_op; + + g_return_val_if_fail (client != NULL, FALSE); + g_return_val_if_fail (IS_CAL_CLIENT (client), FALSE); priv = client->priv; - g_return_val_if_fail (priv->load_state == CAL_CLIENT_LOAD_LOADED, NULL); + + e_mutex_lock (client->priv->mutex); - if (priv->cal_address == NULL) { - CORBA_Environment ev; - CORBA_char *cal_address; + if (client->priv->load_state != CAL_CLIENT_LOAD_LOADED) { + e_mutex_unlock (client->priv->mutex); + E_CALENDAR_CHECK_STATUS (E_CALENDAR_STATUS_URI_NOT_LOADED, error); + } + + if (client->priv->current_op != NULL) { + e_mutex_unlock (client->priv->mutex); + E_CALENDAR_CHECK_STATUS (E_CALENDAR_STATUS_BUSY, error); + } + + our_op = e_calendar_new_op (client); + + e_mutex_lock (our_op->mutex); + + e_mutex_unlock (client->priv->mutex); + + + CORBA_exception_init (&ev); + + GNOME_Evolution_Calendar_Cal_getCalAddress (priv->cal, &ev); + if (BONOBO_EX (&ev)) { + e_calendar_remove_op (client, our_op); + e_mutex_unlock (our_op->mutex); + e_calendar_free_op (our_op); - CORBA_exception_init (&ev); - cal_address = GNOME_Evolution_Calendar_Cal_getCalAddress (priv->cal, &ev); - if (!BONOBO_EX (&ev)) { - priv->cal_address = g_strdup (cal_address); - CORBA_free (cal_address); - } CORBA_exception_free (&ev); + + g_warning (G_STRLOC ": Unable to contact backend"); + + E_CALENDAR_CHECK_STATUS (E_CALENDAR_STATUS_CORBA_EXCEPTION, error); } - return priv->cal_address; + CORBA_exception_free (&ev); + + /* wait for something to happen (both cancellation and a + successful response will notity us via our cv */ + e_mutex_cond_wait (&our_op->cond, our_op->mutex); + + status = our_op->status; + *cal_address = our_op->string; + + e_calendar_remove_op (client, our_op); + e_mutex_unlock (our_op->mutex); + e_calendar_free_op (our_op); + + E_CALENDAR_CHECK_STATUS (status, error); } -const char * -cal_client_get_alarm_email_address (CalClient *client) +gboolean +cal_client_get_alarm_email_address (CalClient *client, char **alarm_address, GError **error) { CalClientPrivate *priv; + CORBA_Environment ev; + ECalendarStatus status; + ECalendarOp *our_op; - g_return_val_if_fail (client != NULL, NULL); - g_return_val_if_fail (IS_CAL_CLIENT (client), NULL); + g_return_val_if_fail (client != NULL, FALSE); + g_return_val_if_fail (IS_CAL_CLIENT (client), FALSE); priv = client->priv; - g_return_val_if_fail (priv->load_state == CAL_CLIENT_LOAD_LOADED, NULL); - if (priv->alarm_email_address == NULL) { - CORBA_Environment ev; - CORBA_char *email_address; + e_mutex_lock (client->priv->mutex); + + if (client->priv->load_state != CAL_CLIENT_LOAD_LOADED) { + e_mutex_unlock (client->priv->mutex); + E_CALENDAR_CHECK_STATUS (E_CALENDAR_STATUS_URI_NOT_LOADED, error); + } + + if (client->priv->current_op != NULL) { + e_mutex_unlock (client->priv->mutex); + E_CALENDAR_CHECK_STATUS (E_CALENDAR_STATUS_BUSY, error); + } + + our_op = e_calendar_new_op (client); + + e_mutex_lock (our_op->mutex); + + e_mutex_unlock (client->priv->mutex); + + + CORBA_exception_init (&ev); + + GNOME_Evolution_Calendar_Cal_getAlarmEmailAddress (priv->cal, &ev); + if (BONOBO_EX (&ev)) { + e_calendar_remove_op (client, our_op); + e_mutex_unlock (our_op->mutex); + e_calendar_free_op (our_op); - CORBA_exception_init (&ev); - email_address = GNOME_Evolution_Calendar_Cal_getAlarmEmailAddress (priv->cal, &ev); - if (!BONOBO_EX (&ev)) { - priv->alarm_email_address = g_strdup (email_address); - CORBA_free (email_address); - } CORBA_exception_free (&ev); + + g_warning (G_STRLOC ": Unable to contact backend"); + + E_CALENDAR_CHECK_STATUS (E_CALENDAR_STATUS_CORBA_EXCEPTION, error); } - return priv->alarm_email_address; + CORBA_exception_free (&ev); + + /* wait for something to happen (both cancellation and a + successful response will notity us via our cv */ + e_mutex_cond_wait (&our_op->cond, our_op->mutex); + + status = our_op->status; + *alarm_address = our_op->string; + + e_calendar_remove_op (client, our_op); + e_mutex_unlock (our_op->mutex); + e_calendar_free_op (our_op); + + E_CALENDAR_CHECK_STATUS (status, error); } -const char * -cal_client_get_ldap_attribute (CalClient *client) +gboolean +cal_client_get_ldap_attribute (CalClient *client, char **ldap_attribute, GError **error) { CalClientPrivate *priv; + CORBA_Environment ev; + ECalendarStatus status; + ECalendarOp *our_op; - g_return_val_if_fail (client != NULL, NULL); - g_return_val_if_fail (IS_CAL_CLIENT (client), NULL); + g_return_val_if_fail (client != NULL, FALSE); + g_return_val_if_fail (IS_CAL_CLIENT (client), FALSE); priv = client->priv; - g_return_val_if_fail (priv->load_state == CAL_CLIENT_LOAD_LOADED, NULL); - if (priv->ldap_attribute == NULL) { - CORBA_Environment ev; - CORBA_char *ldap_attribute; + e_mutex_lock (client->priv->mutex); + + if (client->priv->load_state != CAL_CLIENT_LOAD_LOADED) { + e_mutex_unlock (client->priv->mutex); + E_CALENDAR_CHECK_STATUS (E_CALENDAR_STATUS_URI_NOT_LOADED, error); + } + + if (client->priv->current_op != NULL) { + e_mutex_unlock (client->priv->mutex); + E_CALENDAR_CHECK_STATUS (E_CALENDAR_STATUS_BUSY, error); + } + + our_op = e_calendar_new_op (client); + + e_mutex_lock (our_op->mutex); + + e_mutex_unlock (client->priv->mutex); + + + CORBA_exception_init (&ev); + + GNOME_Evolution_Calendar_Cal_getLdapAttribute (priv->cal, &ev); + if (BONOBO_EX (&ev)) { + e_calendar_remove_op (client, our_op); + e_mutex_unlock (our_op->mutex); + e_calendar_free_op (our_op); - CORBA_exception_init (&ev); - ldap_attribute = GNOME_Evolution_Calendar_Cal_getLdapAttribute (priv->cal, &ev); - if (!BONOBO_EX (&ev)) { - priv->ldap_attribute = g_strdup (ldap_attribute); - CORBA_free (ldap_attribute); - } CORBA_exception_free (&ev); + + g_warning (G_STRLOC ": Unable to contact backend"); + + E_CALENDAR_CHECK_STATUS (E_CALENDAR_STATUS_CORBA_EXCEPTION, error); } - return priv->ldap_attribute; + CORBA_exception_free (&ev); + + /* wait for something to happen (both cancellation and a + successful response will notity us via our cv */ + e_mutex_cond_wait (&our_op->cond, our_op->mutex); + + status = our_op->status; + *ldap_attribute = our_op->string; + + e_calendar_remove_op (client, our_op); + e_mutex_unlock (our_op->mutex); + e_calendar_free_op (our_op); + + E_CALENDAR_CHECK_STATUS (status, error); } -static void -load_static_capabilities (CalClient *client) +static gboolean +load_static_capabilities (CalClient *client, GError **error) { CalClientPrivate *priv; CORBA_Environment ev; + ECalendarStatus status; + ECalendarOp *our_op; char *cap; priv = client->priv; if (priv->capabilities) - return; - + E_CALENDAR_CHECK_STATUS (E_CALENDAR_STATUS_OK, error); + + e_mutex_lock (client->priv->mutex); + + if (client->priv->load_state != CAL_CLIENT_LOAD_LOADED) { + e_mutex_unlock (client->priv->mutex); + E_CALENDAR_CHECK_STATUS (E_CALENDAR_STATUS_URI_NOT_LOADED, error); + } + + if (client->priv->current_op != NULL) { + e_mutex_unlock (client->priv->mutex); + E_CALENDAR_CHECK_STATUS (E_CALENDAR_STATUS_BUSY, error); + } + + our_op = e_calendar_new_op (client); + + e_mutex_lock (our_op->mutex); + + e_mutex_unlock (client->priv->mutex); + + CORBA_exception_init (&ev); - cap = GNOME_Evolution_Calendar_Cal_getStaticCapabilities (priv->cal, &ev); - if (!BONOBO_EX (&ev)) - priv->capabilities = g_strdup (cap); - else - priv->capabilities = g_strdup (""); - CORBA_free (cap); + GNOME_Evolution_Calendar_Cal_getStaticCapabilities (priv->cal, &ev); + if (BONOBO_EX (&ev)) { + e_calendar_remove_op (client, our_op); + e_mutex_unlock (our_op->mutex); + e_calendar_free_op (our_op); + + CORBA_exception_free (&ev); + + g_warning (G_STRLOC ": Unable to contact backend"); + + E_CALENDAR_CHECK_STATUS (E_CALENDAR_STATUS_CORBA_EXCEPTION, error); + } + CORBA_exception_free (&ev); + + /* wait for something to happen (both cancellation and a + successful response will notity us via our cv */ + e_mutex_cond_wait (&our_op->cond, our_op->mutex); + + status = our_op->status; + cap = our_op->string; + + e_calendar_remove_op (client, our_op); + e_mutex_unlock (our_op->mutex); + e_calendar_free_op (our_op); + + E_CALENDAR_CHECK_STATUS (status, error); } static gboolean check_capability (CalClient *client, const char *cap) { CalClientPrivate *priv; - + priv = client->priv; - load_static_capabilities (client); - if (strstr (priv->capabilities, cap)) + /* FIXME Check result */ + load_static_capabilities (client, NULL); + if (priv->capabilities && strstr (priv->capabilities, cap)) return TRUE; return FALSE; @@ -1269,15 +1983,6 @@ cal_client_get_save_schedules (CalClient *client) return check_capability (client, CAL_STATIC_CAPABILITY_SAVE_SCHEDULES); } -/* Converts our representation of a calendar component type into its CORBA representation */ -static GNOME_Evolution_Calendar_CalObjType -corba_obj_type (CalObjType type) -{ - return (((type & CALOBJ_TYPE_EVENT) ? GNOME_Evolution_Calendar_TYPE_EVENT : 0) - | ((type & CALOBJ_TYPE_TODO) ? GNOME_Evolution_Calendar_TYPE_TODO : 0) - | ((type & CALOBJ_TYPE_JOURNAL) ? GNOME_Evolution_Calendar_TYPE_JOURNAL : 0)); -} - gboolean cal_client_set_mode (CalClient *client, CalMode mode) { @@ -1302,45 +2007,6 @@ cal_client_set_mode (CalClient *client, CalMode mode) return retval; } -/** - * cal_client_get_n_objects: - * @client: A calendar client. - * @type: Type of objects that will be counted. - * - * Counts the number of calendar components of the specified @type. This can be - * used to count how many events, to-dos, or journals there are, for example. - * - * Return value: Number of components. - **/ -int -cal_client_get_n_objects (CalClient *client, CalObjType type) -{ - CalClientPrivate *priv; - CORBA_Environment ev; - int n; - int t; - - g_return_val_if_fail (client != NULL, -1); - g_return_val_if_fail (IS_CAL_CLIENT (client), -1); - - priv = client->priv; - g_return_val_if_fail (priv->load_state == CAL_CLIENT_LOAD_LOADED, -1); - - t = corba_obj_type (type); - - CORBA_exception_init (&ev); - n = GNOME_Evolution_Calendar_Cal_countObjects (priv->cal, t, &ev); - - if (BONOBO_EX (&ev)) { - g_message ("cal_client_get_n_objects(): could not get the number of objects"); - CORBA_exception_free (&ev); - return -1; - } - - CORBA_exception_free (&ev); - return n; -} - /* This is used in the callback which fetches all the timezones needed for an object. */ @@ -1348,68 +2014,93 @@ typedef struct _CalClientGetTimezonesData CalClientGetTimezonesData; struct _CalClientGetTimezonesData { CalClient *client; - /* This starts out at CAL_CLIENT_GET_SUCCESS. If an error occurs this + /* This starts out at E_CALENDAR_STATUS_OK. If an error occurs this contains the last error. */ - CalClientGetStatus status; + ECalendarStatus status; }; -CalClientGetStatus -cal_client_get_default_object (CalClient *client, CalObjType type, icalcomponent **icalcomp) +gboolean +cal_client_get_default_object (CalClient *client, icalcomponent **icalcomp, GError **error) { CalClientPrivate *priv; CORBA_Environment ev; - GNOME_Evolution_Calendar_CalObj comp_str; - CalClientGetStatus retval; - CalClientGetTimezonesData cb_data; + ECalendarStatus status; + ECalendarOp *our_op; - g_return_val_if_fail (client != NULL, CAL_CLIENT_GET_NOT_FOUND); - g_return_val_if_fail (IS_CAL_CLIENT (client), CAL_CLIENT_GET_NOT_FOUND); + g_return_val_if_fail (client != NULL, FALSE); + g_return_val_if_fail (IS_CAL_CLIENT (client), FALSE); priv = client->priv; - g_return_val_if_fail (priv->load_state == CAL_CLIENT_LOAD_LOADED, CAL_CLIENT_GET_NOT_FOUND); - g_return_val_if_fail (icalcomp != NULL, CAL_CLIENT_GET_NOT_FOUND); + e_mutex_lock (client->priv->mutex); + + if (client->priv->load_state != CAL_CLIENT_LOAD_LOADED) { + e_mutex_unlock (client->priv->mutex); + E_CALENDAR_CHECK_STATUS (E_CALENDAR_STATUS_URI_NOT_LOADED, error); + } + + if (client->priv->current_op != NULL) { + e_mutex_unlock (client->priv->mutex); + E_CALENDAR_CHECK_STATUS (E_CALENDAR_STATUS_BUSY, error); + } + + our_op = e_calendar_new_op (client); + + e_mutex_lock (our_op->mutex); + + e_mutex_unlock (client->priv->mutex); + + CORBA_exception_init (&ev); + + GNOME_Evolution_Calendar_Cal_getDefaultObject (priv->cal, &ev); + if (BONOBO_EX (&ev)) { + e_calendar_remove_op (client, our_op); + e_mutex_unlock (our_op->mutex); + e_calendar_free_op (our_op); - retval = CAL_CLIENT_GET_NOT_FOUND; - *icalcomp = NULL; + CORBA_exception_free (&ev); - CORBA_exception_init (&ev); - comp_str = GNOME_Evolution_Calendar_Cal_getDefaultObject (priv->cal, type, &ev); + g_warning (G_STRLOC ": Unable to contact backend"); - if (BONOBO_USER_EX (&ev, ex_GNOME_Evolution_Calendar_Cal_NotFound)) - goto out; - else if (BONOBO_EX (&ev)) { - g_message ("cal_client_get_default_object(): could not get the object"); - goto out; + E_CALENDAR_CHECK_STATUS (E_CALENDAR_STATUS_CORBA_EXCEPTION, error); } - *icalcomp = icalparser_parse_string (comp_str); - CORBA_free (comp_str); + CORBA_exception_free (&ev); - if (!*icalcomp) { - retval = CAL_CLIENT_GET_SYNTAX_ERROR; - goto out; - } + /* wait for something to happen (both cancellation and a + successful response will notity us via our cv */ + e_mutex_cond_wait (&our_op->cond, our_op->mutex); - /* Now make sure we have all timezones needed for this object. - We do this to try to avoid any problems caused by getting a timezone - in the middle of other code. Any calls to ORBit result in a - recursive call of the GTK+ main loop, which can cause problems for - code that doesn't expect it. Currently GnomeCanvas has problems if - we try to get a timezone in the middle of a redraw, and there is a - resize pending, which leads to an assert failure and an abort. */ - cb_data.client = client; - cb_data.status = CAL_CLIENT_GET_SUCCESS; - icalcomponent_foreach_tzid (*icalcomp, - cal_client_get_object_timezones_cb, - &cb_data); + status = our_op->status; + *icalcomp = icalparser_parse_string (our_op->string); + g_free (our_op->string); - retval = cb_data.status; + if (!*icalcomp) { + status = E_CALENDAR_STATUS_INVALID_OBJECT; + } else { + CalClientGetTimezonesData cb_data; + + /* Now make sure we have all timezones needed for this object. + We do this to try to avoid any problems caused by getting a timezone + in the middle of other code. Any calls to ORBit result in a + recursive call of the GTK+ main loop, which can cause problems for + code that doesn't expect it. Currently GnomeCanvas has problems if + we try to get a timezone in the middle of a redraw, and there is a + resize pending, which leads to an assert failure and an abort. */ + cb_data.client = client; + cb_data.status = E_CALENDAR_STATUS_OK; + icalcomponent_foreach_tzid (*icalcomp, + cal_client_get_object_timezones_cb, + &cb_data); + + status = cb_data.status; + } - out: + e_calendar_remove_op (client, our_op); + e_mutex_unlock (our_op->mutex); + e_calendar_free_op (our_op); - CORBA_exception_free (&ev); - return retval; + E_CALENDAR_CHECK_STATUS (status, error); } /** @@ -1423,64 +2114,89 @@ cal_client_get_default_object (CalClient *client, CalObjType type, icalcomponent * * Return value: Result code based on the status of the operation. **/ -CalClientGetStatus -cal_client_get_object (CalClient *client, const char *uid, icalcomponent **icalcomp) +gboolean +cal_client_get_object (CalClient *client, const char *uid, const char *rid, icalcomponent **icalcomp, GError **error) { + CalClientPrivate *priv; CORBA_Environment ev; - GNOME_Evolution_Calendar_CalObj comp_str; - CalClientGetStatus retval; - CalClientGetTimezonesData cb_data; + ECalendarStatus status; + ECalendarOp *our_op; - g_return_val_if_fail (client != NULL, CAL_CLIENT_GET_NOT_FOUND); - g_return_val_if_fail (IS_CAL_CLIENT (client), CAL_CLIENT_GET_NOT_FOUND); + g_return_val_if_fail (client != NULL, FALSE); + g_return_val_if_fail (IS_CAL_CLIENT (client), FALSE); priv = client->priv; - g_return_val_if_fail (priv->load_state == CAL_CLIENT_LOAD_LOADED, CAL_CLIENT_GET_NOT_FOUND); - g_return_val_if_fail (uid != NULL, CAL_CLIENT_GET_NOT_FOUND); - g_return_val_if_fail (icalcomp != NULL, CAL_CLIENT_GET_NOT_FOUND); + e_mutex_lock (client->priv->mutex); - retval = CAL_CLIENT_GET_NOT_FOUND; - *icalcomp = NULL; + if (client->priv->load_state != CAL_CLIENT_LOAD_LOADED) { + e_mutex_unlock (client->priv->mutex); + E_CALENDAR_CHECK_STATUS (E_CALENDAR_STATUS_URI_NOT_LOADED, error); + } + + if (client->priv->current_op != NULL) { + e_mutex_unlock (client->priv->mutex); + E_CALENDAR_CHECK_STATUS (E_CALENDAR_STATUS_BUSY, error); + } + + our_op = e_calendar_new_op (client); + + e_mutex_lock (our_op->mutex); + + e_mutex_unlock (client->priv->mutex); CORBA_exception_init (&ev); - comp_str = GNOME_Evolution_Calendar_Cal_getObject (priv->cal, (char *) uid, &ev); - if (BONOBO_USER_EX (&ev, ex_GNOME_Evolution_Calendar_Cal_NotFound)) - goto out; - else if (BONOBO_EX (&ev)) { - g_message ("cal_client_get_object(): could not get the object"); - goto out; - } + GNOME_Evolution_Calendar_Cal_getObject (priv->cal, uid, rid ? rid : "", &ev); + if (BONOBO_EX (&ev)) { + e_calendar_remove_op (client, our_op); + e_mutex_unlock (our_op->mutex); + e_calendar_free_op (our_op); - *icalcomp = icalparser_parse_string (comp_str); - CORBA_free (comp_str); + CORBA_exception_free (&ev); - if (!*icalcomp) { - retval = CAL_CLIENT_GET_SYNTAX_ERROR; - goto out; + g_warning (G_STRLOC ": Unable to contact backend"); + + E_CALENDAR_CHECK_STATUS (E_CALENDAR_STATUS_CORBA_EXCEPTION, error); } - /* Now make sure we have all timezones needed for this object. - We do this to try to avoid any problems caused by getting a timezone - in the middle of other code. Any calls to ORBit result in a - recursive call of the GLib main loop, which can cause problems for - code that doesn't expect it. Currently GnomeCanvas has problems if - we try to get a timezone in the middle of a redraw, and there is a - resize pending, which leads to an assert failure and an abort. */ - cb_data.client = client; - cb_data.status = CAL_CLIENT_GET_SUCCESS; - icalcomponent_foreach_tzid (*icalcomp, - cal_client_get_object_timezones_cb, - &cb_data); + CORBA_exception_free (&ev); - retval = cb_data.status; + /* wait for something to happen (both cancellation and a + successful response will notity us via our cv */ + e_mutex_cond_wait (&our_op->cond, our_op->mutex); - out: + status = our_op->status; + *icalcomp = icalparser_parse_string (our_op->string); + g_free (our_op->string); - CORBA_exception_free (&ev); - return retval; + if (!*icalcomp) { + status = E_CALENDAR_STATUS_INVALID_OBJECT; + } else { + CalClientGetTimezonesData cb_data; + + /* Now make sure we have all timezones needed for this object. + We do this to try to avoid any problems caused by getting a timezone + in the middle of other code. Any calls to ORBit result in a + recursive call of the GTK+ main loop, which can cause problems for + code that doesn't expect it. Currently GnomeCanvas has problems if + we try to get a timezone in the middle of a redraw, and there is a + resize pending, which leads to an assert failure and an abort. */ + cb_data.client = client; + cb_data.status = E_CALENDAR_STATUS_OK; + icalcomponent_foreach_tzid (*icalcomp, + cal_client_get_object_timezones_cb, + &cb_data); + + status = cb_data.status; + } + + e_calendar_remove_op (client, our_op); + e_mutex_unlock (our_op->mutex); + e_calendar_free_op (our_op); + + E_CALENDAR_CHECK_STATUS (status, error); } @@ -1491,106 +2207,18 @@ cal_client_get_object_timezones_cb (icalparameter *param, CalClientGetTimezonesData *cb_data = data; const char *tzid; icaltimezone *zone; - CalClientGetStatus status; + GError *error = NULL; tzid = icalparameter_get_tzid (param); if (!tzid) { - cb_data->status = CAL_CLIENT_GET_SYNTAX_ERROR; + cb_data->status = E_CALENDAR_STATUS_INVALID_OBJECT; return; } - status = cal_client_get_timezone (cb_data->client, tzid, &zone); - if (status != CAL_CLIENT_GET_SUCCESS) - cb_data->status = status; -} - - -CalClientGetStatus -cal_client_get_timezone (CalClient *client, - const char *tzid, - icaltimezone **zone) -{ - CalClientPrivate *priv; - CORBA_Environment ev; - GNOME_Evolution_Calendar_CalObj comp_str; - CalClientGetStatus retval; - icalcomponent *icalcomp; - icaltimezone *tmp_zone; - - g_return_val_if_fail (client != NULL, CAL_CLIENT_GET_NOT_FOUND); - g_return_val_if_fail (IS_CAL_CLIENT (client), CAL_CLIENT_GET_NOT_FOUND); - - priv = client->priv; - g_return_val_if_fail (priv->load_state == CAL_CLIENT_LOAD_LOADED, - CAL_CLIENT_GET_NOT_FOUND); - - g_return_val_if_fail (zone != NULL, CAL_CLIENT_GET_NOT_FOUND); - - /* If tzid is NULL or "" we return NULL, since it is a 'local time'. */ - if (!tzid || !tzid[0]) { - *zone = NULL; - return CAL_CLIENT_GET_SUCCESS; - } - - /* If it is UTC, we return the special UTC timezone. */ - if (!strcmp (tzid, "UTC")) { - *zone = icaltimezone_get_utc_timezone (); - return CAL_CLIENT_GET_SUCCESS; - } - - /* See if we already have it in the cache. */ - tmp_zone = g_hash_table_lookup (priv->timezones, tzid); - if (tmp_zone) { - *zone = tmp_zone; - return CAL_CLIENT_GET_SUCCESS; - } - - retval = CAL_CLIENT_GET_NOT_FOUND; - *zone = NULL; - - /* We don't already have it, so we try to get it from the server. */ - CORBA_exception_init (&ev); - comp_str = GNOME_Evolution_Calendar_Cal_getTimezoneObject (priv->cal, (char *) tzid, &ev); - - if (BONOBO_USER_EX (&ev, ex_GNOME_Evolution_Calendar_Cal_NotFound)) - goto out; - else if (BONOBO_EX (&ev)) { - g_message ("cal_client_get_timezone(): could not get the object"); - goto out; - } - - icalcomp = icalparser_parse_string (comp_str); - CORBA_free (comp_str); - - if (!icalcomp) { - retval = CAL_CLIENT_GET_SYNTAX_ERROR; - goto out; - } - - tmp_zone = icaltimezone_new (); - if (!tmp_zone) { - /* FIXME: Needs better error code - out of memory. Or just - abort like GLib does? */ - retval = CAL_CLIENT_GET_NOT_FOUND; - goto out; - } - - if (!icaltimezone_set_component (tmp_zone, icalcomp)) { - retval = CAL_CLIENT_GET_SYNTAX_ERROR; - goto out; - } - - /* Now add it to the cache, to avoid the server call in future. */ - g_hash_table_insert (priv->timezones, icaltimezone_get_tzid (tmp_zone), - tmp_zone); - - *zone = tmp_zone; - retval = CAL_CLIENT_GET_SUCCESS; - - out: - - CORBA_exception_free (&ev); - return retval; + if (!cal_client_get_timezone (cb_data->client, tzid, &zone, &error)) + cb_data->status = error->code; + + g_clear_error (&error); } /* Resolves TZIDs for the recurrence generator. */ @@ -1599,7 +2227,6 @@ cal_client_resolve_tzid_cb (const char *tzid, gpointer data) { CalClient *client; icaltimezone *zone = NULL; - CalClientGetStatus status; g_return_val_if_fail (data != NULL, NULL); g_return_val_if_fail (IS_CAL_CLIENT (data), NULL); @@ -1607,473 +2234,291 @@ cal_client_resolve_tzid_cb (const char *tzid, gpointer data) client = CAL_CLIENT (data); /* FIXME: Handle errors. */ - status = cal_client_get_timezone (client, tzid, &zone); + cal_client_get_timezone (client, tzid, &zone, NULL); return zone; } - -/* Builds an UID list out of a CORBA UID sequence */ -static GList * -build_uid_list (GNOME_Evolution_Calendar_CalObjUIDSeq *seq) -{ - GList *uids; - int i; - - uids = NULL; - - for (i = 0; i < seq->_length; i++) - uids = g_list_prepend (uids, g_strdup (seq->_buffer[i])); - - return uids; -} - -/** - * cal_client_get_uids: - * @client: A calendar client. - * @type: Bitmask with types of objects to return. - * - * Queries a calendar for a list of unique identifiers corresponding to calendar - * objects whose type matches one of the types specified in the @type flags. - * - * Return value: A list of strings that are the sought UIDs. This should be - * freed using the cal_obj_uid_list_free() function. - **/ -GList * -cal_client_get_uids (CalClient *client, CalObjType type) +gboolean +cal_client_get_changes (CalClient *client, CalObjType type, const char *change_id, GList **changes, GError **error) { - CalClientPrivate *priv; CORBA_Environment ev; - GNOME_Evolution_Calendar_CalObjUIDSeq *seq; - int t; - GList *uids; - - g_return_val_if_fail (client != NULL, NULL); - g_return_val_if_fail (IS_CAL_CLIENT (client), NULL); - - priv = client->priv; - g_return_val_if_fail (priv->load_state == CAL_CLIENT_LOAD_LOADED, NULL); + ECalendarOp *our_op; + ECalendarStatus status; - t = corba_obj_type (type); + g_return_val_if_fail (client != NULL, E_CALENDAR_STATUS_INVALID_ARG); + g_return_val_if_fail (IS_CAL_CLIENT (client), E_CALENDAR_STATUS_INVALID_ARG); + g_return_val_if_fail (change_id != NULL, E_CALENDAR_STATUS_INVALID_ARG); - CORBA_exception_init (&ev); + e_mutex_lock (client->priv->mutex); - seq = GNOME_Evolution_Calendar_Cal_getUIDs (priv->cal, t, &ev); - if (BONOBO_EX (&ev)) { - g_message ("cal_client_get_uids(): could not get the list of UIDs"); - CORBA_exception_free (&ev); - return NULL; + if (client->priv->load_state != CAL_CLIENT_LOAD_LOADED) { + e_mutex_unlock (client->priv->mutex); + E_CALENDAR_CHECK_STATUS (E_CALENDAR_STATUS_URI_NOT_LOADED, error); } - CORBA_exception_free (&ev); - - uids = build_uid_list (seq); - CORBA_free (seq); - - return uids; -} - -/* Builds a GList of CalClientChange structures from the CORBA sequence */ -static GList * -build_change_list (GNOME_Evolution_Calendar_CalObjChangeSeq *seq) -{ - GList *list = NULL; - icalcomponent *icalcomp; - int i; - - /* Create the list in reverse order */ - for (i = 0; i < seq->_length; i++) { - GNOME_Evolution_Calendar_CalObjChange *corba_coc; - CalClientChange *ccc; - - corba_coc = &seq->_buffer[i]; - ccc = g_new (CalClientChange, 1); - - icalcomp = icalparser_parse_string (corba_coc->calobj); - if (!icalcomp) - continue; - - ccc->comp = cal_component_new (); - if (!cal_component_set_icalcomponent (ccc->comp, icalcomp)) { - icalcomponent_free (icalcomp); - g_object_unref (G_OBJECT (ccc->comp)); - continue; - } - ccc->type = corba_coc->type; - - list = g_list_prepend (list, ccc); + if (client->priv->current_op != NULL) { + e_mutex_unlock (client->priv->mutex); + E_CALENDAR_CHECK_STATUS (E_CALENDAR_STATUS_BUSY, error); } - list = g_list_reverse (list); - - return list; -} - -GList * -cal_client_get_changes (CalClient *client, CalObjType type, const char *change_id) -{ - CalClientPrivate *priv; - CORBA_Environment ev; - GNOME_Evolution_Calendar_CalObjChangeSeq *seq; - int t; - GList *changes; + our_op = e_calendar_new_op (client); - g_return_val_if_fail (client != NULL, NULL); - g_return_val_if_fail (IS_CAL_CLIENT (client), NULL); + e_mutex_lock (our_op->mutex); - priv = client->priv; - g_return_val_if_fail (priv->load_state == CAL_CLIENT_LOAD_LOADED, NULL); + e_mutex_unlock (client->priv->mutex); - t = corba_obj_type (type); CORBA_exception_init (&ev); - seq = GNOME_Evolution_Calendar_Cal_getChanges (priv->cal, t, change_id, &ev); - if (BONOBO_EX (&ev)) { - g_message ("cal_client_get_changes(): could not get the list of changes"); - CORBA_exception_free (&ev); - return NULL; - } - - CORBA_exception_free (&ev); - - changes = build_change_list (seq); - CORBA_free (seq); + GNOME_Evolution_Calendar_Cal_getChanges (client->priv->cal, type, change_id, &ev); - return changes; -} + if (BONOBO_EX (&ev)) { + e_calendar_remove_op (client, our_op); + e_mutex_unlock (our_op->mutex); + e_calendar_free_op (our_op); -/* FIXME: Not used? */ -#if 0 -/* Builds a GList of CalObjInstance structures from the CORBA sequence */ -static GList * -build_object_instance_list (GNOME_Evolution_Calendar_CalObjInstanceSeq *seq) -{ - GList *list; - int i; + CORBA_exception_free (&ev); - /* Create the list in reverse order */ + g_warning (G_STRLOC ": Unable to contact backend"); - list = NULL; - for (i = 0; i < seq->_length; i++) { - GNOME_Evolution_Calendar_CalObjInstance *corba_icoi; - CalObjInstance *icoi; + E_CALENDAR_CHECK_STATUS (E_CALENDAR_STATUS_CORBA_EXCEPTION, error); + } + + CORBA_exception_free (&ev); - corba_icoi = &seq->_buffer[i]; - icoi = g_new (CalObjInstance, 1); + /* wait for something to happen (both cancellation and a + successful response will notity us via our cv */ + e_mutex_cond_wait (&our_op->cond, our_op->mutex); - icoi->uid = g_strdup (corba_icoi->uid); - icoi->start = corba_icoi->start; - icoi->end = corba_icoi->end; + status = our_op->status; + *changes = our_op->list; - list = g_list_prepend (list, icoi); - } + e_calendar_remove_op (client, our_op); + e_mutex_unlock (our_op->mutex); + e_calendar_free_op (our_op); - list = g_list_reverse (list); - return list; + E_CALENDAR_CHECK_STATUS (status, error); } -#endif + /** - * cal_client_get_objects_in_range: - * @client: A calendar client. - * @type: Bitmask with types of objects to return. - * @start: Start time for query. - * @end: End time for query. - * - * Queries a calendar for the objects that occur or recur in the specified range - * of time. - * - * Return value: A list of UID strings. This should be freed using the - * cal_obj_uid_list_free() function. + * cal_client_get_object_list: + * @client: + * @query: + * + * + * + * Return value: **/ -GList * -cal_client_get_objects_in_range (CalClient *client, CalObjType type, time_t start, time_t end) +gboolean +cal_client_get_object_list (CalClient *client, const char *query, GList **objects, GError **error) { - CalClientPrivate *priv; CORBA_Environment ev; - GNOME_Evolution_Calendar_CalObjUIDSeq *seq; - GList *uids; - int t; - - g_return_val_if_fail (client != NULL, NULL); - g_return_val_if_fail (IS_CAL_CLIENT (client), NULL); + ECalendarOp *our_op; + ECalendarStatus status; - priv = client->priv; - g_return_val_if_fail (priv->load_state == CAL_CLIENT_LOAD_LOADED, NULL); - - g_return_val_if_fail (start != -1 && end != -1, NULL); - g_return_val_if_fail (start <= end, NULL); - - CORBA_exception_init (&ev); + g_return_val_if_fail (client != NULL, E_CALENDAR_STATUS_INVALID_ARG); + g_return_val_if_fail (IS_CAL_CLIENT (client), E_CALENDAR_STATUS_INVALID_ARG); + g_return_val_if_fail (query != NULL, E_CALENDAR_STATUS_INVALID_ARG); - t = corba_obj_type (type); + e_mutex_lock (client->priv->mutex); - seq = GNOME_Evolution_Calendar_Cal_getObjectsInRange (priv->cal, t, start, end, &ev); - if (BONOBO_EX (&ev)) { - g_message ("cal_client_get_objects_in_range(): could not get the objects"); - CORBA_exception_free (&ev); - return NULL; + if (client->priv->load_state != CAL_CLIENT_LOAD_LOADED) { + e_mutex_unlock (client->priv->mutex); + E_CALENDAR_CHECK_STATUS (E_CALENDAR_STATUS_URI_NOT_LOADED, error); } - CORBA_exception_free (&ev); - - uids = build_uid_list (seq); - CORBA_free (seq); - return uids; -} + if (client->priv->current_op != NULL) { + e_mutex_unlock (client->priv->mutex); + E_CALENDAR_CHECK_STATUS (E_CALENDAR_STATUS_BUSY, error); + } -/** - * cal_client_get_free_busy - * @client:: A calendar client. - * @users: List of users to retrieve free/busy information for. - * @start: Start time for query. - * @end: End time for query. - * - * Gets free/busy information from the calendar server. - * - * Returns: a GList of VFREEBUSY CalComponents - */ -GList * -cal_client_get_free_busy (CalClient *client, GList *users, - time_t start, time_t end) -{ - CalClientPrivate *priv; - CORBA_Environment ev; - GNOME_Evolution_Calendar_UserList *corba_list; - GNOME_Evolution_Calendar_CalObjSeq *calobj_list; - GList *l; - GList *comp_list = NULL; - int len, i; + our_op = e_calendar_new_op (client); - g_return_val_if_fail (client != NULL, NULL); - g_return_val_if_fail (IS_CAL_CLIENT (client), NULL); + e_mutex_lock (our_op->mutex); - priv = client->priv; - g_return_val_if_fail (priv->load_state == CAL_CLIENT_LOAD_LOADED, NULL); + e_mutex_unlock (client->priv->mutex); - g_return_val_if_fail (start != -1 && end != -1, NULL); - g_return_val_if_fail (start <= end, NULL); + CORBA_exception_init (&ev); - /* create the CORBA user list to be passed to the backend */ - len = g_list_length (users); + GNOME_Evolution_Calendar_Cal_getObjectList (client->priv->cal, query, &ev); - corba_list = GNOME_Evolution_Calendar_UserList__alloc (); - CORBA_sequence_set_release (corba_list, TRUE); - corba_list->_length = len; - corba_list->_buffer = CORBA_sequence_GNOME_Evolution_Calendar_User_allocbuf (len); + if (BONOBO_EX (&ev)) { + e_calendar_remove_op (client, our_op); + e_mutex_unlock (our_op->mutex); + e_calendar_free_op (our_op); - for (l = g_list_first (users), i = 0; l; l = l->next, i++) - corba_list->_buffer[i] = CORBA_string_dup ((CORBA_char *) l->data); + CORBA_exception_free (&ev); - /* call the method on the backend */ - CORBA_exception_init (&ev); + g_warning (G_STRLOC ": Unable to contact backend"); - calobj_list = GNOME_Evolution_Calendar_Cal_getFreeBusy (priv->cal, corba_list, - start, end, &ev); - CORBA_free (corba_list); - if (BONOBO_EX (&ev) || !calobj_list) { - if (!BONOBO_USER_EX (&ev, ex_GNOME_Evolution_Calendar_Cal_NotFound)) - g_message ("cal_client_get_free_busy(): could not get the objects"); - CORBA_exception_free (&ev); - return NULL; + E_CALENDAR_CHECK_STATUS (E_CALENDAR_STATUS_CORBA_EXCEPTION, error); } + + CORBA_exception_free (&ev); - for (i = 0; i < calobj_list->_length; i++) { - CalComponent *comp; - icalcomponent *icalcomp; - icalcomponent_kind kind; + /* wait for something to happen (both cancellation and a + successful response will notity us via our cv */ + e_mutex_cond_wait (&our_op->cond, our_op->mutex); - icalcomp = icalparser_parse_string (calobj_list->_buffer[i]); - if (!icalcomp) - continue; + status = our_op->status; + *objects = our_op->list; - kind = icalcomponent_isa (icalcomp); - if (kind == ICAL_VFREEBUSY_COMPONENT) { - comp = cal_component_new (); - if (!cal_component_set_icalcomponent (comp, icalcomp)) { - icalcomponent_free (icalcomp); - g_object_unref (G_OBJECT (comp)); - continue; - } + e_calendar_remove_op (client, our_op); + e_mutex_unlock (our_op->mutex); + e_calendar_free_op (our_op); - comp_list = g_list_append (comp_list, comp); - } - else - icalcomponent_free (icalcomp); + E_CALENDAR_CHECK_STATUS (status, error); +} + +gboolean +cal_client_get_object_list_as_comp (CalClient *client, const char *query, GList **objects, GError **error) +{ + GList *ical_objects = NULL; + GList *l; + + g_return_val_if_fail (client != NULL, E_CALENDAR_STATUS_INVALID_ARG); + g_return_val_if_fail (IS_CAL_CLIENT (client), E_CALENDAR_STATUS_INVALID_ARG); + g_return_val_if_fail (query != NULL, E_CALENDAR_STATUS_INVALID_ARG); + g_return_val_if_fail (objects != NULL, E_CALENDAR_STATUS_INVALID_ARG); + + if (!cal_client_get_object_list (client, query, &ical_objects, error)) + return FALSE; + + *objects = NULL; + for (l = ical_objects; l; l = l->next) { + CalComponent *comp; + + comp = cal_component_new (); + cal_component_set_icalcomponent (comp, l->data); + *objects = g_list_prepend (*objects, comp); } + + g_list_free (ical_objects); - CORBA_exception_free (&ev); - CORBA_free (calobj_list); + return TRUE; +} + +void +cal_client_free_object_list (GList *objects) +{ + GList *l; + + for (l = objects; l; l = l->next) + icalcomponent_free (l->data); - return comp_list; + g_list_free (objects); } -/* Callback used when an object is updated and we must update the copy we have */ -static void -generate_instances_obj_updated_cb (CalClient *client, const char *uid, gpointer data) +/** + * cal_client_get_free_busy + * @client:: A calendar client. + * @users: List of users to retrieve free/busy information for. + * @start: Start time for query. + * @end: End time for query. + * + * Gets free/busy information from the calendar server. + * + * Returns: a GList of VFREEBUSY CalComponents + */ +gboolean +cal_client_get_free_busy (CalClient *client, GList *users, time_t start, time_t end, + GList **freebusy, GError **error) { - GHashTable *uid_comp_hash; - CalComponent *comp; - icalcomponent *icalcomp; - CalClientGetStatus status; - const char *comp_uid; - - uid_comp_hash = data; - - comp = g_hash_table_lookup (uid_comp_hash, uid); - if (!comp) - /* OK, so we don't care about new objects that may indeed be in - * the requested time range. We only care about the ones that - * were returned by the first query to - * cal_client_get_objects_in_range(). - */ - return; - - g_hash_table_remove (uid_comp_hash, uid); - g_object_unref (G_OBJECT (comp)); - - status = cal_client_get_object (client, uid, &icalcomp); + CORBA_Environment ev; + ECalendarOp *our_op; + ECalendarStatus status; + GNOME_Evolution_Calendar_UserList corba_users; + GList *l; + int i, len; + + g_return_val_if_fail (client != NULL, E_CALENDAR_STATUS_INVALID_ARG); + g_return_val_if_fail (IS_CAL_CLIENT (client), E_CALENDAR_STATUS_INVALID_ARG); - switch (status) { - case CAL_CLIENT_GET_SUCCESS: - comp = cal_component_new (); - if (cal_component_set_icalcomponent (comp, icalcomp)) { - /* The hash key comes from the component's internal data */ - cal_component_get_uid (comp, &comp_uid); - g_hash_table_insert (uid_comp_hash, (char *) comp_uid, comp); - } else { - g_object_unref (comp); - icalcomponent_free (icalcomp); - } - break; + e_mutex_lock (client->priv->mutex); - case CAL_CLIENT_GET_NOT_FOUND: - /* No longer in the server, too bad */ - break; + if (client->priv->load_state != CAL_CLIENT_LOAD_LOADED) { + e_mutex_unlock (client->priv->mutex); + E_CALENDAR_CHECK_STATUS (E_CALENDAR_STATUS_URI_NOT_LOADED, error); + } - case CAL_CLIENT_GET_SYNTAX_ERROR: - g_message ("obj_updated_cb(): Syntax error when getting " - "object `%s'; ignoring...", uid); - break; - + if (client->priv->current_op != NULL) { + e_mutex_unlock (client->priv->mutex); + E_CALENDAR_CHECK_STATUS (E_CALENDAR_STATUS_BUSY, error); } -} -/* Callback used when an object is removed and we must delete the copy we have */ -static void -generate_instances_obj_removed_cb (CalClient *client, const char *uid, gpointer data) -{ - GHashTable *uid_comp_hash; - CalComponent *comp; + our_op = e_calendar_new_op (client); - uid_comp_hash = data; + e_mutex_lock (our_op->mutex); - comp = g_hash_table_lookup (uid_comp_hash, uid); - if (!comp) - return; + e_mutex_unlock (client->priv->mutex); - g_hash_table_remove (uid_comp_hash, uid); - g_object_unref (G_OBJECT (comp)); -} + /* create the CORBA user list to be passed to the backend */ + len = g_list_length (users); -/* Adds a component to the list; called from g_hash_table_foreach() */ -static void -add_component (gpointer key, gpointer value, gpointer data) -{ - CalComponent *comp; - GList **list; + corba_users._length = len; + corba_users._buffer = CORBA_sequence_GNOME_Evolution_Calendar_User_allocbuf (len); - comp = CAL_COMPONENT (value); - list = data; + for (l = users, i = 0; l; l = l->next, i++) + corba_users._buffer[i] = CORBA_string_dup (l->data); - *list = g_list_prepend (*list, comp); -} + CORBA_exception_init (&ev); -/* Gets a list of components that recur within the specified range of time. It - * ensures that the resulting list of CalComponent objects contains only objects - * that are actually in the server at the time the initial - * cal_client_get_objects_in_range() query ends. - */ -static GList * -get_objects_atomically (CalClient *client, CalObjType type, time_t start, time_t end) -{ - GList *uids; - GHashTable *uid_comp_hash; - GList *objects; - guint obj_updated_id; - guint obj_removed_id; - GList *l; + GNOME_Evolution_Calendar_Cal_getFreeBusy (client->priv->cal, &corba_users, start, end, &ev); - uids = cal_client_get_objects_in_range (client, type, start, end); + CORBA_free (corba_users._buffer); + + if (BONOBO_EX (&ev)) { + e_calendar_remove_op (client, our_op); + e_mutex_unlock (our_op->mutex); + e_calendar_free_op (our_op); - uid_comp_hash = g_hash_table_new (g_str_hash, g_str_equal); + CORBA_exception_free (&ev); - /* While we are getting the actual object data, keep track of changes */ + g_warning (G_STRLOC ": Unable to contact backend"); - obj_updated_id = g_signal_connect (G_OBJECT (client), "obj_updated", - G_CALLBACK (generate_instances_obj_updated_cb), - uid_comp_hash); + E_CALENDAR_CHECK_STATUS (E_CALENDAR_STATUS_CORBA_EXCEPTION, error); + } + + CORBA_exception_free (&ev); - obj_removed_id = g_signal_connect (G_OBJECT (client), "obj_removed", - G_CALLBACK (generate_instances_obj_removed_cb), - uid_comp_hash); + /* wait for something to happen (both cancellation and a + successful response will notity us via our cv */ + e_mutex_cond_wait (&our_op->cond, our_op->mutex); - /* Get the objects */ + status = our_op->status; - for (l = uids; l; l = l->next) { + *freebusy = NULL; + for (l = our_op->list; l; l = l->next) { CalComponent *comp; - icalcomponent *icalcomp; - CalClientGetStatus status; - char *uid; - const char *comp_uid; - uid = l->data; + icalcomponent *icalcomp; + icalcomponent_kind kind; - status = cal_client_get_object (client, uid, &icalcomp); + icalcomp = icalparser_parse_string (l->data); + if (!icalcomp) + continue; - switch (status) { - case CAL_CLIENT_GET_SUCCESS: + kind = icalcomponent_isa (icalcomp); + if (kind == ICAL_VFREEBUSY_COMPONENT) { comp = cal_component_new (); - if (cal_component_set_icalcomponent (comp, icalcomp)) { - /* The hash key comes from the component's internal data - * instead of the duped UID from the list of UIDS. - */ - cal_component_get_uid (comp, &comp_uid); - g_hash_table_insert (uid_comp_hash, (char *) comp_uid, comp); - } else { - g_object_unref (comp); + if (!cal_component_set_icalcomponent (comp, icalcomp)) { icalcomponent_free (icalcomp); + g_object_unref (G_OBJECT (comp)); + continue; } - break; - - case CAL_CLIENT_GET_NOT_FOUND: - /* Object disappeared from the server, so don't log it */ - break; - - case CAL_CLIENT_GET_SYNTAX_ERROR: - g_message ("get_objects_atomically(): Syntax error when getting " - "object `%s'; ignoring...", uid); - break; - default: - g_assert_not_reached (); + *freebusy = g_list_append (*freebusy, comp); } + else + icalcomponent_free (icalcomp); } - cal_obj_uid_list_free (uids); - - /* Now our state is consistent with the server, so disconnect from the - * notification signals and generate the final list of components. - */ - - g_signal_handler_disconnect (client, obj_updated_id); - g_signal_handler_disconnect (client, obj_removed_id); - - objects = NULL; - g_hash_table_foreach (uid_comp_hash, add_component, &objects); - g_hash_table_destroy (uid_comp_hash); + e_calendar_remove_op (client, our_op); + e_mutex_unlock (our_op->mutex); + e_calendar_free_op (our_op); - return objects; + E_CALENDAR_CHECK_STATUS (status, error); } struct comp_instance { @@ -2127,10 +2572,8 @@ compare_comp_instance (gconstpointer a, gconstpointer b) * @cb: Callback for each generated instance. * @cb_data: Closure data for the callback. * - * Does a combination of cal_client_get_objects_in_range() and - * cal_recur_generate_instances(). It fetches the list of objects in an atomic - * way so that the generated instances are actually in the server at the time - * the initial cal_client_get_objects_in_range() query ends. + * Does a combination of cal_client_get_object_list () and + * cal_recur_generate_instances(). * * The callback function should do a g_object_ref() of the calendar component * it gets passed if it intends to keep it around. @@ -2144,7 +2587,8 @@ cal_client_generate_instances (CalClient *client, CalObjType type, GList *objects; GList *instances; GList *l; - + char *query; + g_return_if_fail (client != NULL); g_return_if_fail (IS_CAL_CLIENT (client)); @@ -2156,8 +2600,13 @@ cal_client_generate_instances (CalClient *client, CalObjType type, g_return_if_fail (cb != NULL); /* Generate objects */ + query = g_strdup_printf ("(occur-in-time-range? (%lu) (%lu))", start, end); + if (!cal_client_get_object_list (client, query, &objects, NULL)) { + g_free (query); + return; + } + g_free (query); - objects = get_objects_atomically (client, type, start, end); instances = NULL; for (l = objects; l; l = l->next) { @@ -2201,64 +2650,22 @@ cal_client_generate_instances (CalClient *client, CalObjType type, g_list_free (instances); } -/* Builds a list of CalAlarmInstance structures */ -static GSList * -build_alarm_instance_list (CalComponent *comp, GNOME_Evolution_Calendar_CalAlarmInstanceSeq *seq) -{ - GSList *alarms; - int i; - - alarms = NULL; - - for (i = 0; i < seq->_length; i++) { - GNOME_Evolution_Calendar_CalAlarmInstance *corba_instance; - CalComponentAlarm *alarm; - const char *auid; - CalAlarmInstance *instance; - - corba_instance = seq->_buffer + i; - - /* Since we want the in-commponent auid, we look for the alarm - * in the component and fetch its "real" auid. - */ - - alarm = cal_component_get_alarm (comp, corba_instance->auid); - if (!alarm) - continue; - - auid = cal_component_alarm_get_uid (alarm); - cal_component_alarm_free (alarm); - - instance = g_new (CalAlarmInstance, 1); - instance->auid = auid; - instance->trigger = corba_instance->trigger; - instance->occur_start = corba_instance->occur_start; - instance->occur_end = corba_instance->occur_end; - - alarms = g_slist_prepend (alarms, instance); - } - - return g_slist_reverse (alarms); -} - /* Builds a list of CalComponentAlarms structures */ static GSList * -build_component_alarms_list (GNOME_Evolution_Calendar_CalComponentAlarmsSeq *seq) +build_component_alarms_list (CalClient *client, GList *object_list, time_t start, time_t end) { GSList *comp_alarms; - int i; + GList *l; comp_alarms = NULL; - for (i = 0; i < seq->_length; i++) { - GNOME_Evolution_Calendar_CalComponentAlarms *corba_alarms; + for (l = object_list; l != NULL; l = l->next) { CalComponent *comp; CalComponentAlarms *alarms; icalcomponent *icalcomp; + CalAlarmAction omit[] = {-1}; - corba_alarms = seq->_buffer + i; - - icalcomp = icalparser_parse_string (corba_alarms->calobj); + icalcomp = icalparser_parse_string (l->data); if (!icalcomp) continue; @@ -2269,11 +2676,10 @@ build_component_alarms_list (GNOME_Evolution_Calendar_CalComponentAlarmsSeq *seq continue; } - alarms = g_new (CalComponentAlarms, 1); - alarms->comp = comp; - alarms->alarms = build_alarm_instance_list (comp, &corba_alarms->alarms); - - comp_alarms = g_slist_prepend (comp_alarms, alarms); + alarms = cal_util_generate_alarms_for_comp (comp, start, end, omit, cal_client_resolve_tzid_cb, + icalcomp, client->priv->default_zone); + if (alarms) + comp_alarms = g_slist_prepend (comp_alarms, alarms); } return comp_alarms; @@ -2297,9 +2703,9 @@ GSList * cal_client_get_alarms_in_range (CalClient *client, time_t start, time_t end) { CalClientPrivate *priv; - CORBA_Environment ev; - GNOME_Evolution_Calendar_CalComponentAlarmsSeq *seq; GSList *alarms; + char *sexp; + GList *object_list = NULL; g_return_val_if_fail (client != NULL, NULL); g_return_val_if_fail (IS_CAL_CLIENT (client), NULL); @@ -2310,18 +2716,20 @@ cal_client_get_alarms_in_range (CalClient *client, time_t start, time_t end) g_return_val_if_fail (start != -1 && end != -1, NULL); g_return_val_if_fail (start <= end, NULL); - CORBA_exception_init (&ev); + /* build the query string */ + sexp = g_strdup ("(and (has-alarms? #t))"); - seq = GNOME_Evolution_Calendar_Cal_getAlarmsInRange (priv->cal, start, end, &ev); - if (BONOBO_EX (&ev)) { - g_message ("cal_client_get_alarms_in_range(): could not get the alarm range"); - CORBA_exception_free (&ev); + /* execute the query on the server */ + if (!cal_client_get_object_list (client, sexp, &object_list, NULL)) { + g_free (sexp); return NULL; } - CORBA_exception_free (&ev); - alarms = build_component_alarms_list (seq); - CORBA_free (seq); + alarms = build_component_alarms_list (client, object_list, start, end); + + g_list_foreach (object_list, (GFunc) g_free, NULL); + g_list_free (object_list); + g_free (sexp); return alarms; } @@ -2371,11 +2779,9 @@ cal_client_get_alarms_for_object (CalClient *client, const char *uid, CalComponentAlarms **alarms) { CalClientPrivate *priv; - CORBA_Environment ev; - GNOME_Evolution_Calendar_CalComponentAlarms *corba_alarms; - gboolean retval; icalcomponent *icalcomp; CalComponent *comp; + CalAlarmAction omit[] = {-1}; g_return_val_if_fail (client != NULL, FALSE); g_return_val_if_fail (IS_CAL_CLIENT (client), FALSE); @@ -2389,40 +2795,23 @@ cal_client_get_alarms_for_object (CalClient *client, const char *uid, g_return_val_if_fail (alarms != NULL, FALSE); *alarms = NULL; - retval = FALSE; - - CORBA_exception_init (&ev); - - corba_alarms = GNOME_Evolution_Calendar_Cal_getAlarmsForObject (priv->cal, (char *) uid, - start, end, &ev); - if (BONOBO_USER_EX (&ev, ex_GNOME_Evolution_Calendar_Cal_NotFound)) - goto out; - else if (BONOBO_EX (&ev)) { - g_message ("cal_client_get_alarms_for_object(): could not get the alarm range"); - goto out; - } - icalcomp = icalparser_parse_string (corba_alarms->calobj); + if (!cal_client_get_object (client, uid, NULL, &icalcomp, NULL)) + return FALSE; if (!icalcomp) - goto out; + return FALSE; comp = cal_component_new (); if (!cal_component_set_icalcomponent (comp, icalcomp)) { icalcomponent_free (icalcomp); g_object_unref (G_OBJECT (comp)); - goto out; + return FALSE; } - retval = TRUE; + *alarms = cal_util_generate_alarms_for_comp (comp, start, end, omit, cal_client_resolve_tzid_cb, + icalcomp, priv->default_zone); - *alarms = g_new (CalComponentAlarms, 1); - (*alarms)->comp = comp; - (*alarms)->alarms = build_alarm_instance_list (comp, &corba_alarms->alarms); - CORBA_free (corba_alarms); - - out: - CORBA_exception_free (&ev); - return retval; + return TRUE; } /** @@ -2439,33 +2828,68 @@ cal_client_get_alarms_for_object (CalClient *client, const char *uid, * Return value: a #CalClientResult value indicating the result of the * operation. */ -CalClientResult -cal_client_discard_alarm (CalClient *client, CalComponent *comp, const char *auid) +gboolean +cal_client_discard_alarm (CalClient *client, CalComponent *comp, const char *auid, GError **error) { CalClientPrivate *priv; - CalClientResult retval; CORBA_Environment ev; + ECalendarStatus status; + ECalendarOp *our_op; const char *uid; - - g_return_val_if_fail (IS_CAL_CLIENT (client), CAL_CLIENT_RESULT_NOT_FOUND); - g_return_val_if_fail (IS_CAL_COMPONENT (comp), CAL_CLIENT_RESULT_NOT_FOUND); - g_return_val_if_fail (auid != NULL, CAL_CLIENT_RESULT_NOT_FOUND); + + g_return_val_if_fail (client != NULL, FALSE); + g_return_val_if_fail (IS_CAL_CLIENT (client), FALSE); priv = client->priv; + e_mutex_lock (client->priv->mutex); + + if (client->priv->load_state != CAL_CLIENT_LOAD_LOADED) { + e_mutex_unlock (client->priv->mutex); + E_CALENDAR_CHECK_STATUS (E_CALENDAR_STATUS_URI_NOT_LOADED, error); + } + + if (client->priv->current_op != NULL) { + e_mutex_unlock (client->priv->mutex); + E_CALENDAR_CHECK_STATUS (E_CALENDAR_STATUS_BUSY, error); + } + + our_op = e_calendar_new_op (client); + + e_mutex_lock (our_op->mutex); + + e_mutex_unlock (client->priv->mutex); + cal_component_get_uid (comp, &uid); CORBA_exception_init (&ev); + GNOME_Evolution_Calendar_Cal_discardAlarm (priv->cal, uid, auid, &ev); - if (BONOBO_USER_EX (&ev, ex_GNOME_Evolution_Calendar_Cal_NotFound)) - retval = CAL_CLIENT_RESULT_NOT_FOUND; - else if (BONOBO_EX (&ev)) - retval = CAL_CLIENT_RESULT_CORBA_ERROR; - else - retval = CAL_CLIENT_RESULT_SUCCESS; + if (BONOBO_EX (&ev)) { + e_calendar_remove_op (client, our_op); + e_mutex_unlock (our_op->mutex); + e_calendar_free_op (our_op); + + CORBA_exception_free (&ev); + + g_warning (G_STRLOC ": Unable to contact backend"); + + E_CALENDAR_CHECK_STATUS (E_CALENDAR_STATUS_CORBA_EXCEPTION, error); + } CORBA_exception_free (&ev); - return retval; + + /* wait for something to happen (both cancellation and a + successful response will notity us via our cv */ + e_mutex_cond_wait (&our_op->cond, our_op->mutex); + + status = our_op->status; + + e_calendar_remove_op (client, our_op); + e_mutex_unlock (our_op->mutex); + e_calendar_free_op (our_op); + + E_CALENDAR_CHECK_STATUS (status, error); } typedef struct _ForeachTZIDCallbackData ForeachTZIDCallbackData; @@ -2500,10 +2924,7 @@ foreach_tzid_callback (icalparameter *param, void *cbdata) return; if (data->include_all_timezones) { - CalClientGetStatus status; - - status = cal_client_get_timezone (data->client, tzid, &zone); - if (status != CAL_CLIENT_GET_SUCCESS) { + if (!cal_client_get_timezone (data->client, tzid, &zone, NULL)) { data->success = FALSE; return; } @@ -2636,246 +3057,525 @@ cal_client_get_component_as_string_internal (CalClient *client, * Return value: the component as a complete iCalendar string, or NULL on * failure. The string should be freed after use. **/ -char* -cal_client_get_component_as_string (CalClient *client, icalcomponent *icalcomp) +char* +cal_client_get_component_as_string (CalClient *client, icalcomponent *icalcomp) +{ + return cal_client_get_component_as_string_internal (client, icalcomp, TRUE); +} + +gboolean +cal_client_create_object (CalClient *client, icalcomponent *icalcomp, char **uid, GError **error) +{ + CalClientPrivate *priv; + CORBA_Environment ev; + ECalendarStatus status; + ECalendarOp *our_op; + + g_return_val_if_fail (client != NULL, FALSE); + g_return_val_if_fail (IS_CAL_CLIENT (client), FALSE); + + priv = client->priv; + + e_mutex_lock (client->priv->mutex); + + if (client->priv->load_state != CAL_CLIENT_LOAD_LOADED) { + e_mutex_unlock (client->priv->mutex); + E_CALENDAR_CHECK_STATUS (E_CALENDAR_STATUS_URI_NOT_LOADED, error); + } + + if (client->priv->current_op != NULL) { + e_mutex_unlock (client->priv->mutex); + E_CALENDAR_CHECK_STATUS (E_CALENDAR_STATUS_BUSY, error); + } + + our_op = e_calendar_new_op (client); + + e_mutex_lock (our_op->mutex); + + e_mutex_unlock (client->priv->mutex); + + CORBA_exception_init (&ev); + + GNOME_Evolution_Calendar_Cal_createObject (priv->cal, icalcomponent_as_ical_string (icalcomp), &ev); + if (BONOBO_EX (&ev)) { + e_calendar_remove_op (client, our_op); + e_mutex_unlock (our_op->mutex); + e_calendar_free_op (our_op); + + CORBA_exception_free (&ev); + + g_warning (G_STRLOC ": Unable to contact backend"); + + E_CALENDAR_CHECK_STATUS (E_CALENDAR_STATUS_CORBA_EXCEPTION, error); + } + + CORBA_exception_free (&ev); + + /* wait for something to happen (both cancellation and a + successful response will notity us via our cv */ + e_mutex_cond_wait (&our_op->cond, our_op->mutex); + + status = our_op->status; + if (uid) + *uid = our_op->uid; + + e_calendar_remove_op (client, our_op); + e_mutex_unlock (our_op->mutex); + e_calendar_free_op (our_op); + + E_CALENDAR_CHECK_STATUS (status, error); +} + +gboolean +cal_client_modify_object (CalClient *client, icalcomponent *icalcomp, CalObjModType mod, GError **error) +{ + CalClientPrivate *priv; + CORBA_Environment ev; + ECalendarStatus status; + ECalendarOp *our_op; + + g_return_val_if_fail (client != NULL, FALSE); + g_return_val_if_fail (IS_CAL_CLIENT (client), FALSE); + g_return_val_if_fail (icalcomp != NULL, FALSE); + + priv = client->priv; + + e_mutex_lock (client->priv->mutex); + + if (client->priv->load_state != CAL_CLIENT_LOAD_LOADED) { + e_mutex_unlock (client->priv->mutex); + E_CALENDAR_CHECK_STATUS (E_CALENDAR_STATUS_URI_NOT_LOADED, error); + } + + if (client->priv->current_op != NULL) { + e_mutex_unlock (client->priv->mutex); + E_CALENDAR_CHECK_STATUS (E_CALENDAR_STATUS_BUSY, error); + } + + our_op = e_calendar_new_op (client); + + e_mutex_lock (our_op->mutex); + + e_mutex_unlock (client->priv->mutex); + + CORBA_exception_init (&ev); + + GNOME_Evolution_Calendar_Cal_modifyObject (priv->cal, icalcomponent_as_ical_string (icalcomp), mod, &ev); + if (BONOBO_EX (&ev)) { + e_calendar_remove_op (client, our_op); + e_mutex_unlock (our_op->mutex); + e_calendar_free_op (our_op); + + CORBA_exception_free (&ev); + + g_warning (G_STRLOC ": Unable to contact backend"); + + E_CALENDAR_CHECK_STATUS (E_CALENDAR_STATUS_CORBA_EXCEPTION, error); + } + + CORBA_exception_free (&ev); + + /* wait for something to happen (both cancellation and a + successful response will notity us via our cv */ + e_mutex_cond_wait (&our_op->cond, our_op->mutex); + + status = our_op->status; + + e_calendar_remove_op (client, our_op); + e_mutex_unlock (our_op->mutex); + e_calendar_free_op (our_op); + + E_CALENDAR_CHECK_STATUS (status, error); +} + +gboolean +cal_client_remove_object_with_mod (CalClient *client, const char *uid, + const char *rid, CalObjModType mod, GError **error) +{ + CalClientPrivate *priv; + CORBA_Environment ev; + ECalendarStatus status; + ECalendarOp *our_op; + + g_return_val_if_fail (client != NULL, FALSE); + g_return_val_if_fail (IS_CAL_CLIENT (client), FALSE); + + priv = client->priv; + + e_mutex_lock (client->priv->mutex); + + if (client->priv->load_state != CAL_CLIENT_LOAD_LOADED) { + e_mutex_unlock (client->priv->mutex); + E_CALENDAR_CHECK_STATUS (E_CALENDAR_STATUS_URI_NOT_LOADED, error); + } + + if (client->priv->current_op != NULL) { + e_mutex_unlock (client->priv->mutex); + E_CALENDAR_CHECK_STATUS (E_CALENDAR_STATUS_BUSY, error); + } + + our_op = e_calendar_new_op (client); + + e_mutex_lock (our_op->mutex); + + e_mutex_unlock (client->priv->mutex); + + + CORBA_exception_init (&ev); + + GNOME_Evolution_Calendar_Cal_removeObject (priv->cal, uid, rid ? rid : "", mod, &ev); + if (BONOBO_EX (&ev)) { + e_calendar_remove_op (client, our_op); + e_mutex_unlock (our_op->mutex); + e_calendar_free_op (our_op); + + CORBA_exception_free (&ev); + + g_warning (G_STRLOC ": Unable to contact backend"); + + E_CALENDAR_CHECK_STATUS (E_CALENDAR_STATUS_CORBA_EXCEPTION, error); + } + + CORBA_exception_free (&ev); + + /* wait for something to happen (both cancellation and a + successful response will notity us via our cv */ + e_mutex_cond_wait (&our_op->cond, our_op->mutex); + + status = our_op->status; + + e_calendar_remove_op (client, our_op); + e_mutex_unlock (our_op->mutex); + e_calendar_free_op (our_op); + + E_CALENDAR_CHECK_STATUS (status, error); +} + +/** + * cal_client_remove_object: + * @client: A calendar client. + * @uid: Unique identifier of the calendar component to remove. + * + * Asks a calendar to remove a component. If the server is able to remove the + * component, all clients will be notified and they will emit the "obj_removed" + * signal. + * + * Return value: a #CalClientResult value indicating the result of the + * operation. + **/ +gboolean +cal_client_remove_object (CalClient *client, const char *uid, GError **error) { - return cal_client_get_component_as_string_internal (client, icalcomp, TRUE); + g_return_val_if_fail (client != NULL, FALSE); + g_return_val_if_fail (IS_CAL_CLIENT (client), FALSE); + + return cal_client_remove_object_with_mod (client, uid, NULL, CALOBJ_MOD_ALL, error); } -CalClientResult -cal_client_update_object_with_mod (CalClient *client, CalComponent *comp, CalObjModType mod) +gboolean +cal_client_receive_objects (CalClient *client, icalcomponent *icalcomp, GError **error) { CalClientPrivate *priv; CORBA_Environment ev; - CalClientResult retval; - char *obj_string; + ECalendarStatus status; + ECalendarOp *our_op; - g_return_val_if_fail (client != NULL, CAL_CLIENT_RESULT_INVALID_OBJECT); - g_return_val_if_fail (IS_CAL_CLIENT (client), CAL_CLIENT_RESULT_INVALID_OBJECT); + g_return_val_if_fail (client != NULL, FALSE); + g_return_val_if_fail (IS_CAL_CLIENT (client), FALSE); priv = client->priv; - g_return_val_if_fail (priv->load_state == CAL_CLIENT_LOAD_LOADED, CAL_CLIENT_RESULT_INVALID_OBJECT); - g_return_val_if_fail (comp != NULL, CAL_CLIENT_RESULT_INVALID_OBJECT); + e_mutex_lock (client->priv->mutex); + + if (client->priv->load_state != CAL_CLIENT_LOAD_LOADED) { + e_mutex_unlock (client->priv->mutex); + E_CALENDAR_CHECK_STATUS (E_CALENDAR_STATUS_URI_NOT_LOADED, error); + } + + if (client->priv->current_op != NULL) { + e_mutex_unlock (client->priv->mutex); + E_CALENDAR_CHECK_STATUS (E_CALENDAR_STATUS_BUSY, error); + } + + our_op = e_calendar_new_op (client); - cal_component_commit_sequence (comp); + e_mutex_lock (our_op->mutex); - obj_string = cal_client_get_component_as_string_internal (client, - cal_component_get_icalcomponent (comp), - FALSE); - if (obj_string == NULL) - return CAL_CLIENT_RESULT_INVALID_OBJECT; + e_mutex_unlock (client->priv->mutex); CORBA_exception_init (&ev); - GNOME_Evolution_Calendar_Cal_updateObjects (priv->cal, obj_string, mod, &ev); - g_free (obj_string); - - if (BONOBO_USER_EX (&ev, ex_GNOME_Evolution_Calendar_Cal_InvalidObject)) - retval = CAL_CLIENT_RESULT_INVALID_OBJECT; - else if (BONOBO_USER_EX (&ev, ex_GNOME_Evolution_Calendar_Cal_NotFound)) - retval = CAL_CLIENT_RESULT_NOT_FOUND; - else if (BONOBO_USER_EX (&ev, ex_GNOME_Evolution_Calendar_Cal_PermissionDenied)) - retval = CAL_CLIENT_RESULT_PERMISSION_DENIED; - else if (BONOBO_EX (&ev)) { - g_message ("cal_client_update_object(): could not update the object"); - retval = CAL_CLIENT_RESULT_CORBA_ERROR; + + GNOME_Evolution_Calendar_Cal_receiveObjects (priv->cal, icalcomponent_as_ical_string (icalcomp), &ev); + if (BONOBO_EX (&ev)) { + e_calendar_remove_op (client, our_op); + e_mutex_unlock (our_op->mutex); + e_calendar_free_op (our_op); + + CORBA_exception_free (&ev); + + g_warning (G_STRLOC ": Unable to contact backend"); + + E_CALENDAR_CHECK_STATUS (E_CALENDAR_STATUS_CORBA_EXCEPTION, error); } - else - retval = CAL_CLIENT_RESULT_SUCCESS; CORBA_exception_free (&ev); - return retval; -} + /* wait for something to happen (both cancellation and a + successful response will notity us via our cv */ + e_mutex_cond_wait (&our_op->cond, our_op->mutex); -/** - * cal_client_update_object: - * @client: A calendar client. - * @comp: A calendar component object. - * - * Asks a calendar to update a component. Any existing component with the - * specified component's UID will be replaced. The client program should not - * assume that the object is actually in the server's storage until it has - * received the "obj_updated" notification signal. - * - * Return value: a #CalClientResult value indicating the result of the - * operation. - **/ -CalClientResult -cal_client_update_object (CalClient *client, CalComponent *comp) -{ + status = our_op->status; + + e_calendar_remove_op (client, our_op); + e_mutex_unlock (our_op->mutex); + e_calendar_free_op (our_op); - return cal_client_update_object_with_mod (client, comp, CALOBJ_MOD_ALL); + E_CALENDAR_CHECK_STATUS (status, error); } -/** - * cal_client_update_objects: - * @client: A calendar client. - * @icalcomp: A toplevel VCALENDAR libical component. - * - * Asks a calendar to add or update one or more components, possibly including - * VTIMEZONE data. Any existing components with the same UIDs will be - * replaced. The VTIMEZONE data will be compared to existing VTIMEZONEs in - * the calendar, and the VTIMEZONEs may possibly be renamed, as well as all - * references to them throughout the VCALENDAR. - * - * The client program should not assume that the objects are actually in the - * server's storage until it has received the "obj_updated" notification - * signal. - * - * Return value: a #CalClientResult value indicating the result of the - * operation. - **/ -CalClientResult -cal_client_update_objects (CalClient *client, icalcomponent *icalcomp) +gboolean +cal_client_send_objects (CalClient *client, icalcomponent *icalcomp, GError **error) { CalClientPrivate *priv; CORBA_Environment ev; - CalClientResult retval; - char *obj_string; + ECalendarStatus status; + ECalendarOp *our_op; - g_return_val_if_fail (client != NULL, CAL_CLIENT_RESULT_INVALID_OBJECT); - g_return_val_if_fail (IS_CAL_CLIENT (client), CAL_CLIENT_RESULT_INVALID_OBJECT); + g_return_val_if_fail (client != NULL, FALSE); + g_return_val_if_fail (IS_CAL_CLIENT (client), FALSE); priv = client->priv; - g_return_val_if_fail (priv->load_state == CAL_CLIENT_LOAD_LOADED, - CAL_CLIENT_RESULT_INVALID_OBJECT); - g_return_val_if_fail (icalcomp != NULL, CAL_CLIENT_RESULT_INVALID_OBJECT); + e_mutex_lock (client->priv->mutex); + + if (client->priv->load_state != CAL_CLIENT_LOAD_LOADED) { + e_mutex_unlock (client->priv->mutex); + E_CALENDAR_CHECK_STATUS (E_CALENDAR_STATUS_URI_NOT_LOADED, error); + } + + if (client->priv->current_op != NULL) { + e_mutex_unlock (client->priv->mutex); + E_CALENDAR_CHECK_STATUS (E_CALENDAR_STATUS_BUSY, error); + } + + our_op = e_calendar_new_op (client); - /* Libical owns this memory, using one of its temporary buffers. */ - obj_string = icalcomponent_as_ical_string (icalcomp); + e_mutex_lock (our_op->mutex); + + e_mutex_unlock (client->priv->mutex); CORBA_exception_init (&ev); - GNOME_Evolution_Calendar_Cal_updateObjects (priv->cal, obj_string, GNOME_Evolution_Calendar_MOD_ALL, &ev); - - if (BONOBO_USER_EX (&ev, ex_GNOME_Evolution_Calendar_Cal_InvalidObject)) - retval = CAL_CLIENT_RESULT_INVALID_OBJECT; - else if (BONOBO_USER_EX (&ev, ex_GNOME_Evolution_Calendar_Cal_NotFound)) - retval = CAL_CLIENT_RESULT_NOT_FOUND; - else if (BONOBO_USER_EX (&ev, ex_GNOME_Evolution_Calendar_Cal_PermissionDenied)) - retval = CAL_CLIENT_RESULT_PERMISSION_DENIED; - else if (BONOBO_EX (&ev)) { - g_message ("cal_client_update_objects(): could not update the objects"); - retval = CAL_CLIENT_RESULT_CORBA_ERROR; + + GNOME_Evolution_Calendar_Cal_sendObjects (priv->cal, icalcomponent_as_ical_string (icalcomp), &ev); + if (BONOBO_EX (&ev)) { + e_calendar_remove_op (client, our_op); + e_mutex_unlock (our_op->mutex); + e_calendar_free_op (our_op); + + CORBA_exception_free (&ev); + + g_warning (G_STRLOC ": Unable to contact backend"); + + E_CALENDAR_CHECK_STATUS (E_CALENDAR_STATUS_CORBA_EXCEPTION, error); } - else - retval = CAL_CLIENT_RESULT_SUCCESS; CORBA_exception_free (&ev); - return retval; + + /* wait for something to happen (both cancellation and a + successful response will notity us via our cv */ + e_mutex_cond_wait (&our_op->cond, our_op->mutex); + + status = our_op->status; + + e_calendar_remove_op (client, our_op); + e_mutex_unlock (our_op->mutex); + e_calendar_free_op (our_op); + + E_CALENDAR_CHECK_STATUS (status, error); } -CalClientResult -cal_client_remove_object_with_mod (CalClient *client, const char *uid, CalObjModType mod) +gboolean +cal_client_get_timezone (CalClient *client, const char *tzid, icaltimezone **zone, GError **error) { CalClientPrivate *priv; CORBA_Environment ev; - CalClientResult retval; + ECalendarStatus status; + ECalendarOp *our_op; + icalcomponent *icalcomp; - g_return_val_if_fail (client != NULL, CAL_CLIENT_RESULT_INVALID_OBJECT); - g_return_val_if_fail (IS_CAL_CLIENT (client), CAL_CLIENT_RESULT_INVALID_OBJECT); + g_return_val_if_fail (IS_CAL_CLIENT (client), FALSE); + g_return_val_if_fail (tzid != NULL, FALSE); priv = client->priv; - g_return_val_if_fail (priv->load_state == CAL_CLIENT_LOAD_LOADED, CAL_CLIENT_RESULT_INVALID_OBJECT); - g_return_val_if_fail (uid != NULL, CAL_CLIENT_RESULT_NOT_FOUND); + e_mutex_lock (priv->mutex); + + if (client->priv->load_state != CAL_CLIENT_LOAD_LOADED) { + e_mutex_unlock (client->priv->mutex); + E_CALENDAR_CHECK_STATUS (E_CALENDAR_STATUS_URI_NOT_LOADED, error); + } + + if (client->priv->current_op != NULL) { + e_mutex_unlock (client->priv->mutex); + E_CALENDAR_CHECK_STATUS (E_CALENDAR_STATUS_BUSY, error); + } + + our_op = e_calendar_new_op (client); + + e_mutex_lock (our_op->mutex); + + e_mutex_unlock (priv->mutex); + + /* Check for well known zones and in the cache */ + *zone = NULL; + + /* If tzid is NULL or "" we return NULL, since it is a 'local time'. */ + if (!tzid || !tzid[0]) { + e_calendar_remove_op (client, our_op); + e_mutex_unlock (our_op->mutex); + e_calendar_free_op (our_op); + + E_CALENDAR_CHECK_STATUS (E_CALENDAR_STATUS_OK, error); + } + + /* If it is UTC, we return the special UTC timezone. */ + if (!strcmp (tzid, "UTC")) { + *zone = icaltimezone_get_utc_timezone (); + } else { + /* See if we already have it in the cache. */ + *zone = g_hash_table_lookup (priv->timezones, tzid); + } + + if (*zone) { + e_calendar_remove_op (client, our_op); + e_mutex_unlock (our_op->mutex); + e_calendar_free_op (our_op); + E_CALENDAR_CHECK_STATUS (E_CALENDAR_STATUS_OK, error); + } + + /* call the backend */ CORBA_exception_init (&ev); - GNOME_Evolution_Calendar_Cal_removeObject (priv->cal, (char *) uid, mod, &ev); - - if (BONOBO_USER_EX (&ev, ex_GNOME_Evolution_Calendar_Cal_InvalidObject)) - retval = CAL_CLIENT_RESULT_INVALID_OBJECT; - else if (BONOBO_USER_EX (&ev, ex_GNOME_Evolution_Calendar_Cal_NotFound)) - retval = CAL_CLIENT_RESULT_NOT_FOUND; - else if (BONOBO_USER_EX (&ev, ex_GNOME_Evolution_Calendar_Cal_PermissionDenied)) - retval = CAL_CLIENT_RESULT_PERMISSION_DENIED; - else if (BONOBO_EX (&ev)) { - g_message ("cal_client_remove_object(): could not remove the object"); - retval = CAL_CLIENT_RESULT_CORBA_ERROR; + + GNOME_Evolution_Calendar_Cal_getTimezone (priv->cal, tzid, &ev); + if (BONOBO_EX (&ev)) { + e_calendar_remove_op (client, our_op); + e_mutex_unlock (our_op->mutex); + e_calendar_free_op (our_op); + + CORBA_exception_free (&ev); + + g_warning (G_STRLOC ": Unable to contact backend"); + + E_CALENDAR_CHECK_STATUS (E_CALENDAR_STATUS_CORBA_EXCEPTION, error); } - else - retval = CAL_CLIENT_RESULT_SUCCESS; CORBA_exception_free (&ev); - return retval; + + /* wait for something to happen (both cancellation and a + successful response will notity us via our cv */ + e_mutex_cond_wait (&our_op->cond, our_op->mutex); + + status = our_op->status; + + icalcomp = icalparser_parse_string (our_op->string); + g_free (our_op->string); + + /* FIXME Invalid object status? */ + if (!icalcomp) + E_CALENDAR_CHECK_STATUS (E_CALENDAR_STATUS_OBJECT_NOT_FOUND, error); + + *zone = icaltimezone_new (); + if (!icaltimezone_set_component (*zone, icalcomp)) { + icaltimezone_free (*zone, 1); + + E_CALENDAR_CHECK_STATUS (E_CALENDAR_STATUS_OBJECT_NOT_FOUND, error); + } + + /* Now add it to the cache, to avoid the server call in future. */ + g_hash_table_insert (priv->timezones, icaltimezone_get_tzid (*zone), *zone); + + e_calendar_remove_op (client, our_op); + e_mutex_unlock (our_op->mutex); + e_calendar_free_op (our_op); + + E_CALENDAR_CHECK_STATUS (status, error); } /** - * cal_client_remove_object: + * cal_client_add_timezone * @client: A calendar client. - * @uid: Unique identifier of the calendar component to remove. - * - * Asks a calendar to remove a component. If the server is able to remove the - * component, all clients will be notified and they will emit the "obj_removed" - * signal. - * - * Return value: a #CalClientResult value indicating the result of the - * operation. - **/ -CalClientResult -cal_client_remove_object (CalClient *client, const char *uid) -{ - return cal_client_remove_object_with_mod (client, uid, CALOBJ_MOD_ALL); -} - -CalClientResult -cal_client_send_object (CalClient *client, icalcomponent *icalcomp, - icalcomponent **new_icalcomp, GList **users, - char **error_msg) + * @izone: The timezone to add. + * @error: Placeholder for error information. + * + * Add a VTIMEZONE object to the given calendar. + * + * Returns: TRUE if successful, FALSE otherwise. + */ +gboolean +cal_client_add_timezone (CalClient *client, icaltimezone *izone, GError **error) { CalClientPrivate *priv; CORBA_Environment ev; - CalClientResult retval; - GNOME_Evolution_Calendar_UserList *user_list; - char *obj_string; - int i; - - g_return_val_if_fail (client != NULL, CAL_CLIENT_RESULT_INVALID_OBJECT); - g_return_val_if_fail (IS_CAL_CLIENT (client), CAL_CLIENT_RESULT_INVALID_OBJECT); + ECalendarStatus status; + ECalendarOp *our_op; + const char *tzobj; + + g_return_val_if_fail (IS_CAL_CLIENT (client), FALSE); + g_return_val_if_fail (izone != NULL, FALSE); priv = client->priv; - g_return_val_if_fail (priv->load_state == CAL_CLIENT_LOAD_LOADED, - CAL_CLIENT_RESULT_INVALID_OBJECT); - g_return_val_if_fail (icalcomp != NULL, CAL_CLIENT_RESULT_INVALID_OBJECT); + e_mutex_lock (priv->mutex); + + if (client->priv->load_state != CAL_CLIENT_LOAD_LOADED) { + e_mutex_unlock (client->priv->mutex); + E_CALENDAR_CHECK_STATUS (E_CALENDAR_STATUS_URI_NOT_LOADED, error); + } + + if (client->priv->current_op != NULL) { + e_mutex_unlock (client->priv->mutex); + E_CALENDAR_CHECK_STATUS (E_CALENDAR_STATUS_BUSY, error); + } + + our_op = e_calendar_new_op (client); + + e_mutex_lock (our_op->mutex); + + e_mutex_unlock (priv->mutex); - /* Libical owns this memory, using one of its temporary buffers. */ - obj_string = icalcomponent_as_ical_string (icalcomp); + /* convert icaltimezone into a string */ + tzobj = icalcomponent_as_ical_string (icaltimezone_get_component (izone)); + /* call the backend */ CORBA_exception_init (&ev); - obj_string = GNOME_Evolution_Calendar_Cal_sendObject (priv->cal, obj_string, &user_list, &ev); - - if (BONOBO_USER_EX (&ev, ex_GNOME_Evolution_Calendar_Cal_InvalidObject)) { - retval = CAL_CLIENT_SEND_INVALID_OBJECT; - } else if (BONOBO_USER_EX (&ev, ex_GNOME_Evolution_Calendar_Cal_Busy)) { - retval = CAL_CLIENT_SEND_BUSY; - if (error_msg) - *error_msg = g_strdup (((GNOME_Evolution_Calendar_Cal_Busy *)(CORBA_exception_value (&ev)))->errorMsg); - } else if (BONOBO_USER_EX (&ev, ex_GNOME_Evolution_Calendar_Cal_PermissionDenied)) { - retval = CAL_CLIENT_SEND_PERMISSION_DENIED; - } else if (BONOBO_EX (&ev)) { - g_message ("cal_client_update_objects(): could not send the objects"); - retval = CAL_CLIENT_SEND_CORBA_ERROR; - } else { - retval = CAL_CLIENT_RESULT_SUCCESS; - - *new_icalcomp = icalparser_parse_string (obj_string); - CORBA_free (obj_string); - - if (*new_icalcomp == NULL) { - retval = CAL_CLIENT_RESULT_INVALID_OBJECT; - } else { - *users = NULL; - for (i = 0; i < user_list->_length; i++) - *users = g_list_append (*users, g_strdup (user_list->_buffer[i])); - CORBA_free (user_list); - } + + GNOME_Evolution_Calendar_Cal_addTimezone (priv->cal, tzobj, &ev); + if (BONOBO_EX (&ev)) { + e_calendar_remove_op (client, our_op); + e_mutex_unlock (our_op->mutex); + e_calendar_free_op (our_op); + + CORBA_exception_free (&ev); + + g_warning (G_STRLOC ": Unable to contact backend"); + + E_CALENDAR_CHECK_STATUS (E_CALENDAR_STATUS_CORBA_EXCEPTION, error); } - + CORBA_exception_free (&ev); - return retval; + /* wait for something to happen (both cancellation and a + successful response will notity us via our cv */ + e_mutex_cond_wait (&our_op->cond, our_op->mutex); + + status = our_op->status; + + e_calendar_remove_op (client, our_op); + e_mutex_unlock (our_op->mutex); + e_calendar_free_op (our_op); + + E_CALENDAR_CHECK_STATUS (status, error); } /** @@ -2888,20 +3588,68 @@ cal_client_send_object (CalClient *client, icalcomponent *icalcomp, * Return value: A query object that will emit notification signals as calendar * components are added and removed from the query in the server. **/ -CalQuery * -cal_client_get_query (CalClient *client, const char *sexp) +gboolean +cal_client_get_query (CalClient *client, const char *sexp, CalQuery **query, GError **error) { - CalClientPrivate *priv; + CORBA_Environment ev; + ECalendarOp *our_op; + ECalendarStatus status; - g_return_val_if_fail (client != NULL, NULL); - g_return_val_if_fail (IS_CAL_CLIENT (client), NULL); + g_return_val_if_fail (client != NULL, E_CALENDAR_STATUS_INVALID_ARG); + g_return_val_if_fail (IS_CAL_CLIENT (client), E_CALENDAR_STATUS_INVALID_ARG); + g_return_val_if_fail (query != NULL, E_CALENDAR_STATUS_INVALID_ARG); - priv = client->priv; - g_return_val_if_fail (priv->load_state == CAL_CLIENT_LOAD_LOADED, FALSE); + e_mutex_lock (client->priv->mutex); + + if (client->priv->load_state != CAL_CLIENT_LOAD_LOADED) { + e_mutex_unlock (client->priv->mutex); + E_CALENDAR_CHECK_STATUS (E_CALENDAR_STATUS_URI_NOT_LOADED, error); + } + + if (client->priv->current_op != NULL) { + e_mutex_unlock (client->priv->mutex); + E_CALENDAR_CHECK_STATUS (E_CALENDAR_STATUS_BUSY, error); + } + + our_op = e_calendar_new_op (client); + + e_mutex_lock (our_op->mutex); + + e_mutex_unlock (client->priv->mutex); + + CORBA_exception_init (&ev); + + our_op->listener = query_listener_new (); + GNOME_Evolution_Calendar_Cal_getQuery (client->priv->cal, sexp, BONOBO_OBJREF (our_op->listener), &ev); + + if (BONOBO_EX (&ev)) { + e_calendar_remove_op (client, our_op); + e_mutex_unlock (our_op->mutex); + e_calendar_free_op (our_op); + + CORBA_exception_free (&ev); + + g_warning (G_STRLOC ": Unable to contact backend"); + + E_CALENDAR_CHECK_STATUS (E_CALENDAR_STATUS_CORBA_EXCEPTION, error); + } + + CORBA_exception_free (&ev); + + /* wait for something to happen (both cancellation and a + successful response will notity us via our cv */ + e_mutex_cond_wait (&our_op->cond, our_op->mutex); - g_return_val_if_fail (sexp != NULL, NULL); + status = our_op->status; + *query = our_op->query; + + bonobo_object_unref (BONOBO_OBJECT (our_op->listener)); + + e_calendar_remove_op (client, our_op); + e_mutex_unlock (our_op->mutex); + e_calendar_free_op (our_op); - return cal_query_new (client, priv->cal, sexp); + E_CALENDAR_CHECK_STATUS (status, error); } @@ -2910,19 +3658,16 @@ cal_client_get_query (CalClient *client, const char *sexp) DATE-TIME values into specific times. (Most of our IDL interface uses time_t values to pass specific times from the server to the client.) */ static gboolean -cal_client_ensure_timezone_on_server (CalClient *client, icaltimezone *zone) +cal_client_ensure_timezone_on_server (CalClient *client, icaltimezone *zone, GError **error) { CalClientPrivate *priv; - char *tzid, *obj_string; + char *tzid; icaltimezone *tmp_zone; - GString *vcal_string; - gboolean retval = FALSE; - icalcomponent *vtimezone_comp; - char *vtimezone_as_string; - CORBA_Environment ev; priv = client->priv; + /* FIXME This is highly broken since there is no locking */ + /* If the zone is NULL or UTC we don't need to do anything. */ if (!zone) return TRUE; @@ -2940,89 +3685,128 @@ cal_client_ensure_timezone_on_server (CalClient *client, icaltimezone *zone) /* Now we have to send it to the server, in case it doesn't already have it. */ - - vcal_string = g_string_new (NULL); - g_string_append (vcal_string, - "BEGIN:VCALENDAR\n" - "PRODID:-//Ximian//NONSGML Evolution Calendar//EN\n" - "VERSION:2.0\n"); - - /* Convert the timezone to a string and add it. */ - vtimezone_comp = icaltimezone_get_component (zone); - if (!vtimezone_comp) { - g_string_free (vcal_string, TRUE); - return FALSE; - } - - /* We don't need to free this string as libical owns it. */ - vtimezone_as_string = icalcomponent_as_ical_string (vtimezone_comp); - g_string_append (vcal_string, vtimezone_as_string); - - g_string_append (vcal_string, "END:VCALENDAR\n"); - - obj_string = vcal_string->str; - g_string_free (vcal_string, FALSE); - - CORBA_exception_init (&ev); - GNOME_Evolution_Calendar_Cal_updateObjects (priv->cal, obj_string, GNOME_Evolution_Calendar_MOD_ALL, &ev); - g_free (obj_string); - - if (BONOBO_USER_EX (&ev, ex_GNOME_Evolution_Calendar_Cal_InvalidObject)) - goto out; - else if (BONOBO_EX (&ev)) { - g_message ("cal_client_ensure_timezone_on_server(): could not add the timezone to the server"); - goto out; - } - - retval = TRUE; - - out: - CORBA_exception_free (&ev); - return retval; + return cal_client_add_timezone (client, zone, error); } - gboolean -cal_client_set_default_timezone (CalClient *client, icaltimezone *zone) +cal_client_set_default_timezone (CalClient *client, icaltimezone *zone, GError **error) { CalClientPrivate *priv; - gboolean retval = FALSE; CORBA_Environment ev; + ECalendarStatus status; + ECalendarOp *our_op; const char *tzid; - - g_return_val_if_fail (client != NULL, FALSE); + g_return_val_if_fail (IS_CAL_CLIENT (client), FALSE); g_return_val_if_fail (zone != NULL, FALSE); priv = client->priv; - g_return_val_if_fail (priv->load_state == CAL_CLIENT_LOAD_LOADED, - FALSE); - /* Make sure the server has the VTIMEZONE data. */ - if (!cal_client_ensure_timezone_on_server (client, zone)) + if (!cal_client_ensure_timezone_on_server (client, zone, error)) return FALSE; - /* Now set the default timezone on the server. */ - CORBA_exception_init (&ev); - tzid = icaltimezone_get_tzid (zone); - GNOME_Evolution_Calendar_Cal_setDefaultTimezone (priv->cal, - (char *) tzid, &ev); + e_mutex_lock (priv->mutex); + + if (client->priv->load_state != CAL_CLIENT_LOAD_LOADED) { + e_mutex_unlock (client->priv->mutex); + E_CALENDAR_CHECK_STATUS (E_CALENDAR_STATUS_URI_NOT_LOADED, error); + } - if (BONOBO_USER_EX (&ev, ex_GNOME_Evolution_Calendar_Cal_NotFound)) - goto out; - else if (BONOBO_EX (&ev)) { - g_message ("cal_client_set_default_timezone(): could not set the default timezone"); - goto out; + if (client->priv->current_op != NULL) { + e_mutex_unlock (client->priv->mutex); + E_CALENDAR_CHECK_STATUS (E_CALENDAR_STATUS_BUSY, error); } - retval = TRUE; + our_op = e_calendar_new_op (client); + + e_mutex_lock (our_op->mutex); + + e_mutex_unlock (priv->mutex); + + /* FIXME Adding it to the server to change the tzid */ + tzid = icaltimezone_get_tzid (zone); + + /* call the backend */ + CORBA_exception_init (&ev); + + GNOME_Evolution_Calendar_Cal_setDefaultTimezone (priv->cal, tzid, &ev); + if (BONOBO_EX (&ev)) { + e_calendar_remove_op (client, our_op); + e_mutex_unlock (our_op->mutex); + e_calendar_free_op (our_op); + + CORBA_exception_free (&ev); - priv->default_zone = zone; + g_warning (G_STRLOC ": Unable to contact backend"); - out: + E_CALENDAR_CHECK_STATUS (E_CALENDAR_STATUS_CORBA_EXCEPTION, error); + } CORBA_exception_free (&ev); - return retval; + + /* wait for something to happen (both cancellation and a + successful response will notity us via our cv */ + e_mutex_cond_wait (&our_op->cond, our_op->mutex); + + status = our_op->status; + + e_calendar_remove_op (client, our_op); + e_mutex_unlock (our_op->mutex); + e_calendar_free_op (our_op); + + E_CALENDAR_CHECK_STATUS (status, error); } +/** + * cal_client_get_error_message + * @status: A status code. + * + * Get an error message for the given status code. + * + * Returns: the error message. + */ +const char * +cal_client_get_error_message (ECalendarStatus status) +{ + switch (status) { + case E_CALENDAR_STATUS_INVALID_ARG : + return _("Invalid argument"); + case E_CALENDAR_STATUS_BUSY : + return _("Backend is busy"); + case E_CALENDAR_STATUS_REPOSITORY_OFFLINE : + return _("Repository is offline"); + case E_CALENDAR_STATUS_NO_SUCH_CALENDAR : + return _("No such calendar"); + case E_CALENDAR_STATUS_OBJECT_NOT_FOUND : + return _("Object not found"); + case E_CALENDAR_STATUS_INVALID_OBJECT : + return _("Invalid object"); + case E_CALENDAR_STATUS_URI_NOT_LOADED : + return _("URI not loaded"); + case E_CALENDAR_STATUS_URI_ALREADY_LOADED : + return _("URI already loaded"); + case E_CALENDAR_STATUS_PERMISSION_DENIED : + return _("Permission denied"); + case E_CALENDAR_STATUS_CARD_NOT_FOUND : + return _("Object not found"); + case E_CALENDAR_STATUS_CARD_ID_ALREADY_EXISTS : + return _("Object ID already exists"); + case E_CALENDAR_STATUS_PROTOCOL_NOT_SUPPORTED : + return _("Protocol not supported"); + case E_CALENDAR_STATUS_CANCELLED : + return _("Operation has been cancelled"); + case E_CALENDAR_STATUS_COULD_NOT_CANCEL : + return _("Could not cancel operation"); + case E_CALENDAR_STATUS_AUTHENTICATION_FAILED : + return _("Authentication failed"); + case E_CALENDAR_STATUS_AUTHENTICATION_REQUIRED : + return _("Authentication required"); + case E_CALENDAR_STATUS_CORBA_EXCEPTION : + return _("A CORBA esception has occurred"); + case E_CALENDAR_STATUS_OTHER_ERROR : + return _("Unknown error"); + } + + return NULL; +} diff --git a/calendar/cal-client/cal-client.h b/calendar/cal-client/cal-client.h index 961ba5d993..277522f097 100644 --- a/calendar/cal-client/cal-client.h +++ b/calendar/cal-client/cal-client.h @@ -25,6 +25,7 @@ #include #include #include +#include "cal-client-types.h" G_BEGIN_DECLS @@ -37,6 +38,7 @@ G_BEGIN_DECLS #define IS_CAL_CLIENT_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), CAL_CLIENT_TYPE)) #define CAL_CLIENT_OPEN_STATUS_ENUM_TYPE (cal_client_open_status_enum_get_type ()) +#define CAL_CLIENT_REMOVE_STATUS_ENUM_TYPE (cal_client_remove_status_enum_get_type ()) #define CAL_CLIENT_SET_MODE_STATUS_ENUM_TYPE (cal_client_set_mode_status_enum_get_type ()) #define CAL_MODE_ENUM_TYPE (cal_mode_enum_get_type ()) @@ -76,14 +78,6 @@ typedef enum { CAL_CLIENT_RESULT_PERMISSION_DENIED } CalClientResult; -typedef enum { - CAL_CLIENT_SEND_SUCCESS, - CAL_CLIENT_SEND_CORBA_ERROR, - CAL_CLIENT_SEND_INVALID_OBJECT, - CAL_CLIENT_SEND_BUSY, - CAL_CLIENT_SEND_PERMISSION_DENIED -} CalClientSendResult; - /* Whether the client is not loaded, is being loaded, or is already loaded */ typedef enum { CAL_CLIENT_LOAD_NOT_LOADED, @@ -104,10 +98,7 @@ struct _CalClientClass { /* Notification signals */ void (* cal_opened) (CalClient *client, CalClientOpenStatus status); - void (* cal_set_mode) (CalClient *client, CalClientSetModeStatus status, CalMode mode); - - void (* obj_updated) (CalClient *client, const char *uid); - void (* obj_removed) (CalClient *client, const char *uid); + void (* cal_set_mode) (CalClient *client, CalClientSetModeStatus status, CalMode mode); void (* backend_error) (CalClient *client, const char *message); @@ -129,21 +120,13 @@ GType cal_client_open_status_enum_get_type (void); GType cal_client_set_mode_status_enum_get_type (void); GType cal_mode_enum_get_type (void); -CalClient *cal_client_construct (CalClient *client); - -CalClient *cal_client_new (void); +CalClient *cal_client_new (const char *uri, CalObjType type); void cal_client_set_auth_func (CalClient *client, CalClientAuthFunc func, gpointer data); -/* Sets the default timezone to use to resolve DATE and floating DATE-TIME - values. This will typically be from the user's timezone setting. Call this - before using any other functions. It will pass the default timezone on to - the server. Returns TRUE on success. */ -gboolean cal_client_set_default_timezone (CalClient *client, icaltimezone *zone); - -gboolean cal_client_open_calendar (CalClient *client, const char *str_uri, gboolean only_if_exists); -gboolean cal_client_open_default_calendar (CalClient *client, gboolean only_if_exists); -gboolean cal_client_open_default_tasks (CalClient *client, gboolean only_if_exists); +gboolean cal_client_open (CalClient *client, gboolean only_if_exists, GError **error); +void cal_client_open_async (CalClient *client, gboolean only_if_exists); +gboolean cal_client_remove_calendar (CalClient *client, GError **error); GList *cal_client_uri_list (CalClient *client, CalMode mode); @@ -151,11 +134,10 @@ CalClientLoadState cal_client_get_load_state (CalClient *client); const char *cal_client_get_uri (CalClient *client); -gboolean cal_client_is_read_only (CalClient *client); - -const char *cal_client_get_cal_address (CalClient *client); -const char *cal_client_get_alarm_email_address (CalClient *client); -const char *cal_client_get_ldap_attribute (CalClient *client); +gboolean cal_client_is_read_only (CalClient *client, gboolean *read_only, GError **error); +gboolean cal_client_get_cal_address (CalClient *client, char **cal_address, GError **error); +gboolean cal_client_get_alarm_email_address (CalClient *client, char **alarm_address, GError **error); +gboolean cal_client_get_ldap_attribute (CalClient *client, char **ldap_attribute, GError **error); gboolean cal_client_get_one_alarm_only (CalClient *client); gboolean cal_client_get_organizer_must_attend (CalClient *client); @@ -164,28 +146,23 @@ gboolean cal_client_get_static_capability (CalClient *client, const char *cap); gboolean cal_client_set_mode (CalClient *client, CalMode mode); -int cal_client_get_n_objects (CalClient *client, CalObjType type); - -CalClientGetStatus cal_client_get_default_object (CalClient *client, - CalObjType type, - icalcomponent **icalcomp); +gboolean cal_client_get_default_object (CalClient *client, + icalcomponent **icalcomp, GError **error); -CalClientGetStatus cal_client_get_object (CalClient *client, - const char *uid, - icalcomponent **icalcomp); +gboolean cal_client_get_object (CalClient *client, + const char *uid, + const char *rid, + icalcomponent **icalcomp, + GError **error); -CalClientGetStatus cal_client_get_timezone (CalClient *client, - const char *tzid, - icaltimezone **zone); +gboolean cal_client_get_changes (CalClient *client, CalObjType type, const char *change_id, GList **changes, GError **error); -GList *cal_client_get_uids (CalClient *client, CalObjType type); -GList *cal_client_get_changes (CalClient *client, CalObjType type, const char *change_id); +gboolean cal_client_get_object_list (CalClient *client, const char *query, GList **objects, GError **error); +gboolean cal_client_get_object_list_as_comp (CalClient *client, const char *query, GList **objects, GError **error); +void cal_client_free_object_list (GList *objects); -GList *cal_client_get_objects_in_range (CalClient *client, CalObjType type, - time_t start, time_t end); - -GList *cal_client_get_free_busy (CalClient *client, GList *users, - time_t start, time_t end); +gboolean cal_client_get_free_busy (CalClient *client, GList *users, time_t start, time_t end, + GList **freebusy, GError **error); void cal_client_generate_instances (CalClient *client, CalObjType type, time_t start, time_t end, @@ -199,24 +176,25 @@ gboolean cal_client_get_alarms_for_object (CalClient *client, const char *uid, time_t start, time_t end, CalComponentAlarms **alarms); -CalClientResult cal_client_discard_alarm (CalClient *client, CalComponent *comp, const char *auid); - -/* Add or update a single object. When adding an object only builtin timezones - are allowed. To use external VTIMEZONE data call update_objects() instead.*/ -CalClientResult cal_client_update_object (CalClient *client, CalComponent *comp); -CalClientResult cal_client_update_object_with_mod (CalClient *client, CalComponent *comp, CalObjModType mod); +gboolean cal_client_create_object (CalClient *client, icalcomponent *icalcomp, char **uid, GError **error); +gboolean cal_client_modify_object (CalClient *client, icalcomponent *icalcomp, CalObjModType mod, GError **error); +gboolean cal_client_remove_object (CalClient *client, const char *uid, GError **error); +gboolean cal_client_remove_object_with_mod (CalClient *client, const char *uid, const char *rid, CalObjModType mod, GError **error); -/* Add or update multiple objects, possibly including VTIMEZONE data. */ -CalClientResult cal_client_update_objects (CalClient *client, icalcomponent *icalcomp); +gboolean cal_client_discard_alarm (CalClient *client, CalComponent *comp, const char *auid, GError **error); -CalClientResult cal_client_remove_object (CalClient *client, const char *uid); -CalClientResult cal_client_remove_object_with_mod (CalClient *client, const char *uid, CalObjModType mod); +gboolean cal_client_receive_objects (CalClient *client, icalcomponent *icalcomp, GError **error); +gboolean cal_client_send_objects (CalClient *client, icalcomponent *icalcomp, GError **error); -CalClientSendResult cal_client_send_object (CalClient *client, icalcomponent *icalcomp, - icalcomponent **new_icalcomp, GList **users, - char **error_msg); +gboolean cal_client_get_timezone (CalClient *client, const char *tzid, icaltimezone **zone, GError **error); +gboolean cal_client_add_timezone (CalClient *client, icaltimezone *izone, GError **error); +/* Sets the default timezone to use to resolve DATE and floating DATE-TIME + values. This will typically be from the user's timezone setting. Call this + before using any other functions. It will pass the default timezone on to + the server. Returns TRUE on success. */ +gboolean cal_client_set_default_timezone (CalClient *client, icaltimezone *zone, GError **error); -CalQuery *cal_client_get_query (CalClient *client, const char *sexp); +gboolean cal_client_get_query (CalClient *client, const char *sexp, CalQuery **query, GError **error); /* Resolves TZIDs for the recurrence generator. */ icaltimezone *cal_client_resolve_tzid_cb (const char *tzid, gpointer data); @@ -225,6 +203,7 @@ icaltimezone *cal_client_resolve_tzid_cb (const char *tzid, gpointer data); used by the component. It also includes a 'METHOD:PUBLISH' property. */ char* cal_client_get_component_as_string (CalClient *client, icalcomponent *icalcomp); +const char * cal_client_get_error_message (ECalendarStatus status); diff --git a/calendar/cal-client/cal-listener.c b/calendar/cal-client/cal-listener.c index c7beef8c97..ac04be7c07 100644 --- a/calendar/cal-client/cal-listener.c +++ b/calendar/cal-client/cal-listener.c @@ -19,6 +19,9 @@ */ #include + +#include +#include "cal-marshal.h" #include "cal-listener.h" @@ -26,10 +29,7 @@ /* Private part of the CalListener structure */ struct CalListenerPrivate { /* Notification functions and their closure data */ - CalListenerCalOpenedFn cal_opened_fn; CalListenerCalSetModeFn cal_set_mode_fn; - CalListenerObjUpdatedFn obj_updated_fn; - CalListenerObjRemovedFn obj_removed_fn; CalListenerErrorOccurredFn error_occurred_fn; CalListenerCategoriesChangedFn categories_changed_fn; gpointer fn_data; @@ -38,124 +38,178 @@ struct CalListenerPrivate { gboolean notify : 1; }; - +/* Signal IDs */ +enum { + READ_ONLY, + CAL_ADDRESS, + ALARM_ADDRESS, + LDAP_ATTRIBUTE, + STATIC_CAPABILITIES, + OPEN, + REMOVE, + CREATE_OBJECT, + MODIFY_OBJECT, + REMOVE_OBJECT, + DISCARD_ALARM, + RECEIVE_OBJECTS, + SEND_OBJECTS, + DEFAULT_OBJECT, + OBJECT, + OBJECT_LIST, + GET_TIMEZONE, + ADD_TIMEZONE, + SET_DEFAULT_TIMEZONE, + GET_CHANGES, + GET_FREE_BUSY, + QUERY, + LAST_SIGNAL +}; -static void cal_listener_class_init (CalListenerClass *klass); -static void cal_listener_init (CalListener *listener, CalListenerClass *klass); -static void cal_listener_finalize (GObject *object); - -static void impl_notifyCalOpened (PortableServer_Servant servant, - GNOME_Evolution_Calendar_Listener_OpenStatus status, - GNOME_Evolution_Calendar_Cal cal, - CORBA_Environment *ev); -static void impl_notifyCalSetMode (PortableServer_Servant servant, - GNOME_Evolution_Calendar_Listener_SetModeStatus status, - GNOME_Evolution_Calendar_CalMode mode, - CORBA_Environment *ev); -static void impl_notifyObjUpdated (PortableServer_Servant servant, - const CORBA_char *uid, - CORBA_Environment *ev); -static void impl_notifyObjRemoved (PortableServer_Servant servant, - const CORBA_char *uid, - CORBA_Environment *ev); -static void impl_notifyErrorOccurred (PortableServer_Servant servant, - const CORBA_char *message, - CORBA_Environment *ev); -static void impl_notifyCategoriesChanged (PortableServer_Servant servant, - const GNOME_Evolution_Calendar_StringSeq *categories, - CORBA_Environment *ev); +static guint signals[LAST_SIGNAL] = { 0 }; static BonoboObjectClass *parent_class; - - -BONOBO_TYPE_FUNC_FULL (CalListener, - GNOME_Evolution_Calendar_Listener, - BONOBO_TYPE_OBJECT, - cal_listener); +static ECalendarStatus +convert_status (const GNOME_Evolution_Calendar_CallStatus status) +{ + switch (status) { + case GNOME_Evolution_Calendar_Success: + return E_CALENDAR_STATUS_OK; + case GNOME_Evolution_Calendar_RepositoryOffline: + return E_CALENDAR_STATUS_REPOSITORY_OFFLINE; + case GNOME_Evolution_Calendar_PermissionDenied: + return E_CALENDAR_STATUS_PERMISSION_DENIED; + case GNOME_Evolution_Calendar_ObjectNotFound: + return E_CALENDAR_STATUS_OBJECT_NOT_FOUND; + case GNOME_Evolution_Calendar_InvalidObject: + return E_CALENDAR_STATUS_INVALID_OBJECT; + case GNOME_Evolution_Calendar_CardIdAlreadyExists: + return E_CALENDAR_STATUS_CARD_ID_ALREADY_EXISTS; + case GNOME_Evolution_Calendar_AuthenticationFailed: + return E_CALENDAR_STATUS_AUTHENTICATION_FAILED; + case GNOME_Evolution_Calendar_AuthenticationRequired: + return E_CALENDAR_STATUS_AUTHENTICATION_REQUIRED; + case GNOME_Evolution_Calendar_OtherError: + default: + return E_CALENDAR_STATUS_OTHER_ERROR; + } +} -/* Class initialization function for the calendar listener */ static void -cal_listener_class_init (CalListenerClass *klass) +impl_notifyReadOnly (PortableServer_Servant servant, + GNOME_Evolution_Calendar_CallStatus status, + const CORBA_boolean read_only, + CORBA_Environment *ev) { - GObjectClass *object_class; - - object_class = (GObjectClass *) klass; + CalListener *listener; + CalListenerPrivate *priv; - parent_class = g_type_class_peek_parent (klass); + listener = CAL_LISTENER (bonobo_object_from_servant (servant)); + priv = listener->priv; - klass->epv.notifyCalOpened = impl_notifyCalOpened; - klass->epv.notifyCalSetMode = impl_notifyCalSetMode; - klass->epv.notifyObjUpdated = impl_notifyObjUpdated; - klass->epv.notifyObjRemoved = impl_notifyObjRemoved; - klass->epv.notifyErrorOccurred = impl_notifyErrorOccurred; - klass->epv.notifyCategoriesChanged = impl_notifyCategoriesChanged; + if (!priv->notify) + return; - object_class->finalize = cal_listener_finalize; + g_signal_emit (G_OBJECT (listener), signals[READ_ONLY], 0, convert_status (status), read_only); } -/* Object initialization function for the calendar listener */ static void -cal_listener_init (CalListener *listener, CalListenerClass *klass) +impl_notifyCalAddress (PortableServer_Servant servant, + GNOME_Evolution_Calendar_CallStatus status, + const CORBA_char *address, + CORBA_Environment *ev) { + CalListener *listener; CalListenerPrivate *priv; - priv = g_new0 (CalListenerPrivate, 1); - listener->priv = priv; + listener = CAL_LISTENER (bonobo_object_from_servant (servant)); + priv = listener->priv; - priv->cal_opened_fn = NULL; - priv->obj_updated_fn = NULL; - priv->obj_removed_fn = NULL; - priv->error_occurred_fn = NULL; - priv->categories_changed_fn = NULL; + if (!priv->notify) + return; - priv->notify = TRUE; + g_signal_emit (G_OBJECT (listener), signals[CAL_ADDRESS], 0, convert_status (status), address); } -/* Finalize handler for the calendar listener */ static void -cal_listener_finalize (GObject *object) +impl_notifyAlarmEmailAddress (PortableServer_Servant servant, + GNOME_Evolution_Calendar_CallStatus status, + const CORBA_char *address, + CORBA_Environment *ev) { CalListener *listener; CalListenerPrivate *priv; - g_return_if_fail (object != NULL); - g_return_if_fail (IS_CAL_LISTENER (object)); - - listener = CAL_LISTENER (object); + listener = CAL_LISTENER (bonobo_object_from_servant (servant)); priv = listener->priv; - priv->cal_opened_fn = NULL; - priv->obj_updated_fn = NULL; - priv->obj_removed_fn = NULL; - priv->error_occurred_fn = NULL; - priv->categories_changed_fn = NULL; - priv->fn_data = NULL; + if (!priv->notify) + return; - priv->notify = FALSE; + g_signal_emit (G_OBJECT (listener), signals[ALARM_ADDRESS], 0, convert_status (status), address); +} - g_free (priv); - listener->priv = NULL; +static void +impl_notifyLDAPAttribute (PortableServer_Servant servant, + GNOME_Evolution_Calendar_CallStatus status, + const CORBA_char *ldap_attribute, + CORBA_Environment *ev) +{ + CalListener *listener; + CalListenerPrivate *priv; - if (G_OBJECT_CLASS (parent_class)->finalize) - (* G_OBJECT_CLASS (parent_class)->finalize) (object); + listener = CAL_LISTENER (bonobo_object_from_servant (servant)); + priv = listener->priv; + + if (!priv->notify) + return; + + g_signal_emit (G_OBJECT (listener), signals[LDAP_ATTRIBUTE], 0, convert_status (status), ldap_attribute); } - +static void +impl_notifyStaticCapabilities (PortableServer_Servant servant, + GNOME_Evolution_Calendar_CallStatus status, + const CORBA_char *capabilities, + CORBA_Environment *ev) +{ + CalListener *listener; + CalListenerPrivate *priv; -/* CORBA servant implementation */ + listener = CAL_LISTENER (bonobo_object_from_servant (servant)); + priv = listener->priv; + + if (!priv->notify) + return; + + g_signal_emit (G_OBJECT (listener), signals[STATIC_CAPABILITIES], 0, convert_status (status)); +} /* ::notifyCalOpened method */ static void impl_notifyCalOpened (PortableServer_Servant servant, - GNOME_Evolution_Calendar_Listener_OpenStatus status, - GNOME_Evolution_Calendar_Cal cal, + GNOME_Evolution_Calendar_CallStatus status, + CORBA_Environment *ev) +{ + CalListener *listener; + CalListenerPrivate *priv; + + listener = CAL_LISTENER (bonobo_object_from_servant (servant)); + priv = listener->priv; + + if (!priv->notify) + return; + + g_signal_emit (G_OBJECT (listener), signals[OPEN], 0, convert_status (status)); +} + +static void +impl_notifyCalRemoved (PortableServer_Servant servant, + GNOME_Evolution_Calendar_CallStatus status, CORBA_Environment *ev) { CalListener *listener; CalListenerPrivate *priv; - CORBA_Environment aev; - GNOME_Evolution_Calendar_Cal cal_copy; listener = CAL_LISTENER (bonobo_object_from_servant (servant)); priv = listener->priv; @@ -163,63 +217,388 @@ impl_notifyCalOpened (PortableServer_Servant servant, if (!priv->notify) return; - CORBA_exception_init (&aev); - cal_copy = CORBA_Object_duplicate (cal, &aev); + g_signal_emit (G_OBJECT (listener), signals[REMOVE], 0, convert_status (status)); +} + +static void +impl_notifyObjectCreated (PortableServer_Servant servant, + GNOME_Evolution_Calendar_CallStatus status, + const CORBA_char *uid, + CORBA_Environment *ev) +{ + CalListener *listener; + CalListenerPrivate *priv; + + listener = CAL_LISTENER (bonobo_object_from_servant (servant)); + priv = listener->priv; + + if (!priv->notify) + return; + + g_signal_emit (G_OBJECT (listener), signals[CREATE_OBJECT], 0, convert_status (status), uid); +} + +static void +impl_notifyObjectModified (PortableServer_Servant servant, + GNOME_Evolution_Calendar_CallStatus status, + CORBA_Environment *ev) +{ + CalListener *listener; + CalListenerPrivate *priv; + + listener = CAL_LISTENER (bonobo_object_from_servant (servant)); + priv = listener->priv; - if (aev._major != CORBA_NO_EXCEPTION) { - g_message ("Listener_notifyCalOpened(): could not duplicate the calendar"); - CORBA_exception_free (&aev); + if (!priv->notify) return; + + g_signal_emit (G_OBJECT (listener), signals[MODIFY_OBJECT], 0, convert_status (status)); +} + +static void +impl_notifyObjectRemoved (PortableServer_Servant servant, + GNOME_Evolution_Calendar_CallStatus status, + CORBA_Environment *ev) +{ + CalListener *listener; + CalListenerPrivate *priv; + + listener = CAL_LISTENER (bonobo_object_from_servant (servant)); + priv = listener->priv; + + if (!priv->notify) + return; + + g_signal_emit (G_OBJECT (listener), signals[REMOVE_OBJECT], 0, convert_status (status)); +} + +static void +impl_notifyAlarmDiscarded (PortableServer_Servant servant, + GNOME_Evolution_Calendar_CallStatus status, + CORBA_Environment *ev) +{ + CalListener *listener; + CalListenerPrivate *priv; + + listener = CAL_LISTENER (bonobo_object_from_servant (servant)); + priv = listener->priv; + + if (!priv->notify) + return; + + g_signal_emit (G_OBJECT (listener), signals[DISCARD_ALARM], 0, convert_status (status)); +} + +static void +impl_notifyObjectsReceived (PortableServer_Servant servant, + GNOME_Evolution_Calendar_CallStatus status, + CORBA_Environment *ev) +{ + CalListener *listener; + CalListenerPrivate *priv; + + listener = CAL_LISTENER (bonobo_object_from_servant (servant)); + priv = listener->priv; + + if (!priv->notify) + return; + + g_signal_emit (G_OBJECT (listener), signals[RECEIVE_OBJECTS], 0, convert_status (status)); +} + +static void +impl_notifyObjectsSent (PortableServer_Servant servant, + GNOME_Evolution_Calendar_CallStatus status, + CORBA_Environment *ev) +{ + CalListener *listener; + CalListenerPrivate *priv; + + listener = CAL_LISTENER (bonobo_object_from_servant (servant)); + priv = listener->priv; + + if (!priv->notify) + return; + + g_signal_emit (G_OBJECT (listener), signals[SEND_OBJECTS], 0, convert_status (status)); +} + +static void +impl_notifyDefaultObjectRequested (PortableServer_Servant servant, + const GNOME_Evolution_Calendar_CallStatus status, + const CORBA_char *object, + CORBA_Environment *ev) +{ + CalListener *listener; + CalListenerPrivate *priv; + + listener = CAL_LISTENER (bonobo_object_from_servant (servant)); + priv = listener->priv; + + if (!priv->notify) + return; + + g_signal_emit (G_OBJECT (listener), signals[DEFAULT_OBJECT], 0, convert_status (status), object); +} + +static void +impl_notifyObjectRequested (PortableServer_Servant servant, + const GNOME_Evolution_Calendar_CallStatus status, + const CORBA_char *object, + CORBA_Environment *ev) +{ + CalListener *listener; + CalListenerPrivate *priv; + + listener = CAL_LISTENER (bonobo_object_from_servant (servant)); + priv = listener->priv; + + if (!priv->notify) + return; + + g_signal_emit (G_OBJECT (listener), signals[OBJECT], 0, convert_status (status), object); +} + +static GList * +build_object_list (const GNOME_Evolution_Calendar_stringlist *seq) +{ + GList *list; + int i; + + list = NULL; + for (i = 0; i < seq->_length; i++) { + icalcomponent *comp; + + comp = icalcomponent_new_from_string (seq->_buffer[i]); + if (!comp) + continue; + + list = g_list_prepend (list, comp); } - CORBA_exception_free (&aev); - g_assert (priv->cal_opened_fn != NULL); - (* priv->cal_opened_fn) (listener, status, cal, priv->fn_data); + return list; +} + +static void +impl_notifyObjectListRequested (PortableServer_Servant servant, + const GNOME_Evolution_Calendar_CallStatus status, + const GNOME_Evolution_Calendar_stringlist *objects, + CORBA_Environment *ev) +{ + CalListener *listener; + CalListenerPrivate *priv; + GList *object_list, *l; + + listener = CAL_LISTENER (bonobo_object_from_servant (servant)); + priv = listener->priv; + + if (!priv->notify) + return; + + object_list = build_object_list (objects); + + g_signal_emit (G_OBJECT (listener), signals[OBJECT_LIST], 0, convert_status (status), object_list); + + for (l = object_list; l; l = l->next) + icalcomponent_free (l->data); + g_list_free (object_list); } -/* ::notifyCalSetMode method */ static void -impl_notifyCalSetMode (PortableServer_Servant servant, - GNOME_Evolution_Calendar_Listener_SetModeStatus status, - GNOME_Evolution_Calendar_CalMode mode, - CORBA_Environment *ev) +impl_notifyTimezoneRequested (PortableServer_Servant servant, + const GNOME_Evolution_Calendar_CallStatus status, + const CORBA_char *object, + CORBA_Environment *ev) { CalListener *listener; CalListenerPrivate *priv; + + listener = CAL_LISTENER (bonobo_object_from_servant (servant)); + priv = listener->priv; + + if (!priv->notify) + return; + + g_signal_emit (G_OBJECT (listener), signals[GET_TIMEZONE], 0, convert_status (status), object); +} +static void +impl_notifyTimezoneAdded (PortableServer_Servant servant, + const GNOME_Evolution_Calendar_CallStatus status, + const CORBA_char *tzid, + CORBA_Environment *ev) +{ + CalListener *listener; + CalListenerPrivate *priv; + listener = CAL_LISTENER (bonobo_object_from_servant (servant)); priv = listener->priv; if (!priv->notify) return; + + g_signal_emit (G_OBJECT (listener), signals[ADD_TIMEZONE], 0, convert_status (status), tzid); +} - g_assert (priv->cal_set_mode_fn != NULL); - (* priv->cal_set_mode_fn) (listener, status, mode, priv->fn_data); +static void +impl_notifyDefaultTimezoneSet (PortableServer_Servant servant, + const GNOME_Evolution_Calendar_CallStatus status, + CORBA_Environment *ev) +{ + CalListener *listener; + CalListenerPrivate *priv; + + listener = CAL_LISTENER (bonobo_object_from_servant (servant)); + priv = listener->priv; + + if (!priv->notify) + return; + + g_signal_emit (G_OBJECT (listener), signals[SET_DEFAULT_TIMEZONE], 0, convert_status (status)); +} + +static GList * +build_change_list (const GNOME_Evolution_Calendar_CalObjChangeSeq *seq) +{ + GList *list = NULL; + icalcomponent *icalcomp; + int i; + + /* Create the list in reverse order */ + for (i = 0; i < seq->_length; i++) { + GNOME_Evolution_Calendar_CalObjChange *corba_coc; + CalClientChange *ccc; + + corba_coc = &seq->_buffer[i]; + ccc = g_new (CalClientChange, 1); + + icalcomp = icalparser_parse_string (corba_coc->calobj); + if (!icalcomp) + continue; + + ccc->comp = cal_component_new (); + if (!cal_component_set_icalcomponent (ccc->comp, icalcomp)) { + icalcomponent_free (icalcomp); + g_object_unref (G_OBJECT (ccc->comp)); + continue; + } + ccc->type = corba_coc->type; + + list = g_list_prepend (list, ccc); + } + + list = g_list_reverse (list); + + return list; } -/* ::notifyObjUpdated method */ static void -impl_notifyObjUpdated (PortableServer_Servant servant, - const CORBA_char *uid, - CORBA_Environment *ev) +impl_notifyChanges (PortableServer_Servant servant, + const GNOME_Evolution_Calendar_CallStatus status, + const GNOME_Evolution_Calendar_CalObjChangeSeq *seq, + CORBA_Environment *ev) { CalListener *listener; CalListenerPrivate *priv; + GList *changes, *l; + + listener = CAL_LISTENER (bonobo_object_from_servant (servant)); + priv = listener->priv; + if (!priv->notify) + return; + + changes = build_change_list (seq); + + g_signal_emit (G_OBJECT (listener), signals[GET_CHANGES], 0, convert_status (status), changes); + + for (l = changes; l; l = l->next) + g_free (l->data); + g_list_free (changes); +} + +static GList * +build_free_busy_list (const GNOME_Evolution_Calendar_CalObjSeq *seq) +{ + GList *list = NULL; + int i; + + /* Create the list in reverse order */ + for (i = 0; i < seq->_length; i++) { + CalComponent *comp; + icalcomponent *icalcomp; + icalcomponent_kind kind; + + icalcomp = icalcomponent_new_from_string (seq->_buffer[i]); + if (!icalcomp) + continue; + + kind = icalcomponent_isa (icalcomp); + if (kind == ICAL_VFREEBUSY_COMPONENT) { + comp = cal_component_new (); + if (!cal_component_set_icalcomponent (comp, icalcomp)) { + icalcomponent_free (icalcomp); + g_object_unref (G_OBJECT (comp)); + continue; + } + + list = g_list_append (list, comp); + } else { + icalcomponent_free (icalcomp); + } + } + + return list; +} + +static void +impl_notifyFreeBusy (PortableServer_Servant servant, + const GNOME_Evolution_Calendar_CallStatus status, + const GNOME_Evolution_Calendar_CalObjSeq *seq, + CORBA_Environment *ev) +{ + CalListener *listener; + CalListenerPrivate *priv; + GList *freebusy, *l; + listener = CAL_LISTENER (bonobo_object_from_servant (servant)); priv = listener->priv; if (!priv->notify) return; + + freebusy = build_free_busy_list (seq); + + g_signal_emit (G_OBJECT (listener), signals[GET_FREE_BUSY], 0, convert_status (status), freebusy); + + for (l = freebusy; l; l = l->next) + g_free (l->data); + g_list_free (freebusy); +} - g_assert (priv->obj_updated_fn != NULL); - (* priv->obj_updated_fn) (listener, uid, priv->fn_data); +static void +impl_notifyQuery (PortableServer_Servant servant, + const GNOME_Evolution_Calendar_CallStatus status, + const GNOME_Evolution_Calendar_Query query, + CORBA_Environment *ev) +{ + CalListener *listener; + CalListenerPrivate *priv; + + listener = CAL_LISTENER (bonobo_object_from_servant (servant)); + priv = listener->priv; + + if (!priv->notify) + return; + + g_signal_emit (G_OBJECT (listener), signals[QUERY], 0, convert_status (status), query); } -/* ::notifyObjRemoved method */ +/* ::notifyCalSetMode method */ static void -impl_notifyObjRemoved (PortableServer_Servant servant, - const CORBA_char *uid, +impl_notifyCalSetMode (PortableServer_Servant servant, + GNOME_Evolution_Calendar_Listener_SetModeStatus status, + GNOME_Evolution_Calendar_CalMode mode, CORBA_Environment *ev) { CalListener *listener; @@ -231,10 +610,13 @@ impl_notifyObjRemoved (PortableServer_Servant servant, if (!priv->notify) return; - g_assert (priv->obj_removed_fn != NULL); - (* priv->obj_removed_fn) (listener, uid, priv->fn_data); + g_message ("notify_set_mode"); + + g_assert (priv->cal_set_mode_fn != NULL); + (* priv->cal_set_mode_fn) (listener, status, mode, priv->fn_data); } + /* ::notifyErrorOccurred method */ static void impl_notifyErrorOccurred (PortableServer_Servant servant, @@ -250,6 +632,8 @@ impl_notifyErrorOccurred (PortableServer_Servant servant, if (!priv->notify) return; + g_message ("notify_error"); + g_assert (priv->error_occurred_fn != NULL); (* priv->error_occurred_fn) (listener, message, priv->fn_data); } @@ -269,21 +653,283 @@ impl_notifyCategoriesChanged (PortableServer_Servant servant, if (!priv->notify) return; + g_message ("notify_categories"); + g_assert (priv->categories_changed_fn != NULL); (* priv->categories_changed_fn) (listener, categories, priv->fn_data); } +/* Object initialization function for the calendar listener */ +static void +cal_listener_init (CalListener *listener, CalListenerClass *klass) +{ + CalListenerPrivate *priv; + + priv = g_new0 (CalListenerPrivate, 1); + listener->priv = priv; + + priv->error_occurred_fn = NULL; + priv->categories_changed_fn = NULL; + + priv->notify = TRUE; +} + +/* Finalize handler for the calendar listener */ +static void +cal_listener_finalize (GObject *object) +{ + CalListener *listener; + CalListenerPrivate *priv; + + g_return_if_fail (object != NULL); + g_return_if_fail (IS_CAL_LISTENER (object)); + + listener = CAL_LISTENER (object); + priv = listener->priv; + + priv->error_occurred_fn = NULL; + priv->categories_changed_fn = NULL; + priv->fn_data = NULL; + + priv->notify = FALSE; + + g_free (priv); + listener->priv = NULL; + + if (G_OBJECT_CLASS (parent_class)->finalize) + (* G_OBJECT_CLASS (parent_class)->finalize) (object); +} + +/* Class initialization function for the calendar listener */ +static void +cal_listener_class_init (CalListenerClass *klass) +{ + GObjectClass *object_class; + + object_class = (GObjectClass *) klass; + + parent_class = g_type_class_peek_parent (klass); + + klass->epv.notifyReadOnly = impl_notifyReadOnly; + klass->epv.notifyCalAddress = impl_notifyCalAddress; + klass->epv.notifyAlarmEmailAddress = impl_notifyAlarmEmailAddress; + klass->epv.notifyLDAPAttribute = impl_notifyLDAPAttribute; + klass->epv.notifyStaticCapabilities = impl_notifyStaticCapabilities; + klass->epv.notifyCalOpened = impl_notifyCalOpened; + klass->epv.notifyCalRemoved = impl_notifyCalRemoved; + klass->epv.notifyObjectCreated = impl_notifyObjectCreated; + klass->epv.notifyObjectModified = impl_notifyObjectModified; + klass->epv.notifyObjectRemoved = impl_notifyObjectRemoved; + klass->epv.notifyAlarmDiscarded = impl_notifyAlarmDiscarded; + klass->epv.notifyObjectsReceived = impl_notifyObjectsReceived; + klass->epv.notifyObjectsSent = impl_notifyObjectsSent; + klass->epv.notifyDefaultObjectRequested = impl_notifyDefaultObjectRequested; + klass->epv.notifyObjectRequested = impl_notifyObjectRequested; + klass->epv.notifyObjectListRequested = impl_notifyObjectListRequested; + klass->epv.notifyTimezoneRequested = impl_notifyTimezoneRequested; + klass->epv.notifyTimezoneAdded = impl_notifyTimezoneAdded; + klass->epv.notifyDefaultTimezoneSet = impl_notifyDefaultTimezoneSet; + klass->epv.notifyChanges = impl_notifyChanges; + klass->epv.notifyFreeBusy = impl_notifyFreeBusy; + klass->epv.notifyQuery = impl_notifyQuery; + klass->epv.notifyCalSetMode = impl_notifyCalSetMode; + klass->epv.notifyErrorOccurred = impl_notifyErrorOccurred; + klass->epv.notifyCategoriesChanged = impl_notifyCategoriesChanged; + + object_class->finalize = cal_listener_finalize; + + signals[READ_ONLY] = + g_signal_new ("read_only", + G_TYPE_FROM_CLASS (klass), + G_SIGNAL_RUN_LAST, + G_STRUCT_OFFSET (CalListenerClass, read_only), + NULL, NULL, + cal_marshal_VOID__INT_BOOLEAN, + G_TYPE_NONE, 2, G_TYPE_INT, G_TYPE_BOOLEAN); + signals[CAL_ADDRESS] = + g_signal_new ("cal_address", + G_TYPE_FROM_CLASS (klass), + G_SIGNAL_RUN_LAST, + G_STRUCT_OFFSET (CalListenerClass, cal_address), + NULL, NULL, + cal_marshal_VOID__INT_STRING, + G_TYPE_NONE, 2, G_TYPE_INT, G_TYPE_STRING); + signals[ALARM_ADDRESS] = + g_signal_new ("alarm_address", + G_TYPE_FROM_CLASS (klass), + G_SIGNAL_RUN_LAST, + G_STRUCT_OFFSET (CalListenerClass, alarm_address), + NULL, NULL, + cal_marshal_VOID__INT_STRING, + G_TYPE_NONE, 2, G_TYPE_INT, G_TYPE_STRING); + signals[LDAP_ATTRIBUTE] = + g_signal_new ("ldap_attribute", + G_TYPE_FROM_CLASS (klass), + G_SIGNAL_RUN_LAST, + G_STRUCT_OFFSET (CalListenerClass, ldap_attribute), + NULL, NULL, + cal_marshal_VOID__INT_STRING, + G_TYPE_NONE, 2, G_TYPE_INT, G_TYPE_STRING); + signals[STATIC_CAPABILITIES] = + g_signal_new ("static_capabilities", + G_TYPE_FROM_CLASS (klass), + G_SIGNAL_RUN_LAST, + G_STRUCT_OFFSET (CalListenerClass, static_capabilities), + NULL, NULL, + cal_marshal_VOID__INT_STRING, + G_TYPE_NONE, 2, G_TYPE_INT, G_TYPE_STRING); + signals[OPEN] = + g_signal_new ("open", + G_TYPE_FROM_CLASS (klass), + G_SIGNAL_RUN_LAST, + G_STRUCT_OFFSET (CalListenerClass, open), + NULL, NULL, + cal_marshal_VOID__INT, + G_TYPE_NONE, 1, G_TYPE_INT); + signals[REMOVE] = + g_signal_new ("remove", + G_TYPE_FROM_CLASS (klass), + G_SIGNAL_RUN_LAST, + G_STRUCT_OFFSET (CalListenerClass, remove), + NULL, NULL, + cal_marshal_VOID__INT, + G_TYPE_NONE, 1, G_TYPE_INT); + signals[CREATE_OBJECT] = + g_signal_new ("create_object", + G_TYPE_FROM_CLASS (klass), + G_SIGNAL_RUN_LAST, + G_STRUCT_OFFSET (CalListenerClass, create_object), + NULL, NULL, + cal_marshal_VOID__INT_STRING, + G_TYPE_NONE, 2, G_TYPE_INT, G_TYPE_STRING); + signals[MODIFY_OBJECT] = + g_signal_new ("modify_object", + G_TYPE_FROM_CLASS (klass), + G_SIGNAL_RUN_LAST, + G_STRUCT_OFFSET (CalListenerClass, modify_object), + NULL, NULL, + cal_marshal_VOID__INT, + G_TYPE_NONE, 1, G_TYPE_INT); + signals[REMOVE_OBJECT] = + g_signal_new ("remove_object", + G_TYPE_FROM_CLASS (klass), + G_SIGNAL_RUN_LAST, + G_STRUCT_OFFSET (CalListenerClass, remove_object), + NULL, NULL, + cal_marshal_VOID__INT, + G_TYPE_NONE, 1, G_TYPE_INT); + signals[DISCARD_ALARM] = + g_signal_new ("discard_alarm", + G_TYPE_FROM_CLASS (klass), + G_SIGNAL_RUN_LAST, + G_STRUCT_OFFSET (CalListenerClass, discard_alarm), + NULL, NULL, + cal_marshal_VOID__INT, + G_TYPE_NONE, 1, G_TYPE_INT); + signals[RECEIVE_OBJECTS] = + g_signal_new ("receive_objects", + G_TYPE_FROM_CLASS (klass), + G_SIGNAL_RUN_LAST, + G_STRUCT_OFFSET (CalListenerClass, receive_objects), + NULL, NULL, + cal_marshal_VOID__INT, + G_TYPE_NONE, 1, G_TYPE_INT); + signals[SEND_OBJECTS] = + g_signal_new ("send_objects", + G_TYPE_FROM_CLASS (klass), + G_SIGNAL_RUN_LAST, + G_STRUCT_OFFSET (CalListenerClass, send_objects), + NULL, NULL, + cal_marshal_VOID__INT, + G_TYPE_NONE, 1, G_TYPE_INT); + signals[DEFAULT_OBJECT] = + g_signal_new ("default_object", + G_TYPE_FROM_CLASS (klass), + G_SIGNAL_RUN_LAST, + G_STRUCT_OFFSET (CalListenerClass, default_object), + NULL, NULL, + cal_marshal_VOID__INT_STRING, + G_TYPE_NONE, 2, G_TYPE_INT, G_TYPE_STRING); + signals[OBJECT] = + g_signal_new ("object", + G_TYPE_FROM_CLASS (klass), + G_SIGNAL_RUN_LAST, + G_STRUCT_OFFSET (CalListenerClass, object), + NULL, NULL, + cal_marshal_VOID__INT_STRING, + G_TYPE_NONE, 2, G_TYPE_INT, G_TYPE_STRING); + signals[OBJECT_LIST] = + g_signal_new ("object_list", + G_TYPE_FROM_CLASS (klass), + G_SIGNAL_RUN_LAST, + G_STRUCT_OFFSET (CalListenerClass, object_list), + NULL, NULL, + cal_marshal_VOID__INT_POINTER, + G_TYPE_NONE, 2, G_TYPE_INT, G_TYPE_POINTER); + signals[GET_TIMEZONE] = + g_signal_new ("get_timezone", + G_TYPE_FROM_CLASS (klass), + G_SIGNAL_RUN_LAST, + G_STRUCT_OFFSET (CalListenerClass, get_timezone), + NULL, NULL, + cal_marshal_VOID__INT_STRING, + G_TYPE_NONE, 2, G_TYPE_INT, G_TYPE_STRING); + signals[ADD_TIMEZONE] = + g_signal_new ("add_timezone", + G_TYPE_FROM_CLASS (klass), + G_SIGNAL_RUN_LAST, + G_STRUCT_OFFSET (CalListenerClass, add_timezone), + NULL, NULL, + cal_marshal_VOID__INT_STRING, + G_TYPE_NONE, 2, G_TYPE_INT, G_TYPE_STRING); + signals[SET_DEFAULT_TIMEZONE] = + g_signal_new ("set_default_timezone", + G_TYPE_FROM_CLASS (klass), + G_SIGNAL_RUN_LAST, + G_STRUCT_OFFSET (CalListenerClass, set_default_timezone), + NULL, NULL, + cal_marshal_VOID__INT, + G_TYPE_NONE, 1, G_TYPE_INT); + signals[GET_CHANGES] = + g_signal_new ("get_changes", + G_TYPE_FROM_CLASS (klass), + G_SIGNAL_RUN_LAST, + G_STRUCT_OFFSET (CalListenerClass, get_changes), + NULL, NULL, + cal_marshal_VOID__INT_POINTER, + G_TYPE_NONE, 1, G_TYPE_INT, G_TYPE_POINTER); + signals[GET_FREE_BUSY] = + g_signal_new ("get_free_busy", + G_TYPE_FROM_CLASS (klass), + G_SIGNAL_RUN_LAST, + G_STRUCT_OFFSET (CalListenerClass, get_free_busy), + NULL, NULL, + cal_marshal_VOID__INT_POINTER, + G_TYPE_NONE, 1, G_TYPE_INT, G_TYPE_POINTER); + signals[QUERY] = + g_signal_new ("query", + G_TYPE_FROM_CLASS (klass), + G_SIGNAL_RUN_LAST, + G_STRUCT_OFFSET (CalListenerClass, query), + NULL, NULL, + cal_marshal_VOID__INT_POINTER, + G_TYPE_NONE, 2, G_TYPE_INT, G_TYPE_POINTER); +} + +BONOBO_TYPE_FUNC_FULL (CalListener, + GNOME_Evolution_Calendar_Listener, + BONOBO_TYPE_OBJECT, + cal_listener); + /** * cal_listener_construct: * @listener: A calendar listener. * @cal_opened_fn: Function that will be called to notify that a calendar was * opened. - * @obj_updated_fn: Function that will be called to notify that an object in the - * calendar was updated. - * @obj_removed_fn: Function that will be called to notify that an object in the - * calendar was removed. + * @cal_removed_fn: Function that will be called to notify that a calendar was + * removed * @error_occurred_fn: Function that will be called to notify errors. * @categories_changed_fn: Function that will be called to notify that the list * of categories that are present in the calendar's objects has changed. @@ -297,10 +943,7 @@ impl_notifyCategoriesChanged (PortableServer_Servant servant, **/ CalListener * cal_listener_construct (CalListener *listener, - CalListenerCalOpenedFn cal_opened_fn, CalListenerCalSetModeFn cal_set_mode_fn, - CalListenerObjUpdatedFn obj_updated_fn, - CalListenerObjRemovedFn obj_removed_fn, CalListenerErrorOccurredFn error_occurred_fn, CalListenerCategoriesChangedFn categories_changed_fn, gpointer fn_data) @@ -309,19 +952,13 @@ cal_listener_construct (CalListener *listener, g_return_val_if_fail (listener != NULL, NULL); g_return_val_if_fail (IS_CAL_LISTENER (listener), NULL); - g_return_val_if_fail (cal_opened_fn != NULL, NULL); g_return_val_if_fail (cal_set_mode_fn != NULL, NULL); - g_return_val_if_fail (obj_updated_fn != NULL, NULL); - g_return_val_if_fail (obj_removed_fn != NULL, NULL); g_return_val_if_fail (error_occurred_fn != NULL, NULL); g_return_val_if_fail (categories_changed_fn != NULL, NULL); priv = listener->priv; - priv->cal_opened_fn = cal_opened_fn; priv->cal_set_mode_fn = cal_set_mode_fn; - priv->obj_updated_fn = obj_updated_fn; - priv->obj_removed_fn = obj_removed_fn; priv->error_occurred_fn = error_occurred_fn; priv->categories_changed_fn = categories_changed_fn; priv->fn_data = fn_data; @@ -333,10 +970,6 @@ cal_listener_construct (CalListener *listener, * cal_listener_new: * @cal_opened_fn: Function that will be called to notify that a calendar was * opened. - * @obj_updated_fn: Function that will be called to notify that an object in the - * calendar was updated. - * @obj_removed_fn: Function that will be called to notify that an object in the - * calendar was removed. * @error_occurred_fn: Function that will be called to notify errors. * @categories_changed_fn: Function that will be called to notify that the list * of categories that are present in the calendar's objects has changed. @@ -348,28 +981,22 @@ cal_listener_construct (CalListener *listener, * Return value: A newly-created #CalListener object. **/ CalListener * -cal_listener_new (CalListenerCalOpenedFn cal_opened_fn, - CalListenerCalSetModeFn cal_set_mode_fn, - CalListenerObjUpdatedFn obj_updated_fn, - CalListenerObjRemovedFn obj_removed_fn, +cal_listener_new (CalListenerCalSetModeFn cal_set_mode_fn, CalListenerErrorOccurredFn error_occurred_fn, CalListenerCategoriesChangedFn categories_changed_fn, gpointer fn_data) { CalListener *listener; - g_return_val_if_fail (cal_opened_fn != NULL, NULL); - g_return_val_if_fail (obj_updated_fn != NULL, NULL); - g_return_val_if_fail (obj_removed_fn != NULL, NULL); g_return_val_if_fail (error_occurred_fn != NULL, NULL); g_return_val_if_fail (categories_changed_fn != NULL, NULL); - listener = g_object_new (CAL_LISTENER_TYPE, NULL); + listener = g_object_new (CAL_LISTENER_TYPE, + "poa", bonobo_poa_get_threaded (ORBIT_THREAD_HINT_PER_REQUEST, NULL), + NULL); + return cal_listener_construct (listener, - cal_opened_fn, cal_set_mode_fn, - obj_updated_fn, - obj_removed_fn, error_occurred_fn, categories_changed_fn, fn_data); diff --git a/calendar/cal-client/cal-listener.h b/calendar/cal-client/cal-listener.h index d0f9a718a4..1230104999 100644 --- a/calendar/cal-client/cal-listener.h +++ b/calendar/cal-client/cal-listener.h @@ -23,6 +23,7 @@ #include #include "evolution-calendar.h" +#include "cal-client-types.h" G_BEGIN_DECLS @@ -48,26 +49,46 @@ typedef struct { BonoboObjectClass parent_class; POA_GNOME_Evolution_Calendar_Listener__epv epv; + + /* Signals */ + void (*read_only) (CalListener *listener, ECalendarStatus status, gboolean read_only); + void (*cal_address) (CalListener *listener, ECalendarStatus status, const char *address); + void (*alarm_address) (CalListener *listener, ECalendarStatus status, const char *address); + void (*ldap_attribute) (CalListener *listener, ECalendarStatus status, const char *ldap_attribute); + void (*static_capabilities) (CalListener *listener, ECalendarStatus status, const char *capabilities); + + void (*open) (CalListener *listener, ECalendarStatus status); + void (*remove) (CalListener *listener, ECalendarStatus status); + + void (*create_object) (CalListener *listener, ECalendarStatus status, const char *id); + void (*modify_object) (CalListener *listener, ECalendarStatus status); + void (*remove_object) (CalListener *listener, ECalendarStatus status); + + void (*discard_alarm) (CalListener *listener, ECalendarStatus status); + + void (*receive_objects) (CalListener *listener, ECalendarStatus status); + void (*send_objects) (CalListener *listener, ECalendarStatus status); + + void (*default_object) (CalListener *listener, ECalendarStatus status, const char *object); + void (*object) (CalListener *listener, ECalendarStatus status, const char *object); + void (*object_list) (CalListener *listener, ECalendarStatus status, GList **objects); + + void (*get_timezone) (CalListener *listener, ECalendarStatus status, const char *object); + void (*add_timezone) (CalListener *listener, ECalendarStatus status, const char *tzid); + void (*set_default_timezone) (CalListener *listener, ECalendarStatus status, const char *tzid); + + void (*get_changes) (CalListener *listener, ECalendarStatus status, GList *changes); + void (*get_free_busy) (CalListener *listener, ECalendarStatus status, GList *freebusy); + + void (*query) (CalListener *listener, ECalendarStatus status, GNOME_Evolution_Calendar_Query query); } CalListenerClass; /* Notification functions */ -typedef void (* CalListenerCalOpenedFn) (CalListener *listener, - GNOME_Evolution_Calendar_Listener_OpenStatus status, - GNOME_Evolution_Calendar_Cal cal, - gpointer data); - typedef void (* CalListenerCalSetModeFn) (CalListener *listener, GNOME_Evolution_Calendar_Listener_SetModeStatus status, GNOME_Evolution_Calendar_CalMode mode, gpointer data); -typedef void (* CalListenerObjUpdatedFn) (CalListener *listener, - const CORBA_char *uid, - gpointer data); -typedef void (* CalListenerObjRemovedFn) (CalListener *listener, - const CORBA_char *uid, - gpointer data); - typedef void (* CalListenerErrorOccurredFn) (CalListener *listener, const char *message, gpointer data); @@ -80,18 +101,12 @@ typedef void (* CalListenerCategoriesChangedFn) (CalListener *listener, GType cal_listener_get_type (void); CalListener *cal_listener_construct (CalListener *listener, - CalListenerCalOpenedFn cal_opened_fn, CalListenerCalSetModeFn cal_set_mode_fn, - CalListenerObjUpdatedFn obj_updated_fn, - CalListenerObjRemovedFn obj_removed_fn, CalListenerErrorOccurredFn error_occurred_fn, CalListenerCategoriesChangedFn categories_changed_fn, gpointer fn_data); -CalListener *cal_listener_new (CalListenerCalOpenedFn cal_opened_fn, - CalListenerCalSetModeFn cal_set_mode_fn, - CalListenerObjUpdatedFn obj_updated_fn, - CalListenerObjRemovedFn obj_removed_fn, +CalListener *cal_listener_new (CalListenerCalSetModeFn cal_set_mode_fn, CalListenerErrorOccurredFn error_occurred_fn, CalListenerCategoriesChangedFn categories_changed_fn, gpointer fn_data); diff --git a/calendar/cal-client/cal-marshal.list b/calendar/cal-client/cal-marshal.list new file mode 100644 index 0000000000..e0ca019669 --- /dev/null +++ b/calendar/cal-client/cal-marshal.list @@ -0,0 +1,6 @@ +NONE:INT +NONE:POINTER +NONE:INT,STRING +NONE:INT,BOOL +NONE:INT,POINTER +NONE:STRING,INT diff --git a/calendar/cal-client/cal-query.c b/calendar/cal-client/cal-query.c index 914af5db28..e77f5ad3e9 100644 --- a/calendar/cal-client/cal-query.c +++ b/calendar/cal-client/cal-query.c @@ -24,7 +24,8 @@ #include #include -#include "cal-util/cal-util-marshal.h" +#include "cal-marshal.h" +#include "cal-client.h" #include "cal-query.h" #include "query-listener.h" @@ -32,143 +33,88 @@ /* Private part of the CalQuery structure */ struct _CalQueryPrivate { - /* Our query listener implementation */ - QueryListener *ql; - /* Handle to the query in the server */ - GNOME_Evolution_Calendar_Query corba_query; + GNOME_Evolution_Calendar_Query query; + + /* Our query listener implementation */ + QueryListener *listener; /* The CalClient associated with this query */ CalClient *client; }; - - -static void cal_query_class_init (CalQueryClass *klass); -static void cal_query_init (CalQuery *query, CalQueryClass *klass); -static void cal_query_finalize (GObject *object); +/* Property IDs */ +enum props { + PROP_0, + PROP_QUERY, + PROP_LISTENER, + PROP_CLIENT +}; /* Signal IDs */ enum { - OBJ_UPDATED, - OBJ_REMOVED, + OBJECTS_ADDED, + OBJECTS_MODIFIED, + OBJECTS_REMOVED, + QUERY_PROGRESS, QUERY_DONE, - EVAL_ERROR, LAST_SIGNAL }; -static guint query_signals[LAST_SIGNAL]; +static guint signals[LAST_SIGNAL]; static GObjectClass *parent_class; -/** - * cal_query_get_type: - * - * Registers the #CalQuery class if necessary, and returns the type ID assigned - * to it. - * - * Return value: The type ID of the #CalQuery class. - **/ -GType -cal_query_get_type (void) +static void +objects_added_cb (QueryListener *listener, GList *objects, gpointer data) { - static GType cal_query_type = 0; + CalQuery *query; - if (!cal_query_type) { - static GTypeInfo info = { - sizeof (CalQueryClass), - (GBaseInitFunc) NULL, - (GBaseFinalizeFunc) NULL, - (GClassInitFunc) cal_query_class_init, - NULL, NULL, - sizeof (CalQuery), - 0, - (GInstanceInitFunc) cal_query_init - }; - cal_query_type = g_type_register_static (G_TYPE_OBJECT, "CalQuery", &info, 0); - } + query = CAL_QUERY (data); - return cal_query_type; + g_signal_emit (G_OBJECT (query), signals[OBJECTS_ADDED], 0, objects); } -GType -cal_query_done_status_enum_get_type (void) +static void +objects_modified_cb (QueryListener *listener, GList *objects, gpointer data) { - static GType cal_query_done_status_enum_type = 0; + CalQuery *query; - if (!cal_query_done_status_enum_type) { - static GEnumValue values [] = { - { CAL_QUERY_DONE_SUCCESS, "CalQueryDoneSuccess", "success" }, - { CAL_QUERY_DONE_PARSE_ERROR, "CalQueryDoneParseError", "parse-error" }, - { -1, NULL, NULL } - }; + query = CAL_QUERY (data); - cal_query_done_status_enum_type = - g_enum_register_static ("CalQueryDoneStatusEnum", values); - } + g_signal_emit (G_OBJECT (query), signals[OBJECTS_MODIFIED], 0, objects); +} + +static void +objects_removed_cb (QueryListener *listener, GList *uids, gpointer data) +{ + CalQuery *query; + + query = CAL_QUERY (data); - return cal_query_done_status_enum_type; + g_signal_emit (G_OBJECT (query), signals[OBJECTS_REMOVED], 0, uids); } -/* Class initialization function for the calendar query */ static void -cal_query_class_init (CalQueryClass *klass) +query_progress_cb (QueryListener *listener, const char *message, int percent, gpointer data) { - GObjectClass *object_class; + CalQuery *query; - object_class = (GObjectClass *) klass; + query = CAL_QUERY (data); - parent_class = g_type_class_peek_parent (klass); + g_signal_emit (G_OBJECT (query), signals[QUERY_PROGRESS], 0, message, percent); +} - query_signals[OBJ_UPDATED] = - g_signal_new ("obj_updated", - G_TYPE_FROM_CLASS (klass), - G_SIGNAL_RUN_FIRST, - G_STRUCT_OFFSET (CalQueryClass, obj_updated), - NULL, NULL, - cal_util_marshal_VOID__STRING_BOOLEAN_INT_INT, - G_TYPE_NONE, 4, - G_TYPE_STRING, - G_TYPE_BOOLEAN, - G_TYPE_INT, - G_TYPE_INT); - query_signals[OBJ_REMOVED] = - g_signal_new ("obj_removed", - G_TYPE_FROM_CLASS (klass), - G_SIGNAL_RUN_FIRST, - G_STRUCT_OFFSET (CalQueryClass, obj_removed), - NULL, NULL, - g_cclosure_marshal_VOID__STRING, - G_TYPE_NONE, 1, - G_TYPE_STRING); - query_signals[QUERY_DONE] = - g_signal_new ("query_done", - G_TYPE_FROM_CLASS (klass), - G_SIGNAL_RUN_FIRST, - G_STRUCT_OFFSET (CalQueryClass, query_done), - NULL, NULL, - cal_util_marshal_VOID__ENUM_STRING, - G_TYPE_NONE, 2, - CAL_QUERY_DONE_STATUS_ENUM_TYPE, - G_TYPE_STRING); - query_signals[EVAL_ERROR] = - g_signal_new ("eval_error", - G_TYPE_FROM_CLASS (klass), - G_SIGNAL_RUN_FIRST, - G_STRUCT_OFFSET (CalQueryClass, eval_error), - NULL, NULL, - g_cclosure_marshal_VOID__STRING, - G_TYPE_NONE, 1, - G_TYPE_STRING); +static void +query_done_cb (QueryListener *listener, ECalendarStatus status, gpointer data) +{ + CalQuery *query; - klass->obj_updated = NULL; - klass->obj_removed = NULL; - klass->query_done = NULL; - klass->eval_error = NULL; + query = CAL_QUERY (data); - object_class->finalize = cal_query_finalize; + g_signal_emit (G_OBJECT (query), signals[QUERY_DONE], 0, status); } /* Object initialization function for the calendar query */ @@ -180,191 +126,193 @@ cal_query_init (CalQuery *query, CalQueryClass *klass) priv = g_new0 (CalQueryPrivate, 1); query->priv = priv; - priv->ql = NULL; - priv->corba_query = CORBA_OBJECT_NIL; + priv->listener = NULL; + priv->query = CORBA_OBJECT_NIL; } -/* Finalize handler for the calendar query */ static void -cal_query_finalize (GObject *object) +cal_query_set_property (GObject *object, guint property_id, const GValue *value, GParamSpec *pspec) { CalQuery *query; CalQueryPrivate *priv; - - g_return_if_fail (object != NULL); - g_return_if_fail (IS_CAL_QUERY (object)); - + query = CAL_QUERY (object); priv = query->priv; - - /* The server keeps a copy of the query listener, so we must unref it */ - query_listener_stop_notification (priv->ql); - bonobo_object_unref (BONOBO_OBJECT (priv->ql)); - priv->ql = NULL; - - if (priv->corba_query != CORBA_OBJECT_NIL) { - CORBA_Environment ev; - - CORBA_exception_init (&ev); - bonobo_object_release_unref (priv->corba_query, &ev); - - if (BONOBO_EX (&ev)) - g_message ("cal_query_destroy(): Could not release/unref the query"); - - CORBA_exception_free (&ev); - priv->corba_query = CORBA_OBJECT_NIL; + + switch (property_id) { + case PROP_QUERY: + priv->query = bonobo_object_dup_ref (g_value_get_pointer (value), NULL); + break; + case PROP_LISTENER: + priv->listener = bonobo_object_ref (g_value_get_pointer (value)); + + g_signal_connect (G_OBJECT (priv->listener), "objects_added", + G_CALLBACK (objects_added_cb), query); + g_signal_connect (G_OBJECT (priv->listener), "objects_modified", + G_CALLBACK (objects_modified_cb), query); + g_signal_connect (G_OBJECT (priv->listener), "objects_removed", + G_CALLBACK (objects_removed_cb), query); + g_signal_connect (G_OBJECT (priv->listener), "query_progress", + G_CALLBACK (query_progress_cb), query); + g_signal_connect (G_OBJECT (priv->listener), "query_done", + G_CALLBACK (query_done_cb), query); + break; + case PROP_CLIENT: + priv->client = CAL_CLIENT (g_value_dup_object (value)); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); + break; } - - g_free (priv); - query->priv = NULL; - - if (G_OBJECT_CLASS (parent_class)->finalize) - (* G_OBJECT_CLASS (parent_class)->finalize) (object); } - - -/* Callback used when an object is updated in the query */ static void -obj_updated_cb (QueryListener *ql, - const GNOME_Evolution_Calendar_CalObjUIDSeq *uids, - CORBA_boolean query_in_progress, - CORBA_long n_scanned, - CORBA_long total, - gpointer data) +cal_query_get_property (GObject *object, guint property_id, GValue *value, GParamSpec *pspec) { CalQuery *query; - int n; - - query = CAL_QUERY (data); + CalQueryPrivate *priv; + + query = CAL_QUERY (object); + priv = query->priv; - for (n = 0; n < uids->_length; n++) { - g_signal_emit (G_OBJECT (query), query_signals[OBJ_UPDATED], 0, - uids->_buffer[n], query_in_progress, - (int) n_scanned, (int) total); + switch (property_id) { + case PROP_QUERY: + g_value_set_pointer (value, priv->query); + break; + case PROP_LISTENER: + g_value_set_pointer (value, priv->listener); + break; + case PROP_CLIENT: + g_value_set_object (value, priv->client); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); + break; } } -/* Callback used when an object is removed from the query */ -static void -obj_removed_cb (QueryListener *ql, - const CORBA_char *uid, - gpointer data) -{ - CalQuery *query; - - query = CAL_QUERY (data); - - g_signal_emit (G_OBJECT (query), query_signals[OBJ_REMOVED], - 0, uid); -} -/* Callback used when the query terminates */ +/* Finalize handler for the calendar query */ static void -query_done_cb (QueryListener *ql, - GNOME_Evolution_Calendar_QueryListener_QueryDoneStatus corba_status, - const CORBA_char *error_str, - gpointer data) +cal_query_finalize (GObject *object) { CalQuery *query; - CalQueryDoneStatus status; + CalQueryPrivate *priv; - query = CAL_QUERY (data); + g_return_if_fail (object != NULL); + g_return_if_fail (IS_CAL_QUERY (object)); - switch (corba_status) { - case GNOME_Evolution_Calendar_QueryListener_SUCCESS: - status = CAL_QUERY_DONE_SUCCESS; - break; + query = CAL_QUERY (object); + priv = query->priv; - case GNOME_Evolution_Calendar_QueryListener_PARSE_ERROR: - status = CAL_QUERY_DONE_PARSE_ERROR; - break; + /* The server keeps a copy of the query listener, so we must unref it */ + g_signal_handlers_disconnect_matched (priv->listener, G_SIGNAL_MATCH_DATA, 0, 0, NULL, NULL, query); + bonobo_object_unref (BONOBO_OBJECT (priv->listener)); - default: - g_assert_not_reached (); - return; - } + if (priv->query != CORBA_OBJECT_NIL) + bonobo_object_release_unref (priv->query, NULL); - g_signal_emit (G_OBJECT (query), query_signals[QUERY_DONE], 0, - status, error_str); + g_free (priv); + + if (G_OBJECT_CLASS (parent_class)->finalize) + (* G_OBJECT_CLASS (parent_class)->finalize) (object); } -/* Callback used when an error occurs when evaluating the query */ +/* Class initialization function for the calendar query */ static void -eval_error_cb (QueryListener *ql, - const CORBA_char *error_str, - gpointer data) +cal_query_class_init (CalQueryClass *klass) { - CalQuery *query; + GObjectClass *object_class; + GParamSpec *param; + + object_class = (GObjectClass *) klass; - query = CAL_QUERY (data); + parent_class = g_type_class_peek_parent (klass); + + object_class->set_property = cal_query_set_property; + object_class->get_property = cal_query_get_property; + object_class->finalize = cal_query_finalize; - g_signal_emit (G_OBJECT (query), query_signals[EVAL_ERROR], 0, - error_str); + param = g_param_spec_pointer ("query", NULL, NULL, + G_PARAM_READABLE | G_PARAM_WRITABLE | G_PARAM_CONSTRUCT_ONLY); + g_object_class_install_property (object_class, PROP_QUERY, param); + param = g_param_spec_pointer ("listener", NULL, NULL, + G_PARAM_READABLE | G_PARAM_WRITABLE | G_PARAM_CONSTRUCT_ONLY); + g_object_class_install_property (object_class, PROP_LISTENER, param); + param = g_param_spec_object ("client", NULL, NULL, CAL_CLIENT_TYPE, + G_PARAM_READABLE | G_PARAM_WRITABLE | G_PARAM_CONSTRUCT_ONLY); + g_object_class_install_property (object_class, PROP_CLIENT, param); + + signals[OBJECTS_ADDED] = + g_signal_new ("objects_added", + G_TYPE_FROM_CLASS (klass), + G_SIGNAL_RUN_FIRST, + G_STRUCT_OFFSET (CalQueryClass, objects_added), + NULL, NULL, + cal_marshal_VOID__POINTER, + G_TYPE_NONE, 1, G_TYPE_POINTER); + signals[OBJECTS_MODIFIED] = + g_signal_new ("objects_modified", + G_TYPE_FROM_CLASS (klass), + G_SIGNAL_RUN_FIRST, + G_STRUCT_OFFSET (CalQueryClass, objects_modified), + NULL, NULL, + cal_marshal_VOID__POINTER, + G_TYPE_NONE, 1, G_TYPE_POINTER); + signals[OBJECTS_REMOVED] = + g_signal_new ("objects_removed", + G_TYPE_FROM_CLASS (klass), + G_SIGNAL_RUN_FIRST, + G_STRUCT_OFFSET (CalQueryClass, objects_removed), + NULL, NULL, + cal_marshal_VOID__POINTER, + G_TYPE_NONE, 1, G_TYPE_POINTER); + signals[QUERY_PROGRESS] = + g_signal_new ("query_progress", + G_TYPE_FROM_CLASS (klass), + G_SIGNAL_RUN_FIRST, + G_STRUCT_OFFSET (CalQueryClass, query_progress), + NULL, NULL, + cal_marshal_VOID__POINTER, + G_TYPE_NONE, 2, G_TYPE_STRING, G_TYPE_INT); + signals[QUERY_DONE] = + g_signal_new ("query_done", + G_TYPE_FROM_CLASS (klass), + G_SIGNAL_RUN_FIRST, + G_STRUCT_OFFSET (CalQueryClass, query_done), + NULL, NULL, + cal_marshal_VOID__INT, + G_TYPE_NONE, 1, G_TYPE_INT); } /** - * cal_query_construct: - * @query: A calendar query. - * @cal: Handle to an open calendar. - * @sexp: S-expression that defines the query. + * cal_query_get_type: * - * Constructs a query object by issuing the query creation request to the - * calendar server. + * Registers the #CalQuery class if necessary, and returns the type ID assigned + * to it. * - * Return value: The same value as @query on success, or NULL if the request - * failed. + * Return value: The type ID of the #CalQuery class. **/ -CalQuery * -cal_query_construct (CalQuery *query, - GNOME_Evolution_Calendar_Cal cal, - const char *sexp) +GType +cal_query_get_type (void) { - CalQueryPrivate *priv; - GNOME_Evolution_Calendar_QueryListener corba_ql; - CORBA_Environment ev; - - g_return_val_if_fail (query != NULL, NULL); - g_return_val_if_fail (IS_CAL_QUERY (query), NULL); - g_return_val_if_fail (sexp != NULL, NULL); - - priv = query->priv; - - priv->ql = query_listener_new (obj_updated_cb, - obj_removed_cb, - query_done_cb, - eval_error_cb, - query); - if (!priv->ql) { - g_message ("cal_query_construct(): Could not create the query listener"); - return NULL; - } + static GType cal_query_type = 0; - corba_ql = BONOBO_OBJREF (priv->ql); - - CORBA_exception_init (&ev); - priv->corba_query = GNOME_Evolution_Calendar_Cal_getQuery (cal, sexp, corba_ql, &ev); - - if (BONOBO_USER_EX (&ev, ex_GNOME_Evolution_Calendar_Cal_CouldNotCreate)) { - g_message ("cal_query_construct(): The server could not create the query"); - goto error; - } else if (BONOBO_EX (&ev)) { - g_message ("cal_query_construct(): Could not issue the getQuery() request"); - goto error; + if (!cal_query_type) { + static GTypeInfo info = { + sizeof (CalQueryClass), + (GBaseInitFunc) NULL, + (GBaseFinalizeFunc) NULL, + (GClassInitFunc) cal_query_class_init, + NULL, NULL, + sizeof (CalQuery), + 0, + (GInstanceInitFunc) cal_query_init + }; + cal_query_type = g_type_register_static (G_TYPE_OBJECT, "CalQuery", &info, 0); } - CORBA_exception_free (&ev); - - return query; - - error: - - CORBA_exception_free (&ev); - - bonobo_object_unref (BONOBO_OBJECT (priv->ql)); - priv->ql = NULL; - priv->corba_query = CORBA_OBJECT_NIL; - return NULL; + return cal_query_type; } /** @@ -379,20 +327,12 @@ cal_query_construct (CalQuery *query, * Return value: A newly-created query object, or NULL if the request failed. **/ CalQuery * -cal_query_new (CalClient *client, - GNOME_Evolution_Calendar_Cal cal, - const char *sexp) +cal_query_new (GNOME_Evolution_Calendar_Query corba_query, QueryListener *listener, CalClient *client) { CalQuery *query; - query = g_object_new (CAL_QUERY_TYPE, NULL); - - if (!cal_query_construct (query, cal, sexp)) { - g_object_unref (G_OBJECT (query)); - return NULL; - } - - query->priv->client = client; + query = g_object_new (CAL_QUERY_TYPE, "query", corba_query, "listener", + listener, "client", client, NULL); return query; } @@ -412,3 +352,23 @@ cal_query_get_client (CalQuery *query) return query->priv->client; } + +void +cal_query_start (CalQuery *query) +{ + CalQueryPrivate *priv; + CORBA_Environment ev; + + g_return_if_fail (query != NULL); + g_return_if_fail (IS_CAL_QUERY (query)); + + priv = query->priv; + + CORBA_exception_init (&ev); + + GNOME_Evolution_Calendar_Query_start (priv->query, &ev); + if (BONOBO_EX (&ev)) + g_warning (G_STRLOC ": Unable to start query"); + + CORBA_exception_free (&ev); +} diff --git a/calendar/cal-client/cal-query.h b/calendar/cal-client/cal-query.h index 77429035fa..05390dd12a 100644 --- a/calendar/cal-client/cal-query.h +++ b/calendar/cal-client/cal-query.h @@ -22,7 +22,8 @@ #define CAL_QUERY_H #include - +#include "cal-client-types.h" +#include "query-listener.h" #include "evolution-calendar.h" G_BEGIN_DECLS @@ -37,14 +38,6 @@ typedef struct _CalClient CalClient; #define IS_CAL_QUERY(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), CAL_QUERY_TYPE)) #define IS_CAL_QUERY_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), CAL_QUERY_TYPE)) -#define CAL_QUERY_DONE_STATUS_ENUM_TYPE (cal_query_done_status_enum_get_type ()) - -/* Status values when a query terminates */ -typedef enum { - CAL_QUERY_DONE_SUCCESS, - CAL_QUERY_DONE_PARSE_ERROR -} CalQueryDoneStatus; - typedef struct _CalQueryPrivate CalQueryPrivate; typedef struct { @@ -58,30 +51,18 @@ typedef struct { GObjectClass parent_class; /* Notification signals */ - - void (* obj_updated) (CalQuery *query, const char *uid, - gboolean query_in_progress, int n_scanned, int total); - void (* obj_removed) (CalQuery *query, const char *uid); - - void (* query_done) (CalQuery *query, CalQueryDoneStatus status, const char *error_str); - - void (* eval_error) (CalQuery *query, const char *error_str); + void (* objects_added) (CalQuery *query, GList *objects); + void (* objects_modified) (CalQuery *query, GList *objects); + void (* objects_removed) (CalQuery *query, GList *uids); + void (* query_progress) (CalQuery *query, char *message, int percent); + void (* query_done) (CalQuery *query, ECalendarStatus status); } CalQueryClass; GType cal_query_get_type (void); -GType cal_query_done_status_enum_get_type (void); - -CalQuery *cal_query_construct (CalQuery *query, - GNOME_Evolution_Calendar_Cal cal, - const char *sexp); - -CalQuery *cal_query_new (CalClient *client, - GNOME_Evolution_Calendar_Cal cal, - const char *sexp); +CalQuery *cal_query_new (GNOME_Evolution_Calendar_Query corba_query, QueryListener *listener, CalClient *client); CalClient *cal_query_get_client (CalQuery *query); - - +void cal_query_start (CalQuery *query); G_END_DECLS diff --git a/calendar/cal-client/client-test.c b/calendar/cal-client/client-test.c index cb6eed17b2..48763be50a 100644 --- a/calendar/cal-client/client-test.c +++ b/calendar/cal-client/client-test.c @@ -45,24 +45,37 @@ cl_printf (CalClient *client, const char *format, ...) va_end (args); } -/* Dumps some interesting data from a component */ static void -dump_component (CalComponent *comp) +objects_added_cb (GObject *object, GList *objects, gpointer data) { - const char *uid; - CalComponentText summary; + GList *l; + + for (l = objects; l; l = l->next) + cl_printf (data, "Object added %s\n", icalcomponent_get_uid (l->data)); +} - cal_component_get_uid (comp, &uid); +static void +objects_modified_cb (GObject *object, GList *objects, gpointer data) +{ + GList *l; + + for (l = objects; l; l = l->next) + cl_printf (data, "Object modified %s\n", icalcomponent_get_uid (l->data)); +} - printf ("UID %s\n", uid); +static void +objects_removed_cb (GObject *object, GList *objects, gpointer data) +{ + GList *l; + + for (l = objects; l; l = l->next) + cl_printf (data, "Object removed %s\n", icalcomponent_get_uid (l->data)); +} - cal_component_get_summary (comp, &summary); - if (summary.value) - printf ("\tSummary: `%s', altrep `%s'\n", - summary.value, - summary.altrep ? summary.altrep : "NONE"); - else - printf ("\tNo summary\n"); +static void +query_done_cb (GObject *object, ECalendarStatus status, gpointer data) +{ + cl_printf (data, "Query done\n"); } /* Lists the UIDs of objects in a calendar, called as an idle handler */ @@ -70,47 +83,38 @@ static gboolean list_uids (gpointer data) { CalClient *client; - GList *uids; + GList *objects = NULL; GList *l; - + client = CAL_CLIENT (data); - uids = cal_client_get_uids (client, CALOBJ_TYPE_ANY); - - cl_printf (client, "UIDs: "); + g_message ("Blah"); + + if (!cal_client_get_object_list (client, "(contains? \"any\" \"Test4\")", &objects, NULL)) + return FALSE; + + cl_printf (client, "UIDS: "); - if (!uids) + if (!objects) printf ("none\n"); else { - for (l = uids; l; l = l->next) { - char *uid; + for (l = objects; l; l = l->next) { + const char *uid; - uid = l->data; + uid = icalcomponent_get_uid (l->data); printf ("`%s' ", uid); } printf ("\n"); - for (l = uids; l; l = l->next) { - char *uid; - CalComponent *comp; - CalClientGetStatus status; - - uid = l->data; - status = cal_client_get_object (client, uid, &comp); - - if (status == CAL_CLIENT_GET_SUCCESS) { - printf ("------------------------------\n"); - dump_component (comp); - printf ("------------------------------\n"); - g_object_unref (comp); - } else { - printf ("FAILED: %d\n", status); - } + for (l = objects; l; l = l->next) { + printf ("------------------------------\n"); + printf ("%s", icalcomponent_as_ical_string (l->data)); + printf ("------------------------------\n"); } } - cal_obj_uid_list_free (uids); + cal_client_free_object_list (objects); g_object_unref (client); @@ -121,6 +125,8 @@ list_uids (gpointer data) static void cal_opened_cb (CalClient *client, CalClientOpenStatus status, gpointer data) { + CalQuery *query; + cl_printf (client, "Load/create %s\n", ((status == CAL_CLIENT_OPEN_SUCCESS) ? "success" : (status == CAL_CLIENT_OPEN_ERROR) ? "error" : @@ -129,40 +135,29 @@ cal_opened_cb (CalClient *client, CalClientOpenStatus status, gpointer data) "unknown status value")); if (status == CAL_CLIENT_OPEN_SUCCESS) { - GList *comp_list; - - /* get free/busy information */ - comp_list = cal_client_get_free_busy (client, NULL, 0, time (NULL)); - if (comp_list) { - GList *l; - - for (l = comp_list; l; l = l->next) { - char *comp_str; - - comp_str = cal_component_get_as_string (CAL_COMPONENT (l->data)); - g_object_unref (l->data); - cl_printf (client, "Free/Busy -> %s\n", comp_str); - g_free (comp_str); - } - g_list_free (comp_list); - } - + if (!cal_client_get_query (client, "(contains? \"any\" \"Test4\")", &query, NULL)) + g_warning (G_STRLOC ": Unable to obtain query"); + + g_signal_connect (G_OBJECT (query), "objects_added", + G_CALLBACK (objects_added_cb), client); + g_signal_connect (G_OBJECT (query), "objects_modified", + G_CALLBACK (objects_modified_cb), client); + g_signal_connect (G_OBJECT (query), "objects_removed", + G_CALLBACK (objects_removed_cb), client); + g_signal_connect (G_OBJECT (query), "query_done", + G_CALLBACK (query_done_cb), client); + + cal_query_start (query); + g_idle_add (list_uids, client); } else g_object_unref (client); } -/* Callback used when an object is updated */ -static void -obj_updated_cb (CalClient *client, const char *uid, gpointer data) -{ - cl_printf (client, "Object updated: %s\n", uid); -} - /* Callback used when a client is destroyed */ static void -client_destroy_cb (GObject *object, gpointer data) +client_destroy_cb (gpointer data, GObject *object) { if (CAL_CLIENT (object) == client1) client1 = NULL; @@ -177,33 +172,24 @@ client_destroy_cb (GObject *object, gpointer data) /* Creates a calendar client and tries to load the specified URI into it */ static void -create_client (CalClient **client, const char *uri, gboolean only_if_exists) +create_client (CalClient **client, const char *uri, CalObjType type, gboolean only_if_exists) { - gboolean result; - - *client = cal_client_new (); + *client = cal_client_new (uri, type); if (!*client) { - g_message ("create_client(): could not create the client"); + g_message (G_STRLOC ": could not create the client"); exit (1); } - g_signal_connect (*client, "destroy", - G_CALLBACK (client_destroy_cb), - NULL); + g_object_weak_ref (G_OBJECT (*client), client_destroy_cb, NULL); g_signal_connect (*client, "cal_opened", G_CALLBACK (cal_opened_cb), NULL); - g_signal_connect (*client, "obj_updated", - G_CALLBACK (obj_updated_cb), - NULL); printf ("Calendar loading `%s'...\n", uri); - result = cal_client_open_calendar (*client, uri, only_if_exists); - - if (!result) { - g_message ("create_client(): failure when issuing calendar open request `%s'", + if (!cal_client_open (*client, only_if_exists, NULL)) { + g_message (G_STRLOC ": failure when issuing calendar open request `%s'", uri); exit (1); } @@ -212,8 +198,6 @@ create_client (CalClient **client, const char *uri, gboolean only_if_exists) int main (int argc, char **argv) { - char *dir; - bindtextdomain (GETTEXT_PACKAGE, EVOLUTION_LOCALEDIR); textdomain (GETTEXT_PACKAGE); @@ -225,10 +209,9 @@ main (int argc, char **argv) exit (1); } - dir = g_strdup_printf ("%s/evolution/local/Calendar/calendar.ics", g_get_home_dir ()); - create_client (&client1, dir, FALSE); - g_free (dir); - create_client (&client2, "/cvs/evolution/calendar/cal-client/test.ics", TRUE); + create_client (&client1, "file:///home/gnome24-evolution-new-calendar/evolution/local/Calendar", + CALOBJ_TYPE_EVENT, FALSE); +// create_client (&client2, "file:///tmp/tasks", TRUE); bonobo_main (); return 0; diff --git a/calendar/cal-client/query-listener.c b/calendar/cal-client/query-listener.c index 6bd7bfc6f7..4c8cbb4fe5 100644 --- a/calendar/cal-client/query-listener.c +++ b/calendar/cal-client/query-listener.c @@ -22,6 +22,7 @@ #include #endif +#include "cal-marshal.h" #include "query-listener.h" @@ -29,166 +30,164 @@ /* Private part of the QueryListener structure */ struct _QueryListenerPrivate { - /* Callbacks for notification and their closure data */ - QueryListenerObjUpdatedFn obj_updated_fn; - QueryListenerObjRemovedFn obj_removed_fn; - QueryListenerQueryDoneFn query_done_fn; - QueryListenerEvalErrorFn eval_error_fn; - gpointer fn_data; - - /* Whether notification is desired */ - gboolean notify : 1; + int dummy; }; - - -static void query_listener_class_init (QueryListenerClass *class); -static void query_listener_init (QueryListener *ql, QueryListenerClass *class); -static void query_listener_finalize (GObject *object); - -static void impl_notifyObjUpdated (PortableServer_Servant servant, - const GNOME_Evolution_Calendar_CalObjUIDSeq *uids, - CORBA_boolean query_in_progress, - CORBA_long n_scanned, - CORBA_long total, - CORBA_Environment *ev); - -static void impl_notifyObjRemoved (PortableServer_Servant servant, - const CORBA_char *uid, - CORBA_Environment *ev); - -static void impl_notifyQueryDone (PortableServer_Servant servant, - GNOME_Evolution_Calendar_QueryListener_QueryDoneStatus corba_status, - const CORBA_char *error_str, - CORBA_Environment *ev); +/* Signal IDs */ +enum { + OBJECTS_ADDED, + OBJECTS_MODIFIED, + OBJECTS_REMOVED, + QUERY_PROGRESS, + QUERY_DONE, + LAST_SIGNAL +}; -static void impl_notifyEvalError (PortableServer_Servant servant, - const CORBA_char *error_str, - CORBA_Environment *ev); +static guint signals[LAST_SIGNAL] = { 0 }; static BonoboObjectClass *parent_class; - - -BONOBO_TYPE_FUNC_FULL (QueryListener, - GNOME_Evolution_Calendar_QueryListener, - BONOBO_TYPE_OBJECT, - query_listener); - -/* Class initialization function for the live search query listener */ -static void -query_listener_class_init (QueryListenerClass *class) +/* CORBA method implementations */ +/* FIXME This is duplicated from cal-listener.c */ +static ECalendarStatus +convert_status (const GNOME_Evolution_Calendar_CallStatus status) { - GObjectClass *object_class; + switch (status) { + case GNOME_Evolution_Calendar_Success: + return E_CALENDAR_STATUS_OK; + case GNOME_Evolution_Calendar_RepositoryOffline: + return E_CALENDAR_STATUS_REPOSITORY_OFFLINE; + case GNOME_Evolution_Calendar_PermissionDenied: + return E_CALENDAR_STATUS_PERMISSION_DENIED; + case GNOME_Evolution_Calendar_ObjectNotFound: + return E_CALENDAR_STATUS_OBJECT_NOT_FOUND; + case GNOME_Evolution_Calendar_CardIdAlreadyExists: + return E_CALENDAR_STATUS_CARD_ID_ALREADY_EXISTS; + case GNOME_Evolution_Calendar_AuthenticationFailed: + return E_CALENDAR_STATUS_AUTHENTICATION_FAILED; + case GNOME_Evolution_Calendar_AuthenticationRequired: + return E_CALENDAR_STATUS_AUTHENTICATION_REQUIRED; + case GNOME_Evolution_Calendar_OtherError: + default: + return E_CALENDAR_STATUS_OTHER_ERROR; + } +} - object_class = (GObjectClass *) class; +/* FIXME This is duplicated from cal-listener.c */ +static GList * +build_object_list (const GNOME_Evolution_Calendar_stringlist *seq) +{ + GList *list; + int i; + + list = NULL; + for (i = 0; i < seq->_length; i++) { + icalcomponent *comp; + + comp = icalcomponent_new_from_string (seq->_buffer[i]); + if (!comp) + continue; + + list = g_list_prepend (list, comp); + } + + return list; +} - parent_class = g_type_class_peek_parent (class); +static GList * +build_uid_list (const GNOME_Evolution_Calendar_CalObjUIDSeq *seq) +{ + GList *list; + int i; - object_class->finalize = query_listener_finalize; + list = NULL; + for (i = 0; i < seq->_length; i++) + list = g_list_prepend (list, g_strdup (seq->_buffer[i])); - class->epv.notifyObjUpdated = impl_notifyObjUpdated; - class->epv.notifyObjRemoved = impl_notifyObjRemoved; - class->epv.notifyQueryDone = impl_notifyQueryDone; - class->epv.notifyEvalError = impl_notifyEvalError; + return list; } -/* Object initialization function for the live search query listener */ static void -query_listener_init (QueryListener *ql, QueryListenerClass *class) +impl_notifyObjectsAdded (PortableServer_Servant servant, + const GNOME_Evolution_Calendar_stringlist *objects, + CORBA_Environment *ev) { + QueryListener *ql; QueryListenerPrivate *priv; + GList *object_list, *l; + + ql = QUERY_LISTENER (bonobo_object_from_servant (servant)); + priv = ql->priv; - priv = g_new0 (QueryListenerPrivate, 1); - ql->priv = priv; - - priv->obj_updated_fn = NULL; - priv->obj_removed_fn = NULL; - priv->query_done_fn = NULL; - priv->eval_error_fn = NULL; - priv->fn_data = NULL; + object_list = build_object_list (objects); + + g_signal_emit (G_OBJECT (ql), signals[OBJECTS_ADDED], 0, object_list); - priv->notify = TRUE; + for (l = object_list; l; l = l->next) + icalcomponent_free (l->data); + g_list_free (object_list); } -/* Finalize handler for the live search query listener */ static void -query_listener_finalize (GObject *object) +impl_notifyObjectsModified (PortableServer_Servant servant, + const GNOME_Evolution_Calendar_stringlist *objects, + CORBA_Environment *ev) { QueryListener *ql; QueryListenerPrivate *priv; - - g_return_if_fail (object != NULL); - g_return_if_fail (IS_QUERY_LISTENER (object)); - - ql = QUERY_LISTENER (object); + GList *object_list, *l; + + ql = QUERY_LISTENER (bonobo_object_from_servant (servant)); priv = ql->priv; - priv->obj_updated_fn = NULL; - priv->obj_removed_fn = NULL; - priv->query_done_fn = NULL; - priv->eval_error_fn = NULL; - priv->fn_data = NULL; - - priv->notify = FALSE; + object_list = build_object_list (objects); + + g_signal_emit (G_OBJECT (ql), signals[OBJECTS_MODIFIED], 0, object_list); - g_free (priv); - ql->priv = NULL; - - if (G_OBJECT_CLASS (parent_class)->finalize) - (* G_OBJECT_CLASS (parent_class)->finalize) (object); + for (l = object_list; l; l = l->next) + icalcomponent_free (l->data); + g_list_free (object_list); } - - -/* CORBA method implementations */ - -/* ::notifyObjUpdated() method */ static void -impl_notifyObjUpdated (PortableServer_Servant servant, - const GNOME_Evolution_Calendar_CalObjUIDSeq *uids, - CORBA_boolean query_in_progress, - CORBA_long n_scanned, - CORBA_long total, - CORBA_Environment *ev) +impl_notifyObjectsRemoved (PortableServer_Servant servant, + const GNOME_Evolution_Calendar_CalObjUIDSeq *uids, + CORBA_Environment *ev) { QueryListener *ql; QueryListenerPrivate *priv; - + GList *uid_list, *l; + ql = QUERY_LISTENER (bonobo_object_from_servant (servant)); priv = ql->priv; - if (!priv->notify) - return; + uid_list = build_uid_list (uids); + + g_signal_emit (G_OBJECT (ql), signals[OBJECTS_REMOVED], 0, uid_list); - g_assert (priv->obj_updated_fn != NULL); - (* priv->obj_updated_fn) (ql, uids, query_in_progress, n_scanned, total, priv->fn_data); + for (l = uid_list; l; l = l->next) + g_free (l->data); + g_list_free (uid_list); } -/* ::notifyObjRemoved() method */ static void -impl_notifyObjRemoved (PortableServer_Servant servant, - const CORBA_char *uid, - CORBA_Environment *ev) +impl_notifyQueryProgress (PortableServer_Servant servant, + const CORBA_char *message, + const CORBA_short percent, + CORBA_Environment *ev) { QueryListener *ql; QueryListenerPrivate *priv; ql = QUERY_LISTENER (bonobo_object_from_servant (servant)); priv = ql->priv; - - if (!priv->notify) - return; - - g_assert (priv->obj_removed_fn != NULL); - (* priv->obj_removed_fn) (ql, uid, priv->fn_data); + + g_signal_emit (G_OBJECT (ql), signals[QUERY_PROGRESS], 0, message, percent); } -/* ::notifyQueryDone() method */ static void impl_notifyQueryDone (PortableServer_Servant servant, - GNOME_Evolution_Calendar_QueryListener_QueryDoneStatus corba_status, - const CORBA_char *error_str, + const GNOME_Evolution_Calendar_CallStatus status, CORBA_Environment *ev) { QueryListener *ql; @@ -196,126 +195,110 @@ impl_notifyQueryDone (PortableServer_Servant servant, ql = QUERY_LISTENER (bonobo_object_from_servant (servant)); priv = ql->priv; + + g_signal_emit (G_OBJECT (ql), signals[QUERY_DONE], 0, convert_status (status)); +} - if (!priv->notify) - return; +/* Object initialization function for the live search query listener */ +static void +query_listener_init (QueryListener *ql, QueryListenerClass *class) +{ + QueryListenerPrivate *priv; - g_assert (priv->query_done_fn != NULL); - (* priv->query_done_fn) (ql, corba_status, error_str, priv->fn_data); + priv = g_new0 (QueryListenerPrivate, 1); + ql->priv = priv; } -/* ::notifyEvalError() method */ +/* Finalize handler for the live search query listener */ static void -impl_notifyEvalError (PortableServer_Servant servant, - const CORBA_char *error_str, - CORBA_Environment *ev) +query_listener_finalize (GObject *object) { QueryListener *ql; QueryListenerPrivate *priv; - ql = QUERY_LISTENER (bonobo_object_from_servant (servant)); + g_return_if_fail (object != NULL); + g_return_if_fail (IS_QUERY_LISTENER (object)); + + ql = QUERY_LISTENER (object); priv = ql->priv; - if (!priv->notify) - return; + g_free (priv); - g_assert (priv->eval_error_fn != NULL); - (* priv->eval_error_fn) (ql, error_str, priv->fn_data); + if (G_OBJECT_CLASS (parent_class)->finalize) + (* G_OBJECT_CLASS (parent_class)->finalize) (object); } - - -/** - * query_listener_construct: - * @ql: A query listener. - * @obj_updated_fn: Callback to use when a component is updated in the query. - * @obj_removed_fn: Callback to use when a component is removed from the query. - * @query_done_fn: Callback to use when a query is done. - * @eval_error_fn: Callback to use when an evaluation error happens during a query. - * @fn_data: Closure data to pass to the callbacks. - * - * Constructs a query listener by setting the callbacks it will use for - * notification from the calendar server. - * - * Return value: The same value as @ql. - **/ -QueryListener * -query_listener_construct (QueryListener *ql, - QueryListenerObjUpdatedFn obj_updated_fn, - QueryListenerObjRemovedFn obj_removed_fn, - QueryListenerQueryDoneFn query_done_fn, - QueryListenerEvalErrorFn eval_error_fn, - gpointer fn_data) +/* Class initialization function for the live search query listener */ +static void +query_listener_class_init (QueryListenerClass *klass) { - QueryListenerPrivate *priv; + GObjectClass *object_class; - g_return_val_if_fail (ql != NULL, NULL); - g_return_val_if_fail (IS_QUERY_LISTENER (ql), NULL); - g_return_val_if_fail (obj_updated_fn != NULL, NULL); - g_return_val_if_fail (obj_removed_fn != NULL, NULL); - g_return_val_if_fail (query_done_fn != NULL, NULL); - g_return_val_if_fail (eval_error_fn != NULL, NULL); + object_class = (GObjectClass *) klass; - priv = ql->priv; + parent_class = g_type_class_peek_parent (klass); - priv->obj_updated_fn = obj_updated_fn; - priv->obj_removed_fn = obj_removed_fn; - priv->query_done_fn = query_done_fn; - priv->eval_error_fn = eval_error_fn; - priv->fn_data = fn_data; + object_class->finalize = query_listener_finalize; - return ql; + klass->epv.notifyObjectsAdded = impl_notifyObjectsAdded; + klass->epv.notifyObjectsModified = impl_notifyObjectsModified; + klass->epv.notifyObjectsRemoved = impl_notifyObjectsRemoved; + klass->epv.notifyQueryProgress = impl_notifyQueryProgress; + klass->epv.notifyQueryDone = impl_notifyQueryDone; + + signals[OBJECTS_ADDED] = + g_signal_new ("objects_added", + G_TYPE_FROM_CLASS (klass), + G_SIGNAL_RUN_FIRST, + G_STRUCT_OFFSET (QueryListenerClass, objects_added), + NULL, NULL, + cal_marshal_VOID__POINTER, + G_TYPE_NONE, 1, G_TYPE_POINTER); + signals[OBJECTS_MODIFIED] = + g_signal_new ("objects_modified", + G_TYPE_FROM_CLASS (klass), + G_SIGNAL_RUN_FIRST, + G_STRUCT_OFFSET (QueryListenerClass, objects_modified), + NULL, NULL, + cal_marshal_VOID__POINTER, + G_TYPE_NONE, 1, G_TYPE_POINTER); + signals[OBJECTS_REMOVED] = + g_signal_new ("objects_removed", + G_TYPE_FROM_CLASS (klass), + G_SIGNAL_RUN_FIRST, + G_STRUCT_OFFSET (QueryListenerClass, objects_removed), + NULL, NULL, + cal_marshal_VOID__POINTER, + G_TYPE_NONE, 1, G_TYPE_POINTER); + signals[QUERY_PROGRESS] = + g_signal_new ("query_progress", + G_TYPE_FROM_CLASS (klass), + G_SIGNAL_RUN_FIRST, + G_STRUCT_OFFSET (QueryListenerClass, query_progress), + NULL, NULL, + cal_marshal_VOID__POINTER, + G_TYPE_NONE, 2, G_TYPE_STRING, G_TYPE_INT); + signals[QUERY_DONE] = + g_signal_new ("query_done", + G_TYPE_FROM_CLASS (klass), + G_SIGNAL_RUN_FIRST, + G_STRUCT_OFFSET (QueryListenerClass, query_done), + NULL, NULL, + cal_marshal_VOID__INT, + G_TYPE_NONE, 1, G_TYPE_INT); } -/** - * query_listener_new: - * @obj_updated_fn: Callback to use when a component is updated in the query. - * @obj_removed_fn: Callback to use when a component is removed from the query. - * @query_done_fn: Callback to use when a query is done. - * @eval_error_fn: Callback to use when an evaluation error happens during a query. - * @fn_data: Closure data to pass to the callbacks. - * - * Creates a new query listener object. - * - * Return value: A newly-created query listener object. - **/ +BONOBO_TYPE_FUNC_FULL (QueryListener, + GNOME_Evolution_Calendar_QueryListener, + BONOBO_TYPE_OBJECT, + query_listener); + QueryListener * -query_listener_new (QueryListenerObjUpdatedFn obj_updated_fn, - QueryListenerObjRemovedFn obj_removed_fn, - QueryListenerQueryDoneFn query_done_fn, - QueryListenerEvalErrorFn eval_error_fn, - gpointer fn_data) +query_listener_new (void) { QueryListener *ql; ql = g_object_new (QUERY_LISTENER_TYPE, NULL); - return query_listener_construct (ql, - obj_updated_fn, - obj_removed_fn, - query_done_fn, - eval_error_fn, - fn_data); -} - -/** - * query_listener_stop_notification: - * @ql: A query listener. - * - * Informs a query listener that no further notification is desired. The - * callbacks specified when the listener was created will no longer be invoked - * after this function is called. - **/ -void -query_listener_stop_notification (QueryListener *ql) -{ - QueryListenerPrivate *priv; - - g_return_if_fail (ql != NULL); - g_return_if_fail (IS_QUERY_LISTENER (ql)); - - priv = ql->priv; - g_return_if_fail (priv->notify != FALSE); - - priv->notify = FALSE; + return ql; } diff --git a/calendar/cal-client/query-listener.h b/calendar/cal-client/query-listener.h index eeb42afc7e..6a204bbf77 100644 --- a/calendar/cal-client/query-listener.h +++ b/calendar/cal-client/query-listener.h @@ -22,6 +22,7 @@ #define QUERY_LISTENER_H #include +#include "cal-client-types.h" #include "evolution-calendar.h" G_BEGIN_DECLS @@ -48,47 +49,18 @@ typedef struct { BonoboObjectClass parent_class; POA_GNOME_Evolution_Calendar_QueryListener__epv epv; + + void (*objects_added) (QueryListener *listener, GList *objects); + void (*objects_modified) (QueryListener *listener, GList *objects); + void (*objects_removed) (QueryListener *listener, GList *uids); + void (*query_progress) (QueryListener *listener, const char *message, int percent); + void (*query_done) (QueryListener *listener, ECalendarStatus status); } QueryListenerClass; /* Notification functions */ -typedef void (* QueryListenerObjUpdatedFn) (QueryListener *ql, - const GNOME_Evolution_Calendar_CalObjUIDSeq *uids, - CORBA_boolean query_in_progress, - CORBA_long n_scanned, - CORBA_long total, - gpointer data); - -typedef void (* QueryListenerObjRemovedFn) (QueryListener *ql, - const CORBA_char *uid, - gpointer data); - -typedef void (* QueryListenerQueryDoneFn) ( - QueryListener *ql, - GNOME_Evolution_Calendar_QueryListener_QueryDoneStatus status, - const CORBA_char *error_str, - gpointer data); - -typedef void (* QueryListenerEvalErrorFn) (QueryListener *ql, - const CORBA_char *error_str, - gpointer data); - GType query_listener_get_type (void); - -QueryListener *query_listener_construct (QueryListener *ql, - QueryListenerObjUpdatedFn obj_updated_fn, - QueryListenerObjRemovedFn obj_removed_fn, - QueryListenerQueryDoneFn query_done_fn, - QueryListenerEvalErrorFn eval_error_fn, - gpointer fn_data); - -QueryListener *query_listener_new (QueryListenerObjUpdatedFn obj_updated_fn, - QueryListenerObjRemovedFn obj_removed_fn, - QueryListenerQueryDoneFn query_done_fn, - QueryListenerEvalErrorFn eval_error_fn, - gpointer fn_data); - -void query_listener_stop_notification (QueryListener *ql); +QueryListener *query_listener_new (void); diff --git a/calendar/cal-util/cal-util.c b/calendar/cal-util/cal-util.c index 1e03c86d75..f1c32610c1 100644 --- a/calendar/cal-util/cal-util.c +++ b/calendar/cal-util/cal-util.c @@ -584,29 +584,7 @@ cal_util_priority_from_string (const char *string) char * cal_util_expand_uri (char *uri, gboolean tasks) { - char *file_uri, *file_name; - - if (!strncmp (uri, "file://", 7)) { - file_uri = uri + 7; - if (strlen (file_uri) > 4 - && !strcmp (file_uri + strlen (file_uri) - 4, ".ics")) { - - /* it's a .ics file */ - return g_strdup (uri); - } - - /* we assume it's a dir and glom .ics onto the end. */ - if (tasks) - file_name = g_concat_dir_and_file (file_uri, "tasks.ics"); - else - file_name = g_concat_dir_and_file (file_uri, "calendar.ics"); - file_uri = g_strdup_printf("file://%s", file_name); - g_free(file_name); - } else { - file_uri = g_strdup (uri); - } - - return file_uri; + return g_strdup (uri); } /* callback for icalcomponent_foreach_tzid */ diff --git a/calendar/conduits/calendar/calendar-conduit.c b/calendar/conduits/calendar/calendar-conduit.c index 1893e6b34c..05ddde2c7f 100644 --- a/calendar/conduits/calendar/calendar-conduit.c +++ b/calendar/conduits/calendar/calendar-conduit.c @@ -253,7 +253,7 @@ struct _ECalConduitContext { icaltimezone *timezone; CalComponent *default_comp; - GList *uids; + GList *comps; GList *changed; GHashTable *changed_hash; GList *locals; @@ -276,7 +276,7 @@ e_calendar_context_new (guint32 pilot_id) ctxt->client = NULL; ctxt->timezone = NULL; ctxt->default_comp = NULL; - ctxt->uids = NULL; + ctxt->comps = NULL; ctxt->changed = NULL; ctxt->changed_hash = NULL; ctxt->locals = NULL; @@ -311,8 +311,11 @@ e_calendar_context_destroy (ECalConduitContext *ctxt) g_object_unref (ctxt->client); if (ctxt->default_comp != NULL) g_object_unref (ctxt->default_comp); - if (ctxt->uids != NULL) - cal_obj_uid_list_free (ctxt->uids); + if (ctxt->comps != NULL) { + for (l = ctxt->comps; l; l = l->next) + g_object_unref (l->data); + g_list_free (ctxt->comps); + } if (ctxt->changed != NULL) cal_client_change_list_free (ctxt->changed); @@ -404,16 +407,24 @@ start_calendar_server_cb (CalClient *cal_client, static int start_calendar_server (ECalConduitContext *ctxt) { + char *uri; gboolean success = FALSE; g_return_val_if_fail (ctxt != NULL, -2); - ctxt->client = cal_client_new (); - + /* FIXME Need a mechanism for the user to select uri's */ + /* FIXME Can we use the cal model? */ + uri = g_strdup_printf ("file://%s/local/Calendar/", g_get_home_dir ()); + ctxt->client = cal_client_new (uri, CALOBJ_TYPE_EVENT); + g_free (uri); + + if (!ctxt->client) + return -1; + g_signal_connect (ctxt->client, "cal_opened", G_CALLBACK (start_calendar_server_cb), &success); - if (!cal_client_open_default_calendar (ctxt->client, FALSE)) + if (!cal_client_open (ctxt->client, FALSE, NULL)) return -1; /* run a sub event loop to turn cal-client's async load @@ -433,8 +444,8 @@ get_timezone (CalClient *client, const char *tzid) icaltimezone *timezone = NULL; timezone = icaltimezone_get_builtin_timezone_from_tzid (tzid); - if (timezone == NULL) - cal_client_get_timezone (client, tzid, &timezone); + if (timezone == NULL) + cal_client_get_timezone (client, tzid, &timezone, NULL); return timezone; } @@ -550,7 +561,7 @@ is_all_day (CalClient *client, CalComponentDateTime *dt_start, CalComponentDateT } static gboolean -process_multi_day (ECalConduitContext *ctxt, CalClientChange *ccc, GList **multi_uid, GList **multi_ccc) +process_multi_day (ECalConduitContext *ctxt, CalClientChange *ccc, GList **multi_comp, GList **multi_ccc) { CalComponentDateTime dt_start, dt_end; icaltimezone *tz_start, *tz_end; @@ -562,7 +573,7 @@ process_multi_day (ECalConduitContext *ctxt, CalClientChange *ccc, GList **multi gboolean ret = TRUE; *multi_ccc = NULL; - *multi_uid = NULL; + *multi_comp = NULL; if (ccc->type == CAL_CLIENT_CHANGE_DELETED) return FALSE; @@ -617,13 +628,14 @@ process_multi_day (ECalConduitContext *ctxt, CalClientChange *ccc, GList **multi dt_end.value = &end_value; cal_component_set_dtend (clone, &dt_end); - cal_client_update_object (ctxt->client, clone); + /* FIXME Error handling */ + cal_client_create_object (ctxt->client, cal_component_get_icalcomponent (clone), NULL, NULL); c->comp = clone; c->type = CAL_CLIENT_CHANGE_ADDED; *multi_ccc = g_list_prepend (*multi_ccc, c); - *multi_uid = g_list_prepend (*multi_uid, new_uid); + *multi_comp = g_list_prepend (*multi_comp, g_object_ref (c->comp)); event_start = day_end; day_end = time_day_end_with_zone (event_start, ctxt->timezone); @@ -632,7 +644,8 @@ process_multi_day (ECalConduitContext *ctxt, CalClientChange *ccc, GList **multi dt_end.value = old_end_value; cal_component_get_uid (ccc->comp, &uid); - cal_client_remove_object (ctxt->client, uid); + /* FIXME Error handling */ + cal_client_remove_object (ctxt->client, uid, NULL); ccc->type = CAL_CLIENT_CHANGE_DELETED; cleanup: @@ -1007,13 +1020,11 @@ local_record_from_uid (ECalLocalRecord *local, { CalComponent *comp; icalcomponent *icalcomp; - CalClientGetStatus status; + GError *error = NULL; g_assert(local!=NULL); - status = cal_client_get_object (ctxt->client, uid, &icalcomp); - - if (status == CAL_CLIENT_GET_SUCCESS) { + if (cal_client_get_object (ctxt->client, uid, NULL, &icalcomp, &error)) { comp = cal_component_new (); if (!cal_component_set_icalcomponent (comp, icalcomp)) { g_object_unref (comp); @@ -1023,7 +1034,7 @@ local_record_from_uid (ECalLocalRecord *local, local_record_from_comp (local, comp, ctxt); g_object_unref (comp); - } else if (status == CAL_CLIENT_GET_NOT_FOUND) { + } else if (error->code == E_CALENDAR_STATUS_OBJECT_NOT_FOUND) { comp = cal_component_new (); cal_component_set_new_vtype (comp, CAL_COMPONENT_EVENT); cal_component_set_uid (comp, uid); @@ -1031,7 +1042,9 @@ local_record_from_uid (ECalLocalRecord *local, g_object_unref (comp); } else { INFO ("Object did not exist"); - } + } + + g_clear_error (&error); } static CalComponent * @@ -1282,21 +1295,6 @@ comp_from_remote_record (GnomePilotConduitSyncAbs *conduit, return comp; } -static void -update_comp (GnomePilotConduitSyncAbs *conduit, CalComponent *comp, - ECalConduitContext *ctxt) -{ - CalClientResult success; - - g_return_if_fail (conduit != NULL); - g_return_if_fail (comp != NULL); - - success = cal_client_update_object (ctxt->client, comp); - - if (success != CAL_CLIENT_RESULT_SUCCESS) - WARN (_("Error while communicating with calendar server")); -} - static void check_for_slow_setting (GnomePilotConduit *c, ECalConduitContext *ctxt) { @@ -1360,11 +1358,13 @@ pre_sync (GnomePilotConduit *conduit, LOG (g_message ( " Using timezone: %s", icaltimezone_get_tzid (ctxt->timezone) )); /* Set the default timezone on the backend. */ - if (ctxt->timezone) - cal_client_set_default_timezone (ctxt->client, ctxt->timezone); + if (ctxt->timezone) { + if (!cal_client_set_default_timezone (ctxt->client, ctxt->timezone, NULL)) + return -1; + } /* Get the default component */ - if (cal_client_get_default_object (ctxt->client, CALOBJ_TYPE_EVENT, &icalcomp) != CAL_CLIENT_GET_SUCCESS) + if (!cal_client_get_default_object (ctxt->client, &icalcomp, NULL)) return -1; ctxt->default_comp = cal_component_new (); @@ -1374,27 +1374,36 @@ pre_sync (GnomePilotConduit *conduit, return -1; } + ctxt->default_comp = cal_component_new (); + if (!cal_component_set_icalcomponent (ctxt->default_comp, icalcomp)) { + g_object_unref (ctxt->default_comp); + icalcomponent_free (icalcomp); + return -1; + } + /* Load the uid <--> pilot id mapping */ filename = map_name (ctxt); e_pilot_map_read (filename, &ctxt->map); g_free (filename); /* Get the local database */ - ctxt->uids = cal_client_get_uids (ctxt->client, CALOBJ_TYPE_EVENT); + if (!cal_client_get_object_list_as_comp (ctxt->client, "(#t)", &ctxt->comps, NULL)) + return -1; /* Find the added, modified and deleted items */ change_id = g_strdup_printf ("pilot-sync-evolution-calendar-%d", ctxt->cfg->pilot_id); - ctxt->changed = cal_client_get_changes (ctxt->client, CALOBJ_TYPE_EVENT, change_id); + if (!cal_client_get_changes (ctxt->client, CALOBJ_TYPE_EVENT, change_id, &ctxt->changed, NULL)) + return -1; ctxt->changed_hash = g_hash_table_new (g_str_hash, g_str_equal); g_free (change_id); /* See if we need to split up any events */ for (l = ctxt->changed; l != NULL; l = l->next) { CalClientChange *ccc = l->data; - GList *multi_uid = NULL, *multi_ccc = NULL; + GList *multi_comp = NULL, *multi_ccc = NULL; - if (process_multi_day (ctxt, ccc, &multi_uid, &multi_ccc)) { - ctxt->uids = g_list_concat (ctxt->uids, multi_uid); + if (process_multi_day (ctxt, ccc, &multi_comp, &multi_ccc)) { + ctxt->comps = g_list_concat (ctxt->comps, multi_comp); added = g_list_concat (added, multi_ccc); removed = g_list_prepend (removed, ccc); @@ -1442,7 +1451,7 @@ pre_sync (GnomePilotConduit *conduit, } /* Set the count information */ - num_records = cal_client_get_n_objects (ctxt->client, CALOBJ_TYPE_EVENT); + num_records = g_list_length (ctxt->comps); gnome_pilot_conduit_sync_abs_set_num_local_records(abs_conduit, num_records); gnome_pilot_conduit_sync_abs_set_num_new_local_records (abs_conduit, add_records); gnome_pilot_conduit_sync_abs_set_num_updated_local_records (abs_conduit, mod_records); @@ -1492,8 +1501,8 @@ post_sync (GnomePilotConduit *conduit, * a race condition if anyone changes a record elsewhere during sycnc */ change_id = g_strdup_printf ("pilot-sync-evolution-calendar-%d", ctxt->cfg->pilot_id); - changed = cal_client_get_changes (ctxt->client, CALOBJ_TYPE_EVENT, change_id); - cal_client_change_list_free (changed); + if (cal_client_get_changes (ctxt->client, CALOBJ_TYPE_EVENT, change_id, &changed, NULL)) + cal_client_change_list_free (changed); g_free (change_id); LOG (g_message ( "---------------------------------------------------------\n" )); @@ -1537,7 +1546,7 @@ for_each (GnomePilotConduitSyncAbs *conduit, ECalLocalRecord **local, ECalConduitContext *ctxt) { - static GList *uids, *iterator; + static GList *comps, *iterator; static int count; g_return_val_if_fail (local != NULL, -1); @@ -1545,17 +1554,17 @@ for_each (GnomePilotConduitSyncAbs *conduit, if (*local == NULL) { LOG (g_message ( "beginning for_each" )); - uids = ctxt->uids; + comps = ctxt->comps; count = 0; - if (uids != NULL) { - LOG (g_message ( "iterating over %d records", g_list_length (uids) )); + if (comps != NULL) { + LOG (g_message ( "iterating over %d records", g_list_length (comps))); *local = g_new0 (ECalLocalRecord, 1); - local_record_from_uid (*local, uids->data, ctxt); + local_record_from_comp (*local, comps->data, ctxt); g_list_prepend (ctxt->locals, *local); - iterator = uids; + iterator = comps; } else { LOG (g_message ( "no events" )); (*local) = NULL; @@ -1681,8 +1690,10 @@ add_record (GnomePilotConduitSyncAbs *conduit, /* Give it a new UID otherwise it will be the uid of the default comp */ uid = cal_component_gen_uid (); cal_component_set_uid (comp, uid); + + if (!cal_client_create_object (ctxt->client, cal_component_get_icalcomponent (comp), NULL, NULL)) + return -1; - update_comp (conduit, comp, ctxt); e_pilot_map_insert (ctxt->map, remote->ID, uid, FALSE); g_free (uid); @@ -1709,7 +1720,10 @@ replace_record (GnomePilotConduitSyncAbs *conduit, new_comp = comp_from_remote_record (conduit, remote, local->comp, ctxt->client, ctxt->timezone); g_object_unref (local->comp); local->comp = new_comp; - update_comp (conduit, local->comp, ctxt); + + if (!cal_client_modify_object (ctxt->client, cal_component_get_icalcomponent (new_comp), + CALOBJ_MOD_ALL, NULL)) + return -1; return retval; } @@ -1729,7 +1743,8 @@ delete_record (GnomePilotConduitSyncAbs *conduit, LOG (g_message ( "delete_record: deleting %s\n", uid )); e_pilot_map_remove_by_uid (ctxt->map, uid); - cal_client_remove_object (ctxt->client, uid); + /* FIXME Error handling */ + cal_client_remove_object (ctxt->client, uid, NULL); return 0; } diff --git a/calendar/conduits/todo/todo-conduit.c b/calendar/conduits/todo/todo-conduit.c index 6868368129..35251f4eb6 100644 --- a/calendar/conduits/todo/todo-conduit.c +++ b/calendar/conduits/todo/todo-conduit.c @@ -255,7 +255,7 @@ struct _EToDoConduitContext { icaltimezone *timezone; CalComponent *default_comp; - GList *uids; + GList *comps; GList *changed; GHashTable *changed_hash; GList *locals; @@ -275,7 +275,7 @@ e_todo_context_new (guint32 pilot_id) ctxt->client = NULL; ctxt->timezone = NULL; ctxt->default_comp = NULL; - ctxt->uids = NULL; + ctxt->comps = NULL; ctxt->changed_hash = NULL; ctxt->changed = NULL; ctxt->locals = NULL; @@ -311,8 +311,11 @@ e_todo_context_destroy (EToDoConduitContext *ctxt) if (ctxt->default_comp != NULL) g_object_unref (ctxt->default_comp); - if (ctxt->uids != NULL) - cal_obj_uid_list_free (ctxt->uids); + if (ctxt->comps != NULL) { + for (l = ctxt->comps; l; l = l->next) + g_object_unref (l->data); + g_list_free (ctxt->comps); + } if (ctxt->changed_hash != NULL) { g_hash_table_foreach_remove (ctxt->changed_hash, e_todo_context_foreach_change, NULL); @@ -411,16 +414,24 @@ start_calendar_server_cb (CalClient *cal_client, static int start_calendar_server (EToDoConduitContext *ctxt) { + char *uri; gboolean success = FALSE; g_return_val_if_fail (ctxt != NULL, -2); - ctxt->client = cal_client_new (); + /* FIXME Need a mechanism for the user to select uri's */ + /* FIXME Can we use the cal model? */ + uri = g_strdup_printf ("file://%s/local/Tasks/", g_get_home_dir ()); + ctxt->client = cal_client_new (uri, CALOBJ_TYPE_TODO); + g_free (uri); + + if (!ctxt->client) + return -1; g_signal_connect (ctxt->client, "cal_opened", G_CALLBACK (start_calendar_server_cb), &success); - if (!cal_client_open_default_tasks (ctxt->client, FALSE)) + if (!cal_client_open (ctxt->client, FALSE, NULL)) return -1; /* run a sub event loop to turn cal-client's async load @@ -441,7 +452,7 @@ get_timezone (CalClient *client, const char *tzid) timezone = icaltimezone_get_builtin_timezone_from_tzid (tzid); if (timezone == NULL) - cal_client_get_timezone (client, tzid, &timezone); + cal_client_get_timezone (client, tzid, &timezone, NULL); return timezone; } @@ -676,13 +687,11 @@ local_record_from_uid (EToDoLocalRecord *local, { CalComponent *comp; icalcomponent *icalcomp; - CalClientGetStatus status; + GError *error = NULL; g_assert(local!=NULL); - status = cal_client_get_object (ctxt->client, uid, &icalcomp); - - if (status == CAL_CLIENT_GET_SUCCESS) { + if (cal_client_get_object (ctxt->client, uid, NULL, &icalcomp, &error)) { comp = cal_component_new (); if (!cal_component_set_icalcomponent (comp, icalcomp)) { g_object_unref (comp); @@ -692,7 +701,7 @@ local_record_from_uid (EToDoLocalRecord *local, local_record_from_comp (local, comp, ctxt); g_object_unref (comp); - } else if (status == CAL_CLIENT_GET_NOT_FOUND) { + } else if (error->code == E_CALENDAR_STATUS_OBJECT_NOT_FOUND) { comp = cal_component_new (); cal_component_set_new_vtype (comp, CAL_COMPONENT_TODO); cal_component_set_uid (comp, uid); @@ -702,7 +711,7 @@ local_record_from_uid (EToDoLocalRecord *local, INFO ("Object did not exist"); } - + g_clear_error (&error); } @@ -823,21 +832,6 @@ comp_from_remote_record (GnomePilotConduitSyncAbs *conduit, return comp; } -static void -update_comp (GnomePilotConduitSyncAbs *conduit, CalComponent *comp, - EToDoConduitContext *ctxt) -{ - CalClientResult success; - - g_return_if_fail (conduit != NULL); - g_return_if_fail (comp != NULL); - - success = cal_client_update_object (ctxt->client, comp); - - if (success != CAL_CLIENT_RESULT_SUCCESS) - WARN (_("Error while communicating with calendar server")); -} - static void check_for_slow_setting (GnomePilotConduit *c, EToDoConduitContext *ctxt) { @@ -902,11 +896,13 @@ pre_sync (GnomePilotConduit *conduit, LOG (g_message ( " Using timezone: %s", icaltimezone_get_tzid (ctxt->timezone) )); /* Set the default timezone on the backend. */ - if (ctxt->timezone) - cal_client_set_default_timezone (ctxt->client, ctxt->timezone); + if (ctxt->timezone) { + if (!cal_client_set_default_timezone (ctxt->client, ctxt->timezone, NULL)) + return -1; + } /* Get the default component */ - if (cal_client_get_default_object (ctxt->client, CALOBJ_TYPE_TODO, &icalcomp) != CAL_CLIENT_GET_SUCCESS) + if (!cal_client_get_default_object (ctxt->client, &icalcomp, NULL)) return -1; ctxt->default_comp = cal_component_new (); @@ -916,17 +912,26 @@ pre_sync (GnomePilotConduit *conduit, return -1; } + ctxt->default_comp = cal_component_new (); + if (!cal_component_set_icalcomponent (ctxt->default_comp, icalcomp)) { + g_object_unref (ctxt->default_comp); + icalcomponent_free (icalcomp); + return -1; + } + /* Load the uid <--> pilot id map */ filename = map_name (ctxt); e_pilot_map_read (filename, &ctxt->map); g_free (filename); /* Get the local database */ - ctxt->uids = cal_client_get_uids (ctxt->client, CALOBJ_TYPE_TODO); + if (!cal_client_get_object_list_as_comp (ctxt->client, "(#t)", &ctxt->comps, NULL)) + return -1; /* Count and hash the changes */ change_id = g_strdup_printf ("pilot-sync-evolution-todo-%d", ctxt->cfg->pilot_id); - ctxt->changed = cal_client_get_changes (ctxt->client, CALOBJ_TYPE_TODO, change_id); + if (!cal_client_get_changes (ctxt->client, CALOBJ_TYPE_TODO, change_id, &ctxt->changed, NULL)) + return -1; ctxt->changed_hash = g_hash_table_new (g_str_hash, g_str_equal); g_free (change_id); @@ -956,7 +961,7 @@ pre_sync (GnomePilotConduit *conduit, } /* Set the count information */ - num_records = cal_client_get_n_objects (ctxt->client, CALOBJ_TYPE_TODO); + num_records = g_list_length (ctxt->comps); gnome_pilot_conduit_sync_abs_set_num_local_records(abs_conduit, num_records); gnome_pilot_conduit_sync_abs_set_num_new_local_records (abs_conduit, add_records); gnome_pilot_conduit_sync_abs_set_num_updated_local_records (abs_conduit, mod_records); @@ -1006,8 +1011,8 @@ post_sync (GnomePilotConduit *conduit, * a race condition if anyone changes a record elsewhere during sycnc */ change_id = g_strdup_printf ("pilot-sync-evolution-todo-%d", ctxt->cfg->pilot_id); - changed = cal_client_get_changes (ctxt->client, CALOBJ_TYPE_TODO, change_id); - cal_client_change_list_free (changed); + if (cal_client_get_changes (ctxt->client, CALOBJ_TYPE_TODO, change_id, &changed, NULL)) + cal_client_change_list_free (changed); g_free (change_id); LOG (g_message ( "---------------------------------------------------------\n" )); @@ -1051,7 +1056,7 @@ for_each (GnomePilotConduitSyncAbs *conduit, EToDoLocalRecord **local, EToDoConduitContext *ctxt) { - static GList *uids, *iterator; + static GList *comps, *iterator; static int count; g_return_val_if_fail (local != NULL, -1); @@ -1059,17 +1064,17 @@ for_each (GnomePilotConduitSyncAbs *conduit, if (*local == NULL) { LOG (g_message ( "beginning for_each" )); - uids = ctxt->uids; + comps = ctxt->comps; count = 0; - if (uids != NULL) { - LOG (g_message ( "iterating over %d records", g_list_length (uids) )); + if (comps != NULL) { + LOG (g_message ( "iterating over %d records", g_list_length (comps))); *local = g_new0 (EToDoLocalRecord, 1); - local_record_from_uid (*local, uids->data, ctxt); + local_record_from_comp (*local, comps->data, ctxt); g_list_prepend (ctxt->locals, *local); - iterator = uids; + iterator = comps; } else { LOG (g_message ( "no events" )); (*local) = NULL; @@ -1196,7 +1201,9 @@ add_record (GnomePilotConduitSyncAbs *conduit, uid = cal_component_gen_uid (); cal_component_set_uid (comp, uid); - update_comp (conduit, comp, ctxt); + if (!cal_client_create_object (ctxt->client, cal_component_get_icalcomponent (comp), NULL, NULL)) + return -1; + e_pilot_map_insert (ctxt->map, remote->ID, uid, FALSE); g_object_unref (comp); @@ -1221,7 +1228,10 @@ replace_record (GnomePilotConduitSyncAbs *conduit, new_comp = comp_from_remote_record (conduit, remote, local->comp, ctxt->timezone); g_object_unref (local->comp); local->comp = new_comp; - update_comp (conduit, local->comp, ctxt); + + if (!cal_client_modify_object (ctxt->client, cal_component_get_icalcomponent (new_comp), + CALOBJ_MOD_ALL, NULL)) + return -1; return retval; } @@ -1241,7 +1251,8 @@ delete_record (GnomePilotConduitSyncAbs *conduit, LOG (g_message ( "delete_record: deleting %s\n", uid )); e_pilot_map_remove_by_uid (ctxt->map, uid); - cal_client_remove_object (ctxt->client, uid); + /* FIXME Error handling */ + cal_client_remove_object (ctxt->client, uid, NULL); return 0; } diff --git a/calendar/gui/GNOME_Evolution_Calendar.server.in.in b/calendar/gui/GNOME_Evolution_Calendar.server.in.in index 801cada120..09f424f69a 100644 --- a/calendar/gui/GNOME_Evolution_Calendar.server.in.in +++ b/calendar/gui/GNOME_Evolution_Calendar.server.in.in @@ -1,6 +1,6 @@ - @@ -15,7 +15,7 @@ + location="OAFIID:GNOME_Evolution_Calendar_Factory_2"> @@ -31,26 +31,20 @@ _value="Evolution Calendar scheduling message viewer"/> - + location="OAFIID:GNOME_Evolution_Calendar_Factory_2"> - + - - - - + + location="OAFIID:GNOME_Evolution_Calendar_Factory_2"> @@ -68,7 +62,7 @@ + location="OAFIID:GNOME_Evolution_Calendar_Factory_2"> @@ -86,7 +80,7 @@ + location="OAFIID:GNOME_Evolution_Calendar_Factory_2"> @@ -99,7 +93,7 @@ + location="OAFIID:GNOME_Evolution_Calendar_Factory_2"> diff --git a/calendar/gui/Makefile.am b/calendar/gui/Makefile.am index 3ee9362b65..19edf95953 100644 --- a/calendar/gui/Makefile.am +++ b/calendar/gui/Makefile.am @@ -169,6 +169,8 @@ libevolution_calendar_la_SOURCES = \ itip-utils.c \ itip-utils.h \ main.c \ + migration.c \ + migration.h \ misc.c \ misc.h \ print.c \ @@ -189,7 +191,8 @@ libevolution_calendar_la_LIBADD = \ $(top_builddir)/calendar/gui/dialogs/libcal-dialogs.la \ $(top_builddir)/widgets/e-timezone-dialog/libetimezonedialog.la \ $(top_builddir)/widgets/misc/libemiscwidgets.la \ - $(top_builddir)/a11y/calendar/libevolution-calendar-a11y.la \ + $(top_builddir)/e-util/libeutil.la \ + $(top_builddir)/a11y/calendar/libevolution-calendar-a11y.la \ $(EVOLUTION_CALENDAR_LIBS) libevolution_calendar_la_LDFLAGS = -avoid-version -module diff --git a/calendar/gui/alarm-notify/alarm-notify.c b/calendar/gui/alarm-notify/alarm-notify.c index 133448e7cd..006533c6bf 100644 --- a/calendar/gui/alarm-notify/alarm-notify.c +++ b/calendar/gui/alarm-notify/alarm-notify.c @@ -31,26 +31,6 @@ -/* A loaded client */ -typedef struct { - /* The actual client */ - CalClient *client; - - /* The URI of the client in gnome-vfs's format. This *is* the key that - * is stored in the uri_client_hash hash table below. - */ - EUri *uri; - - /* Number of times clients have requested this URI to be added to the - * alarm notification system. - */ - int refcount; - - /* the ID of the retry timeout function - */ - int timeout_id; -} LoadedClient; - /* Private part of the AlarmNotify structure */ struct _AlarmNotifyPrivate { /* Mapping from EUri's to LoadedClient structures */ @@ -105,23 +85,7 @@ alarm_notify_init (AlarmNotify *an, AlarmNotifyClass *klass) priv = g_new0 (AlarmNotifyPrivate, 1); an->priv = priv; - priv->uri_client_hash = g_hash_table_new (g_str_hash, g_str_equal); -} - -/* Callback used from g_hash-table_forach(), used to destroy a loade client */ -static void -destroy_loaded_client_cb (gpointer key, gpointer value, gpointer data) -{ - LoadedClient *lc; - char *str_uri; - - str_uri = key; - lc = value; - - g_free (str_uri); - g_object_unref (G_OBJECT (lc->client)); - e_uri_free (lc->uri); - g_free (lc); + priv->uri_client_hash = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_object_unref); } /* Finalize handler for the alarm notify system */ @@ -137,13 +101,9 @@ alarm_notify_finalize (GObject *object) an = ALARM_NOTIFY (object); priv = an->priv; - g_hash_table_foreach (priv->uri_client_hash, destroy_loaded_client_cb, NULL); - g_hash_table_destroy (priv->uri_client_hash); - priv->uri_client_hash = NULL; g_free (priv); - an->priv = NULL; if (G_OBJECT_CLASS (parent_class)->finalize) (* G_OBJECT_CLASS (parent_class)->finalize) (object); @@ -193,21 +153,15 @@ free_uris (GPtrArray *uris) /* Adds an URI to the list of calendars to load on startup */ static void -add_uri_to_load (EUri *uri) +add_uri_to_load (const char *str_uri) { - char *str_uri; GPtrArray *loaded_uris; int i; - /* Canonicalize the URI */ - str_uri = e_uri_to_string (uri, FALSE); - g_assert (str_uri != NULL); - loaded_uris = get_calendars_to_load (); if (!loaded_uris) { g_message ("add_uri_to_load(): Could not get the list of calendars to load; " "will not add `%s'", str_uri); - g_free (str_uri); return; } @@ -219,12 +173,11 @@ add_uri_to_load (EUri *uri) * calendars. */ if (i != -1) { - g_free (str_uri); free_uris (loaded_uris); return; } - g_ptr_array_add (loaded_uris, str_uri); + g_ptr_array_add (loaded_uris, g_strdup (str_uri)); save_calendars_to_load (loaded_uris); free_uris (loaded_uris); @@ -232,29 +185,22 @@ add_uri_to_load (EUri *uri) /* Removes an URI from the list of calendars to load on startup */ static void -remove_uri_to_load (EUri *uri) +remove_uri_to_load (const char *str_uri) { - char *str_uri; GPtrArray *loaded_uris; char *loaded_uri; int i; - /* Canonicalize the URI */ - str_uri = e_uri_to_string (uri, FALSE); - g_assert (str_uri != NULL); - loaded_uris = get_calendars_to_load (); if (!loaded_uris) { g_message ("remove_uri_to_load(): Could not get the list of calendars to load; " "will not add `%s'", str_uri); - g_free (str_uri); return; } /* Look for the URI in the list of calendars to load */ i = find_uri_index (loaded_uris, str_uri); - g_free (str_uri); /* If we didn't find it, there is no need to remove it */ if (i == -1) { @@ -291,61 +237,19 @@ AlarmNotify_removeCalendar (PortableServer_Servant servant, { AlarmNotify *an; AlarmNotifyPrivate *priv; - LoadedClient *lc; - EUri *uri; - char *orig_str; - gpointer lc_ptr, orig_str_ptr; - gboolean found; - - lc_ptr = NULL; - orig_str_ptr = NULL; + CalClient *client; an = ALARM_NOTIFY (bonobo_object_from_servant (servant)); priv = an->priv; - uri = e_uri_new (str_uri); - if (!uri) { - CORBA_exception_set (ev, CORBA_USER_EXCEPTION, - ex_GNOME_Evolution_Calendar_AlarmNotify_InvalidURI, - NULL); - return; - } + client = g_hash_table_lookup (priv->uri_client_hash, str_uri); + if (client) { + alarm_queue_remove_client (client); - remove_uri_to_load (uri); - - found = g_hash_table_lookup_extended (priv->uri_client_hash, str_uri, - &orig_str_ptr, - &lc_ptr); - orig_str = orig_str_ptr; - lc = lc_ptr; - - e_uri_free (uri); - - if (!lc) { - CORBA_exception_set (ev, CORBA_USER_EXCEPTION, - ex_GNOME_Evolution_Calendar_AlarmNotify_NotFound, - NULL); - return; + g_hash_table_remove (priv->uri_client_hash, str_uri); } - g_assert (lc->refcount > 0); - - lc->refcount--; - if (lc->refcount > 0) - return; - - g_hash_table_remove (priv->uri_client_hash, str_uri); - - g_free (orig_str); - g_signal_handlers_disconnect_matched (lc->client, - G_SIGNAL_MATCH_DATA, - 0, 0, NULL, NULL, lc); - if (lc->timeout_id != -1) - g_source_remove (lc->timeout_id); - alarm_queue_remove_client (lc->client); - g_object_unref (G_OBJECT (lc->client)); - e_uri_free (lc->uri); - g_free (lc); + remove_uri_to_load (str_uri); } @@ -367,40 +271,6 @@ alarm_notify_new (void) return an; } -static gboolean -retry_timeout_cb (gpointer data) -{ - LoadedClient *lc = data; - char *str_uri; - - if (cal_client_get_load_state (lc->client) != CAL_CLIENT_LOAD_LOADED) { - str_uri = e_uri_to_string (lc->uri, FALSE); - cal_client_open_calendar (lc->client, str_uri, FALSE); - - g_free (str_uri); - } - - return FALSE; -} - -static void -cal_opened_cb (CalClient *client, CalClientOpenStatus status, gpointer data) -{ - LoadedClient *lc = (LoadedClient *) data; - - if (status == CAL_CLIENT_OPEN_SUCCESS) { - add_uri_to_load (lc->uri); - alarm_queue_add_client (client); - lc->timeout_id = -1; - } - else { - remove_uri_to_load (lc->uri); - - /* we set a timeout of 5 mins before retrying */ - lc->timeout_id = g_timeout_add (300000, (GSourceFunc) retry_timeout_cb, lc); - } -} - /** * alarm_notify_add_calendar: * @an: An alarm notification service. @@ -418,10 +288,7 @@ alarm_notify_add_calendar (AlarmNotify *an, const char *str_uri, gboolean load_a CORBA_Environment *ev) { AlarmNotifyPrivate *priv; - EUri *uri; CalClient *client; - LoadedClient *lc; - gpointer lc_ptr, s_ptr; g_return_if_fail (an != NULL); g_return_if_fail (IS_ALARM_NOTIFY (an)); @@ -430,49 +297,23 @@ alarm_notify_add_calendar (AlarmNotify *an, const char *str_uri, gboolean load_a priv = an->priv; - uri = e_uri_new (str_uri); - if (!uri) { - CORBA_exception_set (ev, CORBA_USER_EXCEPTION, - ex_GNOME_Evolution_Calendar_AlarmNotify_InvalidURI, - NULL); + /* See if we already know about this uri */ + if (g_hash_table_lookup (priv->uri_client_hash, str_uri)) return; - } - if (g_hash_table_lookup_extended (priv->uri_client_hash, str_uri, &s_ptr, &lc_ptr)) { - lc = lc_ptr; - lc->refcount++; - } else { - client = cal_client_new (); - - if (client) { - /* we only add the URI to load_afterwards if we open it - correctly */ - lc = g_new (LoadedClient, 1); - lc->client = client; - lc->uri = uri; - lc->refcount = 1; - lc->timeout_id = -1; - - - g_signal_connect (G_OBJECT (client), "cal_opened", - G_CALLBACK (cal_opened_cb), - lc); - - if (cal_client_open_calendar (client, str_uri, FALSE)) { - g_hash_table_insert (priv->uri_client_hash, - g_strdup (str_uri), lc); - } else { - g_free (lc); - g_object_unref (G_OBJECT (client)); - client = NULL; - } - } else { - e_uri_free (uri); - - CORBA_exception_set (ev, CORBA_USER_EXCEPTION, - ex_GNOME_Evolution_Calendar_AlarmNotify_BackendContactError, - NULL); - return; + client = cal_client_new (str_uri, CALOBJ_TYPE_EVENT); + + if (client) { + if (cal_client_open (client, FALSE, NULL)) { + add_uri_to_load (str_uri); + + g_hash_table_insert (priv->uri_client_hash, + g_strdup (str_uri), client); } + } else { + CORBA_exception_set (ev, CORBA_USER_EXCEPTION, + ex_GNOME_Evolution_Calendar_AlarmNotify_BackendContactError, + NULL); + return; } } diff --git a/calendar/gui/alarm-notify/alarm-queue.c b/calendar/gui/alarm-notify/alarm-queue.c index cb792e466f..cee17bd97e 100644 --- a/calendar/gui/alarm-notify/alarm-queue.c +++ b/calendar/gui/alarm-notify/alarm-queue.c @@ -227,7 +227,7 @@ remove_queued_alarm (CompQueuedAlarms *cqa, gpointer alarm_id, if (remove_alarm) { cqa->expecting_update = TRUE; cal_client_discard_alarm (cqa->parent_client->client, cqa->alarms->comp, - qa->instance->auid); + qa->instance->auid, NULL); cqa->expecting_update = FALSE; } diff --git a/calendar/gui/calendar-commands.c b/calendar/gui/calendar-commands.c index c0d1b3c589..77305098bc 100644 --- a/calendar/gui/calendar-commands.c +++ b/calendar/gui/calendar-commands.c @@ -59,6 +59,7 @@ #include "goto.h" #include "print.h" #include "dialogs/cal-prefs-dialog.h" +#include "dialogs/new-calendar.h" #include "itip-utils.h" #include "evolution-shell-component-utils.h" @@ -73,6 +74,68 @@ typedef struct { guint taskpad_focused : 1; } FocusData; +static void +file_new_calendar_cb (BonoboUIComponent *uic, gpointer data, const char *path) +{ + GnomeCalendar *gcal; + + gcal = GNOME_CALENDAR (data); + + new_calendar_dialog (GTK_WINDOW (gtk_widget_get_toplevel (GTK_WIDGET (gcal)))); +} + +static void +file_new_appointment_cb (BonoboUIComponent *uic, gpointer data, const char *path) +{ + GnomeCalendar *gcal; + time_t dtstart, dtend; + ECalView *cal_view; + + gcal = GNOME_CALENDAR (data); + + cal_view = (ECalView *) gnome_calendar_get_current_view_widget (gcal); + e_cal_view_get_selected_time_range (cal_view, &dtstart, &dtend); + e_cal_view_new_appointment_for (cal_view, dtstart, dtend, FALSE, FALSE); +} + +static void +file_new_event_cb (BonoboUIComponent *uic, gpointer data, const char *path) +{ + GnomeCalendar *gcal; + time_t dtstart, dtend; + ECalView *cal_view; + + gcal = GNOME_CALENDAR (data); + + cal_view = (ECalView *) gnome_calendar_get_current_view_widget (gcal); + e_cal_view_get_selected_time_range (cal_view, &dtstart, &dtend); + e_cal_view_new_appointment_for (cal_view, dtstart, dtend, TRUE, FALSE); +} + +static void +file_new_meeting_cb (BonoboUIComponent *uic, gpointer data, const char *path) +{ + GnomeCalendar *gcal; + time_t dtstart, dtend; + ECalView *cal_view; + + gcal = GNOME_CALENDAR (data); + + cal_view = (ECalView *) gnome_calendar_get_current_view_widget (gcal); + e_cal_view_get_selected_time_range (cal_view, &dtstart, &dtend); + e_cal_view_new_appointment_for (cal_view, dtstart, dtend, FALSE, TRUE); +} + +static void +file_new_task_cb (BonoboUIComponent *uic, gpointer data, const char *path) +{ + GnomeCalendar *gcal; + + gcal = GNOME_CALENDAR (data); + + gnome_calendar_new_task (gcal); +} + /* Prints the calendar at its current view and time range */ static void print (GnomeCalendar *gcal, gboolean preview) @@ -335,12 +398,10 @@ publish_freebusy_cmd (BonoboUIComponent *uic, gpointer data, const gchar *path) start = time_day_begin_with_zone (start, utc); end = time_add_week_with_zone (start, 6, utc); + /* FIXME Should we aggregate the data? */ client_list = e_cal_model_get_client_list (gnome_calendar_get_calendar_model (gcal)); for (cl = client_list; cl != NULL; cl = cl->next) { - GList *tmp_comp_list; - - tmp_comp_list = cal_client_get_free_busy ((CalClient *) cl->data, NULL, start, end); - if (tmp_comp_list) { + if (cal_client_get_free_busy ((CalClient *) cl->data, NULL, start, end, &comp_list, NULL)) { GList *l; for (l = comp_list; l; l = l->next) { @@ -599,19 +660,42 @@ control_util_show_settings (GnomeCalendar *gcal) * is FALSE, all will be disabled. Otherwise, the currently-selected number of * events will be used. */ -static void -sensitize_calendar_commands (GnomeCalendar *gcal, BonoboControl *control, gboolean enable) +void +calendar_control_sensitize_calendar_commands (BonoboControl *control, GnomeCalendar *gcal, gboolean enable) { BonoboUIComponent *uic; + ECalViewEvent *event; + GList *list; int n_selected; - gboolean read_only, has_recurrences; + GtkWidget *view; + CalClient *cal_client; + gboolean read_only = FALSE, has_recurrences; uic = bonobo_control_get_ui_component (control); g_assert (uic != NULL); - n_selected = enable ? gnome_calendar_get_num_events_selected (gcal) : 0; - read_only = cal_client_is_read_only (e_cal_model_get_default_client (gnome_calendar_get_calendar_model (gcal))); + view = gnome_calendar_get_current_view_widget (gcal); + list = e_cal_view_get_selected_events (E_CAL_VIEW (view)); + + n_selected = enable ? g_list_length (list) : 0; + event = (ECalViewEvent *) list ? list->data : NULL; + if (event) { + cal_client_is_read_only (event->comp_data->client, &read_only, NULL); + } else { + cal_client = e_cal_model_get_default_client (gnome_calendar_get_calendar_model (gcal)); + if (cal_client) + cal_client_is_read_only (cal_client, &read_only, NULL); + else + read_only = TRUE; + } + + bonobo_ui_component_set_prop (uic, "/commands/NewAppointment", "sensitive", + read_only ? "0" : "1", NULL); + bonobo_ui_component_set_prop (uic, "/commands/NewAllDayEvent", "sensitive", + read_only ? "0" : "1", NULL); + bonobo_ui_component_set_prop (uic, "/commands/NewMeeting", "sensitive", + read_only ? "0" : "1", NULL); bonobo_ui_component_set_prop (uic, "/commands/Cut", "sensitive", n_selected == 0 || read_only ? "0" : "1", NULL); @@ -628,19 +712,8 @@ sensitize_calendar_commands (GnomeCalendar *gcal, BonoboControl *control, gboole /* occurrence-related menu items */ has_recurrences = FALSE; if (n_selected > 0 && !read_only) { - ECalViewEvent *event; - GList *list; - GtkWidget *view; - - view = gnome_calendar_get_current_view_widget (gcal); - list = e_cal_view_get_selected_events (E_CAL_VIEW (view)); if (list) { event = (ECalViewEvent *) list->data; - g_list_free (list); - } else - event = NULL; - - if (event) { if (cal_util_component_has_recurrences (event->comp_data->icalcomp)) has_recurrences = TRUE; } @@ -652,6 +725,10 @@ sensitize_calendar_commands (GnomeCalendar *gcal, BonoboControl *control, gboole bonobo_ui_component_set_prop (uic, "/commands/DeleteAllOccurrences", "sensitive", has_recurrences ? "1" : "0", NULL); + + /* free memory */ + if (list) + g_list_free (list); } /* Sensitizes the UI Component menu/toolbar tasks commands based on the number @@ -663,14 +740,21 @@ sensitize_taskpad_commands (GnomeCalendar *gcal, BonoboControl *control, gboolea { BonoboUIComponent *uic; int n_selected; - gboolean read_only; + CalClient *cal_client; + gboolean read_only = TRUE; uic = bonobo_control_get_ui_component (control); g_assert (uic != NULL); n_selected = enable ? gnome_calendar_get_num_tasks_selected (gcal) : 0; - read_only = cal_client_is_read_only (gnome_calendar_get_task_pad_cal_client (gcal)); - + cal_client = gnome_calendar_get_task_pad_cal_client (gcal); + if (cal_client) + cal_client_is_read_only (cal_client, &read_only, NULL); + else + read_only = TRUE; + + bonobo_ui_component_set_prop (uic, "/commands/NewTask", "sensitive", + read_only ? "0" : "1", NULL); bonobo_ui_component_set_prop (uic, "/commands/Cut", "sensitive", n_selected == 0 || read_only ? "0" : "1", NULL); @@ -705,7 +789,7 @@ gcal_calendar_selection_changed_cb (GnomeCalendar *gcal, gpointer data) control = BONOBO_CONTROL (data); - sensitize_calendar_commands (gcal, control, TRUE); + calendar_control_sensitize_calendar_commands (control, gcal, TRUE); } /* Callback used when the selection in the taskpad changes */ @@ -734,13 +818,13 @@ gcal_calendar_focus_change_cb (GnomeCalendar *gcal, gboolean in, gpointer data) if (in) { g_signal_connect (gcal, "calendar_selection_changed", G_CALLBACK (gcal_calendar_selection_changed_cb), control); - sensitize_calendar_commands (gcal, control, TRUE); + calendar_control_sensitize_calendar_commands (control, gcal, TRUE); focus->calendar_focused = TRUE; } else if (focus->calendar_focused) { gtk_signal_disconnect_by_func (GTK_OBJECT (gcal), G_CALLBACK (gcal_calendar_selection_changed_cb), control); - sensitize_calendar_commands (gcal, control, FALSE); + calendar_control_sensitize_calendar_commands (control, gcal, FALSE); focus->calendar_focused = FALSE; } } @@ -779,6 +863,11 @@ gcal_taskpad_focus_change_cb (GnomeCalendar *gcal, gboolean in, gpointer data) static BonoboUIVerb verbs [] = { + BONOBO_UI_VERB ("NewCalendar", file_new_calendar_cb), + BONOBO_UI_VERB ("NewAppointment", file_new_appointment_cb), + BONOBO_UI_VERB ("NewAllDayEvent", file_new_event_cb), + BONOBO_UI_VERB ("NewMeeting", file_new_meeting_cb), + BONOBO_UI_VERB ("NewTask", file_new_task_cb), BONOBO_UI_VERB ("CalendarPrint", file_print_cb), BONOBO_UI_VERB ("CalendarPrintPreview", file_print_preview_cb), @@ -808,11 +897,15 @@ static BonoboUIVerb verbs [] = { static EPixmap pixmaps [] = { - E_PIXMAP ("/Toolbar/DayView", "buttons/dayview.xpm"), - E_PIXMAP ("/Toolbar/WorkWeekView", "buttons/workweekview.xpm"), - E_PIXMAP ("/Toolbar/WeekView", "buttons/weekview.xpm"), - E_PIXMAP ("/Toolbar/MonthView", "buttons/monthview.xpm"), - E_PIXMAP ("/Toolbar/ListView", "buttons/listview.xpm"), + E_PIXMAP ("/commands/NewAppointment", "new_appointment.xpm"), + E_PIXMAP ("/commands/NewAllDayEvent", "new_all_day_event.png"), + E_PIXMAP ("/commands/NewMeeting", "meeting-request-16.png"), + E_PIXMAP ("/commands/NewTask", "new_task-16.png"), + E_PIXMAP ("/Toolbar/DayView", "buttons/dayview.xpm"), + E_PIXMAP ("/Toolbar/WorkWeekView", "buttons/workweekview.xpm"), + E_PIXMAP ("/Toolbar/WeekView", "buttons/weekview.xpm"), + E_PIXMAP ("/Toolbar/MonthView", "buttons/monthview.xpm"), + E_PIXMAP ("/Toolbar/ListView", "buttons/listview.xpm"), E_PIXMAP_END }; @@ -855,7 +948,7 @@ calendar_control_activate (BonoboControl *control, g_signal_connect (gcal, "taskpad_focus_change", G_CALLBACK (gcal_taskpad_focus_change_cb), control); - sensitize_calendar_commands (gcal, control, FALSE); + calendar_control_sensitize_calendar_commands (control, gcal, FALSE); sensitize_taskpad_commands (gcal, control, FALSE); bonobo_ui_component_thaw (uic, NULL); diff --git a/calendar/gui/calendar-commands.h b/calendar/gui/calendar-commands.h index 6f418799d2..3e74074140 100644 --- a/calendar/gui/calendar-commands.h +++ b/calendar/gui/calendar-commands.h @@ -38,6 +38,8 @@ GnomeCalendar *new_calendar (void); void calendar_control_activate (BonoboControl *control, GnomeCalendar *gcal); void calendar_control_deactivate (BonoboControl *control, GnomeCalendar *gcal); +void calendar_control_sensitize_calendar_commands (BonoboControl *control, GnomeCalendar *gcal, gboolean enable); + void calendar_goto_today (GnomeCalendar *gcal); void calendar_set_folder_bar_label (GnomeCalendar *gcal, BonoboControl *control); diff --git a/calendar/gui/calendar-component.c b/calendar/gui/calendar-component.c index 98f0964cc4..3e8782f45b 100644 --- a/calendar/gui/calendar-component.c +++ b/calendar/gui/calendar-component.c @@ -1,7 +1,7 @@ /* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */ -/* component-factory.c +/* calendar-component.c * - * Copyright (C) 2000, 2001, 2002, 2003 Ximian, Inc. + * Copyright (C) 2003 Ettore Perazzoli * * This program is free software; you can redistribute it and/or * modify it under the terms of version 2 of the GNU General Public @@ -20,752 +20,269 @@ * Author: Ettore Perazzoli */ +#ifdef CONFIG_H #include +#endif -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include - -#include "evolution-shell-component.h" -#include "calendar-offline-handler.h" #include "calendar-component.h" -#include "tasks-control.h" #include "control-factory.h" -#include "calendar-config.h" -#include "tasks-control.h" -#include "e-comp-editor-registry.h" -#include "dialogs/comp-editor.h" - - -/* OAFIID for the component. */ -#define COMPONENT_ID "OAFIID:GNOME_Evolution_Calendar_ShellComponent" - -/* Folder type IDs */ -#define FOLDER_CALENDAR "calendar" -#define FOLDER_TASKS "tasks" -#define FOLDER_PUBLIC_CALENDAR "calendar/public" -#define FOLDER_PUBLIC_TASKS "tasks/public" - -/* IDs for user creatable items */ -#define CREATE_EVENT_ID "event" -#define CREATE_ALLDAY_EVENT_ID "allday-event" -#define CREATE_MEETING_ID "meeting" -#define CREATE_TASK_ID "task" - -char *evolution_dir = NULL; -EvolutionShellClient *global_shell_client = NULL; -extern ECompEditorRegistry *comp_editor_registry; - -static const EvolutionShellComponentFolderType folder_types[] = { - { FOLDER_CALENDAR, - "evolution-calendar.png", - N_("Calendar"), - N_("Folder containing appointments and events"), - TRUE, NULL, NULL }, - { FOLDER_PUBLIC_CALENDAR, - "evolution-calendar.png", - N_("Public Calendar"), - N_("Public folder containing appointments and events"), - FALSE, NULL, NULL }, - { FOLDER_TASKS, - "evolution-tasks.png", - N_("Tasks"), - N_("Folder containing to-do items"), - TRUE, NULL, NULL }, - { FOLDER_PUBLIC_TASKS, - "evolution-tasks.png", - N_("Public Tasks"), - N_("Public folder containing to-do items"), - FALSE, NULL, NULL }, - { NULL, NULL } -}; +#include "gnome-cal.h" +#include "migration.h" - - -static inline gboolean -type_is_calendar (const char *type) -{ - return !strcmp (type, FOLDER_CALENDAR) || - !strcmp (type, FOLDER_PUBLIC_CALENDAR); -} +#include "widgets/misc/e-source-selector.h" -static inline gboolean -type_is_tasks (const char *type) -{ - return !strcmp (type, FOLDER_TASKS) || - !strcmp (type, FOLDER_PUBLIC_TASKS); -} +#include +#include +#include -/* EvolutionShellComponent methods and signals. */ +#include -static EvolutionShellComponentResult -create_view (EvolutionShellComponent *shell_component, - const char *physical_uri, - const char *type, - const char *view_info, - BonoboControl **control_return, - void *closure) -{ - BonoboControl *control; - - if (type_is_calendar (type)) { - control = control_factory_new_control (); - if (!control) - return EVOLUTION_SHELL_COMPONENT_CORBAERROR; - } else if (type_is_tasks (type)) { - control = tasks_control_new (); - if (!control) - return EVOLUTION_SHELL_COMPONENT_CORBAERROR; - } else { - return EVOLUTION_SHELL_COMPONENT_UNSUPPORTEDTYPE; - } - bonobo_control_set_property (control, NULL, "folder_uri", TC_CORBA_string, physical_uri, NULL); - if (type_is_calendar (type) && *view_info) - bonobo_control_set_property (control, NULL, "view", TC_CORBA_string, view_info, NULL); +#define PARENT_TYPE bonobo_object_get_type () +static BonoboObjectClass *parent_class = NULL; - *control_return = control; - return EVOLUTION_SHELL_COMPONENT_OK; -} +struct _CalendarComponentPrivate { + char *config_directory; -static void -create_folder (EvolutionShellComponent *shell_component, - const char *physical_uri, - const char *type, - const GNOME_Evolution_ShellComponentListener listener, - void *closure) -{ - CORBA_Environment ev; - GnomeVFSURI *uri; + GConfClient *gconf_client; + ESourceList *source_list; +}; - CORBA_exception_init (&ev); - if (!type_is_calendar (type) && !type_is_tasks (type)) { - GNOME_Evolution_ShellComponentListener_notifyResult ( - listener, - GNOME_Evolution_ShellComponentListener_UNSUPPORTED_TYPE, - &ev); - CORBA_exception_free (&ev); - return; - } +/* Utility functions. */ - uri = gnome_vfs_uri_new (physical_uri); - if (uri) { - /* we don't need to do anything */ - GNOME_Evolution_ShellComponentListener_notifyResult ( - listener, - GNOME_Evolution_ShellComponentListener_OK, &ev); - gnome_vfs_uri_unref (uri); - } - else { - GNOME_Evolution_ShellComponentListener_notifyResult ( - listener, - GNOME_Evolution_ShellComponentListener_INVALID_URI, - &ev); - } +static void +load_uri_for_source (ESource *source, BonoboControl *view_control) +{ + GnomeCalendar *gcal; + char *uri = e_source_get_uri (source); - CORBA_exception_free (&ev); + gcal = (GnomeCalendar *) bonobo_control_get_widget (view_control); + gnome_calendar_add_event_uri (gcal, uri); + g_free (uri); } -/* Asks the alarm daemon to stop monitoring the specified URI */ static void -stop_alarms (GnomeVFSURI *uri) +load_uri_for_selection (ESourceSelector *selector, BonoboControl *view_control) { - char *str_uri; - CORBA_Environment ev; - GNOME_Evolution_Calendar_AlarmNotify an; - - /* Activate the alarm notification service */ - - CORBA_exception_init (&ev); - an = bonobo_activation_activate_from_id ("OAFIID:GNOME_Evolution_Calendar_AlarmNotify", 0, NULL, &ev); - - if (BONOBO_EX (&ev)) { - g_message ("stop_alarms(): Could not activate the alarm notification service"); - CORBA_exception_free (&ev); - return; - } - CORBA_exception_free (&ev); - - /* Ask the service to remove the URI from its list of calendars */ - - str_uri = gnome_vfs_uri_to_string (uri, GNOME_VFS_URI_HIDE_NONE); - g_assert (str_uri != NULL); - - CORBA_exception_init (&ev); - GNOME_Evolution_Calendar_AlarmNotify_removeCalendar (an, str_uri, &ev); - g_free (str_uri); - - if (BONOBO_USER_EX (&ev, ex_GNOME_Evolution_Calendar_AlarmNotify_InvalidURI)) { - g_message ("stop_alarms(): Invalid URI reported from the alarm notification service"); - } else if (BONOBO_USER_EX (&ev, ex_GNOME_Evolution_Calendar_AlarmNotify_NotFound)) { - /* This is OK; the service may not have loaded that calendar */ - } else if (BONOBO_EX (&ev)) { - g_message ("stop_alarms(): Could not issue the removeCalendar request"); - } + GSList *selection, *l; - CORBA_exception_free (&ev); - - /* Get rid of the service */ - - CORBA_exception_init (&ev); - bonobo_object_release_unref (an, &ev); - if (BONOBO_EX (&ev)) - g_message ("stop_alarms(): Could not unref the alarm notification service"); - CORBA_exception_free (&ev); + selection = e_source_selector_get_selection (selector); + for (l = selection; l; l = l->next) { + ESource *selected_source = l->data; + + load_uri_for_source (selected_source, view_control); + } } +/* Callbacks. */ static void -remove_folder (EvolutionShellComponent *shell_component, - const char *physical_uri, - const char *type, - const GNOME_Evolution_ShellComponentListener listener, - void *closure) +source_selection_changed_callback (ESourceSelector *selector, + BonoboControl *view_control) { - GnomeVFSURI *dir_uri, *data_uri, *backup_uri; - GnomeVFSResult data_result, backup_result; - - /* check type */ - if (!type_is_calendar (type) && !type_is_tasks (type)) { - CORBA_Environment ev; - - CORBA_exception_init (&ev); - GNOME_Evolution_ShellComponentListener_notifyResult ( - listener, - GNOME_Evolution_ShellComponentListener_UNSUPPORTED_TYPE, - &ev); - - if (BONOBO_EX (&ev)) - g_message ("remove_folder(): Could not notify the listener of " - "an unsupported folder type"); + + load_uri_for_selection (selector, view_control); +} - CORBA_exception_free (&ev); - return; - } +static void +primary_source_selection_changed_callback (ESourceSelector *selector, + BonoboControl *view_control) +{ + ESource *source; + GnomeCalendar *gcal; + ECalModel *model; + CalClient *client; - /* check URI */ - dir_uri = gnome_vfs_uri_new (physical_uri); - if (!dir_uri) { - CORBA_Environment ev; - - CORBA_exception_init (&ev); - GNOME_Evolution_ShellComponentListener_notifyResult ( - listener, - GNOME_Evolution_ShellComponentListener_INVALID_URI, - &ev); - CORBA_exception_free (&ev); + source = e_source_selector_peek_primary_selection (selector); + if (!source) return; - } - /* Compute the URIs of the appropriate files */ - - if (type_is_calendar (type)) { - data_uri = gnome_vfs_uri_append_file_name (dir_uri, "calendar.ics"); - backup_uri = gnome_vfs_uri_append_file_name (dir_uri, "calendar.ics~"); - } else if (type_is_tasks (type)) { - data_uri = gnome_vfs_uri_append_file_name (dir_uri, "tasks.ics"); - backup_uri = gnome_vfs_uri_append_file_name (dir_uri, "tasks.ics~"); - } else { - g_assert_not_reached (); + /* set the default client on the GnomeCalendar */ + gcal = (GnomeCalendar *) bonobo_control_get_widget (view_control); + if (!GNOME_IS_CALENDAR (gcal)) return; - } - - if (!data_uri || !backup_uri) { - CORBA_Environment ev; - - g_message ("remove_folder(): Could not generate the data/backup URIs"); - - CORBA_exception_init (&ev); - GNOME_Evolution_ShellComponentListener_notifyResult ( - listener, - GNOME_Evolution_ShellComponentListener_INVALID_URI, - &ev); - - if (BONOBO_EX (&ev)) - g_message ("remove_folder(): Could not notify the listener " - "of an invalid URI"); - - CORBA_exception_free (&ev); - - goto out; - } - - /* Ask the alarm daemon to stop monitoring this URI */ - - stop_alarms (data_uri); - - /* Delete the data and backup files; the shell will take care of the rest */ - - data_result = gnome_vfs_unlink_from_uri (data_uri); - backup_result = gnome_vfs_unlink_from_uri (backup_uri); - - if ((data_result == GNOME_VFS_OK || data_result == GNOME_VFS_ERROR_NOT_FOUND) - && (backup_result == GNOME_VFS_OK || backup_result == GNOME_VFS_ERROR_NOT_FOUND)) { - CORBA_Environment ev; - - CORBA_exception_init (&ev); - GNOME_Evolution_ShellComponentListener_notifyResult ( - listener, - GNOME_Evolution_ShellComponentListener_OK, - &ev); - - if (BONOBO_EX (&ev)) - g_message ("remove_folder(): Could not notify the listener about success"); - - CORBA_exception_free (&ev); - } else { - CORBA_Environment ev; - - CORBA_exception_init (&ev); - GNOME_Evolution_ShellComponentListener_notifyResult ( - listener, - GNOME_Evolution_ShellComponentListener_PERMISSION_DENIED, - &ev); - - if (BONOBO_EX (&ev)) - g_message ("remove_folder(): Could not notify the listener about failure"); - - CORBA_exception_free (&ev); - } - out: - - gnome_vfs_uri_unref (dir_uri); - - if (data_uri) - gnome_vfs_uri_unref (data_uri); - - if (backup_uri) - gnome_vfs_uri_unref (backup_uri); + model = gnome_calendar_get_calendar_model (gcal); + client = e_cal_model_get_client_for_uri (model, e_source_get_uri (source)); + if (client) + gnome_calendar_set_default_client (gcal, client); } -static GNOME_Evolution_ShellComponentListener_Result -xfer_file (GnomeVFSURI *base_src_uri, - GnomeVFSURI *base_dest_uri, - const char *file_name, - int remove_source) -{ - GnomeVFSURI *src_uri, *dest_uri; - GnomeVFSHandle *hin, *hout; - GnomeVFSResult result; - GnomeVFSFileInfo file_info; - GnomeVFSFileSize size; - char *buffer; - - src_uri = gnome_vfs_uri_append_file_name (base_src_uri, file_name); - - result = gnome_vfs_open_uri (&hin, src_uri, GNOME_VFS_OPEN_READ); - if (result == GNOME_VFS_ERROR_NOT_FOUND) { - gnome_vfs_uri_unref (src_uri); - return GNOME_Evolution_ShellComponentListener_OK; /* No need to xfer anything. */ - } - if (result != GNOME_VFS_OK) { - gnome_vfs_uri_unref (src_uri); - return GNOME_Evolution_ShellComponentListener_PERMISSION_DENIED; - } - - result = gnome_vfs_get_file_info_uri (src_uri, &file_info, GNOME_VFS_FILE_INFO_DEFAULT); - if (result != GNOME_VFS_OK) { - gnome_vfs_uri_unref (src_uri); - return GNOME_Evolution_ShellComponentListener_PERMISSION_DENIED; - } - - dest_uri = gnome_vfs_uri_append_file_name (base_dest_uri, file_name); - - result = gnome_vfs_create_uri (&hout, dest_uri, GNOME_VFS_OPEN_WRITE, FALSE, 0600); - if (result != GNOME_VFS_OK) { - gnome_vfs_close (hin); - gnome_vfs_uri_unref (src_uri); - gnome_vfs_uri_unref (dest_uri); - return GNOME_Evolution_ShellComponentListener_PERMISSION_DENIED; - } +/* GObject methods. */ - /* write source file to destination file */ - buffer = g_malloc (file_info.size); - result = gnome_vfs_read (hin, buffer, file_info.size, &size); - if (result != GNOME_VFS_OK) { - gnome_vfs_close (hin); - gnome_vfs_close (hout); - gnome_vfs_uri_unref (src_uri); - gnome_vfs_uri_unref (dest_uri); - g_free (buffer); - return GNOME_Evolution_ShellComponentListener_PERMISSION_DENIED; - } +static void +impl_dispose (GObject *object) +{ + CalendarComponentPrivate *priv = CALENDAR_COMPONENT (object)->priv; - result = gnome_vfs_write (hout, buffer, file_info.size, &size); - if (result != GNOME_VFS_OK) { - gnome_vfs_close (hin); - gnome_vfs_close (hout); - gnome_vfs_uri_unref (src_uri); - gnome_vfs_uri_unref (dest_uri); - g_free (buffer); - return GNOME_Evolution_ShellComponentListener_PERMISSION_DENIED; + if (priv->source_list != NULL) { + g_object_unref (priv->source_list); + priv->source_list = NULL; } - if (remove_source) { - char *text_uri; - - /* Sigh, we have to do this as there is no gnome_vfs_unlink_uri(). :-( */ - - text_uri = gnome_vfs_uri_to_string (src_uri, GNOME_VFS_URI_HIDE_NONE); - result = gnome_vfs_unlink (text_uri); - g_free (text_uri); + if (priv->gconf_client != NULL) { + g_object_unref (priv->gconf_client); + priv->gconf_client = NULL; } - gnome_vfs_close (hin); - gnome_vfs_close (hout); - gnome_vfs_uri_unref (src_uri); - gnome_vfs_uri_unref (dest_uri); - g_free (buffer); - - return GNOME_Evolution_ShellComponentListener_OK; + (* G_OBJECT_CLASS (parent_class)->dispose) (object); } static void -xfer_folder (EvolutionShellComponent *shell_component, - const char *source_physical_uri, - const char *destination_physical_uri, - const char *type, - gboolean remove_source, - const GNOME_Evolution_ShellComponentListener listener, - void *closure) +impl_finalize (GObject *object) { - CORBA_Environment ev; - GnomeVFSURI *src_uri; - GnomeVFSURI *dest_uri; - GnomeVFSResult result; - char *filename, *backup_filename; - - CORBA_exception_init (&ev); - - /* check type */ - if (!type_is_calendar (type) && !type_is_tasks (type)) { - GNOME_Evolution_ShellComponentListener_notifyResult ( - listener, - GNOME_Evolution_ShellComponentListener_UNSUPPORTED_TYPE, - &ev); - CORBA_exception_free (&ev); - return; - } - - /* check URIs */ - src_uri = gnome_vfs_uri_new (source_physical_uri); - dest_uri = gnome_vfs_uri_new (destination_physical_uri); - if (!src_uri || ! dest_uri) { - GNOME_Evolution_ShellComponentListener_notifyResult ( - listener, - GNOME_Evolution_ShellComponentListener_INVALID_URI, - &ev); - gnome_vfs_uri_unref (src_uri); - gnome_vfs_uri_unref (dest_uri); - CORBA_exception_free (&ev); - return; - } - - if (type_is_calendar (type)) { - filename = "calendar.ics"; - backup_filename = "calendar.ics~"; - } else if (type_is_tasks (type)) { - filename = "tasks.ics"; - backup_filename = "tasks.ics~"; - } else { - g_assert_not_reached (); - return; - } - - result = xfer_file (src_uri, dest_uri, filename, remove_source); - if (result == GNOME_Evolution_ShellComponentListener_OK) - result = xfer_file (src_uri, dest_uri, backup_filename, remove_source); - - GNOME_Evolution_ShellComponentListener_notifyResult (listener, result, &ev); + CalendarComponentPrivate *priv = CALENDAR_COMPONENT (object)->priv; - gnome_vfs_uri_unref (src_uri); - gnome_vfs_uri_unref (dest_uri); + g_free (priv->config_directory); + g_free (priv); - CORBA_exception_free (&ev); + (* G_OBJECT_CLASS (parent_class)->finalize) (object); } -static gboolean -request_quit (EvolutionShellComponent *shell_component, void *closure) -{ - return e_comp_editor_registry_close_all (comp_editor_registry); -} -static void -owner_set_cb (EvolutionShellComponent *shell_component, - EvolutionShellClient *shell_client, - const char *evolution_homedir, - gpointer user_data) -{ - if (evolution_dir) - g_free (evolution_dir); - evolution_dir = g_strdup (evolution_homedir); - global_shell_client = shell_client; -} +/* Evolution::Component CORBA methods. */ static void -owner_unset_cb (EvolutionShellComponent *shell_component, - gpointer user_data) +impl_createControls (PortableServer_Servant servant, + Bonobo_Control *corba_sidebar_control, + Bonobo_Control *corba_view_control, + CORBA_Environment *ev) { - global_shell_client = NULL; -} + CalendarComponent *calendar_component = CALENDAR_COMPONENT (bonobo_object_from_servant (servant)); + GtkWidget *selector; + GtkWidget *selector_scrolled_window; + BonoboControl *sidebar_control; + BonoboControl *view_control; -/* Computes the final URI for a calendar component */ -static char * -get_data_uri (const char *uri, CalComponentVType vtype) -{ - if (uri) { - if (*uri != '/' && strncmp (uri, "file:", 5) != 0) - return g_strdup (uri); - - if (vtype == CAL_COMPONENT_EVENT) - return cal_util_expand_uri ((char *) uri, FALSE); - else if (vtype == CAL_COMPONENT_TODO) - return cal_util_expand_uri ((char *) uri, TRUE); - else - g_assert_not_reached (); - } else { - if (vtype == CAL_COMPONENT_EVENT) - return g_concat_dir_and_file (g_get_home_dir (), - "evolution/local/Calendar/calendar.ics"); - else if (vtype == CAL_COMPONENT_TODO) - return g_concat_dir_and_file (g_get_home_dir (), - "evolution/local/Tasks/tasks.ics"); - else - g_assert_not_reached (); - } + selector = e_source_selector_new (calendar_component->priv->source_list); + gtk_widget_show (selector); - return NULL; -} + selector_scrolled_window = gtk_scrolled_window_new (NULL, NULL); + gtk_container_add (GTK_CONTAINER (selector_scrolled_window), selector); + gtk_widget_show (selector_scrolled_window); -/* Creates a calendar component at a specified URI. If the URI is NULL then it - * uses the default folder for that type of component. - */ -static void -create_component (const char *uri, GNOME_Evolution_Calendar_CompEditorFactory_CompEditorMode type) -{ - char *real_uri; - CORBA_Environment ev; - GNOME_Evolution_Calendar_CompEditorFactory factory; - CalComponentVType vtype; - - switch (type) { - case GNOME_Evolution_Calendar_CompEditorFactory_EDITOR_MODE_EVENT: - case GNOME_Evolution_Calendar_CompEditorFactory_EDITOR_MODE_ALLDAY_EVENT: - case GNOME_Evolution_Calendar_CompEditorFactory_EDITOR_MODE_MEETING: - vtype = CAL_COMPONENT_EVENT; - break; - case GNOME_Evolution_Calendar_CompEditorFactory_EDITOR_MODE_TODO: - vtype = CAL_COMPONENT_TODO; - break; - default: - g_assert_not_reached (); - return; - } + sidebar_control = bonobo_control_new (selector_scrolled_window); - real_uri = get_data_uri (uri, vtype); + view_control = control_factory_new_control (); - /* Get the factory */ + g_signal_connect_object (selector, "selection_changed", + G_CALLBACK (source_selection_changed_callback), + G_OBJECT (view_control), 0); + g_signal_connect_object (selector, "primary_selection_changed", + G_CALLBACK (primary_source_selection_changed_callback), + G_OBJECT (view_control), 0); - CORBA_exception_init (&ev); - factory = bonobo_activation_activate_from_id ("OAFIID:GNOME_Evolution_Calendar_CompEditorFactory", - 0, NULL, &ev); + load_uri_for_selection (E_SOURCE_SELECTOR (selector), view_control); - if (BONOBO_EX (&ev)) { - g_message ("create_component(): Could not activate the component editor factory"); - CORBA_exception_free (&ev); - g_free (real_uri); - return; - } - CORBA_exception_free (&ev); + *corba_sidebar_control = CORBA_Object_duplicate (BONOBO_OBJREF (sidebar_control), ev); + *corba_view_control = CORBA_Object_duplicate (BONOBO_OBJREF (view_control), ev); +} - /* Create the item */ - CORBA_exception_init (&ev); - GNOME_Evolution_Calendar_CompEditorFactory_editNew (factory, real_uri, type, &ev); +/* Initialization. */ - if (BONOBO_EX (&ev)) - g_message ("create_component(): Exception while creating the component"); +static void +calendar_component_class_init (CalendarComponentClass *class) +{ + POA_GNOME_Evolution_Component__epv *epv = &class->epv; + GObjectClass *object_class = G_OBJECT_CLASS (class); - CORBA_exception_free (&ev); - g_free (real_uri); + parent_class = g_type_class_peek_parent (class); - /* Get rid of the factory */ + epv->createControls = impl_createControls; - CORBA_exception_init (&ev); - bonobo_object_release_unref (factory, &ev); - if (BONOBO_EX (&ev)) - g_message ("create_component(): Could not unref the calendar component factory"); + object_class->dispose = impl_dispose; + object_class->finalize = impl_finalize; - CORBA_exception_free (&ev); + epv->createControls = impl_createControls; } -/* Callback used when we must create a user-creatable item */ static void -sc_user_create_new_item_cb (EvolutionShellComponent *shell_component, - const char *id, - const char *parent_folder_physical_uri, - const char *parent_folder_type) +calendar_component_init (CalendarComponent *component) { - char *tmp_uri; - - if (strcmp (id, CREATE_EVENT_ID) == 0) { - if (type_is_calendar (parent_folder_type)) - create_component (parent_folder_physical_uri, - GNOME_Evolution_Calendar_CompEditorFactory_EDITOR_MODE_EVENT); - else { - tmp_uri = calendar_config_default_calendar_folder (); - create_component (tmp_uri, - GNOME_Evolution_Calendar_CompEditorFactory_EDITOR_MODE_EVENT); - g_free (tmp_uri); - } - } else if (strcmp (id, CREATE_ALLDAY_EVENT_ID) == 0) { - if (type_is_calendar (parent_folder_type)) - create_component (parent_folder_physical_uri, - GNOME_Evolution_Calendar_CompEditorFactory_EDITOR_MODE_ALLDAY_EVENT); - else { - tmp_uri = calendar_config_default_calendar_folder (); - create_component (tmp_uri, - GNOME_Evolution_Calendar_CompEditorFactory_EDITOR_MODE_ALLDAY_EVENT); - g_free (tmp_uri); - } - } else if (strcmp (id, CREATE_MEETING_ID) == 0) { - if (type_is_calendar (parent_folder_type)) - create_component (parent_folder_physical_uri, - GNOME_Evolution_Calendar_CompEditorFactory_EDITOR_MODE_MEETING); - else { - tmp_uri = calendar_config_default_calendar_folder (); - create_component (tmp_uri, - GNOME_Evolution_Calendar_CompEditorFactory_EDITOR_MODE_MEETING); - g_free (tmp_uri); + CalendarComponentPrivate *priv; + GSList *groups; + + priv = g_new0 (CalendarComponentPrivate, 1); + + priv->config_directory = g_build_filename (g_get_home_dir (), + ".evolution", "calendar", "config", + NULL); + + /* EPFIXME: Should use a custom one instead? Also we should add + * calendar_component_peek_gconf_client(). */ + priv->gconf_client = gconf_client_get_default (); + + priv->source_list = e_source_list_new_for_gconf (priv->gconf_client, + "/apps/evolution/calendar/sources"); + + /* create default calendars if there are no groups */ + groups = e_source_list_peek_groups (priv->source_list); + if (!groups) { + ESourceGroup *group; + ESource *source; + char *base_uri, *new_dir; + + /* create the source group */ + base_uri = g_build_filename (g_get_home_dir (), + "/.evolution/calendar/local/OnThisComputer/", + NULL); + group = e_source_group_new (_("On This Computer"), base_uri); + e_source_list_add_group (priv->source_list, group, -1); + + /* migrate calendars from older setup */ + if (!migrate_old_calendars (group)) { + /* create default calendars */ + new_dir = g_build_filename (base_uri, "Personal/", NULL); + if (!e_mkdir_hier (new_dir, 0700)) { + source = e_source_new (_("Personal"), "Personal"); + e_source_group_add_source (group, source, -1); + } + g_free (new_dir); + + new_dir = g_build_filename (base_uri, "Work/", NULL); + if (!e_mkdir_hier (new_dir, 0700)) { + source = e_source_new (_("Work"), "Work"); + e_source_group_add_source (group, source, -1); + } + g_free (new_dir); } - } else if (strcmp (id, CREATE_TASK_ID) == 0) { - if (type_is_tasks (parent_folder_type)) - create_component (parent_folder_physical_uri, - GNOME_Evolution_Calendar_CompEditorFactory_EDITOR_MODE_TODO); - else { - tmp_uri = calendar_config_default_tasks_folder (); - create_component (tmp_uri, - GNOME_Evolution_Calendar_CompEditorFactory_EDITOR_MODE_TODO); - g_free (tmp_uri); - } - } else - g_assert_not_reached (); -} - -/* The factory function. */ - -static void -add_creatable_item (EvolutionShellComponent *shell_component, - const char *id, - const char *description, - const char *menu_description, - const char *tooltip, - const char *folder_type, - char menu_shortcut, - const char *icon_name) -{ - char *icon_path; - GdkPixbuf *icon; - - if (icon_name == NULL) { - icon_path = NULL; - icon = NULL; - } else { - icon_path = g_concat_dir_and_file (EVOLUTION_IMAGESDIR, icon_name); - icon = gdk_pixbuf_new_from_file (icon_path, NULL); + g_free (base_uri); } - evolution_shell_component_add_user_creatable_item (shell_component, - id, - description, - menu_description, - tooltip, - folder_type, - menu_shortcut, - icon); - - if (icon != NULL) - gdk_pixbuf_unref (icon); - g_free (icon_path); + component->priv = priv; } -static BonoboObject * -create_object (void) -{ - EvolutionShellComponent *shell_component; - CalendarOfflineHandler *offline_handler; - - shell_component = evolution_shell_component_new (folder_types, - NULL, - create_view, - create_folder, - remove_folder, - xfer_folder, - NULL, /* populate_folder_context_menu_fn */ - NULL, /* unpopulate_folder_context_menu_fn */ - NULL, /* get_dnd_selection_fn */ - request_quit, - NULL /* closure */); - - /* Offline handler */ - offline_handler = calendar_offline_handler_new (); - bonobo_object_add_interface (BONOBO_OBJECT (shell_component), - BONOBO_OBJECT (offline_handler)); - - g_signal_connect (shell_component, "owner_set", G_CALLBACK (owner_set_cb), NULL); - g_signal_connect (shell_component, "owner_unset", G_CALLBACK (owner_unset_cb), NULL); - - /* User creatable items */ - add_creatable_item (shell_component, CREATE_EVENT_ID, - _("New appointment"), _("_Appointment"), - _("Create a new appointment"), - FOLDER_CALENDAR, 'a', "new_appointment.xpm"); +/* Public API. */ - add_creatable_item (shell_component, CREATE_MEETING_ID, - _("New meeting"), _("M_eeting"), - _("Create a new meeting request"), - FOLDER_CALENDAR, 'e', "meeting-request-16.png"); - - add_creatable_item (shell_component, CREATE_TASK_ID, - _("New task"), _("_Task"), - _("Create a new task"), - FOLDER_TASKS, 't', "new_task-16.png"); +CalendarComponent * +calendar_component_peek (void) +{ + static CalendarComponent *component = NULL; - add_creatable_item (shell_component, CREATE_ALLDAY_EVENT_ID, - _("New All Day Appointment"), _("All _Day Appointment"), - _("Create a new all-day appointment"), - FOLDER_CALENDAR, 'd', "new_all_day_event.png"); + if (component == NULL) { + component = g_object_new (calendar_component_get_type (), NULL); - g_signal_connect (shell_component, "user_create_new_item", - G_CALLBACK (sc_user_create_new_item_cb), NULL); + if (e_mkdir_hier (calendar_component_peek_config_directory (component), 0777) != 0) { + g_warning ("Cannot create directory %s: %s", + calendar_component_peek_config_directory (component), + g_strerror (errno)); + g_object_unref (component); + component = NULL; + } + } - return BONOBO_OBJECT (shell_component); + return component; } - -BonoboObject * -calendar_component_get_object (void) +const char * +calendar_component_peek_config_directory (CalendarComponent *component) { - static BonoboObject *object = NULL; + return component->priv->config_directory; +} - if (object != NULL) { - bonobo_object_ref (BONOBO_OBJECT (object)); - } else { - object = create_object (); - g_object_add_weak_pointer (G_OBJECT (object), (void *) &object); - } - return object; -} +BONOBO_TYPE_FUNC_FULL (CalendarComponent, GNOME_Evolution_Component, PARENT_TYPE, calendar_component) diff --git a/calendar/gui/calendar-component.h b/calendar/gui/calendar-component.h index 2d94920adc..96630add5f 100644 --- a/calendar/gui/calendar-component.h +++ b/calendar/gui/calendar-component.h @@ -1,7 +1,7 @@ /* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */ -/* component-factory.h +/* calendar-component.h * - * Copyright (C) 2000, 2001, 2002, 2003 Ximian, Inc. + * Copyright (C) 2003 Ettore Perazzoli * * This program is free software; you can redistribute it and/or * modify it under the terms of version 2 of the GNU General Public @@ -20,13 +20,47 @@ * Author: Ettore Perazzoli */ -#ifndef _COMPONENT_FACTORY_H_ -#define _COMPONENT_FACTORY_H_ +#ifndef _CALENDAR_COMPONENT_H_ +#define _CALENDAR_COMPONENT_H_ + #include -extern char *evolution_dir; +#include "Evolution.h" +#include "e-util/e-source-list.h" + + +#define CALENDAR_TYPE_COMPONENT (calendar_component_get_type ()) +#define CALENDAR_COMPONENT(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), CALENDAR_TYPE_COMPONENT, CalendarComponent)) +#define CALENDAR_COMPONENT_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), CALENDAR_TYPE_COMPONENT, CalendarComponentClass)) +#define CALENDAR_IS_COMPONENT(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), CALENDAR_TYPE_COMPONENT)) +#define CALENDAR_IS_COMPONENT_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((obj), CALENDAR_TYPE_COMPONENT)) + + +typedef struct _CalendarComponent CalendarComponent; +typedef struct _CalendarComponentPrivate CalendarComponentPrivate; +typedef struct _CalendarComponentClass CalendarComponentClass; + +struct _CalendarComponent { + BonoboObject parent; + + CalendarComponentPrivate *priv; +}; + +struct _CalendarComponentClass { + BonoboObjectClass parent_class; + + POA_GNOME_Evolution_Component__epv epv; +}; + + +GType calendar_component_get_type (void); + +CalendarComponent *calendar_component_peek (void); + +const char *calendar_component_peek_config_directory (CalendarComponent *component); + +ESourceList *calendar_component_peek_source_list (CalendarComponent *component); -BonoboObject *calendar_component_get_object (void); -#endif /* _COMPONENT_FACTORY_H_ */ +#endif /* _CALENDAR_COMPONENT_H_ */ diff --git a/calendar/gui/calendar-offline-handler.c b/calendar/gui/calendar-offline-handler.c index 458f951d9a..ff30299746 100644 --- a/calendar/gui/calendar-offline-handler.c +++ b/calendar/gui/calendar-offline-handler.c @@ -29,6 +29,7 @@ #include #include #include +#include #include #include "e-util/e-url.h" #include @@ -180,13 +181,16 @@ backend_go_offline (gpointer data, gpointer user_data) char *uri = data; CalClient *client; gboolean success; + GError *error = NULL; - client = cal_client_new (); + client = cal_client_new (uri, CALOBJ_TYPE_ANY); g_signal_connect (client, "cal_opened", G_CALLBACK (backend_cal_opened_offline), offline_handler); - success = cal_client_open_calendar (client, uri, TRUE); + success = cal_client_open (client, TRUE, &error); if (!success) { + g_warning (_("backend_go_offline(): %s"), error->message); update_offline (offline_handler); g_object_unref (client); + g_error_free (error); return; } } @@ -198,13 +202,16 @@ backend_go_online (gpointer data, gpointer user_data) char *uri = data; CalClient *client; gboolean success; + GError *error = NULL; - client = cal_client_new (); + client = cal_client_new (uri, CALOBJ_TYPE_ANY); g_signal_connect (G_OBJECT (client), "cal_opened", G_CALLBACK (backend_cal_opened_online), offline_handler); - success = cal_client_open_calendar (client, uri, TRUE); + success = cal_client_open (client, TRUE, &error); if (!success) { + g_warning (_("backend_go_online(): %s"), error->message); g_object_unref (G_OBJECT (client)); + g_error_free (error); return; } } @@ -319,7 +326,8 @@ calendar_offline_handler_init (CalendarOfflineHandler *offline_handler) priv = g_new (CalendarOfflineHandlerPrivate, 1); offline_handler->priv = priv; - priv->client = cal_client_new (); + /* FIXME: what URI to use? */ + priv->client = cal_client_new ("", CALOBJ_TYPE_ANY); priv->listener_interface = CORBA_OBJECT_NIL; priv->is_offline = FALSE; } diff --git a/calendar/gui/comp-editor-factory.c b/calendar/gui/comp-editor-factory.c index f76e0d4f03..7b7dcb4c87 100644 --- a/calendar/gui/comp-editor-factory.c +++ b/calendar/gui/comp-editor-factory.c @@ -241,39 +241,26 @@ edit_existing (OpenClient *oc, const char *uid) { CalComponent *comp; icalcomponent *icalcomp; - CalClientGetStatus status; CompEditor *editor; CalComponentVType vtype; g_assert (oc->open); /* Get the object */ + if (!cal_client_get_object (oc->client, uid, NULL, &icalcomp, NULL)) { + /* FIXME Better error handling */ + g_warning (G_STRLOC ": Syntax error while getting component `%s'", uid); - status = cal_client_get_object (oc->client, uid, &icalcomp); - - switch (status) { - case CAL_CLIENT_GET_SUCCESS: - comp = cal_component_new (); - if (!cal_component_set_icalcomponent (comp, icalcomp)) { - g_object_unref (comp); - icalcomponent_free (icalcomp); - return; - } - break; - - case CAL_CLIENT_GET_NOT_FOUND: - /* The object disappeared from the server */ - return; - - case CAL_CLIENT_GET_SYNTAX_ERROR: - g_message ("edit_exiting(): Syntax error while getting component `%s'", uid); return; - - default: - g_assert_not_reached (); + } + + comp = cal_component_new (); + if (!cal_component_set_icalcomponent (comp, icalcomp)) { + g_object_unref (comp); + icalcomponent_free (icalcomp); return; } - + /* Create the appropriate type of editor */ vtype = cal_component_get_vtype (comp); @@ -405,13 +392,15 @@ resolve_pending_requests (OpenClient *oc) factory = oc->factory; priv = factory->priv; - g_assert (oc->pending != NULL); + if (!oc->pending) + return; /* Set the default timezone in the backend. */ location = calendar_config_get_timezone (); zone = icaltimezone_get_builtin_timezone (location); if (zone) - cal_client_set_default_timezone (oc->client, zone); + /* FIXME Error handling? */ + cal_client_set_default_timezone (oc->client, zone, NULL); for (l = oc->pending; l; l = l->next) { Request *request; @@ -501,10 +490,11 @@ open_client (CompEditorFactory *factory, const char *uristr) CompEditorFactoryPrivate *priv; CalClient *client; OpenClient *oc; + GError *error = NULL; priv = factory->priv; - client = cal_client_new (); + client = cal_client_new (uristr, CALOBJ_TYPE_ANY); if (!client) return NULL; @@ -522,10 +512,12 @@ open_client (CompEditorFactory *factory, const char *uristr) g_hash_table_insert (priv->uri_client_hash, oc->uri, oc); - if (!cal_client_open_calendar (oc->client, uristr, FALSE)) { + if (!cal_client_open (oc->client, FALSE, &error)) { + g_warning (_("open_client(): %s"), error->message); g_free (oc->uri); g_object_unref (oc->client); g_free (oc); + g_error_free (error); return NULL; } diff --git a/calendar/gui/comp-util.c b/calendar/gui/comp-util.c index 28bc66bd54..aceff667c2 100644 --- a/calendar/gui/comp-util.c +++ b/calendar/gui/comp-util.c @@ -95,7 +95,6 @@ cal_comp_util_compare_event_timezones (CalComponent *comp, CalClient *client, icaltimezone *zone) { - CalClientGetStatus status; CalComponentDateTime start_datetime, end_datetime; const char *tzid; gboolean retval = FALSE; @@ -143,10 +142,8 @@ cal_comp_util_compare_event_timezones (CalComponent *comp, /* If the TZIDs differ, we have to compare the UTC offsets of the start and end times, using their own timezones and the given timezone. */ - status = cal_client_get_timezone (client, - start_datetime.tzid, - &start_zone); - if (status != CAL_CLIENT_GET_SUCCESS) + if (!cal_client_get_timezone (client, start_datetime.tzid, + &start_zone, NULL)) goto out; if (start_datetime.value) { @@ -160,10 +157,8 @@ cal_comp_util_compare_event_timezones (CalComponent *comp, goto out; } - status = cal_client_get_timezone (client, - end_datetime.tzid, - &end_zone); - if (status != CAL_CLIENT_GET_SUCCESS) + if (!cal_client_get_timezone (client, end_datetime.tzid, + &end_zone, NULL)) goto out; if (end_datetime.value) { @@ -210,8 +205,8 @@ gboolean cal_comp_is_on_server (CalComponent *comp, CalClient *client) { const char *uid; - CalClientGetStatus status; icalcomponent *icalcomp; + GError *error = NULL; g_return_val_if_fail (comp != NULL, FALSE); g_return_val_if_fail (IS_CAL_COMPONENT (comp), FALSE); @@ -226,24 +221,15 @@ cal_comp_is_on_server (CalComponent *comp, CalClient *client) */ cal_component_get_uid (comp, &uid); - status = cal_client_get_object (client, uid, &icalcomp); - - switch (status) { - case CAL_CLIENT_GET_SUCCESS: + if (cal_client_get_object (client, uid, NULL, &icalcomp, &error)) { icalcomponent_free (icalcomp); - return TRUE; - case CAL_CLIENT_GET_SYNTAX_ERROR: - g_message ("confirm_delete_empty_appointment(): Syntax error when getting " - "object `%s'", - uid); return TRUE; + } - case CAL_CLIENT_GET_NOT_FOUND: - return FALSE; - - default: - g_assert_not_reached (); + if (error) { + g_warning ("cal_comp_is_on_server(): %s", error->message); + g_error_free (error); } return FALSE; @@ -268,7 +254,7 @@ cal_comp_event_new_with_defaults (CalClient *client) icalproperty *icalprop; CalAlarmTrigger trigger; - if (cal_client_get_default_object (client, CALOBJ_TYPE_EVENT, &icalcomp) != CAL_CLIENT_GET_SUCCESS) + if (!cal_client_get_default_object (client, &icalcomp, NULL)) return NULL; comp = cal_component_new (); @@ -334,8 +320,16 @@ cal_comp_task_new_with_defaults (CalClient *client) CalComponent *comp; icalcomponent *icalcomp; - if (cal_client_get_default_object (client, CALOBJ_TYPE_TODO, &icalcomp) != CAL_CLIENT_GET_SUCCESS) + if (!cal_client_get_default_object (client, &icalcomp, NULL)) + return NULL; + + comp = cal_component_new (); + if (!cal_component_set_icalcomponent (comp, icalcomp)) { + g_object_unref (comp); + icalcomponent_free (icalcomp); + return NULL; + } comp = cal_component_new (); if (!cal_component_set_icalcomponent (comp, icalcomp)) { diff --git a/calendar/gui/control-factory.c b/calendar/gui/control-factory.c index 191a8d85ea..7adc5e83df 100644 --- a/calendar/gui/control-factory.c +++ b/calendar/gui/control-factory.c @@ -69,8 +69,11 @@ get_prop (BonoboPropertyBag *bag, CORBA_Environment *ev, gpointer user_data) { - GnomeCalendar *gcal = user_data; + GnomeCalendar *gcal; const char *uri; + BonoboControl *control = user_data; + + gcal = (GnomeCalendar *) bonobo_control_get_widget (control); switch (arg_id) { @@ -96,6 +99,7 @@ get_prop (BonoboPropertyBag *bag, case GNOME_CAL_LIST_VIEW: BONOBO_ARG_SET_STRING (arg, "list"); break; + default: } break; @@ -104,7 +108,6 @@ get_prop (BonoboPropertyBag *bag, } } - static void set_prop (BonoboPropertyBag *bag, const BonoboArg *arg, @@ -112,14 +115,19 @@ set_prop (BonoboPropertyBag *bag, CORBA_Environment *ev, gpointer user_data) { - GnomeCalendar *gcal = user_data; + GnomeCalendar *gcal; char *string; GnomeCalendarViewType view; + BonoboControl *control = user_data; + + gcal = (GnomeCalendar *) bonobo_control_get_widget (control); switch (arg_id) { case PROPERTY_CALENDAR_URI_IDX: string = BONOBO_ARG_GET_STRING (arg); - if (!gnome_calendar_open (gcal, string)) { + if (gnome_calendar_add_event_uri (gcal, string)) { + calendar_control_sensitize_calendar_commands (control, gcal, TRUE); + } else { char *msg; msg = g_strdup_printf (_("Could not open the folder in '%s'"), string); @@ -161,7 +169,7 @@ calendar_properties_init (GnomeCalendar *gcal, BonoboControl *control) { BonoboPropertyBag *pbag; - pbag = bonobo_property_bag_new (get_prop, set_prop, gcal); + pbag = bonobo_property_bag_new (get_prop, set_prop, control); bonobo_property_bag_add (pbag, PROPERTY_CALENDAR_URI, diff --git a/calendar/gui/control-factory.h b/calendar/gui/control-factory.h index f599f7b3b8..bab1611c03 100644 --- a/calendar/gui/control-factory.h +++ b/calendar/gui/control-factory.h @@ -23,6 +23,8 @@ #ifndef _CONTROL_FACTORY_H_ #define _CONTROL_FACTORY_H_ +#include + BonoboControl *control_factory_new_control (void); #endif /* _CONTROL_FACTORY_H_ */ diff --git a/calendar/gui/dialogs/Makefile.am b/calendar/gui/dialogs/Makefile.am index 2466ffaa14..84424f8cc0 100644 --- a/calendar/gui/dialogs/Makefile.am +++ b/calendar/gui/dialogs/Makefile.am @@ -61,6 +61,8 @@ libcal_dialogs_la_SOURCES = \ event-page.h \ meeting-page.c \ meeting-page.h \ + new-calendar.c \ + new-calendar.h \ recurrence-page.c \ recurrence-page.h \ recur-comp.c \ @@ -85,6 +87,7 @@ glade_DATA = \ e-delegate-dialog.glade \ event-page.glade \ meeting-page.glade \ + new-calendar.glade \ recurrence-page.glade \ schedule-page.glade \ task-details-page.glade \ diff --git a/calendar/gui/dialogs/alarm-options.c b/calendar/gui/dialogs/alarm-options.c index ef13b78b13..b105dc3c23 100644 --- a/calendar/gui/dialogs/alarm-options.c +++ b/calendar/gui/dialogs/alarm-options.c @@ -39,7 +39,7 @@ #include #include #include -#include +#include #include "Evolution-Addressbook-SelectNames.h" #include "e-util/e-dialog-widgets.h" #include "alarm-options.h" @@ -307,7 +307,7 @@ alarm_to_malarm_widgets (Dialog *dialog, CalComponentAlarm *alarm) CalComponentText description; GtkTextBuffer *text_buffer; GSList *attendee_list, *l; - EDestination **destv; + EABDestination **destv; int len, i; /* Recipients */ @@ -315,22 +315,22 @@ alarm_to_malarm_widgets (Dialog *dialog, CalComponentAlarm *alarm) len = g_slist_length (attendee_list); if (len <= 0) { - destv = g_new0 (EDestination *, 2); - destv[0] = e_destination_new (); - e_destination_set_email (destv[0], dialog->email); + destv = g_new0 (EABDestination *, 2); + destv[0] = eab_destination_new (); + eab_destination_set_email (destv[0], dialog->email); destv[1] = NULL; len = 1; } else { - destv = g_new0 (EDestination *, len + 1); + destv = g_new0 (EABDestination *, len + 1); for (l = attendee_list, i = 0; l != NULL; l = l->next, i++) { CalComponentAttendee *a = l->data; - EDestination *dest; + EABDestination *dest; - dest = e_destination_new (); + dest = eab_destination_new (); if (a->cn != NULL && *a->cn) - e_destination_set_name (dest, a->cn); + eab_destination_set_name (dest, a->cn); if (a->value != NULL && *a->value) - e_destination_set_email (dest, a->value); + eab_destination_set_email (dest, a->value); destv[i] = dest; } @@ -338,7 +338,7 @@ alarm_to_malarm_widgets (Dialog *dialog, CalComponentAlarm *alarm) } bonobo_widget_set_property (BONOBO_WIDGET (dialog->malarm_addresses), - "destinations", e_destination_exportv (destv), NULL); + "destinations", eab_destination_exportv (destv), NULL); for (i = 0; i < len; i++) g_object_unref (GTK_OBJECT (destv[i])); @@ -617,7 +617,7 @@ malarm_widgets_to_alarm (Dialog *dialog, CalComponentAlarm *alarm) char *str; CalComponentText description; GSList *attendee_list = NULL; - EDestination **destv; + EABDestination **destv; GtkTextBuffer *text_buffer; GtkTextIter text_iter_start, text_iter_end; icalcomponent *icalcomp; @@ -627,18 +627,18 @@ malarm_widgets_to_alarm (Dialog *dialog, CalComponentAlarm *alarm) /* Attendees */ bonobo_widget_get_property (BONOBO_WIDGET (dialog->malarm_addresses), "destinations", TC_CORBA_string, &str, NULL); - destv = e_destination_importv (str); + destv = eab_destination_importv (str); g_free (str); for (i = 0; destv[i] != NULL; i++) { - EDestination *dest; + EABDestination *dest; CalComponentAttendee *a; dest = destv[i]; a = g_new0 (CalComponentAttendee, 1); - a->value = e_destination_get_email (dest); - a->cn = e_destination_get_name (dest); + a->value = eab_destination_get_email (dest); + a->cn = eab_destination_get_name (dest); attendee_list = g_slist_append (attendee_list, a); } @@ -646,7 +646,7 @@ malarm_widgets_to_alarm (Dialog *dialog, CalComponentAlarm *alarm) cal_component_alarm_set_attendee_list (alarm, attendee_list); cal_component_free_attendee_list (attendee_list); - e_destination_freev (destv); + eab_destination_freev (destv); /* Description */ text_buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (dialog->dalarm_description)); diff --git a/calendar/gui/e-cal-model-calendar.c b/calendar/gui/e-cal-model-calendar.c index 82de4e6d5a..593d342e70 100644 --- a/calendar/gui/e-cal-model-calendar.c +++ b/calendar/gui/e-cal-model-calendar.c @@ -129,7 +129,7 @@ get_dtend (ECalModelComponent *comp_data) /* FIXME: handle errors */ cal_client_get_timezone (comp_data->client, icaltime_get_tzid (tt_end), - &zone); + &zone, NULL); comp_data->dtend->zone = zone; } @@ -308,8 +308,12 @@ ecmc_set_value_at (ETableModel *etm, int col, int row, const void *value) break; } - if (cal_client_update_objects (comp_data->client, comp_data->icalcomp) != CAL_CLIENT_RESULT_SUCCESS) - g_message ("ecmc_set_value_at(): Could not update the object!"); + /* FIXME ask about mod type */ + if (!cal_client_modify_object (comp_data->client, comp_data->icalcomp, CALOBJ_MOD_ALL, NULL)) { + g_warning (G_STRLOC ": Could not modify the object!"); + + /* FIXME Show error dialog */ + } } static gboolean diff --git a/calendar/gui/e-cal-model-tasks.c b/calendar/gui/e-cal-model-tasks.c index 6bca52586c..76e2e140f3 100644 --- a/calendar/gui/e-cal-model-tasks.c +++ b/calendar/gui/e-cal-model-tasks.c @@ -223,7 +223,7 @@ get_completed (ECalModelComponent *comp_data) /* FIXME: handle errors */ cal_client_get_timezone (comp_data->client, icaltime_get_tzid (tt_completed), - &zone); + &zone, NULL); comp_data->completed->zone = zone; } @@ -253,7 +253,7 @@ get_due (ECalModelComponent *comp_data) /* FIXME: handle errors */ cal_client_get_timezone (comp_data->client, icaltime_get_tzid (tt_due), - &zone); + &zone, NULL); comp_data->due->zone = zone; } @@ -399,7 +399,7 @@ get_due_status (ECalModelTasks *model, ECalModelComponent *comp_data) /* Get the current time in the same timezone as the DUE date.*/ status = cal_client_get_timezone (comp_data->client, icaltime_get_tzid (due_tt), - &zone); + &zone, NULL); if (status != CAL_CLIENT_GET_SUCCESS) return E_CAL_MODEL_TASKS_DUE_FUTURE; @@ -756,8 +756,12 @@ ecmt_set_value_at (ETableModel *etm, int col, int row, const void *value) break; } - if (cal_client_update_objects (comp_data->client, comp_data->icalcomp) != CAL_CLIENT_RESULT_SUCCESS) - g_message ("ecmt_set_value_at(): Could not update the object!"); + /* FIXME ask about mod type */ + if (!cal_client_modify_object (comp_data->client, comp_data->icalcomp, CALOBJ_MOD_ALL, NULL)) { + g_warning (G_STRLOC ": Could not modify the object!"); + + /* FIXME Show error dialog */ + } } static gboolean diff --git a/calendar/gui/e-cal-model.c b/calendar/gui/e-cal-model.c index 1c231f9c72..c8b706c66e 100644 --- a/calendar/gui/e-cal-model.c +++ b/calendar/gui/e-cal-model.c @@ -41,6 +41,9 @@ struct _ECalModelPrivate { /* The list of clients we are managing. Each element is of type ECalModelClient */ GList *clients; + /* The default client in the list */ + CalClient *default_client; + /* Array for storing the objects. Each element is of type ECalModelComponent */ GPtrArray *objects; @@ -352,7 +355,7 @@ get_dtstart (ECalModel *model, ECalModelComponent *comp_data) /* FIXME: handle errors */ cal_client_get_timezone (comp_data->client, icaltime_get_tzid (tt_start), - &zone); + &zone, NULL); comp_data->dtstart->zone = zone; } @@ -609,8 +612,12 @@ ecm_set_value_at (ETableModel *etm, int col, int row, const void *value) break; } - if (cal_client_update_objects (comp_data->client, comp_data->icalcomp) != CAL_CLIENT_RESULT_SUCCESS) - g_message ("ecm_set_value_at(): Could not update the object!"); + /* FIXME ask about mod type */ + if (!cal_client_modify_object (comp_data->client, comp_data->icalcomp, CALOBJ_MOD_ALL, NULL)) { + g_warning (G_STRLOC ": Could not modify the object!"); + + /* FIXME Show error dialog */ + } } static gboolean @@ -673,7 +680,10 @@ ecm_append_row (ETableModel *etm, ETableModel *source, int row) model_class->fill_component_from_model (model, &comp_data, source_model, row); } - if (cal_client_update_objects (comp_data.client, comp_data.icalcomp) != CAL_CLIENT_RESULT_SUCCESS) { + + if (!cal_client_create_object (comp_data.client, comp_data.icalcomp, NULL, NULL)) { + g_warning (G_STRLOC ": Could not create the object!"); + /* FIXME: show error dialog */ } @@ -987,46 +997,53 @@ CalClient * e_cal_model_get_default_client (ECalModel *model) { ECalModelPrivate *priv; - GList *l; - gchar *default_uri = NULL; - EConfigListener *db; ECalModelClient *client_data; + g_return_val_if_fail (model != NULL, NULL); g_return_val_if_fail (E_IS_CAL_MODEL (model), NULL); - + priv = model->priv; + /* we always return a valid CalClient, since we rely on it in many places */ + if (priv->default_client) + return priv->default_client; + if (!priv->clients) return NULL; - db = e_config_listener_new (); + client_data = (ECalModelClient *) priv->clients->data; - /* look at the configuration and return the real default calendar if we've got it loaded */ - if (priv->kind == ICAL_VEVENT_COMPONENT) - default_uri = e_config_listener_get_string (db, "/apps/evolution/shell/default_folders/calendar_uri"); - else if (priv->kind == ICAL_VTODO_COMPONENT) - default_uri = e_config_listener_get_string (db, "/apps/evolution/shell/default_folders/tasks_uri"); + return client_data ? client_data->client : NULL; +} - g_object_unref (db); +void +e_cal_model_set_default_client (ECalModel *model, CalClient *client) +{ + ECalModelPrivate *priv; + GList *l; + gboolean found = FALSE; + + g_return_if_fail (model != NULL); + g_return_if_fail (E_IS_CAL_MODEL (model)); + g_return_if_fail (client != NULL); + g_return_if_fail (IS_CAL_CLIENT (client)); - if (!default_uri) { - client_data = (ECalModelClient *) priv->clients->data; - return client_data->client; - } + priv = model->priv; + /* See if we already know about the client */ for (l = priv->clients; l != NULL; l = l->next) { - client_data = (ECalModelClient *) l->data; + ECalModelClient *client_data = l->data; - if (!strcmp (default_uri, cal_client_get_uri (client_data->client))) { - g_free (default_uri); - return client_data->client; - } + if (client == client_data->client) + found = TRUE; } - g_free (default_uri); - - client_data = (ECalModelClient *) priv->clients->data; - return client_data->client; + /* If its not found, add it */ + if (!found) + e_cal_model_add_client (model, client); + + /* Store the default client */ + priv->default_client = client; } /** @@ -1048,6 +1065,29 @@ e_cal_model_get_client_list (ECalModel *model) return list; } +/** + * e_cal_model_get_client_for_uri + * @model: A calendar model. + * @uri: Uri for the client to get. + */ +CalClient * +e_cal_model_get_client_for_uri (ECalModel *model, const char *uri) +{ + GList *l; + + g_return_val_if_fail (E_IS_CAL_MODEL (model), NULL); + g_return_val_if_fail (uri != NULL, NULL); + + for (l = model->priv->clients; l != NULL; l = l->next) { + ECalModelClient *client_data = (ECalModelClient *) l->data; + + if (!strcmp (uri, cal_client_get_uri (client_data->client))) + return client_data->client; + } + + return NULL; +} + static ECalModelComponent * search_by_uid_and_client (ECalModelPrivate *priv, CalClient *client, const char *uid) { @@ -1084,124 +1124,119 @@ get_position_in_array (GPtrArray *objects, gpointer item) } static void -query_obj_updated_cb (CalQuery *query, const char *uid, - gboolean query_in_progress, - int n_scanned, int total, - gpointer user_data) +query_objects_added_cb (CalQuery *query, GList *objects, gpointer user_data) { - ECalModelPrivate *priv; - icalcomponent *new_icalcomp; - CalClientGetStatus status; - ECalModelComponent *comp_data; - gint pos; ECalModel *model = (ECalModel *) user_data; - - g_return_if_fail (E_IS_CAL_MODEL (model)); - + ECalModelPrivate *priv; + GList *l; + int start_row; + priv = model->priv; e_table_model_pre_change (E_TABLE_MODEL (model)); - comp_data = search_by_uid_and_client (priv, cal_query_get_client (query), uid); - status = cal_client_get_object (cal_query_get_client (query), uid, &new_icalcomp); - switch (status) { - case CAL_CLIENT_GET_SUCCESS : - if (comp_data) { - if (comp_data->icalcomp) - icalcomponent_free (comp_data->icalcomp); - if (comp_data->dtstart) { - g_free (comp_data->dtstart); - comp_data->dtstart = NULL; - } - if (comp_data->dtend) { - g_free (comp_data->dtend); - comp_data->dtend = NULL; - } - if (comp_data->due) { - g_free (comp_data->due); - comp_data->due = NULL; - } - if (comp_data->completed) { - g_free (comp_data->completed); - comp_data->completed = NULL; - } + start_row = priv->objects->len ? priv->objects->len - 1 : 0; + + for (l = objects; l; l = l->next) { + ECalModelComponent *comp_data; - comp_data->icalcomp = new_icalcomp; + comp_data = g_new0 (ECalModelComponent, 1); + comp_data->client = cal_query_get_client (query); + comp_data->icalcomp = icalcomponent_new_clone (l->data); - e_table_model_row_changed (E_TABLE_MODEL (model), get_position_in_array (priv->objects, comp_data)); - } else { - comp_data = g_new0 (ECalModelComponent, 1); - comp_data->client = cal_query_get_client (query); - comp_data->icalcomp = new_icalcomp; + g_ptr_array_add (priv->objects, comp_data); + } - g_ptr_array_add (priv->objects, comp_data); - e_table_model_row_inserted (E_TABLE_MODEL (model), priv->objects->len - 1); - } - break; - case CAL_CLIENT_GET_NOT_FOUND : - case CAL_CLIENT_GET_SYNTAX_ERROR : - if (comp_data) { - /* Nothing; the object may have been removed from the server. We just - notify that the old object was deleted. - */ - pos = get_position_in_array (priv->objects, comp_data); + e_table_model_rows_inserted (E_TABLE_MODEL (model), start_row, priv->objects->len - start_row); +} - g_ptr_array_remove (priv->objects, comp_data); - free_comp_data (comp_data); +static void +query_objects_modified_cb (CalQuery *query, GList *objects, gpointer user_data) +{ + ECalModelPrivate *priv; + ECalModel *model = (ECalModel *) user_data; + GList *l; + + priv = model->priv; - e_table_model_row_deleted (E_TABLE_MODEL (model), pos); - } else - e_table_model_no_change (E_TABLE_MODEL (model)); - break; - default : - g_assert_not_reached (); + for (l = objects; l; l = l->next) { + ECalModelComponent *comp_data; + + e_table_model_pre_change (E_TABLE_MODEL (model)); + + comp_data = search_by_uid_and_client (priv, cal_query_get_client (query), icalcomponent_get_uid (l->data)); + g_assert (comp_data); + + if (comp_data->icalcomp) + icalcomponent_free (comp_data->icalcomp); + if (comp_data->dtstart) { + g_free (comp_data->dtstart); + comp_data->dtstart = NULL; + } + if (comp_data->dtend) { + g_free (comp_data->dtend); + comp_data->dtend = NULL; + } + if (comp_data->due) { + g_free (comp_data->due); + comp_data->due = NULL; + } + if (comp_data->completed) { + g_free (comp_data->completed); + comp_data->completed = NULL; + } + + comp_data->icalcomp = icalcomponent_new_clone (l->data); + + e_table_model_row_changed (E_TABLE_MODEL (model), get_position_in_array (priv->objects, comp_data)); } } static void -query_obj_removed_cb (CalQuery *query, const char *uid, gpointer user_data) +query_objects_removed_cb (CalQuery *query, GList *uids, gpointer user_data) { - ECalModelComponent *comp_data; ECalModelPrivate *priv; ECalModel *model = (ECalModel *) user_data; - - g_return_if_fail (E_IS_CAL_MODEL (model)); - + GList *l; + priv = model->priv; - e_table_model_pre_change (E_TABLE_MODEL (model)); - - comp_data = search_by_uid_and_client (priv, cal_query_get_client (query), uid); - if (comp_data) { - gint pos = get_position_in_array (priv->objects, comp_data); + for (l = uids; l; l = l->next) { + ECalModelComponent *comp_data; + int pos; + e_table_model_pre_change (E_TABLE_MODEL (model)); + + comp_data = search_by_uid_and_client (priv, cal_query_get_client (query), l->data); + g_assert (comp_data); + + pos = get_position_in_array (priv->objects, comp_data); + g_ptr_array_remove (priv->objects, comp_data); free_comp_data (comp_data); - + e_table_model_row_deleted (E_TABLE_MODEL (model), pos); - } else - e_table_model_no_change (E_TABLE_MODEL (model)); + } } static void -query_done_cb (CalQuery *query, CalQueryDoneStatus status, const char *error_str, gpointer user_data) +query_progress_cb (CalQuery *query, const char *message, int percent, gpointer user_data) { ECalModel *model = (ECalModel *) user_data; g_return_if_fail (E_IS_CAL_MODEL (model)); - if (status != CAL_QUERY_DONE_SUCCESS) - g_warning ("query done: %s\n", error_str); + /* FIXME Update status bar */ } static void -query_eval_error_cb (CalQuery *query, const char *error_str, gpointer user_data) +query_done_cb (CalQuery *query, ECalendarStatus status, gpointer user_data) { - ECalModel *model = (ECalModel *) user_data; + ECalModel *model = (ECalModel *) user_data; g_return_if_fail (E_IS_CAL_MODEL (model)); - g_warning ("eval error: %s\n", error_str); + /* FIXME Clear status bar */ } /* Builds a complete query sexp for the calendar model by adding the predicates @@ -1248,24 +1283,28 @@ update_query_for_client (ECalModel *model, ECalModelClient *client_data) g_signal_handlers_disconnect_matched (client_data->query, G_SIGNAL_MATCH_DATA, 0, 0, NULL, NULL, model); g_object_unref (client_data->query); + client_data->query = NULL; } /* prepare the query */ g_assert (priv->sexp != NULL); real_sexp = adjust_query_sexp (model, priv->sexp); - client_data->query = cal_client_get_query (client_data->client, real_sexp); - g_free (real_sexp); + if (!cal_client_get_query (client_data->client, real_sexp, &client_data->query, NULL)) { + g_warning (G_STRLOC ": Unable to get query"); + g_free (real_sexp); - if (!client_data->query) { - g_message ("update_query_for_client(): Could not create the query"); return; - } + } + g_free (real_sexp); - g_signal_connect (client_data->query, "obj_updated", G_CALLBACK (query_obj_updated_cb), model); - g_signal_connect (client_data->query, "obj_removed", G_CALLBACK (query_obj_removed_cb), model); + g_signal_connect (client_data->query, "objects_added", G_CALLBACK (query_objects_added_cb), model); + g_signal_connect (client_data->query, "objects_modified", G_CALLBACK (query_objects_modified_cb), model); + g_signal_connect (client_data->query, "objects_removed", G_CALLBACK (query_objects_removed_cb), model); + g_signal_connect (client_data->query, "query_progress", G_CALLBACK (query_progress_cb), model); g_signal_connect (client_data->query, "query_done", G_CALLBACK (query_done_cb), model); - g_signal_connect (client_data->query, "eval_error", G_CALLBACK (query_eval_error_cb), model); + + cal_query_start (client_data->query); } static void @@ -1465,9 +1504,22 @@ e_cal_model_create_component_with_defaults (ECalModel *model) return NULL; } + if (!comp) + return icalcomponent_new (priv->kind); + icalcomp = icalcomponent_new_clone (cal_component_get_icalcomponent (comp)); g_object_unref (comp); + /* make sure the component has an UID */ + if (!icalcomponent_get_uid (icalcomp)) { + char *uid; + + uid = cal_component_gen_uid (); + icalcomponent_set_uid (icalcomp, uid); + + g_free (uid); + } + return icalcomp; } diff --git a/calendar/gui/e-cal-model.h b/calendar/gui/e-cal-model.h index ec8ab36c44..9c673ca439 100644 --- a/calendar/gui/e-cal-model.h +++ b/calendar/gui/e-cal-model.h @@ -88,7 +88,9 @@ void e_cal_model_set_default_category (ECalModel *model, const gc void e_cal_model_set_use_24_hour_format (ECalModel *model, gboolean use24); CalClient *e_cal_model_get_default_client (ECalModel *model); +void e_cal_model_set_default_client (ECalModel *model, CalClient *client); GList *e_cal_model_get_client_list (ECalModel *model); +CalClient *e_cal_model_get_client_for_uri (ECalModel *model, const char *uri); void e_cal_model_add_client (ECalModel *model, CalClient *client); void e_cal_model_remove_client (ECalModel *model, CalClient *client); void e_cal_model_remove_all_clients (ECalModel *model); diff --git a/calendar/gui/e-cal-view.c b/calendar/gui/e-cal-view.c index 381dca2542..869c8001a3 100644 --- a/calendar/gui/e-cal-view.c +++ b/calendar/gui/e-cal-view.c @@ -37,9 +37,11 @@ #include "comp-util.h" #include "e-cal-model-calendar.h" #include "e-cal-view.h" +#include "e-comp-editor-registry.h" #include "itip-utils.h" #include "dialogs/delete-comp.h" #include "dialogs/delete-error.h" +#include "dialogs/event-editor.h" #include "dialogs/send-comp.h" #include "dialogs/cancel-comp.h" #include "dialogs/recur-comp.h" @@ -70,15 +72,28 @@ struct _ECalViewPrivate { /* The timezone. */ icaltimezone *zone; + + /* The default category */ + char *default_category; }; static void e_cal_view_class_init (ECalViewClass *klass); static void e_cal_view_init (ECalView *cal_view, ECalViewClass *klass); +static void e_cal_view_get_property (GObject *object, guint property_id, GValue *value, GParamSpec *pspec); +static void e_cal_view_set_property (GObject *object, guint property_id, const GValue *value, GParamSpec *pspec); static void e_cal_view_destroy (GtkObject *object); static GObjectClass *parent_class = NULL; static GdkAtom clipboard_atom = GDK_NONE; +extern ECompEditorRegistry *comp_editor_registry; + +/* Property IDs */ +enum props { + PROP_0, + PROP_MODEL, +}; +/* FIXME Why are we emitting these event signals here? Can't the model just be listened to? */ /* Signal IDs */ enum { SELECTION_CHANGED, @@ -90,13 +105,72 @@ enum { static guint e_cal_view_signals[LAST_SIGNAL] = { 0 }; +static void +e_cal_view_set_property (GObject *object, guint property_id, const GValue *value, GParamSpec *pspec) +{ + ECalView *cal_view; + ECalViewPrivate *priv; + + cal_view = E_CAL_VIEW (object); + priv = cal_view->priv; + + switch (property_id) { + case PROP_MODEL: + e_cal_view_set_model (cal_view, E_CAL_MODEL (g_value_get_object (value))); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); + break; + } +} + +static void +e_cal_view_get_property (GObject *object, guint property_id, GValue *value, GParamSpec *pspec) +{ + ECalView *cal_view; + ECalViewPrivate *priv; + + cal_view = E_CAL_VIEW (object); + priv = cal_view->priv; + + switch (property_id) { + case PROP_MODEL: + g_value_set_object (value, e_cal_view_get_model (cal_view)); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); + break; + } +} + static void e_cal_view_class_init (ECalViewClass *klass) { + GObjectClass *gobject_class = G_OBJECT_CLASS (klass); GtkObjectClass *object_class = GTK_OBJECT_CLASS (klass); parent_class = g_type_class_peek_parent (klass); + /* Method override */ + gobject_class->set_property = e_cal_view_set_property; + gobject_class->get_property = e_cal_view_get_property; + object_class->destroy = e_cal_view_destroy; + + klass->selection_changed = NULL; + klass->event_changed = NULL; + klass->event_added = NULL; + + klass->get_selected_events = NULL; + klass->get_selected_time_range = NULL; + klass->set_selected_time_range = NULL; + klass->get_visible_time_range = NULL; + klass->update_query = NULL; + + g_object_class_install_property (gobject_class, PROP_MODEL, + g_param_spec_object ("model", NULL, NULL, E_TYPE_CAL_MODEL, + G_PARAM_READABLE | G_PARAM_WRITABLE + | G_PARAM_CONSTRUCT)); + /* Create class' signals */ e_cal_view_signals[SELECTION_CHANGED] = g_signal_new ("selection_changed", @@ -135,19 +209,6 @@ e_cal_view_class_init (ECalViewClass *klass) G_TYPE_NONE, 1, G_TYPE_POINTER); - /* Method override */ - object_class->destroy = e_cal_view_destroy; - - klass->selection_changed = NULL; - klass->event_changed = NULL; - klass->event_added = NULL; - - klass->get_selected_events = NULL; - klass->get_selected_time_range = NULL; - klass->set_selected_time_range = NULL; - klass->get_visible_time_range = NULL; - klass->update_query = NULL; - /* clipboard atom */ if (!clipboard_atom) clipboard_atom = gdk_atom_intern ("CLIPBOARD", FALSE); @@ -207,6 +268,45 @@ selection_clear_event (GtkWidget *invisible, } } +static void +selection_received_add_event (ECalView *cal_view, CalClient *client, time_t selected_time_start, + icaltimezone *default_zone, icalcomponent *icalcomp) +{ + CalComponent *comp; + struct icaltimetype itime; + time_t tt_start, tt_end; + struct icaldurationtype ic_dur; + char *uid; + + tt_start = icaltime_as_timet (icalcomponent_get_dtstart (icalcomp)); + tt_end = icaltime_as_timet (icalcomponent_get_dtend (icalcomp)); + ic_dur = icaldurationtype_from_int (tt_end - tt_start); + itime = icaltime_from_timet_with_zone (selected_time_start, FALSE, default_zone); + + icalcomponent_set_dtstart (icalcomp, itime); + itime = icaltime_add (itime, ic_dur); + icalcomponent_set_dtend (icalcomp, itime); + + /* FIXME The new uid stuff can go away once we actually set it in the backend */ + uid = cal_component_gen_uid (); + comp = cal_component_new (); + cal_component_set_icalcomponent ( + comp, icalcomponent_new_clone (icalcomp)); + cal_component_set_uid (comp, uid); + + /* FIXME Error handling */ + cal_client_create_object (client, cal_component_get_icalcomponent (comp), NULL, NULL); + if (itip_organizer_is_user (comp, client) && + send_component_dialog ((GtkWindow *) gtk_widget_get_toplevel (GTK_WIDGET (cal_view)), + client, comp, TRUE)) { + itip_send_comp (CAL_COMPONENT_METHOD_REQUEST, comp, + client, NULL); + } + + free (uid); + g_object_unref (comp); +} + static void selection_received (GtkWidget *invisible, GtkSelectionData *selection_data, @@ -216,12 +316,7 @@ selection_received (GtkWidget *invisible, char *comp_str, *default_tzid; icalcomponent *icalcomp; icalcomponent_kind kind; - CalComponent *comp; time_t selected_time_start, selected_time_end; - struct icaltimetype itime; - time_t tt_start, tt_end; - struct icaldurationtype ic_dur; - char *uid; icaltimezone *default_zone; CalClient *client; @@ -238,21 +333,21 @@ selection_received (GtkWidget *invisible, return; default_tzid = calendar_config_get_timezone (); + client = e_cal_model_get_default_client (cal_view->priv->model); - cal_client_get_timezone (client, default_tzid, &default_zone); + /* FIXME Error checking */ + cal_client_get_timezone (client, default_tzid, &default_zone, NULL); /* check the type of the component */ + /* FIXME An error dialog if we return? */ kind = icalcomponent_isa (icalcomp); - if (kind != ICAL_VCALENDAR_COMPONENT && - kind != ICAL_VEVENT_COMPONENT && - kind != ICAL_VTODO_COMPONENT && - kind != ICAL_VJOURNAL_COMPONENT) { + if (kind != ICAL_VCALENDAR_COMPONENT && kind != ICAL_VEVENT_COMPONENT) return; - } e_cal_view_set_status_message (cal_view, _("Updating objects")); e_cal_view_get_selected_time_range (cal_view, &selected_time_start, &selected_time_end); + /* FIXME Timezone handling */ if (kind == ICAL_VCALENDAR_COMPONENT) { icalcomponent_kind child_kind; icalcomponent *subcomp; @@ -260,69 +355,27 @@ selection_received (GtkWidget *invisible, subcomp = icalcomponent_get_first_component (icalcomp, ICAL_ANY_COMPONENT); while (subcomp) { child_kind = icalcomponent_isa (subcomp); - if (child_kind == ICAL_VEVENT_COMPONENT || - child_kind == ICAL_VTODO_COMPONENT || - child_kind == ICAL_VJOURNAL_COMPONENT) { - tt_start = icaltime_as_timet (icalcomponent_get_dtstart (subcomp)); - tt_end = icaltime_as_timet (icalcomponent_get_dtend (subcomp)); - ic_dur = icaldurationtype_from_int (tt_end - tt_start); - itime = icaltime_from_timet_with_zone (selected_time_start, - FALSE, default_zone); - - icalcomponent_set_dtstart (subcomp, itime); - itime = icaltime_add (itime, ic_dur); - icalcomponent_set_dtend (subcomp, itime); - - uid = cal_component_gen_uid (); - comp = cal_component_new (); - cal_component_set_icalcomponent ( - comp, icalcomponent_new_clone (subcomp)); - cal_component_set_uid (comp, uid); - - cal_client_update_object (client, comp); - if (itip_organizer_is_user (comp, client) && - send_component_dialog ((GtkWindow *) gtk_widget_get_toplevel (GTK_WIDGET (cal_view)), - client, comp, TRUE)) { - itip_send_comp (CAL_COMPONENT_METHOD_REQUEST, comp, - client, NULL); - } - - free (uid); - g_object_unref (comp); + if (child_kind == ICAL_VEVENT_COMPONENT) + selection_received_add_event (cal_view, client, selected_time_start, + default_zone, subcomp); + else if (child_kind == ICAL_VTIMEZONE_COMPONENT) { + icaltimezone *zone; + + zone = icaltimezone_new (); + icaltimezone_set_component (zone, subcomp); + cal_client_add_timezone (client, zone, NULL); + + icaltimezone_free (zone, 1); } + subcomp = icalcomponent_get_next_component ( icalcomp, ICAL_ANY_COMPONENT); } icalcomponent_free (icalcomp); - } - else { - tt_start = icaltime_as_timet (icalcomponent_get_dtstart (icalcomp)); - tt_end = icaltime_as_timet (icalcomponent_get_dtend (icalcomp)); - ic_dur = icaldurationtype_from_int (tt_end - tt_start); - itime = icaltime_from_timet_with_zone (selected_time_start, FALSE, default_zone); - - icalcomponent_set_dtstart (icalcomp, itime); - itime = icaltime_add (itime, ic_dur); - icalcomponent_set_dtend (icalcomp, itime); - - uid = cal_component_gen_uid (); - comp = cal_component_new (); - cal_component_set_icalcomponent ( - comp, icalcomponent_new_clone (icalcomp)); - cal_component_set_uid (comp, uid); - - cal_client_update_object (client, comp); - if (itip_organizer_is_user (comp, client) && - send_component_dialog ((GtkWindow *) gtk_widget_get_toplevel (GTK_WIDGET (cal_view)), - client, comp, TRUE)) { - itip_send_comp (CAL_COMPONENT_METHOD_REQUEST, comp, - client, NULL); - } - - free (uid); - g_object_unref (comp); + } else { + selection_received_add_event (cal_view, client, selected_time_start, default_zone, icalcomp); } e_cal_view_set_status_message (cal_view, NULL); @@ -334,6 +387,14 @@ e_cal_view_init (ECalView *cal_view, ECalViewClass *klass) cal_view->priv = g_new0 (ECalViewPrivate, 1); cal_view->priv->model = (ECalModel *) e_cal_model_calendar_new (); + g_signal_connect (G_OBJECT (cal_view->priv->model), "model_changed", + G_CALLBACK (model_changed_cb), cal_view); + g_signal_connect (G_OBJECT (cal_view->priv->model), "model_row_changed", + G_CALLBACK (model_row_changed_cb), cal_view); + g_signal_connect (G_OBJECT (cal_view->priv->model), "model_rows_inserted", + G_CALLBACK (model_rows_changed_cb), cal_view); + g_signal_connect (G_OBJECT (cal_view->priv->model), "model_rows_deleted", + G_CALLBACK (model_rows_changed_cb), cal_view); /* Set up the invisible widget for the clipboard selections */ cal_view->priv->invisible = gtk_invisible_new (); @@ -380,6 +441,11 @@ e_cal_view_destroy (GtkObject *object) cal_view->priv->clipboard_selection = NULL; } + if (cal_view->priv->default_category) { + g_free (cal_view->priv->default_category); + cal_view->priv->default_category = NULL; + } + g_free (cal_view->priv); cal_view->priv = NULL; } @@ -460,11 +526,35 @@ e_cal_view_set_timezone (ECalView *cal_view, icaltimezone *zone) old_zone, cal_view->priv->zone); } +const char * +e_cal_view_get_default_category (ECalView *cal_view) +{ + g_return_val_if_fail (E_IS_CAL_VIEW (cal_view), NULL); + return (const char *) cal_view->priv->default_category; +} + +/** + * e_cal_view_set_default_category + * @cal_view: A calendar view. + * @category: Default category name or NULL for no category. + * + * Sets the default category that will be used when creating new calendar + * components from the given calendar view. + */ void -e_cal_view_set_status_message (ECalView *cal_view, const gchar *message) +e_cal_view_set_default_category (ECalView *cal_view, const char *category) { - extern EvolutionShellClient *global_shell_client; /* ugly */ + g_return_if_fail (E_IS_CAL_VIEW (cal_view)); + + if (cal_view->priv->default_category) + g_free (cal_view->priv->default_category); + + cal_view->priv->default_category = g_strdup (category); +} +void +e_cal_view_set_status_message (ECalView *cal_view, const gchar *message) +{ g_return_if_fail (E_IS_CAL_VIEW (cal_view)); if (!message || !*message) { @@ -473,14 +563,19 @@ e_cal_view_set_status_message (ECalView *cal_view, const gchar *message) cal_view->priv->activity = NULL; } } else if (!cal_view->priv->activity) { +#if 0 int display; +#endif char *client_id = g_strdup_printf ("%p", cal_view); if (progress_icon[0] == NULL) progress_icon[0] = gdk_pixbuf_new_from_file (EVOLUTION_IMAGESDIR "/" EVOLUTION_CALENDAR_PROGRESS_IMAGE, NULL); + +#if 0 cal_view->priv->activity = evolution_activity_client_new ( global_shell_client, client_id, progress_icon, message, TRUE, &display); +#endif g_free (client_id); } else @@ -564,9 +659,9 @@ e_cal_view_cut_clipboard (ECalView *cal_view) e_cal_view_copy_clipboard (cal_view); for (l = selected; l != NULL; l = l->next) { CalComponent *comp; - ECalViewEvent *event = (ECalViewEvent *) l->data; - + GError *error = NULL; + if (!event) continue; @@ -580,9 +675,11 @@ e_cal_view_cut_clipboard (ECalView *cal_view) event->comp_data->client, NULL); cal_component_get_uid (comp, &uid); - delete_error_dialog (cal_client_remove_object (event->comp_data->client, uid), - CAL_COMPONENT_EVENT); + cal_client_remove_object (event->comp_data->client, uid, &error); + delete_error_dialog (error, CAL_COMPONENT_EVENT); + g_clear_error (&error); + g_object_unref (comp); } @@ -657,7 +754,8 @@ delete_event (ECalView *cal_view, ECalViewEvent *event) if (delete_component_dialog (comp, FALSE, 1, vtype, GTK_WIDGET (cal_view))) { const char *uid; - + GError *error = NULL; + if (itip_organizer_is_user (comp, event->comp_data->client) && cancel_component_dialog ((GtkWindow *) gtk_widget_get_toplevel (GTK_WIDGET (cal_view)), event->comp_data->client, @@ -670,9 +768,10 @@ delete_event (ECalView *cal_view, ECalViewEvent *event) g_object_unref (comp); return; } - - delete_error_dialog ( - cal_client_remove_object (event->comp_data->client, uid), CAL_COMPONENT_EVENT); + + cal_client_remove_object (event->comp_data->client, uid, &error); + delete_error_dialog (error, CAL_COMPONENT_EVENT); + g_clear_error (&error); } g_object_unref (comp); @@ -719,35 +818,21 @@ e_cal_view_delete_selected_occurrence (ECalView *cal_view) { ECalViewEvent *event; GList *selected; - + const char *uid; + GError *error = NULL; + selected = e_cal_view_get_selected_events (cal_view); if (!selected) return; event = (ECalViewEvent *) selected->data; - if (cal_util_component_is_instance (event->comp_data->icalcomp)) { - const char *uid; - - uid = icalcomponent_get_uid (event->comp_data->icalcomp); - delete_error_dialog ( - cal_client_remove_object_with_mod (event->comp_data->client, uid, CALOBJ_MOD_THIS), - CAL_COMPONENT_EVENT); - } else { - CalComponent *comp; + uid = icalcomponent_get_uid (event->comp_data->icalcomp); + /* FIXME: use 'rid' argument */ + cal_client_remove_object_with_mod (event->comp_data->client, uid, NULL, CALOBJ_MOD_THIS, &error); - /* we must duplicate the CalComponent, or we won't know it has changed - when we get the "update_event" signal */ - comp = cal_component_new (); - cal_component_set_icalcomponent (comp, icalcomponent_new_clone (event->comp_data->icalcomp)); - cal_comp_util_add_exdate (comp, event->start, cal_view->priv->zone); - - if (cal_client_update_object (event->comp_data->client, comp) - != CAL_CLIENT_RESULT_SUCCESS) - g_message ("e_cal_view_delete_selected_occurrence(): Could not update the object!"); - - g_object_unref (comp); - } + delete_error_dialog (error, CAL_COMPONENT_EVENT); + g_clear_error (&error); /* free memory */ g_list_free (selected); @@ -756,11 +841,9 @@ e_cal_view_delete_selected_occurrence (ECalView *cal_view) static void on_new_appointment (GtkWidget *widget, gpointer user_data) { - time_t dtstart, dtend; ECalView *cal_view = (ECalView *) user_data; - e_cal_view_get_selected_time_range (cal_view, &dtstart, &dtend); - gnome_calendar_new_appointment_for (cal_view->priv->calendar, dtstart, dtend, FALSE, FALSE); + e_cal_view_new_appointment (cal_view); } static void @@ -770,7 +853,7 @@ on_new_event (GtkWidget *widget, gpointer user_data) ECalView *cal_view = (ECalView *) user_data; e_cal_view_get_selected_time_range (cal_view, &dtstart, &dtend); - gnome_calendar_new_appointment_for (cal_view->priv->calendar, dtstart, dtend, TRUE, FALSE); + e_cal_view_new_appointment_for (cal_view, dtstart, dtend, TRUE, FALSE); } static void @@ -780,7 +863,7 @@ on_new_meeting (GtkWidget *widget, gpointer user_data) ECalView *cal_view = (ECalView *) user_data; e_cal_view_get_selected_time_range (cal_view, &dtstart, &dtend); - gnome_calendar_new_appointment_for (cal_view->priv->calendar, dtstart, dtend, FALSE, TRUE); + e_cal_view_new_appointment_for (cal_view, dtstart, dtend, FALSE, TRUE); } static void @@ -817,8 +900,8 @@ on_edit_appointment (GtkWidget *widget, gpointer user_data) ECalViewEvent *event = (ECalViewEvent *) selected->data; if (event) - gnome_calendar_edit_object (cal_view->priv->calendar, event->comp_data->client, - event->comp_data->icalcomp, FALSE); + e_cal_view_edit_appointment (cal_view, event->comp_data->client, + event->comp_data->icalcomp, FALSE); g_list_free (selected); } @@ -834,7 +917,7 @@ on_print (GtkWidget *widget, gpointer user_data) cal_view = E_CAL_VIEW (user_data); - gnome_calendar_get_current_time_range (cal_view->priv->calendar, &start, NULL); + e_cal_view_get_visible_time_range (cal_view, &start, NULL); view_type = gnome_calendar_get_view (cal_view->priv->calendar); switch (view_type) { @@ -930,7 +1013,7 @@ on_meeting (GtkWidget *widget, gpointer user_data) selected = e_cal_view_get_selected_events (cal_view); if (selected) { ECalViewEvent *event = (ECalViewEvent *) selected->data; - gnome_calendar_edit_object (cal_view->priv->calendar, event->comp_data->client, event->comp_data->icalcomp, TRUE); + e_cal_view_edit_appointment (cal_view, event->comp_data->client, event->comp_data->icalcomp, TRUE); g_list_free (selected); } @@ -962,7 +1045,7 @@ on_publish (GtkWidget *widget, gpointer user_data) ECalView *cal_view; icaltimezone *utc; time_t start = time (NULL), end; - GList *comp_list, *client_list, *cl; + GList *comp_list = NULL, *client_list, *cl; cal_view = E_CAL_VIEW (user_data); @@ -972,8 +1055,7 @@ on_publish (GtkWidget *widget, gpointer user_data) client_list = e_cal_model_get_client_list (cal_view->priv->model); for (cl = client_list; cl != NULL; cl = cl->next) { - comp_list = cal_client_get_free_busy ((CalClient *) cl->data, NULL, start, end); - if (comp_list) { + if (cal_client_get_free_busy ((CalClient *) cl->data, NULL, start, end, &comp_list, NULL)) { GList *l; for (l = comp_list; l; l = l->next) { @@ -1041,14 +1123,6 @@ on_paste (GtkWidget *widget, gpointer user_data) e_cal_view_paste_clipboard (cal_view); } -static void -on_unrecur_appointment (GtkWidget *widget, gpointer user_data) -{ - ECalView *cal_view = E_CAL_VIEW (user_data); - - gnome_calendar_unrecur_selection (cal_view->priv->calendar); -} - enum { /* * This is used to "flag" events that can not be editted @@ -1142,7 +1216,6 @@ static EPopupMenu child_items [] = { E_POPUP_SEPARATOR, E_POPUP_ITEM (N_("_Delete"), GTK_SIGNAL_FUNC (on_delete_appointment), MASK_EDITABLE | MASK_SINGLE | MASK_EDITING), - E_POPUP_ITEM (N_("Make this Occurrence _Movable"), GTK_SIGNAL_FUNC (on_unrecur_appointment), MASK_RECURRING | MASK_EDITING | MASK_EDITABLE | MASK_INSTANCE), E_POPUP_ITEM (N_("Delete this _Occurrence"), GTK_SIGNAL_FUNC (on_delete_occurrence), MASK_RECURRING | MASK_EDITING | MASK_EDITABLE), E_POPUP_ITEM (N_("Delete _All Occurrences"), GTK_SIGNAL_FUNC (on_delete_appointment), MASK_RECURRING | MASK_EDITING | MASK_EDITABLE), @@ -1209,21 +1282,18 @@ setup_popup_icons (EPopupMenu *context_menu) GtkMenu * e_cal_view_create_popup_menu (ECalView *cal_view) { - gboolean being_edited, have_selection; GList *selected; EPopupMenu *context_menu; guint32 disable_mask = 0, hide_mask = 0; GtkMenu *popup; CalClient *client = NULL; - + gboolean read_only = TRUE; + g_return_val_if_fail (E_IS_CAL_VIEW (cal_view), NULL); /* get the selection */ - being_edited = FALSE; selected = e_cal_view_get_selected_events (cal_view); - have_selection = GTK_WIDGET_HAS_FOCUS (cal_view) && selected != NULL; - if (selected == NULL) { cal_view->priv->view_menu = gnome_calendar_setup_view_popup (cal_view->priv->calendar); main_items[9].submenu = cal_view->priv->view_menu; @@ -1260,15 +1330,158 @@ e_cal_view_create_popup_menu (ECalView *cal_view) client = event->comp_data->client; } - if (cal_client_is_read_only (client)) + cal_client_is_read_only (client, &read_only, NULL); + if (read_only) disable_mask |= MASK_EDITABLE; - if (being_edited) - disable_mask |= MASK_EDITING; - setup_popup_icons (context_menu); popup = e_popup_menu_create (context_menu, disable_mask, hide_mask, cal_view); g_signal_connect (popup, "selection-done", G_CALLBACK (free_view_popup), cal_view); return popup; } + +/** + * e_cal_view_new_appointment_for + * @cal_view: A calendar view. + * @dtstart: A Unix time_t that marks the beginning of the appointment. + * @dtend: A Unix time_t that marks the end of the appointment. + * @all_day: If TRUE, the dtstart and dtend are expanded to cover + * the entire day, and the event is set to TRANSPARENT. + * @meeting: Whether the appointment is a meeting or not. + * + * Opens an event editor dialog for a new appointment. + */ +void +e_cal_view_new_appointment_for (ECalView *cal_view, + time_t dtstart, time_t dtend, + gboolean all_day, + gboolean meeting) +{ + ECalViewPrivate *priv; + struct icaltimetype itt; + CalComponentDateTime dt; + CalComponent *comp; + icalcomponent *icalcomp; + CalComponentTransparency transparency; + + g_return_if_fail (E_IS_CAL_VIEW (cal_view)); + + priv = cal_view->priv; + + dt.value = &itt; + if (all_day) + dt.tzid = NULL; + else + dt.tzid = icaltimezone_get_tzid (priv->zone); + + icalcomp = e_cal_model_create_component_with_defaults (priv->model); + comp = cal_component_new (); + cal_component_set_icalcomponent (comp, icalcomp); + + /* DTSTART, DTEND */ + itt = icaltime_from_timet_with_zone (dtstart, FALSE, priv->zone); + if (all_day) { + itt.hour = itt.minute = itt.second = 0; + itt.is_date = TRUE; + } + cal_component_set_dtstart (comp, &dt); + + itt = icaltime_from_timet_with_zone (dtend, FALSE, priv->zone); + if (all_day) { + /* We round it up to the end of the day, unless it is + already set to midnight */ + if (itt.hour != 0 || itt.minute != 0 || itt.second != 0) { + icaltime_adjust (&itt, 1, 0, 0, 0); + } + itt.hour = itt.minute = itt.second = 0; + itt.is_date = TRUE; + } + cal_component_set_dtend (comp, &dt); + + /* TRANSPARENCY */ + transparency = all_day ? CAL_COMPONENT_TRANSP_TRANSPARENT + : CAL_COMPONENT_TRANSP_OPAQUE; + cal_component_set_transparency (comp, transparency); + + /* CATEGORY */ + cal_component_set_categories (comp, priv->default_category); + + /* edit the object */ + cal_component_commit_sequence (comp); + + e_cal_view_edit_appointment (cal_view, + e_cal_model_get_default_client (priv->model), + icalcomp, meeting); + + g_object_unref (comp); +} + +/** + * e_cal_view_new_appointment + * @cal_view: A calendar view. + * + * Opens an event editor dialog for a new appointment. The appointment's + * start and end times are set to the currently selected time range in + * the calendar view. + */ +void +e_cal_view_new_appointment (ECalView *cal_view) +{ + time_t dtstart, dtend; + + g_return_if_fail (E_IS_CAL_VIEW (cal_view)); + + e_cal_view_get_selected_time_range (cal_view, &dtstart, &dtend); + e_cal_view_new_appointment_for (cal_view, dtstart, dtend, FALSE, FALSE); +} + +/** + * e_cal_view_edit_appointment + * @cal_view: A calendar view. + * @client: Calendar client. + * @icalcomp: The object to be edited. + * @meeting: Whether the appointment is a meeting or not. + * + * Opens an editor window to allow the user to edit the selected + * object. + */ +void +e_cal_view_edit_appointment (ECalView *cal_view, + CalClient *client, + icalcomponent *icalcomp, + gboolean meeting) +{ + ECalViewPrivate *priv; + CompEditor *ce; + const char *uid; + CalComponent *comp; + + g_return_if_fail (E_IS_CAL_VIEW (cal_view)); + g_return_if_fail (IS_CAL_CLIENT (client)); + g_return_if_fail (icalcomp != NULL); + + priv = cal_view->priv; + + uid = icalcomponent_get_uid (icalcomp); + + ce = e_comp_editor_registry_find (comp_editor_registry, uid); + if (!ce) { + EventEditor *ee; + + ee = event_editor_new (client); + ce = COMP_EDITOR (ee); + + comp = cal_component_new (); + cal_component_set_icalcomponent (comp, icalcomponent_new_clone (icalcomp)); + comp_editor_edit_comp (ce, comp); + if (meeting) + event_editor_show_meeting (ee); + + e_comp_editor_registry_add (comp_editor_registry, ce, FALSE); + + g_object_unref (comp); + } + + comp_editor_focus (ce); +} diff --git a/calendar/gui/e-cal-view.h b/calendar/gui/e-cal-view.h index ea7c11a00d..9a09a5236a 100644 --- a/calendar/gui/e-cal-view.h +++ b/calendar/gui/e-cal-view.h @@ -96,6 +96,8 @@ ECalModel *e_cal_view_get_model (ECalView *cal_view); void e_cal_view_set_model (ECalView *cal_view, ECalModel *model); icaltimezone *e_cal_view_get_timezone (ECalView *cal_view); void e_cal_view_set_timezone (ECalView *cal_view, icaltimezone *zone); +const char *e_cal_view_get_default_category (ECalView *cal_view); +void e_cal_view_set_default_category (ECalView *cal_view, const char *category); void e_cal_view_set_status_message (ECalView *cal_view, const gchar *message); @@ -114,6 +116,17 @@ void e_cal_view_delete_selected_occurrence (ECalView *cal_view); GtkMenu *e_cal_view_create_popup_menu (ECalView *cal_view); +void e_cal_view_new_appointment_for (ECalView *cal_view, + time_t dtstart, + time_t dtend, + gboolean all_day, + gboolean meeting); +void e_cal_view_new_appointment (ECalView *cal_view); +void e_cal_view_edit_appointment (ECalView *cal_view, + CalClient *client, + icalcomponent *icalcomp, + gboolean meeting); + G_END_DECLS #endif diff --git a/calendar/gui/e-calendar-table.c b/calendar/gui/e-calendar-table.c index 5b3f98f373..fdea4d33bb 100644 --- a/calendar/gui/e-calendar-table.c +++ b/calendar/gui/e-calendar-table.c @@ -725,10 +725,12 @@ delete_selected_components (ECalendarTable *cal_table) for (l = objs; l; l = l->next) { ECalModelComponent *comp_data = (ECalModelComponent *) l->data; - - delete_error_dialog (cal_client_remove_object (comp_data->client, - icalcomponent_get_uid (comp_data->icalcomp)), - CAL_COMPONENT_TODO); + GError *error = NULL; + + cal_client_remove_object (comp_data->client, + icalcomponent_get_uid (comp_data->icalcomp), &error); + delete_error_dialog (error, CAL_COMPONENT_TODO); + g_clear_error (&error); } e_calendar_table_set_status_message (cal_table, NULL); @@ -1052,7 +1054,8 @@ e_calendar_table_show_popup_menu (ETable *table, GtkMenu *gtk_menu; icalproperty *prop; ECalModelComponent *comp_data; - + gboolean read_only = TRUE; + n_selected = e_table_selected_count (table); if (n_selected <= 0) return TRUE; @@ -1071,7 +1074,8 @@ e_calendar_table_show_popup_menu (ETable *table, } else hide_mask = MASK_SINGLE; - if (cal_client_is_read_only (comp_data->client)) + cal_client_is_read_only (comp_data->client, &read_only, NULL); + if (!read_only) disable_mask |= MASK_EDITABLE; if (cal_client_get_static_capability (comp_data->client, CAL_STATIC_CAPABILITY_NO_TASK_ASSIGNMENT)) @@ -1315,6 +1319,7 @@ selection_received (GtkWidget *invisible, icalcomponent *icalcomp; char *uid; CalComponent *comp; + CalClient *client; icalcomponent_kind kind; g_return_if_fail (E_IS_CALENDAR_TABLE (cal_table)); @@ -1338,6 +1343,8 @@ selection_received (GtkWidget *invisible, return; } + client = e_cal_model_get_default_client (cal_table->model); + e_calendar_table_set_status_message (cal_table, _("Updating objects")); if (kind == ICAL_VCALENDAR_COMPONENT) { @@ -1360,11 +1367,12 @@ selection_received (GtkWidget *invisible, cal_component_set_icalcomponent ( tmp_comp, icalcomponent_new_clone (subcomp)); cal_component_set_uid (tmp_comp, uid); - - cal_client_update_object ( - e_cal_model_get_default_client (cal_table->model), - tmp_comp); free (uid); + + /* FIXME should we convert start/due/complete times? */ + /* FIXME Error handling */ + cal_client_create_object (client, cal_component_get_icalcomponent (tmp_comp), NULL, NULL); + g_object_unref (tmp_comp); } subcomp = icalcomponent_get_next_component ( @@ -1378,9 +1386,8 @@ selection_received (GtkWidget *invisible, cal_component_set_uid (comp, (const char *) uid); free (uid); - cal_client_update_object ( - e_cal_model_get_default_client (cal_table->model), - comp); + cal_client_create_object (client, cal_component_get_icalcomponent (comp), NULL, NULL); + g_object_unref (comp); } @@ -1433,8 +1440,6 @@ static GdkPixbuf *progress_icon[2] = { NULL, NULL }; void e_calendar_table_set_status_message (ECalendarTable *cal_table, const gchar *message) { - extern EvolutionShellClient *global_shell_client; /* ugly */ - g_return_if_fail (E_IS_CALENDAR_TABLE (cal_table)); if (!message || !*message) { @@ -1448,9 +1453,12 @@ e_calendar_table_set_status_message (ECalendarTable *cal_table, const gchar *mes if (progress_icon[0] == NULL) progress_icon[0] = gdk_pixbuf_new_from_file (EVOLUTION_IMAGESDIR "/" EVOLUTION_TASKS_PROGRESS_IMAGE, NULL); + +#if 0 /* EPFIXME */ cal_table->activity = evolution_activity_client_new ( global_shell_client, client_id, progress_icon, message, TRUE, &display); +#endif g_free (client_id); } else diff --git a/calendar/gui/e-calendar-view.c b/calendar/gui/e-calendar-view.c index 381dca2542..869c8001a3 100644 --- a/calendar/gui/e-calendar-view.c +++ b/calendar/gui/e-calendar-view.c @@ -37,9 +37,11 @@ #include "comp-util.h" #include "e-cal-model-calendar.h" #include "e-cal-view.h" +#include "e-comp-editor-registry.h" #include "itip-utils.h" #include "dialogs/delete-comp.h" #include "dialogs/delete-error.h" +#include "dialogs/event-editor.h" #include "dialogs/send-comp.h" #include "dialogs/cancel-comp.h" #include "dialogs/recur-comp.h" @@ -70,15 +72,28 @@ struct _ECalViewPrivate { /* The timezone. */ icaltimezone *zone; + + /* The default category */ + char *default_category; }; static void e_cal_view_class_init (ECalViewClass *klass); static void e_cal_view_init (ECalView *cal_view, ECalViewClass *klass); +static void e_cal_view_get_property (GObject *object, guint property_id, GValue *value, GParamSpec *pspec); +static void e_cal_view_set_property (GObject *object, guint property_id, const GValue *value, GParamSpec *pspec); static void e_cal_view_destroy (GtkObject *object); static GObjectClass *parent_class = NULL; static GdkAtom clipboard_atom = GDK_NONE; +extern ECompEditorRegistry *comp_editor_registry; + +/* Property IDs */ +enum props { + PROP_0, + PROP_MODEL, +}; +/* FIXME Why are we emitting these event signals here? Can't the model just be listened to? */ /* Signal IDs */ enum { SELECTION_CHANGED, @@ -90,13 +105,72 @@ enum { static guint e_cal_view_signals[LAST_SIGNAL] = { 0 }; +static void +e_cal_view_set_property (GObject *object, guint property_id, const GValue *value, GParamSpec *pspec) +{ + ECalView *cal_view; + ECalViewPrivate *priv; + + cal_view = E_CAL_VIEW (object); + priv = cal_view->priv; + + switch (property_id) { + case PROP_MODEL: + e_cal_view_set_model (cal_view, E_CAL_MODEL (g_value_get_object (value))); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); + break; + } +} + +static void +e_cal_view_get_property (GObject *object, guint property_id, GValue *value, GParamSpec *pspec) +{ + ECalView *cal_view; + ECalViewPrivate *priv; + + cal_view = E_CAL_VIEW (object); + priv = cal_view->priv; + + switch (property_id) { + case PROP_MODEL: + g_value_set_object (value, e_cal_view_get_model (cal_view)); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); + break; + } +} + static void e_cal_view_class_init (ECalViewClass *klass) { + GObjectClass *gobject_class = G_OBJECT_CLASS (klass); GtkObjectClass *object_class = GTK_OBJECT_CLASS (klass); parent_class = g_type_class_peek_parent (klass); + /* Method override */ + gobject_class->set_property = e_cal_view_set_property; + gobject_class->get_property = e_cal_view_get_property; + object_class->destroy = e_cal_view_destroy; + + klass->selection_changed = NULL; + klass->event_changed = NULL; + klass->event_added = NULL; + + klass->get_selected_events = NULL; + klass->get_selected_time_range = NULL; + klass->set_selected_time_range = NULL; + klass->get_visible_time_range = NULL; + klass->update_query = NULL; + + g_object_class_install_property (gobject_class, PROP_MODEL, + g_param_spec_object ("model", NULL, NULL, E_TYPE_CAL_MODEL, + G_PARAM_READABLE | G_PARAM_WRITABLE + | G_PARAM_CONSTRUCT)); + /* Create class' signals */ e_cal_view_signals[SELECTION_CHANGED] = g_signal_new ("selection_changed", @@ -135,19 +209,6 @@ e_cal_view_class_init (ECalViewClass *klass) G_TYPE_NONE, 1, G_TYPE_POINTER); - /* Method override */ - object_class->destroy = e_cal_view_destroy; - - klass->selection_changed = NULL; - klass->event_changed = NULL; - klass->event_added = NULL; - - klass->get_selected_events = NULL; - klass->get_selected_time_range = NULL; - klass->set_selected_time_range = NULL; - klass->get_visible_time_range = NULL; - klass->update_query = NULL; - /* clipboard atom */ if (!clipboard_atom) clipboard_atom = gdk_atom_intern ("CLIPBOARD", FALSE); @@ -207,6 +268,45 @@ selection_clear_event (GtkWidget *invisible, } } +static void +selection_received_add_event (ECalView *cal_view, CalClient *client, time_t selected_time_start, + icaltimezone *default_zone, icalcomponent *icalcomp) +{ + CalComponent *comp; + struct icaltimetype itime; + time_t tt_start, tt_end; + struct icaldurationtype ic_dur; + char *uid; + + tt_start = icaltime_as_timet (icalcomponent_get_dtstart (icalcomp)); + tt_end = icaltime_as_timet (icalcomponent_get_dtend (icalcomp)); + ic_dur = icaldurationtype_from_int (tt_end - tt_start); + itime = icaltime_from_timet_with_zone (selected_time_start, FALSE, default_zone); + + icalcomponent_set_dtstart (icalcomp, itime); + itime = icaltime_add (itime, ic_dur); + icalcomponent_set_dtend (icalcomp, itime); + + /* FIXME The new uid stuff can go away once we actually set it in the backend */ + uid = cal_component_gen_uid (); + comp = cal_component_new (); + cal_component_set_icalcomponent ( + comp, icalcomponent_new_clone (icalcomp)); + cal_component_set_uid (comp, uid); + + /* FIXME Error handling */ + cal_client_create_object (client, cal_component_get_icalcomponent (comp), NULL, NULL); + if (itip_organizer_is_user (comp, client) && + send_component_dialog ((GtkWindow *) gtk_widget_get_toplevel (GTK_WIDGET (cal_view)), + client, comp, TRUE)) { + itip_send_comp (CAL_COMPONENT_METHOD_REQUEST, comp, + client, NULL); + } + + free (uid); + g_object_unref (comp); +} + static void selection_received (GtkWidget *invisible, GtkSelectionData *selection_data, @@ -216,12 +316,7 @@ selection_received (GtkWidget *invisible, char *comp_str, *default_tzid; icalcomponent *icalcomp; icalcomponent_kind kind; - CalComponent *comp; time_t selected_time_start, selected_time_end; - struct icaltimetype itime; - time_t tt_start, tt_end; - struct icaldurationtype ic_dur; - char *uid; icaltimezone *default_zone; CalClient *client; @@ -238,21 +333,21 @@ selection_received (GtkWidget *invisible, return; default_tzid = calendar_config_get_timezone (); + client = e_cal_model_get_default_client (cal_view->priv->model); - cal_client_get_timezone (client, default_tzid, &default_zone); + /* FIXME Error checking */ + cal_client_get_timezone (client, default_tzid, &default_zone, NULL); /* check the type of the component */ + /* FIXME An error dialog if we return? */ kind = icalcomponent_isa (icalcomp); - if (kind != ICAL_VCALENDAR_COMPONENT && - kind != ICAL_VEVENT_COMPONENT && - kind != ICAL_VTODO_COMPONENT && - kind != ICAL_VJOURNAL_COMPONENT) { + if (kind != ICAL_VCALENDAR_COMPONENT && kind != ICAL_VEVENT_COMPONENT) return; - } e_cal_view_set_status_message (cal_view, _("Updating objects")); e_cal_view_get_selected_time_range (cal_view, &selected_time_start, &selected_time_end); + /* FIXME Timezone handling */ if (kind == ICAL_VCALENDAR_COMPONENT) { icalcomponent_kind child_kind; icalcomponent *subcomp; @@ -260,69 +355,27 @@ selection_received (GtkWidget *invisible, subcomp = icalcomponent_get_first_component (icalcomp, ICAL_ANY_COMPONENT); while (subcomp) { child_kind = icalcomponent_isa (subcomp); - if (child_kind == ICAL_VEVENT_COMPONENT || - child_kind == ICAL_VTODO_COMPONENT || - child_kind == ICAL_VJOURNAL_COMPONENT) { - tt_start = icaltime_as_timet (icalcomponent_get_dtstart (subcomp)); - tt_end = icaltime_as_timet (icalcomponent_get_dtend (subcomp)); - ic_dur = icaldurationtype_from_int (tt_end - tt_start); - itime = icaltime_from_timet_with_zone (selected_time_start, - FALSE, default_zone); - - icalcomponent_set_dtstart (subcomp, itime); - itime = icaltime_add (itime, ic_dur); - icalcomponent_set_dtend (subcomp, itime); - - uid = cal_component_gen_uid (); - comp = cal_component_new (); - cal_component_set_icalcomponent ( - comp, icalcomponent_new_clone (subcomp)); - cal_component_set_uid (comp, uid); - - cal_client_update_object (client, comp); - if (itip_organizer_is_user (comp, client) && - send_component_dialog ((GtkWindow *) gtk_widget_get_toplevel (GTK_WIDGET (cal_view)), - client, comp, TRUE)) { - itip_send_comp (CAL_COMPONENT_METHOD_REQUEST, comp, - client, NULL); - } - - free (uid); - g_object_unref (comp); + if (child_kind == ICAL_VEVENT_COMPONENT) + selection_received_add_event (cal_view, client, selected_time_start, + default_zone, subcomp); + else if (child_kind == ICAL_VTIMEZONE_COMPONENT) { + icaltimezone *zone; + + zone = icaltimezone_new (); + icaltimezone_set_component (zone, subcomp); + cal_client_add_timezone (client, zone, NULL); + + icaltimezone_free (zone, 1); } + subcomp = icalcomponent_get_next_component ( icalcomp, ICAL_ANY_COMPONENT); } icalcomponent_free (icalcomp); - } - else { - tt_start = icaltime_as_timet (icalcomponent_get_dtstart (icalcomp)); - tt_end = icaltime_as_timet (icalcomponent_get_dtend (icalcomp)); - ic_dur = icaldurationtype_from_int (tt_end - tt_start); - itime = icaltime_from_timet_with_zone (selected_time_start, FALSE, default_zone); - - icalcomponent_set_dtstart (icalcomp, itime); - itime = icaltime_add (itime, ic_dur); - icalcomponent_set_dtend (icalcomp, itime); - - uid = cal_component_gen_uid (); - comp = cal_component_new (); - cal_component_set_icalcomponent ( - comp, icalcomponent_new_clone (icalcomp)); - cal_component_set_uid (comp, uid); - - cal_client_update_object (client, comp); - if (itip_organizer_is_user (comp, client) && - send_component_dialog ((GtkWindow *) gtk_widget_get_toplevel (GTK_WIDGET (cal_view)), - client, comp, TRUE)) { - itip_send_comp (CAL_COMPONENT_METHOD_REQUEST, comp, - client, NULL); - } - - free (uid); - g_object_unref (comp); + } else { + selection_received_add_event (cal_view, client, selected_time_start, default_zone, icalcomp); } e_cal_view_set_status_message (cal_view, NULL); @@ -334,6 +387,14 @@ e_cal_view_init (ECalView *cal_view, ECalViewClass *klass) cal_view->priv = g_new0 (ECalViewPrivate, 1); cal_view->priv->model = (ECalModel *) e_cal_model_calendar_new (); + g_signal_connect (G_OBJECT (cal_view->priv->model), "model_changed", + G_CALLBACK (model_changed_cb), cal_view); + g_signal_connect (G_OBJECT (cal_view->priv->model), "model_row_changed", + G_CALLBACK (model_row_changed_cb), cal_view); + g_signal_connect (G_OBJECT (cal_view->priv->model), "model_rows_inserted", + G_CALLBACK (model_rows_changed_cb), cal_view); + g_signal_connect (G_OBJECT (cal_view->priv->model), "model_rows_deleted", + G_CALLBACK (model_rows_changed_cb), cal_view); /* Set up the invisible widget for the clipboard selections */ cal_view->priv->invisible = gtk_invisible_new (); @@ -380,6 +441,11 @@ e_cal_view_destroy (GtkObject *object) cal_view->priv->clipboard_selection = NULL; } + if (cal_view->priv->default_category) { + g_free (cal_view->priv->default_category); + cal_view->priv->default_category = NULL; + } + g_free (cal_view->priv); cal_view->priv = NULL; } @@ -460,11 +526,35 @@ e_cal_view_set_timezone (ECalView *cal_view, icaltimezone *zone) old_zone, cal_view->priv->zone); } +const char * +e_cal_view_get_default_category (ECalView *cal_view) +{ + g_return_val_if_fail (E_IS_CAL_VIEW (cal_view), NULL); + return (const char *) cal_view->priv->default_category; +} + +/** + * e_cal_view_set_default_category + * @cal_view: A calendar view. + * @category: Default category name or NULL for no category. + * + * Sets the default category that will be used when creating new calendar + * components from the given calendar view. + */ void -e_cal_view_set_status_message (ECalView *cal_view, const gchar *message) +e_cal_view_set_default_category (ECalView *cal_view, const char *category) { - extern EvolutionShellClient *global_shell_client; /* ugly */ + g_return_if_fail (E_IS_CAL_VIEW (cal_view)); + + if (cal_view->priv->default_category) + g_free (cal_view->priv->default_category); + + cal_view->priv->default_category = g_strdup (category); +} +void +e_cal_view_set_status_message (ECalView *cal_view, const gchar *message) +{ g_return_if_fail (E_IS_CAL_VIEW (cal_view)); if (!message || !*message) { @@ -473,14 +563,19 @@ e_cal_view_set_status_message (ECalView *cal_view, const gchar *message) cal_view->priv->activity = NULL; } } else if (!cal_view->priv->activity) { +#if 0 int display; +#endif char *client_id = g_strdup_printf ("%p", cal_view); if (progress_icon[0] == NULL) progress_icon[0] = gdk_pixbuf_new_from_file (EVOLUTION_IMAGESDIR "/" EVOLUTION_CALENDAR_PROGRESS_IMAGE, NULL); + +#if 0 cal_view->priv->activity = evolution_activity_client_new ( global_shell_client, client_id, progress_icon, message, TRUE, &display); +#endif g_free (client_id); } else @@ -564,9 +659,9 @@ e_cal_view_cut_clipboard (ECalView *cal_view) e_cal_view_copy_clipboard (cal_view); for (l = selected; l != NULL; l = l->next) { CalComponent *comp; - ECalViewEvent *event = (ECalViewEvent *) l->data; - + GError *error = NULL; + if (!event) continue; @@ -580,9 +675,11 @@ e_cal_view_cut_clipboard (ECalView *cal_view) event->comp_data->client, NULL); cal_component_get_uid (comp, &uid); - delete_error_dialog (cal_client_remove_object (event->comp_data->client, uid), - CAL_COMPONENT_EVENT); + cal_client_remove_object (event->comp_data->client, uid, &error); + delete_error_dialog (error, CAL_COMPONENT_EVENT); + g_clear_error (&error); + g_object_unref (comp); } @@ -657,7 +754,8 @@ delete_event (ECalView *cal_view, ECalViewEvent *event) if (delete_component_dialog (comp, FALSE, 1, vtype, GTK_WIDGET (cal_view))) { const char *uid; - + GError *error = NULL; + if (itip_organizer_is_user (comp, event->comp_data->client) && cancel_component_dialog ((GtkWindow *) gtk_widget_get_toplevel (GTK_WIDGET (cal_view)), event->comp_data->client, @@ -670,9 +768,10 @@ delete_event (ECalView *cal_view, ECalViewEvent *event) g_object_unref (comp); return; } - - delete_error_dialog ( - cal_client_remove_object (event->comp_data->client, uid), CAL_COMPONENT_EVENT); + + cal_client_remove_object (event->comp_data->client, uid, &error); + delete_error_dialog (error, CAL_COMPONENT_EVENT); + g_clear_error (&error); } g_object_unref (comp); @@ -719,35 +818,21 @@ e_cal_view_delete_selected_occurrence (ECalView *cal_view) { ECalViewEvent *event; GList *selected; - + const char *uid; + GError *error = NULL; + selected = e_cal_view_get_selected_events (cal_view); if (!selected) return; event = (ECalViewEvent *) selected->data; - if (cal_util_component_is_instance (event->comp_data->icalcomp)) { - const char *uid; - - uid = icalcomponent_get_uid (event->comp_data->icalcomp); - delete_error_dialog ( - cal_client_remove_object_with_mod (event->comp_data->client, uid, CALOBJ_MOD_THIS), - CAL_COMPONENT_EVENT); - } else { - CalComponent *comp; + uid = icalcomponent_get_uid (event->comp_data->icalcomp); + /* FIXME: use 'rid' argument */ + cal_client_remove_object_with_mod (event->comp_data->client, uid, NULL, CALOBJ_MOD_THIS, &error); - /* we must duplicate the CalComponent, or we won't know it has changed - when we get the "update_event" signal */ - comp = cal_component_new (); - cal_component_set_icalcomponent (comp, icalcomponent_new_clone (event->comp_data->icalcomp)); - cal_comp_util_add_exdate (comp, event->start, cal_view->priv->zone); - - if (cal_client_update_object (event->comp_data->client, comp) - != CAL_CLIENT_RESULT_SUCCESS) - g_message ("e_cal_view_delete_selected_occurrence(): Could not update the object!"); - - g_object_unref (comp); - } + delete_error_dialog (error, CAL_COMPONENT_EVENT); + g_clear_error (&error); /* free memory */ g_list_free (selected); @@ -756,11 +841,9 @@ e_cal_view_delete_selected_occurrence (ECalView *cal_view) static void on_new_appointment (GtkWidget *widget, gpointer user_data) { - time_t dtstart, dtend; ECalView *cal_view = (ECalView *) user_data; - e_cal_view_get_selected_time_range (cal_view, &dtstart, &dtend); - gnome_calendar_new_appointment_for (cal_view->priv->calendar, dtstart, dtend, FALSE, FALSE); + e_cal_view_new_appointment (cal_view); } static void @@ -770,7 +853,7 @@ on_new_event (GtkWidget *widget, gpointer user_data) ECalView *cal_view = (ECalView *) user_data; e_cal_view_get_selected_time_range (cal_view, &dtstart, &dtend); - gnome_calendar_new_appointment_for (cal_view->priv->calendar, dtstart, dtend, TRUE, FALSE); + e_cal_view_new_appointment_for (cal_view, dtstart, dtend, TRUE, FALSE); } static void @@ -780,7 +863,7 @@ on_new_meeting (GtkWidget *widget, gpointer user_data) ECalView *cal_view = (ECalView *) user_data; e_cal_view_get_selected_time_range (cal_view, &dtstart, &dtend); - gnome_calendar_new_appointment_for (cal_view->priv->calendar, dtstart, dtend, FALSE, TRUE); + e_cal_view_new_appointment_for (cal_view, dtstart, dtend, FALSE, TRUE); } static void @@ -817,8 +900,8 @@ on_edit_appointment (GtkWidget *widget, gpointer user_data) ECalViewEvent *event = (ECalViewEvent *) selected->data; if (event) - gnome_calendar_edit_object (cal_view->priv->calendar, event->comp_data->client, - event->comp_data->icalcomp, FALSE); + e_cal_view_edit_appointment (cal_view, event->comp_data->client, + event->comp_data->icalcomp, FALSE); g_list_free (selected); } @@ -834,7 +917,7 @@ on_print (GtkWidget *widget, gpointer user_data) cal_view = E_CAL_VIEW (user_data); - gnome_calendar_get_current_time_range (cal_view->priv->calendar, &start, NULL); + e_cal_view_get_visible_time_range (cal_view, &start, NULL); view_type = gnome_calendar_get_view (cal_view->priv->calendar); switch (view_type) { @@ -930,7 +1013,7 @@ on_meeting (GtkWidget *widget, gpointer user_data) selected = e_cal_view_get_selected_events (cal_view); if (selected) { ECalViewEvent *event = (ECalViewEvent *) selected->data; - gnome_calendar_edit_object (cal_view->priv->calendar, event->comp_data->client, event->comp_data->icalcomp, TRUE); + e_cal_view_edit_appointment (cal_view, event->comp_data->client, event->comp_data->icalcomp, TRUE); g_list_free (selected); } @@ -962,7 +1045,7 @@ on_publish (GtkWidget *widget, gpointer user_data) ECalView *cal_view; icaltimezone *utc; time_t start = time (NULL), end; - GList *comp_list, *client_list, *cl; + GList *comp_list = NULL, *client_list, *cl; cal_view = E_CAL_VIEW (user_data); @@ -972,8 +1055,7 @@ on_publish (GtkWidget *widget, gpointer user_data) client_list = e_cal_model_get_client_list (cal_view->priv->model); for (cl = client_list; cl != NULL; cl = cl->next) { - comp_list = cal_client_get_free_busy ((CalClient *) cl->data, NULL, start, end); - if (comp_list) { + if (cal_client_get_free_busy ((CalClient *) cl->data, NULL, start, end, &comp_list, NULL)) { GList *l; for (l = comp_list; l; l = l->next) { @@ -1041,14 +1123,6 @@ on_paste (GtkWidget *widget, gpointer user_data) e_cal_view_paste_clipboard (cal_view); } -static void -on_unrecur_appointment (GtkWidget *widget, gpointer user_data) -{ - ECalView *cal_view = E_CAL_VIEW (user_data); - - gnome_calendar_unrecur_selection (cal_view->priv->calendar); -} - enum { /* * This is used to "flag" events that can not be editted @@ -1142,7 +1216,6 @@ static EPopupMenu child_items [] = { E_POPUP_SEPARATOR, E_POPUP_ITEM (N_("_Delete"), GTK_SIGNAL_FUNC (on_delete_appointment), MASK_EDITABLE | MASK_SINGLE | MASK_EDITING), - E_POPUP_ITEM (N_("Make this Occurrence _Movable"), GTK_SIGNAL_FUNC (on_unrecur_appointment), MASK_RECURRING | MASK_EDITING | MASK_EDITABLE | MASK_INSTANCE), E_POPUP_ITEM (N_("Delete this _Occurrence"), GTK_SIGNAL_FUNC (on_delete_occurrence), MASK_RECURRING | MASK_EDITING | MASK_EDITABLE), E_POPUP_ITEM (N_("Delete _All Occurrences"), GTK_SIGNAL_FUNC (on_delete_appointment), MASK_RECURRING | MASK_EDITING | MASK_EDITABLE), @@ -1209,21 +1282,18 @@ setup_popup_icons (EPopupMenu *context_menu) GtkMenu * e_cal_view_create_popup_menu (ECalView *cal_view) { - gboolean being_edited, have_selection; GList *selected; EPopupMenu *context_menu; guint32 disable_mask = 0, hide_mask = 0; GtkMenu *popup; CalClient *client = NULL; - + gboolean read_only = TRUE; + g_return_val_if_fail (E_IS_CAL_VIEW (cal_view), NULL); /* get the selection */ - being_edited = FALSE; selected = e_cal_view_get_selected_events (cal_view); - have_selection = GTK_WIDGET_HAS_FOCUS (cal_view) && selected != NULL; - if (selected == NULL) { cal_view->priv->view_menu = gnome_calendar_setup_view_popup (cal_view->priv->calendar); main_items[9].submenu = cal_view->priv->view_menu; @@ -1260,15 +1330,158 @@ e_cal_view_create_popup_menu (ECalView *cal_view) client = event->comp_data->client; } - if (cal_client_is_read_only (client)) + cal_client_is_read_only (client, &read_only, NULL); + if (read_only) disable_mask |= MASK_EDITABLE; - if (being_edited) - disable_mask |= MASK_EDITING; - setup_popup_icons (context_menu); popup = e_popup_menu_create (context_menu, disable_mask, hide_mask, cal_view); g_signal_connect (popup, "selection-done", G_CALLBACK (free_view_popup), cal_view); return popup; } + +/** + * e_cal_view_new_appointment_for + * @cal_view: A calendar view. + * @dtstart: A Unix time_t that marks the beginning of the appointment. + * @dtend: A Unix time_t that marks the end of the appointment. + * @all_day: If TRUE, the dtstart and dtend are expanded to cover + * the entire day, and the event is set to TRANSPARENT. + * @meeting: Whether the appointment is a meeting or not. + * + * Opens an event editor dialog for a new appointment. + */ +void +e_cal_view_new_appointment_for (ECalView *cal_view, + time_t dtstart, time_t dtend, + gboolean all_day, + gboolean meeting) +{ + ECalViewPrivate *priv; + struct icaltimetype itt; + CalComponentDateTime dt; + CalComponent *comp; + icalcomponent *icalcomp; + CalComponentTransparency transparency; + + g_return_if_fail (E_IS_CAL_VIEW (cal_view)); + + priv = cal_view->priv; + + dt.value = &itt; + if (all_day) + dt.tzid = NULL; + else + dt.tzid = icaltimezone_get_tzid (priv->zone); + + icalcomp = e_cal_model_create_component_with_defaults (priv->model); + comp = cal_component_new (); + cal_component_set_icalcomponent (comp, icalcomp); + + /* DTSTART, DTEND */ + itt = icaltime_from_timet_with_zone (dtstart, FALSE, priv->zone); + if (all_day) { + itt.hour = itt.minute = itt.second = 0; + itt.is_date = TRUE; + } + cal_component_set_dtstart (comp, &dt); + + itt = icaltime_from_timet_with_zone (dtend, FALSE, priv->zone); + if (all_day) { + /* We round it up to the end of the day, unless it is + already set to midnight */ + if (itt.hour != 0 || itt.minute != 0 || itt.second != 0) { + icaltime_adjust (&itt, 1, 0, 0, 0); + } + itt.hour = itt.minute = itt.second = 0; + itt.is_date = TRUE; + } + cal_component_set_dtend (comp, &dt); + + /* TRANSPARENCY */ + transparency = all_day ? CAL_COMPONENT_TRANSP_TRANSPARENT + : CAL_COMPONENT_TRANSP_OPAQUE; + cal_component_set_transparency (comp, transparency); + + /* CATEGORY */ + cal_component_set_categories (comp, priv->default_category); + + /* edit the object */ + cal_component_commit_sequence (comp); + + e_cal_view_edit_appointment (cal_view, + e_cal_model_get_default_client (priv->model), + icalcomp, meeting); + + g_object_unref (comp); +} + +/** + * e_cal_view_new_appointment + * @cal_view: A calendar view. + * + * Opens an event editor dialog for a new appointment. The appointment's + * start and end times are set to the currently selected time range in + * the calendar view. + */ +void +e_cal_view_new_appointment (ECalView *cal_view) +{ + time_t dtstart, dtend; + + g_return_if_fail (E_IS_CAL_VIEW (cal_view)); + + e_cal_view_get_selected_time_range (cal_view, &dtstart, &dtend); + e_cal_view_new_appointment_for (cal_view, dtstart, dtend, FALSE, FALSE); +} + +/** + * e_cal_view_edit_appointment + * @cal_view: A calendar view. + * @client: Calendar client. + * @icalcomp: The object to be edited. + * @meeting: Whether the appointment is a meeting or not. + * + * Opens an editor window to allow the user to edit the selected + * object. + */ +void +e_cal_view_edit_appointment (ECalView *cal_view, + CalClient *client, + icalcomponent *icalcomp, + gboolean meeting) +{ + ECalViewPrivate *priv; + CompEditor *ce; + const char *uid; + CalComponent *comp; + + g_return_if_fail (E_IS_CAL_VIEW (cal_view)); + g_return_if_fail (IS_CAL_CLIENT (client)); + g_return_if_fail (icalcomp != NULL); + + priv = cal_view->priv; + + uid = icalcomponent_get_uid (icalcomp); + + ce = e_comp_editor_registry_find (comp_editor_registry, uid); + if (!ce) { + EventEditor *ee; + + ee = event_editor_new (client); + ce = COMP_EDITOR (ee); + + comp = cal_component_new (); + cal_component_set_icalcomponent (comp, icalcomponent_new_clone (icalcomp)); + comp_editor_edit_comp (ce, comp); + if (meeting) + event_editor_show_meeting (ee); + + e_comp_editor_registry_add (comp_editor_registry, ce, FALSE); + + g_object_unref (comp); + } + + comp_editor_focus (ce); +} diff --git a/calendar/gui/e-calendar-view.h b/calendar/gui/e-calendar-view.h index ea7c11a00d..9a09a5236a 100644 --- a/calendar/gui/e-calendar-view.h +++ b/calendar/gui/e-calendar-view.h @@ -96,6 +96,8 @@ ECalModel *e_cal_view_get_model (ECalView *cal_view); void e_cal_view_set_model (ECalView *cal_view, ECalModel *model); icaltimezone *e_cal_view_get_timezone (ECalView *cal_view); void e_cal_view_set_timezone (ECalView *cal_view, icaltimezone *zone); +const char *e_cal_view_get_default_category (ECalView *cal_view); +void e_cal_view_set_default_category (ECalView *cal_view, const char *category); void e_cal_view_set_status_message (ECalView *cal_view, const gchar *message); @@ -114,6 +116,17 @@ void e_cal_view_delete_selected_occurrence (ECalView *cal_view); GtkMenu *e_cal_view_create_popup_menu (ECalView *cal_view); +void e_cal_view_new_appointment_for (ECalView *cal_view, + time_t dtstart, + time_t dtend, + gboolean all_day, + gboolean meeting); +void e_cal_view_new_appointment (ECalView *cal_view); +void e_cal_view_edit_appointment (ECalView *cal_view, + CalClient *client, + icalcomponent *icalcomp, + gboolean meeting); + G_END_DECLS #endif diff --git a/calendar/gui/e-day-view.c b/calendar/gui/e-day-view.c index a2a4f09d56..b4ec9faea0 100644 --- a/calendar/gui/e-day-view.c +++ b/calendar/gui/e-day-view.c @@ -65,6 +65,7 @@ #include "calendar-commands.h" #include "calendar-config.h" #include "goto.h" +#include "e-cal-model-calendar.h" #include "e-day-view-time-item.h" #include "e-day-view-top-item.h" #include "e-day-view-layout.h" @@ -592,8 +593,6 @@ e_day_view_init (EDayView *day_view) day_view->auto_scroll_timeout_id = 0; - day_view->default_category = NULL; - day_view->large_font_desc = NULL; /* String to use in 12-hour time format for times in the morning. */ @@ -850,8 +849,11 @@ GtkWidget * e_day_view_new (void) { GtkWidget *day_view; + ECalModel *model; + + model = E_CAL_MODEL (e_cal_model_calendar_new ()); - day_view = GTK_WIDGET (g_object_new (e_day_view_get_type (), NULL)); + day_view = GTK_WIDGET (g_object_new (e_day_view_get_type (), "model", model, NULL)); return day_view; } @@ -881,12 +883,6 @@ e_day_view_destroy (GtkObject *object) day_view->large_font_desc = NULL; } - if (day_view->default_category) { - g_free (day_view->default_category); - day_view->default_category = NULL; - } - - if (day_view->normal_cursor) { gdk_cursor_unref (day_view->normal_cursor); day_view->normal_cursor = NULL; @@ -1429,26 +1425,6 @@ e_day_view_focus_out (GtkWidget *widget, GdkEventFocus *event) return FALSE; } -/** - * e_day_view_set_default_category: - * @day_view: A day view. - * @category: Default category name or NULL for no category. - * - * Sets the default category that will be used when creating new calendar - * components from the day view. - **/ -void -e_day_view_set_default_category (EDayView *day_view, const char *category) -{ - g_return_if_fail (day_view != NULL); - g_return_if_fail (E_IS_DAY_VIEW (day_view)); - - if (day_view->default_category) - g_free (day_view->default_category); - - day_view->default_category = g_strdup (category); -} - static gboolean e_day_view_update_event_cb (EDayView *day_view, gint day, @@ -1794,6 +1770,9 @@ e_day_view_find_event_from_uid (EDayView *day_view, gint day, event_num; const char *u; + if (!uid) + return FALSE; + for (day = 0; day < day_view->days_shown; day++) { for (event_num = 0; event_num < day_view->events[day]->len; event_num++) { @@ -2048,7 +2027,6 @@ e_day_view_find_work_week_start (EDayView *day_view, return icaltime_as_timet_with_zone (tt, e_cal_view_get_timezone (E_CAL_VIEW (day_view))); } - /* Returns the selected time range. */ static void e_day_view_get_selected_time_range (ECalView *cal_view, time_t *start_time, time_t *end_time) @@ -2123,6 +2101,8 @@ e_day_view_recalc_day_starts (EDayView *day_view, day_view->lower = start_time; day_view->upper = day_view->day_starts[day_view->days_shown]; + + e_day_view_update_query (day_view); } @@ -2588,9 +2568,9 @@ e_day_view_on_top_canvas_button_press (GtkWidget *widget, time_t dtstart, dtend; e_day_view_get_selected_time_range ((ECalView *) day_view, &dtstart, &dtend); - gnome_calendar_new_appointment_for (e_cal_view_get_calendar (E_CAL_VIEW (day_view)), - dtstart, dtend, - TRUE, FALSE); + e_cal_view_new_appointment_for (E_CAL_VIEW (day_view), + dtstart, dtend, + TRUE, FALSE); return TRUE; } @@ -2709,9 +2689,9 @@ e_day_view_on_main_canvas_button_press (GtkWidget *widget, time_t dtstart, dtend; e_day_view_get_selected_time_range ((ECalView *) day_view, &dtstart, &dtend); - gnome_calendar_new_appointment_for (e_cal_view_get_calendar (E_CAL_VIEW (day_view)), - dtstart, dtend, - FALSE, FALSE); + e_cal_view_new_appointment_for (E_CAL_VIEW (day_view), + dtstart, dtend, + FALSE, FALSE); return TRUE; } @@ -3101,7 +3081,6 @@ e_day_view_on_event_double_click (EDayView *day_view, gint event_num) { EDayViewEvent *event; - GnomeCalendar *calendar; if (day == -1) event = &g_array_index (day_view->long_events, EDayViewEvent, @@ -3112,11 +3091,9 @@ e_day_view_on_event_double_click (EDayView *day_view, e_day_view_stop_editing_event (day_view); - calendar = e_cal_view_get_calendar (E_CAL_VIEW (day_view)); - if (calendar) - gnome_calendar_edit_object (calendar, event->comp_data->client, event->comp_data->icalcomp, FALSE); - else - g_warning ("Calendar not set"); + e_cal_view_edit_appointment (E_CAL_VIEW (day_view), + event->comp_data->client, + event->comp_data->icalcomp, FALSE); } static void @@ -3207,7 +3184,6 @@ process_component (EDayView *day_view, ECalModelComponent *comp_data) EDayViewEvent, event_num); if (!cal_util_component_has_recurrences (comp_data->icalcomp) - && !cal_component_has_recurrences (event->comp_data->icalcomp) && cal_util_event_dates_match (event->comp_data->icalcomp, comp_data->icalcomp)) { #if 0 g_print ("updated object's dates unchanged\n"); @@ -3228,17 +3204,18 @@ process_component (EDayView *day_view, ECalModelComponent *comp_data) NULL); } - /* Add the occurrences of the event. */ + /* Add the occurrences of the event */ comp = cal_component_new (); cal_component_set_icalcomponent (comp, icalcomponent_new_clone (comp_data->icalcomp)); + add_event_data.day_view = day_view; add_event_data.comp_data = comp_data; cal_recur_generate_instances (comp, day_view->lower, day_view->upper, e_day_view_add_event, &add_event_data, - cal_client_resolve_tzid_cb, - comp_data->client, + cal_client_resolve_tzid_cb, comp_data->client, e_cal_view_get_timezone (E_CAL_VIEW (day_view))); + g_object_unref (comp); e_day_view_queue_layout (day_view); @@ -3258,8 +3235,6 @@ e_day_view_update_query (ECalView *cal_view) e_day_view_free_events (day_view); e_day_view_queue_layout (day_view); - e_cal_view_set_status_message (E_CAL_VIEW (day_view), _("Searching")); - rows = e_table_model_row_count (E_TABLE_MODEL (e_cal_view_get_model (E_CAL_VIEW (day_view)))); for (r = 0; r < rows; r++) { ECalModelComponent *comp_data; @@ -3268,8 +3243,6 @@ e_day_view_update_query (ECalView *cal_view) g_assert (comp_data != NULL); process_component (day_view, comp_data); } - - e_cal_view_set_status_message (E_CAL_VIEW (day_view), NULL); } static void @@ -3282,67 +3255,6 @@ e_day_view_on_event_right_click (EDayView *day_view, day, event_num); } -void -e_day_view_unrecur_appointment (EDayView *day_view) -{ - EDayViewEvent *event; - CalComponent *comp, *new_comp; - CalComponentDateTime date; - struct icaltimetype itt; - - event = e_day_view_get_popup_menu_event (day_view); - if (event == NULL) - return; - - date.value = &itt; - date.tzid = NULL; - - /* For the recurring object, we add an exception to get rid of the - instance. */ - - comp = cal_component_new (); - cal_component_set_icalcomponent (comp, icalcomponent_new_clone (event->comp_data->icalcomp)); - cal_comp_util_add_exdate (comp, event->start, e_cal_view_get_timezone (E_CAL_VIEW (day_view))); - - /* For the unrecurred instance we duplicate the original object, - create a new uid for it, get rid of the recurrence rules, and set - the start & end times to the instances times. */ - new_comp = cal_component_new (); - cal_component_set_icalcomponent (comp, icalcomponent_new_clone (event->comp_data->icalcomp)); - cal_component_set_uid (new_comp, cal_component_gen_uid ()); - cal_component_set_rdate_list (new_comp, NULL); - cal_component_set_rrule_list (new_comp, NULL); - cal_component_set_exdate_list (new_comp, NULL); - cal_component_set_exrule_list (new_comp, NULL); - - date.value = &itt; - date.tzid = icaltimezone_get_tzid (e_cal_view_get_timezone (E_CAL_VIEW (day_view))); - - *date.value = icaltime_from_timet_with_zone (event->start, FALSE, - e_cal_view_get_timezone (E_CAL_VIEW (day_view))); - cal_component_set_dtstart (new_comp, &date); - *date.value = icaltime_from_timet_with_zone (event->end, FALSE, - e_cal_view_get_timezone (E_CAL_VIEW (day_view))); - cal_component_set_dtend (new_comp, &date); - - - /* Now update both CalComponents. Note that we do this last since at - * present the updates happen synchronously so our event may disappear. - */ - if (cal_client_update_object (event->comp_data->client, comp) - != CAL_CLIENT_RESULT_SUCCESS) - g_message ("e_day_view_on_unrecur_appointment(): Could not update the object!"); - - g_object_unref (comp); - - if (cal_client_update_object (event->comp_data->client, new_comp) - != CAL_CLIENT_RESULT_SUCCESS) - g_message ("e_day_view_on_unrecur_appointment(): Could not update the object!"); - - g_object_unref (new_comp); -} - - static EDayViewEvent* e_day_view_get_popup_menu_event (EDayView *day_view) { @@ -3841,7 +3753,9 @@ e_day_view_finish_long_event_resize (EDayView *day_view) struct icaltimetype itt; time_t dt; CalClient *client; - + CalObjModType mod = CALOBJ_MOD_ALL; + GtkWindow *toplevel; + event_num = day_view->resize_event_num; event = &g_array_index (day_view->long_events, EDayViewEvent, event_num); @@ -3870,31 +3784,26 @@ e_day_view_finish_long_event_resize (EDayView *day_view) e_cal_view_get_timezone (E_CAL_VIEW (day_view))); cal_component_set_dtend (comp, &date); } - - if (cal_component_is_instance (comp)) { - CalObjModType mod; - - if (recur_component_dialog (comp, &mod, NULL)) { - if (cal_client_update_object_with_mod (client, comp, mod) == CAL_CLIENT_RESULT_SUCCESS) { - if (itip_organizer_is_user (comp, client) && - send_component_dialog ((GtkWindow *) gtk_widget_get_toplevel (GTK_WIDGET (day_view)), - client, comp, FALSE)) - itip_send_comp (CAL_COMPONENT_METHOD_REQUEST, comp, client, NULL); - } else { - g_message ("e_day_view_finish_resize(): Could not update the object!"); - } - } else { + + if (cal_component_has_recurrences (comp)) { + if (!recur_component_dialog (comp, &mod, NULL)) { gtk_widget_queue_draw (day_view->top_canvas); - } - } else if (cal_client_update_object (client, comp) == CAL_CLIENT_RESULT_SUCCESS) { - if (itip_organizer_is_user (comp, client) && - send_component_dialog ((GtkWindow *) gtk_widget_get_toplevel (GTK_WIDGET (day_view)), - client, comp, TRUE)) - itip_send_comp (CAL_COMPONENT_METHOD_REQUEST, comp, client, NULL); - } else { - g_message ("e_day_view_finish_long_event_resize(): Could not update the object!"); - } - + goto out; + } + } + + toplevel = GTK_WINDOW (gtk_widget_get_toplevel (GTK_WIDGET (day_view))); + + if (cal_client_modify_object (client, cal_component_get_icalcomponent (comp), mod, NULL)) { + if (itip_organizer_is_user (comp, client) && + send_component_dialog (toplevel, client, comp, TRUE)) { + itip_send_comp (CAL_COMPONENT_METHOD_REQUEST, comp, client, NULL); + } else { + g_message (G_STRLOC ": Could not update the object!"); + } + } + + out: gnome_canvas_item_hide (day_view->resize_long_event_rect_item); day_view->resize_drag_pos = E_CAL_VIEW_POS_NONE; @@ -3915,6 +3824,8 @@ e_day_view_finish_resize (EDayView *day_view) struct icaltimetype itt; time_t dt; CalClient *client; + CalObjModType mod = CALOBJ_MOD_ALL; + GtkWindow *toplevel; day = day_view->resize_event_day; event_num = day_view->resize_event_num; @@ -3957,29 +3868,26 @@ e_day_view_finish_resize (EDayView *day_view) day_view->resize_drag_pos = E_CAL_VIEW_POS_NONE; - if (cal_component_is_instance (comp)) { - CalObjModType mod; + if (cal_component_has_recurrences (comp)) { + if (!recur_component_dialog (comp, &mod, NULL)) { + gtk_widget_queue_draw (day_view->top_canvas); + goto out; + } + } + + toplevel = GTK_WINDOW (gtk_widget_get_toplevel (GTK_WIDGET (day_view))); - if (recur_component_dialog (comp, &mod, NULL)) { - if (cal_client_update_object_with_mod (client, comp, mod) == CAL_CLIENT_RESULT_SUCCESS) { - if (itip_organizer_is_user (comp, client) && - send_component_dialog ((GtkWindow *) gtk_widget_get_toplevel (GTK_WIDGET (day_view)), - client, comp, FALSE)) - itip_send_comp (CAL_COMPONENT_METHOD_REQUEST, comp, client, NULL); - } else { - g_message ("e_day_view_finish_resize(): Could not update the object!"); - } - } else { - gtk_widget_queue_draw (day_view->main_canvas); - } - } else if (cal_client_update_object (client, comp) == CAL_CLIENT_RESULT_SUCCESS) { + cal_component_commit_sequence (comp); + if (cal_client_modify_object (client, cal_component_get_icalcomponent (comp), mod, NULL)) { if (itip_organizer_is_user (comp, client) && - send_component_dialog ((GtkWindow *) gtk_widget_get_toplevel (GTK_WIDGET (day_view)), client, comp, FALSE)) + send_component_dialog (toplevel, client, comp, TRUE)) { itip_send_comp (CAL_COMPONENT_METHOD_REQUEST, comp, client, NULL); - } else { - g_message ("e_day_view_finish_resize(): Could not update the object!"); - } - + } else { + g_message (G_STRLOC ": Could not update the object!"); + } + } + + out: g_object_unref (comp); } @@ -4774,6 +4682,8 @@ e_day_view_do_key_press (GtkWidget *widget, GdkEventKey *event) /* Add a new event covering the selected range */ icalcomp = e_cal_model_create_component_with_defaults (e_cal_view_get_model (E_CAL_VIEW (day_view))); + if (!icalcomp) + return FALSE; uid = icalcomponent_get_uid (icalcomp); comp = cal_component_new (); @@ -4801,7 +4711,8 @@ e_day_view_do_key_press (GtkWidget *widget, GdkEventKey *event) cal_component_set_dtstart (comp, &start_dt); cal_component_set_dtend (comp, &end_dt); - cal_component_set_categories (comp, day_view->default_category); + cal_component_set_categories ( + comp, e_cal_view_get_default_category (E_CAL_VIEW (day_view))); /* We add the event locally and start editing it. We don't send it to the server until the user finishes editing it. */ @@ -5777,7 +5688,8 @@ e_day_view_on_editing_stopped (EDayView *day_view, gchar *text = NULL; CalComponentText summary; CalComponent *comp; - + gboolean on_server; + /* Note: the item we are passed here isn't reliable, so we just stop the edit of whatever item was being edited. We also receive this event twice for some reason. */ @@ -5822,8 +5734,9 @@ e_day_view_on_editing_stopped (EDayView *day_view, comp = cal_component_new (); cal_component_set_icalcomponent (comp, icalcomponent_new_clone (event->comp_data->icalcomp)); - if (string_is_empty (text) && - !cal_comp_is_on_server (comp, event->comp_data->client)) { + on_server = cal_comp_is_on_server (comp, event->comp_data->client); + + if (string_is_empty (text) && !on_server) { const char *uid; cal_component_get_uid (comp, &uid); @@ -5845,34 +5758,34 @@ e_day_view_on_editing_stopped (EDayView *day_view, e_day_view_update_event_label (day_view, day, event_num); } else if (summary.value || !string_is_empty (text)) { + icalcomponent *icalcomp = cal_component_get_icalcomponent (comp); + summary.value = text; summary.altrep = NULL; cal_component_set_summary (comp, &summary); - if (cal_component_is_instance (comp)) { - CalObjModType mod; - - if (recur_component_dialog (comp, &mod, NULL)) { - if (cal_client_update_object_with_mod (event->comp_data->client, comp, mod) - == CAL_CLIENT_RESULT_SUCCESS) { - if (itip_organizer_is_user (comp, event->comp_data->client) - && send_component_dialog ((GtkWindow *) gtk_widget_get_toplevel (GTK_WIDGET (day_view)), - event->comp_data->client, comp, FALSE)) - itip_send_comp (CAL_COMPONENT_METHOD_REQUEST, comp, - event->comp_data->client, NULL); - } else { - g_message ("e_day_view_on_editing_stopped(): Could not update the object!"); + if (!on_server) { + if (!cal_client_create_object (event->comp_data->client, icalcomp, NULL, NULL)) + g_message (G_STRLOC ": Could not create the object!"); + } else { + CalObjModType mod = CALOBJ_MOD_ALL; + GtkWindow *toplevel; + if (cal_component_has_recurrences (comp)) { + if (!recur_component_dialog (comp, &mod, NULL)) { + goto out; } } - } else if (cal_client_update_object (event->comp_data->client, comp) == CAL_CLIENT_RESULT_SUCCESS) { - if (itip_organizer_is_user (comp, event->comp_data->client) && - send_component_dialog ((GtkWindow *) gtk_widget_get_toplevel (GTK_WIDGET (day_view)), - event->comp_data->client, comp, FALSE)) - itip_send_comp (CAL_COMPONENT_METHOD_REQUEST, comp, - event->comp_data->client, NULL); - } else { - g_message ("e_day_view_on_editing_stopped(): Could not update the object!"); + + /* FIXME When sending here, what exactly should we send? */ + toplevel = GTK_WINDOW (gtk_widget_get_toplevel (GTK_WIDGET (day_view))); + if (cal_client_modify_object (event->comp_data->client, icalcomp, mod, NULL)) { + if (itip_organizer_is_user (comp, event->comp_data->client) + && send_component_dialog (toplevel, event->comp_data->client, comp, FALSE)) + itip_send_comp (CAL_COMPONENT_METHOD_REQUEST, comp, + event->comp_data->client, NULL); + } } + } out: @@ -6881,7 +6794,10 @@ e_day_view_on_top_canvas_drag_data_received (GtkWidget *widget, x, y, &day, NULL); if (pos != E_CAL_VIEW_POS_OUTSIDE) { + CalObjModType mod = CALOBJ_MOD_ALL; + GtkWindow *toplevel; const char *uid; + num_days = 1; start_offset = 0; end_offset = 0; @@ -6972,33 +6888,20 @@ e_day_view_on_top_canvas_drag_data_received (GtkWidget *widget, if (event->canvas_item) gnome_canvas_item_show (event->canvas_item); - if (cal_component_is_instance (comp)) { - CalObjModType mod; - - if (recur_component_dialog (comp, &mod, NULL)) { - if (cal_client_update_object_with_mod (client, comp, mod) == CAL_CLIENT_RESULT_SUCCESS) { - if (itip_organizer_is_user (comp, client) - && send_component_dialog ((GtkWindow *) gtk_widget_get_toplevel (GTK_WIDGET (day_view)), - client, comp, FALSE)) - itip_send_comp (CAL_COMPONENT_METHOD_REQUEST, comp, - client, NULL); - } else { - g_message ("e_day_view_on_top_canvas_drag_data_received(): Could " - "not update the object!"); - } - } - } else if (cal_client_update_object (client, comp) - == CAL_CLIENT_RESULT_SUCCESS) { - if (itip_organizer_is_user (comp, client) && - send_component_dialog ((GtkWindow *) gtk_widget_get_toplevel (GTK_WIDGET (day_view)), - client, comp, FALSE)) - itip_send_comp (CAL_COMPONENT_METHOD_REQUEST, comp, - client, NULL); - } else { - g_message ("e_day_view_on_top_canvas_drag_data_received(): Could " - "not update the object!"); + if (cal_component_has_recurrences (comp)) { + if (!recur_component_dialog (comp, &mod, NULL)) + return; } + toplevel = GTK_WINDOW (gtk_widget_get_toplevel (GTK_WIDGET (day_view))); + + if (cal_client_modify_object (client, cal_component_get_icalcomponent (comp), mod, NULL)) { + if (itip_organizer_is_user (comp, client) + && send_component_dialog (toplevel, client, comp, FALSE)) + itip_send_comp (CAL_COMPONENT_METHOD_REQUEST, comp, + client, NULL); + } + g_object_unref (comp); return; @@ -7044,7 +6947,10 @@ e_day_view_on_main_canvas_drag_data_received (GtkWidget *widget, x, y, &day, &row, NULL); if (pos != E_CAL_VIEW_POS_OUTSIDE) { + CalObjModType mod = CALOBJ_MOD_ALL; + GtkWindow *toplevel; const char *uid; + num_rows = 1; start_offset = 0; end_offset = 0; @@ -7109,30 +7015,20 @@ e_day_view_on_main_canvas_drag_data_received (GtkWidget *widget, if (event->canvas_item) gnome_canvas_item_show (event->canvas_item); - if (cal_component_is_instance (comp)) { - CalObjModType mod; - - if (recur_component_dialog (comp, &mod, NULL)) { - if (cal_client_update_object_with_mod (client, comp, mod) == CAL_CLIENT_RESULT_SUCCESS) { - if (itip_organizer_is_user (comp, client) - && send_component_dialog ((GtkWindow *) gtk_widget_get_toplevel (GTK_WIDGET (day_view)), - client, comp, FALSE)) - itip_send_comp (CAL_COMPONENT_METHOD_REQUEST, comp, - client, NULL); - } else { - g_message ("e_day_view_on_top_canvas_drag_data_received(): Could " - "not update the object!"); - } + if (cal_component_has_recurrences (comp)) { + if (!recur_component_dialog (comp, &mod, NULL)) { + g_object_unref (comp); + return; } - } else if (cal_client_update_object (client, comp) == CAL_CLIENT_RESULT_SUCCESS) { - if (itip_organizer_is_user (comp, client) && - send_component_dialog ((GtkWindow *) gtk_widget_get_toplevel (GTK_WIDGET (day_view)), - client, comp, FALSE)) - itip_send_comp (CAL_COMPONENT_METHOD_REQUEST, comp, + } + + toplevel = GTK_WINDOW (gtk_widget_get_toplevel (GTK_WIDGET (day_view))); + + if (cal_client_modify_object (client, cal_component_get_icalcomponent (comp), mod, NULL)) { + if (itip_organizer_is_user (comp, client) + && send_component_dialog (toplevel, client, comp, FALSE)) + itip_send_comp (CAL_COMPONENT_METHOD_REQUEST, comp, client, NULL); - } else { - g_message ("e_day_view_on_main_canvas_drag_data_received(): " - "Could not update the object!"); } g_object_unref (comp); diff --git a/calendar/gui/e-day-view.h b/calendar/gui/e-day-view.h index 1c39fd5844..decd281127 100644 --- a/calendar/gui/e-day-view.h +++ b/calendar/gui/e-day-view.h @@ -453,9 +453,6 @@ struct _EDayView gint am_string_width; gint pm_string_width; - /* The default category for new events */ - char *default_category; - /* The activity client used to show messages on the status bar. */ EvolutionActivityClient *activity; }; @@ -472,9 +469,6 @@ GtkWidget* e_day_view_new (void); void e_day_view_set_query (EDayView *day_view, const char *sexp); -void e_day_view_set_default_category (EDayView *day_view, - const char *category); - /* Whether we are displaying a work-week, in which case the display always starts on the first day of the working week. */ gboolean e_day_view_get_work_week_view (EDayView *day_view); @@ -528,7 +522,6 @@ void e_day_view_set_week_start_day (EDayView *day_view, gint week_start_day); void e_day_view_delete_occurrence (EDayView *day_view); -void e_day_view_unrecur_appointment (EDayView *day_view); /* Returns the number of selected events (0 or 1 at present). */ gint e_day_view_get_num_events_selected (EDayView *day_view); diff --git a/calendar/gui/e-itip-control.c b/calendar/gui/e-itip-control.c index 8b39b82b8c..d5e24c8936 100644 --- a/calendar/gui/e-itip-control.c +++ b/calendar/gui/e-itip-control.c @@ -94,8 +94,6 @@ struct _EItipControlPrivate { #define HTML_BODY_END "" #define HTML_FOOTER "" -extern EvolutionShellClient *global_shell_client; - /* We intentionally use "calendar" instead of "calendar / *" here. We * don't want public calendars. */ @@ -132,63 +130,26 @@ class_init (EItipControlClass *klass) object_class->finalize = finalize; } - -/* Calendar Server routines */ -static void -start_calendar_server_cb (CalClient *cal_client, - CalClientOpenStatus status, - gpointer data) -{ - int *success = data; - int orig = *success; - - if (status == CAL_CLIENT_OPEN_SUCCESS) - *success = 1; - else - *success = 0; - - if (orig != -1) - gtk_main_quit (); /* end the sub event loop */ -} - static CalClient * start_calendar_server (EItipControl *itip, char *uri) { CalClient *client; - int success = -1; - - client = cal_client_new (); - - g_signal_connect (client, "cal_opened", G_CALLBACK (start_calendar_server_cb), &success); - - if (!cal_client_open_calendar (client, uri, TRUE)) - goto error; - - /* run a sub event loop to turn cal-client's async load - notification into a synchronous call */ - if (success == -1 && !itip->priv->destroyed) { - success = 0; - - gtk_signal_connect (GTK_OBJECT (itip), "destroy", - gtk_main_quit, NULL); - - gtk_main (); - - gtk_signal_disconnect_by_func (GTK_OBJECT (itip), - gtk_main_quit, NULL); - } + GError *error = NULL; - if (success == 1) - return client; + client = cal_client_new (uri, CALOBJ_TYPE_EVENT); -error: - g_object_unref (client); + if (!cal_client_open (client, TRUE, &error)) { + g_warning (_("start_calendar_server(): %s"), error->message); + g_error_free (error); + g_object_unref (client); + return NULL; + } - return NULL; + return client; } static gboolean -start_default_server_async (EItipControl *itip, CalClient *client, gboolean tasks) +start_default_server (EItipControl *itip, CalClient *client, gboolean tasks) { if (tasks) return cal_client_open_default_tasks (client, FALSE); @@ -196,6 +157,7 @@ start_default_server_async (EItipControl *itip, CalClient *client, gboolean task return cal_client_open_default_calendar (client, FALSE); } +#if 0 /* EPFIXME, rewrite this */ static GPtrArray * get_servers (EItipControl *itip, EvolutionShellClient *shell_client, const char *possible_types[], gboolean tasks) { @@ -263,6 +225,7 @@ get_servers (EItipControl *itip, EvolutionShellClient *shell_client, const char return servers; } +#endif static CalClient * find_server (GPtrArray *servers, CalComponent *comp) @@ -274,11 +237,9 @@ find_server (GPtrArray *servers, CalComponent *comp) for (i = 0; i < servers->len; i++) { CalClient *client; icalcomponent *icalcomp; - CalClientGetStatus status; client = g_ptr_array_index (servers, i); - status = cal_client_get_object (client, uid, &icalcomp); - if (status == CAL_CLIENT_GET_SUCCESS) { + if (cal_client_get_object (client, uid, NULL, &icalcomp, NULL)) { icalcomponent_free (icalcomp); g_object_ref (client); @@ -540,8 +501,7 @@ find_attendee (icalcomponent *ical_comp, const char *address) for (prop = icalcomponent_get_first_property (ical_comp, ICAL_ATTENDEE_PROPERTY); prop != NULL; - prop = icalcomponent_get_next_property (ical_comp, ICAL_ATTENDEE_PROPERTY)) - { + prop = icalcomponent_get_next_property (ical_comp, ICAL_ATTENDEE_PROPERTY)) { icalvalue *value; const char *attendee; char *text; @@ -762,6 +722,7 @@ write_recurrence_piece (EItipControl *itip, CalComponent *comp, } else if (!icaltime_is_null_time (r->until)) { CalComponentDateTime dt; + /* FIXME This should get the tzid id, not the whole zone */ dt.value = &r->until; dt.tzid = r->until.zone; @@ -1220,7 +1181,7 @@ get_real_item (EItipControl *itip) CalComponent *comp; icalcomponent *icalcomp; CalComponentVType type; - CalClientGetStatus status = CAL_CLIENT_GET_NOT_FOUND; + gboolean found = FALSE; const char *uid; priv = itip->priv; @@ -1231,17 +1192,17 @@ get_real_item (EItipControl *itip) switch (type) { case CAL_COMPONENT_EVENT: if (priv->event_client != NULL) - status = cal_client_get_object (priv->event_client, uid, &icalcomp); + found = cal_client_get_object (priv->event_client, uid, NULL, &icalcomp, NULL); break; case CAL_COMPONENT_TODO: if (priv->task_client != NULL) - status = cal_client_get_object (priv->task_client, uid, &icalcomp); + found = cal_client_get_object (priv->task_client, uid, NULL, &icalcomp, NULL); break; default: - status = CAL_CLIENT_GET_NOT_FOUND; + found = FALSE; } - if (status != CAL_CLIENT_GET_SUCCESS) + if (!found) return NULL; comp = cal_component_new (); @@ -1568,13 +1529,18 @@ show_current (EItipControl *itip) switch (type) { case CAL_COMPONENT_EVENT: - if (!priv->event_clients) - priv->event_clients = get_servers (itip, global_shell_client, calendar_types, FALSE); + if (!priv->event_clients) { + priv->event_clients = g_ptr_array_new (); + /* EPFIXME */ + /* priv->event_clients = get_servers (itip, global_shell_client, calendar_types, FALSE); */ + } show_current_event (itip); break; case CAL_COMPONENT_TODO: - if (!priv->task_clients) - priv->task_clients = get_servers (itip, global_shell_client, tasks_types, TRUE); + if (!priv->task_clients) { + /* EPFIXME */ + /* priv->task_clients = get_servers (itip, global_shell_client, tasks_types, TRUE); */ + } show_current_todo (itip); break; case CAL_COMPONENT_FREEBUSY: @@ -1853,7 +1819,6 @@ update_item (EItipControl *itip) CalClient *client; CalComponentVType type; GtkWidget *dialog; - CalClientResult result; priv = itip->priv; @@ -1881,32 +1846,18 @@ update_item (EItipControl *itip) icalcomponent_add_component (priv->top_level, clone); icalcomponent_set_method (priv->top_level, priv->method); - result = cal_client_update_objects (client, priv->top_level); - switch (result) { - case CAL_CLIENT_RESULT_INVALID_OBJECT : - dialog = gnome_warning_dialog (_("Object is invalid and cannot be updated\n")); - break; - case CAL_CLIENT_RESULT_CORBA_ERROR : - dialog = gnome_warning_dialog (_("There was an error on the CORBA system\n")); - break; - case CAL_CLIENT_RESULT_NOT_FOUND : - dialog = gnome_warning_dialog (_("Object could not be found\n")); - break; - case CAL_CLIENT_RESULT_PERMISSION_DENIED : - dialog = gnome_warning_dialog (_("You do not have the right permissions to update the calendar\n")); - break; - case CAL_CLIENT_RESULT_SUCCESS : - dialog = gnome_ok_dialog (_("Update complete\n")); - break; - default : + /* FIXME Better error dialog */ + if (!cal_client_receive_objects (client, priv->top_level, NULL)) { dialog = gnome_warning_dialog (_("Calendar file could not be updated!\n")); - break; + } else { + dialog = gnome_ok_dialog (_("Update complete\n")); } gnome_dialog_run_and_close (GNOME_DIALOG (dialog)); icalcomponent_remove_component (priv->top_level, clone); } +#if 0 static void update_attendee_status (EItipControl *itip) { @@ -1936,7 +1887,7 @@ update_attendee_status (EItipControl *itip) /* Obtain our version */ cal_component_get_uid (priv->comp, &uid); - status = cal_client_get_object (client, uid, &icalcomp); + status = cal_client_get_object (client, uid, NULL, &icalcomp); if (status == CAL_CLIENT_GET_SUCCESS) { GSList *attendees; @@ -2010,6 +1961,7 @@ update_attendee_status (EItipControl *itip) g_object_unref (comp); gnome_dialog_run_and_close (GNOME_DIALOG (dialog)); } +#endif static void remove_item (EItipControl *itip) @@ -2019,7 +1971,7 @@ remove_item (EItipControl *itip) CalComponentVType type; const char *uid; GtkWidget *dialog; - CalClientResult result; + GError *error = NULL; priv = itip->priv; @@ -2033,13 +1985,15 @@ remove_item (EItipControl *itip) return; cal_component_get_uid (priv->comp, &uid); - result = cal_client_remove_object (client, uid); - if (result == CAL_CLIENT_RESULT_SUCCESS || result == CAL_CLIENT_RESULT_NOT_FOUND) { + cal_client_remove_object (client, uid, &error); + if (!error || error->code == E_CALENDAR_STATUS_OBJECT_NOT_FOUND) { dialog = gnome_ok_dialog (_("Removal Complete")); gnome_dialog_run_and_close (GNOME_DIALOG (dialog)); } else { - delete_error_dialog (result, type); - } + delete_error_dialog (error, type); + } + + g_clear_error (&error); } static void @@ -2081,7 +2035,7 @@ send_freebusy (EItipControl *itip) CalComponentDateTime datetime; time_t start, end; GtkWidget *dialog; - GList *comp_list; + GList *comp_list = NULL; icaltimezone *zone; priv = itip->priv; @@ -2106,9 +2060,7 @@ send_freebusy (EItipControl *itip) end = icaltime_as_timet_with_zone (*datetime.value, zone); cal_component_free_datetime (&datetime); - comp_list = cal_client_get_free_busy (priv->event_client, NULL, start, end); - - if (comp_list) { + if (cal_client_get_free_busy (priv->event_client, NULL, start, end, &comp_list, NULL)) { GList *l; for (l = comp_list; l; l = l->next) { @@ -2210,6 +2162,7 @@ default_server_started_cb (CalClient *client, CalClientOpenStatus status, gpoint vtype = cal_component_get_vtype (priv->comp); switch (vtype) { +#if 0 /* EPFIXME */ case CAL_COMPONENT_EVENT: button = evolution_folder_selector_button_new ( global_shell_client, _("Select Calendar Folder"), @@ -2222,6 +2175,7 @@ default_server_started_cb (CalClient *client, CalClientOpenStatus status, gpoint calendar_config_default_tasks_folder (), tasks_types); break; +#endif default: button = NULL; } @@ -2251,29 +2205,30 @@ object_requested_cb (GtkHTML *html, GtkHTMLEmbedded *eb, gpointer data) context = g_new0 (ObjectRequestContext, 1); context->itip = itip; context->eb = eb; - context->client = cal_client_new (); - - g_object_ref (itip); - g_signal_connect (context->client, "cal_opened", - G_CALLBACK (default_server_started_cb), context); + /* FIXME: use the default URIs */ switch (vtype) { case CAL_COMPONENT_EVENT: - success = start_default_server_async (itip, context->client, FALSE); + context->client = cal_client_new ("", CALOBJ_TYPE_EVENT); + success = start_default_server (itip, context->client, FALSE); break; case CAL_COMPONENT_TODO: - success = start_default_server_async (itip, context->client, TRUE); + context->client = cal_client_new ("", CALOBJ_TYPE_TODO); + success = start_default_server (itip, context->client, TRUE); break; default: - success = FALSE; + g_free (context); + return FALSE; } if (!success) { - g_object_unref (itip); g_object_unref (context->client); g_free (context); + return FALSE; } + g_object_ref (itip); + return TRUE; } @@ -2330,7 +2285,8 @@ ok_clicked_cb (GtkHTML *html, const gchar *method, const gchar *url, const gchar send_freebusy (itip); break; case 'R': - update_attendee_status (itip); + /* FIXME Make sure this does the right thing in the backend */ + update_item (itip); break; case 'S': send_item (itip); diff --git a/calendar/gui/e-meeting-list-view.c b/calendar/gui/e-meeting-list-view.c index 7d3a4ce6c6..64463fdcb6 100644 --- a/calendar/gui/e-meeting-list-view.c +++ b/calendar/gui/e-meeting-list-view.c @@ -35,11 +35,7 @@ #include #include #include -#include -#include -#include -#include -#include +#include #include #include #include @@ -47,6 +43,7 @@ #include "calendar-config.h" #include "e-meeting-list-view.h" #include +#include #include "e-select-names-renderer.h" #define SELECT_NAMES_OAFID "OAFIID:GNOME_Evolution_Addressbook_SelectNames" @@ -56,8 +53,6 @@ struct _EMeetingListViewPrivate EMeetingStore *store; EBook *ebook; - gboolean book_loaded; - gboolean book_load_wait; GNOME_Evolution_Addressbook_SelectNames corba_select_names; }; @@ -77,27 +72,18 @@ static icalparameter_role roles[] = {ICAL_ROLE_CHAIR, static GtkTreeViewClass *parent_class = NULL; -static void -book_open_cb (EBook *book, EBookStatus status, gpointer data) -{ - EMeetingListView *view = E_MEETING_LIST_VIEW (data); - - if (status == E_BOOK_STATUS_SUCCESS) - view->priv->book_loaded = TRUE; - else - g_warning ("Book not loaded"); - - if (view->priv->book_load_wait) { - view->priv->book_load_wait = FALSE; - gtk_main_quit (); - } -} - static void start_addressbook_server (EMeetingListView *view) { + GError *error = NULL; + view->priv->ebook = e_book_new (); - e_book_load_default_book (view->priv->ebook, book_open_cb, view); + if (!e_book_load_local_addressbook (view->priv->ebook, &error)) { + g_warning ("start_addressbook_server(): %s", error->message); + g_error_free (error); + + return; + } } static void @@ -319,49 +305,41 @@ e_meeting_list_view_column_set_visible (EMeetingListView *view, const gchar *col } static void -process_section (EMeetingListView *view, GNOME_Evolution_Addressbook_SimpleCardList *cards, icalparameter_role role) +process_section (EMeetingListView *view, EABDestination **cards, icalparameter_role role) { EMeetingListViewPrivate *priv; int i; priv = view->priv; - for (i = 0; i < cards->_length; i++) { - const char *name, *attendee = NULL, *attr; - GNOME_Evolution_Addressbook_SimpleCard card; - CORBA_Environment ev; + for (i = 0; i < G_N_ELEMENTS (cards); i++) { + const char *name, *attendee = NULL; + char *attr = NULL; - card = cards->_buffer[i]; - - CORBA_exception_init (&ev); - - /* Get the CN */ - name = GNOME_Evolution_Addressbook_SimpleCard_get (card, GNOME_Evolution_Addressbook_SimpleCard_FullName, &ev); - if (BONOBO_EX (&ev)) { - CORBA_exception_free (&ev); - continue; - } + name = eab_destination_get_name (cards[i]); /* Get the field as attendee from the backend */ - attr = cal_client_get_ldap_attribute (e_meeting_store_get_cal_client (priv->store)); - if (attr) { + if (cal_client_get_ldap_attribute (e_meeting_store_get_cal_client (priv->store), + &attr, NULL)) { /* FIXME this should be more general */ - if (!g_ascii_strcasecmp (attr, "icscalendar")) - attendee = GNOME_Evolution_Addressbook_SimpleCard_get (card, GNOME_Evolution_Addressbook_SimpleCard_Icscalendar, &ev); + if (!g_ascii_strcasecmp (attr, "icscalendar")) { + EContact *contact; + + /* FIXME: this does not work, have to use first + eab_destination_use_contact() */ + contact = eab_destination_get_contact (cards[i]); + if (contact) { + attendee = e_contact_get (contact, E_CONTACT_FREEBUSY_URL); + if (!attendee) + attendee = e_contact_get (contact, E_CONTACT_CALENDAR_URI); + } + } } - CORBA_exception_init (&ev); - /* If we couldn't get the attendee prior, get the email address as the default */ if (attendee == NULL || *attendee == '\0') { - attendee = GNOME_Evolution_Addressbook_SimpleCard_get (card, GNOME_Evolution_Addressbook_SimpleCard_Email, &ev); - if (BONOBO_EX (&ev)) { - CORBA_exception_free (&ev); - continue; - } + attendee = eab_destination_get_email (cards[i]); } - CORBA_exception_free (&ev); - if (attendee == NULL || *attendee == '\0') continue; @@ -381,22 +359,21 @@ static void select_names_ok_cb (BonoboListener *listener, const char *event_name, const CORBA_any *arg, CORBA_Environment *ev, gpointer data) { EMeetingListView *view = E_MEETING_LIST_VIEW (data); - BonoboArg *card_arg; int i; for (i = 0; sections[i] != NULL; i++) { + EABDestination **destv; + char *string = NULL; Bonobo_Control corba_control = GNOME_Evolution_Addressbook_SelectNames_getEntryBySection (view->priv->corba_select_names, sections[i], ev); GtkWidget *control_widget = bonobo_widget_new_control_from_objref (corba_control, CORBA_OBJECT_NIL); - BonoboControlFrame *control_frame = bonobo_widget_get_control_frame (BONOBO_WIDGET (control_widget)); - Bonobo_PropertyBag pb = bonobo_control_frame_get_control_property_bag (control_frame, NULL); - card_arg = bonobo_property_bag_client_get_value_any (pb, "simple_card_list", NULL); - if (card_arg != NULL) { - GNOME_Evolution_Addressbook_SimpleCardList cards; - cards = BONOBO_ARG_GET_GENERAL (card_arg, TC_GNOME_Evolution_Addressbook_SimpleCardList, - GNOME_Evolution_Addressbook_SimpleCardList, NULL); - process_section (view, &cards, roles[i]); - bonobo_arg_release (card_arg); + + bonobo_widget_get_property (BONOBO_WIDGET (control_widget), "destinations", + TC_CORBA_string, &string, NULL); + destv = eab_destination_importv (string); + if (destv) { + process_section (view, destv, roles[i]); + g_free (destv); } } } diff --git a/calendar/gui/e-meeting-model.c b/calendar/gui/e-meeting-model.c new file mode 100644 index 0000000000..4742116cf2 --- /dev/null +++ b/calendar/gui/e-meeting-model.c @@ -0,0 +1,1780 @@ +/* -*- Mod:e C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */ +/* itip-model.c + * + * Copyright (C) 2001 Ximian, Inc. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of version 2 of the GNU General Public + * License as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public + * License along with this program; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + * + * Author: JP Rosevear + */ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "Evolution-Addressbook-SelectNames.h" +#include "calendar-config.h" +#include "itip-utils.h" +#include "e-meeting-utils.h" +#include "e-meeting-attendee.h" +#include "e-meeting-model.h" + +#define SELECT_NAMES_OAFID "OAFIID:GNOME_Evolution_Addressbook_SelectNames" + +struct _EMeetingModelPrivate +{ + GPtrArray *attendees; + + GList *tables; + + CalClient *client; + icaltimezone *zone; + + EBook *ebook; + gboolean book_loaded; + gboolean book_load_wait; + + GPtrArray *refresh_queue; + GHashTable *refresh_data; + guint refresh_idle_id; + + /* For invite others dialogs */ + GNOME_Evolution_Addressbook_SelectNames corba_select_names; +}; + +#define BUF_SIZE 1024 + +static char *sections[] = {N_("Chair Persons"), + N_("Required Participants"), + N_("Optional Participants"), + N_("Resources"), + NULL}; +static icalparameter_role roles[] = {ICAL_ROLE_CHAIR, + ICAL_ROLE_REQPARTICIPANT, + ICAL_ROLE_OPTPARTICIPANT, + ICAL_ROLE_NONPARTICIPANT, + ICAL_ROLE_NONE}; + +typedef struct _EMeetingModelQueueData EMeetingModelQueueData; +struct _EMeetingModelQueueData { + EMeetingModel *im; + EMeetingAttendee *ia; + + gboolean refreshing; + + EMeetingTime start; + EMeetingTime end; + + char buffer[BUF_SIZE]; + GString *string; + + GPtrArray *call_backs; + GPtrArray *data; +}; + + +static void class_init (EMeetingModelClass *klass); +static void init (EMeetingModel *model); +static void finalize (GObject *obj); + +static void refresh_queue_add (EMeetingModel *im, int row, + EMeetingTime *start, + EMeetingTime *end, + EMeetingModelRefreshCallback call_back, + gpointer data); +static void refresh_queue_remove (EMeetingModel *im, + EMeetingAttendee *ia); +static gboolean refresh_busy_periods (gpointer data); + +static void attendee_changed_cb (EMeetingAttendee *ia, gpointer data); +static void select_names_ok_cb (BonoboListener *listener, + const char *event_name, + const CORBA_any *arg, + CORBA_Environment *ev, + gpointer data); + +static void table_destroy_state_cb (ETableScrolled *etable, gpointer data); +static void table_destroy_list_cb (ETableScrolled *etable, gpointer data); + +static ETableModelClass *parent_class = NULL; + +E_MAKE_TYPE (e_meeting_model, "EMeetingModel", EMeetingModel, + class_init, init, E_TABLE_MODEL_TYPE); + +static void +book_open_cb (EBook *book, EBookStatus status, gpointer data) +{ + EMeetingModel *im = E_MEETING_MODEL (data); + EMeetingModelPrivate *priv; + + priv = im->priv; + + priv->ebook = book; + + if (status == E_BOOK_ERROR_OK) + priv->book_loaded = TRUE; + else + g_warning ("Book not loaded"); + + if (priv->book_load_wait) { + priv->book_load_wait = FALSE; + gtk_main_quit (); + } +} + +static void +start_addressbook_server (EMeetingModel *im) +{ + e_book_async_get_default_addressbook (book_open_cb, im); +} + +static EMeetingAttendee * +find_match (EMeetingModel *im, const char *address, int *pos) +{ + EMeetingModelPrivate *priv; + EMeetingAttendee *ia; + const gchar *ia_address; + int i; + + priv = im->priv; + + if (address == NULL) + return NULL; + + /* Make sure we can add the new delegatee person */ + for (i = 0; i < priv->attendees->len; i++) { + ia = g_ptr_array_index (priv->attendees, i); + + ia_address = e_meeting_attendee_get_address (ia); + if (ia_address != NULL && !g_strcasecmp (itip_strip_mailto (ia_address), itip_strip_mailto (address))) { + if (pos != NULL) + *pos = i; + return ia; + } + } + + return NULL; +} + +static icalparameter_cutype +text_to_type (const char *type) +{ + if (!g_strcasecmp (type, _("Individual"))) + return ICAL_CUTYPE_INDIVIDUAL; + else if (!g_strcasecmp (type, _("Group"))) + return ICAL_CUTYPE_GROUP; + else if (!g_strcasecmp (type, _("Resource"))) + return ICAL_CUTYPE_RESOURCE; + else if (!g_strcasecmp (type, _("Room"))) + return ICAL_CUTYPE_ROOM; + else + return ICAL_CUTYPE_NONE; +} + +static char * +type_to_text (icalparameter_cutype type) +{ + switch (type) { + case ICAL_CUTYPE_INDIVIDUAL: + return _("Individual"); + case ICAL_CUTYPE_GROUP: + return _("Group"); + case ICAL_CUTYPE_RESOURCE: + return _("Resource"); + case ICAL_CUTYPE_ROOM: + return _("Room"); + default: + return _("Unknown"); + } + + return NULL; + +} + +static icalparameter_role +text_to_role (const char *role) +{ + if (!g_strcasecmp (role, _("Chair"))) + return ICAL_ROLE_CHAIR; + else if (!g_strcasecmp (role, _("Required Participant"))) + return ICAL_ROLE_REQPARTICIPANT; + else if (!g_strcasecmp (role, _("Optional Participant"))) + return ICAL_ROLE_OPTPARTICIPANT; + else if (!g_strcasecmp (role, _("Non-Participant"))) + return ICAL_ROLE_NONPARTICIPANT; + else + return ICAL_ROLE_NONE; +} + +static char * +role_to_text (icalparameter_role role) +{ + switch (role) { + case ICAL_ROLE_CHAIR: + return _("Chair"); + case ICAL_ROLE_REQPARTICIPANT: + return _("Required Participant"); + case ICAL_ROLE_OPTPARTICIPANT: + return _("Optional Participant"); + case ICAL_ROLE_NONPARTICIPANT: + return _("Non-Participant"); + default: + return _("Unknown"); + } + + return NULL; +} + +static gboolean +text_to_boolean (const char *role) +{ + if (!g_strcasecmp (role, _("Yes"))) + return TRUE; + else + return FALSE; +} + +static char * +boolean_to_text (gboolean b) +{ + if (b) + return _("Yes"); + else + return _("No"); +} + +static icalparameter_partstat +text_to_partstat (const char *partstat) +{ + if (!g_strcasecmp (partstat, _("Needs Action"))) + return ICAL_PARTSTAT_NEEDSACTION; + else if (!g_strcasecmp (partstat, _("Accepted"))) + return ICAL_PARTSTAT_ACCEPTED; + else if (!g_strcasecmp (partstat, _("Declined"))) + return ICAL_PARTSTAT_DECLINED; + else if (!g_strcasecmp (partstat, _("Tentative"))) + return ICAL_PARTSTAT_TENTATIVE; + else if (!g_strcasecmp (partstat, _("Delegated"))) + return ICAL_PARTSTAT_DELEGATED; + else if (!g_strcasecmp (partstat, _("Completed"))) + return ICAL_PARTSTAT_COMPLETED; + else if (!g_strcasecmp (partstat, _("In Process"))) + return ICAL_PARTSTAT_INPROCESS; + else + return ICAL_PARTSTAT_NONE; +} + +static char * +partstat_to_text (icalparameter_partstat partstat) +{ + switch (partstat) { + case ICAL_PARTSTAT_NEEDSACTION: + return _("Needs Action"); + case ICAL_PARTSTAT_ACCEPTED: + return _("Accepted"); + case ICAL_PARTSTAT_DECLINED: + return _("Declined"); + case ICAL_PARTSTAT_TENTATIVE: + return _("Tentative"); + case ICAL_PARTSTAT_DELEGATED: + return _("Delegated"); + case ICAL_PARTSTAT_COMPLETED: + return _("Completed"); + case ICAL_PARTSTAT_INPROCESS: + return _("In Process"); + case ICAL_PARTSTAT_NONE: + default: + return _("Unknown"); + } + + return NULL; +} + +static int +column_count (ETableModel *etm) +{ + return E_MEETING_MODEL_COLUMN_COUNT; +} + +static int +row_count (ETableModel *etm) +{ + EMeetingModel *im; + EMeetingModelPrivate *priv; + + im = E_MEETING_MODEL (etm); + priv = im->priv; + + return (priv->attendees->len); +} + +static void +append_row (ETableModel *etm, ETableModel *source, int row) +{ + EMeetingModel *im; + EMeetingModelPrivate *priv; + EMeetingAttendee *ia; + char *address; + + im = E_MEETING_MODEL (etm); + priv = im->priv; + + address = (char *) e_table_model_value_at (source, E_MEETING_MODEL_ADDRESS_COL, row); + if (find_match (im, address, NULL) != NULL) { + return; + } + + ia = E_MEETING_ATTENDEE (e_meeting_attendee_new ()); + + e_meeting_attendee_set_address (ia, g_strdup_printf ("MAILTO:%s", address)); + e_meeting_attendee_set_member (ia, g_strdup (e_table_model_value_at (source, E_MEETING_MODEL_MEMBER_COL, row))); + e_meeting_attendee_set_cutype (ia, text_to_type (e_table_model_value_at (source, E_MEETING_MODEL_TYPE_COL, row))); + e_meeting_attendee_set_role (ia, text_to_role (e_table_model_value_at (source, E_MEETING_MODEL_ROLE_COL, row))); + e_meeting_attendee_set_rsvp (ia, text_to_boolean (e_table_model_value_at (source, E_MEETING_MODEL_RSVP_COL, row))); + e_meeting_attendee_set_delto (ia, g_strdup (e_table_model_value_at (source, E_MEETING_MODEL_DELTO_COL, row))); + e_meeting_attendee_set_delfrom (ia, g_strdup (e_table_model_value_at (source, E_MEETING_MODEL_DELFROM_COL, row))); + e_meeting_attendee_set_status (ia, text_to_partstat (e_table_model_value_at (source, E_MEETING_MODEL_STATUS_COL, row))); + e_meeting_attendee_set_cn (ia, g_strdup (e_table_model_value_at (source, E_MEETING_MODEL_CN_COL, row))); + e_meeting_attendee_set_language (ia, g_strdup (e_table_model_value_at (source, E_MEETING_MODEL_LANGUAGE_COL, row))); + + e_meeting_model_add_attendee (E_MEETING_MODEL (etm), ia); + g_object_unref (ia); +} + +static void * +value_at (ETableModel *etm, int col, int row) +{ + EMeetingModel *im; + EMeetingModelPrivate *priv; + EMeetingAttendee *ia; + + im = E_MEETING_MODEL (etm); + priv = im->priv; + + ia = g_ptr_array_index (priv->attendees, row); + + switch (col) { + case E_MEETING_MODEL_ADDRESS_COL: + return (void *)itip_strip_mailto (e_meeting_attendee_get_address (ia)); + case E_MEETING_MODEL_MEMBER_COL: + return (void *)e_meeting_attendee_get_member (ia); + case E_MEETING_MODEL_TYPE_COL: + return type_to_text (e_meeting_attendee_get_cutype (ia)); + case E_MEETING_MODEL_ROLE_COL: + return role_to_text (e_meeting_attendee_get_role (ia)); + case E_MEETING_MODEL_RSVP_COL: + return boolean_to_text (e_meeting_attendee_get_rsvp (ia)); + case E_MEETING_MODEL_DELTO_COL: + return (void *)itip_strip_mailto (e_meeting_attendee_get_delto (ia)); + case E_MEETING_MODEL_DELFROM_COL: + return (void *)itip_strip_mailto (e_meeting_attendee_get_delfrom (ia)); + case E_MEETING_MODEL_STATUS_COL: + return partstat_to_text (e_meeting_attendee_get_status (ia)); + case E_MEETING_MODEL_CN_COL: + return (void *)e_meeting_attendee_get_cn (ia); + case E_MEETING_MODEL_LANGUAGE_COL: + return (void *)e_meeting_attendee_get_language (ia); + } + + return NULL; +} + +static void +set_value_at (ETableModel *etm, int col, int row, const void *val) +{ + EMeetingModel *im; + EMeetingModelPrivate *priv; + EMeetingAttendee *ia; + icalparameter_cutype type; + + im = E_MEETING_MODEL (etm); + priv = im->priv; + + ia = g_ptr_array_index (priv->attendees, row); + + e_table_model_pre_change (etm); + + switch (col) { + case E_MEETING_MODEL_ADDRESS_COL: + if (val != NULL && *((char *)val)) + e_meeting_attendee_set_address (ia, g_strdup_printf ("MAILTO:%s", (char *) val)); + break; + case E_MEETING_MODEL_MEMBER_COL: + e_meeting_attendee_set_member (ia, g_strdup (val)); + break; + case E_MEETING_MODEL_TYPE_COL: + type = text_to_type (val); + e_meeting_attendee_set_cutype (ia, text_to_type (val)); + if (type == ICAL_CUTYPE_RESOURCE) { + e_meeting_attendee_set_role (ia, ICAL_ROLE_NONPARTICIPANT); + e_table_model_cell_changed (etm, E_MEETING_MODEL_ROLE_COL, row); + } + break; + case E_MEETING_MODEL_ROLE_COL: + e_meeting_attendee_set_role (ia, text_to_role (val)); + break; + case E_MEETING_MODEL_RSVP_COL: + e_meeting_attendee_set_rsvp (ia, text_to_boolean (val)); + break; + case E_MEETING_MODEL_DELTO_COL: + e_meeting_attendee_set_delto (ia, g_strdup (val)); + break; + case E_MEETING_MODEL_DELFROM_COL: + e_meeting_attendee_set_delfrom (ia, g_strdup (val)); + break; + case E_MEETING_MODEL_STATUS_COL: + e_meeting_attendee_set_status (ia, text_to_partstat (val)); + break; + case E_MEETING_MODEL_CN_COL: + e_meeting_attendee_set_cn (ia, g_strdup (val)); + break; + case E_MEETING_MODEL_LANGUAGE_COL: + e_meeting_attendee_set_language (ia, g_strdup (val)); + break; + } + + e_table_model_cell_changed (etm, col, row); +} + +static gboolean +is_cell_editable (ETableModel *etm, int col, int row) +{ + EMeetingModel *im; + EMeetingModelPrivate *priv; + EMeetingAttendee *ia; + EMeetingAttendeeEditLevel level; + + im = E_MEETING_MODEL (etm); + priv = im->priv; + + if (col == E_MEETING_MODEL_DELTO_COL + || col == E_MEETING_MODEL_DELFROM_COL) + return FALSE; + + if (row == -1) + return TRUE; + if (row >= priv->attendees->len) + return TRUE; + + ia = g_ptr_array_index (priv->attendees, row); + level = e_meeting_attendee_get_edit_level (ia); + + switch (level) { + case E_MEETING_ATTENDEE_EDIT_FULL: + return TRUE; + case E_MEETING_ATTENDEE_EDIT_STATUS: + return col == E_MEETING_MODEL_STATUS_COL; + case E_MEETING_ATTENDEE_EDIT_NONE: + return FALSE; + } + + return TRUE; +} + +static void * +duplicate_value (ETableModel *etm, int col, const void *val) +{ + return g_strdup (val); +} + +static void +free_value (ETableModel *etm, int col, void *val) +{ + g_free (val); +} + +static void * +init_value (ETableModel *etm, int col) +{ + switch (col) { + case E_MEETING_MODEL_ADDRESS_COL: + return g_strdup (""); + case E_MEETING_MODEL_MEMBER_COL: + return g_strdup (""); + case E_MEETING_MODEL_TYPE_COL: + return g_strdup (_("Individual")); + case E_MEETING_MODEL_ROLE_COL: + return g_strdup (_("Required Participant")); + case E_MEETING_MODEL_RSVP_COL: + return g_strdup (_("Yes")); + case E_MEETING_MODEL_DELTO_COL: + return g_strdup (""); + case E_MEETING_MODEL_DELFROM_COL: + return g_strdup (""); + case E_MEETING_MODEL_STATUS_COL: + return g_strdup (_("Needs Action")); + case E_MEETING_MODEL_CN_COL: + return g_strdup (""); + case E_MEETING_MODEL_LANGUAGE_COL: + return g_strdup ("en"); + } + + return g_strdup (""); +} + +static gboolean +value_is_empty (ETableModel *etm, int col, const void *val) +{ + + switch (col) { + case E_MEETING_MODEL_ADDRESS_COL: + case E_MEETING_MODEL_MEMBER_COL: + case E_MEETING_MODEL_DELTO_COL: + case E_MEETING_MODEL_DELFROM_COL: + case E_MEETING_MODEL_CN_COL: + if (val && !g_strcasecmp (val, "")) + return TRUE; + else + return FALSE; + default: + ; + } + + return TRUE; +} + +static char * +value_to_string (ETableModel *etm, int col, const void *val) +{ + return g_strdup (val); +} + +static void +class_init (EMeetingModelClass *klass) +{ + GObjectClass *gobject_class; + ETableModelClass *etm_class; + + gobject_class = G_OBJECT_CLASS (klass); + etm_class = E_TABLE_MODEL_CLASS (klass); + + parent_class = g_type_class_peek_parent (klass); + + gobject_class->finalize = finalize; + + etm_class->column_count = column_count; + etm_class->row_count = row_count; + etm_class->value_at = value_at; + etm_class->set_value_at = set_value_at; + etm_class->is_cell_editable = is_cell_editable; + etm_class->append_row = append_row; + etm_class->duplicate_value = duplicate_value; + etm_class->free_value = free_value; + etm_class->initialize_value = init_value; + etm_class->value_is_empty = value_is_empty; + etm_class->value_to_string = value_to_string; +} + + +static void +init (EMeetingModel *im) +{ + EMeetingModelPrivate *priv; + + priv = g_new0 (EMeetingModelPrivate, 1); + + im->priv = priv; + + priv->attendees = g_ptr_array_new (); + + priv->tables = NULL; + + priv->client = NULL; + priv->zone = icaltimezone_get_builtin_timezone (calendar_config_get_timezone ()); + + priv->ebook = NULL; + priv->book_loaded = FALSE; + priv->book_load_wait = FALSE; + + priv->refresh_queue = g_ptr_array_new (); + priv->refresh_data = g_hash_table_new (g_direct_hash, g_direct_equal); + priv->refresh_idle_id = 0; + + priv->corba_select_names = CORBA_OBJECT_NIL; + + start_addressbook_server (im); +} + +static void +finalize (GObject *obj) +{ + EMeetingModel *im = E_MEETING_MODEL (obj); + EMeetingModelPrivate *priv; + GList *l; + int i; + + priv = im->priv; + + for (i = 0; i < priv->attendees->len; i++) + g_object_unref (g_ptr_array_index (priv->attendees, i)); + g_ptr_array_free (priv->attendees, TRUE); + + for (l = priv->tables; l != NULL; l = l->next) + g_signal_handlers_disconnect_matched (G_OBJECT (l->data), G_SIGNAL_MATCH_DATA, + 0, 0, NULL, NULL, im); + g_list_free (priv->tables); + + if (priv->client != NULL) + g_object_unref (priv->client); + + if (priv->ebook != NULL) + g_object_unref (priv->ebook); + + if (priv->corba_select_names != CORBA_OBJECT_NIL) { + CORBA_Environment ev; + CORBA_exception_init (&ev); + bonobo_object_release_unref (priv->corba_select_names, &ev); + CORBA_exception_free (&ev); + } + + while (priv->refresh_queue->len > 0) + refresh_queue_remove (im, g_ptr_array_index (priv->refresh_queue, 0)); + g_ptr_array_free (priv->refresh_queue, TRUE); + g_hash_table_destroy (priv->refresh_data); + + if (priv->refresh_idle_id) + g_source_remove (priv->refresh_idle_id); + + g_free (priv); + + if (G_OBJECT_CLASS (parent_class)->finalize) + (* G_OBJECT_CLASS (parent_class)->finalize) (obj); +} + +GtkObject * +e_meeting_model_new (void) +{ + return g_object_new (E_TYPE_MEETING_MODEL, NULL); +} + + +CalClient * +e_meeting_model_get_cal_client (EMeetingModel *im) +{ + EMeetingModelPrivate *priv; + + priv = im->priv; + + return priv->client; +} + +void +e_meeting_model_set_cal_client (EMeetingModel *im, CalClient *client) +{ + EMeetingModelPrivate *priv; + + priv = im->priv; + + if (priv->client != NULL) + g_object_unref (priv->client); + + if (client != NULL) + g_object_ref (client); + priv->client = client; +} + +icaltimezone * +e_meeting_model_get_zone (EMeetingModel *im) +{ + EMeetingModelPrivate *priv; + + g_return_val_if_fail (im != NULL, NULL); + g_return_val_if_fail (E_IS_MEETING_MODEL (im), NULL); + + priv = im->priv; + + return priv->zone; +} + +void +e_meeting_model_set_zone (EMeetingModel *im, icaltimezone *zone) +{ + EMeetingModelPrivate *priv; + + g_return_if_fail (im != NULL); + g_return_if_fail (E_IS_MEETING_MODEL (im)); + + priv = im->priv; + + priv->zone = zone; +} + +static ETableScrolled * +build_etable (ETableModel *model, const gchar *spec_file, const gchar *state_file) +{ + GtkWidget *etable; + ETable *real_table; + ETableExtras *extras; + GList *strings; + ECell *popup_cell, *cell; + + extras = e_table_extras_new (); + + /* For type */ + cell = e_cell_text_new (NULL, GTK_JUSTIFY_LEFT); + popup_cell = e_cell_combo_new (); + e_cell_popup_set_child (E_CELL_POPUP (popup_cell), cell); + g_object_unref (cell); + + strings = NULL; + strings = g_list_append (strings, (char*) _("Individual")); + strings = g_list_append (strings, (char*) _("Group")); + strings = g_list_append (strings, (char*) _("Resource")); + strings = g_list_append (strings, (char*) _("Room")); + strings = g_list_append (strings, (char*) _("Unknown")); + + e_cell_combo_set_popdown_strings (E_CELL_COMBO (popup_cell), strings); + e_table_extras_add_cell (extras, "typeedit", popup_cell); + + /* For role */ + cell = e_cell_text_new (NULL, GTK_JUSTIFY_LEFT); + popup_cell = e_cell_combo_new (); + e_cell_popup_set_child (E_CELL_POPUP (popup_cell), cell); + g_object_unref (cell); + + strings = NULL; + strings = g_list_append (strings, (char*) _("Chair")); + strings = g_list_append (strings, (char*) _("Required Participant")); + strings = g_list_append (strings, (char*) _("Optional Participant")); + strings = g_list_append (strings, (char*) _("Non-Participant")); + strings = g_list_append (strings, (char*) _("Unknown")); + + e_cell_combo_set_popdown_strings (E_CELL_COMBO (popup_cell), strings); + e_table_extras_add_cell (extras, "roleedit", popup_cell); + + /* For rsvp */ + cell = e_cell_text_new (NULL, GTK_JUSTIFY_LEFT); + popup_cell = e_cell_combo_new (); + e_cell_popup_set_child (E_CELL_POPUP (popup_cell), cell); + g_object_unref (cell); + + strings = NULL; + strings = g_list_append (strings, (char*) _("Yes")); + strings = g_list_append (strings, (char*) _("No")); + + e_cell_combo_set_popdown_strings (E_CELL_COMBO (popup_cell), strings); + e_table_extras_add_cell (extras, "rsvpedit", popup_cell); + + /* For status */ + cell = e_cell_text_new (NULL, GTK_JUSTIFY_LEFT); + popup_cell = e_cell_combo_new (); + e_cell_popup_set_child (E_CELL_POPUP (popup_cell), cell); + g_object_unref (cell); + + strings = NULL; + strings = g_list_append (strings, (char*) _("Needs Action")); + strings = g_list_append (strings, (char*) _("Accepted")); + strings = g_list_append (strings, (char*) _("Declined")); + strings = g_list_append (strings, (char*) _("Tentative")); + strings = g_list_append (strings, (char*) _("Delegated")); + + e_cell_combo_set_popdown_strings (E_CELL_COMBO (popup_cell), strings); + e_table_extras_add_cell (extras, "statusedit", popup_cell); + + etable = e_table_scrolled_new_from_spec_file (model, extras, spec_file, NULL); + real_table = e_table_scrolled_get_table (E_TABLE_SCROLLED (etable)); + g_object_set (G_OBJECT (real_table), "uniform_row_height", TRUE, NULL); + e_table_load_state (real_table, state_file); + +#if 0 + g_signal_connect (real_table, "right_click", G_CALLBACK (right_click_cb), mpage); +#endif + + g_signal_connect (etable, "destroy", G_CALLBACK (table_destroy_state_cb), g_strdup (state_file)); + + g_object_unref (extras); + + return E_TABLE_SCROLLED (etable); +} + +void +e_meeting_model_add_attendee (EMeetingModel *im, EMeetingAttendee *ia) +{ + EMeetingModelPrivate *priv; + + priv = im->priv; + + e_table_model_pre_change (E_TABLE_MODEL (im)); + + g_object_ref (ia); + g_ptr_array_add (priv->attendees, ia); + + g_signal_connect (ia, "changed", G_CALLBACK (attendee_changed_cb), im); + + e_table_model_row_inserted (E_TABLE_MODEL (im), row_count (E_TABLE_MODEL (im)) - 1); +} + +EMeetingAttendee * +e_meeting_model_add_attendee_with_defaults (EMeetingModel *im) +{ + EMeetingAttendee *ia; + char *str; + + ia = E_MEETING_ATTENDEE (e_meeting_attendee_new ()); + + e_meeting_attendee_set_address (ia, init_value (E_TABLE_MODEL (im), E_MEETING_MODEL_ADDRESS_COL)); + e_meeting_attendee_set_member (ia, init_value (E_TABLE_MODEL (im), E_MEETING_MODEL_MEMBER_COL)); + + str = init_value (E_TABLE_MODEL (im), E_MEETING_MODEL_TYPE_COL); + e_meeting_attendee_set_cutype (ia, text_to_type (str)); + g_free (str); + str = init_value (E_TABLE_MODEL (im), E_MEETING_MODEL_ROLE_COL); + e_meeting_attendee_set_role (ia, text_to_role (str)); + g_free (str); + str = init_value (E_TABLE_MODEL (im), E_MEETING_MODEL_RSVP_COL); + e_meeting_attendee_set_rsvp (ia, text_to_boolean (str)); + g_free (str); + + e_meeting_attendee_set_delto (ia, init_value (E_TABLE_MODEL (im), E_MEETING_MODEL_DELTO_COL)); + e_meeting_attendee_set_delfrom (ia, init_value (E_TABLE_MODEL (im), E_MEETING_MODEL_DELFROM_COL)); + + str = init_value (E_TABLE_MODEL (im), E_MEETING_MODEL_STATUS_COL); + e_meeting_attendee_set_status (ia, text_to_partstat (str)); + g_free (str); + + e_meeting_attendee_set_cn (ia, init_value (E_TABLE_MODEL (im), E_MEETING_MODEL_CN_COL)); + e_meeting_attendee_set_language (ia, init_value (E_TABLE_MODEL (im), E_MEETING_MODEL_LANGUAGE_COL)); + + e_meeting_model_add_attendee (im, ia); + + return ia; +} + +void +e_meeting_model_remove_attendee (EMeetingModel *im, EMeetingAttendee *ia) +{ + EMeetingModelPrivate *priv; + gint i, row = -1; + + priv = im->priv; + + for (i = 0; i < priv->attendees->len; i++) { + if (ia == g_ptr_array_index (priv->attendees, i)) { + row = i; + break; + } + } + + if (row != -1) { + e_table_model_pre_change (E_TABLE_MODEL (im)); + + g_ptr_array_remove_index (priv->attendees, row); + g_object_unref (ia); + + e_table_model_row_deleted (E_TABLE_MODEL (im), row); + } +} + +void +e_meeting_model_remove_all_attendees (EMeetingModel *im) +{ + EMeetingModelPrivate *priv; + gint i, len; + + priv = im->priv; + + e_table_model_pre_change (E_TABLE_MODEL (im)); + + len = priv->attendees->len; + + for (i = 0; i < len; i++) { + EMeetingAttendee *ia = g_ptr_array_index (priv->attendees, i); + g_object_unref (ia); + } + g_ptr_array_set_size (priv->attendees, 0); + + e_table_model_rows_deleted (E_TABLE_MODEL (im), 0, len); +} + +EMeetingAttendee * +e_meeting_model_find_attendee (EMeetingModel *im, const gchar *address, gint *row) +{ + EMeetingModelPrivate *priv; + EMeetingAttendee *ia; + int i; + + priv = im->priv; + + if (address == NULL) + return NULL; + + for (i = 0; i < priv->attendees->len; i++) { + const gchar *ia_address; + + ia = g_ptr_array_index (priv->attendees, i); + + ia_address = e_meeting_attendee_get_address (ia); + if (ia_address && !g_strcasecmp (itip_strip_mailto (ia_address), itip_strip_mailto (address))) { + if (row != NULL) + *row = i; + + return ia; + } + } + + return NULL; +} + +EMeetingAttendee * +e_meeting_model_find_attendee_at_row (EMeetingModel *im, gint row) +{ + EMeetingModelPrivate *priv; + + g_return_val_if_fail (im != NULL, NULL); + g_return_val_if_fail (E_IS_MEETING_MODEL (im), NULL); + g_return_val_if_fail (row >= 0, NULL); + + priv = im->priv; + g_return_val_if_fail (row < priv->attendees->len, NULL); + + return g_ptr_array_index (priv->attendees, row); +} + +gint +e_meeting_model_count_actual_attendees (EMeetingModel *im) +{ + EMeetingModelPrivate *priv; + + priv = im->priv; + + return e_table_model_row_count (E_TABLE_MODEL (im)); +} + +const GPtrArray * +e_meeting_model_get_attendees (EMeetingModel *im) +{ + EMeetingModelPrivate *priv; + + priv = im->priv; + + return priv->attendees; +} + +static icaltimezone * +find_zone (icalproperty *ip, icalcomponent *tz_top_level) +{ + icalparameter *param; + icalcomponent *sub_comp; + const char *tzid; + icalcompiter iter; + + if (tz_top_level == NULL) + return NULL; + + param = icalproperty_get_first_parameter (ip, ICAL_TZID_PARAMETER); + if (param == NULL) + return NULL; + tzid = icalparameter_get_tzid (param); + + iter = icalcomponent_begin_component (tz_top_level, ICAL_VTIMEZONE_COMPONENT); + while ((sub_comp = icalcompiter_deref (&iter)) != NULL) { + icalcomponent *clone; + const char *tz_tzid; + + /* FIXME We aren't passing a property here */ + tz_tzid = icalproperty_get_tzid (sub_comp); + if (!strcmp (tzid, tz_tzid)) { + icaltimezone *zone; + + zone = icaltimezone_new (); + clone = icalcomponent_new_clone (sub_comp); + icaltimezone_set_component (zone, clone); + + return zone; + } + + icalcompiter_next (&iter); + } + + return NULL; +} + + +static void +refresh_queue_add (EMeetingModel *im, int row, + EMeetingTime *start, + EMeetingTime *end, + EMeetingModelRefreshCallback call_back, + gpointer data) +{ + EMeetingModelPrivate *priv; + EMeetingAttendee *ia; + EMeetingModelQueueData *qdata; + + priv = im->priv; + + ia = g_ptr_array_index (priv->attendees, row); + if (ia == NULL) + return; + + qdata = g_hash_table_lookup (priv->refresh_data, ia); + if (qdata == NULL) { + qdata = g_new0 (EMeetingModelQueueData, 1); + + qdata->im = im; + qdata->ia = ia; + e_meeting_attendee_clear_busy_periods (ia); + e_meeting_attendee_set_has_calendar_info (ia, FALSE); + + qdata->start = *start; + qdata->end = *end; + qdata->string = g_string_new (NULL); + qdata->call_backs = g_ptr_array_new (); + qdata->data = g_ptr_array_new (); + g_ptr_array_add (qdata->call_backs, call_back); + g_ptr_array_add (qdata->data, data); + + g_hash_table_insert (priv->refresh_data, ia, qdata); + } else { + if (e_meeting_time_compare_times (start, &qdata->start) == -1) + qdata->start = *start; + if (e_meeting_time_compare_times (end, &qdata->end) == 1) + qdata->end = *end; + g_ptr_array_add (qdata->call_backs, call_back); + g_ptr_array_add (qdata->data, data); + } + + g_object_ref (ia); + g_ptr_array_add (priv->refresh_queue, ia); + + if (priv->refresh_idle_id == 0) + priv->refresh_idle_id = g_idle_add (refresh_busy_periods, im); +} + +static void +refresh_queue_remove (EMeetingModel *im, EMeetingAttendee *ia) +{ + EMeetingModelPrivate *priv; + EMeetingModelQueueData *qdata; + + priv = im->priv; + + /* Free the queue data */ + qdata = g_hash_table_lookup (priv->refresh_data, ia); + g_assert (qdata != NULL); + + g_hash_table_remove (priv->refresh_data, ia); + g_ptr_array_free (qdata->call_backs, TRUE); + g_ptr_array_free (qdata->data, TRUE); + g_free (qdata); + + /* Unref the attendee */ + g_ptr_array_remove (priv->refresh_queue, ia); + g_object_unref (ia); +} + +static void +process_callbacks (EMeetingModelQueueData *qdata) +{ + EMeetingModel *im; + int i; + + for (i = 0; i < qdata->call_backs->len; i++) { + EMeetingModelRefreshCallback call_back; + gpointer *data; + + call_back = g_ptr_array_index (qdata->call_backs, i); + data = g_ptr_array_index (qdata->data, i); + + call_back (data); + } + + im = qdata->im; + refresh_queue_remove (qdata->im, qdata->ia); + g_object_unref (im); +} + +static void +process_free_busy_comp (EMeetingAttendee *ia, + icalcomponent *fb_comp, + icaltimezone *zone, + icalcomponent *tz_top_level) +{ + icalproperty *ip; + + ip = icalcomponent_get_first_property (fb_comp, ICAL_DTSTART_PROPERTY); + if (ip != NULL) { + struct icaltimetype dtstart; + icaltimezone *ds_zone; + + dtstart = icalproperty_get_dtstart (ip); + if (!dtstart.is_utc) + ds_zone = find_zone (ip, tz_top_level); + else + ds_zone = icaltimezone_get_utc_timezone (); + icaltimezone_convert_time (&dtstart, ds_zone, zone); + e_meeting_attendee_set_start_busy_range (ia, + dtstart.year, + dtstart.month, + dtstart.day, + dtstart.hour, + dtstart.minute); + } + + ip = icalcomponent_get_first_property (fb_comp, ICAL_DTEND_PROPERTY); + if (ip != NULL) { + struct icaltimetype dtend; + icaltimezone *de_zone; + + dtend = icalproperty_get_dtend (ip); + if (!dtend.is_utc) + de_zone = find_zone (ip, tz_top_level); + else + de_zone = icaltimezone_get_utc_timezone (); + icaltimezone_convert_time (&dtend, de_zone, zone); + e_meeting_attendee_set_end_busy_range (ia, + dtend.year, + dtend.month, + dtend.day, + dtend.hour, + dtend.minute); + } + + ip = icalcomponent_get_first_property (fb_comp, ICAL_FREEBUSY_PROPERTY); + while (ip != NULL) { + icalparameter *param; + struct icalperiodtype fb; + EMeetingFreeBusyType busy_type = E_MEETING_FREE_BUSY_LAST; + icalparameter_fbtype fbtype = ICAL_FBTYPE_BUSY; + + fb = icalproperty_get_freebusy (ip); + param = icalproperty_get_first_parameter (ip, ICAL_FBTYPE_PARAMETER); + if (param != NULL) + fbtype = icalparameter_get_fbtype (param); + + switch (fbtype) { + case ICAL_FBTYPE_BUSY: + busy_type = E_MEETING_FREE_BUSY_BUSY; + break; + + case ICAL_FBTYPE_BUSYUNAVAILABLE: + busy_type = E_MEETING_FREE_BUSY_OUT_OF_OFFICE; + break; + + case ICAL_FBTYPE_BUSYTENTATIVE: + busy_type = E_MEETING_FREE_BUSY_TENTATIVE; + break; + + default: + break; + } + + if (busy_type != E_MEETING_FREE_BUSY_LAST) { + icaltimezone *utc_zone = icaltimezone_get_utc_timezone (); + + icaltimezone_convert_time (&fb.start, utc_zone, zone); + icaltimezone_convert_time (&fb.end, utc_zone, zone); + e_meeting_attendee_add_busy_period (ia, + fb.start.year, + fb.start.month, + fb.start.day, + fb.start.hour, + fb.start.minute, + fb.end.year, + fb.end.month, + fb.end.day, + fb.end.hour, + fb.end.minute, + busy_type); + } + + ip = icalcomponent_get_next_property (fb_comp, ICAL_FREEBUSY_PROPERTY); + } +} + +static void +process_free_busy (EMeetingModelQueueData *qdata, char *text) +{ + EMeetingModel *im = qdata->im; + EMeetingModelPrivate *priv; + EMeetingAttendee *ia = qdata->ia; + icalcomponent *main_comp; + icalcomponent_kind kind = ICAL_NO_COMPONENT; + + priv = im->priv; + + main_comp = icalparser_parse_string (text); + if (main_comp == NULL) { + process_callbacks (qdata); + return; + } + + kind = icalcomponent_isa (main_comp); + if (kind == ICAL_VCALENDAR_COMPONENT) { + icalcompiter iter; + icalcomponent *tz_top_level, *sub_comp; + + tz_top_level = cal_util_new_top_level (); + + iter = icalcomponent_begin_component (main_comp, ICAL_VTIMEZONE_COMPONENT); + while ((sub_comp = icalcompiter_deref (&iter)) != NULL) { + icalcomponent *clone; + + clone = icalcomponent_new_clone (sub_comp); + icalcomponent_add_component (tz_top_level, clone); + + icalcompiter_next (&iter); + } + + iter = icalcomponent_begin_component (main_comp, ICAL_VFREEBUSY_COMPONENT); + while ((sub_comp = icalcompiter_deref (&iter)) != NULL) { + process_free_busy_comp (ia, sub_comp, priv->zone, tz_top_level); + + icalcompiter_next (&iter); + } + icalcomponent_free (tz_top_level); + } else if (kind == ICAL_VFREEBUSY_COMPONENT) { + process_free_busy_comp (ia, main_comp, priv->zone, NULL); + } + + icalcomponent_free (main_comp); + + process_callbacks (qdata); +} + +static void +async_close (GnomeVFSAsyncHandle *handle, + GnomeVFSResult result, + gpointer data) +{ + EMeetingModelQueueData *qdata = data; + + process_free_busy (qdata, qdata->string->str); +} + +static void +async_read (GnomeVFSAsyncHandle *handle, + GnomeVFSResult result, + gpointer buffer, + GnomeVFSFileSize requested, + GnomeVFSFileSize read, + gpointer data) +{ + EMeetingModelQueueData *qdata = data; + GnomeVFSFileSize buf_size = BUF_SIZE - 1; + + if (result != GNOME_VFS_OK && result != GNOME_VFS_ERROR_EOF) { + gnome_vfs_async_close (handle, async_close, qdata); + return; + } + + ((char *)buffer)[read] = '\0'; + qdata->string = g_string_append (qdata->string, buffer); + + if (result == GNOME_VFS_ERROR_EOF) { + gnome_vfs_async_close (handle, async_close, qdata); + return; + } + + gnome_vfs_async_read (handle, qdata->buffer, buf_size, async_read, qdata); +} + +static void +async_open (GnomeVFSAsyncHandle *handle, + GnomeVFSResult result, + gpointer data) +{ + EMeetingModelQueueData *qdata = data; + GnomeVFSFileSize buf_size = BUF_SIZE - 1; + + if (result != GNOME_VFS_OK) { + gnome_vfs_async_close (handle, async_close, qdata); + return; + } + + gnome_vfs_async_read (handle, qdata->buffer, buf_size, async_read, qdata); +} + +static void +contacts_cb (EBook *book, EBookStatus status, GList *contacts, gpointer data) +{ + EMeetingModelQueueData *qdata = data; + GList *l; + + if (status != E_BOOK_ERROR_OK) + return; + + for (l = contacts; l; l = l->next) { + GnomeVFSAsyncHandle *handle; + EContact *contact = E_CONTACT (l->data); + const char *fburl = e_contact_get_const (contact, E_CONTACT_FREEBUSY_URL); + + if (!fburl || !*fburl) + continue; + + /* Read in free/busy data from the url */ + gnome_vfs_async_open (&handle, fburl, GNOME_VFS_OPEN_READ, + GNOME_VFS_PRIORITY_DEFAULT, async_open, qdata); + + e_free_object_list (contacts); + return; + } + + process_callbacks (qdata); + e_free_object_list (contacts); +} + +static gboolean +refresh_busy_periods (gpointer data) +{ + EMeetingModel *im = E_MEETING_MODEL (data); + EMeetingModelPrivate *priv; + EMeetingAttendee *ia = NULL; + EMeetingModelQueueData *qdata = NULL; + char *query; + int i; + + priv = im->priv; + + /* Check to see if there are any remaining attendees in the queue */ + for (i = 0; i < priv->refresh_queue->len; i++) { + ia = g_ptr_array_index (priv->refresh_queue, i); + g_assert (ia != NULL); + + qdata = g_hash_table_lookup (priv->refresh_data, ia); + g_assert (qdata != NULL); + + if (!qdata->refreshing) + break; + } + + /* The everything in the queue is being refreshed */ + if (i >= priv->refresh_queue->len) { + priv->refresh_idle_id = 0; + return FALSE; + } + + /* Indicate we are trying to refresh it */ + qdata->refreshing = TRUE; + + /* We take a ref in case we get destroyed in the gui during a callback */ + g_object_ref (qdata->im); + + /* Check the server for free busy data */ + if (priv->client) { + GList *fb_data = NULL, *users = NULL; + struct icaltimetype itt; + time_t startt, endt; + const char *user; + + itt = icaltime_null_time (); + itt.year = g_date_year (&qdata->start.date); + itt.month = g_date_month (&qdata->start.date); + itt.day = g_date_day (&qdata->start.date); + itt.hour = qdata->start.hour; + itt.minute = qdata->start.minute; + startt = icaltime_as_timet_with_zone (itt, priv->zone); + + itt = icaltime_null_time (); + itt.year = g_date_year (&qdata->end.date); + itt.month = g_date_month (&qdata->end.date); + itt.day = g_date_day (&qdata->end.date); + itt.hour = qdata->end.hour; + itt.minute = qdata->end.minute; + endt = icaltime_as_timet_with_zone (itt, priv->zone); + + user = itip_strip_mailto (e_meeting_attendee_get_address (ia)); + users = g_list_append (users, g_strdup (user)); + + /* FIXME Error checking */ + cal_client_get_free_busy (priv->client, users, startt, endt, &fb_data, NULL); + + g_list_foreach (users, (GFunc)g_free, NULL); + g_list_free (users); + + if (fb_data != NULL) { + CalComponent *comp = fb_data->data; + char *comp_str; + + comp_str = cal_component_get_as_string (comp); + process_free_busy (qdata, comp_str); + g_free (comp_str); + return TRUE; + } + } + + /* Look for fburl's of attendee with no free busy info on server */ + if (!priv->book_loaded) { + priv->book_load_wait = TRUE; + gtk_main (); + } + + if (!e_meeting_attendee_is_set_address (ia)) { + process_callbacks (qdata); + return TRUE; + } + + query = g_strdup_printf ("(is \"email\" \"%s\")", + itip_strip_mailto (e_meeting_attendee_get_address (ia))); + if (!e_book_async_get_contacts (priv->ebook, query, contacts_cb, qdata)) + process_callbacks (qdata); + g_free (query); + + return TRUE; +} + +void +e_meeting_model_refresh_all_busy_periods (EMeetingModel *im, + EMeetingTime *start, + EMeetingTime *end, + EMeetingModelRefreshCallback call_back, + gpointer data) +{ + EMeetingModelPrivate *priv; + int i; + + g_return_if_fail (im != NULL); + g_return_if_fail (E_IS_MEETING_MODEL (im)); + + priv = im->priv; + + for (i = 0; i < priv->attendees->len; i++) + refresh_queue_add (im, i, start, end, call_back, data); +} + +void +e_meeting_model_refresh_busy_periods (EMeetingModel *im, + int row, + EMeetingTime *start, + EMeetingTime *end, + EMeetingModelRefreshCallback call_back, + gpointer data) +{ + EMeetingModelPrivate *priv; + + g_return_if_fail (im != NULL); + g_return_if_fail (E_IS_MEETING_MODEL (im)); + + priv = im->priv; + + refresh_queue_add (im, row, start, end, call_back, data); +} + +ETableScrolled * +e_meeting_model_etable_from_model (EMeetingModel *im, const gchar *spec_file, const gchar *state_file) +{ + EMeetingModelPrivate *priv; + ETableScrolled *ets; + + g_return_val_if_fail (im != NULL, NULL); + g_return_val_if_fail (E_IS_MEETING_MODEL (im), NULL); + + priv = im->priv; + + ets = build_etable (E_TABLE_MODEL (im), spec_file, state_file); + + priv->tables = g_list_prepend (priv->tables, ets); + + g_signal_connect (ets, "destroy", G_CALLBACK (table_destroy_list_cb), im); + + return ets; +} + +void +e_meeting_model_etable_click_to_add (EMeetingModel *im, gboolean click_to_add) +{ + EMeetingModelPrivate *priv; + GList *l; + + g_return_if_fail (im != NULL); + g_return_if_fail (E_IS_MEETING_MODEL (im)); + + priv = im->priv; + + for (l = priv->tables; l != NULL; l = l->next) { + ETableScrolled *ets; + ETable *real_table; + + ets = l->data; + real_table = e_table_scrolled_get_table (ets); + + g_object_set (G_OBJECT (real_table), "use_click_to_add", click_to_add, NULL); + } +} + +int +e_meeting_model_etable_model_to_view_row (ETable *et, EMeetingModel *im, int model_row) +{ + EMeetingModelPrivate *priv; + + g_return_val_if_fail (im != NULL, -1); + g_return_val_if_fail (E_IS_MEETING_MODEL (im), -1); + + priv = im->priv; + + return e_table_model_to_view_row (et, model_row); +} + +int +e_meeting_model_etable_view_to_model_row (ETable *et, EMeetingModel *im, int view_row) +{ + EMeetingModelPrivate *priv; + + g_return_val_if_fail (im != NULL, -1); + g_return_val_if_fail (E_IS_MEETING_MODEL (im), -1); + + priv = im->priv; + + return e_table_view_to_model_row (et, view_row); +} + + +static void +add_section (GNOME_Evolution_Addressbook_SelectNames corba_select_names, const char *name) +{ + CORBA_Environment ev; + + CORBA_exception_init (&ev); + + GNOME_Evolution_Addressbook_SelectNames_addSection (corba_select_names, + name, + gettext (name), + &ev); + + CORBA_exception_free (&ev); +} + +static gboolean +get_select_name_dialog (EMeetingModel *im) +{ + EMeetingModelPrivate *priv; + CORBA_Environment ev; + int i; + + priv = im->priv; + + if (priv->corba_select_names != CORBA_OBJECT_NIL) { + Bonobo_Control corba_control; + GtkWidget *control_widget; + int i; + + CORBA_exception_init (&ev); + for (i = 0; sections[i] != NULL; i++) { + corba_control = GNOME_Evolution_Addressbook_SelectNames_getEntryBySection + (priv->corba_select_names, sections[i], &ev); + if (BONOBO_EX (&ev)) { + CORBA_exception_free (&ev); + return FALSE; + } + + control_widget = bonobo_widget_new_control_from_objref (corba_control, CORBA_OBJECT_NIL); + + bonobo_widget_set_property (BONOBO_WIDGET (control_widget), "text", TC_CORBA_string, "", NULL); + } + CORBA_exception_free (&ev); + + return TRUE; + } + + CORBA_exception_init (&ev); + + priv->corba_select_names = bonobo_activation_activate_from_id (SELECT_NAMES_OAFID, 0, NULL, &ev); + + for (i = 0; sections[i] != NULL; i++) + add_section (priv->corba_select_names, sections[i]); + + bonobo_event_source_client_add_listener (priv->corba_select_names, + (BonoboListenerCallbackFn) select_names_ok_cb, + "GNOME/Evolution:ok:dialog", + NULL, im); + + if (BONOBO_EX (&ev)) { + CORBA_exception_free (&ev); + return FALSE; + } + + CORBA_exception_free (&ev); + + return TRUE; +} + +void +e_meeting_model_invite_others_dialog (EMeetingModel *im) +{ + EMeetingModelPrivate *priv; + CORBA_Environment ev; + + priv = im->priv; + + if (!get_select_name_dialog (im)) + return; + + CORBA_exception_init (&ev); + + GNOME_Evolution_Addressbook_SelectNames_activateDialog ( + priv->corba_select_names, _("Required Participants"), &ev); + + CORBA_exception_free (&ev); +} + +static void +process_section (EMeetingModel *im, EABDestination **destv, icalparameter_role role) +{ + EMeetingModelPrivate *priv; + int i; + + if (!destv) + return; + + priv = im->priv; + for (i = 0; destv[i]; i++) { + EMeetingAttendee *ia; + const char *name, *attendee = NULL; + char *attr; + CORBA_Environment ev; + EABDestination *dest = destv[i]; + + CORBA_exception_init (&ev); + + /* Get the CN */ + name = eab_destination_get_name (dest); + + /* Get the field as attendee from the backend */ + if (cal_client_get_ldap_attribute (priv->client, &attr, NULL) && attr) { + /* FIXME this should be more general */ + if (!strcmp (attr, "icscalendar")) { + EContact *contact = eab_destination_get_contact (dest); + if (contact) + attendee = e_contact_get_const (contact, E_CONTACT_ICS_CALENDAR); + } + + g_free (attr); + } + + CORBA_exception_init (&ev); + + /* If we couldn't get the attendee prior, get the email address as the default */ + if (attendee == NULL || *attendee == '\0') { + attendee = eab_destination_get_email (dest); + } + + CORBA_exception_free (&ev); + + if (attendee == NULL || *attendee == '\0') + continue; + + if (e_meeting_model_find_attendee (im, attendee, NULL) == NULL) { + ia = e_meeting_model_add_attendee_with_defaults (im); + + e_meeting_attendee_set_address (ia, g_strdup_printf ("MAILTO:%s", attendee)); + e_meeting_attendee_set_role (ia, role); + if (role == ICAL_ROLE_NONPARTICIPANT) + e_meeting_attendee_set_cutype (ia, ICAL_CUTYPE_RESOURCE); + e_meeting_attendee_set_cn (ia, g_strdup (name)); + } + } +} + +static void +select_names_ok_cb (BonoboListener *listener, + const char *event_name, + const CORBA_any *arg, + CORBA_Environment *ev, + gpointer data) +{ + EMeetingModel *im = data; + EMeetingModelPrivate *priv; + Bonobo_Control corba_control; + GtkWidget *control_widget; + BonoboControlFrame *control_frame; + Bonobo_PropertyBag pb; + char *dest_str; + EABDestination **dest; + int i; + + priv = im->priv; + + for (i = 0; sections[i] != NULL; i++) { + corba_control = GNOME_Evolution_Addressbook_SelectNames_getEntryBySection + (priv->corba_select_names, sections[i], ev); + control_widget = bonobo_widget_new_control_from_objref + (corba_control, CORBA_OBJECT_NIL); + + control_frame = bonobo_widget_get_control_frame (BONOBO_WIDGET (control_widget)); + pb = bonobo_control_frame_get_control_property_bag (control_frame, NULL); + dest_str = bonobo_pbclient_get_string (pb, "destinations", NULL); + dest = eab_destination_importv (dest_str); + process_section (im, dest, roles[i]); + eab_destination_freev (dest); + } +} + +static void +attendee_changed_cb (EMeetingAttendee *ia, gpointer data) +{ + EMeetingModel *im = E_MEETING_MODEL (data); + EMeetingModelPrivate *priv; + gint row = -1, i; + + priv = im->priv; + + /* FIXME: Ideally I think you are supposed to call pre_change() before + the data structures are changed. */ + e_table_model_pre_change (E_TABLE_MODEL (im)); + + for (i = 0; i < priv->attendees->len; i++) { + if (ia == g_ptr_array_index (priv->attendees, i)) { + row = i; + break; + } + } + + if (row == -1) + e_table_model_no_change (E_TABLE_MODEL (im)); + else + e_table_model_row_changed (E_TABLE_MODEL (im), row); +} + +static void +table_destroy_state_cb (ETableScrolled *etable, gpointer data) +{ + ETable *real_table; + char *filename = data; + + real_table = e_table_scrolled_get_table (etable); + e_table_save_state (real_table, filename); + + g_free (data); +} + +static void +table_destroy_list_cb (ETableScrolled *etable, gpointer data) +{ + EMeetingModel *im = E_MEETING_MODEL (data); + EMeetingModelPrivate *priv; + + priv = im->priv; + + priv->tables = g_list_remove (priv->tables, etable); +} + diff --git a/calendar/gui/e-meeting-model.h b/calendar/gui/e-meeting-model.h new file mode 100644 index 0000000000..50fba6c7a6 --- /dev/null +++ b/calendar/gui/e-meeting-model.h @@ -0,0 +1,116 @@ +/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */ +/* e-model.h + * + * Copyright (C) 2001 Ximian, Inc. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of version 2 of the GNU General Public + * License as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public + * License along with this program; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + * + * Author: JP Rosevear + */ + +#ifndef _E_MEETING_MODEL_H_ +#define _E_MEETING_MODEL_H_ + +#include +#include +#include +#include +#include "e-meeting-attendee.h" + +G_BEGIN_DECLS + +#define E_TYPE_MEETING_MODEL (e_meeting_model_get_type ()) +#define E_MEETING_MODEL(obj) (GTK_CHECK_CAST ((obj), E_TYPE_MEETING_MODEL, EMeetingModel)) +#define E_MEETING_MODEL_CLASS(klass) (GTK_CHECK_CLASS_CAST ((klass), E_TYPE_MEETING_MODEL, EMeetingModelClass)) +#define E_IS_MEETING_MODEL(obj) (GTK_CHECK_TYPE ((obj), E_TYPE_MEETING_MODEL)) +#define E_IS_MEETING_MODEL_CLASS(klass) (GTK_CHECK_CLASS_TYPE ((obj), E_TYPE_MEETING_MODEL)) + + +typedef struct _EMeetingModel EMeetingModel; +typedef struct _EMeetingModelPrivate EMeetingModelPrivate; +typedef struct _EMeetingModelClass EMeetingModelClass; + +typedef enum { + E_MEETING_MODEL_ADDRESS_COL, + E_MEETING_MODEL_MEMBER_COL, + E_MEETING_MODEL_TYPE_COL, + E_MEETING_MODEL_ROLE_COL, + E_MEETING_MODEL_RSVP_COL, + E_MEETING_MODEL_DELTO_COL, + E_MEETING_MODEL_DELFROM_COL, + E_MEETING_MODEL_STATUS_COL, + E_MEETING_MODEL_CN_COL, + E_MEETING_MODEL_LANGUAGE_COL, + E_MEETING_MODEL_COLUMN_COUNT +} EMeetingModelColumns; + +struct _EMeetingModel { + ETableModel parent; + + EMeetingModelPrivate *priv; +}; + +struct _EMeetingModelClass { + ETableModelClass parent_class; +}; + +typedef void (* EMeetingModelRefreshCallback) (gpointer data); + + +GtkType e_meeting_model_get_type (void); +GtkObject *e_meeting_model_new (void); + +CalClient *e_meeting_model_get_cal_client (EMeetingModel *im); +void e_meeting_model_set_cal_client (EMeetingModel *im, CalClient *client); + +icaltimezone *e_meeting_model_get_zone (EMeetingModel *im); +void e_meeting_model_set_zone (EMeetingModel *im, icaltimezone *zone); + +void e_meeting_model_add_attendee (EMeetingModel *im, EMeetingAttendee *ia); +EMeetingAttendee *e_meeting_model_add_attendee_with_defaults (EMeetingModel *im); + +void e_meeting_model_remove_attendee (EMeetingModel *im, EMeetingAttendee *ia); +void e_meeting_model_remove_all_attendees (EMeetingModel *im); + +EMeetingAttendee *e_meeting_model_find_attendee (EMeetingModel *im, const gchar *address, gint *row); +EMeetingAttendee *e_meeting_model_find_attendee_at_row (EMeetingModel *im, gint row); + +gint e_meeting_model_count_actual_attendees (EMeetingModel *im); +const GPtrArray *e_meeting_model_get_attendees (EMeetingModel *im); + +void e_meeting_model_refresh_all_busy_periods (EMeetingModel *im, + EMeetingTime *start, + EMeetingTime *end, + EMeetingModelRefreshCallback call_back, + gpointer data); +void e_meeting_model_refresh_busy_periods (EMeetingModel *im, + int row, + EMeetingTime *start, + EMeetingTime *end, + EMeetingModelRefreshCallback call_back, + gpointer data); + + +/* Helpful functions */ +ETableScrolled *e_meeting_model_etable_from_model (EMeetingModel *im, const gchar *spec_file, const gchar *state_file); +void e_meeting_model_etable_click_to_add (EMeetingModel *im, gboolean click_to_add); +int e_meeting_model_etable_model_to_view_row (ETable *et, EMeetingModel *im, int model_row); +int e_meeting_model_etable_view_to_model_row (ETable *et, EMeetingModel *im, int view_row); + +void e_meeting_model_invite_others_dialog (EMeetingModel *im); + +G_END_DECLS + +#endif diff --git a/calendar/gui/e-meeting-store.c b/calendar/gui/e-meeting-store.c index 0129756e7c..6064971d9f 100644 --- a/calendar/gui/e-meeting-store.c +++ b/calendar/gui/e-meeting-store.c @@ -30,7 +30,6 @@ #include #include #include -#include #include #include #include @@ -50,8 +49,6 @@ struct _EMeetingStorePrivate { icaltimezone *zone; EBook *ebook; - gboolean book_loaded; - gboolean book_load_wait; GPtrArray *refresh_queue; GHashTable *refresh_data; @@ -80,27 +77,11 @@ struct _EMeetingStoreQueueData { static GObjectClass *parent_class = NULL; -static void -book_open_cb (EBook *book, EBookStatus status, gpointer data) -{ - EMeetingStore *store = E_MEETING_STORE (data); - - if (status == E_BOOK_STATUS_SUCCESS) - store->priv->book_loaded = TRUE; - else - g_warning ("Book not loaded"); - - if (store->priv->book_load_wait) { - store->priv->book_load_wait = FALSE; - gtk_main_quit (); - } -} - static void start_addressbook_server (EMeetingStore *store) { store->priv->ebook = e_book_new (); - e_book_load_default_book (store->priv->ebook, book_open_cb, store); + e_book_load_local_addressbook (store->priv->ebook, NULL); } static icalparameter_cutype @@ -914,9 +895,11 @@ find_zone (icalproperty *ip, icalcomponent *tz_top_level) iter = icalcomponent_begin_component (tz_top_level, ICAL_VTIMEZONE_COMPONENT); while ((sub_comp = icalcompiter_deref (&iter)) != NULL) { icalcomponent *clone; + icalproperty *prop; const char *tz_tzid; - - tz_tzid = icalproperty_get_tzid (sub_comp); + + prop = icalcomponent_get_first_property (sub_comp, ICAL_TZID_PROPERTY); + tz_tzid = icalproperty_get_tzid (prop); if (!strcmp (tzid, tz_tzid)) { icaltimezone *zone; @@ -1141,7 +1124,7 @@ refresh_busy_periods (gpointer data) /* Check the server for free busy data */ if (priv->client) { - GList *fb_data, *users = NULL; + GList *fb_data = NULL, *users = NULL; struct icaltimetype itt; time_t startt, endt; const char *user; @@ -1164,7 +1147,7 @@ refresh_busy_periods (gpointer data) user = itip_strip_mailto (e_meeting_attendee_get_address (attendee)); users = g_list_append (users, g_strdup (user)); - fb_data = cal_client_get_free_busy (priv->client, users, startt, endt); + cal_client_get_free_busy (priv->client, users, startt, endt, &fb_data, NULL); g_list_foreach (users, (GFunc)g_free, NULL); g_list_free (users); @@ -1181,11 +1164,6 @@ refresh_busy_periods (gpointer data) } /* Look for fburl's of attendee with no free busy info on server */ - if (!priv->book_loaded) { - priv->book_load_wait = TRUE; - gtk_main (); - } - if (!e_meeting_attendee_is_set_address (attendee)) { process_callbacks (qdata); return TRUE; diff --git a/calendar/gui/e-meeting-time-sel.c b/calendar/gui/e-meeting-time-sel.c index 157320ef16..91d915a4d7 100644 --- a/calendar/gui/e-meeting-time-sel.c +++ b/calendar/gui/e-meeting-time-sel.c @@ -265,6 +265,7 @@ e_meeting_time_selector_init (EMeetingTimeSelector * mts) void e_meeting_time_selector_construct (EMeetingTimeSelector * mts, EMeetingStore *ems) { + char *filename; GtkWidget *hbox, *vbox, *separator, *button, *label, *table; GtkWidget *alignment, *child_hbox, *arrow, *menuitem; GSList *group; @@ -313,7 +314,12 @@ e_meeting_time_selector_construct (EMeetingTimeSelector * mts, EMeetingStore *em gtk_box_pack_start (GTK_BOX (vbox), mts->attendees_vbox, TRUE, TRUE, 0); gtk_widget_show (mts->attendees_vbox); + + /* build the etable */ + filename = g_build_filename (calendar_component_peek_config_directory (calendar_component_peek ()), + "config", "et-header-meeting-time-sel", NULL); mts->model = ems; + if (mts->model) g_object_ref (mts->model); diff --git a/calendar/gui/e-select-names-editable.c b/calendar/gui/e-select-names-editable.c index 2fcc93397a..29c54c7979 100644 --- a/calendar/gui/e-select-names-editable.c +++ b/calendar/gui/e-select-names-editable.c @@ -25,7 +25,7 @@ #include #include #include -#include +#include #include "e-select-names-editable.h" #include "Evolution-Addressbook-SelectNames.h" @@ -187,16 +187,16 @@ e_select_names_editable_new () gchar * e_select_names_editable_get_address (ESelectNamesEditable *esne) { - EDestination **dest; + EABDestination **dest; gchar *dest_str; gchar *result; g_return_val_if_fail (E_SELECT_NAMES_EDITABLE (esne), NULL); dest_str = bonobo_pbclient_get_string (esne->priv->bag, "destinations", NULL); - dest = e_destination_importv (dest_str); - result = g_strdup (e_destination_get_email (*dest)); - e_destination_freev (dest); + dest = eab_destination_importv (dest_str); + result = g_strdup (eab_destination_get_email (*dest)); + eab_destination_freev (dest); return result; } @@ -204,16 +204,16 @@ e_select_names_editable_get_address (ESelectNamesEditable *esne) gchar * e_select_names_editable_get_name (ESelectNamesEditable *esne) { - EDestination **dest; + EABDestination **dest; gchar *dest_str; gchar *result; g_return_val_if_fail (E_SELECT_NAMES_EDITABLE (esne), NULL); dest_str = bonobo_pbclient_get_string (esne->priv->bag, "destinations", NULL); - dest = e_destination_importv (dest_str); - result = g_strdup (e_destination_get_name (*dest)); - e_destination_freev (dest); + dest = eab_destination_importv (dest_str); + result = g_strdup (eab_destination_get_name (*dest)); + eab_destination_freev (dest); return result; } diff --git a/calendar/gui/e-tasks.c b/calendar/gui/e-tasks.c index b441aee09d..768b2e587c 100644 --- a/calendar/gui/e-tasks.c +++ b/calendar/gui/e-tasks.c @@ -572,7 +572,6 @@ GtkWidget * e_tasks_construct (ETasks *tasks) { ETasksPrivate *priv; - ECalModel *model; g_return_val_if_fail (tasks != NULL, NULL); g_return_val_if_fail (E_IS_TASKS (tasks), NULL); @@ -581,24 +580,6 @@ e_tasks_construct (ETasks *tasks) setup_widgets (tasks); - priv->client = cal_client_new (); - if (!priv->client) - return NULL; - - g_signal_connect (priv->client, "cal_opened", - G_CALLBACK (cal_opened_cb), tasks); - g_signal_connect (priv->client, "backend_error", - G_CALLBACK (backend_error_cb), tasks); - g_signal_connect (priv->client, "categories_changed", - G_CALLBACK (client_categories_changed_cb), tasks); - g_signal_connect (priv->client, "obj_updated", - G_CALLBACK (client_obj_updated_cb), tasks); - - model = e_calendar_table_get_model (E_CALENDAR_TABLE (priv->tasks_view)); - g_assert (model != NULL); - - e_cal_model_add_client (model, priv->client); - return GTK_WIDGET (tasks); } @@ -685,6 +666,8 @@ e_tasks_open (ETasks *tasks, EUri *uri; char *real_uri; char *urinopwd; + ECalModel *model; + GError *error = NULL; g_return_val_if_fail (tasks != NULL, FALSE); g_return_val_if_fail (E_IS_TASKS (tasks), FALSE); @@ -704,10 +687,30 @@ e_tasks_open (ETasks *tasks, g_free (message); g_free (urinopwd); - if (!cal_client_open_calendar (priv->client, real_uri, FALSE)) { - g_message ("e_tasks_open(): Could not issue the request"); + /* create the CalClient */ + priv->client = cal_client_new (real_uri, CALOBJ_TYPE_TODO); + if (!priv->client) + return NULL; + + g_signal_connect (priv->client, "cal_opened", + G_CALLBACK (cal_opened_cb), tasks); + g_signal_connect (priv->client, "backend_error", + G_CALLBACK (backend_error_cb), tasks); + g_signal_connect (priv->client, "categories_changed", + G_CALLBACK (client_categories_changed_cb), tasks); + g_signal_connect (priv->client, "obj_updated", + G_CALLBACK (client_obj_updated_cb), tasks); + + model = e_calendar_table_get_model (E_CALENDAR_TABLE (priv->tasks_view)); + g_assert (model != NULL); + + e_cal_model_add_client (model, priv->client); + + if (cal_client_open (priv->client, FALSE, &error)) { + g_message ("e_tasks_open(): %s", error->message); g_free (real_uri); e_uri_free (uri); + g_error_free (error); return FALSE; } @@ -787,7 +790,8 @@ cal_opened_cb (CalClient *client, location = calendar_config_get_timezone (); zone = icaltimezone_get_builtin_timezone (location); if (zone) - cal_client_set_default_timezone (client, zone); + /* FIXME Error checking */ + cal_client_set_default_timezone (client, zone, NULL); return; case CAL_CLIENT_OPEN_ERROR: @@ -937,60 +941,6 @@ create_sexp (void) return sexp; } -/* Callback used when a component is updated in the live query */ -static void -query_obj_updated_cb (CalQuery *query, const char *uid, - gboolean query_in_progress, int n_scanned, int total, - gpointer data) -{ - ETasks *tasks; - ETasksPrivate *priv; - - tasks = E_TASKS (data); - priv = tasks->priv; - - delete_error_dialog (cal_client_remove_object (priv->client, uid), CAL_COMPONENT_TODO); -} - -/* Callback used when an evaluation error occurs when running a query */ -static void -query_eval_error_cb (CalQuery *query, const char *error_str, gpointer data) -{ - ETasks *tasks; - ETasksPrivate *priv; - - tasks = E_TASKS (data); - priv = tasks->priv; - - g_warning ("eval error: %s\n", error_str); - - set_status_message (tasks, NULL); - - g_signal_handlers_disconnect_matched (priv->query, G_SIGNAL_MATCH_DATA, - 0, 0, NULL, NULL, tasks); - g_object_unref (priv->query); - priv->query = NULL; -} - -static void -query_query_done_cb (CalQuery *query, CalQueryDoneStatus status, const char *error_str, gpointer data) -{ - ETasks *tasks; - ETasksPrivate *priv; - - tasks = E_TASKS (data); - priv = tasks->priv; - - if (status != CAL_QUERY_DONE_SUCCESS) - g_warning ("query done: %s\n", error_str); - - set_status_message (tasks, NULL); - - g_signal_handlers_disconnect_matched (priv->query, G_SIGNAL_MATCH_DATA, - 0, 0, NULL, NULL, tasks); - g_object_unref (priv->query); - priv->query = NULL; -} /** * e_tasks_expunge: * @tasks: A tasks control widget @@ -1002,31 +952,32 @@ e_tasks_delete_completed (ETasks *tasks) { ETasksPrivate *priv; char *sexp; + GList *objects, *l; g_return_if_fail (tasks != NULL); g_return_if_fail (E_IS_TASKS (tasks)); priv = tasks->priv; - /* If we have a query, we are already expunging */ - if (priv->query) - return; + /* FIXME Confirm expunge */ sexp = create_sexp (); set_status_message (tasks, _("Expunging")); - priv->query = cal_client_get_query (priv->client, sexp); - g_free (sexp); - - if (!priv->query) { + + if (!cal_client_get_object_list (priv->client, sexp, &objects, NULL)) { set_status_message (tasks, NULL); - g_message ("update_query(): Could not create the query"); + g_warning (G_STRLOC ": Could not get the objects"); + return; } + + for (l = objects; l; l = l->next) { + /* FIXME Better error handling */ + cal_client_remove_object (priv->client, icalcomponent_get_uid (l->data), NULL); + } - g_signal_connect (priv->query, "obj_updated", G_CALLBACK (query_obj_updated_cb), tasks); - g_signal_connect (priv->query, "query_done", G_CALLBACK (query_query_done_cb), tasks); - g_signal_connect (priv->query, "eval_error", G_CALLBACK (query_eval_error_cb), tasks); + set_status_message (tasks, NULL); } /* Callback used from the view collection when we need to display a new view */ @@ -1181,6 +1132,7 @@ e_tasks_update_all_config_settings (void) calendar_config_configure_e_calendar_table (E_CALENDAR_TABLE (priv->tasks_view)); if (zone) - cal_client_set_default_timezone (priv->client, zone); + /* FIXME Error checking */ + cal_client_set_default_timezone (priv->client, zone, NULL); } } diff --git a/calendar/gui/e-week-view-event-item.c b/calendar/gui/e-week-view-event-item.c index 139f28bb13..fd68130bc5 100644 --- a/calendar/gui/e-week-view-event-item.c +++ b/calendar/gui/e-week-view-event-item.c @@ -890,7 +890,6 @@ e_week_view_event_item_double_click (EWeekViewEventItem *wveitem, EWeekView *week_view; EWeekViewEvent *event; GnomeCanvasItem *item; - GnomeCalendar *calendar; item = GNOME_CANVAS_ITEM (wveitem); @@ -902,11 +901,7 @@ e_week_view_event_item_double_click (EWeekViewEventItem *wveitem, e_week_view_stop_editing_event (week_view); - calendar = e_cal_view_get_calendar (E_CAL_VIEW (week_view)); - if (calendar) - gnome_calendar_edit_object (calendar, event->comp_data->client, event->comp_data->icalcomp, FALSE); - else - g_warning ("Calendar not set"); + e_cal_view_edit_appointment (E_CAL_VIEW (week_view), event->comp_data->client, event->comp_data->icalcomp, FALSE); return TRUE; } diff --git a/calendar/gui/e-week-view.c b/calendar/gui/e-week-view.c index 8028bf13e6..1be94fc1de 100644 --- a/calendar/gui/e-week-view.c +++ b/calendar/gui/e-week-view.c @@ -62,6 +62,7 @@ #include "calendar-config.h" #include "print.h" #include "goto.h" +#include "e-cal-model-calendar.h" #include "e-week-view-event-item.h" #include "e-week-view-layout.h" #include "e-week-view-main-item.h" @@ -312,8 +313,6 @@ e_week_view_init (EWeekView *week_view) week_view->main_gc = NULL; - week_view->default_category = NULL; - /* Create the small font. */ week_view->use_small_font = TRUE; @@ -423,8 +422,11 @@ GtkWidget * e_week_view_new (void) { GtkWidget *week_view; + ECalModel *model; + + model = E_CAL_MODEL (e_cal_model_calendar_new ()); - week_view = GTK_WIDGET (g_object_new (e_week_view_get_type (), NULL)); + week_view = GTK_WIDGET (g_object_new (e_week_view_get_type (), "model", model, NULL)); return week_view; } @@ -457,11 +459,6 @@ e_week_view_destroy (GtkObject *object) week_view->small_font_desc = NULL; } - if (week_view->default_category) { - g_free (week_view->default_category); - week_view->default_category = NULL; - } - if (week_view->normal_cursor) { gdk_cursor_unref (week_view->normal_cursor); week_view->normal_cursor = NULL; @@ -1149,7 +1146,7 @@ process_component (EWeekView *week_view, ECalModelComponent *comp_data) g_object_unref (tmp_comp); } - /* Add the occurrences of the event. */ + /* Add the occurrences of the event */ num_days = week_view->multi_week_view ? week_view->weeks_shown * 7 : 7; add_event_data.week_view = week_view; @@ -1158,8 +1155,7 @@ process_component (EWeekView *week_view, ECalModelComponent *comp_data) week_view->day_starts[0], week_view->day_starts[num_days], e_week_view_add_event, &add_event_data, - cal_client_resolve_tzid_cb, - comp_data->client, + cal_client_resolve_tzid_cb, comp_data->client, e_cal_view_get_timezone (E_CAL_VIEW (week_view))); g_object_unref (comp); @@ -1178,8 +1174,6 @@ e_week_view_update_query (ECalView *cal_view) e_week_view_free_events (week_view); e_week_view_queue_layout (week_view); - e_cal_view_set_status_message (E_CAL_VIEW (week_view), _("Searching")); - rows = e_table_model_row_count (E_TABLE_MODEL (e_cal_view_get_model (E_CAL_VIEW (week_view)))); for (r = 0; r < rows; r++) { ECalModelComponent *comp_data; @@ -1188,8 +1182,6 @@ e_week_view_update_query (ECalView *cal_view) g_assert (comp_data != NULL); process_component (week_view, comp_data); } - - e_cal_view_set_status_message (E_CAL_VIEW (week_view), NULL); } static void @@ -1217,27 +1209,6 @@ e_week_view_draw_shadow (EWeekView *week_view) gdk_draw_line (window, light_gc, x1, y2, x2, y2); } -/** - * e_week_view_set_default_category: - * @week_view: A week view. - * @category: Default category name or NULL for no category. - * - * Sets the default category that will be used when creating new calendar - * components from the week view. - **/ -void -e_week_view_set_default_category (EWeekView *week_view, const char *category) -{ - g_return_if_fail (week_view != NULL); - g_return_if_fail (E_IS_WEEK_VIEW (week_view)); - - if (week_view->default_category) - g_free (week_view->default_category); - - week_view->default_category = g_strdup (category); -} - - /* This sets the selected time range. The EWeekView will show the corresponding month and the days between start_time and end_time will be selected. To select a single day, use the same value for start_time & end_time. */ @@ -2015,7 +1986,7 @@ e_week_view_on_button_press (GtkWidget *widget, return FALSE; if (event->button == 1 && event->type == GDK_2BUTTON_PRESS) { - gnome_calendar_new_appointment (e_cal_view_get_calendar (E_CAL_VIEW (week_view))); + e_cal_view_new_appointment (E_CAL_VIEW (week_view)); return TRUE; } @@ -2876,14 +2847,11 @@ e_week_view_on_text_item_event (GnomeCanvasItem *item, { EWeekViewEvent *event; gint event_num, span_num; - GnomeCalendar *calendar; #if 0 g_print ("In e_week_view_on_text_item_event\n"); #endif - calendar = e_cal_view_get_calendar (E_CAL_VIEW (week_view)); - switch (gdkevent->type) { case GDK_KEY_PRESS: if (gdkevent && gdkevent->key.keyval == GDK_Return) { @@ -2912,10 +2880,9 @@ e_week_view_on_text_item_event (GnomeCanvasItem *item, event = &g_array_index (week_view->events, EWeekViewEvent, event_num); - if (calendar) - gnome_calendar_edit_object (calendar, event->comp_data->client, event->comp_data->icalcomp, FALSE); - else - g_warning ("Calendar not set"); + e_cal_view_edit_appointment (E_CAL_VIEW (week_view), + event->comp_data->client, + event->comp_data->icalcomp, FALSE); gtk_signal_emit_stop_by_name (GTK_OBJECT (item), "event"); return TRUE; @@ -3049,7 +3016,8 @@ e_week_view_on_editing_stopped (EWeekView *week_view, CalComponent *comp; CalComponentText summary; const char *uid; - + gboolean on_server; + /* Note: the item we are passed here isn't reliable, so we just stop the edit of whatever item was being edited. We also receive this event twice for some reason. */ @@ -3079,8 +3047,9 @@ e_week_view_on_editing_stopped (EWeekView *week_view, comp = cal_component_new (); cal_component_set_icalcomponent (comp, icalcomponent_new_clone (event->comp_data->icalcomp)); - if (string_is_empty (text) && - !cal_comp_is_on_server (comp, event->comp_data->client)) { + on_server = cal_comp_is_on_server (comp, event->comp_data->client); + + if (string_is_empty (text) && !on_server) { const char *uid; cal_component_get_uid (comp, &uid); @@ -3099,33 +3068,33 @@ e_week_view_on_editing_stopped (EWeekView *week_view, e_week_view_reshape_event_span (week_view, event_num, span_num); } else if (summary.value || !string_is_empty (text)) { + icalcomponent *icalcomp = cal_component_get_icalcomponent (comp); + summary.value = text; summary.altrep = NULL; cal_component_set_summary (comp, &summary); - - if (cal_component_is_instance (comp)) { - CalObjModType mod; - - if (recur_component_dialog (comp, &mod, NULL)) { - if (cal_client_update_object_with_mod (event->comp_data->client, comp, mod) - == CAL_CLIENT_RESULT_SUCCESS) { - if (itip_organizer_is_user (comp, event->comp_data->client) - && send_component_dialog ((GtkWindow *) gtk_widget_get_toplevel (GTK_WIDGET (week_view)), - event->comp_data->client, comp, FALSE)) - itip_send_comp (CAL_COMPONENT_METHOD_REQUEST, comp, - event->comp_data->client, NULL); - } else { - g_message ("e_week_view_on_editing_stopped(): Could not update the object!"); + + if (!on_server) { + if (!cal_client_create_object (event->comp_data->client, icalcomp, NULL, NULL)) + g_message (G_STRLOC ": Could not create the object!"); + } else { + CalObjModType mod = CALOBJ_MOD_ALL; + GtkWindow *toplevel; + + if (cal_component_has_recurrences (comp)) { + if (!recur_component_dialog (comp, &mod, NULL)) { + goto out; } } - } else if (cal_client_update_object (event->comp_data->client, comp) == CAL_CLIENT_RESULT_SUCCESS) { - if (itip_organizer_is_user (comp, event->comp_data->client) && - send_component_dialog ((GtkWindow *) gtk_widget_get_toplevel (GTK_WIDGET (week_view)), - event->comp_data->client, comp, FALSE)) - itip_send_comp (CAL_COMPONENT_METHOD_REQUEST, comp, - event->comp_data->client, NULL); - } else { - g_message ("e_week_view_on_editing_stopped(): Could not update the object!"); + + /* FIXME When sending here, what exactly should we send? */ + toplevel = GTK_WINDOW (gtk_widget_get_toplevel (GTK_WIDGET (week_view))); + if (cal_client_modify_object (event->comp_data->client, icalcomp, mod, NULL)) { + if (itip_organizer_is_user (comp, event->comp_data->client) + && send_component_dialog (toplevel, event->comp_data->client, comp, FALSE)) + itip_send_comp (CAL_COMPONENT_METHOD_REQUEST, comp, + event->comp_data->client, NULL); + } } } @@ -3182,6 +3151,10 @@ e_week_view_find_event_from_uid (EWeekView *week_view, EWeekViewEvent *event; gint event_num, num_events; + *event_num_return = -1; + if (!uid) + return FALSE; + num_events = week_view->events->len; for (event_num = 0; event_num < num_events; event_num++) { const char *u; @@ -3291,6 +3264,8 @@ e_week_view_do_key_press (GtkWidget *widget, GdkEventKey *event) /* Add a new event covering the selected range. */ icalcomp = e_cal_model_create_component_with_defaults (e_cal_view_get_model (E_CAL_VIEW (week_view))); + if (!icalcomp) + return FALSE; uid = icalcomponent_get_uid (icalcomp); comp = cal_component_new (); @@ -3313,7 +3288,8 @@ e_week_view_do_key_press (GtkWidget *widget, GdkEventKey *event) e_cal_view_get_timezone (E_CAL_VIEW (week_view))); cal_component_set_dtend (comp, &date); - cal_component_set_categories (comp, week_view->default_category); + cal_component_set_categories ( + comp, e_cal_view_get_default_category (E_CAL_VIEW (week_view))); /* We add the event locally and start editing it. We don't send it to the server until the user finishes editing it. */ @@ -3545,63 +3521,6 @@ e_week_view_popup_menu (GtkWidget *widget) return TRUE; } -void -e_week_view_unrecur_appointment (EWeekView *week_view) -{ - EWeekViewEvent *event; - CalComponent *comp, *new_comp; - CalComponentDateTime date; - struct icaltimetype itt; - - if (week_view->popup_event_num == -1) - return; - - event = &g_array_index (week_view->events, EWeekViewEvent, - week_view->popup_event_num); - - /* For the recurring object, we add a exception to get rid of the - instance. */ - comp = cal_component_new (); - cal_component_set_icalcomponent (comp, icalcomponent_new_clone (event->comp_data->icalcomp)); - cal_comp_util_add_exdate (comp, event->start, e_cal_view_get_timezone (E_CAL_VIEW (week_view))); - - /* For the unrecurred instance we duplicate the original object, - create a new uid for it, get rid of the recurrence rules, and set - the start & end times to the instances times. */ - new_comp = cal_component_new (); - cal_component_set_icalcomponent (new_comp, icalcomponent_new_clone (event->comp_data->icalcomp)); - cal_component_set_uid (new_comp, cal_component_gen_uid ()); - cal_component_set_rdate_list (new_comp, NULL); - cal_component_set_rrule_list (new_comp, NULL); - cal_component_set_exdate_list (new_comp, NULL); - cal_component_set_exrule_list (new_comp, NULL); - - date.value = &itt; - date.tzid = icaltimezone_get_tzid (e_cal_view_get_timezone (E_CAL_VIEW (week_view))); - - *date.value = icaltime_from_timet_with_zone (event->start, FALSE, - e_cal_view_get_timezone (E_CAL_VIEW (week_view))); - cal_component_set_dtstart (new_comp, &date); - *date.value = icaltime_from_timet_with_zone (event->end, FALSE, - e_cal_view_get_timezone (E_CAL_VIEW (week_view))); - cal_component_set_dtend (new_comp, &date); - - /* Now update both CalComponents. Note that we do this last since at - present the updates happen synchronously so our event may disappear. - */ - if (cal_client_update_object (event->comp_data->client, comp) - != CAL_CLIENT_RESULT_SUCCESS) - g_message ("e_week_view_on_unrecur_appointment(): Could not update the object!"); - - g_object_unref (comp); - - if (cal_client_update_object (event->comp_data->client, new_comp) - != CAL_CLIENT_RESULT_SUCCESS) - g_message ("e_week_view_on_unrecur_appointment(): Could not update the object!"); - - g_object_unref (new_comp); -} - void e_week_view_jump_to_button_item (EWeekView *week_view, GnomeCanvasItem *item) { diff --git a/calendar/gui/e-week-view.h b/calendar/gui/e-week-view.h index c24470155d..0296c19c42 100644 --- a/calendar/gui/e-week-view.h +++ b/calendar/gui/e-week-view.h @@ -331,9 +331,6 @@ struct _EWeekView gchar *pm_string; gint am_string_width; gint pm_string_width; - - /* The default category for new events */ - char *default_category; }; struct _EWeekViewClass @@ -353,9 +350,6 @@ void e_week_view_get_first_day_shown (EWeekView *week_view, void e_week_view_set_first_day_shown (EWeekView *week_view, GDate *date); -void e_week_view_set_default_category (EWeekView *week_view, - const char *category); - /* The selected time range. The EWeekView will show the corresponding month and the days between start_time and end_time will be selected. To select a single day, use the same value for start_time & end_time. */ @@ -396,8 +390,6 @@ void e_week_view_set_24_hour_format (EWeekView *week_view, void e_week_view_delete_occurrence (EWeekView *week_view); -void e_week_view_unrecur_appointment (EWeekView *week_view); - /* Returns the number of selected events (0 or 1 at present). */ gint e_week_view_get_num_events_selected (EWeekView *week_view); diff --git a/calendar/gui/gnome-cal.c b/calendar/gui/gnome-cal.c index c2a0c2c61e..bcefd8eeee 100644 --- a/calendar/gui/gnome-cal.c +++ b/calendar/gui/gnome-cal.c @@ -61,8 +61,6 @@ #include "misc.h" #include "ea-calendar.h" -extern ECompEditorRegistry *comp_editor_registry; - /* Private part of the GnomeCalendar structure */ @@ -71,6 +69,8 @@ struct _GnomeCalendarPrivate { * The Calendar Folder. */ + GHashTable *clients; + /* Set of categories from the calendar client */ GPtrArray *cal_categories; @@ -119,6 +119,7 @@ struct _GnomeCalendarPrivate { /* This is the view currently shown. We use it to keep track of the positions of the panes. range_selected is TRUE if a range of dates was selected in the date navigator to show the view. */ + ECalView *views[GNOME_CAL_LAST_VIEW]; GnomeCalendarViewType current_view_type; gboolean range_selected; @@ -145,10 +146,6 @@ struct _GnomeCalendarPrivate { 'dates-shown-changed' signal.*/ time_t visible_start; time_t visible_end; - - /* Calendar query for purging old events */ - GList *exp_queries; - time_t exp_older_than; }; /* Signal IDs */ @@ -361,97 +358,70 @@ gnome_calendar_class_init (GnomeCalendarClass *class) /* Callback used when the calendar query reports of an updated object */ static void -dn_query_obj_updated_cb (CalQuery *query, const char *uid, - gboolean query_in_progress, int n_scanned, int total, - gpointer data) +dn_query_objects_added_cb (CalQuery *query, GList *objects, gpointer data) { GnomeCalendar *gcal; GnomeCalendarPrivate *priv; - CalComponent *comp = NULL; - icalcomponent *icalcomp; - CalClientGetStatus status; - + GList *l; + gcal = GNOME_CALENDAR (data); priv = gcal->priv; - /* If this is an update that is not part of an ongoing query, we have to - * retag the whole thing: an event may change dates and the - * tag_calendar_by_comp() below would not know how to untag the old - * dates. - */ - if (!query_in_progress) { - update_query (gcal); - return; - } + for (l = objects; l; l = l->next) { + CalComponent *comp = NULL; - status = cal_client_get_object (cal_query_get_client (query), uid, &icalcomp); - - switch (status) { - case CAL_CLIENT_GET_SUCCESS: comp = cal_component_new (); - if (!cal_component_set_icalcomponent (comp, icalcomp)) { + if (!cal_component_set_icalcomponent (comp, icalcomponent_new_clone (l->data))) { g_object_unref (comp); - icalcomponent_free (icalcomp); - return; + + continue; } - break; - - case CAL_CLIENT_GET_SYNTAX_ERROR: - g_message ("dn_query_obj_updated_cb(): Syntax error while getting object `%s'", uid); - return; - - case CAL_CLIENT_GET_NOT_FOUND: - /* The object is no longer in the server, so do nothing */ - return; - default: - g_assert_not_reached (); - return; + tag_calendar_by_comp (priv->date_navigator, comp, cal_query_get_client (query), NULL, + FALSE, TRUE); + g_object_unref (comp); } - - tag_calendar_by_comp (priv->date_navigator, comp, cal_query_get_client (query), NULL, - FALSE, TRUE); - g_object_unref (comp); } -/* Callback used when the calendar query reports of a removed object */ static void -dn_query_obj_removed_cb (CalQuery *query, const char *uid, gpointer data) +dn_query_objects_modified_cb (CalQuery *query, GList *objects, gpointer data) { GnomeCalendar *gcal; + GnomeCalendarPrivate *priv; gcal = GNOME_CALENDAR (data); + priv = gcal->priv; - /* Just retag the whole thing */ + /* We have to retag the whole thing: an event may change dates + * and the tag_calendar_by_comp() below would not know how to + * untag the old dates. + */ update_query (gcal); } -/* Callback used when the calendar query is done */ +/* Callback used when the calendar query reports of a removed object */ static void -dn_query_query_done_cb (CalQuery *query, CalQueryDoneStatus status, const char *error_str, - gpointer data) +dn_query_objects_removed_cb (CalQuery *query, GList *uids, gpointer data) { GnomeCalendar *gcal; gcal = GNOME_CALENDAR (data); - /* FIXME */ - - if (status != CAL_QUERY_DONE_SUCCESS) - fprintf (stderr, "query done: %s\n", error_str); + /* Just retag the whole thing */ + update_query (gcal); } -/* Callback used when the calendar query reports an evaluation error */ +/* Callback used when the calendar query is done */ static void -dn_query_eval_error_cb (CalQuery *query, const char *error_str, gpointer data) +dn_query_done_cb (CalQuery *query, ECalendarStatus status, gpointer data) { GnomeCalendar *gcal; gcal = GNOME_CALENDAR (data); - /* FIXME */ - - fprintf (stderr, "eval error: %s\n", error_str); + /* FIXME Better error reporting */ + if (status != E_CALENDAR_STATUS_OK) + g_warning (G_STRLOC ": Query did not successfully complete"); } /* Returns the current view widget, an EDayView, EWeekView or ECalListView. */ @@ -603,6 +573,7 @@ adjust_query_sexp (GnomeCalendar *gcal, const char *sexp) start, end, sexp); + g_free (start); g_free (end); @@ -649,22 +620,24 @@ update_query (GnomeCalendar *gcal) /* create queries for each loaded client */ client_list = e_cal_model_get_client_list (e_cal_view_get_model (E_CAL_VIEW (priv->day_view))); for (l = client_list; l != NULL; l = l->next) { - old_query = cal_client_get_query ((CalClient *) l->data, real_sexp); - if (!old_query) { - g_message ("update_query(): Could not create the query"); + if (!cal_client_get_query ((CalClient *) l->data, real_sexp, &old_query, NULL)) { + g_warning (G_STRLOC ": Could not create the query"); + continue; } - g_signal_connect (old_query, "obj_updated", - G_CALLBACK (dn_query_obj_updated_cb), gcal); - g_signal_connect (old_query, "obj_removed", - G_CALLBACK (dn_query_obj_removed_cb), gcal); + g_signal_connect (old_query, "objects_added", + G_CALLBACK (dn_query_objects_added_cb), gcal); + g_signal_connect (old_query, "objects_modified", + G_CALLBACK (dn_query_objects_modified_cb), gcal); + g_signal_connect (old_query, "objects_removed", + G_CALLBACK (dn_query_objects_removed_cb), gcal); g_signal_connect (old_query, "query_done", - G_CALLBACK (dn_query_query_done_cb), gcal); - g_signal_connect (old_query, "eval_error", - G_CALLBACK (dn_query_eval_error_cb), gcal); + G_CALLBACK (dn_query_done_cb), gcal); priv->dn_queries = g_list_append (priv->dn_queries, old_query); + + cal_query_start (old_query); } g_list_free (client_list); @@ -673,6 +646,30 @@ update_query (GnomeCalendar *gcal) e_cal_view_set_status_message (E_CAL_VIEW (priv->week_view), NULL); } +static void +adjust_query_for_view (ECalView *cal_view, const char *sexp) +{ + char *real_sexp, *start, *end; + time_t ttstart, ttend; + + e_cal_view_get_visible_time_range (cal_view, &ttstart, &ttend); + + start = isodate_from_time_t (ttstart); + end = isodate_from_time_t (ttend); + + real_sexp = g_strdup_printf ( + "(and (occur-in-time-range? (make-time \"%s\")" + " (make-time \"%s\"))" + " %s)", + start, end, sexp); + + e_cal_model_set_query (e_cal_view_get_model (cal_view), real_sexp); + + g_free (start); + g_free (end); + g_free (real_sexp); +} + /** * gnome_calendar_set_query: * @gcal: A calendar. @@ -685,6 +682,7 @@ gnome_calendar_set_query (GnomeCalendar *gcal, const char *sexp) { GnomeCalendarPrivate *priv; ECalModel *model; + int i; g_return_if_fail (gcal != NULL); g_return_if_fail (GNOME_IS_CALENDAR (gcal)); @@ -701,9 +699,9 @@ gnome_calendar_set_query (GnomeCalendar *gcal, const char *sexp) update_query (gcal); - /* Set the query on the main view */ - model = e_cal_view_get_model (E_CAL_VIEW (gnome_calendar_get_current_view_widget (gcal))); - e_cal_model_set_query (model, sexp); + /* Set the query on the views */ + for (i = 0; i < GNOME_CAL_LAST_VIEW; i++) + adjust_query_for_view (E_CAL_VIEW (priv->views[i]), sexp); /* Set the query on the task pad */ model = e_calendar_table_get_model (E_CALENDAR_TABLE (priv->todo)); @@ -747,14 +745,15 @@ search_bar_category_changed_cb (CalSearchBar *cal_search, const char *category, GnomeCalendar *gcal; GnomeCalendarPrivate *priv; ECalModel *model; + int i; gcal = GNOME_CALENDAR (data); priv = gcal->priv; - e_day_view_set_default_category (E_DAY_VIEW (priv->day_view), category); - e_day_view_set_default_category (E_DAY_VIEW (priv->work_week_view), category); - e_week_view_set_default_category (E_WEEK_VIEW (priv->week_view), category); - e_week_view_set_default_category (E_WEEK_VIEW (priv->month_view), category); + for (i = 0; i < GNOME_CAL_LAST_VIEW; i++) { + e_cal_view_set_default_category (E_CAL_VIEW (priv->views[i]), + category); + } model = e_calendar_table_get_model (E_CALENDAR_TABLE (priv->todo)); e_cal_model_set_default_category (model, category); @@ -853,7 +852,6 @@ setup_widgets (GnomeCalendar *gcal) GtkWidget *w; gchar *filename; ETable *etable; - ECalModel *model; priv = gcal->priv; @@ -915,7 +913,8 @@ setup_widgets (GnomeCalendar *gcal) gtk_paned_pack2 (GTK_PANED (priv->vpane), priv->todo, TRUE, TRUE); gtk_widget_show (priv->todo); - filename = g_strdup_printf ("%s/config/TaskPad", evolution_dir); + filename = g_build_filename (calendar_component_peek_config_directory (calendar_component_peek ()), + "TaskPad", NULL); e_calendar_table_load_state (E_CALENDAR_TABLE (priv->todo), filename); g_free (filename); @@ -977,7 +976,7 @@ setup_widgets (GnomeCalendar *gcal) connect_week_view_focus (gcal, E_WEEK_VIEW (priv->month_view)); /* The List View. */ - filename = g_strdup_printf ("%s/config/CalListView", evolution_dir); + filename = g_strdup_printf (".evolution/config/CalListView"); priv->list_view = e_cal_list_view_new (filename); g_free (filename); @@ -988,14 +987,12 @@ setup_widgets (GnomeCalendar *gcal) connect_list_view_focus (gcal, E_CAL_LIST_VIEW (priv->list_view)); - model = (ECalModel *) e_cal_model_calendar_new (); - e_cal_view_set_model (E_CAL_VIEW (priv->day_view), model); - e_cal_view_set_model (E_CAL_VIEW (priv->work_week_view), model); - e_cal_view_set_model (E_CAL_VIEW (priv->week_view), model); - e_cal_view_set_model (E_CAL_VIEW (priv->month_view), model); - e_cal_view_set_model (E_CAL_VIEW (priv->list_view), model); + priv->views[GNOME_CAL_DAY_VIEW] = E_CAL_VIEW (priv->day_view); + priv->views[GNOME_CAL_WORK_WEEK_VIEW] = E_CAL_VIEW (priv->work_week_view); + priv->views[GNOME_CAL_WEEK_VIEW] = E_CAL_VIEW (priv->week_view); + priv->views[GNOME_CAL_MONTH_VIEW] = E_CAL_VIEW (priv->month_view); + priv->views[GNOME_CAL_LIST_VIEW] = E_CAL_VIEW (priv->list_view); - g_object_unref (model); gnome_calendar_update_config_settings (gcal, TRUE); } @@ -1008,6 +1005,8 @@ gnome_calendar_init (GnomeCalendar *gcal) priv = g_new0 (GnomeCalendarPrivate, 1); gcal->priv = priv; + priv->clients = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_object_unref); + priv->cal_categories = NULL; priv->tasks_categories = NULL; @@ -1027,8 +1026,6 @@ gnome_calendar_init (GnomeCalendar *gcal) priv->visible_start = -1; priv->visible_end = -1; - - priv->exp_queries = NULL; } /* Frees a set of categories */ @@ -1062,6 +1059,8 @@ gnome_calendar_destroy (GtkObject *object) if (priv) { GList *l, *client_list; + g_hash_table_destroy (priv->clients); + free_categories (priv->cal_categories); priv->cal_categories = NULL; @@ -1078,7 +1077,8 @@ gnome_calendar_destroy (GtkObject *object) g_list_free (client_list); /* Save the TaskPad layout. */ - filename = g_strdup_printf ("%s/config/TaskPad", evolution_dir); + filename = g_build_filename (calendar_component_peek_config_directory (calendar_component_peek ()), + "TaskPad", NULL); e_calendar_table_save_state (E_CALENDAR_TABLE (priv->todo), filename); g_free (filename); @@ -1120,19 +1120,6 @@ gnome_calendar_destroy (GtkObject *object) priv->view_menus = NULL; } - if (priv->exp_queries) { - GList *l; - - for (l = priv->exp_queries; l != NULL; l = l->next) { - g_signal_handlers_disconnect_matched ((CalQuery *) l->data, G_SIGNAL_MATCH_DATA, - 0, 0, NULL, NULL, gcal); - g_object_unref (l->data); - } - - g_list_free (priv->exp_queries); - priv->exp_queries = NULL; - } - g_free (priv); gcal->priv = NULL; } @@ -1764,7 +1751,8 @@ client_cal_opened_cb (CalClient *client, CalClientOpenStatus status, gpointer da case CAL_CLIENT_OPEN_SUCCESS: /* Set the client's default timezone, if we have one. */ if (priv->zone) { - cal_client_set_default_timezone (client, priv->zone); + /* FIXME Error checking */ + cal_client_set_default_timezone (client, priv->zone, NULL); } /* add the alarms for this client */ @@ -1996,7 +1984,7 @@ gnome_calendar_construct (GnomeCalendar *gcal) /* * TaskPad Folder Client. */ - priv->task_pad_client = cal_client_new (); + priv->task_pad_client = cal_client_new ("", CALOBJ_TYPE_TODO); /* FIXME: use default tasks */ if (!priv->task_pad_client) return NULL; @@ -2063,7 +2051,8 @@ gnome_calendar_get_calendar_model (GnomeCalendar *gcal) priv = gcal->priv; - return e_cal_view_get_model (E_CAL_VIEW (priv->week_view)); + return e_cal_view_get_model ( + gnome_calendar_get_current_view_widget (gcal)); } /** @@ -2077,6 +2066,28 @@ gnome_calendar_get_default_client (GnomeCalendar *gcal) return e_cal_model_get_default_client (e_cal_view_get_model (E_CAL_VIEW (gcal->priv->week_view))); } +/** + * gnome_calendar_set_default_client + * @gcal: A calendar view. + * @client: The client to use as default. + * + * Set the default client on the given calendar view. The default calendar will + * be used as the default when creating events in the view. + */ +void +gnome_calendar_set_default_client (GnomeCalendar *gcal, CalClient *client) +{ + int i; + + g_return_if_fail (GNOME_IS_CALENDAR (gcal)); + + for (i = 0; i < GNOME_CAL_LAST_VIEW; i++) { + e_cal_model_set_default_client ( + e_cal_view_get_model (E_CAL_VIEW (gcal->priv->views[i])), + client); + } +} + /** * gnome_calendar_get_task_pad_cal_client: * @gcal: A calendar view. @@ -2145,67 +2156,56 @@ add_alarms (const char *uri) CORBA_exception_free (&ev); } +/** + * gnome_calendar_add_event_uri: + * @gcal: A GnomeCalendar. + * @str_uri: URI to add to the calendar views. + * + * Adds the given calendar URI to the calendar views. + * + * Returns: TRUE if successful, FALSE if error. + */ gboolean -gnome_calendar_open (GnomeCalendar *gcal, const char *str_uri) +gnome_calendar_add_event_uri (GnomeCalendar *gcal, const char *str_uri) { GnomeCalendarPrivate *priv; - gboolean success; - EUri *uri; - char *message; - char *real_uri; - char *urinopwd; CalClient *client; - + int i; + g_return_val_if_fail (gcal != NULL, FALSE); g_return_val_if_fail (GNOME_IS_CALENDAR (gcal), FALSE); g_return_val_if_fail (str_uri != NULL, FALSE); priv = gcal->priv; - g_return_val_if_fail ( - cal_client_get_load_state (priv->task_pad_client) == CAL_CLIENT_LOAD_NOT_LOADED, - FALSE); - - uri = e_uri_new (str_uri); - if (!uri || !g_strncasecmp (uri->protocol, "file", 4)) - real_uri = g_concat_dir_and_file (str_uri, "calendar.ics"); - else - real_uri = g_strdup (str_uri); - - urinopwd = get_uri_without_password (str_uri); - message = g_strdup_printf (_("Opening calendar at %s"), urinopwd); - g_free (urinopwd); - e_cal_view_set_status_message (E_CAL_VIEW (priv->week_view), message); - g_free (message); - - client = cal_client_new (); - g_signal_connect (G_OBJECT (client), "cal_opened", G_CALLBACK (client_cal_opened_cb), gcal); + client = g_hash_table_lookup (priv->clients, str_uri); + if (client) + return TRUE; + + client = cal_client_new (str_uri, CALOBJ_TYPE_EVENT); + g_hash_table_insert (priv->clients, g_strdup (str_uri), g_object_ref (client)); + g_signal_connect (G_OBJECT (client), "backend_error", G_CALLBACK (backend_error_cb), gcal); g_signal_connect (G_OBJECT (client), "categories_changed", G_CALLBACK (client_categories_changed_cb), gcal); g_signal_connect (G_OBJECT (client), "backend_died", G_CALLBACK (backend_died_cb), gcal); - if (!cal_client_open_calendar (client, real_uri, FALSE)) { - g_warning (G_STRLOC ": Could not issue the request to open the calendar folder"); + if (!cal_client_open (client, FALSE, NULL)) { + g_hash_table_remove (priv->clients, str_uri); g_object_unref (client); - e_cal_view_set_status_message (E_CAL_VIEW (priv->week_view), NULL); return FALSE; } - /* Open the appropriate Tasks folder to show in the TaskPad */ - e_calendar_table_set_status_message (E_CALENDAR_TABLE (priv->todo), - _("Opening default tasks folder")); - success = cal_client_open_default_tasks (priv->task_pad_client, FALSE); - - g_free (real_uri); - e_uri_free (uri); - - if (!success) { - g_message ("gnome_calendar_open(): Could not issue the request to open the tasks folder"); - e_calendar_table_set_status_message (E_CALENDAR_TABLE (priv->todo), NULL); - return FALSE; + for (i = 0; i < GNOME_CAL_LAST_VIEW; i++) { + ECalModel *model; + + model = e_cal_view_get_model (priv->views[i]); + e_cal_model_add_client (model, client); } + /* update date navigator query */ + update_query (gcal); + return TRUE; } @@ -2308,7 +2308,8 @@ gnome_calendar_update_config_settings (GnomeCalendar *gcal, CalClient *client = l->data; if (cal_client_get_load_state (client) == CAL_CLIENT_LOAD_LOADED) - cal_client_set_default_timezone (client, priv->zone); + /* FIXME Error checking */ + cal_client_set_default_timezone (client, priv->zone, NULL); } g_list_free (client_list); @@ -2316,8 +2317,9 @@ gnome_calendar_update_config_settings (GnomeCalendar *gcal, if (priv->task_pad_client && cal_client_get_load_state (priv->task_pad_client) == CAL_CLIENT_LOAD_LOADED) { + /* FIXME Error Checking */ cal_client_set_default_timezone (priv->task_pad_client, - priv->zone); + priv->zone, NULL); } e_cal_view_set_timezone (E_CAL_VIEW (priv->day_view), priv->zone); @@ -2383,147 +2385,6 @@ gnome_calendar_get_selected_time_range (GnomeCalendar *gcal, *end_time = priv->selection_end_time; } -void -gnome_calendar_edit_object (GnomeCalendar *gcal, CalClient *client, icalcomponent *icalcomp, gboolean meeting) -{ - GnomeCalendarPrivate *priv; - CompEditor *ce; - const char *uid; - CalComponent *comp; - - g_return_if_fail (GNOME_IS_CALENDAR (gcal)); - g_return_if_fail (IS_CAL_CLIENT (client)); - g_return_if_fail (icalcomp != NULL); - - priv = gcal->priv; - - uid = icalcomponent_get_uid (icalcomp); - - ce = e_comp_editor_registry_find (comp_editor_registry, uid); - if (!ce) { - EventEditor *ee; - - ee = event_editor_new (client); - if (!ee) { - g_message ("gnome_calendar_edit_object(): Could not create the event editor"); - return; - } - ce = COMP_EDITOR (ee); - - comp = cal_component_new (); - cal_component_set_icalcomponent (comp, icalcomponent_new_clone (icalcomp)); - - comp_editor_edit_comp (ce, comp); - if (meeting) - event_editor_show_meeting (ee); - - e_comp_editor_registry_add (comp_editor_registry, ce, FALSE); - - g_object_unref (comp); - } - - comp_editor_focus (ce); -} - -/** - * gnome_calendar_new_appointment_for: - * @gcal: An Evolution calendar. - * @dtstart: a Unix time_t that marks the beginning of the appointment. - * @dtend: a Unix time_t that marks the end of the appointment. - * @all_day: if true, the dtstart and dtend are expanded to cover the entire - * day, and the event is set to TRANSPARENT. - * - * Opens an event editor dialog for a new appointment. - * - **/ -void -gnome_calendar_new_appointment_for (GnomeCalendar *cal, - time_t dtstart, time_t dtend, - gboolean all_day, - gboolean meeting) -{ - GnomeCalendarPrivate *priv; - struct icaltimetype itt; - CalComponentDateTime dt; - CalComponent *comp; - icalcomponent *icalcomp; - CalComponentTransparency transparency; - const char *category; - - g_return_if_fail (cal != NULL); - g_return_if_fail (GNOME_IS_CALENDAR (cal)); - - priv = cal->priv; - - dt.value = &itt; - if (all_day) - dt.tzid = NULL; - else - dt.tzid = icaltimezone_get_tzid (priv->zone); - - icalcomp = e_cal_model_create_component_with_defaults (e_cal_view_get_model (E_CAL_VIEW (priv->week_view))); - comp = cal_component_new (); - cal_component_set_icalcomponent (comp, icalcomp); - - /* DTSTART, DTEND */ - - itt = icaltime_from_timet_with_zone (dtstart, FALSE, priv->zone); - if (all_day) { - itt.hour = itt.minute = itt.second = 0; - itt.is_date = TRUE; - } - cal_component_set_dtstart (comp, &dt); - - itt = icaltime_from_timet_with_zone (dtend, FALSE, priv->zone); - if (all_day) { - /* We round it up to the end of the day, unless it is already - set to midnight. */ - if (itt.hour != 0 || itt.minute != 0 || itt.second != 0) { - icaltime_adjust (&itt, 1, 0, 0, 0); - } - itt.hour = itt.minute = itt.second = 0; - itt.is_date = TRUE; - } - cal_component_set_dtend (comp, &dt); - - transparency = all_day ? CAL_COMPONENT_TRANSP_TRANSPARENT - : CAL_COMPONENT_TRANSP_OPAQUE; - cal_component_set_transparency (comp, transparency); - - - /* Category */ - - category = cal_search_bar_get_category (CAL_SEARCH_BAR (priv->search_bar)); - cal_component_set_categories (comp, category); - - /* Edit! */ - - cal_component_commit_sequence (comp); - - gnome_calendar_edit_object (cal, gnome_calendar_get_default_client (cal), icalcomp, meeting); - g_object_unref (comp); -} - -/** - * gnome_calendar_new_appointment: - * @gcal: An Evolution calendar. - * - * Opens an event editor dialog for a new appointment. The appointment's start - * and end times are set to the currently selected time range in the calendar - * views. - **/ -void -gnome_calendar_new_appointment (GnomeCalendar *gcal) -{ - time_t dtstart, dtend; - - g_return_if_fail (gcal != NULL); - g_return_if_fail (GNOME_IS_CALENDAR (gcal)); - - gnome_calendar_get_current_time_range (gcal, &dtstart, &dtend); - gnome_calendar_new_appointment_for (gcal, dtstart, dtend, FALSE, FALSE); -} - /** * gnome_calendar_new_task: * @gcal: An Evolution calendar. @@ -3020,136 +2881,17 @@ gnome_calendar_delete_selected_occurrence (GnomeCalendar *gcal) } } -void -gnome_calendar_unrecur_selection (GnomeCalendar *gcal) -{ - GnomeCalendarPrivate *priv; - FocusLocation location; - GtkWidget *view; - - g_return_if_fail (GNOME_IS_CALENDAR (gcal)); - - priv = gcal->priv; - - location = get_focus_location (gcal); - - if (location == FOCUS_CALENDAR) { - - view = gnome_calendar_get_current_view_widget (gcal); - - if (E_IS_DAY_VIEW (view)) - e_day_view_unrecur_appointment (E_DAY_VIEW (view)); - else - e_week_view_unrecur_appointment (E_WEEK_VIEW (view)); - } -} - -typedef struct { - gboolean remove; - GnomeCalendar *gcal; -} obj_updated_closure; - static gboolean check_instance_cb (CalComponent *comp, time_t instance_start, time_t instance_end, gpointer data) { - obj_updated_closure *closure = data; - - if (instance_start >= closure->gcal->priv->exp_older_than || - instance_end >= closure->gcal->priv->exp_older_than) { - closure->remove = FALSE; - return FALSE; - } - - closure->remove = TRUE; - return TRUE; -} - -static void -purging_obj_updated_cb (CalQuery *query, const char *uid, - gboolean query_in_progress, int n_scanned, int total, - gpointer data) -{ - GnomeCalendarPrivate *priv; - GnomeCalendar *gcal = data; - CalComponent *comp; - icalcomponent *icalcomp; - obj_updated_closure closure; - gchar *msg; - - priv = gcal->priv; - - if (cal_client_get_object (cal_query_get_client (query), uid, &icalcomp) != CAL_CLIENT_GET_SUCCESS) - return; - - comp = cal_component_new (); - if (!cal_component_set_icalcomponent (comp, icalcomp)) { - g_object_unref (comp); - icalcomponent_free (icalcomp); - return; - } - - msg = g_strdup_printf (_("Purging event %s"), uid); - - /* further filter the event, to check the last recurrence end date */ - if (cal_component_has_recurrences (comp)) { - closure.remove = TRUE; - closure.gcal = gcal; - - cal_recur_generate_instances (comp, priv->exp_older_than, -1, - (CalRecurInstanceFn) check_instance_cb, - &closure, - (CalRecurResolveTimezoneFn) cal_client_resolve_tzid_cb, - cal_query_get_client (query), priv->zone); - - if (closure.remove) { - e_cal_view_set_status_message (E_CAL_VIEW (priv->week_view), msg); - delete_error_dialog (cal_client_remove_object (cal_query_get_client (query), uid), - CAL_COMPONENT_EVENT); - } - } else { - e_cal_view_set_status_message (E_CAL_VIEW (priv->week_view), msg); - delete_error_dialog (cal_client_remove_object (cal_query_get_client (query), uid), CAL_COMPONENT_EVENT); - } - - g_object_unref (comp); - g_free (msg); -} - -static void -purging_eval_error_cb (CalQuery *query, const char *error_str, gpointer data) -{ - GnomeCalendarPrivate *priv; - GnomeCalendar *gcal = data; - - priv = gcal->priv; - - e_cal_view_set_status_message (E_CAL_VIEW (priv->week_view), NULL); - - g_signal_handlers_disconnect_matched (query, G_SIGNAL_MATCH_DATA, - 0, 0, NULL, NULL, gcal); - - priv->exp_queries = g_list_remove (priv->exp_queries, query); - g_object_unref (query); -} + gboolean *remove = data; -static void -purging_query_done_cb (CalQuery *query, CalQueryDoneStatus status, const char *error_str, gpointer data) -{ - GnomeCalendarPrivate *priv; - GnomeCalendar *gcal = data; - - priv = gcal->priv; - - e_cal_view_set_status_message (E_CAL_VIEW (priv->week_view), NULL); + *remove = FALSE; - g_signal_handlers_disconnect_matched (query, G_SIGNAL_MATCH_DATA, - 0, 0, NULL, NULL, gcal); - - priv->exp_queries = g_list_remove (priv->exp_queries, query); - g_object_unref (query); + return FALSE; } void @@ -3163,11 +2905,6 @@ gnome_calendar_purge (GnomeCalendar *gcal, time_t older_than) priv = gcal->priv; - /* if we have a query, we are already purging */ - if (priv->exp_queries) - return; - - priv->exp_older_than = older_than; start = isodate_from_time_t (0); end = isodate_from_time_t (older_than); sexp = g_strdup_printf ("(and (= (get-vtype) \"VEVENT\")" @@ -3177,27 +2914,47 @@ gnome_calendar_purge (GnomeCalendar *gcal, time_t older_than) e_cal_view_set_status_message (E_CAL_VIEW (priv->week_view), _("Purging")); + /* FIXME Confirm expunge */ + client_list = e_cal_model_get_client_list (e_cal_view_get_model (E_CAL_VIEW (priv->week_view))); for (l = client_list; l != NULL; l = l->next) { - CalQuery *exp_query; - - if (cal_client_is_read_only ((CalClient *) l->data)) + CalClient *client = l->data; + GList *objects, *l; + gboolean read_only = TRUE; + + cal_client_is_read_only (client, &read_only, NULL); + if (!read_only) continue; - - exp_query = cal_client_get_query ((CalClient *) l->data, sexp); - if (!exp_query) { - e_cal_view_set_status_message (E_CAL_VIEW (priv->week_view), NULL); - g_message ("gnome_calendar_purge(): Could not create the query"); + + if (!cal_client_get_object_list (client, sexp, &objects, NULL)) { + g_warning (G_STRLOC ": Could not get the objects"); + continue; } - - g_signal_connect (exp_query, "obj_updated", G_CALLBACK (purging_obj_updated_cb), gcal); - g_signal_connect (exp_query, "query_done", G_CALLBACK (purging_query_done_cb), gcal); - g_signal_connect (exp_query, "eval_error", G_CALLBACK (purging_eval_error_cb), gcal); - - priv->exp_queries = g_list_append (priv->exp_queries, exp_query); + + for (l = objects; l; l = l->next) { + CalComponent *comp; + gboolean remove = TRUE; + + comp = cal_component_new (); + cal_component_set_icalcomponent (comp, icalcomponent_new_clone (l->data)); + + cal_recur_generate_instances (comp, older_than, -1, + (CalRecurInstanceFn) check_instance_cb, + &remove, + (CalRecurResolveTimezoneFn) cal_client_resolve_tzid_cb, + client, priv->zone); + + /* FIXME Better error handling */ + if (remove) + cal_client_remove_object (client, icalcomponent_get_uid (l->data), NULL); + + g_object_unref (comp); + } } + e_cal_view_set_status_message (E_CAL_VIEW (priv->week_view), NULL); + g_list_free (client_list); g_free (sexp); g_free (start); diff --git a/calendar/gui/gnome-cal.h b/calendar/gui/gnome-cal.h index c9bbcbaff4..f56ec69211 100644 --- a/calendar/gui/gnome-cal.h +++ b/calendar/gui/gnome-cal.h @@ -55,7 +55,8 @@ typedef enum { GNOME_CAL_WORK_WEEK_VIEW, GNOME_CAL_WEEK_VIEW, GNOME_CAL_MONTH_VIEW, - GNOME_CAL_LIST_VIEW + GNOME_CAL_LIST_VIEW, + GNOME_CAL_LAST_VIEW } GnomeCalendarViewType; typedef enum @@ -106,9 +107,10 @@ ECalendarTable *gnome_calendar_get_task_pad (GnomeCalendar *gcal); ECalModel *gnome_calendar_get_calendar_model (GnomeCalendar *gcal); CalClient *gnome_calendar_get_default_client (GnomeCalendar *gcal); +void gnome_calendar_set_default_client (GnomeCalendar *gcal, CalClient *client); CalClient *gnome_calendar_get_task_pad_cal_client(GnomeCalendar *gcal); -gboolean gnome_calendar_open (GnomeCalendar *gcal, const char *str_uri); +gboolean gnome_calendar_add_event_uri (GnomeCalendar *gcal, const char *str_uri); void gnome_calendar_set_query (GnomeCalendar *gcal, const char *sexp); @@ -145,17 +147,6 @@ void gnome_calendar_get_selected_time_range (GnomeCalendar *gcal, time_t *start_time, time_t *end_time); -void gnome_calendar_edit_object (GnomeCalendar *gcal, - CalClient *client, - icalcomponent *icalcomp, - gboolean meeting); - -void gnome_calendar_new_appointment (GnomeCalendar *gcal); -void gnome_calendar_new_appointment_for (GnomeCalendar *cal, - time_t dtstart, time_t dtend, - gboolean all_day, - gboolean meeting); - void gnome_calendar_new_task (GnomeCalendar *gcal); /* Returns the selected time range for the current view. Note that this may be @@ -193,7 +184,6 @@ void gnome_calendar_paste_clipboard (GnomeCalendar *gcal); void gnome_calendar_delete_selection (GnomeCalendar *gcal); void gnome_calendar_delete_selected_occurrence (GnomeCalendar *gcal); -void gnome_calendar_unrecur_selection (GnomeCalendar *gcal); void gnome_calendar_purge (GnomeCalendar *gcal, time_t older_than); diff --git a/calendar/gui/itip-utils.c b/calendar/gui/itip-utils.c index f5baa8bb05..e2640f01f4 100644 --- a/calendar/gui/itip-utils.c +++ b/calendar/gui/itip-utils.c @@ -70,8 +70,11 @@ static EAccountList *accounts = NULL; EAccountList * itip_addresses_get (void) { - if (accounts == NULL) - accounts = e_account_list_new(gconf_client_get_default()); + if (accounts == NULL) { + GConfClient *gconf_client = gconf_client_get_default (); + accounts = e_account_list_new (gconf_client); + g_object_unref (gconf_client); + } return accounts; } @@ -98,12 +101,14 @@ itip_organizer_is_user (CalComponent *comp, CalClient *client) strip = itip_strip_mailto (organizer.value); if (cal_client_get_static_capability (client, CAL_STATIC_CAPABILITY_ORGANIZER_NOT_EMAIL_ADDRESS)) { - const char *email; + char *email; - email = cal_client_get_cal_address (client); - if (email && !g_strcasecmp (email, strip)) + if (cal_client_get_cal_address (client, &email, NULL) && !g_strcasecmp (email, strip)) { + g_free (email); + return TRUE; - + } + return FALSE; } @@ -185,8 +190,8 @@ foreach_tzid_callback (icalparameter *param, gpointer data) zone = icalcomponent_get_timezone (tz_data->zones, tzid); if (zone == NULL) zone = icaltimezone_get_builtin_timezone_from_tzid (tzid); - if (zone == NULL && tz_data->client != NULL) - cal_client_get_timezone (tz_data->client, tzid, &zone); + if (zone == NULL && tz_data->client != NULL) + cal_client_get_timezone (tz_data->client, tzid, &zone, NULL); if (zone == NULL) return; @@ -528,28 +533,23 @@ static gboolean comp_server_send (CalComponentItipMethod method, CalComponent *comp, CalClient *client, icalcomponent *zones, GList **users) { - CalClientSendResult result; - icalcomponent *top_level, *new_top_level = NULL; - char *error_msg; + icalcomponent *top_level; gboolean retval = TRUE; + GError *error = NULL; top_level = comp_toplevel_with_zones (method, comp, client, zones); - result = cal_client_send_object (client, top_level, &new_top_level, users, &error_msg); - - if (result == CAL_CLIENT_SEND_SUCCESS) { - icalcomponent *ical_comp; - - ical_comp = icalcomponent_get_inner (new_top_level); - icalcomponent_remove_component (new_top_level, ical_comp); - cal_component_set_icalcomponent (comp, ical_comp); - icalcomponent_free (new_top_level); - } else if (result == CAL_CLIENT_SEND_BUSY) { - e_notice (NULL, GTK_MESSAGE_ERROR, error_msg); - - g_free (error_msg); - retval = FALSE; + if (!cal_client_send_objects (client, top_level, &error)) { + /* FIXME Really need a book problem status code */ + if (error->code != E_CALENDAR_STATUS_OK) { + /* FIXME Better error message */ + e_notice (NULL, GTK_MESSAGE_ERROR, "Unable to book"); + + retval = FALSE; + } } + g_clear_error (&error); + icalcomponent_free (top_level); return retval; @@ -755,7 +755,8 @@ comp_compliant (CalComponentItipMethod method, CalComponent *comp, CalClient *cl if (from_zone == NULL) from_zone = icaltimezone_get_builtin_timezone_from_tzid (dt.tzid); if (from_zone == NULL && client != NULL) - cal_client_get_timezone (client, dt.tzid, &from_zone); + /* FIXME Error checking */ + cal_client_get_timezone (client, dt.tzid, &from_zone, NULL); } to_zone = icaltimezone_get_utc_timezone (); diff --git a/calendar/gui/main.c b/calendar/gui/main.c index a15c0ef846..681417f1df 100644 --- a/calendar/gui/main.c +++ b/calendar/gui/main.c @@ -49,9 +49,9 @@ #include "tasks-control.h" -#define FACTORY_ID "OAFIID:GNOME_Evolution_Calendar_Factory" +#define FACTORY_ID "OAFIID:GNOME_Evolution_Calendar_Factory_2" -#define CALENDAR_COMPONENT_ID "OAFIID:GNOME_Evolution_Calendar_ShellComponent" +#define CALENDAR_COMPONENT_ID "OAFIID:GNOME_Evolution_Calendar_Component" #define CALENDAR_CONTROL_ID "OAFIID:GNOME_Evolution_Calendar_Control" #define TASKS_CONTROL_ID "OAFIID:GNOME_Evolution_Tasks_Control" #define ITIP_CONTROL_ID "OAFIID:GNOME_Evolution_Calendar_iTip_Control" @@ -155,23 +155,19 @@ factory (BonoboGenericFactory *factory, initialized = TRUE; } - if (strcmp (component_id, CALENDAR_COMPONENT_ID) == 0) - return calendar_component_get_object (); - if (strcmp (component_id, CALENDAR_CONTROL_ID) == 0) + if (strcmp (component_id, CALENDAR_COMPONENT_ID) == 0) { + BonoboObject *object = BONOBO_OBJECT (calendar_component_peek ()); + bonobo_object_ref (object); + return object; + } else if (strcmp (component_id, CALENDAR_CONTROL_ID) == 0) return BONOBO_OBJECT (control_factory_new_control ()); - if (strcmp (component_id, TASKS_CONTROL_ID) == 0) + else if (strcmp (component_id, TASKS_CONTROL_ID) == 0) return BONOBO_OBJECT (tasks_control_new ()); - if (strcmp (component_id, ITIP_CONTROL_ID) == 0) + else if (strcmp (component_id, ITIP_CONTROL_ID) == 0) return BONOBO_OBJECT (itip_bonobo_control_new ()); - if (strcmp (component_id, CONFIG_CONTROL_ID) == 0) { - extern EvolutionShellClient *global_shell_client; /* FIXME ugly */ - - if (global_shell_client == NULL) - return NULL; - else - return BONOBO_OBJECT (cal_prefs_dialog_new ()); - } - if (strcmp (component_id, COMP_EDITOR_FACTORY_ID) == 0) + else if (strcmp (component_id, CONFIG_CONTROL_ID) == 0) + return BONOBO_OBJECT (cal_prefs_dialog_new ()); + else if (strcmp (component_id, COMP_EDITOR_FACTORY_ID) == 0) return BONOBO_OBJECT (comp_editor_factory_fn ()); g_warning (FACTORY_ID ": Don't know what to do with %s", component_id); diff --git a/calendar/gui/migration.c b/calendar/gui/migration.c new file mode 100644 index 0000000000..be93309f1f --- /dev/null +++ b/calendar/gui/migration.c @@ -0,0 +1,126 @@ +/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */ +/* calendar-component.c + * + * Copyright (C) 2003 Ximian, Inc + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of version 2 of the GNU General Public + * License as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public + * License along with this program; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + * + * Author: Rodrigo Moya + */ + +#include +#include +#include +#include +#include "migration.h" + +static gboolean +process_calendar_dir (ESourceGroup *source_group, const char *path, + const char *name, const char *base_uri) +{ + char *s; + GnomeVFSURI *from, *to; + GnomeVFSResult vres; + ESource *source; + GDir *dir; + gboolean retval = TRUE; + + s = g_build_filename (path, "calendar.ics", NULL); + if (!g_file_test (s, G_FILE_TEST_EXISTS)) { + g_free (s); + return FALSE; + } + + /* transfer the old file to its new location */ + from = gnome_vfs_uri_new (s); + g_free (s); + if (!from) + return FALSE; + + s = g_build_filename (e_source_group_peek_base_uri (source_group), base_uri, + "calendar.ics", NULL); + if (e_mkdir_hier (s, 0700) != 0) { + gnome_vfs_uri_unref (from); + g_free (s); + return FALSE; + } + to = gnome_vfs_uri_new (s); + g_free (s); + if (!to) { + gnome_vfs_uri_unref (from); + return FALSE; + } + + vres = gnome_vfs_xfer_uri ((const GnomeVFSURI *) from, + (const GnomeVFSURI *) to, + GNOME_VFS_XFER_DEFAULT, + GNOME_VFS_XFER_ERROR_MODE_ABORT, + GNOME_VFS_XFER_OVERWRITE_MODE_REPLACE, + NULL, NULL); + gnome_vfs_uri_unref (from); + gnome_vfs_uri_unref (to); + + if (vres != GNOME_VFS_OK) + return FALSE; + + /* create the new source */ + source = e_source_new (name, base_uri); + e_source_group_add_source (source_group, source, -1); + + /* process subfolders */ + s = g_build_filename (path, "subfolders", NULL); + dir = g_dir_open (s, 0, NULL); + if (dir) { + const char *name, *tmp_s; + + while ((name = g_dir_read_name (dir))) { + tmp_s = g_build_filename (s, name, NULL); + if (g_file_test (tmp_s, G_FILE_TEST_IS_DIR)) { + retval = process_calendar_dir (source_group, tmp_s, name, name); + } + + g_free (tmp_s); + } + + g_dir_close (dir); + } + + g_free (s); + + return retval; +} + +gboolean +migrate_old_calendars (ESourceGroup *source_group) +{ + char *path; + gboolean retval; + + g_return_val_if_fail (E_IS_SOURCE_GROUP (source_group), FALSE); + + path = g_build_filename (g_get_home_dir (), "evolution", NULL); + if (!g_file_test (path, G_FILE_TEST_IS_DIR)) { + g_free (path); + return FALSE; + } + g_free (path); + + /* look for the top-level calendar */ + path = g_build_filename (g_get_home_dir (), "evolution/local/Calendar", NULL); + retval = process_calendar_dir (source_group, path, _("Personal"), "Personal"); + g_free (path); + + return retval; +} diff --git a/calendar/gui/migration.h b/calendar/gui/migration.h new file mode 100644 index 0000000000..2453d47abd --- /dev/null +++ b/calendar/gui/migration.h @@ -0,0 +1,30 @@ +/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */ +/* calendar-component.c + * + * Copyright (C) 2003 Ximian, Inc + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of version 2 of the GNU General Public + * License as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public + * License along with this program; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + * + * Author: Rodrigo Moya + */ + +#ifndef MIGRATION_H +#define MIGRATION_H + +#include + +gboolean migrate_old_calendars (ESourceGroup *source_group); + +#endif diff --git a/calendar/gui/print.c b/calendar/gui/print.c index 6aeb9f6566..0c0fa44886 100644 --- a/calendar/gui/print.c +++ b/calendar/gui/print.c @@ -522,6 +522,16 @@ format_date(time_t time, int flags, char *buffer, int bufflen) return buffer; } +static gboolean +instance_cb (CalComponent *comp, time_t instance_start, time_t instance_end, gpointer data) +{ + gboolean *found = data; + + *found = TRUE; + + return FALSE; +} + /* print out the month small, embolden any days with events. @@ -625,16 +635,16 @@ print_month_small (GnomePrintContext *pc, GnomeCalendar *gcal, time_t month, day = days[y * 7 + x]; if (day != 0) { - GList *uids; + gboolean found = FALSE; sprintf (buf, "%d", day); /* this is a slow messy way to do this ... but easy ... */ - uids = cal_client_get_objects_in_range (client, - CALOBJ_TYPE_EVENT, - now, time_day_end_with_zone (now, zone)); - font = uids ? font_bold : font_normal; - cal_obj_uid_list_free (uids); + cal_client_generate_instances (client, now, CALOBJ_TYPE_EVENT, + time_day_end_with_zone (now, zone), + instance_cb, &found); + + font = found ? font_bold : font_normal; next = time_add_day_with_zone (now, 1, zone); if ((now >= greystart && now < greyend) @@ -1805,7 +1815,7 @@ print_todo_details (GnomePrintContext *pc, GnomeCalendar *gcal, comp = cal_component_new (); cal_component_set_icalcomponent (comp, icalcomponent_new_clone (comp_data->icalcomp)); - cal_component_get_summary (comp_data->icalcomp, &summary); + cal_component_get_summary (comp, &summary); if (!summary.value) { g_object_unref (comp); continue; @@ -2161,11 +2171,8 @@ get_zone_from_tzid (CalClient *client, const char *tzid) the builtin timezone with the TZID first. */ zone = icaltimezone_get_builtin_timezone_from_tzid (tzid); if (!zone) { - CalClientGetStatus status; - - status = cal_client_get_timezone (client, tzid, &zone); - /* FIXME: Handle error better. */ - if (status != CAL_CLIENT_GET_SUCCESS) + if (!cal_client_get_timezone (client, tzid, &zone, NULL)) + /* FIXME: Handle error better. */ g_warning ("Couldn't get timezone from server: %s", tzid ? tzid : ""); } diff --git a/calendar/gui/tag-calendar.c b/calendar/gui/tag-calendar.c index 03e0b3dee4..147a69f246 100644 --- a/calendar/gui/tag-calendar.c +++ b/calendar/gui/tag-calendar.c @@ -162,7 +162,6 @@ resolve_tzid_cb (const char *tzid, gpointer data) { CalClient *client; icaltimezone *zone = NULL; - CalClientGetStatus status; g_return_val_if_fail (data != NULL, NULL); g_return_val_if_fail (IS_CAL_CLIENT (data), NULL); @@ -174,7 +173,7 @@ resolve_tzid_cb (const char *tzid, gpointer data) if (!zone) { /* FIXME: Handle errors. */ - status = cal_client_get_timezone (client, tzid, &zone); + cal_client_get_timezone (client, tzid, &zone, NULL); } return zone; diff --git a/calendar/gui/tasks-control.c b/calendar/gui/tasks-control.c index 5ed9faa0d6..d97ed2d585 100644 --- a/calendar/gui/tasks-control.c +++ b/calendar/gui/tasks-control.c @@ -235,12 +235,12 @@ static void sensitize_commands (ETasks *tasks, BonoboControl *control, int n_selected) { BonoboUIComponent *uic; - gboolean read_only; + gboolean read_only = TRUE; uic = bonobo_control_get_ui_component (control); g_assert (uic != NULL); - read_only = cal_client_is_read_only (e_tasks_get_cal_client (tasks)); + cal_client_is_read_only (e_tasks_get_cal_client (tasks), &read_only, NULL); bonobo_ui_component_set_prop (uic, "/commands/TasksCut", "sensitive", n_selected == 0 || read_only ? "0" : "1", diff --git a/configure.in b/configure.in index f5338d51d5..b29fd92db0 100644 --- a/configure.in +++ b/configure.in @@ -1051,6 +1051,13 @@ dnl ************************* GNOME_COMPILE_WARNINGS(yes) CFLAGS="$CFLAGS $WARN_CFLAGS" +case $CFLAGS in +*-Wall*) + # Turn off the annoying "comparison between signed and unsigned" + # warning in gcc 3.3 + CFLAGS="$CFLAGS -Wno-sign-compare" + ;; +esac AM_PATH_ORBIT2 @@ -1127,7 +1134,7 @@ AC_SUBST(SHELL_LIBS) dnl --- evolution-addressbook flags -EVOLUTION_ADDRESSBOOK_DEPS="gconf-2.0 libbonoboui-2.0 libglade-2.0 gal-2.2 >= $GAL_REQUIRED libgnomeui-2.0 libgnome-2.0 libgnomecanvas-2.0 gnome-vfs-2.0 libgnomeprintui-2.2" +EVOLUTION_ADDRESSBOOK_DEPS="gconf-2.0 libbonoboui-2.0 libglade-2.0 gal-2.2 >= $GAL_REQUIRED libgnomeui-2.0 libgnome-2.0 libgnomecanvas-2.0 gnome-vfs-2.0 libgnomeprintui-2.2 libgtkhtml-3.1 >= $GTKHTML_REQUIRED" EVO_SET_COMPILE_FLAGS(EVOLUTION_ADDRESSBOOK, $EVOLUTION_ADDRESSBOOK_DEPS) AC_SUBST(EVOLUTION_ADDRESSBOOK_CFLAGS) @@ -1331,11 +1338,15 @@ addressbook/gui/search/Makefile addressbook/gui/widgets/Makefile addressbook/backend/Makefile addressbook/backend/ebook/Makefile +addressbook/backend/ebook/tests/Makefile +addressbook/backend/ebook/tests/ebook/Makefile +addressbook/backend/ebook/tests/vcard/Makefile addressbook/backend/pas/Makefile addressbook/backend/idl/Makefile addressbook/conduit/Makefile addressbook/printing/Makefile addressbook/tools/Makefile +addressbook/util/Makefile art/Makefile camel/Makefile camel/providers/Makefile diff --git a/evolution-calendar.pc.in b/evolution-calendar.pc.in index 755578fe91..28042a122b 100644 --- a/evolution-calendar.pc.in +++ b/evolution-calendar.pc.in @@ -14,4 +14,4 @@ Description: libraries needed for Evolution calendar backends Version: @VERSION@ Requires: libgnome-2.0 libbonobo-2.0 gal-2.2 >= @GAL_REQUIRED@ gnome-vfs-2.0 Libs: -L${privlibdir} -lpcs -lcal-util -lcal-client -lical-evolution -leutil -Cflags: -I${privincludedir} +Cflags: -I${privincludedir} -I${privincludedir}/libical -- cgit v1.2.3