[evolution-patches] #127535: Birthday/anniversary calendar backend



Hi,

Here's the first version of a new calendar backend for #127535. How this
will be wired to the GUI is yet to be decided, but I want to get the
backend stuff in so I can manage it in the future with CVS.

Index: ChangeLog
===================================================================
RCS file: /cvs/gnome/evolution-data-server/ChangeLog,v
retrieving revision 1.52
diff -u -r1.52 ChangeLog
--- ChangeLog	4 Dec 2003 19:42:11 -0000	1.52
+++ ChangeLog	5 Dec 2003 23:48:46 -0000
@@ -1,3 +1,9 @@
+2003-12-06  ERDI Gergo  <cactus cactus rulez org>
+
+	* src/contactdates-server.c: new factory for ContactDates backend
+
+	* configure.in: Added new ContactDates calendar backend
+
 2003-12-04  JP Rosevear <jpr ximian com>
 
 	* libedataserver/e-source-list.c
Index: configure.in
===================================================================
RCS file: /cvs/gnome/evolution-data-server/configure.in,v
retrieving revision 1.22
diff -u -r1.22 configure.in
--- configure.in	25 Nov 2003 22:29:36 -0000	1.22
+++ configure.in	5 Dec 2003 23:48:47 -0000
@@ -285,6 +285,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: 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
--- calendar/backends/Makefile.am	14 Nov 2003 16:38:25 -0000	1.2
+++ calendar/backends/Makefile.am	5 Dec 2003 23:48:48 -0000
@@ -1 +1 @@
-SUBDIRS = file groupwise http
+SUBDIRS = file groupwise http contacts
Index: calendar/backends/contacts/.cvsignore
===================================================================
RCS file: calendar/backends/contacts/.cvsignore
diff -N calendar/backends/contacts/.cvsignore
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ calendar/backends/contacts/.cvsignore	5 Dec 2003 23:48:48 -0000
@@ -0,0 +1,2 @@
+Makefile
+Makefile.in
\ No newline at end of file
Index: calendar/backends/contacts/Makefile.am
===================================================================
RCS file: calendar/backends/contacts/Makefile.am
diff -N calendar/backends/contacts/Makefile.am
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ calendar/backends/contacts/Makefile.am	5 Dec 2003 23:48:48 -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: calendar/backends/contacts/e-cal-backend-contacts.c
===================================================================
RCS file: calendar/backends/contacts/e-cal-backend-contacts.c
diff -N calendar/backends/contacts/e-cal-backend-contacts.c
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ calendar/backends/contacts/e-cal-backend-contacts.c	5 Dec 2003 23:48:49 -0000
@@ -0,0 +1,799 @@
+/* -*- 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_const (contact, E_CONTACT_BIRTH_DATE) &&
+                    !e_contact_get_const (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_const (contact, E_CONTACT_BIRTH_DATE) ||
+                    e_contact_get_const (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 time_t
+cdate_to_time (EContactDate *cdate)
+{
+        struct tm time_tm = { 0, 0, 0, 0, 0, 0, 0, 0 };
+        time_t    time;
+
+        time_tm.tm_year = cdate->year - 1900;
+        time_tm.tm_mon = cdate->month - 1;
+        time_tm.tm_mday = cdate->day + 1;
+        time = mktime (&time_tm);
+
+        return time;
+}
+
+/* Contact -> Event creator */
+static ECalComponent *
+create_component (ECalBackendContacts *cbc, EContactDate *cdate, char *summary)
+{
+        ECalComponent             *cal_comp;
+	ECalComponentText          comp_summary;
+        icalcomponent             *ical_comp;
+        time_t                     start;
+        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 */
+        start = cdate_to_time (cdate);
+	itt = icaltime_from_timet (start, TRUE);
+        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);
+
+        /* 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_const (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_const (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)
+{
+	/* 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)
+{
+        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: src/.cvsignore
===================================================================
RCS file: /cvs/gnome/evolution-data-server/src/.cvsignore,v
retrieving revision 1.2
diff -u -r1.2 .cvsignore
--- src/.cvsignore	6 Nov 2003 17:40:15 -0000	1.2
+++ src/.cvsignore	5 Dec 2003 23:48:59 -0000
@@ -6,4 +6,6 @@
 Evolution-DataServer.h
 GNOME_Evolution_DataServer.server.in.in
 GNOME_Evolution_DataServer_1.0.server
-evolution-data-server
\ No newline at end of file
+GNOME_Evolution_ContactDatesServer_1.0.server
+evolution-data-server
+evolution-contactdates-server
\ No newline at end of file
Index: src/GNOME_Evolution_ContactDatesServer.server.in.in
===================================================================
RCS file: src/GNOME_Evolution_ContactDatesServer.server.in.in
diff -N src/GNOME_Evolution_ContactDatesServer.server.in.in
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ src/GNOME_Evolution_ContactDatesServer.server.in.in	5 Dec 2003 23:48:59 -0000
@@ -0,0 +1,31 @@
+<oaf_info>
+
+<oaf_server iid="OAFIID:GNOME_Evolution_ContactDatesServer_CalFactory"
+            type="exe"
+            location="@LIBEXECDIR@/evolution-contactdates-server- VERSION@">
+
+	<oaf_attribute name="repo_ids" type="stringv">
+		<item value="IDL:GNOME/Evolution/Calendar/CalFactory:1.0"/>
+		<item value="IDL:Bonobo/Unknown:1.0"/>
+	</oaf_attribute>
+
+	<oaf_attribute name="name" type="string"
+                       _value="Evolution ContactDates Calendar backend"/>
+
+        <oaf_attribute name="calendar:supported_protocols" type="stringv">
+		<item value="contacts"/>
+        </oaf_attribute>
+</oaf_server>
+
+<oaf_server iid="OAFIID:GNOME_Evolution_ContactDatesServer_InterfaceCheck"
+            type="exe"
+            location="@LIBEXECDIR@/evolution-contactdates-server- VERSION@">
+
+	<oaf_attribute name="repo_ids" type="stringv">
+		<item value="IDL:GNOME/Evolution/ServerInterfaceCheck:1.0"/>
+		<item value="IDL:Bonobo/Unknown:1.0"/>
+	</oaf_attribute>
+
+</oaf_server>
+
+</oaf_info>
Index: src/Makefile.am
===================================================================
RCS file: /cvs/gnome/evolution-data-server/src/Makefile.am,v
retrieving revision 1.10
diff -u -r1.10 Makefile.am
--- src/Makefile.am	30 Nov 2003 03:28:33 -0000	1.10
+++ src/Makefile.am	5 Dec 2003 23:48:59 -0000
@@ -34,8 +34,9 @@
 $(IDL_GENERATED_C): $(IDL_GENERATED_H)
 
 
-noinst_PROGRAMS =	\
-	evolution-data-server
+noinst_PROGRAMS =			\
+	evolution-data-server		\
+	evolution-contactdates-server
 
 evolution_data_server_SOURCES = \
 	$(IDL_GENERATED)		\
@@ -45,6 +46,12 @@
 	server-logging.h		\
 	server.c
 
+evolution_contactdates_server_SOURCES = \
+	$(IDL_GENERATED)		\
+	server-interface-check.c	\
+	server-interface-check.h	\
+	contactdates-server.c
+
 if ENABLE_LDAP
 LDAP_BACKEND_LIB=$(top_builddir)/addressbook/backends/ldap/libebookbackendldap.la
 else
@@ -60,13 +67,19 @@
 	$(top_builddir)/calendar/backends/file/libecalbackendfile.la		\
 	$(top_builddir)/calendar/backends/groupwise/libecalbackendgroupwise.la	\
 	$(top_builddir)/calendar/backends/http/libecalbackendhttp.la		\
+	$(top_builddir)/calendar/backends/contacts/libecalbackendcontacts.la	\
 	$(LDAP_LIBS)								\
 	$(E_DATA_SERVER_LIBS)
 
-install-evolution-data-server:
+evolution_contactdates_server_LDADD =						\
+	$(top_builddir)/addressbook/libebook/libebook.la			\
+	$(top_builddir)/calendar/backends/contacts/libecalbackendcontacts.la	\
+	$(E_DATA_SERVER_LIBS)
+
+install-evolution-data-servers:
 	$(mkinstalldirs) $(DESTDIR)$(libexecdir)
 	$(LIBTOOL) --mode=install $(INSTALL_PROGRAM) evolution-data-server $(DESTDIR)$(libexecdir)/evolution-data-server-$(BASE_VERSION)
-
+	$(LIBTOOL) --mode=install $(INSTALL_PROGRAM) evolution-contactdates-server $(DESTDIR)$(libexecdir)/evolution-contactdates-server-$(BASE_VERSION)
 
 if ENABLE_LDAP
 SERVER_IN_FILE=GNOME_Evolution_DataServerLDAP.server.in.in
@@ -77,7 +90,7 @@
 GNOME_Evolution_DataServer.server.in.in: $(SERVER_IN_FILE) Makefile
 	cp $< $@
 
-server_in_files = GNOME_Evolution_DataServer.server.in.in
+server_in_files = GNOME_Evolution_DataServer.server.in.in GNOME_Evolution_ContactDatesServer.server.in.in
 server_DATA = $(server_in_files:.server.in.in=_$(BASE_VERSION).server)
 @EVO_SUBST_SERVER_RULE@
 @EVO_NAME_SERVER_RULE@
@@ -89,12 +102,13 @@
 	$(server_in_files)				\
 	$(idl_DATA)					\
 	GNOME_Evolution_DataServerLDAP.server.in.in	\
-	GNOME_Evolution_DataServerNOLDAP.server.in.in
+	GNOME_Evolution_DataServerNOLDAP.server.in.in	\
+	GNOME_Evolution_ContactDatesServer.server.in.in
 
 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: src/contactdates-server.c
===================================================================
RCS file: src/contactdates-server.c
diff -N src/contactdates-server.c
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ src/contactdates-server.c	5 Dec 2003 23:48:59 -0000
@@ -0,0 +1,209 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+/* contactdates-server.c
+ *
+ * Copyright (C) 2000-2003, Ximian, Inc.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of version 2 of the GNU General Public
+ * License as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public
+ * License along with this program; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ *
+ * Author: Nat Friedman (nat ximian com)
+ *         ERDI Gergo (cactus cactus rulez org)
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+/* define this if you need/want to be able to send USR2 to server and
+   get a list of the active backends */
+/*#define DEBUG_BACKENDS*/
+
+#include <stdlib.h>
+#ifdef DEBUG_BACKENDS
+#include <sys/signal.h>
+#endif
+
+#include <glib.h>
+#include <libgnome/gnome-init.h>
+#include <bonobo-activation/bonobo-activation.h>
+#include <libgnomevfs/gnome-vfs-init.h>
+#include <bonobo/bonobo-main.h>
+#include <bonobo/bonobo-i18n.h>
+#include <bonobo/bonobo-exception.h>
+#include <bonobo/bonobo-generic-factory.h>
+
+#include <calendar/libedata-cal/e-data-cal-factory.h>
+#include <calendar/backends/contacts/e-cal-backend-contacts.h>
+
+#include "server-interface-check.h"
+
+#define SERVER_INTERFACE_CHECK_OAF_ID "OAFIID:GNOME_Evolution_ContactDatesServer_InterfaceCheck"
+
+#define CAL_FACTORY_OAF_ID "OAFIID:GNOME_Evolution_ContactDatesServer_CalFactory"
+
+/* The calendar factories */
+
+static EDataCalFactory *cal_factory;
+
+/* Timeout interval in milliseconds for termination */
+#define EXIT_TIMEOUT 5000
+
+/* Timeout ID for termination handler */
+static guint termination_handler_id;
+
+static GStaticMutex termination_lock = G_STATIC_MUTEX_INIT;
+
+
+
+/* Termination */
+
+/* Termination handler.  Checks if both factories have zero running backends,
+ * and if so terminates the program.
+ */
+static gboolean
+termination_handler (gpointer data)
+{
+	if (e_data_cal_factory_get_n_backends (cal_factory) == 0) {
+		fprintf (stderr, "termination_handler(): Terminating the Server.  Have a nice day.\n");
+		bonobo_main_quit ();
+	}
+
+	termination_handler_id = 0;
+	return FALSE;
+}
+
+/* Queues a timeout for handling termination of Server */
+static void
+queue_termination (void)
+{
+	g_static_mutex_lock (&termination_lock);
+	if (termination_handler_id)
+		g_source_remove (termination_handler_id);
+
+	termination_handler_id = g_timeout_add (EXIT_TIMEOUT, termination_handler, NULL);
+	g_static_mutex_unlock (&termination_lock);
+}
+
+
+
+/* Callback used when the calendar factory has no more running backends */
+static void
+last_calendar_gone_cb (EDataCalFactory *factory, gpointer data)
+{
+	queue_termination ();
+}
+
+/* Creates the calendar factory object and registers it */
+static gboolean
+setup_cals (void)
+{
+	cal_factory = e_data_cal_factory_new ();
+
+	if (!cal_factory) {
+		g_warning (G_STRLOC ": Could not create the calendar factory");
+		return FALSE;
+	}
+
+	e_data_cal_factory_register_method (cal_factory, "contacts", ICAL_VEVENT_COMPONENT, E_TYPE_CAL_BACKEND_CONTACTS);
+
+	if (!e_data_cal_factory_register_storage (cal_factory, CAL_FACTORY_OAF_ID)) {
+		bonobo_object_unref (BONOBO_OBJECT (cal_factory));
+		cal_factory = NULL;
+		return FALSE;
+	}
+
+	g_signal_connect (G_OBJECT (cal_factory),
+			  "last_calendar_gone",
+			  G_CALLBACK (last_calendar_gone_cb),
+			  NULL);
+
+	return TRUE;
+}
+
+
+/* Interface check iface.  */
+
+static gboolean
+setup_interface_check (void)
+{
+	ServerInterfaceCheck *interface_check_iface = server_interface_check_new ();
+	int result;
+
+	result = bonobo_activation_active_server_register (SERVER_INTERFACE_CHECK_OAF_ID,
+							   BONOBO_OBJREF (interface_check_iface));
+
+	return result == Bonobo_ACTIVATION_REG_SUCCESS;
+}
+
+
+
+#ifdef DEBUG_BACKENDS
+static void
+dump_backends (int signal)
+{
+	e_data_cal_factory_dump_active_backends (cal_factory);
+}
+#endif
+
+int
+main (int argc, char **argv)
+{
+	gboolean did_books=FALSE, did_cals=FALSE;
+
+	bindtextdomain (GETTEXT_PACKAGE, EVOLUTION_LOCALEDIR);
+	textdomain (GETTEXT_PACKAGE);
+
+	g_message ("Starting server");
+
+#ifdef DEBUG_BACKENDS
+	signal (SIGUSR2, dump_backends);
+#endif
+
+       	gnome_program_init (PACKAGE, VERSION,
+			    LIBGNOME_MODULE,
+			    argc, argv,
+			    GNOME_PROGRAM_STANDARD_PROPERTIES, NULL);
+
+	bonobo_init_full (&argc, argv,
+			  bonobo_activation_orb_get(),
+			  CORBA_OBJECT_NIL,
+			  CORBA_OBJECT_NIL);
+
+	if (!setup_cals ()) {
+
+		g_error (G_STRLOC ": could not initialize Server service \"CALS\"; terminating");
+
+		if (cal_factory) {
+			bonobo_object_unref (BONOBO_OBJECT (cal_factory));
+			cal_factory = NULL;
+		}
+		exit (EXIT_FAILURE);
+	}
+
+	if (!setup_interface_check ()) {
+		g_error (G_STRLOC "Cannot register DataServer::InterfaceCheck object");
+		exit (EXIT_FAILURE);
+	}
+
+	g_message ("Server up and running\n");
+
+	bonobo_main ();
+
+	bonobo_object_unref (BONOBO_OBJECT (cal_factory));
+	cal_factory = NULL;
+
+	gnome_vfs_shutdown ();
+
+	return 0;
+}

-- 
   .--= ULLA! =---------------------.   `We are not here to give users what
   \     http://cactus.rulez.org     \   they want'  -- RMS, at GUADEC 2001
    `---= cactus cactus rulez org =---'
A CONFIG.SYS-edben mindíg legyen egy BUGS=OFF sor!





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