evolution-data-server r8676 - branches/EXCHANGE_MAPI_BRANCH/calendar/backends/mapi



Author: msuman
Date: Thu Apr 24 05:34:45 2008
New Revision: 8676
URL: http://svn.gnome.org/viewvc/evolution-data-server?rev=8676&view=rev

Log:
Incorporate the new delta_fetch style from the GW backend, limiting the number of delta-threads running to 1. Fix up a few class funtions which were incomplete.

Modified:
   branches/EXCHANGE_MAPI_BRANCH/calendar/backends/mapi/ChangeLog
   branches/EXCHANGE_MAPI_BRANCH/calendar/backends/mapi/e-cal-backend-mapi-utils.c
   branches/EXCHANGE_MAPI_BRANCH/calendar/backends/mapi/e-cal-backend-mapi.c

Modified: branches/EXCHANGE_MAPI_BRANCH/calendar/backends/mapi/e-cal-backend-mapi-utils.c
==============================================================================
--- branches/EXCHANGE_MAPI_BRANCH/calendar/backends/mapi/e-cal-backend-mapi-utils.c	(original)
+++ branches/EXCHANGE_MAPI_BRANCH/calendar/backends/mapi/e-cal-backend-mapi-utils.c	Thu Apr 24 05:34:45 2008
@@ -752,7 +752,7 @@
 	icalproperty *prop;
 	struct icaltimetype dtstart, dtend, utc_dtstart, utc_dtend;
 	const icaltimezone *utc_zone;
-	const char *dtstart_tzid, *dtend_tzid;
+	const char *dtstart_tzid, *dtend_tzid, *text = NULL;
 	struct timeval t;
 
 	switch (kind) {
@@ -792,24 +792,28 @@
 	utc_dtend = icaltime_convert_to_zone (dtend, utc_zone);
 
 	/* FIXME: convert to unicode */
+	text = icalcomponent_get_summary (ical_comp);
+	if (!(text && *text)) 
+		text = "";
 	set_SPropValue_proptag(&props[i++], PR_SUBJECT, 					/* prop count: 2 */ 
-					(const void *) icalcomponent_get_summary (ical_comp));
-
-	/* FIXME: convert to unicode */
+					(const void *) text);
 	set_SPropValue_proptag(&props[i++], PR_NORMALIZED_SUBJECT, 				/* prop count: 3 */ 
-					(const void *) icalcomponent_get_summary (ical_comp));
-
-	/* FIXME: convert to unicode AND do we need this property ?? */
+					(const void *) text);
 	set_SPropValue_proptag(&props[i++], PR_CONVERSATION_TOPIC, 				/* prop count: 4 */
-					(const void *) icalcomponent_get_summary (ical_comp));
+					(const void *) text);
+	text = NULL;
 
 	/* we don't support HTML event/task/memo editor */
 	flag32 = EDITOR_FORMAT_PLAINTEXT;
 	set_SPropValue_proptag(&props[i++], PR_MSG_EDITOR_FORMAT, &flag32); 			/* prop count: 5 */
 
 	/* it'd be better to convert, then set it in unicode */
+	text = icalcomponent_get_description (ical_comp);
+	if (!(text && *text)) 
+		text = "";
 	set_SPropValue_proptag(&props[i++], PR_BODY, 						/* prop count: 6 */
-					(const void *) icalcomponent_get_description (ical_comp));
+					(const void *) text);
+	text = NULL;
 
 	/* Priority */
 	flag32 = PRIORITY_NORMAL; 	/* default */
@@ -920,7 +924,11 @@
 		set_SPropValue_proptag(&props[i++], proptag_array->aulPropTag[I_APPT_BUSYSTATUS], (const void *) &flag32);
 
 		/* Location */
-		set_SPropValue_proptag(&props[i++], proptag_array->aulPropTag[I_APPT_LOCATION], (const void *) icalcomponent_get_location (ical_comp));
+		text = icalcomponent_get_location (ical_comp);
+		if (!(text && *text)) 
+			text = "";
+		set_SPropValue_proptag(&props[i++], proptag_array->aulPropTag[I_APPT_LOCATION], (const void *) text);
+		text = NULL;
 
 		/* Start */
 		t.tv_sec = icaltime_as_timet (utc_dtstart);

Modified: branches/EXCHANGE_MAPI_BRANCH/calendar/backends/mapi/e-cal-backend-mapi.c
==============================================================================
--- branches/EXCHANGE_MAPI_BRANCH/calendar/backends/mapi/e-cal-backend-mapi.c	(original)
+++ branches/EXCHANGE_MAPI_BRANCH/calendar/backends/mapi/e-cal-backend-mapi.c	Thu Apr 24 05:34:45 2008
@@ -1,7 +1,7 @@
 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*-
  *
  *  Suman Manjunath <msuman novell com>
- *  Copyright (C) 2007 Novell, Inc.
+ *  Copyright (C) 2008 Novell, Inc.
  *
  *  This program is free software; you can redistribute it and/or modify
  *  it under the terms of the GNU General Public License as published by
@@ -20,39 +20,51 @@
 
 
 #include <libecal/e-cal-time-util.h>
+#include <gio/gio.h>
 
 #include "e-cal-backend-mapi.h"
 #include "e-cal-backend-mapi-utils.h"
 #include "e-cal-backend-mapi-tz-utils.h"
 
-#define gmtime_r(tp,tmp) (gmtime(tp)?(*(tmp)=*gmtime(tp),(tmp)):0)
-
 #define d(x) x
 
-static ECalBackendClass *parent_class = NULL;
+#ifdef G_OS_WIN32
+/* Undef the similar macro from pthread.h, it doesn't check if
+ * gmtime() returns NULL.
+ */
+#undef gmtime_r
+
+/* The gmtime() in Microsoft's C library is MT-safe */
+#define gmtime_r(tp,tmp) (gmtime(tp)?(*(tmp)=*gmtime(tp),(tmp)):0)
+#endif
+
+typedef struct {
+	GCond *cond;
+	GMutex *mutex;
+	gboolean exit;
+} SyncDelta;
 
 /* Private part of the CalBackendMAPI structure */
 struct _ECalBackendMAPIPrivate {
 	mapi_id_t 		fid;
 	uint32_t 		olFolder;
-	char 			*owner_name;
-	char 			*owner_email;	
-	char			*user_name;
-	char			*user_email;
+
+	/* These fields are entirely for access rights */
+	gchar 			*owner_name;
+	gchar 			*owner_email;	
+	gchar			*user_name;
+	gchar			*user_email;
 
 	/* A mutex to control access to the private structure */
 	GMutex			*mutex;
 	ECalBackendCache	*cache;
 	gboolean		read_only;
-	char			*uri;
-	char			*username;
-	char			*password;
-	int			timeout_id;
+	gchar			*uri;
+	gchar			*username;
+	gchar			*password;
 	CalMode			mode;
 	gboolean		mode_changed;
 	icaltimezone		*default_zone;
-	GHashTable		*categories_by_id;
-	GHashTable		*categories_by_name;
 
 	/* number of calendar items in the folder */
 	guint32			total_count;
@@ -60,12 +72,18 @@
 	/* timeout handler for syncing sendoptions */
 	guint			sendoptions_sync_timeout;
 	
-	char			*local_attachments_store;
+	gchar			*local_attachments_store;
 
 	/* used exclusively for delta fetching */
+	guint 			timeout_id;
+	GThread 		*dthread;
+	SyncDelta 		*dlock;
 	GSList 			*cache_keys;
 };
 
+#define PARENT_TYPE E_TYPE_CAL_BACKEND_SYNC
+static ECalBackendClass *parent_class = NULL;
+
 #define CACHE_REFRESH_INTERVAL 600000
 
 static gboolean authenticated = FALSE;
@@ -80,15 +98,12 @@
 	cbmapi = E_CAL_BACKEND_MAPI (backend);
 	priv = cbmapi->priv;
 
-	g_static_mutex_lock (&auth_mutex);
 	if (authenticated || exchange_mapi_connection_exists () || exchange_mapi_connection_new (priv->user_email, NULL)) {
 		authenticated = TRUE;
-		g_static_mutex_unlock (&auth_mutex);
 		return GNOME_Evolution_Calendar_Success;
 	} else { 
 		authenticated = FALSE;
 		e_cal_backend_notify_error (E_CAL_BACKEND (cbmapi), _("Authentication failed"));
-		g_static_mutex_unlock (&auth_mutex);
 		return GNOME_Evolution_Calendar_AuthenticationFailed;
 	}
 }
@@ -120,6 +135,27 @@
 	priv = cbmapi->priv;
 
 	/* Clean up */
+	if (priv->timeout_id) {
+		g_source_remove (priv->timeout_id);
+		priv->timeout_id = 0;
+	}
+
+	if (priv->dlock) {
+		g_mutex_lock (priv->dlock->mutex);
+		priv->dlock->exit = TRUE;
+		g_mutex_unlock (priv->dlock->mutex);
+		
+		g_cond_signal (priv->dlock->cond);
+
+		if (priv->dthread)
+			g_thread_join (priv->dthread);
+		
+		g_mutex_free (priv->dlock->mutex);
+		g_cond_free (priv->dlock->cond);
+		g_free (priv->dlock);
+		priv->dthread = NULL;
+	}
+
 	if (priv->mutex) {
 		g_mutex_free (priv->mutex);
 		priv->mutex = NULL;
@@ -130,11 +166,6 @@
 		priv->cache = NULL;
 	}
 
-	if (priv->uri) {
-		g_free (priv->uri);
-		priv->uri = NULL;
-	}
-
 	if (priv->username) {
 		g_free (priv->username);
 		priv->username = NULL;
@@ -145,21 +176,31 @@
 		priv->password = NULL;
 	}
 
+	if (priv->user_name) {
+		g_free (priv->user_name);
+		priv->user_name = NULL;
+	}
+
 	if (priv->user_email) {
 		g_free (priv->user_email);
 		priv->user_email = NULL;
 	}
 
+	if (priv->owner_name) {
+		g_free (priv->owner_name);
+		priv->owner_name = NULL;
+	}
+
+	if (priv->owner_email) {
+		g_free (priv->owner_email);
+		priv->owner_email = NULL;
+	}
+
 	if (priv->local_attachments_store) {
 		g_free (priv->local_attachments_store);
 		priv->local_attachments_store = NULL;
 	}
 
-	if (priv->timeout_id) {
-		g_source_remove (priv->timeout_id);
-		priv->timeout_id = 0;
-	}
-
 	if (priv->sendoptions_sync_timeout) {
 		g_source_remove (priv->sendoptions_sync_timeout);
 		priv->sendoptions_sync_timeout = 0;
@@ -212,11 +253,10 @@
 static ECalBackendSyncStatus 
 e_cal_backend_mapi_get_alarm_email_address (ECalBackendSync *backend, EDataCal *cal, char **address)
 {
-	/* We don't support email alarms (?). This should not have been called. */
+	/* We don't support email alarms. This should not have been called. */
 
 	*address = NULL;
 
-	/* return Success OR OtherError ? */
 	return GNOME_Evolution_Calendar_Success;
 }
 
@@ -280,8 +320,14 @@
 		return GNOME_Evolution_Calendar_RepositoryOffline;
 
 	/* FIXME: check for return status and respond */
-	if (!authenticated)
+	if (!authenticated) {
+		g_static_mutex_lock (&auth_mutex); 
 		e_cal_backend_mapi_authenticate (E_CAL_BACKEND (cbmapi));
+		g_static_mutex_unlock (&auth_mutex);
+	}
+
+	if (!authenticated)
+		return GNOME_Evolution_Calendar_AuthenticationFailed;
 
 	status = exchange_mapi_remove_folder (priv->olFolder, priv->fid);
 	if (!status)
@@ -340,6 +386,12 @@
 };
 static const uint16_t n_GetPropsList = G_N_ELEMENTS (GetPropsList);
 
+static const uint32_t IDList[] = {
+	PR_FID, 
+	PR_MID
+};
+static const uint16_t n_IDList = G_N_ELEMENTS (IDList);
+
 static gboolean
 get_changes_cb (struct mapi_SPropValue_array *array, const mapi_id_t fid, const mapi_id_t mid, 
 		GSList *streams, GSList *recipients, GSList *attachments, gpointer data)
@@ -347,7 +399,7 @@
 	ECalBackendMAPI *cbmapi	= data;
 	ECalBackendMAPIPrivate *priv = cbmapi->priv;
 	gchar *tmp = NULL;
-	GSList *cache_comp_uid = NULL;
+	ECalComponent *cache_comp = NULL;
 	const bool *recurring;
 
 	/* FIXME: Provide support for meetings/assigned tasks */
@@ -373,9 +425,9 @@
 	}
 
 	tmp = exchange_mapi_util_mapi_id_to_string (mid);
-	cache_comp_uid = g_slist_find_custom (priv->cache_keys, tmp, (GCompareFunc) (g_ascii_strcasecmp));
+	cache_comp = e_cal_backend_cache_get_component (priv->cache, tmp, NULL);
 
-	if (cache_comp_uid == NULL) {
+	if (cache_comp == NULL) {
 		ECalComponent *comp = e_cal_backend_mapi_props_to_comp (cbmapi, tmp, array, streams, recipients, attachments, priv->default_zone);
 
 		if (E_IS_CAL_COMPONENT (comp)) {
@@ -394,37 +446,35 @@
 		struct timeval t;
 
 		if (get_mapi_SPropValue_array_date_timeval (&t, array, PR_LAST_MODIFICATION_TIME) == MAPI_E_SUCCESS) {
-			ECalComponent *cache_comp;
 			struct icaltimetype itt, *cache_comp_lm = NULL;
+
 			itt = icaltime_from_timet_with_zone (t.tv_sec, 0, 0);
 			icaltime_set_timezone (&itt, icaltimezone_get_utc_timezone ());
 
-			cache_comp = e_cal_backend_cache_get_component (priv->cache, (const char *) cache_comp_uid->data, NULL);
 			e_cal_component_get_last_modified (cache_comp, &cache_comp_lm);
-			if (!cache_comp_lm || icaltime_compare (itt, *cache_comp_lm) != 0) {
+			if (!cache_comp_lm || (icaltime_compare (itt, *cache_comp_lm) != 0)) {
 				ECalComponent *comp;
-				char *old_comp_str = NULL, *new_comp_str = NULL;
+				char *cache_comp_str = NULL, *modif_comp_str = NULL;
 
 				e_cal_component_commit_sequence (cache_comp);
-				old_comp_str = e_cal_component_get_as_string (cache_comp);
+				cache_comp_str = e_cal_component_get_as_string (cache_comp);
 
-				comp = e_cal_backend_mapi_props_to_comp (cbmapi, (const char *) cache_comp_uid->data, array, 
+				comp = e_cal_backend_mapi_props_to_comp (cbmapi, tmp, array, 
 									streams, recipients, attachments, priv->default_zone);
 
 				e_cal_component_commit_sequence (comp);
-				new_comp_str = e_cal_component_get_as_string (comp);
+				modif_comp_str = e_cal_component_get_as_string (comp);
 
-				e_cal_backend_notify_object_modified (E_CAL_BACKEND (cbmapi), old_comp_str, new_comp_str);
+				e_cal_backend_notify_object_modified (E_CAL_BACKEND (cbmapi), cache_comp_str, modif_comp_str);
 				e_cal_backend_cache_put_component (priv->cache, comp);
 
 				g_object_unref (comp);
-				g_free (old_comp_str); 
-				g_free (new_comp_str);
+				g_free (cache_comp_str); 
+				g_free (modif_comp_str);
 			}
 			g_object_unref (cache_comp);
 			g_free (cache_comp_lm);
 		}
-		priv->cache_keys = g_slist_remove_link (priv->cache_keys, cache_comp_uid);
 	}
 
 	g_free (tmp);
@@ -432,79 +482,105 @@
 }
 
 static gboolean
+handle_deleted_items_cb (struct mapi_SPropValue_array *array, const mapi_id_t fid, const mapi_id_t mid, 
+			 GSList *streams, GSList *recipients, GSList *attachments, gpointer data)
+{
+	ECalBackendMAPI *cbmapi	= data;
+	ECalBackendMAPIPrivate *priv = cbmapi->priv;
+	gchar *tmp = NULL;
+	GSList *cache_comp_uid = NULL;
+
+	tmp = exchange_mapi_util_mapi_id_to_string (mid);
+	cache_comp_uid = g_slist_find_custom (priv->cache_keys, tmp, (GCompareFunc) (g_ascii_strcasecmp));
+	if (cache_comp_uid != NULL)
+		priv->cache_keys = g_slist_remove_link (priv->cache_keys, cache_comp_uid);
+
+	g_free (tmp);
+	return TRUE;
+}
+
+/* Simple workflow for fetching deltas: 
+ * Poke cache for server_utc_time -> if exists, fetch all items modified after that time, 
+ * note current time before fetching and update cache with the same after fetching. 
+ * If server_utc_time does not exist OR is invalid, fetch all items 
+ * (we anyway process the results only if last_modified has changed).
+ */
+
+static gboolean
 get_deltas (gpointer handle)
 {
 	ECalBackendMAPI *cbmapi;
 	ECalBackendMAPIPrivate *priv;
-	ECalBackendCache *cache; 
 	icalcomponent_kind kind;
-	char *time_string = NULL;
-	char t_str [26]; 
-	const char *serv_time;
 	static GStaticMutex updating = G_STATIC_MUTEX_INIT;
-	const char *time_interval_string;
-	int time_interval;
-	icaltimetype temp;
-	struct tm tm;
+	icaltimetype itt_current, itt_cache = icaltime_null_time(); 
 	time_t current_time;
+	struct tm tm;
+	gchar *time_string = NULL;
+	gchar t_str [26]; 
+	const char *serv_time;
+	struct mapi_SRestriction res;
+	gboolean use_restriction = FALSE;
 	GSList *ls = NULL;
 
 	if (!handle)
 		return FALSE;
 
 	cbmapi = (ECalBackendMAPI *) handle;
-	priv= cbmapi->priv;
 	kind = e_cal_backend_get_kind (E_CAL_BACKEND (cbmapi));
-	cache = priv->cache; 
+	priv= cbmapi->priv;
 
 	if (priv->mode == CAL_MODE_LOCAL)
 		return FALSE;
 
 	g_static_mutex_lock (&updating);
 
-	serv_time = e_cal_backend_cache_get_server_utc_time (cache);
-	if (serv_time) {
-		icaltimetype tmp;
-		g_strlcpy (t_str, e_cal_backend_cache_get_server_utc_time (cache), 26);
-		if (!*t_str || !strcmp (t_str, "")) {
-			/* FIXME: When time-stamp is crashed, getting changes from current time */
-			g_warning ("Could not get a valid time stamp.");
-			tmp = icaltime_current_time_with_zone (icaltimezone_get_utc_timezone ());
-			current_time = icaltime_as_timet_with_zone (tmp, icaltimezone_get_utc_timezone ());
-			gmtime_r (&current_time, &tm);
-			strftime (t_str, 26, "%Y-%m-%dT%H:%M:%SZ", &tm);
-		}
-	} else {
-		icaltimetype tmp;
-		/* FIXME: When time-stamp is crashed, getting changes from current time */
-		g_warning ("Could not get a valid time stamp.");
-		tmp = icaltime_current_time_with_zone (icaltimezone_get_utc_timezone ());
-		current_time = icaltime_as_timet_with_zone (tmp, icaltimezone_get_utc_timezone ());
-		gmtime_r (&current_time, &tm);
-		strftime (t_str, 26, "%Y-%m-%dT%H:%M:%SZ", &tm);
+	serv_time = e_cal_backend_cache_get_server_utc_time (priv->cache);
+	itt_cache = icaltime_from_string (serv_time); 
+	if (!icaltime_is_null_time (itt_cache)) {
+		/* FIXME: prepare the restriction here */
+	} 
+
+	itt_current = icaltime_current_time_with_zone (icaltimezone_get_utc_timezone ());
+	current_time = icaltime_as_timet_with_zone (itt_current, icaltimezone_get_utc_timezone ());
+	gmtime_r (&current_time, &tm);
+	strftime (t_str, 26, "%Y-%m-%dT%H:%M:%SZ", &tm);
+
+//	e_file_cache_freeze_changes (E_FILE_CACHE (priv->cache));
+	if (!exchange_mapi_connection_fetch_items (priv->fid, GetPropsList, n_GetPropsList, mapi_cal_build_name_id, use_restriction ? &res : NULL, get_changes_cb, cbmapi, MAPI_OPTIONS_FETCH_ALL)) {
+		/* FIXME: better string please... */
+		e_cal_backend_notify_error (E_CAL_BACKEND (cbmapi), _("Error fetching changes from the server. Removing the cache might help."));
+//		e_file_cache_thaw_changes (E_FILE_CACHE (priv->cache));
+		g_static_mutex_unlock (&updating);
+		return FALSE;
 	}
+//	e_file_cache_thaw_changes (E_FILE_CACHE (priv->cache));
+
 	time_string = g_strdup (t_str);
+	e_cal_backend_cache_put_server_utc_time (priv->cache, time_string);
+	g_free (time_string);
 
-	 /* e_cal_backend_cache_get_keys returns a list of all the keys. 
-	  * The items in the list are pointers to internal data, 
-	  * so should not be freed, only the list should. */
-	priv->cache_keys = e_cal_backend_cache_get_keys (cache);
+	/* handle deleted items here by going over the entire cache and
+	 * checking for deleted items.*/
 
-//	e_file_cache_freeze_changes (E_FILE_CACHE (cache));
-	if (!exchange_mapi_connection_fetch_items (priv->fid, GetPropsList, n_GetPropsList, mapi_cal_build_name_id, NULL, get_changes_cb, cbmapi, MAPI_OPTIONS_FETCH_ALL)) {
-		e_cal_backend_notify_error (E_CAL_BACKEND (cbmapi), _("Could not create cache file"));
-		e_file_cache_thaw_changes (E_FILE_CACHE (cache));
+	/* e_cal_backend_cache_get_keys returns a list of all the keys. 
+	 * The items in the list are pointers to internal data, 
+	 * so should not be freed, only the list should. */
+	priv->cache_keys = e_cal_backend_cache_get_keys (priv->cache);
+	if (!exchange_mapi_connection_fetch_items (priv->fid, IDList, n_IDList, NULL, NULL, handle_deleted_items_cb, cbmapi, 0)) {
+		/* FIXME: better string please... */
+		e_cal_backend_notify_error (E_CAL_BACKEND (cbmapi), _("Error fetching changes from the server. Removing the cache might help."));
 		priv->cache_keys = NULL;
-		return GNOME_Evolution_Calendar_OtherError;
+		g_static_mutex_unlock (&updating);
+		return FALSE;
 	}
-//	e_file_cache_thaw_changes (E_FILE_CACHE (cache));
 
-//	e_file_cache_freeze_changes (E_FILE_CACHE (cache));
+	e_file_cache_freeze_changes (E_FILE_CACHE (priv->cache));
 	for (ls = priv->cache_keys; ls ; ls = g_slist_next (ls)) {
 		ECalComponent *comp = NULL;
 		icalcomponent *icalcomp = NULL;
 
-		comp = e_cal_backend_cache_get_component (cache, (const char *) ls->data, NULL);
+		comp = e_cal_backend_cache_get_component (priv->cache, (const char *) ls->data, NULL);
 
 		if (!comp)
 			continue;
@@ -517,157 +593,22 @@
 			comp_str = e_cal_component_get_as_string (comp);
 			e_cal_backend_notify_object_removed (E_CAL_BACKEND (cbmapi), 
 					id, comp_str, NULL);
-			e_cal_backend_cache_remove_component (cache, (const char *) id->uid, id->rid);
+			e_cal_backend_cache_remove_component (priv->cache, (const char *) id->uid, id->rid);
 
 			e_cal_component_free_id (id);
 			g_free (comp_str);
 		}
 		g_object_unref (comp);
 	}
-//	e_file_cache_thaw_changes (E_FILE_CACHE (cache));
+	e_file_cache_thaw_changes (E_FILE_CACHE (priv->cache));
 
 //	g_slist_free (priv->cache_keys); 
 	priv->cache_keys = NULL;
 
-#if 0
-	filter = e_gw_filter_new ();
-	/* Items modified after the time-stamp */
-	e_gw_filter_add_filter_component (filter, E_GW_FILTER_OP_GREATERTHAN, "modified", time_string);
-	e_gw_filter_add_filter_component (filter, E_GW_FILTER_OP_EQUAL, "@type", get_element_type (kind));
-	e_gw_filter_group_conditions (filter, E_GW_FILTER_OP_AND, 2);
-
-	status = e_gw_connection_get_items (cnc, cbmapi->priv->container_id, "attachments recipients message recipientStatus default peek", filter, &item_list);
-	if (status == E_GW_CONNECTION_STATUS_INVALID_CONNECTION)
-		status = e_gw_connection_get_items (cnc, cbmapi->priv->container_id, "attachments recipients message recipientStatus default peek", filter, &item_list);
-	g_object_unref (filter);
-
-	if (status != E_GW_CONNECTION_STATUS_OK) {
-
-		const char *msg = NULL;
-
-		if (!attempts) {
-			e_cal_backend_cache_put_key_value (cache, key, "2");
-		} else {
-			int failures;
-			failures = g_ascii_strtod(attempts, NULL) + 1;
-			e_cal_backend_cache_put_key_value (cache, key, GINT_TO_POINTER (failures));
-		}
-
-		if (status == E_GW_CONNECTION_STATUS_NO_RESPONSE) { 
-			g_static_mutex_unlock (&updating);
-			return TRUE;
-		}
-
-		msg = e_gw_connection_get_error_message (status);
-
-		g_static_mutex_unlock (&updating);
-		return TRUE;
-	}
-#endif
-	temp = icaltime_from_string (time_string);
-	current_time = icaltime_as_timet_with_zone (temp, icaltimezone_get_utc_timezone ());
-	gmtime_r (&current_time, &tm);
-
-	time_interval = (CACHE_REFRESH_INTERVAL / 60000);
-	time_interval_string = g_getenv ("GETQM_TIME_INTERVAL");
-	if (time_interval_string) {
-		time_interval = g_ascii_strtod (time_interval_string, NULL);
-	} 
-
-	tm.tm_min += time_interval;
-
-	strftime (t_str, 26, "%Y-%m-%dT%H:%M:%SZ", &tm);
-	time_string = g_strdup (t_str);
-
-	e_cal_backend_cache_put_server_utc_time (cache, time_string);
-
-	g_free (time_string);
-	time_string = NULL;
-
 	g_static_mutex_unlock (&updating);
 	return TRUE;        
 }
 
-static gboolean
-get_deltas_timeout (gpointer cbmapi)
-{
-	GThread *thread;
-	GError *error = NULL;
-
-	if (!cbmapi)
-		return FALSE;
-
-	thread = g_thread_create ((GThreadFunc) get_deltas, cbmapi, FALSE, &error);
-	if (!thread) {
-		g_warning (G_STRLOC ": %s", error->message);
-		g_error_free (error);
-	}
-
-	return TRUE;
-}
-
-static GMutex *mutex = NULL;
-
-static gboolean
-cache_create_cb (struct mapi_SPropValue_array *properties, const mapi_id_t fid, const mapi_id_t mid, 
-		GSList *streams, GSList *recipients, GSList *attachments, gpointer data)
-{
-	ECalBackendMAPI *cbmapi	= E_CAL_BACKEND_MAPI (data);
-	ECalBackendMAPIPrivate *priv = cbmapi->priv;
-        ECalComponent *comp = NULL;
-	int i;
-	gchar *tmp = NULL;
-	const bool *recurring = NULL;
-
-	/* FIXME: Provide support for meetings/assigned tasks */
-	if (recipients != NULL) {
-		g_warning ("Calendar backend failed to parse a meeting");
-		return TRUE;
-	}
-
-	switch (e_cal_backend_get_kind (E_CAL_BACKEND (cbmapi))) {
-		case ICAL_VEVENT_COMPONENT:
-			/* FIXME: Provide backend support for recurrence */
-			recurring = (const bool *)find_mapi_SPropValue_data(properties, PROP_TAG(PT_BOOLEAN, 0x8223));
-			if (recurring && *recurring) {
-				g_warning ("Encountered a recurring event.");
-				return TRUE;
-			}
-			break;
-		case ICAL_VTODO_COMPONENT:
-			/* FIXME: Evolution does not support recurring tasks */
-			recurring = (const bool *)find_mapi_SPropValue_data(properties, PROP_TAG(PT_BOOLEAN, 0x8126));
-			if (recurring && *recurring) {
-				g_warning ("Encountered a recurring task.");
-				return TRUE;
-			}
-			break;
-		case ICAL_VJOURNAL_COMPONENT:
-			break;
-		default:
-			return FALSE; 
-	}
-	
-	tmp = exchange_mapi_util_mapi_id_to_string (mid);
-	comp = e_cal_backend_mapi_props_to_comp (cbmapi, tmp, properties, streams, recipients, attachments, priv->default_zone);
-	g_free (tmp);
-
-//	e_cal_backend_mapi_dump_properties (properties);
-
-	if (E_IS_CAL_COMPONENT (comp)) {
-		char *comp_str;
-
-		e_cal_component_commit_sequence (comp);
-		comp_str = e_cal_component_get_as_string (comp);	
-		e_cal_backend_notify_object_created (E_CAL_BACKEND (cbmapi), (const char *) comp_str);
-		g_free (comp_str);
-		e_cal_backend_cache_put_component (priv->cache, comp);
-		g_object_unref (comp);
-	}
-
-	return TRUE;
-}
-
 static ECalBackendSyncStatus
 e_cal_backend_mapi_get_default_object (ECalBackendSync *backend, EDataCal *cal, char **object)
 {
@@ -703,11 +644,11 @@
 	ECalBackendMAPIPrivate *priv;
 	ECalComponent *comp;
 
-	cbmapi = E_CAL_BACKEND_MAPI (backend);	
-	priv = cbmapi->priv;
-
+	cbmapi = (ECalBackendMAPI *)(backend);
 	g_return_val_if_fail (E_IS_CAL_BACKEND_MAPI (cbmapi), GNOME_Evolution_Calendar_OtherError);
 
+	priv = cbmapi->priv;
+
 	g_mutex_lock (priv->mutex);
 
 	/* search the object in the cache */
@@ -787,225 +728,249 @@
 	return GNOME_Evolution_Calendar_Success;
 }
 
-static ECalBackendSyncStatus
-populate_cache (ECalBackendMAPI *cbmapi)
+static guint
+get_cache_refresh_interval (void)
 {
+	guint time_interval;
+	const char *time_interval_string = NULL;
+	
+	time_interval = CACHE_REFRESH_INTERVAL;
+	time_interval_string = g_getenv ("GETQM_TIME_INTERVAL");
+	if (time_interval_string) {
+		time_interval = g_ascii_strtod (time_interval_string, NULL);
+		time_interval *= (60*1000);
+	}
+		
+	return time_interval;
+}
+
+static gpointer
+delta_thread (gpointer data)
+{
+	ECalBackendMAPI *cbmapi;
 	ECalBackendMAPIPrivate *priv;
-	ESource *source = NULL;
-        GList *list = NULL, *l;
-	gboolean done = FALSE,  forward = FALSE;
-	int cursor = 0;
-	guint32	total, num = 0;
-	int percent = 0, i;
-	icalcomponent_kind kind;
-//	const char *type;
-//	EGwFilter* filter[3];
-	char l_str[26]; 
-	char h_str[26];
-	icaltimetype temp;
-	struct tm tm;
-	time_t h_time, l_time;
-	gchar *progress_string = NULL;
+	GTimeVal timeout;
+
+	cbmapi = (ECalBackendMAPI *)(data);
+	g_return_val_if_fail (E_IS_CAL_BACKEND_MAPI (cbmapi), GINT_TO_POINTER (GNOME_Evolution_Calendar_OtherError));
 
 	priv = cbmapi->priv;
-	source = e_cal_backend_get_source (E_CAL_BACKEND (cbmapi));
-	kind = e_cal_backend_get_kind (E_CAL_BACKEND (cbmapi));
-	total = priv->total_count;
 
-	if (!mutex) {
-		mutex = g_mutex_new ();
+	timeout.tv_sec = 0;
+	timeout.tv_usec = 0;
+
+	while (TRUE)	{
+		gboolean succeeded = get_deltas (cbmapi);
+
+		g_mutex_lock (priv->dlock->mutex);
+
+		if (!succeeded || priv->dlock->exit) 
+			break;
+
+		g_get_current_time (&timeout);
+		g_time_val_add (&timeout, get_cache_refresh_interval () * 1000);
+		g_cond_timed_wait (priv->dlock->cond, priv->dlock->mutex, &timeout);
+		
+		if (priv->dlock->exit) 
+			break;	
+		
+		g_mutex_unlock (priv->dlock->mutex);
 	}
 
-	g_mutex_lock (mutex);
+	g_mutex_unlock (priv->dlock->mutex);
+	priv->dthread = NULL;	
+	return NULL;
+}
 
-//	type = get_element_type (kind);	
-
-	/* Fetch the data with a bias to present, near past/future */
-	temp = icaltime_current_time_with_zone (icaltimezone_get_utc_timezone ());
-	i = g_ascii_strtod (g_getenv ("PRELOAD_WINDOW_DAYS")? g_getenv ("PRELOAD_WINDOW_DAYS"):"15", NULL);
-	temp.day -= i;
-	icaltime_normalize (temp);
-	l_time = icaltime_as_timet_with_zone (temp, icaltimezone_get_utc_timezone ());
-	gmtime_r (&l_time, &tm);
-	strftime (l_str, 26, "%Y-%m-%dT%H:%M:%SZ", &tm);
-	temp.day += (2*i);
-	icaltime_normalize (temp);
-	h_time = icaltime_as_timet_with_zone (temp, icaltimezone_get_utc_timezone ());
-	gmtime_r (&h_time, &tm);
-	strftime (h_str, 26, "%Y-%m-%dT%H:%M:%SZ", &tm);
-#if 0
-	filter[0] = e_gw_filter_new ();
-	e_gw_filter_add_filter_component (filter[0], E_GW_FILTER_OP_GREATERTHAN_OR_EQUAL, "startDate", l_str);
-	e_gw_filter_add_filter_component (filter[0], E_GW_FILTER_OP_LESSTHAN_OR_EQUAL, "startDate", h_str);
-	e_gw_filter_add_filter_component (filter[0], E_GW_FILTER_OP_EQUAL, "@type", type);
-	e_gw_filter_group_conditions (filter[0], E_GW_FILTER_OP_AND, 3);
-	filter[1] = e_gw_filter_new ();
-	e_gw_filter_add_filter_component (filter[1], E_GW_FILTER_OP_GREATERTHAN, "startDate", h_str);
-	e_gw_filter_add_filter_component (filter[1], E_GW_FILTER_OP_EQUAL, "@type", type);
-	e_gw_filter_group_conditions (filter[1], E_GW_FILTER_OP_AND, 2);
-	filter[2] = e_gw_filter_new ();
-	e_gw_filter_add_filter_component (filter[2], E_GW_FILTER_OP_LESSTHAN, "startDate", l_str);
-	e_gw_filter_add_filter_component (filter[2], E_GW_FILTER_OP_EQUAL, "@type", type);
-	e_gw_filter_group_conditions (filter[2], E_GW_FILTER_OP_AND, 2);
-
-	for (i = 0; i < 3; i++) {
-		status = e_gw_connection_create_cursor (priv->cnc,
-				priv->container_id, 
-				"recipients message recipientStatus attachments default peek", filter[i], &cursor);
-		if (status != E_GW_CONNECTION_STATUS_OK) {
-			e_cal_backend_groupwise_notify_error_code (cbmapi, status);
-			g_mutex_unlock (mutex);
-			return status;
-		}
-		done = FALSE;
-		if (i == 1) {
-			position = E_GW_CURSOR_POSITION_START;
-			forward = TRUE;
+static gboolean
+fetch_deltas (ECalBackendMAPI *cbmapi)
+{
+	ECalBackendMAPIPrivate *priv;
+	GError *error = NULL;
 
-		} else {
-			position = E_GW_CURSOR_POSITION_END;
-			forward = FALSE;
-		}
-			
-		while (!done) {
-			status = e_gw_connection_read_cursor (priv->cnc, priv->container_id, cursor, forward, CURSOR_ITEM_LIMIT, position, &list);
-			if (status != E_GW_CONNECTION_STATUS_OK) {
-				e_cal_backend_groupwise_notify_error_code (cbmapi, status);
-				g_mutex_unlock (mutex);
-				return status;
+	g_return_val_if_fail (E_IS_CAL_BACKEND_MAPI (cbmapi), GNOME_Evolution_Calendar_OtherError);
+
+	priv = cbmapi->priv;
+
+	/* If the thread is already running just return back */	
+	if (priv->dthread) 
+		return FALSE;
+	
+	if (!priv->dlock) {
+		priv->dlock = g_new0 (SyncDelta, 1);
+		priv->dlock->mutex = g_mutex_new ();
+		priv->dlock->cond = g_cond_new ();
+	}
+	
+	priv->dlock->exit = FALSE;
+	priv->dthread = g_thread_create ((GThreadFunc) delta_thread, cbmapi, TRUE, &error);
+	if (!priv->dthread) {
+		g_warning (G_STRLOC ": %s", error->message);
+		g_error_free (error);
+	}
+
+	return TRUE;
+}
+
+
+static gboolean
+start_fetch_deltas (gpointer data)
+{
+	ECalBackendMAPI *cbmapi;
+	ECalBackendMAPIPrivate *priv;
+
+	cbmapi = (ECalBackendMAPI *)(data);
+	g_return_val_if_fail (E_IS_CAL_BACKEND_MAPI (cbmapi), GNOME_Evolution_Calendar_OtherError);
+
+	priv = cbmapi->priv;
+
+	fetch_deltas (cbmapi);
+
+	priv->timeout_id = 0;
+
+	return FALSE;
+}
+
+static gboolean
+cache_create_cb (struct mapi_SPropValue_array *properties, const mapi_id_t fid, const mapi_id_t mid, 
+		 GSList *streams, GSList *recipients, GSList *attachments, gpointer data)
+{
+	ECalBackendMAPI *cbmapi	= E_CAL_BACKEND_MAPI (data);
+	ECalBackendMAPIPrivate *priv = cbmapi->priv;
+        ECalComponent *comp = NULL;
+	gchar *tmp = NULL;
+	const bool *recurring = NULL;
+
+//	e_cal_backend_mapi_util_dump_properties (properties);
+
+	/* FIXME: Provide support for meetings/assigned tasks */
+	if (recipients != NULL) {
+		g_warning ("Calendar backend failed to parse a meeting");
+		return TRUE;
+	}
+
+	switch (e_cal_backend_get_kind (E_CAL_BACKEND (cbmapi))) {
+		case ICAL_VEVENT_COMPONENT:
+			/* FIXME: Provide backend support for recurrence */
+			recurring = (const bool *)find_mapi_SPropValue_data(properties, PROP_TAG(PT_BOOLEAN, 0x8223));
+			if (recurring && *recurring) {
+				g_warning ("Encountered a recurring event.");
+				return TRUE;
 			}
-			for (l = list; l != NULL; l = g_list_next(l)) {
-				EGwItem *item;
-				char *progress_string = NULL;
-
-				item = E_GW_ITEM (l->data);
-				comp = e_gw_item_to_cal_component (item, cbmapi);
-				g_object_unref (item);
-				
-				/* Show the progress information */
-				num++;
-				percent = ((float) num/total) * 100;
-
-				/* FIXME The total obtained from the server is wrong. Sometimes the num can 
-				be greater than the total. The following makes sure that the percentage is not >= 100 */
-
-				if (percent > 100)
-					percent = 99; 
-
-				progress_string = g_strdup_printf (_("Loading %s items"), e_source_peek_name (source));
-				e_cal_backend_notify_view_progress (E_CAL_BACKEND (cbmapi), progress_string, percent);
-
-				if (E_IS_CAL_COMPONENT (comp)) {
-					char *comp_str;
-
-					e_cal_component_commit_sequence (comp);
-					comp_str = e_cal_component_get_as_string (comp);	
-					e_cal_backend_notify_object_created (E_CAL_BACKEND (cbmapi), (const char *) comp_str);
-					g_free (comp_str);
-					e_cal_backend_cache_put_component (priv->cache, comp);
-					g_object_unref (comp);
-				}
-				g_free (progress_string);
+			break;
+		case ICAL_VTODO_COMPONENT:
+			/* FIXME: Evolution does not support recurring tasks */
+			recurring = (const bool *)find_mapi_SPropValue_data(properties, PROP_TAG(PT_BOOLEAN, 0x8126));
+			if (recurring && *recurring) {
+				g_warning ("Encountered a recurring task.");
+				return TRUE;
 			}
+			break;
+		case ICAL_VJOURNAL_COMPONENT:
+			break;
+		default:
+			return FALSE; 
+	}
+	
+	tmp = exchange_mapi_util_mapi_id_to_string (mid);
+	comp = e_cal_backend_mapi_props_to_comp (cbmapi, tmp, properties, streams, recipients, attachments, priv->default_zone);
+	g_free (tmp);
 
-			if (!list  || g_list_length (list) == 0)
-				done = TRUE;
-			g_list_free (list);
-			list = NULL;
-			position = E_GW_CURSOR_POSITION_CURRENT;
-		}
-		e_gw_connection_destroy_cursor (priv->cnc, priv->container_id, cursor);
-		g_object_unref (filter[i]);
+	if (E_IS_CAL_COMPONENT (comp)) {
+		gchar *comp_str;
+		e_cal_component_commit_sequence (comp);
+		comp_str = e_cal_component_get_as_string (comp);	
+		e_cal_backend_notify_object_created (E_CAL_BACKEND (cbmapi), (const char *) comp_str);
+		g_free (comp_str);
+		e_cal_backend_cache_put_component (priv->cache, comp);
+		g_object_unref (comp);
 	}
-#endif
+
+	return TRUE;
+}
+
+static ECalBackendSyncStatus
+populate_cache (ECalBackendMAPI *cbmapi)
+{
+	ECalBackendMAPIPrivate *priv;
+	ESource *source = NULL;
+	icalcomponent_kind kind;
+	gchar *progress_string = NULL;
+	icaltimetype itt_current; 
+	time_t current_time;
+	struct tm tm;
+	gchar *time_string = NULL;
+	gchar t_str [26]; 
+
+	priv = cbmapi->priv;
+	source = e_cal_backend_get_source (E_CAL_BACKEND (cbmapi));
+	kind = e_cal_backend_get_kind (E_CAL_BACKEND (cbmapi));
+
+	g_mutex_lock (priv->mutex);
 
 	progress_string = g_strdup_printf (_("Loading %s items"), e_source_peek_name (source));
 	/*  FIXME: Is there a way to update progress within the callback that follows ? */
 	e_cal_backend_notify_view_progress (E_CAL_BACKEND (cbmapi), progress_string, 99);
 
+	itt_current = icaltime_current_time_with_zone (icaltimezone_get_utc_timezone ());
+	current_time = icaltime_as_timet_with_zone (itt_current, icaltimezone_get_utc_timezone ());
+	gmtime_r (&current_time, &tm);
+	strftime (t_str, 26, "%Y-%m-%dT%H:%M:%SZ", &tm);
+
 //	e_file_cache_freeze_changes (E_FILE_CACHE (priv->cache));
 	if (!exchange_mapi_connection_fetch_items (priv->fid, GetPropsList, n_GetPropsList, mapi_cal_build_name_id, NULL, cache_create_cb, cbmapi, MAPI_OPTIONS_FETCH_ALL)) {
 		e_cal_backend_notify_error (E_CAL_BACKEND (cbmapi), _("Could not create cache file"));
 		e_file_cache_thaw_changes (E_FILE_CACHE (priv->cache));
 		g_free (progress_string);
+		g_mutex_unlock (priv->mutex);
 		return GNOME_Evolution_Calendar_OtherError;
 	}
 //	e_file_cache_thaw_changes (E_FILE_CACHE (priv->cache));
 
-	e_cal_backend_notify_view_done (E_CAL_BACKEND (cbmapi), GNOME_Evolution_Calendar_Success);
+	time_string = g_strdup (t_str);
+	e_cal_backend_cache_put_server_utc_time (priv->cache, time_string);
+	g_free (time_string);
+
+	e_cal_backend_cache_set_marker (priv->cache);
 
+	e_cal_backend_notify_view_done (E_CAL_BACKEND (cbmapi), GNOME_Evolution_Calendar_Success);
 	g_free (progress_string);
-	g_mutex_unlock (mutex);
+	g_mutex_unlock (priv->mutex);
+
 	return GNOME_Evolution_Calendar_Success;
 }
 
-static ECalBackendSyncStatus
+static gpointer
 cache_init (ECalBackendMAPI *cbmapi)
 {
 	ECalBackendMAPIPrivate *priv = cbmapi->priv;
-	ECalBackendSyncStatus status;
 	icalcomponent_kind kind;
-	const char *time_interval_string;
-	int time_interval;
+	ECalBackendSyncStatus status; 
 
 	kind = e_cal_backend_get_kind (E_CAL_BACKEND (cbmapi));
 
-	time_interval = CACHE_REFRESH_INTERVAL;
-	time_interval_string = g_getenv ("GETQM_TIME_INTERVAL");
-	if (time_interval_string) {
-		time_interval = g_ascii_strtod (time_interval_string, NULL);
-		time_interval *= (60*1000); 
-	}
+	priv->mode = CAL_MODE_REMOTE;
 
-	/* We poke the cache for a default timezone. Its
-	 * absence indicates that the cache file has not been
-	 * populated before. */
 	if (!e_cal_backend_cache_get_marker (priv->cache)) {
 		/* Populate the cache for the first time.*/
-		/* start a timed polling thread set to 1 minute*/
 		status = populate_cache (cbmapi);
 		if (status != GNOME_Evolution_Calendar_Success) {
 			g_warning (G_STRLOC ": Could not populate the cache");
 			/*FIXME  why dont we do a notify here */
-			return GNOME_Evolution_Calendar_PermissionDenied;
+			return GINT_TO_POINTER(GNOME_Evolution_Calendar_PermissionDenied);
 		} else {
-			gchar *time_string = NULL;
-			time_t current_time;
-			icaltimetype tmp;
-			struct tm tm;
-			char t_str [26]; 
-
-			tmp = icaltime_current_time_with_zone (icaltimezone_get_utc_timezone ());
-			current_time = icaltime_as_timet_with_zone (tmp, icaltimezone_get_utc_timezone ());
-			gmtime_r (&current_time, &tm);
-			strftime (t_str, 26, "%Y-%m-%dT%H:%M:%SZ", &tm);
-			time_string = g_strdup (t_str);
- 
-			e_cal_backend_cache_set_marker (priv->cache);
-			e_cal_backend_cache_put_server_utc_time (priv->cache, time_string);
-			/* FIXME: not the right thing to do + do we have to free other stuff here ? */
-			g_free (time_string);
-
 			/*  Set delta fetch timeout */
-			priv->timeout_id = g_timeout_add (time_interval, (GSourceFunc) get_deltas_timeout, (gpointer) cbmapi);
-			priv->mode = CAL_MODE_REMOTE;
+			priv->timeout_id = g_timeout_add (get_cache_refresh_interval (), start_fetch_deltas, (gpointer) cbmapi);
 
-			return GNOME_Evolution_Calendar_Success;
-		}
-	} else {
-		/* get the deltas from the cache */
-		if (get_deltas (cbmapi)) {
-			priv->timeout_id = g_timeout_add (time_interval, (GSourceFunc) get_deltas_timeout, (gpointer) cbmapi);
-			priv->mode = CAL_MODE_REMOTE;
-			return GNOME_Evolution_Calendar_Success;
-		} else {
-			g_warning (G_STRLOC ": Could not populate the cache");
-			/*FIXME  why dont we do a notify here */
-			return GNOME_Evolution_Calendar_PermissionDenied;	
+			return NULL;
 		}
 	}
 
-	return GNOME_Evolution_Calendar_Success;
+	g_mutex_lock (priv->mutex);
+	fetch_deltas (cbmapi);
+	g_mutex_unlock (priv->mutex);
+
+	return NULL;
 }
 
 static ECalBackendSyncStatus
@@ -1021,28 +986,20 @@
 
 	source = e_cal_backend_get_source (E_CAL_BACKEND (cbmapi));
 
-	/* FIXME: check status and respond */
-	if (!authenticated)
-		e_cal_backend_mapi_authenticate (E_CAL_BACKEND (cbmapi));
+	if (!authenticated) {
+		e_cal_backend_notify_error (E_CAL_BACKEND (cbmapi), _("Authentication failed"));
+		return GNOME_Evolution_Calendar_AuthenticationFailed; 
+	}
 
 	/* We have established a connection */
-	if (authenticated && priv->cache && priv->fid) {
+	if (priv->cache && priv->fid) {
 		priv->mode = CAL_MODE_REMOTE;
 		priv->total_count = exchange_mapi_folder_get_total_count (exchange_mapi_folder_get_folder (priv->fid));
-		if (priv->mode_changed && !priv->timeout_id ) {
-			GThread *thread1;
+		if (priv->mode_changed && !priv->dthread) {
 			priv->mode_changed = FALSE;
-
-			thread1 = g_thread_create ((GThreadFunc) get_deltas, cbmapi, FALSE, &error);
-			if (!thread1) {
-				g_warning (G_STRLOC ": %s", error->message);
-				g_error_free (error);
-
-				e_cal_backend_notify_error (E_CAL_BACKEND (cbmapi), _("Could not create thread for getting deltas"));
-				return GNOME_Evolution_Calendar_OtherError;
-			}
-			priv->timeout_id = g_timeout_add (CACHE_REFRESH_INTERVAL, (GSourceFunc) get_deltas_timeout, (gpointer)cbmapi);
+			fetch_deltas (cbmapi);
 		}
+
 		/* FIXME: put server UTC time in cache */
 		return GNOME_Evolution_Calendar_Success;
 	}
@@ -1066,7 +1023,6 @@
 
 	priv->cache = e_cal_backend_cache_new (e_cal_backend_get_uri (E_CAL_BACKEND (cbmapi)), source_type);
 	if (!priv->cache) {
-//		g_mutex_unlock (priv->mutex);
 		e_cal_backend_notify_error (E_CAL_BACKEND (cbmapi), _("Could not create cache file"));
 		return GNOME_Evolution_Calendar_OtherError;
 	}
@@ -1078,7 +1034,6 @@
 	if (!thread) {
 		g_warning (G_STRLOC ": %s", error->message);
 		g_error_free (error);
-
 		e_cal_backend_notify_error (E_CAL_BACKEND (cbmapi), _("Could not create thread for populating cache"));
 		return GNOME_Evolution_Calendar_OtherError;
 	} 
@@ -1151,7 +1106,6 @@
 			if (!priv->cache) {
 				g_mutex_unlock (priv->mutex);
 				e_cal_backend_notify_error (E_CAL_BACKEND (cbmapi), _("Could not create cache file"));
-				
 				return GNOME_Evolution_Calendar_OtherError;
 			}
 		}
@@ -1188,9 +1142,12 @@
 		g_filename_to_uri (filename, NULL, NULL);
 	g_free (filename);
 
-	status = e_cal_backend_mapi_authenticate (E_CAL_BACKEND (cbmapi));
 	g_mutex_unlock (priv->mutex);
 
+	g_static_mutex_lock (&auth_mutex);
+	status = e_cal_backend_mapi_authenticate (E_CAL_BACKEND (cbmapi));
+	g_static_mutex_unlock (&auth_mutex); 
+
 	if (status == GNOME_Evolution_Calendar_Success)
 		return e_cal_backend_mapi_connect (cbmapi);
 	else
@@ -1502,7 +1459,7 @@
 	if (!icalcomp)
 		return GNOME_Evolution_Calendar_InvalidObject;
 
-	*object = g_strdup (icalcomponent_as_ical_string (icalcomp));
+	*object = icalcomponent_as_ical_string (icalcomp);
 
 	return GNOME_Evolution_Calendar_Success;
 }
@@ -1580,12 +1537,118 @@
 
 }
 
-static ECalBackendSyncStatus 
+typedef struct {
+	ECalBackendMAPI *backend;
+	icalcomponent_kind kind;
+	GList *deletes;
+	EXmlHash *ehash;
+} ECalBackendMAPIComputeChangesData;
+
+static void
+e_cal_backend_mapi_compute_changes_foreach_key (const char *key, const char *value, gpointer data)
+{
+	ECalBackendMAPIComputeChangesData *be_data = data;
+
+	if (!e_cal_backend_cache_get_component (be_data->backend->priv->cache, key, NULL)) {
+		ECalComponent *comp;
+
+		comp = e_cal_component_new ();
+		if (be_data->kind == ICAL_VTODO_COMPONENT)
+			e_cal_component_set_new_vtype (comp, E_CAL_COMPONENT_TODO);
+		else
+			e_cal_component_set_new_vtype (comp, E_CAL_COMPONENT_EVENT);
+
+		e_cal_component_set_uid (comp, key);
+		be_data->deletes = g_list_prepend (be_data->deletes, e_cal_component_get_as_string (comp));
+
+		e_xmlhash_remove (be_data->ehash, key);
+		g_object_unref (comp);
+ 	}
+}
+
+static ECalBackendSyncStatus
+e_cal_backend_mapi_compute_changes (ECalBackendMAPI *cbmapi, const char *change_id,
+				    GList **adds, GList **modifies, GList **deletes)
+{
+	ECalBackendSyncStatus status;
+	ECalBackendCache *cache;
+	gchar *filename;
+	EXmlHash *ehash;
+	ECalBackendMAPIComputeChangesData be_data;
+	GList *i, *list = NULL;
+	gchar *unescaped_uri;
+
+	cache = cbmapi->priv->cache;
+
+	/* FIXME Will this always work? */
+	unescaped_uri = g_uri_unescape_string (cbmapi->priv->uri, "");
+	filename = g_strdup_printf ("%s-%s.db", unescaped_uri, change_id);
+	ehash = e_xmlhash_new (filename);
+	g_free (filename);
+	g_free (unescaped_uri);
+
+        status = e_cal_backend_mapi_get_object_list (E_CAL_BACKEND_SYNC (cbmapi), NULL, "#t", &list);
+        if (status != GNOME_Evolution_Calendar_Success)
+                return status;
+
+        /* Calculate adds and modifies */
+	for (i = list; i != NULL; i = g_list_next (i)) {
+		const char *uid;
+		char *calobj;
+		ECalComponent *comp;
+
+		comp = e_cal_component_new_from_string (i->data);
+		e_cal_component_get_uid (comp, &uid);
+		calobj = i->data;
+
+		g_assert (calobj != NULL);
+
+		/* check what type of change has occurred, if any */
+		switch (e_xmlhash_compare (ehash, uid, calobj)) {
+		case E_XMLHASH_STATUS_SAME:
+			break;
+		case E_XMLHASH_STATUS_NOT_FOUND:
+			*adds = g_list_prepend (*adds, g_strdup (calobj));
+			e_xmlhash_add (ehash, uid, calobj);
+			break;
+		case E_XMLHASH_STATUS_DIFFERENT:
+			*modifies = g_list_prepend (*modifies, g_strdup (calobj));
+			e_xmlhash_add (ehash, uid, calobj);
+			break;
+		}
+
+		g_free (calobj);
+		g_object_unref (comp);
+	}
+	g_list_free (list);
+
+	/* Calculate deletions */
+	be_data.backend = cbmapi;
+	be_data.kind = e_cal_backend_get_kind (E_CAL_BACKEND (cbmapi));
+	be_data.deletes = NULL;
+	be_data.ehash = ehash;
+   	e_xmlhash_foreach_key (ehash, (EXmlHashFunc)e_cal_backend_mapi_compute_changes_foreach_key, &be_data);
+
+	*deletes = be_data.deletes;
+
+	e_xmlhash_write (ehash);
+  	e_xmlhash_destroy (ehash);
+
+	return GNOME_Evolution_Calendar_Success;
+}
+
+static ECalBackendSyncStatus
 e_cal_backend_mapi_get_changes (ECalBackendSync *backend, EDataCal *cal, const char *change_id,
 				GList **adds, GList **modifies, GList **deletes)
 {
+	ECalBackendMAPI *cbmapi;
 
-	return GNOME_Evolution_Calendar_Success;
+	cbmapi = E_CAL_BACKEND_MAPI (backend);
+
+	g_return_val_if_fail (E_IS_CAL_BACKEND_MAPI (cbmapi), GNOME_Evolution_Calendar_InvalidObject);
+	g_return_val_if_fail (change_id != NULL, GNOME_Evolution_Calendar_ObjectNotFound);
+
+	return e_cal_backend_mapi_compute_changes (cbmapi, change_id, adds, modifies, deletes);
 
 }
 
@@ -1706,6 +1769,10 @@
 	icaltimezone *zone;
 
 	zone = icaltimezone_get_builtin_timezone_from_tzid (tzid);
+
+	if (!zone && E_CAL_BACKEND_CLASS (parent_class)->internal_get_timezone)
+		zone = E_CAL_BACKEND_CLASS (parent_class)->internal_get_timezone (backend, tzid);
+
 	if (!zone)
 		return icaltimezone_get_utc_timezone ();
 



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