Re: [evolution-patches] Birthday/Anniversary calendar backend



On Fri, 9 Jan 2004, JP Rosevear wrote:

> 1. You didn't patch configure.in's AC_OUTPUT in e-d-s.

I did, just forgot to include it in the patch :)

> 2. The migration code seems to be #ifdef'ed out
> 4. The comp-util change is gratuitous (and does follow the style
> anyhow)
> 6. Dump the warnings in the goto dialog
> 7. Why did you add the runtime check in comp-editor-factory.c?

these are just cruft that I haven't yet removed, I inserted these when I
was poking around in the code for the first time.


> 3. It should upgrade if the minor version is less than 2, not 3 (1.5.2
> will be the next release).

good point.

> 5. When bailing out of request new item, you should probably throw up a
> dialog telling the user the calendar is read only.  Actually we should
> handle this better in the gui since we have the selector to select
> calendars in the editor now.

The backend tells the GUI it's readonly, it shouldn't show any dialogs by
itself (that woudl have to be duplicated in every readonly backend). The
GUI should be more intelligent.

I am *attaching* a new version of the patch:)

-- 
   .--= ULLA! =---------------------.   `We are not here to give users what
   \     http://cactus.rulez.org     \   they want'  -- RMS, at GUADEC 2001
    `---= cactus cactus rulez org =---'
I'm a qmail admin. I sleep at night. (seen on /.)
? evolution-data-server/calendar/config.guess
? evolution-data-server/calendar/config.sub
? evolution-data-server/calendar/install-sh
? evolution-data-server/calendar/ltmain.sh
? evolution-data-server/calendar/missing
? evolution-data-server/calendar/mkinstalldirs
? evolution-data-server/calendar/backends/contacts.2
? evolution-data-server/calendar/backends/contacts/e-cal-backend-contacts-stub.c
? evolution-data-server/calendar/backends/groupwise/create-account
? evolution-data-server/calendar/backends/groupwise/soap-test
? evolution-data-server/calendar/libical/src/libicalss/icalsslexer.c
? evolution-data-server/calendar/libical/src/libicalss/icalssyacc.c
? evolution-data-server/calendar/libical/src/libicalss/y.output
? evolution-data-server/calendar/libical/src/libicalvcal/vcc.c
? evolution-data-server/src/GNOME_Evolution_ContactDatesServer_1.0.server
? evolution/calendar/common/Makefile
? evolution/calendar/common/Makefile.in
? evolution/calendar/gui/apps_evolution_calendar-1.5.schemas
Index: evolution-data-server/ChangeLog
===================================================================
RCS file: /cvs/gnome/evolution-data-server/ChangeLog,v
retrieving revision 1.75
diff -u -r1.75 ChangeLog
--- evolution-data-server/ChangeLog	9 Jan 2004 17:56:45 -0000	1.75
+++ evolution-data-server/ChangeLog	9 Jan 2004 18:13:15 -0000
@@ -1,3 +1,11 @@
+2004-01-09  ERDI Gergo  <cactus cactus rulez org>
+
+	* 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 <rodrigo ximian com>
 
 	* libedataserver/e-source-list.[ch]
Index: evolution-data-server/configure.in
===================================================================
RCS file: /cvs/gnome/evolution-data-server/configure.in,v
retrieving revision 1.29
diff -u -r1.29 configure.in
--- evolution-data-server/configure.in	29 Dec 2003 15:53:05 -0000	1.29
+++ evolution-data-server/configure.in	9 Jan 2004 18:13:16 -0000
@@ -300,6 +300,7 @@
 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
Index: evolution-data-server/calendar/backends/Makefile.am
===================================================================
RCS file: /cvs/gnome/evolution-data-server/calendar/backends/Makefile.am,v
retrieving revision 1.2
diff -u -r1.2 Makefile.am
--- evolution-data-server/calendar/backends/Makefile.am	14 Nov 2003 16:38:25 -0000	1.2
+++ evolution-data-server/calendar/backends/Makefile.am	9 Jan 2004 18:13:16 -0000
@@ -1 +1 @@
-SUBDIRS = file groupwise http
+SUBDIRS = file groupwise http contacts
Index: evolution-data-server/calendar/backends/contacts/.cvsignore
===================================================================
RCS file: evolution-data-server/calendar/backends/contacts/.cvsignore
diff -N evolution-data-server/calendar/backends/contacts/.cvsignore
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ evolution-data-server/calendar/backends/contacts/.cvsignore	9 Jan 2004 18:13:16 -0000
@@ -0,0 +1,2 @@
+Makefile
+Makefile.in
\ No newline at end of file
Index: evolution-data-server/calendar/backends/contacts/Makefile.am
===================================================================
RCS file: evolution-data-server/calendar/backends/contacts/Makefile.am
diff -N evolution-data-server/calendar/backends/contacts/Makefile.am
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ evolution-data-server/calendar/backends/contacts/Makefile.am	9 Jan 2004 18:13:16 -0000
@@ -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
+
Index: evolution-data-server/calendar/backends/contacts/e-cal-backend-contacts.c
===================================================================
RCS file: evolution-data-server/calendar/backends/contacts/e-cal-backend-contacts.c
diff -N evolution-data-server/calendar/backends/contacts/e-cal-backend-contacts.c
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ evolution-data-server/calendar/backends/contacts/e-cal-backend-contacts.c	9 Jan 2004 18:13:19 -0000
@@ -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 <federico ximian com>
+ *          Rodrigo Moya <rodrigo ximian com>
+ *          Gergő Érdi <cactus cactus rulez org>
+ *
+ * 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 <config.h>
+#endif
+#include <bonobo/bonobo-i18n.h>
+
+#include "e-cal-backend-contacts.h"
+
+#include <libedataserver/e-xml-hash-utils.h>
+#include <libecal/e-cal-recur.h>
+#include <libecal/e-cal-util.h>
+#include <libedata-cal/e-cal-backend-util.h>
+#include <libedata-cal/e-cal-backend-sexp.h>
+
+#include <libebook/e-book.h>
+
+#include <libedataserver/e-source-list.h>
+
+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;
+}
Index: evolution-data-server/calendar/backends/contacts/e-cal-backend-contacts.h
===================================================================
RCS file: evolution-data-server/calendar/backends/contacts/e-cal-backend-contacts.h
diff -N evolution-data-server/calendar/backends/contacts/e-cal-backend-contacts.h
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ evolution-data-server/calendar/backends/contacts/e-cal-backend-contacts.h	9 Jan 2004 18:13:19 -0000
@@ -0,0 +1,62 @@
+/* Evolution calendar - iCalendar file backend
+ *
+ * Copyright (C) 2000 Ximian, Inc.
+ * Copyright (C) 2003 Gergő Érdi
+ *
+ * Authors: Federico Mena-Quintero <federico ximian com>,
+ *          Gergő Érdi <cactus cactus rulez org>
+ *
+ * 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 <libedata-cal/e-cal-backend-sync.h>
+
+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
Index: evolution-data-server/calendar/libecal/e-cal.c
===================================================================
RCS file: /cvs/gnome/evolution-data-server/calendar/libecal/e-cal.c,v
retrieving revision 1.24
diff -u -r1.24 e-cal.c
--- evolution-data-server/calendar/libecal/e-cal.c	9 Jan 2004 03:48:19 -0000	1.24
+++ evolution-data-server/calendar/libecal/e-cal.c	9 Jan 2004 18:13:28 -0000
@@ -2157,7 +2157,10 @@
 	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);
Index: evolution-data-server/libedataserver/e-source-group.c
===================================================================
RCS file: /cvs/gnome/evolution-data-server/libedataserver/e-source-group.c,v
retrieving revision 1.3
diff -u -r1.3 e-source-group.c
--- evolution-data-server/libedataserver/e-source-group.c	14 Nov 2003 22:02:10 -0000	1.3
+++ evolution-data-server/libedataserver/e-source-group.c	9 Jan 2004 18:13:49 -0000
@@ -41,6 +41,7 @@
 	GSList *sources;
 
 	gboolean ignore_source_changed;
+	gboolean readonly;
 };
 
 
@@ -221,6 +222,7 @@
 	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 @@
 	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_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 @@
 	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 @@
 	}
 	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 @@
 {
 	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 @@
 	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 @@
 	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 @@
 	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 @@
 {
 	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 @@
 	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 @@
 	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 @@
 	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)
Index: evolution-data-server/libedataserver/e-source-group.h
===================================================================
RCS file: /cvs/gnome/evolution-data-server/libedataserver/e-source-group.h,v
retrieving revision 1.2
diff -u -r1.2 e-source-group.h
--- evolution-data-server/libedataserver/e-source-group.h	21 Oct 2003 18:51:19 -0000	1.2
+++ evolution-data-server/libedataserver/e-source-group.h	9 Jan 2004 18:13:49 -0000
@@ -78,9 +78,13 @@
 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,
Index: evolution-data-server/libedataserver/e-source.c
===================================================================
RCS file: /cvs/gnome/evolution-data-server/libedataserver/e-source.c,v
retrieving revision 1.10
diff -u -r1.10 e-source.c
--- evolution-data-server/libedataserver/e-source.c	18 Dec 2003 02:15:56 -0000	1.10
+++ evolution-data-server/libedataserver/e-source.c	9 Jan 2004 18:13:51 -0000
@@ -48,6 +48,8 @@
 	char *relative_uri;
 	char *absolute_uri;
 
+	gboolean readonly;
+	
 	gboolean has_color;
 	guint32 color;
 
@@ -414,6 +416,9 @@
 	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 @@
 {
 	g_return_if_fail (E_IS_SOURCE (source));
 
+	if (source->priv->readonly)
+		return;
+	
 	if (source->priv->name == name)
 		return;
 
@@ -454,6 +462,9 @@
 {
 	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 @@
 }
 
 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 @@
 	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 @@
 	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);
Index: evolution-data-server/libedataserver/e-source.h
===================================================================
RCS file: /cvs/gnome/evolution-data-server/libedataserver/e-source.h,v
retrieving revision 1.6
diff -u -r1.6 e-source.h
--- evolution-data-server/libedataserver/e-source.h	17 Dec 2003 00:43:56 -0000	1.6
+++ evolution-data-server/libedataserver/e-source.h	9 Jan 2004 18:13:51 -0000
@@ -76,6 +76,8 @@
 				  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 @@
 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);
 
Index: evolution-data-server/po/ChangeLog
===================================================================
RCS file: /cvs/gnome/evolution-data-server/po/ChangeLog,v
retrieving revision 1.23
diff -u -r1.23 ChangeLog
--- evolution-data-server/po/ChangeLog	9 Jan 2004 16:30:08 -0000	1.23
+++ evolution-data-server/po/ChangeLog	9 Jan 2004 18:13:52 -0000
@@ -62,6 +62,10 @@
 
 	*  it.po: updated italian translation
 
+2003-12-08  ERDI Gergo  <cactus cactus rulez org>
+
+	* POTFILES.in: Added ContactDates backend source
+
 2003-11-19  Marco Ciampa <ciampix libero it>
 
 	*  it.po: updated italian translation
Index: evolution-data-server/po/POTFILES.in
===================================================================
RCS file: /cvs/gnome/evolution-data-server/po/POTFILES.in,v
retrieving revision 1.5
diff -u -r1.5 POTFILES.in
--- evolution-data-server/po/POTFILES.in	6 Nov 2003 17:40:03 -0000	1.5
+++ evolution-data-server/po/POTFILES.in	9 Jan 2004 18:13:52 -0000
@@ -11,6 +11,7 @@
 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
Index: evolution-data-server/src/GNOME_Evolution_DataServerLDAP.server.in.in
===================================================================
RCS file: /cvs/gnome/evolution-data-server/src/GNOME_Evolution_DataServerLDAP.server.in.in,v
retrieving revision 1.10
diff -u -r1.10 GNOME_Evolution_DataServerLDAP.server.in.in
--- evolution-data-server/src/GNOME_Evolution_DataServerLDAP.server.in.in	8 Dec 2003 13:17:43 -0000	1.10
+++ evolution-data-server/src/GNOME_Evolution_DataServerLDAP.server.in.in	9 Jan 2004 18:13:52 -0000
@@ -35,6 +35,7 @@
 		<item value="file"/>
 		<item value="webcal"/>
 		<item value="groupwise"/>
+		<item value="contacts"/>
         </oaf_attribute>
 </oaf_server>
 
Index: evolution-data-server/src/GNOME_Evolution_DataServerNOLDAP.server.in.in
===================================================================
RCS file: /cvs/gnome/evolution-data-server/src/GNOME_Evolution_DataServerNOLDAP.server.in.in,v
retrieving revision 1.12
diff -u -r1.12 GNOME_Evolution_DataServerNOLDAP.server.in.in
--- evolution-data-server/src/GNOME_Evolution_DataServerNOLDAP.server.in.in	8 Dec 2003 13:17:43 -0000	1.12
+++ evolution-data-server/src/GNOME_Evolution_DataServerNOLDAP.server.in.in	9 Jan 2004 18:13:52 -0000
@@ -34,6 +34,7 @@
 		<item value="file"/>
 		<item value="webcal"/>
 		<item value="groupwise"/>
+		<item value="contacts"/>
         </oaf_attribute>
 </oaf_server>
 
Index: evolution-data-server/src/Makefile.am
===================================================================
RCS file: /cvs/gnome/evolution-data-server/src/Makefile.am,v
retrieving revision 1.10
diff -u -r1.10 Makefile.am
--- evolution-data-server/src/Makefile.am	30 Nov 2003 03:28:33 -0000	1.10
+++ evolution-data-server/src/Makefile.am	9 Jan 2004 18:13:52 -0000
@@ -34,7 +34,7 @@
 $(IDL_GENERATED_C): $(IDL_GENERATED_H)
 
 
-noinst_PROGRAMS =	\
+noinst_PROGRAMS =			\
 	evolution-data-server
 
 evolution_data_server_SOURCES = \
@@ -60,14 +60,15 @@
 	$(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 @@
 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)
Index: evolution-data-server/src/server.c
===================================================================
RCS file: /cvs/gnome/evolution-data-server/src/server.c,v
retrieving revision 1.13
diff -u -r1.13 server.c
--- evolution-data-server/src/server.c	18 Dec 2003 19:17:57 -0000	1.13
+++ evolution-data-server/src/server.c	9 Jan 2004 18:13:53 -0000
@@ -54,6 +54,7 @@
 #include <backends/file/e-cal-backend-file-todos.h>
 #include <backends/groupwise/e-cal-backend-groupwise.h>
 #include <backends/http/e-cal-backend-http.h>
+#include <backends/contacts/e-cal-backend-contacts.h>
 
 #include "server-interface-check.h"
 #include "server-logging.h"
@@ -182,6 +183,7 @@
 	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));
Index: evolution/calendar/ChangeLog
===================================================================
RCS file: /cvs/gnome/evolution/calendar/ChangeLog,v
retrieving revision 1.2052
diff -u -r1.2052 ChangeLog
--- evolution/calendar/ChangeLog	9 Jan 2004 07:48:24 -0000	1.2052
+++ evolution/calendar/ChangeLog	9 Jan 2004 18:14:16 -0000
@@ -1,3 +1,8 @@
+2004-01-07  ERDI Gergo  <cactus cactus rulez org>
+
+	* gui/calendar-component.c (impl_upgradeFromVersion): Create
+	ESource for anniversaries
+
 2004-01-09  Andrew Wu <Yang Wu sun com>
 
 	* gui/e-cal-view.c (e_calendar_view_class_init):
Index: evolution/calendar/gui/calendar-component.c
===================================================================
RCS file: /cvs/gnome/evolution/calendar/gui/calendar-component.c,v
retrieving revision 1.124
diff -u -r1.124 calendar-component.c
--- evolution/calendar/gui/calendar-component.c	6 Jan 2004 18:35:29 -0000	1.124
+++ evolution/calendar/gui/calendar-component.c	9 Jan 2004 18:14:21 -0000
@@ -168,7 +168,7 @@
 	ESource *source;
 
 	priv = calendar_component->priv;
-	
+
 	source = e_source_selector_peek_primary_selection (E_SOURCE_SELECTOR (priv->source_selector));
 	if (!source)
 		return;
@@ -257,6 +257,8 @@
 
 	comp = cal_comp_event_new_with_defaults (client);
 
+	g_return_val_if_fail (comp, NULL);
+	
 	location = calendar_config_get_timezone ();
 	zone = icaltimezone_get_builtin_timezone (location);
 
@@ -551,11 +553,25 @@
 			g_free (new_dir);
 		}
 
+		g_free (base_uri);
+
 		/* create the remote source group */
 		group = e_source_group_new (_("On The Web"), "webcal://");
 		e_source_list_add_group (priv->source_list, group, -1);
+	}
 
-		g_free (base_uri);
+	/* create calendar for birthdays & anniversaries */
+	if ((major < 0) ||
+	    ((major == 1) && (minor < 5)) ||
+	    ((major == 1) && (minor == 5) && (revision < 2))) {
+		ESource *source;
+		char *base_uri, *new_dir;
+		
+		group = e_source_group_new (_("Birthdays"), "contacts://");
+		source = e_source_new (_("Birthdays & Anniversaries"), "/");
+		e_source_group_add_source (group, source, -1);
+		e_source_group_set_readonly (group, TRUE);
+		e_source_list_add_group (priv->source_list, group, -1);
 	}
 }
 
@@ -784,12 +800,18 @@
 	ECalComponent *comp;
 	EventEditor *editor;
 	gboolean is_meeting = FALSE;
+	gboolean read_only = FALSE;
 	
 	priv = calendar_component->priv;
 
 	if (!setup_create_ecal (calendar_component)) {
 		bonobo_exception_set (ev, ex_GNOME_Evolution_Component_Failed);
 		return;
+
+	e_cal_is_read_only (priv->create_ecal, &read_only, NULL);
+	if (read_only)
+		return;
+	
 	}
 	
 	editor = event_editor_new (priv->create_ecal);
Index: evolution/calendar/gui/dialogs/new-calendar.c
===================================================================
RCS file: /cvs/gnome/evolution/calendar/gui/dialogs/new-calendar.c,v
retrieving revision 1.6
diff -u -r1.6 new-calendar.c
--- evolution/calendar/gui/dialogs/new-calendar.c	24 Nov 2003 10:13:24 -0000	1.6
+++ evolution/calendar/gui/dialogs/new-calendar.c	9 Jan 2004 18:14:24 -0000
@@ -132,7 +132,8 @@
 		 * silently translate an explicit file:// into http:// though. */
 		if (uri->protocol &&
 		    strcmp (uri->protocol, "http") &&
-		    strcmp (uri->protocol, "webcal")) {
+		    strcmp (uri->protocol, "webcal") &&
+                    strcmp (uri->protocol, "contacts")) {
 			e_uri_free (uri);
 			e_notice (parent, GTK_MESSAGE_ERROR,
 				  _("The source location '%s' is not a webcal source."),


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]