1 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
2 /* Evolution calendar - iCalendar file backend
4 * Copyright (C) 2000-2003 Ximian, Inc.
5 * Copyright (C) 2003 Gergõ Érdi
7 * Authors: Federico Mena-Quintero <federico@ximian.com>
8 * Rodrigo Moya <rodrigo@ximian.com>
9 * Gergõ Érdi <cactus@cactus.rulez.org>
11 * This program is free software; you can redistribute it and/or
12 * modify it under the terms of version 2 of the GNU Lesser General Public
13 * License as published by the Free Software Foundation.
15 * This program is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU Lesser General Public License for more details.
20 * You should have received a copy of the GNU Lesser General Public License
21 * along with this program; if not, write to the Free Software
22 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
31 #include "e-cal-backend-contacts.h"
33 #include <glib/gi18n-lib.h>
34 #include "libedataserver/e-xml-hash-utils.h"
35 #include <libecal/e-cal-recur.h>
36 #include <libecal/e-cal-util.h>
37 #include <libedata-cal/e-cal-backend-util.h>
38 #include <libedata-cal/e-cal-backend-sexp.h>
40 #include <libebook/e-book.h>
42 #include "libedataserver/e-source-list.h"
44 static ECalBackendSyncClass *parent_class;
46 /* Private part of the ECalBackendContacts structure */
47 struct _ECalBackendContactsPrivate {
48 ESourceList *addressbook_sources;
50 GHashTable *addressbooks; /* UID -> BookRecord */
51 gboolean addressbook_loaded;
54 GHashTable *tracked_contacts; /* UID -> ContactRecord */
57 icaltimezone *default_zone;
60 typedef struct _BookRecord {
65 typedef struct _ContactRecord {
66 ECalBackendContacts *cbc;
68 ECalComponent *comp_birthday, *comp_anniversary;
73 #define ANNIVERSARY_UID_EXT "-anniversary"
74 #define BIRTHDAY_UID_EXT "-birthday"
76 static ECalComponent * create_birthday (ECalBackendContacts *cbc, EContact *contact);
77 static ECalComponent * create_anniversary (ECalBackendContacts *cbc, EContact *contact);
79 static void contacts_changed_cb (EBookView *book_view, const GList *contacts, gpointer user_data);
80 static void contacts_added_cb (EBookView *book_view, const GList *contacts, gpointer user_data);
81 static void contacts_removed_cb (EBookView *book_view, const GList *contact_ids, gpointer user_data);
82 static ECalBackendSyncStatus
83 e_cal_backend_contacts_add_timezone (ECalBackendSync *backend, EDataCal *cal, const char *tzobj);
85 /* BookRecord methods */
87 book_record_new (ECalBackendContacts *cbc, ESource *source)
95 book = e_book_new (source, NULL);
96 e_book_open (book, TRUE, NULL);
98 /* Create book view */
99 fields = g_list_append (fields, (char*)e_contact_field_name (E_CONTACT_FILE_AS));
100 fields = g_list_append (fields, (char*)e_contact_field_name (E_CONTACT_BIRTH_DATE));
101 fields = g_list_append (fields, (char*)e_contact_field_name (E_CONTACT_ANNIVERSARY));
102 query = e_book_query_any_field_contains ("");
104 if (!e_book_get_book_view (book, query, fields, -1, &book_view, NULL)) {
105 g_list_free (fields);
106 e_book_query_unref (query);
109 e_book_query_unref (query);
110 g_list_free (fields);
112 g_signal_connect (book_view, "contacts_added", G_CALLBACK (contacts_added_cb), cbc);
113 g_signal_connect (book_view, "contacts_removed", G_CALLBACK (contacts_removed_cb), cbc);
114 g_signal_connect (book_view, "contacts_changed", G_CALLBACK (contacts_changed_cb), cbc);
116 e_book_view_start (book_view);
118 br = g_new (BookRecord, 1);
120 br->book_view = book_view;
126 book_record_free (BookRecord *br)
131 g_object_unref (br->book_view);
132 g_object_unref (br->book);
137 /* ContactRecord methods */
138 static ContactRecord *
139 contact_record_new (ECalBackendContacts *cbc, EContact *contact)
141 ContactRecord *cr = g_new0 (ContactRecord, 1);
145 cr->contact = contact;
146 cr->comp_birthday = create_birthday (cbc, contact);
147 cr->comp_anniversary = create_anniversary (cbc, contact);
149 if (cr->comp_birthday) {
150 comp_str = e_cal_component_get_as_string (cr->comp_birthday);
151 e_cal_backend_notify_object_created (E_CAL_BACKEND (cbc),
156 if (cr->comp_anniversary) {
158 comp_str = e_cal_component_get_as_string (cr->comp_anniversary);
159 e_cal_backend_notify_object_created (E_CAL_BACKEND (cbc),
164 g_object_ref (G_OBJECT (contact));
170 contact_record_free (ContactRecord *cr)
175 g_object_unref (G_OBJECT (cr->contact));
177 /* Remove the birthday event */
178 if (cr->comp_birthday) {
179 comp_str = e_cal_component_get_as_string (cr->comp_birthday);
180 id = e_cal_component_get_id (cr->comp_birthday);
181 e_cal_backend_notify_object_removed (E_CAL_BACKEND (cr->cbc), id, comp_str, NULL);
183 e_cal_component_free_id (id);
185 g_object_unref (G_OBJECT (cr->comp_birthday));
188 /* Remove the anniversary event */
189 if (cr->comp_anniversary) {
190 comp_str = e_cal_component_get_as_string (cr->comp_anniversary);
191 id = e_cal_component_get_id (cr->comp_anniversary);
193 e_cal_backend_notify_object_removed (E_CAL_BACKEND (cr->cbc), id, comp_str, NULL);
195 e_cal_component_free_id (id);
197 g_object_unref (G_OBJECT (cr->comp_anniversary));
203 /* ContactRecordCB methods */
204 typedef struct _ContactRecordCB {
205 ECalBackendContacts *cbc;
206 ECalBackendSExp *sexp;
210 static ContactRecordCB *
211 contact_record_cb_new (ECalBackendContacts *cbc, ECalBackendSExp *sexp)
213 ContactRecordCB *cb_data = g_new (ContactRecordCB, 1);
216 cb_data->sexp = sexp;
217 cb_data->result = NULL;
223 contact_record_cb_free (ContactRecordCB *cb_data)
225 g_list_foreach (cb_data->result, (GFunc) g_free, NULL);
226 g_list_free (cb_data->result);
232 contact_record_cb (gpointer key, gpointer value, gpointer user_data)
234 ContactRecordCB *cb_data = user_data;
235 ContactRecord *record = value;
237 if (record->comp_birthday && e_cal_backend_sexp_match_comp (cb_data->sexp, record->comp_birthday, E_CAL_BACKEND (cb_data->cbc))) {
238 char * comp_str = e_cal_component_get_as_string (record->comp_birthday);
239 cb_data->result = g_list_append (cb_data->result, comp_str);
242 if (record->comp_anniversary && e_cal_backend_sexp_match_comp (cb_data->sexp, record->comp_anniversary, E_CAL_BACKEND (cb_data->cbc))) {
243 char * comp_str = e_cal_component_get_as_string (record->comp_anniversary);
244 cb_data->result = g_list_append (cb_data->result, comp_str);
248 /* SourceList callbacks */
250 add_source (ECalBackendContacts *cbc, ESource *source)
252 BookRecord *br = book_record_new (cbc, source);
253 const char *uid = e_source_peek_uid (source);
255 g_hash_table_insert (cbc->priv->addressbooks, g_strdup (uid), br);
259 source_added_cb (ESourceGroup *group, ESource *source, gpointer user_data)
261 ECalBackendContacts *cbc = E_CAL_BACKEND_CONTACTS (user_data);
263 g_return_if_fail (cbc);
265 add_source (cbc, source);
269 source_removed_cb (ESourceGroup *group, ESource *source, gpointer user_data)
271 ECalBackendContacts *cbc = E_CAL_BACKEND_CONTACTS (user_data);
272 const char *uid = e_source_peek_uid (source);
274 g_return_if_fail (cbc);
276 g_hash_table_remove (cbc->priv->addressbooks, uid);
280 source_group_added_cb (ESourceList *source_list, ESourceGroup *group, gpointer user_data)
282 ECalBackendContacts *cbc = E_CAL_BACKEND_CONTACTS (user_data);
283 const gchar *base_uri;
286 g_return_if_fail (cbc);
288 base_uri = e_source_group_peek_base_uri (group);
292 /* Load all address books from this group */
293 if (!strncmp (base_uri, "file", 4)) {
294 for (i = e_source_group_peek_sources (group); i; i = i->next) {
295 ESource *source = E_SOURCE (i->data);
296 add_source (cbc, source);
299 /* Watch for future changes */
300 g_signal_connect (group, "source_added", G_CALLBACK (source_added_cb), cbc);
301 g_signal_connect (group, "source_removed", G_CALLBACK (source_removed_cb), cbc);
306 source_group_removed_cb (ESourceList *source_list, ESourceGroup *group, gpointer user_data)
308 ECalBackendContacts *cbc = E_CAL_BACKEND_CONTACTS (user_data);
311 g_return_if_fail (cbc);
313 /* Unload all address books from this group */
314 for (i = e_source_group_peek_sources (group); i; i = i->next) {
315 ESource *source = E_SOURCE (i->data);
316 const char *uid = e_source_peek_uid (source);
318 g_hash_table_remove (cbc->priv->addressbooks, uid);
322 /************************************************************************************/
325 contacts_changed_cb (EBookView *book_view, const GList *contacts, gpointer user_data)
327 ECalBackendContacts *cbc = E_CAL_BACKEND_CONTACTS (user_data);
330 for (i = contacts; i; i = i->next) {
331 EContact *contact = E_CONTACT (i->data);
332 const char *uid = e_contact_get_const (contact, E_CONTACT_UID);
334 /* Because this is a change of contact, then always remove old tracked data
335 and if possible, add with (possibly) new values.
337 g_hash_table_remove (cbc->priv->tracked_contacts, (char *)uid);
339 if (e_contact_get (contact, E_CONTACT_BIRTH_DATE) ||
340 e_contact_get (contact, E_CONTACT_ANNIVERSARY)) {
341 ContactRecord *cr = contact_record_new (cbc, contact);
342 g_hash_table_insert (cbc->priv->tracked_contacts, g_strdup (uid), cr);
348 contacts_added_cb (EBookView *book_view, const GList *contacts, gpointer user_data)
350 ECalBackendContacts *cbc = E_CAL_BACKEND_CONTACTS (user_data);
353 /* See if any new contacts have BIRTHDAY or ANNIVERSARY fields */
354 for (i = contacts; i; i = i->next)
356 EContact *contact = E_CONTACT (i->data);
357 EContactDate *birthday, *anniversary;
359 birthday = e_contact_get (contact, E_CONTACT_BIRTH_DATE);
360 anniversary = e_contact_get (contact, E_CONTACT_ANNIVERSARY);
362 if (birthday || anniversary) {
363 ContactRecord *cr = contact_record_new (cbc, contact);
364 const char *uid = e_contact_get_const (contact, E_CONTACT_UID);
366 g_hash_table_insert (cbc->priv->tracked_contacts, g_strdup (uid), cr);
369 e_contact_date_free (birthday);
370 e_contact_date_free (anniversary);
375 contacts_removed_cb (EBookView *book_view, const GList *contact_ids, gpointer user_data)
377 ECalBackendContacts *cbc = E_CAL_BACKEND_CONTACTS (user_data);
380 /* Stop tracking these */
381 for (i = contact_ids; i; i = i->next)
382 g_hash_table_remove (cbc->priv->tracked_contacts, i->data);
385 /************************************************************************************/
386 static struct icaltimetype
387 cdate_to_icaltime (EContactDate *cdate)
389 struct icaltimetype ret;
391 /*FIXME: this is a really _ugly_ (temporary) hack
392 * since several functions are still depending on the epoch,
393 * let entries start (earliest) at 19700101
395 ret.year = cdate->year >= 1970 ? cdate->year : 1970;
396 ret.month = cdate->month;
397 ret.day = cdate->day;
401 ret.is_daylight = FALSE;
403 ret.hour = ret.minute = ret.second = 0;
408 /* Contact -> Event creator */
409 static ECalComponent *
410 create_component (ECalBackendContacts *cbc, const char *uid, EContactDate *cdate, const char *summary)
412 ECalComponent *cal_comp;
413 ECalComponentText comp_summary;
414 icalcomponent *ical_comp;
415 struct icaltimetype itt;
416 ECalComponentDateTime dt;
417 struct icalrecurrencetype r;
420 g_return_val_if_fail (E_IS_CAL_BACKEND_CONTACTS (cbc), NULL);
425 ical_comp = icalcomponent_new (ICAL_VEVENT_COMPONENT);
427 /* Create the event object */
428 cal_comp = e_cal_component_new ();
429 e_cal_component_set_icalcomponent (cal_comp, ical_comp);
432 d(g_message ("Creating UID: %s", uid));
433 e_cal_component_set_uid (cal_comp, uid);
435 /* Set all-day event's date from contact data */
436 itt = cdate_to_icaltime (cdate);
439 e_cal_component_set_dtstart (cal_comp, &dt);
441 itt = cdate_to_icaltime (cdate);
442 icaltime_adjust (&itt, 1, 0, 0, 0);
445 /* We have to add 1 day to DTEND, as it is not inclusive. */
446 e_cal_component_set_dtend (cal_comp, &dt);
448 /* Create yearly recurrence */
449 icalrecurrencetype_clear (&r);
450 r.freq = ICAL_YEARLY_RECURRENCE;
452 recur_list.data = &r;
453 recur_list.next = NULL;
454 e_cal_component_set_rrule_list (cal_comp, &recur_list);
457 comp_summary.value = summary;
458 comp_summary.altrep = NULL;
459 e_cal_component_set_summary (cal_comp, &comp_summary);
461 /* Set category and visibility */
462 if (g_str_has_suffix (uid, ANNIVERSARY_UID_EXT))
463 e_cal_component_set_categories (cal_comp, _("Anniversary"));
464 else if (g_str_has_suffix (uid, BIRTHDAY_UID_EXT))
465 e_cal_component_set_categories (cal_comp, _("Birthday"));
467 e_cal_component_set_classification (cal_comp, E_CAL_COMPONENT_CLASS_PRIVATE);
469 /* Birthdays/anniversaries are shown as free time */
470 e_cal_component_set_transparency (cal_comp, E_CAL_COMPONENT_TRANSP_TRANSPARENT);
472 /* Don't forget to call commit()! */
473 e_cal_component_commit_sequence (cal_comp);
478 static ECalComponent *
479 create_birthday (ECalBackendContacts *cbc, EContact *contact)
482 ECalComponent *cal_comp;
487 cdate = e_contact_get (contact, E_CONTACT_BIRTH_DATE);
488 name = e_contact_get_const (contact, E_CONTACT_FILE_AS);
490 uid = g_strdup_printf ("%s%s", (char *) e_contact_get_const (contact, E_CONTACT_UID), BIRTHDAY_UID_EXT);
491 summary = g_strdup_printf (_("Birthday: %s"), name);
493 cal_comp = create_component (cbc, uid, cdate, summary);
495 e_contact_date_free (cdate);
502 static ECalComponent *
503 create_anniversary (ECalBackendContacts *cbc, EContact *contact)
506 ECalComponent *cal_comp;
511 cdate = e_contact_get (contact, E_CONTACT_ANNIVERSARY);
512 name = e_contact_get_const (contact, E_CONTACT_FILE_AS);
514 uid = g_strdup_printf ("%s%s", (char *) e_contact_get_const (contact, E_CONTACT_UID), ANNIVERSARY_UID_EXT);
515 summary = g_strdup_printf (_("Anniversary: %s"), name);
517 cal_comp = create_component (cbc, uid, cdate, summary);
519 e_contact_date_free (cdate);
526 /************************************************************************************/
527 /* Calendar backend method implementations */
529 /* First the empty stubs */
531 static ECalBackendSyncStatus
532 e_cal_backend_contacts_get_cal_address (ECalBackendSync *backend, EDataCal *cal,
535 /* A contact backend has no particular email address associated
536 * with it (although that would be a useful feature some day).
540 return GNOME_Evolution_Calendar_Success;
543 static ECalBackendSyncStatus
544 e_cal_backend_contacts_get_ldap_attribute (ECalBackendSync *backend, EDataCal *cal,
549 return GNOME_Evolution_Calendar_Success;
552 static ECalBackendSyncStatus
553 e_cal_backend_contacts_get_alarm_email_address (ECalBackendSync *backend, EDataCal *cal,
556 /* A contact backend has no particular email address associated
557 * with it (although that would be a useful feature some day).
561 return GNOME_Evolution_Calendar_Success;
564 static ECalBackendSyncStatus
565 e_cal_backend_contacts_get_static_capabilities (ECalBackendSync *backend, EDataCal *cal,
568 *capabilities = NULL;
570 return GNOME_Evolution_Calendar_Success;
573 static ECalBackendSyncStatus
574 e_cal_backend_contacts_remove (ECalBackendSync *backend, EDataCal *cal)
577 return GNOME_Evolution_Calendar_PermissionDenied;
580 static ECalBackendSyncStatus
581 e_cal_backend_contacts_get_default_object (ECalBackendSync *backend, EDataCal *cal,
584 return GNOME_Evolution_Calendar_UnsupportedMethod;
587 static ECalBackendSyncStatus
588 e_cal_backend_contacts_get_object (ECalBackendSync *backend, EDataCal *cal,
589 const char *uid, const char *rid,
592 ECalBackendContacts *cbc = E_CAL_BACKEND_CONTACTS (backend);
593 ECalBackendContactsPrivate *priv = cbc->priv;
594 ContactRecord *record;
598 return GNOME_Evolution_Calendar_ObjectNotFound;
599 else if (g_str_has_suffix (uid, ANNIVERSARY_UID_EXT))
600 real_uid = g_strndup (uid, strlen (uid) - strlen (ANNIVERSARY_UID_EXT));
601 else if (g_str_has_suffix (uid, BIRTHDAY_UID_EXT))
602 real_uid = g_strndup (uid, strlen (uid) - strlen (BIRTHDAY_UID_EXT));
604 return GNOME_Evolution_Calendar_ObjectNotFound;
606 record = g_hash_table_lookup (priv->tracked_contacts, real_uid);
610 return GNOME_Evolution_Calendar_ObjectNotFound;
612 if (record->comp_birthday && g_str_has_suffix (uid, BIRTHDAY_UID_EXT)) {
613 *object = e_cal_component_get_as_string (record->comp_birthday);
615 d(g_message ("Return birthday: %s", *object));
616 return GNOME_Evolution_Calendar_Success;
619 if (record->comp_anniversary && g_str_has_suffix (uid, ANNIVERSARY_UID_EXT)) {
620 *object = e_cal_component_get_as_string (record->comp_anniversary);
622 d(g_message ("Return anniversary: %s", *object));
623 return GNOME_Evolution_Calendar_Success;
626 d(g_message ("Returning nothing for uid: %s", uid));
628 return GNOME_Evolution_Calendar_ObjectNotFound;
631 static ECalBackendSyncStatus
632 e_cal_backend_contacts_get_free_busy (ECalBackendSync *backend, EDataCal *cal,
633 GList *users, time_t start, time_t end,
636 /* Birthdays/anniversaries don't count as busy time */
638 icalcomponent *vfb = icalcomponent_new_vfreebusy ();
639 icaltimezone *utc_zone = icaltimezone_get_utc_timezone ();
644 icalparameter *param;
646 prop = icalproperty_new_organizer (address);
647 if (prop != NULL && cn != NULL) {
648 param = icalparameter_new_cn (cn);
649 icalproperty_add_parameter (prop, param);
652 icalcomponent_add_property (vfb, prop);
655 icalcomponent_set_dtstart (vfb, icaltime_from_timet_with_zone (start, FALSE, utc_zone));
656 icalcomponent_set_dtend (vfb, icaltime_from_timet_with_zone (end, FALSE, utc_zone));
658 calobj = icalcomponent_as_ical_string (vfb);
659 *freebusy = g_list_append (NULL, g_strdup (calobj));
660 icalcomponent_free (vfb);
663 return GNOME_Evolution_Calendar_Success;
666 static ECalBackendSyncStatus
667 e_cal_backend_contacts_get_changes (ECalBackendSync *backend, EDataCal *cal,
668 const char *change_id,
669 GList **adds, GList **modifies, GList **deletes)
672 return GNOME_Evolution_Calendar_Success;
675 static ECalBackendSyncStatus
676 e_cal_backend_contacts_discard_alarm (ECalBackendSync *backend, EDataCal *cal,
677 const char *uid, const char *auid)
680 return GNOME_Evolution_Calendar_Success;
683 static ECalBackendSyncStatus
684 e_cal_backend_contacts_receive_objects (ECalBackendSync *backend, EDataCal *cal,
687 return GNOME_Evolution_Calendar_PermissionDenied;
690 static ECalBackendSyncStatus
691 e_cal_backend_contacts_send_objects (ECalBackendSync *backend, EDataCal *cal,
692 const char *calobj, GList **users, char **modified_calobj)
695 *modified_calobj = NULL;
696 /* TODO: Investigate this */
697 return GNOME_Evolution_Calendar_PermissionDenied;
700 /* Then the real implementations */
703 e_cal_backend_contacts_get_mode (ECalBackend *backend)
705 return CAL_MODE_LOCAL;
709 e_cal_backend_contacts_set_mode (ECalBackend *backend, CalMode mode)
711 e_cal_backend_notify_mode (backend,
712 GNOME_Evolution_Calendar_CalListener_MODE_NOT_SUPPORTED,
713 GNOME_Evolution_Calendar_MODE_LOCAL);
717 static ECalBackendSyncStatus
718 e_cal_backend_contacts_is_read_only (ECalBackendSync *backend, EDataCal *cal,
723 return GNOME_Evolution_Calendar_Success;
726 static ECalBackendSyncStatus
727 e_cal_backend_contacts_open (ECalBackendSync *backend, EDataCal *cal,
728 gboolean only_if_exists,
729 const char *username, const char *password)
731 ECalBackendContacts *cbc = E_CAL_BACKEND_CONTACTS (backend);
732 ECalBackendContactsPrivate *priv = cbc->priv;
736 if (priv->addressbook_loaded)
737 return GNOME_Evolution_Calendar_Success;
739 if (priv->default_zone && priv->default_zone != icaltimezone_get_utc_timezone ()) {
740 icalcomponent *icalcomp = icaltimezone_get_component (priv->default_zone);
741 icaltimezone *zone = icaltimezone_new ();
743 icaltimezone_set_component (zone, icalcomponent_new_clone (icalcomp));
745 g_hash_table_insert (priv->zones, g_strdup (icaltimezone_get_tzid (zone)), zone);
748 /* Create address books for existing sources */
749 for (i = e_source_list_peek_groups (priv->addressbook_sources); i; i = i->next) {
750 ESourceGroup *source_group = E_SOURCE_GROUP (i->data);
752 source_group_added_cb (priv->addressbook_sources, source_group, cbc);
755 /* Listen for source list changes */
756 g_signal_connect (priv->addressbook_sources, "group_added", G_CALLBACK (source_group_added_cb), cbc);
757 g_signal_connect (priv->addressbook_sources, "group_removed", G_CALLBACK (source_group_removed_cb), cbc);
759 priv->addressbook_loaded = TRUE;
760 return GNOME_Evolution_Calendar_Success;
764 e_cal_backend_contacts_is_loaded (ECalBackend *backend)
766 ECalBackendContacts *cbc = E_CAL_BACKEND_CONTACTS (backend);
767 ECalBackendContactsPrivate *priv = cbc->priv;
769 return priv->addressbook_loaded;
772 static ECalBackendSyncStatus
773 e_cal_backend_contacts_get_timezone (ECalBackendSync *backend, EDataCal *cal, const char *tzid, char **object)
775 ECalBackendContacts *cbcontacts;
776 ECalBackendContactsPrivate *priv;
778 icalcomponent *icalcomp;
780 cbcontacts = E_CAL_BACKEND_CONTACTS (backend);
781 priv = cbcontacts->priv;
783 g_return_val_if_fail (tzid != NULL, GNOME_Evolution_Calendar_ObjectNotFound);
785 zone = e_cal_backend_internal_get_timezone (E_CAL_BACKEND (backend), tzid);
787 return GNOME_Evolution_Calendar_ObjectNotFound;
789 icalcomp = icaltimezone_get_component (zone);
791 return GNOME_Evolution_Calendar_InvalidObject;
793 *object = g_strdup (icalcomponent_as_ical_string (icalcomp));
795 return GNOME_Evolution_Calendar_Success;
798 /* Add_timezone handler for the file backend */
799 static ECalBackendSyncStatus
800 e_cal_backend_contacts_add_timezone (ECalBackendSync *backend, EDataCal *cal, const char *tzobj)
802 ECalBackendContacts *cbcontacts;
803 ECalBackendContactsPrivate *priv;
804 icalcomponent *tz_comp;
808 cbcontacts = (ECalBackendContacts *) backend;
810 g_return_val_if_fail (E_IS_CAL_BACKEND_CONTACTS (cbcontacts), GNOME_Evolution_Calendar_OtherError);
811 g_return_val_if_fail (tzobj != NULL, GNOME_Evolution_Calendar_OtherError);
813 priv = cbcontacts->priv;
815 tz_comp = icalparser_parse_string (tzobj);
817 return GNOME_Evolution_Calendar_InvalidObject;
819 if (icalcomponent_isa (tz_comp) != ICAL_VTIMEZONE_COMPONENT)
820 return GNOME_Evolution_Calendar_InvalidObject;
822 zone = icaltimezone_new ();
823 icaltimezone_set_component (zone, tz_comp);
824 tzid = icaltimezone_get_tzid (zone);
826 if (g_hash_table_lookup (priv->zones, tzid)) {
827 icaltimezone_free (zone, TRUE);
829 return GNOME_Evolution_Calendar_Success;
832 g_hash_table_insert (priv->zones, g_strdup (tzid), zone);
834 return GNOME_Evolution_Calendar_Success;
837 static ECalBackendSyncStatus
838 e_cal_backend_contacts_set_default_zone (ECalBackendSync *backend, EDataCal *cal, const char *tzobj)
840 icalcomponent *tz_comp;
841 ECalBackendContacts *cbcontacts;
842 ECalBackendContactsPrivate *priv;
845 cbcontacts = (ECalBackendContacts *) backend;
847 g_return_val_if_fail (E_IS_CAL_BACKEND_CONTACTS (cbcontacts), GNOME_Evolution_Calendar_OtherError);
848 g_return_val_if_fail (tzobj != NULL, GNOME_Evolution_Calendar_OtherError);
850 priv = cbcontacts->priv;
852 tz_comp = icalparser_parse_string (tzobj);
854 return GNOME_Evolution_Calendar_InvalidObject;
856 zone = icaltimezone_new ();
857 icaltimezone_set_component (zone, tz_comp);
859 if (priv->default_zone && priv->default_zone != icaltimezone_get_utc_timezone ())
860 icaltimezone_free (priv->default_zone, 1);
862 /* Set the default timezone to it. */
863 priv->default_zone = zone;
865 return GNOME_Evolution_Calendar_Success;
868 static ECalBackendSyncStatus
869 e_cal_backend_contacts_get_object_list (ECalBackendSync *backend, EDataCal *cal,
870 const char *sexp_string, GList **objects)
872 ECalBackendContacts *cbc = E_CAL_BACKEND_CONTACTS (backend);
873 ECalBackendContactsPrivate *priv = cbc->priv;
874 ECalBackendSExp *sexp = e_cal_backend_sexp_new (sexp_string);
875 ContactRecordCB *cb_data;
878 return GNOME_Evolution_Calendar_InvalidQuery;
880 cb_data = contact_record_cb_new (cbc, sexp);
881 g_hash_table_foreach (priv->tracked_contacts, contact_record_cb, cb_data);
882 *objects = cb_data->result;
884 /* Don't call cb_data_free as that would destroy the results
888 return GNOME_Evolution_Calendar_Success;
892 e_cal_backend_contacts_start_query (ECalBackend *backend, EDataCalView *query)
894 ECalBackendContacts *cbc = E_CAL_BACKEND_CONTACTS (backend);
895 ECalBackendContactsPrivate *priv = cbc->priv;
896 ECalBackendSExp *sexp;
897 ContactRecordCB *cb_data;
899 sexp = e_data_cal_view_get_object_sexp (query);
901 e_data_cal_view_notify_done (query, GNOME_Evolution_Calendar_InvalidQuery);
905 cb_data = contact_record_cb_new (cbc, sexp);
907 g_hash_table_foreach (priv->tracked_contacts, contact_record_cb, cb_data);
908 e_data_cal_view_notify_objects_added (query, cb_data->result);
910 contact_record_cb_free (cb_data);
912 e_data_cal_view_notify_done (query, GNOME_Evolution_Calendar_Success);
915 static icaltimezone *
916 e_cal_backend_contacts_internal_get_default_timezone (ECalBackend *backend)
918 ECalBackendContacts *cbc = E_CAL_BACKEND_CONTACTS (backend);
920 return cbc->priv->default_zone;
923 static icaltimezone *
924 e_cal_backend_contacts_internal_get_timezone (ECalBackend *backend, const char *tzid)
926 ECalBackendContacts *cbc = E_CAL_BACKEND_CONTACTS (backend);
928 return cbc->priv->default_zone;
931 /***********************************************************************************
935 free_zone (gpointer data)
937 icaltimezone_free (data, TRUE);
940 /* Finalize handler for the contacts backend */
942 e_cal_backend_contacts_finalize (GObject *object)
944 ECalBackendContacts *cbc;
945 ECalBackendContactsPrivate *priv;
947 g_return_if_fail (object != NULL);
948 g_return_if_fail (E_IS_CAL_BACKEND_CONTACTS (object));
950 cbc = E_CAL_BACKEND_CONTACTS (object);
953 if (priv->default_zone && priv->default_zone != icaltimezone_get_utc_timezone ()) {
954 icaltimezone_free (priv->default_zone, 1);
957 priv->default_zone = NULL;
958 g_hash_table_destroy (priv->addressbooks);
959 g_hash_table_destroy (priv->tracked_contacts);
960 g_hash_table_destroy (priv->zones);
965 if (G_OBJECT_CLASS (parent_class)->finalize)
966 (* G_OBJECT_CLASS (parent_class)->finalize) (object);
969 /* Object initialization function for the contacts backend */
971 e_cal_backend_contacts_init (ECalBackendContacts *cbc, ECalBackendContactsClass *class)
973 ECalBackendContactsPrivate *priv;
975 priv = g_new0 (ECalBackendContactsPrivate, 1);
977 e_book_get_addressbooks (&priv->addressbook_sources, NULL);
979 priv->addressbooks = g_hash_table_new_full (g_str_hash, g_str_equal,
980 g_free, (GDestroyNotify) book_record_free);
981 priv->tracked_contacts = g_hash_table_new_full (g_str_hash, g_str_equal,
982 g_free, (GDestroyNotify)contact_record_free);
984 priv->zones = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, free_zone);
985 priv->default_zone = icaltimezone_get_utc_timezone ();
989 e_cal_backend_sync_set_lock (E_CAL_BACKEND_SYNC (cbc), TRUE);
992 static ECalBackendSyncStatus
993 e_cal_backend_contacts_create_object (ECalBackendSync *backend, EDataCal *cal, char **calobj, char **uid)
995 ECalBackendContacts *cbcontacts;
996 ECalBackendContactsPrivate *priv;
998 cbcontacts = E_CAL_BACKEND_CONTACTS (backend);
999 priv = cbcontacts->priv;
1001 return GNOME_Evolution_Calendar_PermissionDenied;
1004 /* Class initialization function for the contacts backend */
1006 e_cal_backend_contacts_class_init (ECalBackendContactsClass *class)
1008 GObjectClass *object_class;
1009 ECalBackendClass *backend_class;
1010 ECalBackendSyncClass *sync_class;
1012 object_class = (GObjectClass *) class;
1013 backend_class = (ECalBackendClass *) class;
1014 sync_class = (ECalBackendSyncClass *) class;
1016 parent_class = (ECalBackendSyncClass *) g_type_class_peek_parent (class);
1018 object_class->finalize = e_cal_backend_contacts_finalize;
1020 sync_class->is_read_only_sync = e_cal_backend_contacts_is_read_only;
1021 sync_class->get_cal_address_sync = e_cal_backend_contacts_get_cal_address;
1022 sync_class->get_alarm_email_address_sync = e_cal_backend_contacts_get_alarm_email_address;
1023 sync_class->get_ldap_attribute_sync = e_cal_backend_contacts_get_ldap_attribute;
1024 sync_class->get_static_capabilities_sync = e_cal_backend_contacts_get_static_capabilities;
1025 sync_class->open_sync = e_cal_backend_contacts_open;
1026 sync_class->remove_sync = e_cal_backend_contacts_remove;
1027 sync_class->create_object_sync = e_cal_backend_contacts_create_object;
1028 sync_class->discard_alarm_sync = e_cal_backend_contacts_discard_alarm;
1029 sync_class->receive_objects_sync = e_cal_backend_contacts_receive_objects;
1030 sync_class->send_objects_sync = e_cal_backend_contacts_send_objects;
1031 sync_class->get_default_object_sync = e_cal_backend_contacts_get_default_object;
1032 sync_class->get_object_sync = e_cal_backend_contacts_get_object;
1033 sync_class->get_object_list_sync = e_cal_backend_contacts_get_object_list;
1034 sync_class->get_timezone_sync = e_cal_backend_contacts_get_timezone;
1035 sync_class->add_timezone_sync = e_cal_backend_contacts_add_timezone;
1036 sync_class->set_default_zone_sync = e_cal_backend_contacts_set_default_zone;
1037 sync_class->get_freebusy_sync = e_cal_backend_contacts_get_free_busy;
1038 sync_class->get_changes_sync = e_cal_backend_contacts_get_changes;
1039 backend_class->is_loaded = e_cal_backend_contacts_is_loaded;
1040 backend_class->start_query = e_cal_backend_contacts_start_query;
1041 backend_class->get_mode = e_cal_backend_contacts_get_mode;
1042 backend_class->set_mode = e_cal_backend_contacts_set_mode;
1044 backend_class->internal_get_default_timezone = e_cal_backend_contacts_internal_get_default_timezone;
1045 backend_class->internal_get_timezone = e_cal_backend_contacts_internal_get_timezone;
1050 * e_cal_backend_contacts_get_type:
1053 * Registers the #ECalBackendContacts class if necessary, and returns
1054 * the type ID associated to it.
1056 * Return value: The type ID of the #ECalBackendContacts class.
1059 e_cal_backend_contacts_get_type (void)
1061 static GType e_cal_backend_contacts_type = 0;
1063 if (!e_cal_backend_contacts_type) {
1064 static GTypeInfo info = {
1065 sizeof (ECalBackendContactsClass),
1066 (GBaseInitFunc) NULL,
1067 (GBaseFinalizeFunc) NULL,
1068 (GClassInitFunc) e_cal_backend_contacts_class_init,
1070 sizeof (ECalBackendContacts),
1072 (GInstanceInitFunc) e_cal_backend_contacts_init
1074 e_cal_backend_contacts_type = g_type_register_static (E_TYPE_CAL_BACKEND_SYNC,
1075 "ECalBackendContacts", &info, 0);
1078 return e_cal_backend_contacts_type;