[evolution-data-server] CalDAV fixes/improvements



commit 5bb20ac7b26a125b130e799548efcc27ef67adf5
Author: Milan Crha <mcrha redhat com>
Date:   Wed Jun 24 21:17:00 2009 +0200

    CalDAV fixes/improvements
    
     - store CTag at the fully finished sync, not before
     - listen for ESource changes
     - less aggressive locking
     - sync can be interrupted
     - create/modify/remove operations have precedence before the sync

 calendar/backends/caldav/e-cal-backend-caldav.c |  339 ++++++++++++++---------
 1 files changed, 209 insertions(+), 130 deletions(-)
---
diff --git a/calendar/backends/caldav/e-cal-backend-caldav.c b/calendar/backends/caldav/e-cal-backend-caldav.c
index 4475be7..6266f83 100644
--- a/calendar/backends/caldav/e-cal-backend-caldav.c
+++ b/calendar/backends/caldav/e-cal-backend-caldav.c
@@ -77,8 +77,10 @@ struct _ECalBackendCalDAVPrivate {
 	/* TRUE after caldav_open */
 	gboolean loaded;
 
+	/* lock to indicate a busy state */
+	GMutex *busy_lock;
 	/* lock to protect cache */
-	GMutex *lock;
+	GStaticRecMutex cache_lock;
 
 	/* cond to synch threads */
 	GCond *cond;
@@ -89,8 +91,8 @@ struct _ECalBackendCalDAVPrivate {
 	/* BG synch thread */
 	const GThread *synch_slave; /* just for a reference, whether thread exists */
 	SlaveCommand slave_cmd;
+	gboolean slave_busy; /* whether is slave working */
 	GTimeVal refresh_time;
-	gboolean do_synch;
 
 	/* The main soup session  */
 	SoupSession *session;
@@ -114,6 +116,7 @@ struct _ECalBackendCalDAVPrivate {
 
 	/* support for 'getctag' extension */
 	gboolean ctag_supported;
+	gchar *ctag_to_store;
 
 	/* TRUE when 'calendar-schedule' supported on the server */
 	gboolean calendar_schedule;
@@ -251,6 +254,7 @@ static ECalBackendSyncClass *parent_class = NULL;
 
 static icaltimezone *caldav_internal_get_default_timezone (ECalBackend *backend);
 static icaltimezone *caldav_internal_get_timezone (ECalBackend *backend, const gchar *tzid);
+static void caldav_source_changed_cb (ESource *source, ECalBackendCalDAV *cbdav);
 
 static gboolean remove_comp_from_cache (ECalBackendCalDAV *cbdav, const gchar *uid, const gchar *rid);
 static gboolean put_comp_to_cache (ECalBackendCalDAV *cbdav, icalcomponent *icalcomp, const gchar *href, const gchar *etag);
@@ -976,7 +980,6 @@ caldav_server_open_calendar (ECalBackendCalDAV *cbdav)
 
 	if (calendar_access) {
 		priv->read_only = ! (put_allowed && delete_allowed);
-		priv->do_synch = TRUE;
 		return GNOME_Evolution_Calendar_Success;
 	}
 
@@ -1049,13 +1052,20 @@ check_calendar_changed_on_server (ECalBackendCalDAV *cbdav)
 		gchar *ctag = NULL;
 
 		if (parse_propfind_response (message, XPATH_GETCTAG_STATUS, XPATH_GETCTAG, &ctag)) {
-			const gchar *my_ctag = e_cal_backend_cache_get_key_value (priv->cache, CALDAV_CTAG_KEY);
+			const gchar *my_ctag;
+
+			g_static_rec_mutex_lock (&priv->cache_lock);
+			my_ctag = e_cal_backend_cache_get_key_value (priv->cache, CALDAV_CTAG_KEY);
+			g_static_rec_mutex_unlock (&priv->cache_lock);
 
 			if (ctag && my_ctag && g_str_equal (ctag, my_ctag)) {
 				/* ctag is same, no change in the calendar */
 				result = FALSE;
 			} else {
-				e_cal_backend_cache_put_key_value (priv->cache, CALDAV_CTAG_KEY, ctag);
+				/* do not store ctag now, do it rather after complete sync */
+				g_free (priv->ctag_to_store);
+				priv->ctag_to_store = ctag;
+				ctag = NULL;
 			}
 
 			g_free (ctag);
@@ -1678,7 +1688,10 @@ synchronize_cache (ECalBackendCalDAV *cbdav)
 		return;
 
 	hindex = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL);
+
+	g_static_rec_mutex_lock (&priv->cache_lock);
 	cobjs = e_cal_backend_cache_get_components (bcache);
+	g_static_rec_mutex_unlock (&priv->cache_lock);
 
 	/* build up a index for the href entry */
 	for (citer = cobjs; citer; citer = g_list_next (citer)) {
@@ -1702,7 +1715,7 @@ synchronize_cache (ECalBackendCalDAV *cbdav)
 	}
 
 	/* see if we have to update or add some objects */
-	for (i = 0, object = sobjs; i < len; i++, object++) {
+	for (i = 0, object = sobjs; i < len && priv->slave_cmd == SLAVE_SHOULD_WORK; i++, object++) {
 		ECalComponent *ccomp;
 		gchar *etag = NULL;
 
@@ -1792,6 +1805,18 @@ synchronize_cache (ECalBackendCalDAV *cbdav)
 		g_object_unref (old_comp);
 	}
 
+	if (priv->ctag_to_store) {
+		/* store only when wasn't interrupted */
+		if (priv->slave_cmd == SLAVE_SHOULD_WORK) {
+			g_static_rec_mutex_lock (&priv->cache_lock);
+			e_cal_backend_cache_put_key_value (priv->cache, CALDAV_CTAG_KEY, priv->ctag_to_store);
+			g_static_rec_mutex_unlock (&priv->cache_lock);
+		}
+
+		g_free (priv->ctag_to_store);
+		priv->ctag_to_store = NULL;
+	}
+
 	g_hash_table_destroy (hindex);
 	g_list_free (cobjs);
 	g_list_free (created);
@@ -1809,13 +1834,13 @@ synch_slave_loop (gpointer data)
 	cbdav = E_CAL_BACKEND_CALDAV (data);
 	priv = E_CAL_BACKEND_CALDAV_GET_PRIVATE (cbdav);
 
-	g_mutex_lock (priv->lock);
+	g_mutex_lock (priv->busy_lock);
 
 	while (priv->slave_cmd != SLAVE_SHOULD_DIE) {
 		GTimeVal alarm_clock;
 		if (priv->slave_cmd == SLAVE_SHOULD_SLEEP) {
 			/* just sleep until we get woken up again */
-			g_cond_wait (priv->cond, priv->lock);
+			g_cond_wait (priv->cond, priv->busy_lock);
 
 			/* check if we should die, work or sleep again */
 			continue;
@@ -1824,13 +1849,15 @@ synch_slave_loop (gpointer data)
 		/* Ok here we go, do some real work
 		 * Synch it baby one more time ...
 		 */
+		priv->slave_busy = TRUE;
 		synchronize_cache (cbdav);
+		priv->slave_busy = FALSE;
 
 		/* puhh that was hard, get some rest :) */
 		g_get_current_time (&alarm_clock);
 		alarm_clock.tv_sec += priv->refresh_time.tv_sec;
 		g_cond_timed_wait (priv->cond,
-				   priv->lock,
+				   priv->busy_lock,
 				   &alarm_clock);
 
 	}
@@ -1841,7 +1868,7 @@ synch_slave_loop (gpointer data)
 	priv->synch_slave = NULL;
 
 	/* we got killed ... */
-	g_mutex_unlock (priv->lock);
+	g_mutex_unlock (priv->busy_lock);
 	return NULL;
 }
 
@@ -1927,6 +1954,9 @@ initialize_backend (ECalBackendCalDAV *cbdav)
 	result = GNOME_Evolution_Calendar_Success;
 	source = e_cal_backend_get_source (E_CAL_BACKEND (cbdav));
 
+	if (!g_signal_handler_find (G_OBJECT (source), G_SIGNAL_MATCH_FUNC | G_SIGNAL_MATCH_DATA, 0, 0, NULL, caldav_source_changed_cb, cbdav))
+		g_signal_connect (G_OBJECT (source), "changed", G_CALLBACK (caldav_source_changed_cb), cbdav);
+
 	os_val = e_source_get_property (source, "offline_sync");
 
 	if (!os_val || !g_str_equal (os_val, "1")) {
@@ -2072,7 +2102,7 @@ caldav_do_open (ECalBackendSync *backend,
 
 	status = GNOME_Evolution_Calendar_Success;
 
-	g_mutex_lock (priv->lock);
+	g_mutex_lock (priv->busy_lock);
 
 	/* let it decide the 'getctag' extension availability again */
 	priv->ctag_supported = TRUE;
@@ -2082,13 +2112,13 @@ caldav_do_open (ECalBackendSync *backend,
 	}
 
 	if (status != GNOME_Evolution_Calendar_Success) {
-		g_mutex_unlock (priv->lock);
+		g_mutex_unlock (priv->busy_lock);
 		return status;
 	}
 
 	if (priv->need_auth) {
 		if ((username == NULL || password == NULL)) {
-			g_mutex_unlock (priv->lock);
+			g_mutex_unlock (priv->busy_lock);
 			return GNOME_Evolution_Calendar_AuthenticationRequired;
 		}
 
@@ -2099,7 +2129,7 @@ caldav_do_open (ECalBackendSync *backend,
 	}
 
 	if (!priv->do_offline && priv->mode == CAL_MODE_LOCAL) {
-		g_mutex_unlock (priv->lock);
+		g_mutex_unlock (priv->busy_lock);
 		return GNOME_Evolution_Calendar_RepositoryOffline;
 	}
 
@@ -2119,7 +2149,7 @@ caldav_do_open (ECalBackendSync *backend,
 		priv->read_only = TRUE;
 	}
 
-	g_mutex_unlock (priv->lock);
+	g_mutex_unlock (priv->busy_lock);
 
 	return status;
 }
@@ -2136,10 +2166,13 @@ caldav_remove (ECalBackendSync *backend,
 	cbdav = E_CAL_BACKEND_CALDAV (backend);
 	priv  = E_CAL_BACKEND_CALDAV_GET_PRIVATE (cbdav);
 
-	g_mutex_lock (priv->lock);
+	/* first tell it to die, then wait for its lock */
+	priv->slave_cmd = SLAVE_SHOULD_DIE;
+
+	g_mutex_lock (priv->busy_lock);
 
 	if (!priv->loaded) {
-		g_mutex_unlock (priv->lock);
+		g_mutex_unlock (priv->busy_lock);
 		return GNOME_Evolution_Calendar_Success;
 	}
 
@@ -2152,20 +2185,20 @@ caldav_remove (ECalBackendSync *backend,
 	e_file_cache_remove (E_FILE_CACHE (priv->cache));
 	priv->cache  = NULL;
 	priv->loaded = FALSE;
-	priv->slave_cmd = SLAVE_SHOULD_DIE;
 
 	if (priv->synch_slave) {
 		g_cond_signal (priv->cond);
 
 		/* wait until the slave died */
-		g_cond_wait (priv->slave_gone_cond, priv->lock);
+		g_cond_wait (priv->slave_gone_cond, priv->busy_lock);
 	}
 
-	g_mutex_unlock (priv->lock);
+	g_mutex_unlock (priv->busy_lock);
 
 	return GNOME_Evolution_Calendar_Success;
 }
 
+/* has priv->cache_lock locked already */
 static void
 remove_comp_from_cache_cb (gpointer value, gpointer user_data)
 {
@@ -2191,6 +2224,8 @@ remove_comp_from_cache (ECalBackendCalDAV *cbdav, const gchar *uid, const gchar
 
 	priv  = E_CAL_BACKEND_CALDAV_GET_PRIVATE (cbdav);
 
+	g_static_rec_mutex_lock (&priv->cache_lock);
+
 	if (!rid || !*rid) {
 		/* get with detached instances */
 		GSList *objects = e_cal_backend_cache_get_components_by_uid (priv->cache, uid);
@@ -2206,6 +2241,8 @@ remove_comp_from_cache (ECalBackendCalDAV *cbdav, const gchar *uid, const gchar
 		res = e_cal_backend_cache_remove_component (priv->cache, uid, rid);
 	}
 
+	g_static_rec_mutex_unlock (&priv->cache_lock);
+
 	return res;
 }
 
@@ -2340,8 +2377,10 @@ put_comp_to_cache (ECalBackendCalDAV *cbdav, icalcomponent *icalcomp, const gcha
 				if (etag)
 					ecalcomp_set_etag (comp, etag);
 
+				g_static_rec_mutex_lock (&priv->cache_lock);
 				if (e_cal_backend_cache_put_component (priv->cache, comp))
 					res = TRUE;
+				g_static_rec_mutex_unlock (&priv->cache_lock);
 			}
 		}
 	} else if (icalcomponent_isa (icalcomp) == my_kind) {
@@ -2353,7 +2392,9 @@ put_comp_to_cache (ECalBackendCalDAV *cbdav, icalcomponent *icalcomp, const gcha
 			if (etag)
 				ecalcomp_set_etag (comp, etag);
 
+			g_static_rec_mutex_lock (&priv->cache_lock);
 			res = e_cal_backend_cache_put_component (priv->cache, comp);
+			g_static_rec_mutex_unlock (&priv->cache_lock);
 		}
 	}
 
@@ -2446,7 +2487,9 @@ add_timezones_from_component (ECalBackendCalDAV *cbdav, icalcomponent *vcal_comp
 	f_data.vcal_comp = vcal_comp;
 	f_data.icalcomp = icalcomp;
 
+	g_static_rec_mutex_lock (&priv->cache_lock);
 	icalcomponent_foreach_tzid (icalcomp, add_timezone_cb, &f_data);
+	g_static_rec_mutex_unlock (&priv->cache_lock);
 }
 
 /* also removes X-EVOLUTION-CALDAV from all the components */
@@ -2550,7 +2593,9 @@ cache_contains (ECalBackendCalDAV *cbdav, const gchar *uid, const gchar *rid)
 	priv  = E_CAL_BACKEND_CALDAV_GET_PRIVATE (cbdav);
 	g_return_val_if_fail (priv != NULL && priv->cache != NULL, FALSE);
 
+	g_static_rec_mutex_lock (&priv->cache_lock);
 	comp = e_cal_backend_cache_get_component (priv->cache, uid, rid);
+	g_static_rec_mutex_unlock (&priv->cache_lock);
 	res = comp != NULL;
 
 	if (comp)
@@ -2671,7 +2716,7 @@ replace_master (ECalBackendCalDAV *cbdav, icalcomponent *old_comp, icalcomponent
 	return old_comp;
 }
 
-/* priv->lock is supposed to be locked already, when calling this function */
+/* a busy_lock and a cache_lock are supposed to be locked already, when calling this function */
 static ECalBackendSyncStatus
 do_create_object (ECalBackendCalDAV *cbdav, gchar **calobj, gchar **uid)
 {
@@ -2773,7 +2818,7 @@ do_create_object (ECalBackendCalDAV *cbdav, gchar **calobj, gchar **uid)
 	return status;
 }
 
-/* priv->lock is supposed to be locked already, when calling this function */
+/* a busy_lock and a cache_lock are supposed to be locked already, when calling this function */
 static ECalBackendSyncStatus
 do_modify_object (ECalBackendCalDAV *cbdav, const gchar *calobj, CalObjModType mod, gchar **old_object, gchar **new_object)
 {
@@ -2839,7 +2884,7 @@ do_modify_object (ECalBackendCalDAV *cbdav, const gchar *calobj, CalObjModType m
 
 		if (e_cal_component_is_instance (comp)) {
 			/* set detached instance as the old object, if any */
-			ECalComponent *old_instance = e_cal_backend_cache_get_component (priv->cache, id->uid, id->rid);
+			ECalComponent *old_instance = old_instance = e_cal_backend_cache_get_component (priv->cache, id->uid, id->rid);
 
 			if (old_instance) {
 				*old_object = e_cal_component_get_as_string (old_instance);
@@ -2930,7 +2975,7 @@ do_modify_object (ECalBackendCalDAV *cbdav, const gchar *calobj, CalObjModType m
 	return status;
 }
 
-/* priv->lock is supposed to be locked already, when calling this function */
+/* a busy_lock and a cache_lock are supposed to be locked already, when calling this function */
 static ECalBackendSyncStatus
 do_remove_object (ECalBackendCalDAV *cbdav, const gchar *uid, const gchar *rid, CalObjModType mod, gchar **old_object, gchar **object)
 {
@@ -3032,66 +3077,6 @@ do_remove_object (ECalBackendCalDAV *cbdav, const gchar *uid, const gchar *rid,
 }
 
 static ECalBackendSyncStatus
-caldav_create_object (ECalBackendSync *backend, EDataCal *cal, gchar **calobj, gchar **uid)
-{
-	ECalBackendCalDAV        *cbdav;
-	ECalBackendCalDAVPrivate *priv;
-	ECalBackendSyncStatus     status;
-
-	cbdav = E_CAL_BACKEND_CALDAV (backend);
-	priv  = E_CAL_BACKEND_CALDAV_GET_PRIVATE (cbdav);
-
-	g_mutex_lock (priv->lock);
-	status = do_create_object (cbdav, calobj, uid);
-	g_mutex_unlock (priv->lock);
-
-	return status;
-}
-
-static ECalBackendSyncStatus
-caldav_modify_object (ECalBackendSync *backend, EDataCal *cal, const gchar *calobj, CalObjModType mod, gchar **old_object, gchar **new_object)
-{
-	ECalBackendCalDAV        *cbdav;
-	ECalBackendCalDAVPrivate *priv;
-	ECalBackendSyncStatus     status;
-
-	cbdav = E_CAL_BACKEND_CALDAV (backend);
-	priv  = E_CAL_BACKEND_CALDAV_GET_PRIVATE (cbdav);
-
-	g_mutex_lock (priv->lock);
-	status = do_modify_object (cbdav, calobj, mod, old_object, new_object);
-	g_mutex_unlock (priv->lock);
-
-	return status;
-}
-
-static ECalBackendSyncStatus
-caldav_remove_object (ECalBackendSync *backend, EDataCal *cal, const gchar *uid, const gchar *rid, CalObjModType mod, gchar **old_object, gchar **object)
-{
-	ECalBackendCalDAV        *cbdav;
-	ECalBackendCalDAVPrivate *priv;
-	ECalBackendSyncStatus     status;
-
-	cbdav = E_CAL_BACKEND_CALDAV (backend);
-	priv  = E_CAL_BACKEND_CALDAV_GET_PRIVATE (cbdav);
-
-	g_mutex_lock (priv->lock);
-	status = do_remove_object (cbdav, uid, rid, mod, old_object, object);
-	g_mutex_unlock (priv->lock);
-
-	return status;
-}
-
-static ECalBackendSyncStatus
-caldav_discard_alarm (ECalBackendSync *backend,
-		      EDataCal        *cal,
-		      const gchar      *uid,
-		      const gchar      *auid)
-{
-	return GNOME_Evolution_Calendar_Success;
-}
-
-static ECalBackendSyncStatus
 extract_objects (icalcomponent       *icomp,
 		 icalcomponent_kind   ekind,
 		 GList              **objects)
@@ -3144,6 +3129,8 @@ extract_timezones (ECalBackendCalDAV *cbdav, icalcomponent *icomp)
 
 	priv = E_CAL_BACKEND_CALDAV_GET_PRIVATE (cbdav);
 
+	g_static_rec_mutex_lock (&priv->cache_lock);
+
 	zone = icaltimezone_new ();
 	for (iter = timezones; iter; iter = iter->next) {
 		if (icaltimezone_set_component (zone, iter->data)) {
@@ -3153,14 +3140,14 @@ extract_timezones (ECalBackendCalDAV *cbdav, icalcomponent *icomp)
 		}
 	}
 
+	g_static_rec_mutex_unlock (&priv->cache_lock);
+
 	icaltimezone_free (zone, TRUE);
 	g_list_free (timezones);
 
 	return TRUE;
 }
 
-#define is_error(__status) (__status != GNOME_Evolution_Calendar_Success)
-
 static ECalBackendSyncStatus
 process_object (ECalBackendCalDAV   *cbdav,
 		ECalComponent       *ecomp,
@@ -3271,9 +3258,7 @@ process_object (ECalBackendCalDAV   *cbdav,
 }
 
 static ECalBackendSyncStatus
-caldav_receive_objects (ECalBackendSync *backend,
-			EDataCal        *cal,
-			const gchar      *calobj)
+do_receive_objects (ECalBackendSync *backend, EDataCal *cal, const gchar *calobj)
 {
 	ECalBackendCalDAV        *cbdav;
 	ECalBackendCalDAVPrivate *priv;
@@ -3288,6 +3273,11 @@ caldav_receive_objects (ECalBackendSync *backend,
 	cbdav = E_CAL_BACKEND_CALDAV (backend);
 	priv  = E_CAL_BACKEND_CALDAV_GET_PRIVATE (cbdav);
 
+	status = check_state (cbdav, &online);
+	if (status != GNOME_Evolution_Calendar_Success) {
+		return status;
+	}
+
 	icomp = icalparser_parse_string (calobj);
 
 	/* Try to parse cal object string */
@@ -3306,21 +3296,9 @@ caldav_receive_objects (ECalBackendSync *backend,
 	/* Extract optional timezone compnents */
 	extract_timezones (cbdav, icomp);
 
-	/*   */
-	g_mutex_lock (priv->lock);
-
-	status = check_state (cbdav, &online);
-
-	if (status != GNOME_Evolution_Calendar_Success) {
-		/* FIXME: free components here */
-		g_mutex_unlock (priv->lock);
-		icalcomponent_free (icomp);
-		return status;
-	}
-
 	tmethod = icalcomponent_get_method (icomp);
 
-	for (iter = objects; iter && ! is_error (status); iter = iter->next) {
+	for (iter = objects; iter && status == GNOME_Evolution_Calendar_Success; iter = iter->next) {
 		icalcomponent       *scomp;
 		ECalComponent       *ecomp;
 		icalproperty_method  method;
@@ -3343,12 +3321,73 @@ caldav_receive_objects (ECalBackendSync *backend,
 
 	g_list_free (objects);
 
-	g_mutex_unlock (priv->lock);
 	icalcomponent_free (icomp);
 
 	return status;
 }
 
+#define caldav_busy_stub(_func_name, _params, _call_func, _call_params)	\
+static ECalBackendSyncStatus						\
+_func_name _params							\
+{									\
+	ECalBackendCalDAV        *cbdav;				\
+	ECalBackendCalDAVPrivate *priv;					\
+	ECalBackendSyncStatus     status;				\
+	SlaveCommand		  old_slave_cmd;			\
+	gboolean		  was_slave_busy;			\
+									\
+	cbdav = E_CAL_BACKEND_CALDAV (backend);				\
+	priv  = E_CAL_BACKEND_CALDAV_GET_PRIVATE (cbdav);		\
+									\
+	/* this is done before locking */				\
+	old_slave_cmd = priv->slave_cmd;				\
+	was_slave_busy = priv->slave_busy;				\
+	if (was_slave_busy) {						\
+		/* let it pause its work and do our job */		\
+		priv->slave_cmd = SLAVE_SHOULD_SLEEP;			\
+	}								\
+									\
+	g_mutex_lock (priv->busy_lock);					\
+	g_static_rec_mutex_lock (&priv->cache_lock);			\
+	status = _call_func _call_params;				\
+	g_static_rec_mutex_unlock (&priv->cache_lock);			\
+									\
+	/* this is done before unlocking */				\
+	if (was_slave_busy) {						\
+		priv->slave_cmd = old_slave_cmd;			\
+		g_cond_signal (priv->cond);				\
+	}								\
+									\
+	g_mutex_unlock (priv->busy_lock);				\
+									\
+	return status;							\
+}
+
+caldav_busy_stub (
+	caldav_create_object, (ECalBackendSync *backend, EDataCal *cal, gchar **calobj, gchar **uid),
+	do_create_object, (cbdav, calobj, uid))
+
+caldav_busy_stub (
+	caldav_modify_object, (ECalBackendSync *backend, EDataCal *cal, const gchar *calobj, CalObjModType mod, gchar **old_object, gchar **new_object),
+	do_modify_object, (cbdav, calobj, mod, old_object, new_object))
+
+caldav_busy_stub (
+	caldav_remove_object, (ECalBackendSync *backend, EDataCal *cal, const gchar *uid, const gchar *rid, CalObjModType mod, gchar **old_object, gchar **object),
+	do_remove_object, (cbdav, uid, rid, mod, old_object, object))
+
+caldav_busy_stub (
+	caldav_receive_objects, (ECalBackendSync *backend, EDataCal *cal, const gchar *calobj),
+	do_receive_objects, (backend, cal, calobj))
+
+static ECalBackendSyncStatus
+caldav_discard_alarm (ECalBackendSync *backend,
+		      EDataCal        *cal,
+		      const gchar      *uid,
+		      const gchar      *auid)
+{
+	return GNOME_Evolution_Calendar_Success;
+}
+
 static ECalBackendSyncStatus
 caldav_send_objects (ECalBackendSync  *backend,
 		     EDataCal         *cal,
@@ -3406,12 +3445,12 @@ caldav_get_object (ECalBackendSync  *backend,
 	cbdav = E_CAL_BACKEND_CALDAV (backend);
 	priv  = E_CAL_BACKEND_CALDAV_GET_PRIVATE (cbdav);
 
-	g_mutex_lock (priv->lock);
+	g_static_rec_mutex_lock (&priv->cache_lock);
 
 	*object = NULL;
 	icalcomp = get_comp_from_cache (cbdav, uid, rid, NULL, NULL);
 
-	g_mutex_unlock (priv->lock);
+	g_static_rec_mutex_unlock (&priv->cache_lock);
 
 	if (!icalcomp) {
 		return GNOME_Evolution_Calendar_ObjectNotFound;
@@ -3440,9 +3479,9 @@ caldav_get_timezone (ECalBackendSync  *backend,
 	g_return_val_if_fail (tzid, GNOME_Evolution_Calendar_ObjectNotFound);
 
 	/* first try to get the timezone from the cache */
-	g_mutex_lock (priv->lock);
+	g_static_rec_mutex_lock (&priv->cache_lock);
 	zone = e_cal_backend_cache_get_timezone (priv->cache, tzid);
-	g_mutex_unlock (priv->lock);
+	g_static_rec_mutex_unlock (&priv->cache_lock);
 
 	if (!zone) {
 		zone = icaltimezone_get_builtin_timezone_from_tzid (tzid);
@@ -3488,9 +3527,9 @@ caldav_add_timezone (ECalBackendSync *backend,
 		zone = icaltimezone_new ();
 		icaltimezone_set_component (zone, tz_comp);
 
-		g_mutex_lock (priv->lock);
+		g_static_rec_mutex_lock (&priv->cache_lock);
 		e_cal_backend_cache_put_timezone (priv->cache, zone);
-		g_mutex_unlock (priv->lock);
+		g_static_rec_mutex_unlock (&priv->cache_lock);
 
 		icaltimezone_free (zone, TRUE);
 	} else {
@@ -3564,9 +3603,10 @@ caldav_get_object_list (ECalBackendSync  *backend,
 	*objects = NULL;
 	bcache = priv->cache;
 
-	g_mutex_lock (priv->lock);
-
+	g_static_rec_mutex_lock (&priv->cache_lock);
 	list = e_cal_backend_cache_get_components (bcache);
+	g_static_rec_mutex_unlock (&priv->cache_lock);
+
 	bkend = E_CAL_BACKEND (backend);
 
 	for (iter = list; iter; iter = g_list_next (iter)) {
@@ -3584,8 +3624,6 @@ caldav_get_object_list (ECalBackendSync  *backend,
 	g_object_unref (sexp);
 	g_list_free (list);
 
-	g_mutex_unlock (priv->lock);
-
 	return GNOME_Evolution_Calendar_Success;
 }
 
@@ -3615,9 +3653,10 @@ caldav_start_query (ECalBackend  *backend,
 		do_search = TRUE;
 	}
 
-	g_mutex_lock (priv->lock);
-
+	g_static_rec_mutex_lock (&priv->cache_lock);
 	list = e_cal_backend_cache_get_components (priv->cache);
+	g_static_rec_mutex_unlock (&priv->cache_lock);
+
 	bkend = E_CAL_BACKEND (backend);
 
 	for (iter = list; iter; iter = g_list_next (iter)) {
@@ -3636,10 +3675,7 @@ caldav_start_query (ECalBackend  *backend,
 	g_object_unref (sexp);
 	g_list_free (list);
 
-
 	e_data_cal_view_notify_done (query, GNOME_Evolution_Calendar_Success);
-	g_mutex_unlock (priv->lock);
-	return;
 }
 
 static ECalBackendSyncStatus
@@ -3858,7 +3894,7 @@ caldav_set_mode (ECalBackend *backend, CalMode mode)
 	cbdav = E_CAL_BACKEND_CALDAV (backend);
 	priv  = E_CAL_BACKEND_CALDAV_GET_PRIVATE (cbdav);
 
-	/*g_mutex_lock (priv->lock);*/
+	/*g_mutex_lock (priv->busy_lock);*/
 
 	/* We only support online and offline */
 	if (mode != CAL_MODE_REMOTE &&
@@ -3866,7 +3902,7 @@ caldav_set_mode (ECalBackend *backend, CalMode mode)
 		e_cal_backend_notify_mode (backend,
 					   GNOME_Evolution_Calendar_CalListener_MODE_NOT_SUPPORTED,
 					   cal_mode_to_corba (mode));
-		/*g_mutex_unlock (priv->lock);*/
+		/*g_mutex_unlock (priv->busy_lock);*/
 		return;
 	}
 
@@ -3875,7 +3911,7 @@ caldav_set_mode (ECalBackend *backend, CalMode mode)
 		e_cal_backend_notify_mode (backend,
 					   GNOME_Evolution_Calendar_CalListener_MODE_SET,
 					   cal_mode_to_corba (mode));
-		/*g_mutex_unlock (priv->lock);*/
+		/*g_mutex_unlock (priv->busy_lock);*/
 		return;
 	}
 
@@ -3894,7 +3930,7 @@ caldav_set_mode (ECalBackend *backend, CalMode mode)
 				   GNOME_Evolution_Calendar_CalListener_MODE_SET,
 				   cal_mode_to_corba (mode));
 
-	/*g_mutex_unlock (priv->lock);*/
+	/*g_mutex_unlock (priv->busy_lock);*/
 }
 
 static icaltimezone *
@@ -3931,6 +3967,37 @@ caldav_internal_get_timezone (ECalBackend *backend,
 	return zone;
 }
 
+static void
+caldav_source_changed_cb (ESource *source, ECalBackendCalDAV *cbdav)
+{
+	ECalBackendCalDAVPrivate *priv;
+	SlaveCommand old_slave_cmd;
+	gboolean old_slave_busy;
+
+	g_return_if_fail (source != NULL);
+	g_return_if_fail (cbdav != NULL);
+
+	priv = E_CAL_BACKEND_CALDAV_GET_PRIVATE (cbdav);
+	g_return_if_fail (priv != NULL);
+
+	old_slave_cmd = priv->slave_cmd;
+	old_slave_busy = priv->slave_busy;
+	if (old_slave_busy) {
+		priv->slave_cmd = SLAVE_SHOULD_SLEEP;
+		g_mutex_lock (priv->busy_lock);
+	}
+
+	initialize_backend (cbdav);
+
+	/* always wakeup thread, even when it was sleeping */
+	g_cond_signal (priv->cond);
+
+	if (old_slave_busy) {
+		priv->slave_cmd = old_slave_cmd;
+		g_mutex_unlock (priv->busy_lock);
+	}
+}
+
 /* ************************************************************************* */
 /* ***************************** GObject Foo ******************************* */
 
@@ -3941,24 +4008,32 @@ e_cal_backend_caldav_dispose (GObject *object)
 {
 	ECalBackendCalDAV        *cbdav;
 	ECalBackendCalDAVPrivate *priv;
+	ESource *source;
 
 	cbdav = E_CAL_BACKEND_CALDAV (object);
 	priv = E_CAL_BACKEND_CALDAV_GET_PRIVATE (cbdav);
 
-	g_mutex_lock (priv->lock);
+	/* tell the slave to stop before acquiring a lock,
+	   as it can work at the moment, and lock can be locked */
+	priv->slave_cmd = SLAVE_SHOULD_DIE;
+
+	g_mutex_lock (priv->busy_lock);
 
 	if (priv->disposed) {
-		g_mutex_unlock (priv->lock);
+		g_mutex_unlock (priv->busy_lock);
 		return;
 	}
 
+	source = e_cal_backend_get_source (E_CAL_BACKEND (cbdav));
+	if (source)
+		g_signal_handlers_disconnect_by_func (G_OBJECT (source), caldav_source_changed_cb, cbdav);
+
 	/* stop the slave  */
-	priv->slave_cmd = SLAVE_SHOULD_DIE;
 	if (priv->synch_slave) {
 		g_cond_signal (priv->cond);
 
 		/* wait until the slave died */
-		g_cond_wait (priv->slave_gone_cond, priv->lock);
+		g_cond_wait (priv->slave_gone_cond, priv->busy_lock);
 	}
 
 	g_object_unref (priv->session);
@@ -3974,7 +4049,7 @@ e_cal_backend_caldav_dispose (GObject *object)
 	}
 
 	priv->disposed = TRUE;
-	g_mutex_unlock (priv->lock);
+	g_mutex_unlock (priv->busy_lock);
 
 	if (G_OBJECT_CLASS (parent_class)->dispose)
 		(* G_OBJECT_CLASS (parent_class)->dispose) (object);
@@ -3989,7 +4064,8 @@ e_cal_backend_caldav_finalize (GObject *object)
 	cbdav = E_CAL_BACKEND_CALDAV (object);
 	priv = E_CAL_BACKEND_CALDAV_GET_PRIVATE (cbdav);
 
-	g_mutex_free (priv->lock);
+	g_mutex_free (priv->busy_lock);
+	g_static_rec_mutex_free (&priv->cache_lock);
 	g_cond_free (priv->cond);
 	g_cond_free (priv->slave_gone_cond);
 
@@ -4006,6 +4082,7 @@ static void
 e_cal_backend_caldav_init (ECalBackendCalDAV *cbdav)
 {
 	ECalBackendCalDAVPrivate *priv;
+
 	priv = E_CAL_BACKEND_CALDAV_GET_PRIVATE (cbdav);
 
 	priv->session = soup_session_sync_new ();
@@ -4019,20 +4096,22 @@ e_cal_backend_caldav_init (ECalBackendCalDAV *cbdav)
 	priv->default_zone = icaltimezone_get_utc_timezone ();
 
 	priv->disposed = FALSE;
-	priv->do_synch = FALSE;
 	priv->loaded   = FALSE;
 
 	/* Thinks the 'getctag' extension is available the first time, but unset it when realizes it isn't. */
 	priv->ctag_supported = TRUE;
+	priv->ctag_to_store = NULL;
 
 	priv->schedule_outbox_url = NULL;
 
-	priv->lock = g_mutex_new ();
+	priv->busy_lock = g_mutex_new ();
+	g_static_rec_mutex_init (&priv->cache_lock);
 	priv->cond = g_cond_new ();
 	priv->slave_gone_cond = g_cond_new ();
 
 	/* Slave control ... */
 	priv->slave_cmd = SLAVE_SHOULD_SLEEP;
+	priv->slave_busy = FALSE;
 	priv->refresh_time.tv_usec = 0;
 	priv->refresh_time.tv_sec  = DEFAULT_REFRESH_TIME;
 



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