From 156e6359a64df7bd1e6bcf62dd5f208ea702afe9 Mon Sep 17 00:00:00 2001 From: =?utf8?q?=C3=89RDI=20Gergo?= Date: Fri, 9 Jan 2004 20:05:38 +0000 Subject: [PATCH] New calendar backend to show birthdays & anniversaries from the contact list --- ChangeLog | 8 + calendar/backends/Makefile.am | 2 +- calendar/backends/contacts/.cvsignore | 2 + calendar/backends/contacts/Makefile.am | 19 + .../backends/contacts/e-cal-backend-contacts.c | 833 +++++++++++++++++++++ .../backends/contacts/e-cal-backend-contacts.h | 62 ++ calendar/libecal/e-cal.c | 5 +- configure.in | 1 + libedataserver/e-source-group.c | 65 +- libedataserver/e-source-group.h | 4 + libedataserver/e-source.c | 40 +- libedataserver/e-source.h | 3 + po/ChangeLog | 4 + po/POTFILES.in | 1 + src/GNOME_Evolution_DataServerLDAP.server.in.in | 1 + src/GNOME_Evolution_DataServerNOLDAP.server.in.in | 1 + src/Makefile.am | 9 +- src/server.c | 2 + 18 files changed, 1052 insertions(+), 10 deletions(-) create mode 100644 calendar/backends/contacts/.cvsignore create mode 100644 calendar/backends/contacts/Makefile.am create mode 100644 calendar/backends/contacts/e-cal-backend-contacts.c create mode 100644 calendar/backends/contacts/e-cal-backend-contacts.h diff --git a/ChangeLog b/ChangeLog index 39e6d09..3f3efa8 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,11 @@ +2004-01-09 ERDI Gergo + + * libedataserver/e-source-group.h: added new read-only flag + + * src/contactdates-server.c: new factory for ContactDates backend + + * configure.in: Added new ContactDates calendar backend + 2004-01-09 Rodrigo Moya * libedataserver/e-source-list.[ch] diff --git a/calendar/backends/Makefile.am b/calendar/backends/Makefile.am index 4b92fa0..a5174ca 100644 --- a/calendar/backends/Makefile.am +++ b/calendar/backends/Makefile.am @@ -1 +1 @@ -SUBDIRS = file groupwise http +SUBDIRS = file groupwise http contacts diff --git a/calendar/backends/contacts/.cvsignore b/calendar/backends/contacts/.cvsignore new file mode 100644 index 0000000..c038ed7 --- /dev/null +++ b/calendar/backends/contacts/.cvsignore @@ -0,0 +1,2 @@ +Makefile +Makefile.in \ No newline at end of file diff --git a/calendar/backends/contacts/Makefile.am b/calendar/backends/contacts/Makefile.am new file mode 100644 index 0000000..717e64a --- /dev/null +++ b/calendar/backends/contacts/Makefile.am @@ -0,0 +1,19 @@ +INCLUDES = \ + -DG_LOG_DOMAIN=\"libecalbackendcontact\" \ + -I$(top_srcdir)/calendar \ + -I$(top_builddir)/calendar \ + -I$(top_srcdir)/calendar/libical/src \ + -I$(top_builddir)/calendar/libical/src \ + -I$(top_srcdir)/addressbook \ + -I$(top_builddir)/addressbook \ + $(EVOLUTION_CALENDAR_CFLAGS) + +noinst_LTLIBRARIES = libecalbackendcontacts.la + +libecalbackendcontacts_la_SOURCES = \ + e-cal-backend-contacts.c \ + e-cal-backend-contacts.h + +libecalbackendcontacts_la_LIBADD = \ + $(top_builddir)/calendar/libedata-cal/libedata-cal.la + diff --git a/calendar/backends/contacts/e-cal-backend-contacts.c b/calendar/backends/contacts/e-cal-backend-contacts.c new file mode 100644 index 0000000..1cb6770 --- /dev/null +++ b/calendar/backends/contacts/e-cal-backend-contacts.c @@ -0,0 +1,833 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ +/* Evolution calendar - iCalendar file backend + * + * Copyright (C) 2000-2003 Ximian, Inc. + * Copyright (C) 2003 Gergõ Érdi + * + * Authors: Federico Mena-Quintero + * Rodrigo Moya + * Gergõ Érdi + * + * 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. + */ + +#ifdef HAVE_CONFIG_H +#include +#endif +#include + +#include "e-cal-backend-contacts.h" + +#include +#include +#include +#include +#include + +#include + +#include + +static ECalBackendSyncClass *parent_class; + +/* Private part of the ECalBackendContacts structure */ +struct _ECalBackendContactsPrivate { + ESourceList *addressbook_sources; + + GHashTable *addressbooks; /* UID -> BookRecord */ + gboolean addressbook_loaded; + + EBookView *book_view; + GHashTable *tracked_contacts; /* UID -> ContactRecord */ + + icaltimezone *default_zone; +}; + +typedef struct _BookRecord { + EBook *book; + EBookView *book_view; +} BookRecord; + +typedef struct _ContactRecord { + ECalBackendContacts *cbc; + EContact *contact; + ECalComponent *comp_birthday, *comp_anniversary; +} ContactRecord; + +static ECalComponent * create_birthday (ECalBackendContacts *cbc, EContact *contact); +static ECalComponent * create_anniversary (ECalBackendContacts *cbc, EContact *contact); + +static void contacts_changed_cb (EBookView *book_view, const GList *contacts, gpointer user_data); +static void contacts_added_cb (EBookView *book_view, const GList *contacts, gpointer user_data); +static void contacts_removed_cb (EBookView *book_view, const GList *contact_ids, gpointer user_data); + +/* BookRecord methods */ +static BookRecord * +book_record_new (ECalBackendContacts *cbc, ESource *source) +{ + EBook *book = e_book_new (); + GList *fields = 0; + EBookQuery *query; + EBookView *book_view; + BookRecord *br; + + e_book_load_source (book, source, TRUE, NULL); + + /* Create book view */ + fields = g_list_append (fields, e_contact_field_name (E_CONTACT_FILE_AS)); + fields = g_list_append (fields, e_contact_field_name (E_CONTACT_BIRTH_DATE)); + fields = g_list_append (fields, e_contact_field_name (E_CONTACT_ANNIVERSARY)); + query = e_book_query_any_field_contains (""); + + if (!e_book_get_book_view (book, query, fields, -1, &book_view, NULL)) { + e_book_query_unref (query); + return NULL; + } + e_book_query_unref (query); + + g_signal_connect (book_view, "contacts_added", G_CALLBACK (contacts_added_cb), cbc); + g_signal_connect (book_view, "contacts_removed", G_CALLBACK (contacts_removed_cb), cbc); + g_signal_connect (book_view, "contacts_changed", G_CALLBACK (contacts_changed_cb), cbc); + + e_book_view_start (book_view); + + br = g_new (BookRecord, 1); + br->book = book; + br->book_view = book_view; + + return br; +} + +static void +book_record_free (BookRecord *br) +{ + if (!br) + return; + + g_object_unref (br->book_view); + g_object_unref (br->book); + + g_free (br); +} + +/* ContactRecord methods */ +static ContactRecord * +contact_record_new (ECalBackendContacts *cbc, EContact *contact) +{ + ContactRecord *cr = g_new0 (ContactRecord, 1); + char *comp_str; + + cr->cbc = cbc; + cr->contact = contact; + cr->comp_birthday = create_birthday (cbc, contact); + cr->comp_anniversary = create_anniversary (cbc, contact); + + comp_str = e_cal_component_get_as_string (cr->comp_birthday); + e_cal_backend_notify_object_created (E_CAL_BACKEND (cbc), + comp_str); + g_free (comp_str); + + comp_str = e_cal_component_get_as_string (cr->comp_anniversary); + e_cal_backend_notify_object_created (E_CAL_BACKEND (cbc), + comp_str); + g_free (comp_str); + + g_object_ref (G_OBJECT (contact)); + + return cr; +} + +static void +contact_record_free (ContactRecord *cr) +{ + char *comp_str; + const char *uid; + + g_object_unref (G_OBJECT (cr->contact)); + + /* Remove the birthday event */ + comp_str = e_cal_component_get_as_string (cr->comp_birthday); + e_cal_component_get_uid (cr->comp_birthday, &uid); + e_cal_backend_notify_object_removed (E_CAL_BACKEND (cr->cbc), uid, comp_str); + g_free (comp_str); + + /* Remove the anniversary event */ + comp_str = e_cal_component_get_as_string (cr->comp_anniversary); + e_cal_component_get_uid (cr->comp_anniversary, &uid); + e_cal_backend_notify_object_removed (E_CAL_BACKEND (cr->cbc), uid, comp_str); + g_free (comp_str); + + g_object_unref (G_OBJECT (cr->comp_birthday)); + g_object_unref (G_OBJECT (cr->comp_anniversary)); + + g_free (cr); +} + +/* ContactRecordCB methods */ +typedef struct _ContactRecordCB { + ECalBackendContacts *cbc; + ECalBackendSExp *sexp; + GList *result; +} ContactRecordCB; + +static ContactRecordCB * +contact_record_cb_new (ECalBackendContacts *cbc, ECalBackendSExp *sexp) +{ + ContactRecordCB *cb_data = g_new (ContactRecordCB, 1); + + cb_data->cbc = cbc; + cb_data->sexp = sexp; + cb_data->result = 0; + + return cb_data; +} + +static void +contact_record_cb_free (ContactRecordCB *cb_data) +{ + g_list_foreach (cb_data->result, (GFunc) g_free, 0); + g_list_free (cb_data->result); + + g_free (cb_data); +} + +static void +contact_record_cb (gpointer key, gpointer value, gpointer user_data) +{ + ContactRecordCB *cb_data = user_data; + ContactRecord *record = value; + + if (e_cal_backend_sexp_match_comp (cb_data->sexp, record->comp_birthday, E_CAL_BACKEND (cb_data->cbc))) { + char * comp_str = e_cal_component_get_as_string (record->comp_birthday); + cb_data->result = g_list_append (cb_data->result, comp_str); + } + + if (e_cal_backend_sexp_match_comp (cb_data->sexp, record->comp_anniversary, E_CAL_BACKEND (cb_data->cbc))) { + char * comp_str = e_cal_component_get_as_string (record->comp_anniversary); + cb_data->result = g_list_append (cb_data->result, comp_str); + } +} + +/* SourceList callbacks */ +static void +add_source (ECalBackendContacts *cbc, ESource *source) +{ + BookRecord *br = book_record_new (cbc, source); + const char *uid = e_source_peek_uid (source); + + g_hash_table_insert (cbc->priv->addressbooks, g_strdup (uid), br); +} + +static void +source_added_cb (ESourceGroup *group, ESource *source, gpointer user_data) +{ + ECalBackendContacts *cbc = E_CAL_BACKEND_CONTACTS (user_data); + + g_return_if_fail (cbc); + + add_source (cbc, source); +} + +static void +source_removed_cb (ESourceGroup *group, ESource *source, gpointer user_data) +{ + ECalBackendContacts *cbc = E_CAL_BACKEND_CONTACTS (user_data); + const char *uid = e_source_peek_uid (source); + + g_return_if_fail (cbc); + + g_hash_table_remove (cbc->priv->addressbooks, uid); +} + +static void +source_group_added_cb (ESourceList *source_list, ESourceGroup *group, gpointer user_data) +{ + ECalBackendContacts *cbc = E_CAL_BACKEND_CONTACTS (user_data); + GSList *i; + + g_return_if_fail (cbc); + + /* Load all address books from this group */ + for (i = e_source_group_peek_sources (group); i; i = i->next) + { + ESource *source = E_SOURCE (i->data); + add_source (cbc, source); + } + + /* Watch for future changes */ + g_signal_connect (group, "source_added", G_CALLBACK (source_added_cb), cbc); + g_signal_connect (group, "source_removed", G_CALLBACK (source_removed_cb), cbc); +} + +static void +source_group_removed_cb (ESourceList *source_list, ESourceGroup *group, gpointer user_data) +{ + ECalBackendContacts *cbc = E_CAL_BACKEND_CONTACTS (user_data); + GSList *i = 0; + + g_return_if_fail (cbc); + + /* Unload all address books from this group */ + for (i = e_source_group_peek_sources (group); i; i = i->next) + { + ESource *source = E_SOURCE (i->data); + const char *uid = e_source_peek_uid (source); + + g_hash_table_remove (cbc->priv->addressbooks, uid); + } +} + +/************************************************************************************/ + +static void +contacts_changed_cb (EBookView *book_view, const GList *contacts, gpointer user_data) +{ + ECalBackendContacts *cbc = E_CAL_BACKEND_CONTACTS (user_data); + const GList *i; + + for (i = contacts; i; i = i->next) + { + EContact *contact = E_CONTACT (i->data); + char *uid = e_contact_get_const (contact, E_CONTACT_UID); + + /* If no date is set, remove from list of tracked contacts */ + if (!e_contact_get (contact, E_CONTACT_BIRTH_DATE) && + !e_contact_get (contact, E_CONTACT_ANNIVERSARY)) { + g_hash_table_remove (cbc->priv->tracked_contacts, uid); + } else { + ContactRecord *cr = contact_record_new (cbc, contact); + g_hash_table_insert (cbc->priv->tracked_contacts, g_strdup (uid), cr); + } + } +} + +static void +contacts_added_cb (EBookView *book_view, const GList *contacts, gpointer user_data) +{ + ECalBackendContacts *cbc = E_CAL_BACKEND_CONTACTS (user_data); + const GList *i; + + /* See if any new contacts have BIRTHDAY or ANNIVERSARY fields */ + for (i = contacts; i; i = i->next) + { + EContact *contact = E_CONTACT (i->data); + + if (e_contact_get (contact, E_CONTACT_BIRTH_DATE) || + e_contact_get (contact, E_CONTACT_ANNIVERSARY)) { + ContactRecord *cr = contact_record_new (cbc, contact); + const char *uid = e_contact_get_const (contact, E_CONTACT_UID); + + g_hash_table_insert (cbc->priv->tracked_contacts, g_strdup (uid), cr); + } + } +} + +static void +contacts_removed_cb (EBookView *book_view, const GList *contact_ids, gpointer user_data) +{ + ECalBackendContacts *cbc = E_CAL_BACKEND_CONTACTS (user_data); + const GList *i; + + /* Stop tracking these */ + for (i = contact_ids; i; i = i->next) + g_hash_table_remove (cbc->priv->tracked_contacts, i->data); +} + +/************************************************************************************/ +static struct icaltimetype +cdate_to_icaltime (EContactDate *cdate) +{ + struct icaltimetype ret; + + ret.year = cdate->year; + ret.month = cdate->month; + ret.day = cdate->day; + ret.is_date = TRUE; + ret.zone = icaltimezone_get_utc_timezone (); + + ret.hour = ret.minute = ret.second = 0; + + return ret; +} + +/* Contact -> Event creator */ +static ECalComponent * +create_component (ECalBackendContacts *cbc, EContactDate *cdate, char *summary) +{ + ECalComponent *cal_comp; + ECalComponentText comp_summary; + icalcomponent *ical_comp; + struct icaltimetype itt; + ECalComponentDateTime dt; + struct icalrecurrencetype r; + GSList recur_list; + + g_return_val_if_fail (E_IS_CAL_BACKEND_CONTACTS (cbc), 0); + + if (!cdate) + return NULL; + + ical_comp = icalcomponent_new (ICAL_VEVENT_COMPONENT); + + /* Create the event object */ + cal_comp = e_cal_component_new (); + e_cal_component_gen_uid (); + e_cal_component_set_icalcomponent (cal_comp, ical_comp); + + /* Set all-day event's date from contact data */ + itt = cdate_to_icaltime (cdate); + dt.value = &itt; + dt.tzid = 0; + e_cal_component_set_dtstart (cal_comp, &dt); + + /* Create yearly recurrence */ + icalrecurrencetype_clear (&r); + r.freq = ICAL_YEARLY_RECURRENCE; + r.interval = 1; + recur_list.data = &r; + recur_list.next = 0; + e_cal_component_set_rrule_list (cal_comp, &recur_list); + + /* Create summary */ + comp_summary.value = summary; + comp_summary.altrep = 0; + e_cal_component_set_summary (cal_comp, &comp_summary); + + /* Set category and visibility */ + e_cal_component_set_categories (cal_comp, _("Birthday")); + e_cal_component_set_classification (cal_comp, E_CAL_COMPONENT_CLASS_PRIVATE); + + /* Birthdays/anniversaries are shown as free time */ + e_cal_component_set_transparency (cal_comp, E_CAL_COMPONENT_TRANSP_TRANSPARENT); + + /* Don't forget to call commit()! */ + e_cal_component_commit_sequence (cal_comp); + + return cal_comp; +} + +static ECalComponent * +create_birthday (ECalBackendContacts *cbc, EContact *contact) +{ + EContactDate *cdate; + ECalComponent *cal_comp; + char *summary; + const char *name; + + cdate = e_contact_get (contact, E_CONTACT_BIRTH_DATE); + name = e_contact_get_const (contact, E_CONTACT_FILE_AS); + summary = g_strdup_printf (_("Birthday: %s"), name); + + cal_comp = create_component (cbc, cdate, summary); + + g_free (summary); + + return cal_comp; +} + +static ECalComponent * +create_anniversary (ECalBackendContacts *cbc, EContact *contact) +{ + EContactDate *cdate; + ECalComponent *cal_comp; + char *summary; + const char *name; + + cdate = e_contact_get (contact, E_CONTACT_ANNIVERSARY); + name = e_contact_get_const (contact, E_CONTACT_FILE_AS); + summary = g_strdup_printf (_("Anniversary: %s"), name); + + cal_comp = create_component (cbc, cdate, summary); + + g_free (summary); + + return cal_comp; +} + +/************************************************************************************/ +/* Calendar backend method implementations */ + +/* First the empty stubs */ + +static ECalBackendSyncStatus +e_cal_backend_contacts_get_cal_address (ECalBackendSync *backend, EDataCal *cal, + char **address) +{ + /* WRITE ME */ + return GNOME_Evolution_Calendar_Success; +} + +static ECalBackendSyncStatus +e_cal_backend_contacts_get_ldap_attribute (ECalBackendSync *backend, EDataCal *cal, + char **attribute) +{ + /* WRITE ME */ + return GNOME_Evolution_Calendar_Success; +} + +static ECalBackendSyncStatus +e_cal_backend_contacts_get_alarm_email_address (ECalBackendSync *backend, EDataCal *cal, + char **address) +{ + /* WRITE ME */ + return GNOME_Evolution_Calendar_Success; +} + +static ECalBackendSyncStatus +e_cal_backend_contacts_get_static_capabilities (ECalBackendSync *backend, EDataCal *cal, + char **capabilities) +{ + /* WRITE ME */ + return GNOME_Evolution_Calendar_Success; +} + +static ECalBackendSyncStatus +e_cal_backend_contacts_remove (ECalBackendSync *backend, EDataCal *cal) +{ + /* WRITE ME */ + return GNOME_Evolution_Calendar_Success; +} + +static ECalBackendSyncStatus +e_cal_backend_contacts_get_default_object (ECalBackendSync *backend, EDataCal *cal, + char **object) +{ + return GNOME_Evolution_Calendar_UnsupportedMethod; +} + +static ECalBackendSyncStatus +e_cal_backend_contacts_get_object (ECalBackendSync *backend, EDataCal *cal, + const char *uid, const char *rid, + char **object) +{ + /* WRITE ME */ + return GNOME_Evolution_Calendar_Success; +} + +static ECalBackendSyncStatus +e_cal_backend_contacts_get_free_busy (ECalBackendSync *backend, EDataCal *cal, + GList *users, time_t start, time_t end, + GList **freebusy) +{ + /* Birthdays/anniversaries don't count as busy time */ + + icalcomponent *vfb = icalcomponent_new_vfreebusy (); + icaltimezone *utc_zone = icaltimezone_get_utc_timezone (); + char *calobj; + +#if 0 + icalproperty *prop; + icalparameter *param; + + prop = icalproperty_new_organizer (address); + if (prop != NULL && cn != NULL) { + param = icalparameter_new_cn (cn); + icalproperty_add_parameter (prop, param); + } + if (prop != NULL) + icalcomponent_add_property (vfb, prop); +#endif + + icalcomponent_set_dtstart (vfb, icaltime_from_timet_with_zone (start, FALSE, utc_zone)); + icalcomponent_set_dtend (vfb, icaltime_from_timet_with_zone (end, FALSE, utc_zone)); + + calobj = icalcomponent_as_ical_string (vfb); + *freebusy = g_list_append (NULL, g_strdup (calobj)); + icalcomponent_free (vfb); + + /* WRITE ME */ + return GNOME_Evolution_Calendar_Success; +} + +static ECalBackendSyncStatus +e_cal_backend_contacts_get_changes (ECalBackendSync *backend, EDataCal *cal, + const char *change_id, + GList **adds, GList **modifies, GList **deletes) +{ + /* WRITE ME */ + return GNOME_Evolution_Calendar_Success; +} + +static ECalBackendSyncStatus +e_cal_backend_contacts_discard_alarm (ECalBackendSync *backend, EDataCal *cal, + const char *uid, const char *auid) +{ + /* WRITE ME */ + return GNOME_Evolution_Calendar_Success; +} + +static ECalBackendSyncStatus +e_cal_backend_contacts_receive_objects (ECalBackendSync *backend, EDataCal *cal, + const char *calobj) +{ + return GNOME_Evolution_Calendar_UnsupportedMethod; +} + +static ECalBackendSyncStatus +e_cal_backend_contacts_send_objects (ECalBackendSync *backend, EDataCal *cal, + const char *calobj) +{ + /* TODO: Investigate this */ + return GNOME_Evolution_Calendar_Success; +} + +/* Then the real implementations */ + +static CalMode +e_cal_backend_contacts_get_mode (ECalBackend *backend) +{ + return CAL_MODE_LOCAL; +} + +static void +e_cal_backend_contacts_set_mode (ECalBackend *backend, CalMode mode) +{ + e_cal_backend_notify_mode (backend, + GNOME_Evolution_Calendar_CalListener_MODE_NOT_SUPPORTED, + GNOME_Evolution_Calendar_MODE_LOCAL); + +} + +static ECalBackendSyncStatus +e_cal_backend_contacts_is_read_only (ECalBackendSync *backend, EDataCal *cal, + gboolean *read_only) +{ + *read_only = TRUE; + + return GNOME_Evolution_Calendar_Success; +} + +static ECalBackendSyncStatus +e_cal_backend_contacts_open (ECalBackendSync *backend, EDataCal *cal, + gboolean only_if_exists, + const char *username, const char *password) +{ + ECalBackendContacts *cbc = E_CAL_BACKEND_CONTACTS (backend); + ECalBackendContactsPrivate *priv = cbc->priv; + + GSList *i; + + if (priv->addressbook_loaded) + return GNOME_Evolution_Calendar_Success; + + /* Create address books for existing sources */ + for (i = e_source_list_peek_groups (priv->addressbook_sources); i; i = i->next) + { + ESourceGroup *source_group = E_SOURCE_GROUP (i->data); + + source_group_added_cb (priv->addressbook_sources, source_group, cbc); + } + + /* Listen for source list changes */ + g_signal_connect (priv->addressbook_sources, "group_added", G_CALLBACK (source_group_added_cb), cbc); + g_signal_connect (priv->addressbook_sources, "group_removed", G_CALLBACK (source_group_removed_cb), cbc); + + priv->addressbook_loaded = TRUE; + return GNOME_Evolution_Calendar_Success; +} + +static gboolean +e_cal_backend_contacts_is_loaded (ECalBackend *backend) +{ + ECalBackendContacts *cbc = E_CAL_BACKEND_CONTACTS (backend); + ECalBackendContactsPrivate *priv = cbc->priv; + + return priv->addressbook_loaded; +} + +static ECalBackendSyncStatus +e_cal_backend_contacts_get_object_list (ECalBackendSync *backend, EDataCal *cal, + const char *sexp_string, GList **objects) +{ + ECalBackendContacts *cbc = E_CAL_BACKEND_CONTACTS (backend); + ECalBackendContactsPrivate *priv = cbc->priv; + ECalBackendSExp *sexp = e_cal_backend_sexp_new (sexp_string); + ContactRecordCB *cb_data; + + if (!sexp) + return GNOME_Evolution_Calendar_InvalidQuery; + + cb_data = contact_record_cb_new (cbc, sexp); + g_hash_table_foreach (priv->tracked_contacts, contact_record_cb, cb_data); + *objects = cb_data->result; + + /* Don't call cb_data_free as that would destroy the results + * in *objects */ + g_free (cb_data); + + return GNOME_Evolution_Calendar_Success; +} + +static void +e_cal_backend_contacts_start_query (ECalBackend *backend, EDataCalView *query) +{ + ECalBackendContacts *cbc = E_CAL_BACKEND_CONTACTS (backend); + ECalBackendContactsPrivate *priv = cbc->priv; + ECalBackendSExp *sexp; + ContactRecordCB *cb_data; + + sexp = e_data_cal_view_get_object_sexp (query); + if (!sexp) { + e_data_cal_view_notify_done (query, GNOME_Evolution_Calendar_InvalidQuery); + return; + } + + cb_data = contact_record_cb_new (cbc, sexp); + + g_hash_table_foreach (priv->tracked_contacts, contact_record_cb, cb_data); + e_data_cal_view_notify_objects_added (query, cb_data->result); + + contact_record_cb_free (cb_data); + + e_data_cal_view_notify_done (query, GNOME_Evolution_Calendar_Success); +} + +static icaltimezone * +e_cal_backend_contacts_internal_get_default_timezone (ECalBackend *backend) +{ + ECalBackendContacts *cbc = E_CAL_BACKEND_CONTACTS (backend); + + return cbc->priv->default_zone; +} + +static icaltimezone * +e_cal_backend_contacts_internal_get_timezone (ECalBackend *backend, const char *tzid) +{ + ECalBackendContacts *cbc = E_CAL_BACKEND_CONTACTS (backend); + + return cbc->priv->default_zone; +} + +/*********************************************************************************** + */ + +/* Finalize handler for the contacts backend */ +static void +e_cal_backend_contacts_finalize (GObject *object) +{ + ECalBackendContacts *cbc; + ECalBackendContactsPrivate *priv; + + g_return_if_fail (object != NULL); + g_return_if_fail (E_IS_CAL_BACKEND_CONTACTS (object)); + + cbc = E_CAL_BACKEND_CONTACTS (object); + priv = cbc->priv; + + g_hash_table_destroy (priv->tracked_contacts); + + g_free (priv); + cbc->priv = NULL; + + if (G_OBJECT_CLASS (parent_class)->finalize) + (* G_OBJECT_CLASS (parent_class)->finalize) (object); +} + +/* Object initialization function for the contacts backend */ +static void +e_cal_backend_contacts_init (ECalBackendContacts *cbc, ECalBackendContactsClass *class) +{ + ECalBackendContactsPrivate *priv; + GConfClient *gconf_client; + + priv = g_new0 (ECalBackendContactsPrivate, 1); + + gconf_client = gconf_client_get_default (); + priv->addressbook_sources = e_source_list_new_for_gconf ( + gconf_client, "/apps/evolution/addressbook/sources"); + + priv->addressbooks = g_hash_table_new_full (g_str_hash, g_str_equal, + g_free, (GDestroyNotify)book_record_free); + priv->tracked_contacts = g_hash_table_new_full (g_str_hash, g_str_equal, + g_free, (GDestroyNotify)contact_record_free); + + priv->default_zone = icaltimezone_get_utc_timezone (); + + cbc->priv = priv; +} + +/* Class initialization function for the contacts backend */ +static void +e_cal_backend_contacts_class_init (ECalBackendContactsClass *class) +{ + GObjectClass *object_class; + ECalBackendClass *backend_class; + ECalBackendSyncClass *sync_class; + + object_class = (GObjectClass *) class; + backend_class = (ECalBackendClass *) class; + sync_class = (ECalBackendSyncClass *) class; + + parent_class = (ECalBackendSyncClass *) g_type_class_peek_parent (class); + + object_class->finalize = e_cal_backend_contacts_finalize; + + sync_class->is_read_only_sync = e_cal_backend_contacts_is_read_only; + sync_class->get_cal_address_sync = e_cal_backend_contacts_get_cal_address; + sync_class->get_alarm_email_address_sync = e_cal_backend_contacts_get_alarm_email_address; + sync_class->get_ldap_attribute_sync = e_cal_backend_contacts_get_ldap_attribute; + sync_class->get_static_capabilities_sync = e_cal_backend_contacts_get_static_capabilities; + sync_class->open_sync = e_cal_backend_contacts_open; + sync_class->remove_sync = e_cal_backend_contacts_remove; + sync_class->discard_alarm_sync = e_cal_backend_contacts_discard_alarm; + sync_class->receive_objects_sync = e_cal_backend_contacts_receive_objects; + sync_class->send_objects_sync = e_cal_backend_contacts_send_objects; + sync_class->get_default_object_sync = e_cal_backend_contacts_get_default_object; + sync_class->get_object_sync = e_cal_backend_contacts_get_object; + sync_class->get_object_list_sync = e_cal_backend_contacts_get_object_list; + sync_class->get_freebusy_sync = e_cal_backend_contacts_get_free_busy; + sync_class->get_changes_sync = e_cal_backend_contacts_get_changes; + backend_class->is_loaded = e_cal_backend_contacts_is_loaded; + backend_class->start_query = e_cal_backend_contacts_start_query; + backend_class->get_mode = e_cal_backend_contacts_get_mode; + backend_class->set_mode = e_cal_backend_contacts_set_mode; + + backend_class->internal_get_default_timezone = e_cal_backend_contacts_internal_get_default_timezone; + backend_class->internal_get_timezone = e_cal_backend_contacts_internal_get_timezone; +} + + +/** + * e_cal_backend_contacts_get_type: + * @void: + * + * Registers the #ECalBackendContacts class if necessary, and returns + * the type ID associated to it. + * + * Return value: The type ID of the #ECalBackendContacts class. + **/ +GType +e_cal_backend_contacts_get_type (void) +{ + static GType e_cal_backend_contacts_type = 0; + + fprintf (stderr, "e_cal_backend_contacts_get_type ()\n"); + + if (!e_cal_backend_contacts_type) { + static GTypeInfo info = { + sizeof (ECalBackendContactsClass), + (GBaseInitFunc) NULL, + (GBaseFinalizeFunc) NULL, + (GClassInitFunc) e_cal_backend_contacts_class_init, + NULL, NULL, + sizeof (ECalBackendContacts), + 0, + (GInstanceInitFunc) e_cal_backend_contacts_init + }; + e_cal_backend_contacts_type = g_type_register_static (E_TYPE_CAL_BACKEND_SYNC, + "ECalBackendContacts", &info, 0); + } + + return e_cal_backend_contacts_type; +} diff --git a/calendar/backends/contacts/e-cal-backend-contacts.h b/calendar/backends/contacts/e-cal-backend-contacts.h new file mode 100644 index 0000000..8d5092e --- /dev/null +++ b/calendar/backends/contacts/e-cal-backend-contacts.h @@ -0,0 +1,62 @@ +/* Evolution calendar - iCalendar file backend + * + * Copyright (C) 2000 Ximian, Inc. + * Copyright (C) 2003 Gergõ Érdi + * + * Authors: Federico Mena-Quintero , + * Gergõ Érdi + * + * 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_CAL_BACKEND_CONTACTS_H +#define E_CAL_BACKEND_CONTACTS_H + +#include + +G_BEGIN_DECLS + + + +#define E_TYPE_CAL_BACKEND_CONTACTS (e_cal_backend_contacts_get_type ()) +#define E_CAL_BACKEND_CONTACTS(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), E_TYPE_CAL_BACKEND_CONTACTS, \ + ECalBackendContacts)) +#define E_CAL_BACKEND_CONTACTS_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), E_TYPE_CAL_BACKEND_CONTACTS, \ + ECalBackendContactsClass)) +#define E_IS_CAL_BACKEND_CONTACTS(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), E_TYPE_CAL_BACKEND_CONTACTS)) +#define E_IS_CAL_BACKEND_CONTACTS_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), E_TYPE_CAL_BACKEND_CONTACTS)) + +typedef struct _ECalBackendContacts ECalBackendContacts; +typedef struct _ECalBackendContactsClass ECalBackendContactsClass; + +typedef struct _ECalBackendContactsPrivate ECalBackendContactsPrivate; + +struct _ECalBackendContacts { + ECalBackendSync backend; + + /* Private data */ + ECalBackendContactsPrivate *priv; +}; + +struct _ECalBackendContactsClass { + ECalBackendSyncClass parent_class; +}; + +GType e_cal_backend_contacts_get_type (void); + + + +G_END_DECLS + +#endif diff --git a/calendar/libecal/e-cal.c b/calendar/libecal/e-cal.c index 87334a4..32fd6c6 100644 --- a/calendar/libecal/e-cal.c +++ b/calendar/libecal/e-cal.c @@ -2157,7 +2157,10 @@ e_cal_get_default_object (ECal *ecal, icalcomponent **icalcomp, GError **error) g_cond_wait (our_op->cond, our_op->mutex); status = our_op->status; - *icalcomp = icalparser_parse_string (our_op->string); + if (status) + *icalcomp = NULL; + else + *icalcomp = icalparser_parse_string (our_op->string); g_free (our_op->string); e_calendar_remove_op (ecal, our_op); diff --git a/configure.in b/configure.in index 8001dbe..bac35c3 100644 --- a/configure.in +++ b/configure.in @@ -300,6 +300,7 @@ calendar/backends/Makefile calendar/backends/file/Makefile calendar/backends/groupwise/Makefile calendar/backends/http/Makefile +calendar/backends/contacts/Makefile libdb/Makefile libedataserver/Makefile libedataserver/libedataserver-1.0.pc diff --git a/libedataserver/e-source-group.c b/libedataserver/e-source-group.c index 3789d5b..f7b2828 100644 --- a/libedataserver/e-source-group.c +++ b/libedataserver/e-source-group.c @@ -41,6 +41,7 @@ struct _ESourceGroupPrivate { GSList *sources; gboolean ignore_source_changed; + gboolean readonly; }; @@ -221,6 +222,7 @@ e_source_group_new_from_xmldoc (xmlDocPtr doc) xmlChar *uid; xmlChar *name; xmlChar *base_uri; + xmlChar *readonly_str; ESourceGroup *new = NULL; g_return_val_if_fail (doc != NULL, NULL); @@ -232,6 +234,7 @@ e_source_group_new_from_xmldoc (xmlDocPtr doc) uid = xmlGetProp (root, "uid"); name = xmlGetProp (root, "name"); base_uri = xmlGetProp (root, "base_uri"); + readonly_str = xmlGetProp (root, "readonly"); if (uid == NULL || name == NULL || base_uri == NULL) goto done; @@ -241,17 +244,21 @@ e_source_group_new_from_xmldoc (xmlDocPtr doc) e_source_group_set_name (new, name); e_source_group_set_base_uri (new, base_uri); - + for (p = root->children; p != NULL; p = p->next) { ESource *new_source = e_source_new_from_xml_node (p); e_source_group_add_source (new, new_source, -1); } + e_source_group_set_readonly (new, readonly_str && !strcmp (readonly_str, "yes")); + done: if (name != NULL) xmlFree (name); if (base_uri != NULL) xmlFree (base_uri); + if (readonly_str != NULL) + xmlFree (readonly_str); return new; } @@ -283,7 +290,8 @@ e_source_group_update_from_xmldoc (ESourceGroup *group, GHashTable *new_sources_hash; GSList *new_sources_list = NULL; xmlNodePtr root, nodep; - xmlChar *name, *base_uri; + xmlChar *name, *base_uri, *readonly_str; + gboolean readonly; gboolean changed = FALSE; GSList *p, *q; @@ -320,6 +328,14 @@ e_source_group_update_from_xmldoc (ESourceGroup *group, } xmlFree (base_uri); + readonly_str = xmlGetProp (root, "readonly"); + readonly = readonly_str && !strcmp (readonly_str, "yes"); + if (readonly != group->priv->readonly) { + group->priv->readonly = readonly; + changed = TRUE; + } + xmlFree (readonly_str); + new_sources_hash = g_hash_table_new (g_direct_hash, g_direct_equal); for (nodep = root->children; nodep != NULL; nodep = nodep->next) { @@ -431,6 +447,9 @@ e_source_group_set_name (ESourceGroup *group, { g_return_if_fail (E_IS_SOURCE_GROUP (group)); g_return_if_fail (name != NULL); + + if (group->priv->readonly) + return; if (group->priv->name == name) return; @@ -447,6 +466,9 @@ void e_source_group_set_base_uri (ESourceGroup *group, g_return_if_fail (E_IS_SOURCE_GROUP (group)); g_return_if_fail (base_uri != NULL); + if (group->priv->readonly) + return; + if (group->priv->base_uri == base_uri) return; @@ -456,6 +478,25 @@ void e_source_group_set_base_uri (ESourceGroup *group, g_signal_emit (group, signals[CHANGED], 0); } +void e_source_group_set_readonly (ESourceGroup *group, + gboolean readonly) +{ + GSList *i; + + g_return_if_fail (E_IS_SOURCE_GROUP (group)); + + if (group->priv->readonly) + return; + + if (group->priv->readonly == readonly) + return; + + group->priv->readonly = readonly; + for (i = group->priv->sources; i != NULL; i = i->next) + e_source_set_readonly (E_SOURCE (i->data), readonly); + + g_signal_emit (group, signals[CHANGED], 0); +} const char * e_source_group_peek_uid (ESourceGroup *group) @@ -481,6 +522,13 @@ e_source_group_peek_base_uri (ESourceGroup *group) return group->priv->base_uri; } +gboolean +e_source_group_get_readonly (ESourceGroup *group) +{ + g_return_val_if_fail (E_IS_SOURCE_GROUP (group), FALSE); + + return group->priv->readonly; +} GSList * e_source_group_peek_sources (ESourceGroup *group) @@ -525,10 +573,14 @@ e_source_group_add_source (ESourceGroup *group, { g_return_val_if_fail (E_IS_SOURCE_GROUP (group), FALSE); + if (group->priv->readonly) + return FALSE; + if (e_source_group_peek_source_by_uid (group, e_source_peek_uid (source)) != NULL) return FALSE; e_source_set_group (source, group); + e_source_set_readonly (source, group->priv->readonly); g_object_ref (source); g_signal_connect (source, "changed", G_CALLBACK (source_changed_callback), group); @@ -549,6 +601,9 @@ e_source_group_remove_source (ESourceGroup *group, g_return_val_if_fail (E_IS_SOURCE_GROUP (group), FALSE); g_return_val_if_fail (E_IS_SOURCE (source), FALSE); + if (group->priv->readonly) + return FALSE; + for (p = group->priv->sources; p != NULL; p = p->next) { if (E_SOURCE (p->data) == source) { group->priv->sources = g_slist_remove_link (group->priv->sources, p); @@ -570,6 +625,9 @@ e_source_group_remove_source_by_uid (ESourceGroup *group, g_return_val_if_fail (E_IS_SOURCE_GROUP (group), FALSE); g_return_val_if_fail (uid != NULL, FALSE); + if (group->priv->readonly) + return FALSE; + for (p = group->priv->sources; p != NULL; p = p->next) { ESource *source = E_SOURCE (p->data); @@ -601,7 +659,8 @@ e_source_group_to_xml (ESourceGroup *group) xmlSetProp (root, "uid", e_source_group_peek_uid (group)); xmlSetProp (root, "name", e_source_group_peek_name (group)); xmlSetProp (root, "base_uri", e_source_group_peek_base_uri (group)); - + xmlSetProp (root, "readonly", group->priv->readonly ? "yes" : "no"); + xmlDocSetRootElement (doc, root); for (p = group->priv->sources; p != NULL; p = p->next) diff --git a/libedataserver/e-source-group.h b/libedataserver/e-source-group.h index bebecba..35c8e3a 100644 --- a/libedataserver/e-source-group.h +++ b/libedataserver/e-source-group.h @@ -78,9 +78,13 @@ void e_source_group_set_name (ESourceGroup *group, void e_source_group_set_base_uri (ESourceGroup *group, const char *base_uri); +void e_source_group_set_readonly (ESourceGroup *group, + gboolean readonly); + const char *e_source_group_peek_uid (ESourceGroup *group); const char *e_source_group_peek_name (ESourceGroup *group); const char *e_source_group_peek_base_uri (ESourceGroup *group); +gboolean e_source_group_get_readonly (ESourceGroup *group); GSList *e_source_group_peek_sources (ESourceGroup *group); ESource *e_source_group_peek_source_by_uid (ESourceGroup *group, diff --git a/libedataserver/e-source.c b/libedataserver/e-source.c index e419470..5fb821c 100644 --- a/libedataserver/e-source.c +++ b/libedataserver/e-source.c @@ -48,6 +48,8 @@ struct _ESourcePrivate { char *relative_uri; char *absolute_uri; + gboolean readonly; + gboolean has_color; guint32 color; @@ -414,6 +416,9 @@ e_source_set_group (ESource *source, g_return_if_fail (E_IS_SOURCE (source)); g_return_if_fail (group == NULL || E_IS_SOURCE_GROUP (group)); + if (source->priv->readonly) + return; + if (source->priv->group == group) return; @@ -439,6 +444,9 @@ e_source_set_name (ESource *source, { g_return_if_fail (E_IS_SOURCE (source)); + if (source->priv->readonly) + return; + if (source->priv->name == name) return; @@ -454,6 +462,9 @@ e_source_set_relative_uri (ESource *source, { g_return_if_fail (E_IS_SOURCE (source)); + if (source->priv->readonly) + return; + if (source->priv->relative_uri == relative_uri) return; @@ -464,11 +475,29 @@ e_source_set_relative_uri (ESource *source, } void +e_source_set_readonly (ESource *source, + gboolean readonly) +{ + g_return_if_fail (E_IS_SOURCE (source)); + + if (source->priv->readonly == readonly) + return; + + source->priv->readonly = readonly; + + g_signal_emit (source, signals[CHANGED], 0); + +} + +void e_source_set_color (ESource *source, guint32 color) { g_return_if_fail (E_IS_SOURCE (source)); + if (source->priv->readonly) + return; + if (source->priv->has_color && source->priv->color == color) return; @@ -523,6 +552,15 @@ e_source_peek_relative_uri (ESource *source) return source->priv->relative_uri; } +gboolean +e_source_get_readonly (ESource *source) +{ + g_return_val_if_fail (E_IS_SOURCE (source), FALSE); + + return source->priv->readonly; +} + + /** * e_source_get_color: * @source: An ESource @@ -596,7 +634,7 @@ dump_common_to_xml_node (ESource *source, xmlSetProp (node, "uid", e_source_peek_uid (source)); xmlSetProp (node, "name", e_source_peek_name (source)); xmlSetProp (node, "relative_uri", e_source_peek_relative_uri (source)); - + has_color = e_source_get_color (source, &color); if (has_color) { char *color_string = g_strdup_printf (COLOR_FORMAT_STRING, color); diff --git a/libedataserver/e-source.h b/libedataserver/e-source.h index 1a8f408..4b5eef9 100644 --- a/libedataserver/e-source.h +++ b/libedataserver/e-source.h @@ -76,6 +76,8 @@ void e_source_set_name (ESource *source, const char *name); void e_source_set_relative_uri (ESource *source, const char *relative_uri); +void e_source_set_readonly (ESource *source, + gboolean readonly); void e_source_set_color (ESource *source, guint32 color); void e_source_unset_color (ESource *source); @@ -84,6 +86,7 @@ ESourceGroup *e_source_peek_group (ESource *source); const char *e_source_peek_uid (ESource *source); const char *e_source_peek_name (ESource *source); const char *e_source_peek_relative_uri (ESource *source); +gboolean e_source_get_readonly (ESource *source); gboolean e_source_get_color (ESource *source, guint32 *color_return); diff --git a/po/ChangeLog b/po/ChangeLog index a36a249..5e205f3 100644 --- a/po/ChangeLog +++ b/po/ChangeLog @@ -62,6 +62,10 @@ * it.po: updated italian translation +2003-12-08 ERDI Gergo + + * POTFILES.in: Added ContactDates backend source + 2003-11-19 Marco Ciampa * it.po: updated italian translation diff --git a/po/POTFILES.in b/po/POTFILES.in index a7d119c..83bc9dd 100644 --- a/po/POTFILES.in +++ b/po/POTFILES.in @@ -11,6 +11,7 @@ calendar/libecal/e-cal-util.c calendar/libecal/e-cal.c calendar/libedata-cal/e-cal-backend-sexp.c calendar/backends/file/e-cal-backend-file.c +calendar/backends/contacts/e-cal-backend-contacts.c calendar/backends/http/e-cal-backend-http.c src/GNOME_Evolution_DataServerLDAP.server.in.in src/GNOME_Evolution_DataServerNOLDAP.server.in.in diff --git a/src/GNOME_Evolution_DataServerLDAP.server.in.in b/src/GNOME_Evolution_DataServerLDAP.server.in.in index 190a1fe..d5e89d5 100644 --- a/src/GNOME_Evolution_DataServerLDAP.server.in.in +++ b/src/GNOME_Evolution_DataServerLDAP.server.in.in @@ -35,6 +35,7 @@ + diff --git a/src/GNOME_Evolution_DataServerNOLDAP.server.in.in b/src/GNOME_Evolution_DataServerNOLDAP.server.in.in index d5f4092..6a65c06 100644 --- a/src/GNOME_Evolution_DataServerNOLDAP.server.in.in +++ b/src/GNOME_Evolution_DataServerNOLDAP.server.in.in @@ -34,6 +34,7 @@ + diff --git a/src/Makefile.am b/src/Makefile.am index ad0797b..3cbcaeb 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -34,7 +34,7 @@ $(IDL_GENERATED_H): $(IDLS) $(IDL_GENERATED_C): $(IDL_GENERATED_H) -noinst_PROGRAMS = \ +noinst_PROGRAMS = \ evolution-data-server evolution_data_server_SOURCES = \ @@ -60,14 +60,15 @@ evolution_data_server_LDADD = \ $(top_builddir)/calendar/backends/file/libecalbackendfile.la \ $(top_builddir)/calendar/backends/groupwise/libecalbackendgroupwise.la \ $(top_builddir)/calendar/backends/http/libecalbackendhttp.la \ + $(top_builddir)/addressbook/libebook/libebook.la \ + $(top_builddir)/calendar/backends/contacts/libecalbackendcontacts.la \ $(LDAP_LIBS) \ $(E_DATA_SERVER_LIBS) -install-evolution-data-server: +install-evolution-data-servers: $(mkinstalldirs) $(DESTDIR)$(libexecdir) $(LIBTOOL) --mode=install $(INSTALL_PROGRAM) evolution-data-server $(DESTDIR)$(libexecdir)/evolution-data-server-$(BASE_VERSION) - if ENABLE_LDAP SERVER_IN_FILE=GNOME_Evolution_DataServerLDAP.server.in.in else @@ -94,7 +95,7 @@ EXTRA_DIST = \ BUILT_SOURCES = $(IDL_GENERATED) $(server_DATA) CLEANFILES = $(BUILT_SOURCES) -install-exec-local: install-evolution-data-server +install-exec-local: install-evolution-data-servers dist-hook: cd $(distdir); rm -f $(BUILT_SOURCES) diff --git a/src/server.c b/src/server.c index ba408fe..da37d13 100644 --- a/src/server.c +++ b/src/server.c @@ -54,6 +54,7 @@ #include #include #include +#include #include "server-interface-check.h" #include "server-logging.h" @@ -182,6 +183,7 @@ setup_cals (void) e_data_cal_factory_register_method (e_data_cal_factory, "groupwise", ICAL_VEVENT_COMPONENT, E_TYPE_CAL_BACKEND_GROUPWISE); e_data_cal_factory_register_method (e_data_cal_factory, "groupwise", ICAL_VTODO_COMPONENT, E_TYPE_CAL_BACKEND_GROUPWISE); e_data_cal_factory_register_method (e_data_cal_factory, "webcal", ICAL_VEVENT_COMPONENT, E_TYPE_CAL_BACKEND_HTTP); + e_data_cal_factory_register_method (e_data_cal_factory, "contacts", ICAL_VEVENT_COMPONENT, E_TYPE_CAL_BACKEND_CONTACTS); if (!e_data_cal_factory_register_storage (e_data_cal_factory, E_DATA_CAL_FACTORY_OAF_ID)) { bonobo_object_unref (BONOBO_OBJECT (e_data_cal_factory)); -- 2.7.4