Blob Blame History Raw
Backport of upstream commits:

commit 37768f933d00b64bfc5f902ccc2ecc85fee2b918
Adding new strings to copy/move event/task/memo and handle possible errors on those operations
   
commit 96c6e7bc26132d31c87e05a6ef702b008a47ac85
Add EShellView to E{Calendar,MemoList,TaskList}Selector
  
commit ed2bc85f4fe13a67aec032c8dddef0614df6419f
Bug #657808 - Copy/move of a single instance should grab whole serie

diff -up evolution-3.8.5/calendar/calendar.error.xml.copy-move-recurrences evolution-3.8.5/calendar/calendar.error.xml
--- evolution-3.8.5/calendar/calendar.error.xml.copy-move-recurrences	2013-07-18 14:10:38.000000000 +0200
+++ evolution-3.8.5/calendar/calendar.error.xml	2013-11-04 22:11:17.120317884 +0100
@@ -307,4 +307,16 @@
     <secondary>{0}</secondary>
   </error>
 
+  <error id="failed-copy-event" type="error" default="GTK_RESPONSE_YES">
+    <!-- Translators: {0} is the name of the calendar. -->
+    <_primary>Failed to copy an event into the calendar '{0}'</_primary>
+    <secondary>{1}</secondary>
+  </error>
+
+  <error id="failed-move-event" type="error" default="GTK_RESPONSE_YES">
+    <!-- Translators: {0} is the name of the calendar. -->
+    <_primary>Failed to move an event into the calendar '{0}'</_primary>
+    <secondary>{1}</secondary>
+  </error>
+
 </error-list>
diff -up evolution-3.8.5/calendar/gui/comp-util.c.copy-move-recurrences evolution-3.8.5/calendar/gui/comp-util.c
--- evolution-3.8.5/calendar/gui/comp-util.c.copy-move-recurrences	2013-07-23 14:52:29.000000000 +0200
+++ evolution-3.8.5/calendar/gui/comp-util.c	2013-11-04 22:11:17.120317884 +0100
@@ -813,3 +813,366 @@ icalcomp_suggest_filename (icalcomponent
 
 	return g_strconcat (summary, ".ics", NULL);
 }
+
+typedef struct _AsyncContext {
+	ECalClient *src_client;
+	icalcomponent *icalcomp_clone;
+	gboolean do_copy;
+} AsyncContext;
+
+struct ForeachTzidData
+{
+	ECalClient *source_client;
+	ECalClient *destination_client;
+	GCancellable *cancellable;
+	GError **error;
+	gboolean success;
+};
+
+static void
+async_context_free (AsyncContext *async_context)
+{
+	if (async_context->src_client)
+		g_object_unref (async_context->src_client);
+
+	if (async_context->icalcomp_clone)
+		icalcomponent_free (async_context->icalcomp_clone);
+
+	g_slice_free (AsyncContext, async_context);
+}
+
+static void
+add_timezone_to_cal_cb (icalparameter *param,
+			gpointer data)
+{
+	struct ForeachTzidData *ftd = data;
+	icaltimezone *tz = NULL;
+	const gchar *tzid;
+
+	g_return_if_fail (ftd != NULL);
+	g_return_if_fail (ftd->source_client != NULL);
+	g_return_if_fail (ftd->destination_client != NULL);
+
+	if (!ftd->success)
+		return;
+
+	if (ftd->cancellable && g_cancellable_is_cancelled (ftd->cancellable)) {
+		ftd->success = FALSE;
+		return;
+	}
+
+	tzid = icalparameter_get_tzid (param);
+	if (!tzid || !*tzid)
+		return;
+
+	if (e_cal_client_get_timezone_sync (ftd->source_client, tzid, &tz, ftd->cancellable, NULL) && tz)
+		ftd->success = e_cal_client_add_timezone_sync (
+				ftd->destination_client, tz, ftd->cancellable, ftd->error);
+}
+
+/* Helper for cal_comp_transfer_item_to() */
+static void
+cal_comp_transfer_item_to_thread (GSimpleAsyncResult *simple,
+				  GObject *source_object,
+				  GCancellable *cancellable)
+{
+	AsyncContext *async_context;
+	GError *local_error = NULL;
+
+	async_context = g_simple_async_result_get_op_res_gpointer (simple);
+
+	cal_comp_transfer_item_to_sync (
+		async_context->src_client,
+		E_CAL_CLIENT (source_object),
+		async_context->icalcomp_clone,
+		async_context->do_copy,
+		cancellable, &local_error);
+
+	if (local_error != NULL)
+		g_simple_async_result_take_error (simple, local_error);
+}
+
+void
+cal_comp_transfer_item_to (ECalClient *src_client,
+			   ECalClient *dest_client,
+			   icalcomponent *icalcomp_vcal,
+			   gboolean do_copy,
+			   GCancellable *cancellable,
+			   GAsyncReadyCallback callback,
+			   gpointer user_data)
+{
+	GSimpleAsyncResult *simple;
+	AsyncContext *async_context;
+
+	g_return_val_if_fail (E_IS_CAL_CLIENT (src_client), FALSE);
+	g_return_val_if_fail (E_IS_CAL_CLIENT (dest_client), FALSE);
+	g_return_val_if_fail (icalcomp_vcal != NULL, FALSE);
+
+	async_context = g_slice_new0 (AsyncContext);
+	async_context->src_client = g_object_ref (src_client);
+	async_context->icalcomp_clone = icalcomponent_new_clone (icalcomp_vcal);
+	async_context->do_copy = do_copy;
+
+	simple = g_simple_async_result_new (
+		G_OBJECT (dest_client), callback, user_data,
+		cal_comp_transfer_item_to);
+
+	g_simple_async_result_set_check_cancellable (simple, cancellable);
+
+	g_simple_async_result_set_op_res_gpointer (
+		simple, async_context, (GDestroyNotify) async_context_free);
+
+	g_simple_async_result_run_in_thread (
+		simple, cal_comp_transfer_item_to_thread,
+		G_PRIORITY_DEFAULT, cancellable);
+
+	g_object_unref (simple);
+}
+
+gboolean
+cal_comp_transfer_item_to_finish (ECalClient *client,
+				  GAsyncResult *result,
+				  GError **error)
+{
+	GSimpleAsyncResult *simple;
+
+	g_return_val_if_fail (
+		g_simple_async_result_is_valid (result, G_OBJECT (client), cal_comp_transfer_item_to),
+		FALSE);
+
+	simple = G_SIMPLE_ASYNC_RESULT (result);
+
+	if (g_simple_async_result_propagate_error (simple, error))
+		return FALSE;
+
+	return TRUE;
+}
+
+gboolean
+cal_comp_transfer_item_to_sync (ECalClient *src_client,
+				ECalClient *dest_client,
+				icalcomponent *icalcomp_vcal,
+				gboolean do_copy,
+				GCancellable *cancellable,
+				GError **error)
+{
+	icalcomponent *icalcomp;
+	icalcomponent *icalcomp_event, *subcomp;
+	icalcomponent_kind icalcomp_kind;
+	const gchar *uid;
+	gchar *new_uid = NULL;
+	struct ForeachTzidData ftd;
+	ECalClientSourceType source_type;
+	GHashTable *processed_uids;
+	gboolean success = FALSE;
+
+	g_return_val_if_fail (E_IS_CAL_CLIENT (src_client), FALSE);
+	g_return_val_if_fail (E_IS_CAL_CLIENT (dest_client), FALSE);
+	g_return_val_if_fail (icalcomp_vcal != NULL, FALSE);
+
+	icalcomp_event = icalcomponent_get_inner (icalcomp_vcal);
+	g_return_val_if_fail (icalcomp_event != NULL, FALSE);
+
+	source_type = e_cal_client_get_source_type (src_client);
+	switch (source_type) {
+		case E_CAL_CLIENT_SOURCE_TYPE_EVENTS:
+			icalcomp_kind = ICAL_VEVENT_COMPONENT;
+			break;
+		case E_CAL_CLIENT_SOURCE_TYPE_TASKS:
+			icalcomp_kind = ICAL_VTODO_COMPONENT;
+			break;
+		case E_CAL_CLIENT_SOURCE_TYPE_MEMOS:
+			icalcomp_kind = ICAL_VJOURNAL_COMPONENT;
+			break;
+		default:
+			g_return_val_if_reached (FALSE);
+	}
+
+	processed_uids = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL);
+
+	icalcomp_event = icalcomponent_get_first_component (icalcomp_vcal, icalcomp_kind);
+	/*
+	 * This check should be removed in the near future.
+	 * We should be able to work properly with multiselection, which means that we always
+	 * will receive a component with subcomponents.
+	 */
+	if (icalcomp_event == NULL)
+		icalcomp_event = icalcomp_vcal;
+	for (;
+	     icalcomp_event;
+	     icalcomp_event = icalcomponent_get_next_component (icalcomp_vcal, icalcomp_kind)) {
+		GError *local_error = NULL;
+
+		uid = icalcomponent_get_uid (icalcomp_event);
+
+		if (g_hash_table_lookup (processed_uids, uid))
+			continue;
+
+		success = e_cal_client_get_object_sync (dest_client, uid, NULL, &icalcomp, cancellable, &local_error);
+		if (success) {
+			success = e_cal_client_modify_object_sync (
+				dest_client, icalcomp_event, CALOBJ_MOD_ALL, cancellable, error);
+
+			icalcomponent_free (icalcomp);
+			if (!success)
+				goto exit;
+
+			if (!do_copy) {
+				ECalObjModType mod_type = CALOBJ_MOD_THIS;
+
+				/* Remove the item from the source calendar. */
+				if (e_cal_util_component_is_instance (icalcomp_event) ||
+				    e_cal_util_component_has_recurrences (icalcomp_event))
+					mod_type = CALOBJ_MOD_ALL;
+
+				success = e_cal_client_remove_object_sync (
+						src_client, uid, NULL, mod_type, cancellable, error);
+				if (!success)
+					goto exit;
+			}
+
+			continue;
+		} else if (local_error != NULL && !g_error_matches (
+					local_error, E_CAL_CLIENT_ERROR, E_CAL_CLIENT_ERROR_OBJECT_NOT_FOUND)) {
+			g_propagate_error (error, local_error);
+			goto exit;
+		} else {
+			g_clear_error (&local_error);
+		}
+
+		if (e_cal_util_component_is_instance (icalcomp_event)) {
+			GSList *ecalcomps = NULL, *eiter;
+			ECalComponent *comp ;
+
+			success = e_cal_client_get_objects_for_uid_sync (src_client, uid, &ecalcomps, cancellable, error);
+			if (!success)
+				goto exit;
+
+			if (ecalcomps && !ecalcomps->next) {
+				/* only one component, no need for a vCalendar list */
+				comp = ecalcomps->data;
+				icalcomp = icalcomponent_new_clone (e_cal_component_get_icalcomponent (comp));
+			} else {
+				icalcomp = icalcomponent_new (ICAL_VCALENDAR_COMPONENT);
+				for (eiter = ecalcomps; eiter; eiter = g_slist_next (eiter)) {
+					comp = eiter->data;
+
+					icalcomponent_add_component (icalcomp,
+						icalcomponent_new_clone (e_cal_component_get_icalcomponent (comp)));
+				}
+			}
+
+			e_cal_client_free_ecalcomp_slist (ecalcomps);
+		} else {
+			icalcomp = icalcomponent_new_clone (icalcomp_event);
+		}
+
+		if (do_copy) {
+			/* Change the UID to avoid problems with duplicated UID */
+			new_uid = e_cal_component_gen_uid ();
+			if (icalcomponent_isa (icalcomp) == ICAL_VCALENDAR_COMPONENT) {
+				/* in case of a vCalendar, the component might have detached instances,
+				   thus change the UID on all of the subcomponents of it */
+				for (subcomp = icalcomponent_get_first_component (icalcomp, icalcomp_kind);
+				     subcomp;
+				     subcomp = icalcomponent_get_next_component (icalcomp, icalcomp_kind)) {
+					icalcomponent_set_uid (subcomp, new_uid);
+				}
+			} else {
+				icalcomponent_set_uid (icalcomp, new_uid);
+			}
+			g_free (new_uid);
+			new_uid = NULL;
+		}
+
+		ftd.source_client = src_client;
+		ftd.destination_client = dest_client;
+		ftd.cancellable = cancellable;
+		ftd.error = error;
+		ftd.success = TRUE;
+
+		if (icalcomponent_isa (icalcomp) == ICAL_VCALENDAR_COMPONENT) {
+			/* in case of a vCalendar, the component might have detached instances,
+			   thus check timezones on all of the subcomponents of it */
+			for (subcomp = icalcomponent_get_first_component (icalcomp, icalcomp_kind);
+			     subcomp && ftd.success;
+			     subcomp = icalcomponent_get_next_component (icalcomp, icalcomp_kind)) {
+				icalcomponent_foreach_tzid (subcomp, add_timezone_to_cal_cb, &ftd);
+			}
+		} else {
+			icalcomponent_foreach_tzid (icalcomp, add_timezone_to_cal_cb, &ftd);
+		}
+
+		if (!ftd.success) {
+			success = FALSE;
+			goto exit;
+		}
+
+		if (icalcomponent_isa (icalcomp) == ICAL_VCALENDAR_COMPONENT) {
+			gboolean did_add = FALSE;
+
+			/* in case of a vCalendar, the component might have detached instances,
+			   thus add the master object first, and then all of the subcomponents of it */
+			for (subcomp = icalcomponent_get_first_component (icalcomp, icalcomp_kind);
+			     subcomp && !did_add;
+			     subcomp = icalcomponent_get_next_component (icalcomp, icalcomp_kind)) {
+				if (icaltime_is_null_time (icalcomponent_get_recurrenceid (subcomp))) {
+					did_add = TRUE;
+					success = e_cal_client_create_object_sync (dest_client, subcomp,
+						&new_uid, cancellable, error);
+					g_free (new_uid);
+				}
+			}
+
+			if (!success) {
+				icalcomponent_free (icalcomp);
+				goto exit;
+			}
+
+			/* deal with detached instances */
+			for (subcomp = icalcomponent_get_first_component (icalcomp, icalcomp_kind);
+			     subcomp && success;
+			     subcomp = icalcomponent_get_next_component (icalcomp, icalcomp_kind)) {
+				if (!icaltime_is_null_time (icalcomponent_get_recurrenceid (subcomp))) {
+					if (did_add) {
+						success = e_cal_client_modify_object_sync (dest_client, subcomp,
+							CALOBJ_MOD_THIS, cancellable, error);
+					} else {
+						/* just in case there are only detached instances and no master object */
+						did_add = TRUE;
+						success = e_cal_client_create_object_sync (dest_client, subcomp,
+							&new_uid, cancellable, error);
+						g_free (new_uid);
+					}
+				}
+			}
+		} else {
+			success = e_cal_client_create_object_sync (dest_client, icalcomp, &new_uid, cancellable, error);
+			g_free (new_uid);
+		}
+
+		icalcomponent_free (icalcomp);
+		if (!success)
+			goto exit;
+
+		if (!do_copy) {
+			ECalObjModType mod_type = CALOBJ_MOD_THIS;
+
+			/* Remove the item from the source calendar. */
+			if (e_cal_util_component_is_instance (icalcomp_event) ||
+			    e_cal_util_component_has_recurrences (icalcomp_event))
+				mod_type = CALOBJ_MOD_ALL;
+
+			success = e_cal_client_remove_object_sync (src_client, uid, NULL, mod_type, cancellable, error);
+			if (!success)
+				goto exit;
+		}
+
+		g_hash_table_insert (processed_uids, g_strdup (uid), GINT_TO_POINTER (1));
+	}
+
+ exit:
+	g_hash_table_destroy (processed_uids);
+
+	return success;
+}
diff -up evolution-3.8.5/calendar/gui/comp-util.h.copy-move-recurrences evolution-3.8.5/calendar/gui/comp-util.h
--- evolution-3.8.5/calendar/gui/comp-util.h.copy-move-recurrences	2013-07-23 14:52:35.000000000 +0200
+++ evolution-3.8.5/calendar/gui/comp-util.h	2013-11-04 22:11:17.121317884 +0100
@@ -75,4 +75,21 @@ void comp_util_sanitize_recurrence_maste
 
 gchar *icalcomp_suggest_filename (icalcomponent *icalcomp, const gchar *default_name);
 
+void cal_comp_transfer_item_to			(ECalClient *src_client,
+						 ECalClient *dest_client,
+						 icalcomponent *icalcomp_vcal,
+						 gboolean do_copy,
+						 GCancellable *cancellable,
+						 GAsyncReadyCallback callback,
+						 gpointer user_data);
+gboolean cal_comp_transfer_item_to_finish	(ECalClient *client,
+						 GAsyncResult *result,
+						 GError **error);
+gboolean cal_comp_transfer_item_to_sync		(ECalClient *src_client,
+						 ECalClient *dest_client,
+						 icalcomponent *icalcomp_event,
+						 gboolean do_copy,
+						 GCancellable *cancellable,
+						 GError **error);
+
 #endif
diff -up evolution-3.8.5/calendar/gui/e-calendar-selector.c.copy-move-recurrences evolution-3.8.5/calendar/gui/e-calendar-selector.c
--- evolution-3.8.5/calendar/gui/e-calendar-selector.c.copy-move-recurrences	2013-07-23 14:52:35.000000000 +0200
+++ evolution-3.8.5/calendar/gui/e-calendar-selector.c	2013-11-04 22:11:17.122317884 +0100
@@ -20,7 +20,10 @@
 
 #include <config.h>
 
+#include <glib/gi18n.h>
+
 #include "e-calendar-selector.h"
+#include "comp-util.h"
 
 #include <libecal/libecal.h>
 
@@ -29,7 +32,9 @@
 	((obj), E_TYPE_CALENDAR_SELECTOR, ECalendarSelectorPrivate))
 
 struct _ECalendarSelectorPrivate {
-	gint dummy_value;
+	EShellView *shell_view;
+
+	gpointer transfer_alert; /* weak pointer to EAlert */
 };
 
 G_DEFINE_TYPE (
@@ -37,113 +42,193 @@ G_DEFINE_TYPE (
 	e_calendar_selector,
 	E_TYPE_CLIENT_SELECTOR)
 
-static gboolean
-calendar_selector_update_single_object (ECalClient *client,
-                                        icalcomponent *icalcomp)
+enum {
+	PROP_0,
+	PROP_SHELL_VIEW,
+};
+
+static void
+cal_transferring_update_alert (ECalendarSelector *calendar_selector,
+			       EShellView *shell_view,
+			       const gchar *domain,
+			       const gchar *calendar,
+			       const gchar *message)
 {
-	gchar *uid;
-	icalcomponent *tmp_icalcomp;
+	ECalendarSelectorPrivate *priv;
+	EShellContent *shell_content;
+	EAlert *alert;
+
+	g_return_if_fail (calendar_selector != NULL);
+	g_return_if_fail (calendar_selector->priv != NULL);
+
+	priv = calendar_selector->priv;
+
+	if (priv->transfer_alert) {
+		e_alert_response (
+			priv->transfer_alert,
+			e_alert_get_default_response (priv->transfer_alert));
+		priv->transfer_alert = NULL;
+	}
 
-	uid = (gchar *) icalcomponent_get_uid (icalcomp);
+	if (!message)
+		return;
 
-	if (e_cal_client_get_object_sync (client, uid, NULL, &tmp_icalcomp, NULL, NULL)) {
-		icalcomponent_free (tmp_icalcomp);
+	alert = e_alert_new (domain, calendar, message, NULL);
+	g_return_if_fail (alert != NULL);
 
-		return e_cal_client_modify_object_sync (
-			client, icalcomp, CALOBJ_MOD_ALL, NULL, NULL);
-	}
+	priv->transfer_alert = alert;
+	g_object_add_weak_pointer (G_OBJECT (alert), &priv->transfer_alert);
+	e_alert_start_timer (priv->transfer_alert, 300);
+
+	shell_content = e_shell_view_get_shell_content (shell_view);
+	e_alert_sink_submit_alert (E_ALERT_SINK (shell_content), priv->transfer_alert);
+	g_object_unref (priv->transfer_alert);
+}
 
-	uid = NULL;
-	if (!e_cal_client_create_object_sync (client, icalcomp, &uid, NULL, NULL))
-		return FALSE;
+typedef struct _TransferItemToData {
+	ESource *destination;
+	ESourceSelector *selector;
+	EClient *src_client;
+	EShellView *shell_view;
+	EActivity *activity;
+	icalcomponent *icalcomp;
+	const gchar *display_name;
+	gboolean do_copy;
+} TransferItemToData;
 
-	if (uid)
-		icalcomponent_set_uid (icalcomp, uid);
-	g_free (uid);
+static void
+transfer_item_to_cb (GObject *source_object,
+		     GAsyncResult *result,
+		     gpointer user_data)
+{
+	TransferItemToData *titd = user_data;
+	GError *error = NULL;
+	GCancellable *cancellable;
+	gboolean success;
 
-	return TRUE;
+	success = cal_comp_transfer_item_to_finish (E_CAL_CLIENT (source_object), result, &error);
+
+	if (!success) {
+		cal_transferring_update_alert (
+			E_CALENDAR_SELECTOR (titd->selector),
+			titd->shell_view,
+			titd->do_copy ? "calendar:failed-copy-event" : "calendar:failed-move-event",
+			titd->display_name,
+			error->message);
+		g_clear_error (&error);
+	}
+
+	cancellable = e_activity_get_cancellable (titd->activity);
+	e_activity_set_state (
+		titd->activity,
+		g_cancellable_is_cancelled (cancellable) ? E_ACTIVITY_CANCELLED : E_ACTIVITY_COMPLETED);
+
+	g_object_unref (titd->activity);
+	icalcomponent_free (titd->icalcomp);
+	g_free (titd);
 }
 
-static gboolean
-calendar_selector_update_objects (ECalClient *client,
-                                  icalcomponent *icalcomp)
+static void
+destination_client_connect_cb (GObject *source_object,
+			       GAsyncResult *result,
+			       gpointer user_data)
 {
-	icalcomponent *subcomp;
-	icalcomponent_kind kind;
+	EClient *client;
+	TransferItemToData *titd = user_data;
+	GCancellable *cancellable;
+	GError *error = NULL;
 
-	kind = icalcomponent_isa (icalcomp);
-	if (kind == ICAL_VTODO_COMPONENT || kind == ICAL_VEVENT_COMPONENT)
-		return calendar_selector_update_single_object (
-			client, icalcomp);
-	else if (kind != ICAL_VCALENDAR_COMPONENT)
-		return FALSE;
-
-	subcomp = icalcomponent_get_first_component (
-		icalcomp, ICAL_ANY_COMPONENT);
-	while (subcomp != NULL) {
-		gboolean success;
-
-		kind = icalcomponent_isa (subcomp);
-		if (kind == ICAL_VTIMEZONE_COMPONENT) {
-			icaltimezone *zone;
-			GError *error = NULL;
-
-			zone = icaltimezone_new ();
-			icaltimezone_set_component (zone, subcomp);
-
-			e_cal_client_add_timezone_sync (client, zone, NULL, &error);
-			icaltimezone_free (zone, 1);
-
-			if (error != NULL) {
-				g_warning (
-					"%s: Failed to add timezone: %s",
-					G_STRFUNC, error->message);
-				g_error_free (error);
-				return FALSE;
-			}
-		} else if (kind == ICAL_VTODO_COMPONENT ||
-			kind == ICAL_VEVENT_COMPONENT) {
-			success = calendar_selector_update_single_object (
-				client, subcomp);
-			if (!success)
-				return FALSE;
-		}
+	client = e_client_selector_get_client_finish (E_CLIENT_SELECTOR (source_object), result, &error);
 
-		subcomp = icalcomponent_get_next_component (
-			icalcomp, ICAL_ANY_COMPONENT);
+	/* Sanity check. */
+	g_return_if_fail (
+		((client != NULL) && (error == NULL)) ||
+		((client == NULL) && (error != NULL)));
+
+	cancellable = e_activity_get_cancellable (titd->activity);
+
+	if (error != NULL) {
+		cal_transferring_update_alert (
+			E_CALENDAR_SELECTOR (titd->selector),
+			titd->shell_view,
+			titd->do_copy ? "calendar:failed-copy-event" : "calendar:failed-move-event",
+			titd->display_name,
+			error->message);
+		g_clear_error (&error);
+
+		goto exit;
 	}
 
-	return TRUE;
+	if (g_cancellable_is_cancelled (cancellable))
+		goto exit;
+
+	cal_comp_transfer_item_to (
+		E_CAL_CLIENT (titd->src_client), E_CAL_CLIENT (client),
+		titd->icalcomp, titd->do_copy, cancellable, transfer_item_to_cb, titd);
+
+	return;
+
+exit:
+	e_activity_set_state (
+		titd->activity,
+		g_cancellable_is_cancelled (cancellable) ? E_ACTIVITY_CANCELLED : E_ACTIVITY_COMPLETED);
+
+	g_object_unref (titd->activity);
+	icalcomponent_free (titd->icalcomp);
+	g_free (titd);
+
 }
 
 static void
-client_connect_cb (GObject *source_object,
-                   GAsyncResult *result,
-                   gpointer user_data)
+source_client_connect_cb (GObject *source_object,
+			  GAsyncResult *result,
+			  gpointer user_data)
 {
 	EClient *client;
-	icalcomponent *icalcomp = user_data;
+	TransferItemToData *titd = user_data;
+	GCancellable *cancellable;
 	GError *error = NULL;
 
-	g_return_if_fail (icalcomp != NULL);
-
-	client = e_client_selector_get_client_finish (
-		E_CLIENT_SELECTOR (source_object), result, &error);
+	client = e_client_selector_get_client_finish (E_CLIENT_SELECTOR (source_object), result, &error);
 
 	/* Sanity check. */
 	g_return_if_fail (
 		((client != NULL) && (error == NULL)) ||
 		((client == NULL) && (error != NULL)));
 
+	cancellable = e_activity_get_cancellable (titd->activity);
+
 	if (error != NULL) {
-		g_warning ("%s: %s", G_STRFUNC, error->message);
-		g_error_free (error);
+		cal_transferring_update_alert (
+			E_CALENDAR_SELECTOR (titd->selector),
+			titd->shell_view,
+			titd->do_copy ? "calendar:failed-copy-event" : "calendar:failed-move-event",
+			titd->display_name,
+			error->message);
+		g_clear_error (&error);
+
+		goto exit;
 	}
 
-	calendar_selector_update_objects (E_CAL_CLIENT (client), icalcomp);
-	g_object_unref (client);
+	if (g_cancellable_is_cancelled (cancellable))
+		goto exit;
+
+	titd->src_client = client;
+
+	e_client_selector_get_client (
+		E_CLIENT_SELECTOR (titd->selector), titd->destination, cancellable,
+		destination_client_connect_cb, titd);
+
+	return;
 
-	icalcomponent_free (icalcomp);
+exit:
+	e_activity_set_state (
+		titd->activity,
+		g_cancellable_is_cancelled (cancellable) ? E_ACTIVITY_CANCELLED : E_ACTIVITY_COMPLETED);
+
+	g_object_unref (titd->activity);
+	icalcomponent_free (titd->icalcomp);
+	g_free (titd);
 }
 
 static void
@@ -171,40 +256,148 @@ calendar_selector_data_dropped (ESourceS
                                 GdkDragAction action,
                                 guint info)
 {
-	GtkTreePath *path = NULL;
-	icalcomponent *icalcomp;
+	icalcomponent *icalcomp = NULL;
+	EActivity *activity;
+	EShellBackend *shell_backend;
+	EShellView *shell_view;
+	ESource *source = NULL;
+	ESourceRegistry *registry;
+	GCancellable *cancellable;
+	gchar **segments;
+	gchar *source_uid = NULL;
+	gchar *message;
+	const gchar *display_name;
 	const guchar *data;
-	gboolean success = FALSE;
-	gpointer object = NULL;
+	gboolean do_copy;
+	TransferItemToData *titd;
 
 	data = gtk_selection_data_get_data (selection_data);
-	icalcomp = icalparser_parse_string ((const gchar *) data);
+	g_return_val_if_fail (data != NULL, FALSE);
 
-	if (icalcomp == NULL)
+	segments = g_strsplit ((const gchar *) data, "\n", 2);
+	if (g_strv_length (segments) != 2)
 		goto exit;
 
-	/* FIXME Deal with GDK_ACTION_ASK. */
-	if (action == GDK_ACTION_COPY) {
-		gchar *uid;
+	source_uid = g_strdup (segments[0]);
+	icalcomp = icalparser_parse_string (segments[1]);
 
-		uid = e_cal_component_gen_uid ();
-		icalcomponent_set_uid (icalcomp, uid);
-	}
+	if (!icalcomp)
+		goto exit;
 
-	e_client_selector_get_client (
-		E_CLIENT_SELECTOR (selector), destination, NULL,
-		client_connect_cb, icalcomp);
+	registry = e_source_selector_get_registry (selector);
+	source = e_source_registry_ref_source (registry, source_uid);
+	if (!source)
+		goto exit;
+
+	shell_view = e_calendar_selector_get_shell_view (E_CALENDAR_SELECTOR (selector));
+	shell_backend = e_shell_view_get_shell_backend (shell_view);
+
+	display_name = e_source_get_display_name (destination);
 
-	success = TRUE;
+	do_copy = action == GDK_ACTION_COPY ? TRUE : FALSE;
+
+	message = do_copy ?
+		g_strdup_printf (_("Copying an event into the calendar %s"), display_name) :
+		g_strdup_printf (_("Moving an event into the calendar %s"), display_name);
+
+	cancellable = g_cancellable_new ();
+	activity = e_activity_new ();
+	e_activity_set_cancellable (activity, cancellable);
+	e_activity_set_state (activity, E_ACTIVITY_RUNNING);
+	e_activity_set_text (activity, message);
+	g_free (message);
+
+	e_shell_backend_add_activity (shell_backend, activity);
+
+	titd = g_new0 (TransferItemToData, 1);
+
+	titd->destination = destination;
+	titd->icalcomp = icalcomponent_new_clone (icalcomp);
+	titd->selector = selector;
+	titd->shell_view = shell_view;
+	titd->activity = activity;
+	titd->display_name = display_name;
+	titd->do_copy = do_copy;
+
+	e_client_selector_get_client (
+		E_CLIENT_SELECTOR (selector), source, cancellable,
+		source_client_connect_cb, titd);
 
 exit:
-	if (path != NULL)
-		gtk_tree_path_free (path);
+	if (source)
+		g_object_unref (source);
 
-	if (object != NULL)
-		g_object_unref (object);
+	if (icalcomp)
+		icalcomponent_free (icalcomp);
 
-	return success;
+	g_free (source_uid);
+	g_strfreev (segments);
+	return TRUE;
+}
+
+EShellView *
+e_calendar_selector_get_shell_view (ECalendarSelector *calendar_selector)
+{
+	g_return_val_if_fail (E_IS_CALENDAR_SELECTOR (calendar_selector), NULL);
+
+	return calendar_selector->priv->shell_view;
+}
+
+static void
+e_calendar_selector_set_shell_view (ECalendarSelector *calendar_selector,
+				    EShellView *shell_view)
+{
+	g_return_if_fail (E_IS_SHELL_VIEW (shell_view));
+	g_return_if_fail (calendar_selector->priv->shell_view == NULL);
+
+	calendar_selector->priv->shell_view = g_object_ref (shell_view);
+}
+
+static void
+calendar_selector_set_property (GObject *object,
+				guint property_id,
+				const GValue *value,
+				GParamSpec *pspec)
+{
+	switch (property_id) {
+		case PROP_SHELL_VIEW:
+			e_calendar_selector_set_shell_view (
+				E_CALENDAR_SELECTOR (object),
+				g_value_get_object (value));
+			return;
+	}
+
+	G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+}
+
+static void
+calendar_selector_get_property (GObject *object,
+				guint property_id,
+				GValue *value,
+				GParamSpec *pspec)
+{
+	switch (property_id) {
+		case PROP_SHELL_VIEW:
+			g_value_set_object (
+				value,
+				e_calendar_selector_get_shell_view (E_CALENDAR_SELECTOR (object)));
+			return;
+	}
+
+	G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+}
+
+static void
+calendar_selector_dispose (GObject *object)
+{
+	ECalendarSelectorPrivate *priv;
+
+	priv = E_CALENDAR_SELECTOR_GET_PRIVATE (object);
+
+	g_clear_object (&priv->shell_view);
+
+	/* Chain up to the parent' s dispose() method. */
+	G_OBJECT_CLASS (e_calendar_selector_parent_class)->dispose (object);
 }
 
 static void
@@ -217,9 +410,24 @@ e_calendar_selector_class_init (ECalenda
 
 	object_class = G_OBJECT_CLASS (class);
 	object_class->constructed = calendar_selector_constructed;
+	object_class->set_property = calendar_selector_set_property;
+	object_class->get_property = calendar_selector_get_property;
+	object_class->dispose = calendar_selector_dispose;
 
 	source_selector_class = E_SOURCE_SELECTOR_CLASS (class);
 	source_selector_class->data_dropped = calendar_selector_data_dropped;
+
+	g_object_class_install_property (
+		object_class,
+		PROP_SHELL_VIEW,
+		g_param_spec_object (
+			"shell-view",
+			NULL,
+			NULL,
+			E_TYPE_SHELL_VIEW,
+			G_PARAM_READWRITE |
+			G_PARAM_CONSTRUCT_ONLY |
+			G_PARAM_STATIC_STRINGS));
 }
 
 static void
@@ -235,12 +443,14 @@ e_calendar_selector_init (ECalendarSelec
 }
 
 GtkWidget *
-e_calendar_selector_new (EClientCache *client_cache)
+e_calendar_selector_new (EClientCache *client_cache,
+			 EShellView *shell_view)
 {
 	ESourceRegistry *registry;
 	GtkWidget *widget;
 
 	g_return_val_if_fail (E_IS_CLIENT_CACHE (client_cache), NULL);
+	g_return_val_if_fail (E_IS_SHELL_VIEW (shell_view), NULL);
 
 	registry = e_client_cache_ref_registry (client_cache);
 
@@ -248,7 +458,9 @@ e_calendar_selector_new (EClientCache *c
 		E_TYPE_CALENDAR_SELECTOR,
 		"client-cache", client_cache,
 		"extension-name", E_SOURCE_EXTENSION_CALENDAR,
-		"registry", registry, NULL);
+		"registry", registry,
+		"shell-view", shell_view,
+		NULL);
 
 	g_object_unref (registry);
 
diff -up evolution-3.8.5/calendar/gui/e-calendar-selector.h.copy-move-recurrences evolution-3.8.5/calendar/gui/e-calendar-selector.h
--- evolution-3.8.5/calendar/gui/e-calendar-selector.h.copy-move-recurrences	2013-07-23 14:52:29.000000000 +0200
+++ evolution-3.8.5/calendar/gui/e-calendar-selector.h	2013-11-04 22:11:17.122317884 +0100
@@ -22,6 +22,7 @@
 #define E_CALENDAR_SELECTOR_H
 
 #include <e-util/e-util.h>
+#include <shell/e-shell-view.h>
 
 /* Standard GObject macros */
 #define E_TYPE_CALENDAR_SELECTOR \
@@ -58,7 +59,10 @@ struct _ECalendarSelectorClass {
 };
 
 GType		e_calendar_selector_get_type	(void);
-GtkWidget *	e_calendar_selector_new		(EClientCache *client_cache);
+GtkWidget *	e_calendar_selector_new		(EClientCache *client_cache,
+						 EShellView *shell_backend);
+EShellView *	e_calendar_selector_get_shell_view
+						(ECalendarSelector *calendar_selector);
 
 G_END_DECLS
 
diff -up evolution-3.8.5/calendar/gui/e-memo-list-selector.c.copy-move-recurrences evolution-3.8.5/calendar/gui/e-memo-list-selector.c
--- evolution-3.8.5/calendar/gui/e-memo-list-selector.c.copy-move-recurrences	2013-07-23 14:52:30.000000000 +0200
+++ evolution-3.8.5/calendar/gui/e-memo-list-selector.c	2013-11-04 22:11:17.122317884 +0100
@@ -32,7 +32,7 @@
 	((obj), E_TYPE_MEMO_LIST_SELECTOR, EMemoListSelectorPrivate))
 
 struct _EMemoListSelectorPrivate {
-	gint dummy_value;
+	EShellView *shell_view;
 };
 
 G_DEFINE_TYPE (
@@ -40,6 +40,11 @@ G_DEFINE_TYPE (
 	e_memo_list_selector,
 	E_TYPE_CLIENT_SELECTOR)
 
+enum {
+	PROP_0,
+	PROP_SHELL_VIEW
+};
+
 static gboolean
 memo_list_selector_update_single_object (ECalClient *client,
                                          icalcomponent *icalcomp)
@@ -323,6 +328,71 @@ memo_list_selector_data_dropped (ESource
 	return TRUE;
 }
 
+EShellView *
+e_memo_list_selector_get_shell_view (EMemoListSelector *memo_list_selector)
+{
+	g_return_val_if_fail (E_IS_MEMO_LIST_SELECTOR (memo_list_selector), NULL);
+
+	return memo_list_selector->priv->shell_view;
+}
+
+static void
+e_memo_list_selector_set_shell_view (EMemoListSelector *memo_list_selector,
+				     EShellView *shell_view)
+{
+	g_return_if_fail (E_IS_SHELL_VIEW (shell_view));
+	g_return_if_fail (memo_list_selector->priv->shell_view == NULL);
+
+	memo_list_selector->priv->shell_view = g_object_ref (shell_view);
+}
+
+static void
+memo_list_selector_set_property (GObject *object,
+				 guint property_id,
+				 const GValue *value,
+				 GParamSpec *pspec)
+{
+	switch (property_id) {
+		case PROP_SHELL_VIEW:
+			e_memo_list_selector_set_shell_view (
+				E_MEMO_LIST_SELECTOR (object),
+				g_value_get_object (value));
+			return;
+	}
+
+	G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+}
+
+static void
+memo_list_selector_get_property (GObject *object,
+				 guint property_id,
+				 GValue *value,
+				 GParamSpec *pspec)
+{
+	switch (property_id) {
+		case PROP_SHELL_VIEW:
+			g_value_set_object (
+				value,
+				e_memo_list_selector_get_shell_view (E_MEMO_LIST_SELECTOR (object)));
+			return;
+	}
+
+	G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+}
+
+static void
+memo_list_selector_dispose (GObject *object)
+{
+	EMemoListSelectorPrivate *priv;
+
+	priv = E_MEMO_LIST_SELECTOR_GET_PRIVATE (object);
+
+	g_clear_object (&priv->shell_view);
+
+	/* Chain up to the parent' s dispose() method. */
+	G_OBJECT_CLASS (e_memo_list_selector_parent_class)->dispose (object);
+}
+
 static void
 e_memo_list_selector_class_init (EMemoListSelectorClass *class)
 {
@@ -333,9 +403,24 @@ e_memo_list_selector_class_init (EMemoLi
 
 	object_class = G_OBJECT_CLASS (class);
 	object_class->constructed = memo_list_selector_constructed;
+	object_class->set_property = memo_list_selector_set_property;
+	object_class->get_property = memo_list_selector_get_property;
+	object_class->dispose = memo_list_selector_dispose;
 
 	source_selector_class = E_SOURCE_SELECTOR_CLASS (class);
 	source_selector_class->data_dropped = memo_list_selector_data_dropped;
+
+	g_object_class_install_property (
+		object_class,
+		PROP_SHELL_VIEW,
+		g_param_spec_object (
+			"shell-view",
+			NULL,
+			NULL,
+			E_TYPE_SHELL_VIEW,
+			G_PARAM_READWRITE |
+			G_PARAM_CONSTRUCT_ONLY |
+			G_PARAM_STATIC_STRINGS));
 }
 
 static void
@@ -351,12 +436,14 @@ e_memo_list_selector_init (EMemoListSele
 }
 
 GtkWidget *
-e_memo_list_selector_new (EClientCache *client_cache)
+e_memo_list_selector_new (EClientCache *client_cache,
+			  EShellView *shell_view)
 {
 	ESourceRegistry *registry;
 	GtkWidget *widget;
 
 	g_return_val_if_fail (E_IS_CLIENT_CACHE (client_cache), NULL);
+	g_return_val_if_fail (E_IS_SHELL_VIEW (shell_view), NULL);
 
 	registry = e_client_cache_ref_registry (client_cache);
 
@@ -364,6 +451,7 @@ e_memo_list_selector_new (EClientCache *
 		E_TYPE_MEMO_LIST_SELECTOR,
 		"client-cache", client_cache,
 		"extension-name", E_SOURCE_EXTENSION_MEMO_LIST,
+		"shell-view", shell_view,
 		"registry", registry, NULL);
 
 	g_object_unref (registry);
diff -up evolution-3.8.5/calendar/gui/e-memo-list-selector.h.copy-move-recurrences evolution-3.8.5/calendar/gui/e-memo-list-selector.h
--- evolution-3.8.5/calendar/gui/e-memo-list-selector.h.copy-move-recurrences	2013-07-23 14:52:30.000000000 +0200
+++ evolution-3.8.5/calendar/gui/e-memo-list-selector.h	2013-11-04 22:11:17.123317884 +0100
@@ -27,6 +27,7 @@
 #define E_MEMO_LIST_SELECTOR_H
 
 #include <e-util/e-util.h>
+#include <shell/e-shell-view.h>
 
 /* Standard GObject macros */
 #define E_TYPE_MEMO_LIST_SELECTOR \
@@ -63,7 +64,10 @@ struct _EMemoListSelectorClass {
 };
 
 GType		e_memo_list_selector_get_type	(void);
-GtkWidget *	e_memo_list_selector_new	(EClientCache *client_cache);
+GtkWidget *	e_memo_list_selector_new	(EClientCache *client_cache,
+						 EShellView *shell_view);
+EShellView *	e_memo_list_selector_get_shell_view
+						(EMemoListSelector *memo_list_selector);
 
 G_END_DECLS
 
diff -up evolution-3.8.5/calendar/gui/e-task-list-selector.c.copy-move-recurrences evolution-3.8.5/calendar/gui/e-task-list-selector.c
--- evolution-3.8.5/calendar/gui/e-task-list-selector.c.copy-move-recurrences	2013-07-23 14:52:36.000000000 +0200
+++ evolution-3.8.5/calendar/gui/e-task-list-selector.c	2013-11-04 22:11:17.123317884 +0100
@@ -32,7 +32,7 @@
 	((obj), E_TYPE_TASK_LIST_SELECTOR, ETaskListSelectorPrivate))
 
 struct _ETaskListSelectorPrivate {
-	gint dummy_value;
+	EShellView *shell_view;
 };
 
 G_DEFINE_TYPE (
@@ -40,6 +40,11 @@ G_DEFINE_TYPE (
 	e_task_list_selector,
 	E_TYPE_CLIENT_SELECTOR)
 
+enum {
+	PROP_0,
+	PROP_SHELL_VIEW
+};
+
 static gboolean
 task_list_selector_update_single_object (ECalClient *client,
                                          icalcomponent *icalcomp)
@@ -325,6 +330,71 @@ task_list_selector_data_dropped (ESource
 	return TRUE;
 }
 
+EShellView *
+e_task_list_selector_get_shell_view (ETaskListSelector *task_list_selector)
+{
+	g_return_val_if_fail (E_IS_TASK_LIST_SELECTOR (task_list_selector), NULL);
+
+	return task_list_selector->priv->shell_view;
+}
+
+static void
+e_task_list_selector_set_shell_view (ETaskListSelector *task_list_selector,
+				     EShellView *shell_view)
+{
+	g_return_if_fail (E_IS_SHELL_VIEW (shell_view));
+	g_return_if_fail (task_list_selector->priv->shell_view == NULL);
+
+	task_list_selector->priv->shell_view = g_object_ref (shell_view);
+}
+
+static void
+task_list_selector_set_property (GObject *object,
+				 guint property_id,
+				 const GValue *value,
+				 GParamSpec *pspec)
+{
+	switch (property_id) {
+		case PROP_SHELL_VIEW:
+			e_task_list_selector_set_shell_view (
+				E_TASK_LIST_SELECTOR (object),
+				g_value_get_object (value));
+			return;
+	}
+
+	G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+}
+
+static void
+task_list_selector_get_property (GObject *object,
+				 guint property_id,
+				 GValue *value,
+				 GParamSpec *pspec)
+{
+	switch (property_id) {
+		case PROP_SHELL_VIEW:
+			g_value_set_object (
+				value,
+				e_task_list_selector_get_shell_view (E_TASK_LIST_SELECTOR (object)));
+			return;
+	}
+
+	G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+}
+
+static void
+task_list_selector_dispose (GObject *object)
+{
+	ETaskListSelectorPrivate *priv;
+
+	priv = E_TASK_LIST_SELECTOR_GET_PRIVATE (object);
+
+	g_clear_object (&priv->shell_view);
+
+	/* Chain up to the parent' s dispose() method. */
+	G_OBJECT_CLASS (e_task_list_selector_parent_class)->dispose (object);
+}
+
 static void
 e_task_list_selector_class_init (ETaskListSelectorClass *class)
 {
@@ -335,9 +405,24 @@ e_task_list_selector_class_init (ETaskLi
 
 	object_class = G_OBJECT_CLASS (class);
 	object_class->constructed = task_list_selector_constructed;
+	object_class->set_property = task_list_selector_set_property;
+	object_class->get_property = task_list_selector_get_property;
+	object_class->dispose = task_list_selector_dispose;
 
 	source_selector_class = E_SOURCE_SELECTOR_CLASS (class);
 	source_selector_class->data_dropped = task_list_selector_data_dropped;
+
+	g_object_class_install_property (
+		object_class,
+		PROP_SHELL_VIEW,
+		g_param_spec_object (
+			"shell-view",
+			NULL,
+			NULL,
+			E_TYPE_SHELL_VIEW,
+			G_PARAM_READWRITE |
+			G_PARAM_CONSTRUCT_ONLY |
+			G_PARAM_STATIC_STRINGS));
 }
 
 static void
@@ -353,12 +438,14 @@ e_task_list_selector_init (ETaskListSele
 }
 
 GtkWidget *
-e_task_list_selector_new (EClientCache *client_cache)
+e_task_list_selector_new (EClientCache *client_cache,
+			  EShellView *shell_view)
 {
 	ESourceRegistry *registry;
 	GtkWidget *widget;
 
 	g_return_val_if_fail (E_IS_CLIENT_CACHE (client_cache), NULL);
+	g_return_val_if_fail (E_IS_SHELL_VIEW (shell_view), NULL);
 
 	registry = e_client_cache_ref_registry (client_cache);
 
@@ -366,6 +453,7 @@ e_task_list_selector_new (EClientCache *
 		E_TYPE_TASK_LIST_SELECTOR,
 		"client-cache", client_cache,
 		"extension-name", E_SOURCE_EXTENSION_TASK_LIST,
+		"shell-view", shell_view,
 		"registry", registry, NULL);
 
 	g_object_unref (registry);
diff -up evolution-3.8.5/calendar/gui/e-task-list-selector.h.copy-move-recurrences evolution-3.8.5/calendar/gui/e-task-list-selector.h
--- evolution-3.8.5/calendar/gui/e-task-list-selector.h.copy-move-recurrences	2013-07-23 14:52:30.000000000 +0200
+++ evolution-3.8.5/calendar/gui/e-task-list-selector.h	2013-11-04 22:11:17.123317884 +0100
@@ -27,6 +27,7 @@
 #define E_TASK_LIST_SELECTOR_H
 
 #include <e-util/e-util.h>
+#include <shell/e-shell-view.h>
 
 /* Standard GObject macros */
 #define E_TYPE_TASK_LIST_SELECTOR \
@@ -63,7 +64,10 @@ struct _ETaskListSelectorClass {
 };
 
 GType		e_task_list_selector_get_type	(void);
-GtkWidget *	e_task_list_selector_new	(EClientCache *client_cache);
+GtkWidget *	e_task_list_selector_new	(EClientCache *client_cache,
+						 EShellView *shell_view);
+EShellView *	e_task_list_selector_get_shell_view
+						(ETaskListSelector *task_list_selector);
 
 G_END_DECLS
 
diff -up evolution-3.8.5/modules/calendar/e-cal-shell-sidebar.c.copy-move-recurrences evolution-3.8.5/modules/calendar/e-cal-shell-sidebar.c
--- evolution-3.8.5/modules/calendar/e-cal-shell-sidebar.c.copy-move-recurrences	2013-07-23 14:51:47.000000000 +0200
+++ evolution-3.8.5/modules/calendar/e-cal-shell-sidebar.c	2013-11-04 22:11:17.124317884 +0100
@@ -576,7 +576,7 @@ cal_shell_sidebar_constructed (GObject *
 	container = widget;
 
 	client_cache = e_shell_get_client_cache (shell);
-	widget = e_calendar_selector_new (client_cache);
+	widget = e_calendar_selector_new (client_cache, shell_view);
 	e_source_selector_set_select_new (E_SOURCE_SELECTOR (widget), TRUE);
 	gtk_container_add (GTK_CONTAINER (container), widget);
 	a11y = gtk_widget_get_accessible (widget);
diff -up evolution-3.8.5/modules/calendar/e-cal-shell-view-private.c.copy-move-recurrences evolution-3.8.5/modules/calendar/e-cal-shell-view-private.c
--- evolution-3.8.5/modules/calendar/e-cal-shell-view-private.c.copy-move-recurrences	2013-07-23 14:51:48.000000000 +0200
+++ evolution-3.8.5/modules/calendar/e-cal-shell-view-private.c	2013-11-04 22:11:17.125317884 +0100
@@ -914,30 +914,78 @@ e_cal_shell_view_set_status_message (ECa
 	cal_shell_view->priv->calendar_activity = activity;
 }
 
-struct ForeachTzidData
+static void
+cal_transferring_update_alert (ECalShellView *cal_shell_view,
+			       const gchar *domain,
+			       const gchar *calendar,
+			       const gchar *message)
 {
-	ECalClient *source_client;
-	ECalClient *dest_client;
-};
+	ECalShellViewPrivate *priv;
+	EShellContent *shell_content;
+	EAlert *alert;
+
+	g_return_if_fail (cal_shell_view != NULL);
+	g_return_if_fail (cal_shell_view->priv != NULL);
+
+	priv = cal_shell_view->priv;
+
+	if (priv->transfer_alert) {
+		e_alert_response (
+			priv->transfer_alert,
+			e_alert_get_default_response (priv->transfer_alert));
+		priv->transfer_alert = NULL;
+	}
+
+	if (!message)
+		return;
+
+	alert = e_alert_new (domain, calendar, message, NULL);
+	g_return_if_fail (alert != NULL);
+
+	priv->transfer_alert = alert;
+	g_object_add_weak_pointer (G_OBJECT (alert), &priv->transfer_alert);
+	e_alert_start_timer (priv->transfer_alert, 300);
+
+	shell_content = e_shell_view_get_shell_content (E_SHELL_VIEW (cal_shell_view));
+	e_alert_sink_submit_alert (E_ALERT_SINK (shell_content), priv->transfer_alert);
+	g_object_unref (priv->transfer_alert);
+}
+
+typedef struct _TransferItemToData {
+	ECalShellView *cal_shell_view;
+	EActivity *activity;
+	const gchar *display_name;
+	gboolean remove;
+} TransferItemToData;
 
 static void
-add_timezone_to_cal_cb (icalparameter *param,
-                        gpointer data)
+transfer_item_to_cb (GObject *src_object,
+		     GAsyncResult *result,
+		     gpointer user_data)
 {
-	struct ForeachTzidData *ftd = data;
-	icaltimezone *tz = NULL;
-	const gchar *tzid;
-
-	g_return_if_fail (ftd != NULL);
-	g_return_if_fail (ftd->source_client != NULL);
-	g_return_if_fail (ftd->dest_client != NULL);
+	TransferItemToData *titd = user_data;
+	GError *error = NULL;
+	GCancellable *cancellable;
+	gboolean success;
 
-	tzid = icalparameter_get_tzid (param);
-	if (!tzid || !*tzid)
-		return;
+	success = cal_comp_transfer_item_to_finish (E_CAL_CLIENT (src_object), result, &error);
+
+	cancellable = e_activity_get_cancellable (titd->activity);
+	e_activity_set_state (
+		titd->activity,
+		g_cancellable_is_cancelled (cancellable) ? E_ACTIVITY_CANCELLED : E_ACTIVITY_COMPLETED);
+
+	if (!success) {
+		cal_transferring_update_alert (
+			titd->cal_shell_view,
+			titd->remove ? "calendar:failed-move-event" : "calendar:failed-copy-event",
+			titd->display_name,
+			error->message);
+		g_clear_error (&error);
+	}
 
-	if (e_cal_client_get_timezone_sync (ftd->source_client, tzid, &tz, NULL, NULL) && tz)
-		e_cal_client_add_timezone_sync (ftd->dest_client, tz, NULL, NULL);
+	g_object_unref (titd->activity);
+	g_free (titd);
 }
 
 void
@@ -946,129 +994,50 @@ e_cal_shell_view_transfer_item_to (ECalS
                                    ECalClient *destination_client,
                                    gboolean remove)
 {
-	icalcomponent *icalcomp;
-	icalcomponent *icalcomp_clone;
-	icalcomponent *icalcomp_event;
-	gboolean success;
-	const gchar *uid;
-
-	/* XXX This function should be split up into
-	 *     smaller, more understandable pieces. */
+	EActivity *activity;
+	EShellBackend *shell_backend;
+	ESource *source;
+	GCancellable *cancellable = NULL;
+	gchar *message;
+	const gchar *display_name;
+	TransferItemToData *titd;
 
 	g_return_if_fail (E_IS_CAL_SHELL_VIEW (cal_shell_view));
 	g_return_if_fail (event != NULL);
+	g_return_if_fail (is_comp_data_valid (event) != FALSE);
 	g_return_if_fail (E_IS_CAL_CLIENT (destination_client));
 
 	if (!is_comp_data_valid (event))
 		return;
 
-	icalcomp_event = event->comp_data->icalcomp;
-	uid = icalcomponent_get_uid (icalcomp_event);
-
-	/* Put the new object into the destination calendar. */
+	source = e_client_get_source (E_CLIENT (destination_client));
+	display_name = e_source_get_display_name (source);
 
-	success = e_cal_client_get_object_sync (
-		destination_client, uid, NULL, &icalcomp, NULL, NULL);
-
-	if (success) {
-		icalcomponent_free (icalcomp);
-		success = e_cal_client_modify_object_sync (
-			destination_client, icalcomp_event,
-			CALOBJ_MOD_ALL, NULL, NULL);
-
-		/* do not delete the event when it was found in the calendar */
-		return;
-	} else {
-		icalproperty *icalprop;
-		gchar *new_uid;
-		GError *error = NULL;
-		struct ForeachTzidData ftd;
-
-		ftd.source_client = event->comp_data->client;
-		ftd.dest_client = destination_client;
-
-		if (e_cal_util_component_is_instance (icalcomp_event)) {
-			success = e_cal_client_get_object_sync (
-				event->comp_data->client,
-				uid, NULL, &icalcomp, NULL, NULL);
-			if (success) {
-				/* Use master object when working
-				 * with a recurring event ... */
-				icalcomp_clone = icalcomponent_new_clone (icalcomp);
-				icalcomponent_free (icalcomp);
-			} else {
-				/* ... or remove the recurrence ID ... */
-				icalcomp_clone =
-					icalcomponent_new_clone (icalcomp_event);
-				if (e_cal_util_component_has_recurrences (icalcomp_clone)) {
-					/* ... for non-detached instances,
-					 * to make it a master object. */
-					icalprop = icalcomponent_get_first_property (
-						icalcomp_clone, ICAL_RECURRENCEID_PROPERTY);
-					if (icalprop != NULL)
-						icalcomponent_remove_property (
-							icalcomp_clone, icalprop);
-				}
-			}
-		} else
-			icalcomp_clone =
-				icalcomponent_new_clone (icalcomp_event);
-
-		icalprop = icalproperty_new_x ("1");
-		icalproperty_set_x_name (icalprop, "X-EVOLUTION-MOVE-CALENDAR");
-		icalcomponent_add_property (icalcomp_clone, icalprop);
-
-		if (!remove) {
-			/* Change the UID to avoid problems with
-			 * duplicated UIDs. */
-			new_uid = e_cal_component_gen_uid ();
-			icalcomponent_set_uid (icalcomp_clone, new_uid);
-			g_free (new_uid);
-		}
-
-		new_uid = NULL;
-		icalcomponent_foreach_tzid (
-			icalcomp_clone, add_timezone_to_cal_cb, &ftd);
-		success = e_cal_client_create_object_sync (
-			destination_client, icalcomp_clone,
-			&new_uid, NULL, &error);
-		if (!success) {
-			icalcomponent_free (icalcomp_clone);
-			g_warning (
-				"%s: Failed to create object: %s",
-				G_STRFUNC, error->message);
-			g_error_free (error);
-			return;
-		}
-
-		icalcomponent_free (icalcomp_clone);
-		g_free (new_uid);
-	}
-
-	if (remove) {
-		ECalClient *source_client = event->comp_data->client;
-
-		/* Remove the item from the source calendar. */
-		if (e_cal_util_component_is_instance (icalcomp_event) ||
-			e_cal_util_component_has_recurrences (icalcomp_event)) {
-			icaltimetype icaltime;
-			gchar *rid;
-
-			icaltime =
-				icalcomponent_get_recurrenceid (icalcomp_event);
-			if (!icaltime_is_null_time (icaltime))
-				rid = icaltime_as_ical_string_r (icaltime);
-			else
-				rid = NULL;
-			e_cal_client_remove_object_sync (
-				source_client, uid, rid,
-				CALOBJ_MOD_ALL, NULL, NULL);
-			g_free (rid);
-		} else
-			e_cal_client_remove_object_sync (
-				source_client, uid, NULL,
-				CALOBJ_MOD_THIS, NULL, NULL);
-	}
+	message = remove ?
+		g_strdup_printf (_("Moving an event into the calendar %s"), display_name) :
+		g_strdup_printf (_("Copying an event into the calendar %s"), display_name);
+
+	shell_backend = e_shell_view_get_shell_backend (E_SHELL_VIEW (cal_shell_view));
+
+	cancellable = g_cancellable_new ();
+	activity = e_activity_new ();
+	e_activity_set_cancellable (activity, cancellable);
+	e_activity_set_state (activity, E_ACTIVITY_RUNNING);
+	e_activity_set_text (activity, message);
+	g_free (message);
+
+	e_shell_backend_add_activity (shell_backend, activity);
+
+	titd = g_new0 (TransferItemToData, 1);
+
+	titd->cal_shell_view = cal_shell_view;
+	titd->activity = activity;
+	titd->display_name = display_name;
+	titd->remove = remove;
+
+	cal_comp_transfer_item_to (
+		event->comp_data->client, destination_client,
+		event->comp_data->icalcomp, !remove, cancellable, transfer_item_to_cb, titd);
 }
 
 void
diff -up evolution-3.8.5/modules/calendar/e-cal-shell-view-private.h.copy-move-recurrences evolution-3.8.5/modules/calendar/e-cal-shell-view-private.h
--- evolution-3.8.5/modules/calendar/e-cal-shell-view-private.h.copy-move-recurrences	2013-07-23 14:51:48.000000000 +0200
+++ evolution-3.8.5/modules/calendar/e-cal-shell-view-private.h	2013-11-04 22:11:17.125317884 +0100
@@ -115,6 +115,9 @@ struct _ECalShellViewPrivate {
 	gint search_direction; /* negative value is backward, positive is forward, zero is error; in days */
 	GSList *search_hit_cache; /* pointers on time_t for matched events */
 
+	/* Event/Task/Memo transferring */
+	gpointer transfer_alert; /* weak pointer to EAlert * */
+
         GFileMonitor *monitors[CHECK_NB];
 };
 
diff -up evolution-3.8.5/modules/calendar/e-memo-shell-sidebar.c.copy-move-recurrences evolution-3.8.5/modules/calendar/e-memo-shell-sidebar.c
--- evolution-3.8.5/modules/calendar/e-memo-shell-sidebar.c.copy-move-recurrences	2013-07-23 14:51:47.000000000 +0200
+++ evolution-3.8.5/modules/calendar/e-memo-shell-sidebar.c	2013-11-04 22:11:17.126317884 +0100
@@ -507,7 +507,7 @@ memo_shell_sidebar_constructed (GObject
 	container = GTK_CONTAINER (widget);
 
 	client_cache = e_shell_get_client_cache (shell);
-	widget = e_memo_list_selector_new (client_cache);
+	widget = e_memo_list_selector_new (client_cache, shell_view);
 	e_source_selector_set_select_new (E_SOURCE_SELECTOR (widget), TRUE);
 	gtk_container_add (container, widget);
 	a11y = gtk_widget_get_accessible (widget);
diff -up evolution-3.8.5/modules/calendar/e-task-shell-sidebar.c.copy-move-recurrences evolution-3.8.5/modules/calendar/e-task-shell-sidebar.c
--- evolution-3.8.5/modules/calendar/e-task-shell-sidebar.c.copy-move-recurrences	2013-07-23 14:51:47.000000000 +0200
+++ evolution-3.8.5/modules/calendar/e-task-shell-sidebar.c	2013-11-04 22:11:17.126317884 +0100
@@ -507,7 +507,7 @@ task_shell_sidebar_constructed (GObject
 	container = GTK_CONTAINER (widget);
 
 	client_cache = e_shell_get_client_cache (shell);
-	widget = e_task_list_selector_new (client_cache);
+	widget = e_task_list_selector_new (client_cache, shell_view);
 	e_source_selector_set_select_new (E_SOURCE_SELECTOR (widget), TRUE);
 	gtk_container_add (container, widget);
 	a11y = gtk_widget_get_accessible (widget);