[evolution-data-server] Really implement e_cal_client_view_set_fields_of_interest().



commit 466623351e070410d7cc1e0a3cfb485210d6015a
Author: Tristan Van Berkom <tristan van berkom gmail com>
Date:   Sat Oct 15 11:34:32 2011 -0400

    Really implement e_cal_client_view_set_fields_of_interest().
    
    As discussed on bug https://bugzilla.gnome.org/show_bug.cgi?id=652180,
    this patch adds many '_component' variants to functions that are named
    with '_object', all the '_component' variants take an 'icalcomponent *'
    instead of an ical string.
    
    The magic filtering happens in e_data_cal_view_get_component_string()
    which creates an ical string representation while omitting properties
    that are not mentioned in the fields of interest.

 calendar/backends/caldav/e-cal-backend-caldav.c    |  167 ++++++-----
 .../backends/contacts/e-cal-backend-contacts.c     |   11 +-
 calendar/backends/file/e-cal-backend-file.c        |  302 +++++++++++++------
 calendar/backends/http/e-cal-backend-http.c        |   46 ++--
 calendar/libedata-cal/e-cal-backend-sync.c         |  115 ++++---
 calendar/libedata-cal/e-cal-backend-sync.h         |   12 +-
 calendar/libedata-cal/e-cal-backend.c              |  294 +++++++++++++++++--
 calendar/libedata-cal/e-cal-backend.h              |    6 +
 calendar/libedata-cal/e-data-cal-view.c            |  316 +++++++++++++++++++-
 calendar/libedata-cal/e-data-cal-view.h            |    8 +
 calendar/libedata-cal/e-data-cal.c                 |   40 ++--
 calendar/libedata-cal/e-data-cal.h                 |    6 +-
 12 files changed, 1015 insertions(+), 308 deletions(-)
---
diff --git a/calendar/backends/caldav/e-cal-backend-caldav.c b/calendar/backends/caldav/e-cal-backend-caldav.c
index facdd52..c6b071c 100644
--- a/calendar/backends/caldav/e-cal-backend-caldav.c
+++ b/calendar/backends/caldav/e-cal-backend-caldav.c
@@ -3524,11 +3524,11 @@ replace_master (ECalBackendCalDAV *cbdav,
 
 /* a busy_lock is supposed to be locked already, when calling this function */
 static void
-do_create_object (ECalBackendCalDAV *cbdav,
-                  const gchar *in_calobj,
-                  gchar **uid,
-                  gchar **new_calobj,
-                  GError **perror)
+do_create_object (ECalBackendCalDAV *cbdav, 
+		  const gchar       *in_calobj, 
+		  gchar            **uid, 
+		  icalcomponent    **new_component,
+		  GError           **perror)
 {
 	ECalComponent            *comp;
 	gboolean                  online, did_put = FALSE;
@@ -3610,13 +3610,15 @@ do_create_object (ECalBackendCalDAV *cbdav,
 			icalcomponent *master = get_master_comp (cbdav, icalcomp);
 
 			if (!master)
-				*new_calobj = e_cal_component_get_as_string (comp);
+			  *new_component =
+			    icalcomponent_new_clone (e_cal_component_get_icalcomponent (comp));
 			else
-				*new_calobj = icalcomponent_as_ical_string_r (master);
+			  *new_component = icalcomponent_new_clone (master);
 
 			icalcomponent_free (icalcomp);
 		} else {
-			*new_calobj = e_cal_component_get_as_string (comp);
+		  *new_component =
+		    icalcomponent_new_clone (e_cal_component_get_icalcomponent (comp));
 		}
 	}
 
@@ -3626,11 +3628,11 @@ do_create_object (ECalBackendCalDAV *cbdav,
 /* a busy_lock is supposed to be locked already, when calling this function */
 static void
 do_modify_object (ECalBackendCalDAV *cbdav,
-                  const gchar *calobj,
-                  CalObjModType mod,
-                  gchar **old_object,
-                  gchar **new_object,
-                  GError **error)
+		  const gchar    *calobj,
+		  CalObjModType   mod,
+		  icalcomponent **old_component,
+		  icalcomponent **new_component,
+		  GError        **error)
 {
 	ECalBackendCalDAVPrivate *priv;
 	ECalComponent            *comp;
@@ -3642,8 +3644,8 @@ do_modify_object (ECalBackendCalDAV *cbdav,
 
 	priv  = cbdav->priv;
 
-	if (new_object)
-		*new_object = NULL;
+	if (new_component)
+		*new_component = NULL;
 
 	if (!check_state (cbdav, &online, error))
 		return;
@@ -3689,26 +3691,28 @@ do_modify_object (ECalBackendCalDAV *cbdav,
 		/*ecalcomp_set_synch_state (comp, ECALCOMP_LOCALLY_MODIFIED);*/
 	}
 
-	if (old_object) {
-		*old_object = NULL;
+	if (old_component) {
+		*old_component = NULL;
 
 		if (e_cal_component_is_instance (comp)) {
 			/* set detached instance as the old object, if any */
 			ECalComponent *old_instance = e_cal_backend_store_get_component (priv->store, id->uid, id->rid);
 
+			/* This will give a reference to 'old_component' */
 			if (old_instance) {
-				*old_object = e_cal_component_get_as_string (old_instance);
+				*old_component =
+					icalcomponent_new_clone (e_cal_component_get_icalcomponent
+								 (old_instance));
 				g_object_unref (old_instance);
 			}
 		}
 
-		if (!*old_object) {
+		if (!*old_component) {
 			icalcomponent *master = get_master_comp (cbdav, cache_comp);
 
-			if (master) {
-				/* set full component as the old object */
-				*old_object = icalcomponent_as_ical_string_r (master);
-			}
+			if (master)
+			  /* set full component as the old object */
+			  *old_component = icalcomponent_new_clone (master);
 		}
 	}
 
@@ -3719,8 +3723,8 @@ do_modify_object (ECalBackendCalDAV *cbdav,
 			icalcomponent *new_comp = e_cal_component_get_icalcomponent (comp);
 
 			/* new object is only this instance */
-			if (new_object)
-				*new_object = e_cal_component_get_as_string (comp);
+			if (new_component)
+				*new_component = icalcomponent_new_clone (new_comp);
 
 			/* add the detached instance */
 			if (icalcomponent_isa (cache_comp) == ICAL_VCALENDAR_COMPONENT) {
@@ -3774,7 +3778,7 @@ do_modify_object (ECalBackendCalDAV *cbdav,
 	}
 
 	if (did_put) {
-		if (new_object && !*new_object) {
+		if (new_component && !*new_component) {
 			/* read the comp from cache again, as some servers can modify it on put */
 			icalcomponent *newcomp = get_comp_from_cache (cbdav, id->uid, NULL, NULL, NULL), *master;
 
@@ -3784,7 +3788,7 @@ do_modify_object (ECalBackendCalDAV *cbdav,
 			master = get_master_comp (cbdav, newcomp);
 
 			if (master)
-				*new_object = icalcomponent_as_ical_string_r (master);
+				*new_component = icalcomponent_new_clone (master);
 
 			if (cache_comp != newcomp)
 				icalcomponent_free (newcomp);
@@ -3801,12 +3805,12 @@ do_modify_object (ECalBackendCalDAV *cbdav,
 /* a busy_lock is supposed to be locked already, when calling this function */
 static void
 do_remove_object (ECalBackendCalDAV *cbdav,
-                  const gchar *uid,
-                  const gchar *rid,
-                  CalObjModType mod,
-                  gchar **old_object,
-                  gchar **object,
-                  GError **perror)
+		  const gchar       *uid,
+		  const gchar       *rid,
+		  CalObjModType      mod,
+		  icalcomponent    **old_component,
+		  icalcomponent    **component,
+		  GError           **perror)
 {
 	ECalBackendCalDAVPrivate *priv;
 	icalcomponent            *cache_comp;
@@ -3815,8 +3819,8 @@ do_remove_object (ECalBackendCalDAV *cbdav,
 
 	priv  = cbdav->priv;
 
-	if (object)
-		*object = NULL;
+	if (component)
+		*component = NULL;
 
 	if (!check_state (cbdav, &online, perror))
 		return;
@@ -3828,17 +3832,18 @@ do_remove_object (ECalBackendCalDAV *cbdav,
 		return;
 	}
 
-	if (old_object) {
+	if (old_component) {
 		ECalComponent *old = e_cal_backend_store_get_component (priv->store, uid, rid);
 
 		if (old) {
-			*old_object = e_cal_component_get_as_string (old);
+			*old_component = 
+				icalcomponent_new_clone (e_cal_component_get_icalcomponent (old));
 			g_object_unref (old);
 		} else {
 			icalcomponent *master = get_master_comp (cbdav, cache_comp);
 
 			if (master)
-				*old_object = icalcomponent_as_ical_string_r (master);
+				*old_component = icalcomponent_new_clone (master);
 		}
 	}
 
@@ -3848,11 +3853,11 @@ do_remove_object (ECalBackendCalDAV *cbdav,
 		if (rid && *rid) {
 			/* remove one instance from the component */
 			if (remove_instance (cbdav, cache_comp, icaltime_from_string (rid), mod, mod != CALOBJ_MOD_ONLY_THIS)) {
-				if (object) {
+				if (component) {
 					icalcomponent *master = get_master_comp (cbdav, cache_comp);
 
 					if (master)
-						*object = icalcomponent_as_ical_string_r (master);
+						*component = icalcomponent_new_clone (master);
 				}
 			} else {
 				/* this was the last instance, thus delete whole component */
@@ -4012,60 +4017,69 @@ process_object (ECalBackendCalDAV *cbdav,
 		is_declined = e_cal_backend_user_declined (e_cal_component_get_icalcomponent (ecomp));
 		if (is_in_cache) {
 			if (!is_declined) {
-				gchar *new_object = NULL, *old_object = NULL;
+				icalcomponent *new_component = NULL, *old_component = NULL;
 
-				do_modify_object (cbdav, new_obj_str, mod, &old_object, &new_object, &err);
+				do_modify_object (cbdav, new_obj_str, mod, 
+						  &old_component, &new_component, &err);
 				if (!err) {
-					if (!old_object)
-						e_cal_backend_notify_object_created (backend, new_object);
+					if (!old_component)
+						e_cal_backend_notify_component_created (backend, new_component);
 					else
-						e_cal_backend_notify_object_modified (backend, old_object, new_object);
+						e_cal_backend_notify_component_modified (backend, old_component, new_component);
 				}
 
-				g_free (new_object);
-				g_free (old_object);
+				if (new_component)
+					icalcomponent_free (new_component);
+				if (old_component)
+					icalcomponent_free (old_component);
 			} else {
-				gchar *new_object = NULL, *old_object = NULL;
+				icalcomponent *new_component = NULL, *old_component = NULL;
 
-				do_remove_object (cbdav, id->uid, id->rid, mod, &old_object, &new_object, &err);
+				do_remove_object (cbdav, id->uid, id->rid, mod, &old_component, &new_component, &err);
 				if (!err) {
-					if (new_object) {
-						e_cal_backend_notify_object_modified (backend, old_object, new_object);
+					if (new_component) {
+						e_cal_backend_notify_component_modified (backend, old_component, new_component);
 					} else {
-						e_cal_backend_notify_object_removed (backend, id, old_object, NULL);
+						e_cal_backend_notify_component_removed (backend, id, old_component, NULL);
 					}
 				}
 
-				g_free (new_object);
-				g_free (old_object);
+				if (new_component)
+					icalcomponent_free (new_component);
+				if (old_component)
+					icalcomponent_free (old_component);
 			}
 		} else if (!is_declined) {
-			gchar *new_object = new_obj_str;
+			icalcomponent *new_component = NULL;
+
+			do_create_object (cbdav, new_obj_str, NULL, &new_component, &err);
 
-			do_create_object (cbdav, new_object, NULL, &new_object, &err);
 			if (!err) {
-				e_cal_backend_notify_object_created (backend, new_object);
+				e_cal_backend_notify_component_created (backend, new_component);
 			}
 
-			if (new_object != new_obj_str)
-				g_free (new_object);
+			if (new_component)
+				icalcomponent_free (new_component);
+
 		}
 		break;
 	case ICAL_METHOD_CANCEL:
 		if (is_in_cache) {
-			gchar *old_object = NULL, *new_object = NULL;
+			icalcomponent *new_component = NULL, *old_component = NULL;
 
-			do_remove_object (cbdav, id->uid, id->rid, CALOBJ_MOD_THIS, &old_object, &new_object, &err);
+			do_remove_object (cbdav, id->uid, id->rid, CALOBJ_MOD_THIS, &old_component, &new_component, &err);
 			if (!err) {
-				if (new_object) {
-					e_cal_backend_notify_object_modified (backend, old_object, new_object);
+				if (new_component) {
+					e_cal_backend_notify_component_modified (backend, old_component, new_component);
 				} else {
-					e_cal_backend_notify_object_removed (backend, id, old_object, NULL);
+					e_cal_backend_notify_component_removed (backend, id, old_component, NULL);
 				}
 			}
 
-			g_free (old_object);
-			g_free (new_object);
+			if (new_component)
+				icalcomponent_free (new_component);
+			if (old_component)
+				icalcomponent_free (old_component);
 		} else {
 			err = EDC_ERROR (ObjectNotFound);
 		}
@@ -4142,7 +4156,6 @@ do_receive_objects (ECalBackendSync *backend,
 		}
 
 		process_object (cbdav, ecomp, online, method, &err);
-
 		g_object_unref (ecomp);
 	}
 
@@ -4193,13 +4206,13 @@ caldav_busy_stub (
                   GCancellable *cancellable,
                   const gchar *in_calobj,
                   gchar **uid,
-                  gchar **new_calobj,
+                  icalcomponent **new_component,
                   GError **perror),
         do_create_object,
                   (cbdav,
                   in_calobj,
                   uid,
-                  new_calobj,
+                  new_component,
                   perror))
 
 caldav_busy_stub (
@@ -4209,15 +4222,15 @@ caldav_busy_stub (
                   GCancellable *cancellable,
                   const gchar *calobj,
                   CalObjModType mod,
-                  gchar **old_object,
-                  gchar **new_object,
+                  icalcomponent **old_component,
+                  icalcomponent **new_component,
                   GError **perror),
         do_modify_object,
                   (cbdav,
                   calobj,
                   mod,
-                  old_object,
-                  new_object,
+                  old_component,
+                  new_component,
                   perror))
 
 caldav_busy_stub (
@@ -4228,16 +4241,16 @@ caldav_busy_stub (
                   const gchar *uid,
                   const gchar *rid,
                   CalObjModType mod,
-                  gchar **old_object,
-                  gchar **object,
+                  icalcomponent **old_component,
+                  icalcomponent **component,
                   GError **perror),
         do_remove_object,
                   (cbdav,
                   uid,
                   rid,
                   mod,
-                  old_object,
-                  object,
+                  old_component,
+                  component,
                   perror))
 
 caldav_busy_stub (
diff --git a/calendar/backends/contacts/e-cal-backend-contacts.c b/calendar/backends/contacts/e-cal-backend-contacts.c
index 81b09e8..fd86ad6 100644
--- a/calendar/backends/contacts/e-cal-backend-contacts.c
+++ b/calendar/backends/contacts/e-cal-backend-contacts.c
@@ -1260,12 +1260,11 @@ e_cal_backend_contacts_init (ECalBackendContacts *cbc)
 
 static void
 e_cal_backend_contacts_create_object (ECalBackendSync *backend,
-                                      EDataCal *cal,
-                                      GCancellable *cancellable,
-                                      const gchar *calobj,
-                                      gchar **uid,
-                                      gchar **new_calobj,
-                                      GError **perror)
+				      EDataCal *cal,
+				      GCancellable *cancellable,
+				      const gchar *calobj, gchar **uid,
+				      icalcomponent **new_component,
+				      GError **perror)
 {
 	g_propagate_error (perror, EDC_ERROR (PermissionDenied));
 }
diff --git a/calendar/backends/file/e-cal-backend-file.c b/calendar/backends/file/e-cal-backend-file.c
index 0c59542..ba1fcf0 100644
--- a/calendar/backends/file/e-cal-backend-file.c
+++ b/calendar/backends/file/e-cal-backend-file.c
@@ -128,6 +128,7 @@ static void free_refresh_data (ECalBackendFile *cbfile);
 static icaltimezone *
 e_cal_backend_file_internal_get_timezone (ECalBackend *backend, const gchar *tzid);
 
+
 /* g_hash_table_foreach() callback to destroy a ECalBackendFileObject */
 static void
 free_object_data (gpointer data)
@@ -1097,18 +1098,16 @@ notify_adds_modifies_cb (gpointer key,
 		if (!new_icomp)
 			return;
 
-		new_obj_str = icalcomponent_as_ical_string_r (new_icomp);
-		if (!new_obj_str)
-			return;
-
-		e_cal_backend_notify_object_created (context->backend, new_obj_str);
-		g_free (new_obj_str);
+		e_cal_backend_notify_component_created (context->backend, new_icomp);
 	} else {
 		old_icomp = e_cal_component_get_icalcomponent (old_obj_data->full_object);
 		new_icomp = e_cal_component_get_icalcomponent (new_obj_data->full_object);
 		if (!old_icomp || !new_icomp)
 			return;
 
+		/* There should be better ways to compare an icalcomponent
+		 * than serializing and comparing the strings...
+		 */
 		old_obj_str = icalcomponent_as_ical_string_r (old_icomp);
 		new_obj_str = icalcomponent_as_ical_string_r (new_icomp);
 		if (!old_obj_str || !new_obj_str)
@@ -1116,8 +1115,7 @@ notify_adds_modifies_cb (gpointer key,
 
 		if (strcmp (old_obj_str, new_obj_str)) {
 			/* Object was modified */
-
-			e_cal_backend_notify_object_modified (context->backend, old_obj_str, new_obj_str);
+			e_cal_backend_notify_component_modified (context->backend, old_icomp, new_icomp);
 		}
 		g_free (old_obj_str);
 		g_free (new_obj_str);
@@ -1590,8 +1588,24 @@ typedef struct {
 	const gchar *query;
 	ECalBackendSExp *obj_sexp;
 	ECalBackend *backend;
+	EDataCalView *view;
 } MatchObjectData;
 
+
+static GSList *
+prepend_component (GSList *list, MatchObjectData *match_data, icalcomponent *icalcomp)
+{
+	gchar *str;
+
+	if (match_data->view)
+		str = e_data_cal_view_get_component_string (match_data->view, icalcomp);
+	else
+		str = icalcomponent_as_ical_string_r (icalcomp);
+
+	return g_slist_prepend (list, str);
+}
+
+
 static void
 match_object_sexp_to_component (gpointer value,
                                 gpointer data)
@@ -1601,6 +1615,8 @@ match_object_sexp_to_component (gpointer value,
 	const gchar *uid;
 	ECalBackendFile *cbfile;
 	ECalBackendFilePrivate *priv;
+	icalcomponent *icalcomp;
+
 	e_cal_component_get_uid (comp, &uid);
 
 	g_return_if_fail (comp != NULL);
@@ -1613,9 +1629,11 @@ match_object_sexp_to_component (gpointer value,
 
 	g_return_if_fail (priv != NULL);
 
+	icalcomp = e_cal_component_get_icalcomponent (comp);
+
 	if ((!match_data->search_needed) ||
 	    (e_cal_backend_sexp_match_comp (match_data->obj_sexp, comp, match_data->backend))) {
-		match_data->obj_list = g_slist_append (match_data->obj_list, e_cal_component_get_as_string (comp));
+		match_data->obj_list = prepend_component (match_data->obj_list, match_data, icalcomp);
 	}
 }
 
@@ -1625,11 +1643,14 @@ match_recurrence_sexp (gpointer key,
                        gpointer data)
 {
 	ECalComponent *comp = value;
+	icalcomponent *icalcomp;
 	MatchObjectData *match_data = data;
 
+	icalcomp = e_cal_component_get_icalcomponent (comp);
+
 	if ((!match_data->search_needed) ||
 	    (e_cal_backend_sexp_match_comp (match_data->obj_sexp, comp, match_data->backend))) {
-		match_data->obj_list = g_slist_append (match_data->obj_list, e_cal_component_get_as_string (comp));
+		match_data->obj_list = prepend_component (match_data->obj_list, match_data, icalcomp);
 	}
 }
 
@@ -1643,8 +1664,13 @@ match_object_sexp (gpointer key,
 
 	if (obj_data->full_object) {
 		if ((!match_data->search_needed) ||
-		    (e_cal_backend_sexp_match_comp (match_data->obj_sexp, obj_data->full_object, match_data->backend))) {
-			match_data->obj_list = g_slist_append (match_data->obj_list, e_cal_component_get_as_string (obj_data->full_object));
+		    (e_cal_backend_sexp_match_comp (match_data->obj_sexp,
+						    obj_data->full_object,
+						    match_data->backend))) {
+			icalcomponent *icalcomp =
+				e_cal_component_get_icalcomponent (obj_data->full_object);
+
+			match_data->obj_list = prepend_component (match_data->obj_list, match_data, icalcomp);
 		}
 	}
 
@@ -1665,7 +1691,7 @@ e_cal_backend_file_get_object_list (ECalBackendSync *backend,
 {
 	ECalBackendFile *cbfile;
 	ECalBackendFilePrivate *priv;
-	MatchObjectData match_data;
+	MatchObjectData match_data = { 0, };
 	time_t occur_start = -1, occur_end = -1;
 	gboolean prunning_by_time;
 	GList * objs_occuring_in_tw;
@@ -1709,7 +1735,7 @@ e_cal_backend_file_get_object_list (ECalBackendSync *backend,
 
 	g_static_rec_mutex_unlock (&priv->idle_save_rmutex);
 
-	*objects = match_data.obj_list;
+	*objects = g_slist_reverse (match_data.obj_list);
 
 	if (objs_occuring_in_tw) {
 		g_list_foreach (objs_occuring_in_tw, (GFunc) g_object_unref, NULL);
@@ -1850,7 +1876,7 @@ e_cal_backend_file_start_view (ECalBackend *backend,
 {
 	ECalBackendFile *cbfile;
 	ECalBackendFilePrivate *priv;
-	MatchObjectData match_data;
+	MatchObjectData match_data = { 0, };
 	time_t occur_start = -1, occur_end = -1;
 	gboolean prunning_by_time;
 	GList * objs_occuring_in_tw;
@@ -1865,6 +1891,7 @@ e_cal_backend_file_start_view (ECalBackend *backend,
 	match_data.obj_list = NULL;
 	match_data.backend = backend;
 	match_data.obj_sexp = e_data_cal_view_get_object_sexp (query);
+	match_data.view = query;
 
 	if (!strcmp (match_data.query, "#t"))
 		match_data.search_needed = FALSE;
@@ -1908,6 +1935,8 @@ e_cal_backend_file_start_view (ECalBackend *backend,
 
 	/* notify listeners of all objects */
 	if (match_data.obj_list) {
+		match_data.obj_list = g_slist_reverse (match_data.obj_list);
+
 		e_data_cal_view_notify_objects_added (query, match_data.obj_list);
 
 		/* free memory */
@@ -2169,7 +2198,7 @@ e_cal_backend_file_create_object (ECalBackendSync *backend,
                                   GCancellable *cancellable,
                                   const gchar *in_calobj,
                                   gchar **uid,
-                                  gchar **new_object,
+                                  icalcomponent **new_component,
                                   GError **error)
 {
 	ECalBackendFile *cbfile;
@@ -2184,7 +2213,7 @@ e_cal_backend_file_create_object (ECalBackendSync *backend,
 
 	e_return_data_cal_error_if_fail (priv->icalcomp != NULL, NoSuchCal);
 	e_return_data_cal_error_if_fail (in_calobj != NULL, ObjectNotFound);
-	e_return_data_cal_error_if_fail (new_object != NULL, ObjectNotFound);
+	e_return_data_cal_error_if_fail (new_component != NULL, ObjectNotFound);
 
 	/* Parse the icalendar text */
 	icalcomp = icalparser_parse_string (in_calobj);
@@ -2250,7 +2279,8 @@ e_cal_backend_file_create_object (ECalBackendSync *backend,
 	/* Return the UID and the modified component */
 	if (uid)
 		*uid = g_strdup (comp_uid);
-	*new_object = e_cal_component_get_as_string (comp);
+
+	*new_component = icalcomponent_new_clone (icalcomp);
 
 	g_static_rec_mutex_unlock (&priv->idle_save_rmutex);
 }
@@ -2297,8 +2327,8 @@ e_cal_backend_file_modify_object (ECalBackendSync *backend,
                                   GCancellable *cancellable,
                                   const gchar *calobj,
                                   CalObjModType mod,
-                                  gchar **old_object,
-                                  gchar **new_object,
+                                  icalcomponent **old_component,
+                                  icalcomponent **new_component,
                                   GError **error)
 {
 	RemoveRecurrenceData rrdata;
@@ -2372,8 +2402,11 @@ e_cal_backend_file_modify_object (ECalBackendSync *backend,
 	switch (mod) {
 	case CALOBJ_MOD_THIS :
 		if (!rid || !*rid) {
-			if (old_object && obj_data->full_object)
-				*old_object = e_cal_component_get_as_string (obj_data->full_object);
+			if (old_component && obj_data->full_object) {
+				icalcomponent *old_icalcomp =
+					e_cal_component_get_icalcomponent (obj_data->full_object);
+				*old_component = icalcomponent_new_clone (old_icalcomp);
+			}
 
 			/* replace only the full object */
 			if (obj_data->full_object) {
@@ -2393,8 +2426,11 @@ e_cal_backend_file_modify_object (ECalBackendSync *backend,
 
 			save (cbfile);
 
-			if (new_object)
-				*new_object = e_cal_component_get_as_string (comp);
+			if (new_component) {
+				icalcomponent *new_icalcomp =
+					e_cal_component_get_icalcomponent (comp);
+				*new_component = icalcomponent_new_clone (new_icalcomp);
+			}
 
 			g_static_rec_mutex_unlock (&priv->idle_save_rmutex);
 			g_free (rid);
@@ -2402,8 +2438,11 @@ e_cal_backend_file_modify_object (ECalBackendSync *backend,
 		}
 
 		if (g_hash_table_lookup_extended (obj_data->recurrences, rid, (gpointer *) &real_rid, (gpointer *) &recurrence)) {
-			if (old_object)
-				*old_object = e_cal_component_get_as_string (recurrence);
+			if (old_component) {
+				icalcomponent *old_icalcomp =
+					e_cal_component_get_icalcomponent (recurrence);
+				*old_component = icalcomponent_new_clone (old_icalcomp);
+			}
 
 			/* remove the component from our data */
 			icalcomponent_remove_component (priv->icalcomp,
@@ -2426,8 +2465,12 @@ e_cal_backend_file_modify_object (ECalBackendSync *backend,
 	case CALOBJ_MOD_THISANDPRIOR :
 	case CALOBJ_MOD_THISANDFUTURE :
 		if (!rid || !*rid) {
-			if (old_object && obj_data->full_object)
-				*old_object = e_cal_component_get_as_string (obj_data->full_object);
+
+			if (old_component && obj_data->full_object) {
+				icalcomponent *old_icalcomp =
+					e_cal_component_get_icalcomponent (obj_data->full_object);
+				*old_component = icalcomponent_new_clone (old_icalcomp);
+			}
 
 			remove_component (cbfile, comp_uid, obj_data);
 
@@ -2448,8 +2491,12 @@ e_cal_backend_file_modify_object (ECalBackendSync *backend,
 		/* now deal with the detached recurrence */
 		if (g_hash_table_lookup_extended (obj_data->recurrences, rid,
 						  (gpointer *) &real_rid, (gpointer *) &recurrence)) {
-			if (old_object)
-				*old_object = e_cal_component_get_as_string (recurrence);
+
+			if (old_component) {
+				icalcomponent *old_icalcomp =
+					e_cal_component_get_icalcomponent (recurrence);
+				*old_component = icalcomponent_new_clone (old_icalcomp);
+			}
 
 			/* remove the component from our data */
 			icalcomponent_remove_component (priv->icalcomp,
@@ -2458,8 +2505,12 @@ e_cal_backend_file_modify_object (ECalBackendSync *backend,
 			obj_data->recurrences_list = g_list_remove (obj_data->recurrences_list, recurrence);
 			g_hash_table_remove (obj_data->recurrences, rid);
 		} else {
-			if (old_object && obj_data->full_object)
-				*old_object = e_cal_component_get_as_string (obj_data->full_object);
+
+			if (old_component && obj_data->full_object) {
+				icalcomponent *old_icalcomp =
+					e_cal_component_get_icalcomponent (obj_data->full_object);
+				*old_component = icalcomponent_new_clone (old_icalcomp);
+			}
 		}
 
 		rrdata.cbfile = cbfile;
@@ -2489,8 +2540,11 @@ e_cal_backend_file_modify_object (ECalBackendSync *backend,
 		break;
 	case CALOBJ_MOD_ALL :
 		/* Remove the old version */
-		if (old_object && obj_data->full_object)
-			*old_object = e_cal_component_get_as_string (obj_data->full_object);
+		if (old_component && obj_data->full_object) {
+			icalcomponent *old_icalcomp =
+				e_cal_component_get_icalcomponent (obj_data->full_object);
+			*old_component = icalcomponent_new_clone (old_icalcomp);
+		}
 
 		if (obj_data->recurrences_list) {
 			/* has detached components, preserve them */
@@ -2534,8 +2588,11 @@ e_cal_backend_file_modify_object (ECalBackendSync *backend,
 	save (cbfile);
 	g_free (rid);
 
-	if (new_object)
-		*new_object = e_cal_component_get_as_string (comp);
+	if (new_component) {
+		icalcomponent *new_icalcomp =
+			e_cal_component_get_icalcomponent (comp);
+		*new_component = icalcomponent_new_clone (new_icalcomp);
+	}
 
 	g_static_rec_mutex_unlock (&priv->idle_save_rmutex);
 }
@@ -2560,8 +2617,8 @@ remove_instance (ECalBackendFile *cbfile,
                  const gchar *uid,
                  const gchar *rid,
                  CalObjModType mod,
-                 gchar **old_object,
-                 gchar **object,
+                 icalcomponent **old_component,
+                 icalcomponent **component,
                  GError **error)
 {
 	gchar *hash_rid;
@@ -2578,9 +2635,13 @@ remove_instance (ECalBackendFile *cbfile,
 						  (gpointer *) &hash_rid, (gpointer *) &comp)) {
 			/* Removing without parent or not modifying parent?
 			 * Report removal to caller. */
-			if (old_object &&
-			    (!obj_data->full_object || mod == CALOBJ_MOD_ONLY_THIS))
-				*old_object = e_cal_component_get_as_string (comp);
+			if (old_component &&
+			    (!obj_data->full_object || mod == CALOBJ_MOD_ONLY_THIS)) {
+				icalcomponent *icalcomp =
+					e_cal_component_get_icalcomponent (comp);
+
+				*old_component = icalcomponent_new_clone (icalcomp);
+			}
 
 			/* Reporting parent modification to caller?
 			 * Report directly instead of going via caller. */
@@ -2629,8 +2690,13 @@ remove_instance (ECalBackendFile *cbfile,
 		cbfile->priv->comp = g_list_remove (cbfile->priv->comp, obj_data->full_object);
 
 		/* add EXDATE or EXRULE to parent, report as update */
-		if (old_object)
-			*old_object = e_cal_component_get_as_string (obj_data->full_object);
+		if (old_component) {
+			icalcomponent *icalcomp =
+				e_cal_component_get_icalcomponent (obj_data->full_object);
+
+			*old_component = icalcomponent_new_clone (icalcomp);
+		}
+
 		e_cal_util_remove_instances (e_cal_component_get_icalcomponent (obj_data->full_object),
 					     icaltime_from_string (rid), CALOBJ_MOD_THIS);
 
@@ -2640,8 +2706,12 @@ remove_instance (ECalBackendFile *cbfile,
 		e_cal_component_set_last_modified (obj_data->full_object, &current);
 
 		/* report update */
-		if (object)
-			*object = e_cal_component_get_as_string (obj_data->full_object);
+		if (component) {
+			icalcomponent *icalcomp =
+				e_cal_component_get_icalcomponent (obj_data->full_object);
+
+			*component = icalcomponent_new_clone (icalcomp);
+		}
 
 		/* add the modified object to the beginning of the list,
 		 * so that it's always before any detached instance we
@@ -2670,8 +2740,12 @@ remove_instance (ECalBackendFile *cbfile,
 		cbfile->priv->comp = g_list_remove (cbfile->priv->comp, obj_data->full_object);
 
 		/* remove parent, report as removal */
-		if (old_object)
-			*old_object = e_cal_component_get_as_string (obj_data->full_object);
+		if (old_component) {
+			icalcomponent *icalcomp =
+				e_cal_component_get_icalcomponent (obj_data->full_object);
+
+			*old_component = icalcomponent_new_clone (icalcomp);
+		}
 		g_object_unref (obj_data->full_object);
 		obj_data->full_object = NULL;
 
@@ -2686,29 +2760,30 @@ remove_instance (ECalBackendFile *cbfile,
 	return obj_data;
 }
 
-static gchar *
-get_object_string_from_fileobject (ECalBackendFileObject *obj_data,
-                                   const gchar *rid)
+static icalcomponent *
+clone_icalcomp_from_fileobject (ECalBackendFileObject *obj_data, const gchar *rid)
 {
 	ECalComponent *comp = obj_data->full_object;
-	gchar *real_rid;
+	icalcomponent *icalcomp = NULL;
+	gchar         *real_rid;
 
 	if (!comp)
 		return NULL;
 
 	if (!rid) {
-		return e_cal_component_get_as_string (comp);
+		icalcomp = e_cal_component_get_icalcomponent (comp);
 	} else {
-		if (g_hash_table_lookup_extended (obj_data->recurrences, rid, (gpointer *) &real_rid, (gpointer *) &comp))
-			return e_cal_component_get_as_string (comp);
+		if (g_hash_table_lookup_extended (obj_data->recurrences, rid,
+						  (gpointer *) &real_rid, (gpointer *) &comp))
+			icalcomp = e_cal_component_get_icalcomponent (comp);
 		else {
 			/* FIXME remove this once we delete an instance from master object through
 			 * modify request by setting exception */
-			return e_cal_component_get_as_string (comp);
+			icalcomp = e_cal_component_get_icalcomponent (comp);
 		}
 	}
 
-	return NULL;
+	return icalcomp ? icalcomponent_new_clone (icalcomp) : NULL;
 }
 
 static void
@@ -2742,8 +2817,8 @@ e_cal_backend_file_remove_object (ECalBackendSync *backend,
                                   const gchar *uid,
                                   const gchar *rid,
                                   CalObjModType mod,
-                                  gchar **old_object,
-                                  gchar **object,
+                                  icalcomponent **old_component,
+                                  icalcomponent **component,
                                   GError **error)
 {
 	ECalBackendFile *cbfile;
@@ -2758,6 +2833,7 @@ e_cal_backend_file_remove_object (ECalBackendSync *backend,
 
 	e_return_data_cal_error_if_fail (priv->icalcomp != NULL, NoSuchCal);
 	e_return_data_cal_error_if_fail (uid != NULL, ObjectNotFound);
+
 	switch (mod) {
 	case CALOBJ_MOD_THIS:
 	case CALOBJ_MOD_THISANDPRIOR:
@@ -2770,7 +2846,7 @@ e_cal_backend_file_remove_object (ECalBackendSync *backend,
 		return;
 	}
 
-	*old_object = *object = NULL;
+	*old_component = *component = NULL;
 
 	g_static_rec_mutex_lock (&priv->idle_save_rmutex);
 
@@ -2786,16 +2862,17 @@ e_cal_backend_file_remove_object (ECalBackendSync *backend,
 
 	switch (mod) {
 	case CALOBJ_MOD_ALL :
-		*old_object = get_object_string_from_fileobject (obj_data, recur_id);
+		*old_component = clone_icalcomp_from_fileobject (obj_data, recur_id);
 		if (obj_data->recurrences_list)
 			g_list_foreach (obj_data->recurrences_list, notify_comp_removed_cb, cbfile);
 		remove_component (cbfile, uid, obj_data);
 
-		*object = NULL;
+		*component = NULL;
 		break;
 	case CALOBJ_MOD_ONLY_THIS:
 	case CALOBJ_MOD_THIS :
-		obj_data = remove_instance (cbfile, obj_data, uid, recur_id, mod, old_object, object, error);
+		obj_data = remove_instance (cbfile, obj_data, uid, recur_id, mod,
+					    old_component, component, error);
 		break;
 	case CALOBJ_MOD_THISANDPRIOR :
 	case CALOBJ_MOD_THISANDFUTURE :
@@ -2808,7 +2885,9 @@ e_cal_backend_file_remove_object (ECalBackendSync *backend,
 		}
 
 		if (comp) {
-			*old_object = e_cal_component_get_as_string (comp);
+			icalcomponent *icalcomp = 
+				e_cal_component_get_icalcomponent (comp);
+			*old_component = icalcomponent_new_clone (icalcomp);
 
 			/* remove the component from our data, temporarily */
 			icalcomponent_remove_component (priv->icalcomp,
@@ -2832,8 +2911,12 @@ e_cal_backend_file_remove_object (ECalBackendSync *backend,
 		if (comp)
 			priv->comp = g_list_prepend (priv->comp, comp);
 
-		if (obj_data->full_object)
-			*object = e_cal_component_get_as_string (obj_data->full_object);
+		if (obj_data->full_object) {
+			icalcomponent *icalcomp =
+				e_cal_component_get_icalcomponent (obj_data->full_object);
+
+			*component = icalcomponent_new_clone (icalcomp);
+		}
 		break;
 	}
 
@@ -2845,8 +2928,8 @@ e_cal_backend_file_remove_object (ECalBackendSync *backend,
 static gboolean
 cancel_received_object (ECalBackendFile *cbfile,
                         icalcomponent *icalcomp,
-                        gchar **old_object,
-                        gchar **new_object)
+                        icalcomponent **old_icalcomp,
+                        icalcomponent **new_icalcomp)
 {
 	ECalBackendFileObject *obj_data;
 	ECalBackendFilePrivate *priv;
@@ -2856,8 +2939,8 @@ cancel_received_object (ECalBackendFile *cbfile,
 
 	priv = cbfile->priv;
 
-	*old_object = NULL;
-	*new_object = NULL;
+	*old_icalcomp = NULL;
+	*new_icalcomp = NULL;
 
 	/* Find the old version of the component. */
 	obj_data = g_hash_table_lookup (priv->comp_uid_hash, uid);
@@ -2873,13 +2956,20 @@ cancel_received_object (ECalBackendFile *cbfile,
 
 	rid = e_cal_component_get_recurid_as_string (comp);
 	if (rid && *rid) {
-		obj_data = remove_instance (cbfile, obj_data, uid, rid, CALOBJ_MOD_THIS, old_object, new_object, NULL);
-		if (obj_data && obj_data->full_object)
-			*new_object = e_cal_component_get_as_string (obj_data->full_object);
+		obj_data = remove_instance (cbfile, obj_data, uid, rid, CALOBJ_MOD_THIS,
+					    old_icalcomp, new_icalcomp, NULL);
+		if (obj_data && obj_data->full_object) {
+			icalcomponent *tmp_icalcomp =
+				e_cal_component_get_icalcomponent (obj_data->full_object);
+			*new_icalcomp = icalcomponent_new_clone (tmp_icalcomp);
+		}
 	} else {
-		/* report as removal by keeping *new_object NULL */
-		if (obj_data->full_object)
-			*old_object = e_cal_component_get_as_string (obj_data->full_object);
+		/* report as removal by keeping *new_component NULL */
+		if (obj_data->full_object) {
+			icalcomponent *tmp_icalcomp =
+				e_cal_component_get_icalcomponent (obj_data->full_object);
+			*old_icalcomp = icalcomponent_new_clone (tmp_icalcomp);
+		}
 		remove_component (cbfile, uid, obj_data);
 	}
 
@@ -3078,8 +3168,10 @@ e_cal_backend_file_receive_objects (ECalBackendSync *backend,
 
 	/* Now we manipulate the components we care about */
 	for (l = comps; l; l = l->next) {
+		icalcomponent *old_component = NULL;
+		icalcomponent *component = NULL;
 		const gchar *uid;
-		gchar *object, *old_object = NULL, *rid, *new_object;
+		gchar *rid;
 		ECalBackendFileObject *obj_data;
 		gboolean is_declined;
 
@@ -3113,40 +3205,53 @@ e_cal_backend_file_receive_objects (ECalBackendSync *backend,
 				fetch_attachments (backend, comp);
 			obj_data = g_hash_table_lookup (priv->comp_uid_hash, uid);
 			if (obj_data) {
+
 				if (rid) {
+					icalcomponent *ignore_icalcomp = NULL;
+
 					remove_instance (cbfile, obj_data, uid, rid, CALOBJ_MOD_THIS,
-							 &old_object, &new_object, NULL);
+							 &old_component, &ignore_icalcomp, NULL);
+
+					if (ignore_icalcomp)
+						icalcomponent_free (ignore_icalcomp);
 				} else {
-					if (obj_data->full_object)
-						old_object = e_cal_component_get_as_string (obj_data->full_object);
+					if (obj_data->full_object) {
+						icalcomponent *full_icalcomp =
+							e_cal_component_get_icalcomponent (obj_data->full_object);
+						old_component = icalcomponent_new_clone (full_icalcomp);
+					}
 					remove_component (cbfile, uid, obj_data);
 				}
 
 				if (!is_declined)
 					add_component (cbfile, comp, FALSE);
 
-				object = e_cal_component_get_as_string (comp);
+
+				component = icalcomponent_new_clone (e_cal_component_get_icalcomponent (comp));
 				if (!is_declined)
-					e_cal_backend_notify_object_modified (E_CAL_BACKEND (backend), old_object, object);
+					e_cal_backend_notify_component_modified (E_CAL_BACKEND (backend),
+										 old_component, component);
 				else {
 					ECalComponentId *id = e_cal_component_get_id (comp);
 
-					if (rid)
-						e_cal_backend_notify_object_removed (E_CAL_BACKEND (backend), id, old_object, object);
-					else
-						e_cal_backend_notify_object_removed (E_CAL_BACKEND (backend), id, old_object, NULL);
+					e_cal_backend_notify_component_removed (E_CAL_BACKEND (backend),
+										id, old_component,
+										rid ? component : NULL);
 
 					e_cal_component_free_id (id);
 				}
 
-				g_free (object);
-				g_free (old_object);
+				if (component)
+					icalcomponent_free (component);
+				if (old_component)
+					icalcomponent_free (old_component);
+
 			} else if (!is_declined) {
 				add_component (cbfile, comp, FALSE);
 
-				object = e_cal_component_get_as_string (comp);
-				e_cal_backend_notify_object_created (E_CAL_BACKEND (backend), object);
-				g_free (object);
+				component = e_cal_component_get_icalcomponent (comp);
+
+				e_cal_backend_notify_component_created (E_CAL_BACKEND (backend), component);
 			}
 			g_free (rid);
 			break;
@@ -3167,22 +3272,25 @@ e_cal_backend_file_receive_objects (ECalBackendSync *backend,
 			goto error;
 			break;
 		case ICAL_METHOD_CANCEL:
-			old_object = NULL;
-			new_object = NULL;
-			if (cancel_received_object (cbfile, subcomp, &old_object, &new_object)) {
+			old_component = NULL;
+			component = NULL;
+			if (cancel_received_object (cbfile, subcomp, &old_component, &component)) {
 				ECalComponentId *id;
 
 				id = e_cal_component_get_id (comp);
 
-				e_cal_backend_notify_object_removed (E_CAL_BACKEND (backend), id, old_object, new_object);
+				e_cal_backend_notify_component_removed (E_CAL_BACKEND (backend),
+									id, old_component, component);
 
 				/* remove the component from the toplevel VCALENDAR */
 				icalcomponent_remove_component (toplevel_comp, subcomp);
 				icalcomponent_free (subcomp);
 				e_cal_component_free_id (id);
 
-				g_free (new_object);
-				g_free (old_object);
+				if (component)
+					icalcomponent_free (component);
+				if (old_component)
+					icalcomponent_free (old_component);
 			}
 			g_free (rid);
 			break;
@@ -3485,7 +3593,7 @@ test_query_by_scanning_all_objects (ECalBackendFile *cbfile,
 
 	g_static_rec_mutex_unlock (&priv->idle_save_rmutex);
 
-	*objects = match_data.obj_list;
+	*objects = g_slist_reverse (match_data.obj_list);
 
 	g_object_unref (match_data.obj_sexp);
 }
diff --git a/calendar/backends/http/e-cal-backend-http.c b/calendar/backends/http/e-cal-backend-http.c
index e564eb9..6d6efd3 100644
--- a/calendar/backends/http/e-cal-backend-http.c
+++ b/calendar/backends/http/e-cal-backend-http.c
@@ -1262,26 +1262,26 @@ e_cal_backend_http_get_free_busy (ECalBackendSync *backend,
 }
 
 static void
-e_cal_backend_http_create_object (ECalBackendSync *backend,
-                                  EDataCal *cal,
-                                  GCancellable *cancellable,
-                                  const gchar *calobj,
-                                  gchar **uid,
-                                  gchar **new_calobj,
-                                  GError **perror)
+e_cal_backend_http_create_object (ECalBackendSync *backend, 
+				  EDataCal *cal, 
+				  GCancellable *cancellable, 
+				  const gchar *calobj, 
+				  gchar **uid, 
+				  icalcomponent **new_component, 
+				  GError **perror)
 {
 	g_propagate_error (perror, EDC_ERROR (PermissionDenied));
 }
 
 static void
 e_cal_backend_http_modify_object (ECalBackendSync *backend,
-                                  EDataCal *cal,
-                                  GCancellable *cancellable,
-                                  const gchar *calobj,
-                                  CalObjModType mod,
-                                  gchar **old_object,
-                                  gchar **new_object,
-                                  GError **perror)
+				  EDataCal      *cal,
+				  GCancellable  *cancellable,
+				  const gchar   *calobj,
+				  CalObjModType   mod,
+				  icalcomponent **old_component,
+				  icalcomponent **component,
+				  GError        **perror)
 {
 	g_propagate_error (perror, EDC_ERROR (PermissionDenied));
 }
@@ -1289,16 +1289,16 @@ e_cal_backend_http_modify_object (ECalBackendSync *backend,
 /* Remove_object handler for the file backend */
 static void
 e_cal_backend_http_remove_object (ECalBackendSync *backend,
-                                  EDataCal *cal,
-                                  GCancellable *cancellable,
-                                  const gchar *uid,
-                                  const gchar *rid,
-                                  CalObjModType mod,
-                                  gchar **old_object,
-                                  gchar **object,
-                                  GError **perror)
+				  EDataCal       *cal,
+				  GCancellable   *cancellable,
+				  const gchar    *uid,
+				  const gchar    *rid,
+				  CalObjModType   mod, 
+				  icalcomponent **old_component,
+				  icalcomponent **component,
+				  GError        **perror)
 {
-	*old_object = *object = NULL;
+	*old_component = *component = NULL;
 
 	g_propagate_error (perror, EDC_ERROR (PermissionDenied));
 }
diff --git a/calendar/libedata-cal/e-cal-backend-sync.c b/calendar/libedata-cal/e-cal-backend-sync.c
index 27a9c18..de043e7 100644
--- a/calendar/libedata-cal/e-cal-backend-sync.c
+++ b/calendar/libedata-cal/e-cal-backend-sync.c
@@ -309,24 +309,24 @@ e_cal_backend_sync_get_free_busy (ECalBackendSync *backend,
  * @cancellable: a #GCancellable for the operation
  * @calobj: The object to be added.
  * @uid: Placeholder for server-generated UID.
- * @new_object: Placeholder for server-calobj, if it changed. Can be left as is if it's same as @calobj.
+ * @new_component: (out) (transfer full): Placeholder for returned #icalcomponent.
  * @error: Out parameter for a #GError.
  *
  * Calls the create_object_sync method on the given backend.
  */
 void
 e_cal_backend_sync_create_object (ECalBackendSync *backend,
-                                  EDataCal *cal,
-                                  GCancellable *cancellable,
-                                  const gchar *calobj,
-                                  gchar **uid,
-                                  gchar **new_object,
-                                  GError **error)
+				  EDataCal        *cal, 
+				  GCancellable    *cancellable, 
+				  const gchar     *calobj, 
+				  gchar          **uid, 
+				  icalcomponent  **new_component, 
+				  GError         **error)
 {
 	e_return_data_cal_error_if_fail (backend && E_IS_CAL_BACKEND_SYNC (backend), InvalidArg);
 	e_return_data_cal_error_if_fail (E_CAL_BACKEND_SYNC_GET_CLASS (backend)->create_object_sync != NULL, UnsupportedMethod);
 
-	LOCK_WRAPPER (create_object_sync, (backend, cal, cancellable, calobj, uid, new_object, error));
+	LOCK_WRAPPER (create_object_sync, (backend, cal, cancellable, calobj, uid, new_component, error));
 }
 
 /**
@@ -336,9 +336,9 @@ e_cal_backend_sync_create_object (ECalBackendSync *backend,
  * @cancellable: a #GCancellable for the operation
  * @calobj: Object to be modified.
  * @mod: Type of modification to be done.
- * @old_object: Placeholder for returning the old object as it was stored on the
+ * @old_component: (out) (transfer full): Placeholder for returning the old component as it was stored on the
  * backend.
- * @new_object: Placeholder for returning the new object as it has been stored
+ * @new_component: (out) (transfer full): Placeholder for returning the new component as it has been stored
  * on the backend.
  * @error: Out parameter for a #GError.
  *
@@ -346,18 +346,18 @@ e_cal_backend_sync_create_object (ECalBackendSync *backend,
  */
 void
 e_cal_backend_sync_modify_object (ECalBackendSync *backend,
-                                  EDataCal *cal,
-                                  GCancellable *cancellable,
-                                  const gchar *calobj,
-                                  CalObjModType mod,
-                                  gchar **old_object,
-                                  gchar **new_object,
-                                  GError **error)
+				  EDataCal        *cal,
+				  GCancellable    *cancellable, 
+				  const gchar     *calobj,
+				  CalObjModType    mod,
+				  icalcomponent  **old_component,
+				  icalcomponent  **new_component,
+				  GError         **error)
 {
 	e_return_data_cal_error_if_fail (backend && E_IS_CAL_BACKEND_SYNC (backend), InvalidArg);
 	e_return_data_cal_error_if_fail (E_CAL_BACKEND_SYNC_GET_CLASS (backend)->modify_object_sync != NULL, UnsupportedMethod);
 
-	LOCK_WRAPPER (modify_object_sync, (backend, cal, cancellable, calobj, mod, old_object, new_object, error));
+	LOCK_WRAPPER (modify_object_sync, (backend, cal, cancellable, calobj, mod, old_component, new_component, error));
 }
 
 /**
@@ -369,30 +369,30 @@ e_cal_backend_sync_modify_object (ECalBackendSync *backend,
  * @rid: Recurrence ID of the instance to remove, or NULL if removing the
  * whole object.
  * @mod: Type of removal.
- * @old_object: Placeholder for returning the old object as it was stored on the
+ * @old_component: (out) (transfer full): Placeholder for returning the old component as it was stored on the
  * backend.
- * @new_object: Placeholder for returning the object after it has been modified (when
- * removing individual instances). If removing the whole object, this will be
- * NULL.
+ * @new_component: (out) (transfer full): Placeholder for returning the new component as it has been stored
+ * on the backend (when removing individual instances). If removing the whole object,
+ * this will be set to %NULL.
  * @error: Out parameter for a #GError.
  *
  * Calls the remove_object_sync method on the given backend.
  */
 void
 e_cal_backend_sync_remove_object (ECalBackendSync *backend,
-                                  EDataCal *cal,
-                                  GCancellable *cancellable,
-                                  const gchar *uid,
-                                  const gchar *rid,
-                                  CalObjModType mod,
-                                  gchar **old_object,
-                                  gchar **new_object,
-                                  GError **error)
+				  EDataCal        *cal,
+				  GCancellable    *cancellable,
+				  const gchar     *uid,
+				  const gchar     *rid,
+				  CalObjModType    mod,
+				  icalcomponent  **old_component,
+				  icalcomponent  **new_component,
+				  GError         **error)
 {
 	e_return_data_cal_error_if_fail (backend && E_IS_CAL_BACKEND_SYNC (backend), InvalidArg);
 	e_return_data_cal_error_if_fail (E_CAL_BACKEND_SYNC_GET_CLASS (backend)->remove_object_sync != NULL, UnsupportedMethod);
 
-	LOCK_WRAPPER (remove_object_sync, (backend, cal, cancellable, uid, rid, mod, old_object, new_object, error));
+	LOCK_WRAPPER (remove_object_sync, (backend, cal, cancellable, uid, rid, mod, old_component, new_component, error));
 }
 
 /**
@@ -732,14 +732,20 @@ cal_backend_create_object (ECalBackend *backend,
                            const gchar *calobj)
 {
 	GError *error = NULL;
-	gchar *uid = NULL, *new_object = NULL;
+	gchar *uid = NULL;
+	icalcomponent *new_component = NULL;
+
+	e_cal_backend_sync_create_object (E_CAL_BACKEND_SYNC (backend), cal, cancellable, calobj, &uid, &new_component, &error);
 
-	e_cal_backend_sync_create_object (E_CAL_BACKEND_SYNC (backend), cal, cancellable, calobj, &uid, &new_object, &error);
+	if (!new_component)
+		new_component = icalparser_parse_string (calobj);
 
-	e_data_cal_respond_create_object (cal, opid, error, uid, new_object ? new_object : calobj);
+	e_data_cal_respond_create_object (cal, opid, error, uid, new_component);
 
 	g_free (uid);
-	g_free (new_object);
+
+	if (new_component)
+		icalcomponent_free (new_component);
 }
 
 static void
@@ -751,38 +757,47 @@ cal_backend_modify_object (ECalBackend *backend,
                            CalObjModType mod)
 {
 	GError *error = NULL;
-	gchar *old_object = NULL, *new_object = NULL;
+	icalcomponent *old_component = NULL, *new_component = NULL;
+
+	e_cal_backend_sync_modify_object (E_CAL_BACKEND_SYNC (backend), cal, cancellable, calobj, mod, &old_component, &new_component, &error);
+
+	if (!old_component)
+		old_component = icalparser_parse_string (calobj);
 
-	e_cal_backend_sync_modify_object (E_CAL_BACKEND_SYNC (backend), cal, cancellable, calobj, mod, &old_object, &new_object, &error);
+	e_data_cal_respond_modify_object (cal, opid, error, old_component, new_component);
 
-	e_data_cal_respond_modify_object (cal, opid, error, old_object ? old_object : calobj, new_object);
+	if (old_component)
+		icalcomponent_free (old_component);
 
-	g_free (old_object);
-	g_free (new_object);
+	if (new_component)
+		icalcomponent_free (new_component);
 }
 
 static void
-cal_backend_remove_object (ECalBackend *backend,
-                           EDataCal *cal,
-                           guint32 opid,
+cal_backend_remove_object (ECalBackend  *backend,
+                           EDataCal     *cal,
+                           guint32       opid,
                            GCancellable *cancellable,
-                           const gchar *uid,
-                           const gchar *rid,
+                           const gchar  *uid,
+                           const gchar  *rid,
                            CalObjModType mod)
 {
 	GError *error = NULL;
-	gchar *old_object = NULL, *new_object = NULL;
+	icalcomponent *old_component = NULL, *new_component = NULL;
 	ECalComponentId compid;
 
 	compid.uid = (gchar *) uid;
 	compid.rid = (gchar *) ((mod == CALOBJ_MOD_THIS || mod == CALOBJ_MOD_ONLY_THIS) ? rid : NULL);
 
-	e_cal_backend_sync_remove_object (E_CAL_BACKEND_SYNC (backend), cal, cancellable, uid, rid, mod, &old_object, &new_object, &error);
+	e_cal_backend_sync_remove_object (E_CAL_BACKEND_SYNC (backend), cal, cancellable, uid, rid, mod, &old_component, &new_component, &error);
+
+	e_data_cal_respond_remove_object (cal, opid, error, &compid, old_component, new_component);
 
-	e_data_cal_respond_remove_object (cal, opid, error, &compid, old_object, new_object);
+	if (old_component)
+		icalcomponent_free (old_component);
 
-	g_free (old_object);
-	g_free (new_object);
+	if (new_component)
+		icalcomponent_free (new_component);
 }
 
 static void
diff --git a/calendar/libedata-cal/e-cal-backend-sync.h b/calendar/libedata-cal/e-cal-backend-sync.h
index 1b64a50..c6fa3d1 100644
--- a/calendar/libedata-cal/e-cal-backend-sync.h
+++ b/calendar/libedata-cal/e-cal-backend-sync.h
@@ -39,9 +39,9 @@ struct _ECalBackendSyncClass {
 	void	(* get_object_sync)		(ECalBackendSync *backend, EDataCal *cal, GCancellable *cancellable, const gchar *uid, const gchar *rid, gchar **calobj, GError **error);
 	void	(* get_object_list_sync)	(ECalBackendSync *backend, EDataCal *cal, GCancellable *cancellable, const gchar *sexp, GSList **calobjs, GError **error);
 	void	(* get_free_busy_sync)		(ECalBackendSync *backend, EDataCal *cal, GCancellable *cancellable, const GSList *users, time_t start, time_t end, GSList **freebusyobjs, GError **error);
-	void	(* create_object_sync)		(ECalBackendSync *backend, EDataCal *cal, GCancellable *cancellable, const gchar *calobj, gchar **uid, gchar **new_object, GError **error);
-	void	(* modify_object_sync)		(ECalBackendSync *backend, EDataCal *cal, GCancellable *cancellable, const gchar *calobj, CalObjModType mod, gchar **old_object, gchar **new_object, GError **error);
-	void	(* remove_object_sync)		(ECalBackendSync *backend, EDataCal *cal, GCancellable *cancellable, const gchar *uid, const gchar *rid, CalObjModType mod, gchar **old_object, gchar **new_object, GError **error);
+	void	(* create_object_sync)		(ECalBackendSync *backend, EDataCal *cal, GCancellable *cancellable, const gchar *calobj, gchar **uid, icalcomponent **new_component, GError **error);
+	void	(* modify_object_sync)		(ECalBackendSync *backend, EDataCal *cal, GCancellable *cancellable, const gchar *calobj, CalObjModType mod, icalcomponent **old_component, icalcomponent **new_component, GError **error);
+	void	(* remove_object_sync)		(ECalBackendSync *backend, EDataCal *cal, GCancellable *cancellable, const gchar *uid, const gchar *rid, CalObjModType mod, icalcomponent **old_component, icalcomponent **new_component, GError **error);
 	void	(* receive_objects_sync)	(ECalBackendSync *backend, EDataCal *cal, GCancellable *cancellable, const gchar *calobj, GError **error);
 	void	(* send_objects_sync)		(ECalBackendSync *backend, EDataCal *cal, GCancellable *cancellable, const gchar *calobj, GSList **users, gchar **modified_calobj, GError **error);
 	void	(* get_attachment_uris_sync)	(ECalBackendSync *backend, EDataCal *cal, GCancellable *cancellable, const gchar *uid, const gchar *rid, GSList **attachments, GError **error);
@@ -64,9 +64,9 @@ gboolean e_cal_backend_sync_set_backend_property (ECalBackendSync *backend, EDat
 void	e_cal_backend_sync_get_object		(ECalBackendSync *backend, EDataCal *cal, GCancellable *cancellable, const gchar *uid, const gchar *rid, gchar **calobj, GError **error);
 void	e_cal_backend_sync_get_object_list	(ECalBackendSync *backend, EDataCal *cal, GCancellable *cancellable, const gchar *sexp, GSList **calobjs, GError **error);
 void	e_cal_backend_sync_get_free_busy	(ECalBackendSync *backend, EDataCal *cal, GCancellable *cancellable, const GSList *users, time_t start, time_t end, GSList **freebusyobjs, GError **error);
-void	e_cal_backend_sync_create_object	(ECalBackendSync *backend, EDataCal *cal, GCancellable *cancellable, const gchar *calobj, gchar **uid, gchar **new_object, GError **error);
-void	e_cal_backend_sync_modify_object	(ECalBackendSync *backend, EDataCal *cal, GCancellable *cancellable, const gchar *calobj, CalObjModType mod, gchar **old_object, gchar **new_object, GError **error);
-void	e_cal_backend_sync_remove_object	(ECalBackendSync *backend, EDataCal *cal, GCancellable *cancellable, const gchar *uid, const gchar *rid, CalObjModType mod, gchar **old_object, gchar **new_object, GError **error);
+void	e_cal_backend_sync_create_object	(ECalBackendSync *backend, EDataCal *cal, GCancellable *cancellable, const gchar *calobj, gchar **uid, icalcomponent **new_component, GError **error);
+void	e_cal_backend_sync_modify_object	(ECalBackendSync *backend, EDataCal *cal, GCancellable *cancellable, const gchar *calobj, CalObjModType mod, icalcomponent **old_component, icalcomponent **new_component, GError **error);
+void	e_cal_backend_sync_remove_object	(ECalBackendSync *backend, EDataCal *cal, GCancellable *cancellable, const gchar *uid, const gchar *rid, CalObjModType mod, icalcomponent **old_component, icalcomponent **new_component, GError **error);
 void	e_cal_backend_sync_receive_objects	(ECalBackendSync *backend, EDataCal *cal, GCancellable *cancellable, const gchar *calobj, GError **error);
 void	e_cal_backend_sync_send_objects		(ECalBackendSync *backend, EDataCal *cal, GCancellable *cancellable, const gchar *calobj, GSList **users, gchar **modified_calobj, GError **error);
 void	e_cal_backend_sync_get_attachment_uris	(ECalBackendSync *backend, EDataCal *cal, GCancellable *cancellable, const gchar *uid, const gchar *rid, GSList **attachments, GError **error);
diff --git a/calendar/libedata-cal/e-cal-backend.c b/calendar/libedata-cal/e-cal-backend.c
index ccfb57f..4c3dcc7 100644
--- a/calendar/libedata-cal/e-cal-backend.c
+++ b/calendar/libedata-cal/e-cal-backend.c
@@ -1373,9 +1373,263 @@ e_cal_backend_stop_view (ECalBackend *backend,
 }
 
 static gboolean
-object_created_cb (EDataCalView *view,
-                   gpointer calobj)
+component_created_cb (EDataCalView *view, gpointer data)
 {
+	ECalComponent *comp     = (ECalComponent *)data;
+	icalcomponent *icalcomp = e_cal_component_get_icalcomponent (comp);
+
+	if (e_data_cal_view_component_matches (view, comp))
+		e_data_cal_view_notify_components_added_1 (view, icalcomp);
+
+	return TRUE;
+}
+
+static ECalComponent *
+ecal_comp_from_icalcomp (const icalcomponent *component)
+{
+	ECalComponent *comp = NULL;
+	icalcomponent *icalclone;
+
+	if (component) {
+		comp      = e_cal_component_new ();
+		icalclone = icalcomponent_new_clone ((icalcomponent *)component);
+
+		if (!e_cal_component_set_icalcomponent (comp, icalclone)) {
+			g_warning ("ecal_comp_from_icalcomp failed to set icalcomponent");
+
+			icalcomponent_free (icalclone);
+			g_object_unref (comp);
+			comp = NULL;
+		}
+	}
+
+	return comp;
+}
+
+/**
+ * e_cal_backend_notify_component_created:
+ * @backend: an #ECalBackend
+ * @component: the newly created #icalcomponent
+ *
+ * Notifies each of the backend's listeners about a new object.
+ *
+ * Like e_cal_backend_notify_object_created() except takes an #icalcomponent
+ * instead of an ical string representation and uses the #EDataCalView's fields-of-interest
+ * to filter out unwanted information from ical strings sent over the bus.
+ *
+ * Since: 3.4
+ **/
+void
+e_cal_backend_notify_component_created (ECalBackend         *backend,
+					const icalcomponent *component)
+{
+	ECalBackendPrivate *priv;
+	ECalComponent      *comp;
+
+	priv = backend->priv;
+
+	if (priv->notification_proxy) {
+		e_cal_backend_notify_component_created (priv->notification_proxy, component);
+		return;
+	}
+
+	comp = ecal_comp_from_icalcomp (component);
+
+	e_cal_backend_foreach_view (backend, component_created_cb, (gpointer) comp);
+	g_object_unref (comp);
+}
+
+/**
+ * e_cal_backend_notify_components_added:
+ *
+ * Like e_cal_backend_notify_objects_added() except take a list of #icalcomponents
+ * instead of ical string representations and uses the #EDataCalView's fields-of-interest
+ * to filter out unwanted information from ical strings sent over the bus.
+ *
+ * Since: 3.4
+ **/
+void
+e_cal_backend_notify_components_added (ECalBackend  *backend,
+				       EDataCalView *view,
+				       const GSList *objects)
+{
+	e_data_cal_view_notify_components_added (view, objects);
+}
+
+static void
+match_view_and_notify_component (EDataCalView  *view,
+				 ECalComponent *old_component,
+				 ECalComponent *component)
+{
+	gboolean old_match = FALSE, new_match = FALSE;
+	icalcomponent *icalcomp;
+
+	if (old_component)
+		old_match = e_data_cal_view_component_matches (view, old_component);
+
+	new_match = e_data_cal_view_component_matches (view, component);
+	icalcomp  = e_cal_component_get_icalcomponent (component);
+
+	if (old_match && new_match)
+		e_data_cal_view_notify_components_modified_1 (view, icalcomp);
+	else if (new_match)
+		e_data_cal_view_notify_components_added_1 (view, icalcomp);
+	else if (old_match) {
+
+		ECalComponentId *id = e_cal_component_get_id (old_component);
+
+		e_data_cal_view_notify_objects_removed_1 (view, id);
+
+		e_cal_component_free_id (id);
+	}
+}
+
+struct component_call_data {
+	ECalComponent         *old_component;
+	ECalComponent         *component;
+	const ECalComponentId *id;
+};
+
+static gboolean
+call_match_and_notify_component (EDataCalView *view, gpointer user_data)
+{
+	struct component_call_data *cd = user_data;
+
+	g_return_val_if_fail (user_data != NULL, FALSE);
+
+	match_view_and_notify_component (view, cd->old_component, cd->component);
+
+	return TRUE;
+}
+
+/**
+ * e_cal_backend_notify_component_modified:
+ * @backend: an #ECalBackend
+ * @old_component: the #icalcomponent before the modification
+ * @component: the #icalcomponent after the modification
+ *
+ * Notifies each of the backend's listeners about a modified object.
+ *
+ * Like e_cal_backend_notify_object_modified() except takes an #icalcomponent
+ * instead of an ical string representation and uses the #EDataCalView's fields-of-interest
+ * to filter out unwanted information from ical strings sent over the bus.
+ *
+ * Since: 3.4
+ **/
+void
+e_cal_backend_notify_component_modified (ECalBackend         *backend,
+					 const icalcomponent *old_component,
+					 const icalcomponent *component)
+{
+	ECalBackendPrivate *priv;
+	struct component_call_data cd;
+
+	priv = backend->priv;
+
+	if (priv->notification_proxy) {
+		e_cal_backend_notify_component_modified (priv->notification_proxy, old_component, component);
+		return;
+	}
+
+	cd.old_component = ecal_comp_from_icalcomp (old_component);
+	cd.component     = ecal_comp_from_icalcomp (component);
+	cd.id            = NULL;
+
+	e_cal_backend_foreach_view (backend, call_match_and_notify_component, &cd);
+
+	if (cd.old_component)
+		g_object_unref (cd.old_component);
+
+	if (cd.component)
+		g_object_unref (cd.component);
+}
+
+/**
+ * e_cal_backend_notify_components_modified:
+ *
+ * Like e_cal_backend_notify_objects_modified() except takes a list of #icalcomponents
+ * instead of a ical string representations and uses the #EDataCalView's fields-of-interest
+ * to filter out unwanted information from ical strings sent over the bus.
+ *
+ * Since: 3.4
+ **/
+void
+e_cal_backend_notify_components_modified (ECalBackend  *backend,
+					  EDataCalView *view,
+					  const GSList *objects)
+{
+	e_data_cal_view_notify_components_modified (view, objects);
+}
+
+static gboolean
+component_removed_cb (EDataCalView *view, gpointer user_data)
+{
+	struct component_call_data *cd = user_data;
+
+	g_return_val_if_fail (user_data != NULL, FALSE);
+
+	if (cd->component == NULL) {
+		/* if object == NULL, it means the object has been completely
+		   removed from the backend */
+		if (!cd->old_component || e_data_cal_view_component_matches (view, cd->old_component))
+			e_data_cal_view_notify_objects_removed_1 (view, cd->id);
+	} else
+		match_view_and_notify_component (view, cd->old_component, cd->component);
+
+	return TRUE;
+}
+
+/**
+ * e_cal_backend_notify_component_removed:
+ * @backend: an #ECalBackend
+ * @id: the Id of the removed object
+ * @old_component: the removed component
+ * @component: the component after the removal. This only applies to recurrent 
+ * appointments that had an instance removed. In that case, this function notifies a 
+ * modification instead of a removal.
+ *
+ * Notifies each of the backend's listeners about a removed object.
+ *
+ * Like e_cal_backend_notify_object_removed() except takes an #icalcomponent
+ * instead of an ical string representation and uses the #EDataCalView's fields-of-interest
+ * to filter out unwanted information from ical strings sent over the bus.
+ *
+ * Since: 3.4
+ **/
+void
+e_cal_backend_notify_component_removed (ECalBackend           *backend,
+					const ECalComponentId *id,
+					const icalcomponent   *old_component,
+					const icalcomponent   *component)
+{
+	ECalBackendPrivate *priv;
+	struct component_call_data cd;
+
+	priv = backend->priv;
+
+	if (priv->notification_proxy) {
+		e_cal_backend_notify_component_removed (priv->notification_proxy, id, old_component, component);
+		return;
+	}
+
+	cd.old_component = ecal_comp_from_icalcomp (old_component);
+	cd.component     = ecal_comp_from_icalcomp (component);
+	cd.id            = id;
+
+	e_cal_backend_foreach_view (backend, component_removed_cb, &cd);
+
+	if (cd.old_component)
+		g_object_unref (cd.old_component);
+
+	if (cd.component)
+		g_object_unref (cd.component);
+}
+
+static gboolean
+object_created_cb (EDataCalView *view, gpointer data)
+{
+	const gchar *calobj = data;
+
 	if (e_data_cal_view_object_matches (view, calobj))
 		e_data_cal_view_notify_objects_added_1 (view, calobj);
 
@@ -1385,7 +1639,7 @@ object_created_cb (EDataCalView *view,
 /**
  * e_cal_backend_notify_object_created:
  * @backend: an #ECalBackend
- * @calobj: iCalendar representation of new object
+ * @calobj: the newly created object
  *
  * Notifies each of the backend's listeners about a new object.
  *
@@ -1423,9 +1677,9 @@ e_cal_backend_notify_objects_added (ECalBackend *backend,
 }
 
 static void
-match_view_and_notify (EDataCalView *view,
-                       const gchar *old_object,
-                       const gchar *object)
+match_view_and_notify_object (EDataCalView *view,
+			      const gchar  *old_object,
+			      const gchar  *object)
 {
 	gboolean old_match = FALSE, new_match = FALSE;
 
@@ -1452,21 +1706,20 @@ match_view_and_notify (EDataCalView *view,
 	}
 }
 
-struct call_data {
+struct object_call_data {
 	const gchar *old_object;
 	const gchar *object;
 	const ECalComponentId *id;
 };
 
 static gboolean
-call_match_and_notify (EDataCalView *view,
-                       gpointer user_data)
+call_match_and_notify_object (EDataCalView *view, gpointer user_data)
 {
-	struct call_data *cd = user_data;
+	struct object_call_data *cd = user_data;
 
 	g_return_val_if_fail (user_data != NULL, FALSE);
 
-	match_view_and_notify (view, cd->old_object, cd->object);
+	match_view_and_notify_object (view, cd->old_object, cd->object);
 
 	return TRUE;
 }
@@ -1489,7 +1742,7 @@ e_cal_backend_notify_object_modified (ECalBackend *backend,
                                       const gchar *object)
 {
 	ECalBackendPrivate *priv;
-	struct call_data cd;
+	struct object_call_data cd;
 
 	priv = backend->priv;
 
@@ -1502,7 +1755,7 @@ e_cal_backend_notify_object_modified (ECalBackend *backend,
 	cd.object = object;
 	cd.id = NULL;
 
-	e_cal_backend_foreach_view (backend, call_match_and_notify, &cd);
+	e_cal_backend_foreach_view (backend, call_match_and_notify_object, &cd);
 }
 
 /**
@@ -1522,7 +1775,7 @@ static gboolean
 object_removed_cb (EDataCalView *view,
                    gpointer user_data)
 {
-	struct call_data *cd = user_data;
+	struct object_call_data *cd = user_data;
 
 	g_return_val_if_fail (user_data != NULL, FALSE);
 
@@ -1532,7 +1785,7 @@ object_removed_cb (EDataCalView *view,
 		if (!cd->old_object || e_data_cal_view_object_matches (view, cd->old_object))
 			e_data_cal_view_notify_objects_removed_1 (view, cd->id);
 	} else
-		match_view_and_notify (view, cd->old_object, cd->object);
+		match_view_and_notify_object (view, cd->old_object, cd->object);
 
 	return TRUE;
 }
@@ -1559,7 +1812,7 @@ e_cal_backend_notify_object_removed (ECalBackend *backend,
                                      const gchar *object)
 {
 	ECalBackendPrivate *priv;
-	struct call_data cd;
+	struct object_call_data cd;
 
 	priv = backend->priv;
 
@@ -1868,17 +2121,16 @@ e_cal_backend_empty_cache (ECalBackend *backend,
 	for (comps_in_cache = e_cal_backend_cache_get_components (cache);
 	     comps_in_cache;
 	     comps_in_cache = comps_in_cache->next) {
-		gchar *comp_str;
 		ECalComponentId *id;
-		ECalComponent *comp = comps_in_cache->data;
+		ECalComponent   *comp     = comps_in_cache->data;
+		icalcomponent   *icalcomp = e_cal_component_get_icalcomponent (comp);
 
 		id = e_cal_component_get_id (comp);
-		comp_str = e_cal_component_get_as_string (comp);
 
 		e_cal_backend_cache_remove_component (cache, id->uid, id->rid);
-		e_cal_backend_notify_object_removed (backend, id, comp_str, NULL);
 
-		g_free (comp_str);
+		e_cal_backend_notify_component_removed	(backend, id, icalcomp, NULL);
+
 		e_cal_component_free_id (id);
 		g_object_unref (comp);
 	}
diff --git a/calendar/libedata-cal/e-cal-backend.h b/calendar/libedata-cal/e-cal-backend.h
index 73198c6..e566110 100644
--- a/calendar/libedata-cal/e-cal-backend.h
+++ b/calendar/libedata-cal/e-cal-backend.h
@@ -214,6 +214,12 @@ icaltimezone *	e_cal_backend_internal_get_timezone	(ECalBackend *backend, const
 void		e_cal_backend_start_view		(ECalBackend *backend, EDataCalView *view);
 void		e_cal_backend_stop_view			(ECalBackend *backend, EDataCalView *view);
 
+void		e_cal_backend_notify_component_created	(ECalBackend *backend, const icalcomponent *component);
+void		e_cal_backend_notify_components_added	(ECalBackend *backend, EDataCalView *view, const GSList *components);
+void		e_cal_backend_notify_component_modified	(ECalBackend *backend, const icalcomponent *old_component, const icalcomponent *new_component);
+void		e_cal_backend_notify_components_modified(ECalBackend *backend, EDataCalView *view, const GSList *components);
+void		e_cal_backend_notify_component_removed	(ECalBackend *backend, const ECalComponentId *id, const icalcomponent *old_component, const icalcomponent *component);
+
 void		e_cal_backend_notify_object_created	(ECalBackend *backend, const gchar *calobj);
 void		e_cal_backend_notify_objects_added	(ECalBackend *backend, EDataCalView *view, const GSList *objects);
 void		e_cal_backend_notify_object_modified	(ECalBackend *backend, const gchar *old_object, const gchar *object);
diff --git a/calendar/libedata-cal/e-data-cal-view.c b/calendar/libedata-cal/e-data-cal-view.c
index 6a63017..24b2589 100644
--- a/calendar/libedata-cal/e-data-cal-view.c
+++ b/calendar/libedata-cal/e-data-cal-view.c
@@ -270,7 +270,7 @@ ensure_pending_flush_timeout (EDataCalView *view)
 
 static void
 notify_add (EDataCalView *view,
-            gchar *obj)
+            gchar        *obj)
 {
 	EDataCalViewPrivate *priv = view->priv;
 	ECalComponent *comp;
@@ -293,8 +293,37 @@ notify_add (EDataCalView *view,
 }
 
 static void
-notify_change (EDataCalView *view,
-               gchar *obj)
+notify_add_component (EDataCalView *view, icalcomponent *icalcomp)
+{
+	EDataCalViewPrivate *priv = view->priv;
+	icalcomponent       *icalclone;
+	ECalComponent       *comp;
+	gchar               *obj;
+
+	obj = e_data_cal_view_get_component_string (view, icalcomp);
+
+	send_pending_changes (view);
+	send_pending_removes (view);
+
+	if (priv->adds->len == THRESHOLD_ITEMS) {
+		send_pending_adds (view);
+	}
+	g_array_append_val (priv->adds, obj);
+
+	comp = e_cal_component_new ();
+	icalclone = icalcomponent_new_clone (icalcomp);
+	e_cal_component_set_icalcomponent (comp, icalclone);
+
+	g_hash_table_insert (priv->ids,
+			     e_cal_component_get_id (comp),
+			     GUINT_TO_POINTER (1));
+	g_object_unref (comp);
+
+	ensure_pending_flush_timeout (view);
+}
+
+static void
+notify_change (EDataCalView *view, gchar *obj)
 {
 	EDataCalViewPrivate *priv = view->priv;
 
@@ -311,8 +340,17 @@ notify_change (EDataCalView *view,
 }
 
 static void
-notify_remove (EDataCalView *view,
-               ECalComponentId *id)
+notify_change_component (EDataCalView *view, icalcomponent *comp)
+{
+	gchar *obj;
+
+	obj = e_data_cal_view_get_component_string (view, comp);
+
+	notify_change (view, obj);
+}
+
+static void
+notify_remove (EDataCalView *view, ECalComponentId *id)
 {
 	EDataCalViewPrivate *priv = view->priv;
 	gchar *ids;
@@ -672,6 +710,32 @@ e_data_cal_view_object_matches (EDataCalView *view,
 }
 
 /**
+ * e_data_cal_view_component_matches:
+ * @view: A view object.
+ * @component: the #ECalComponent object to match.
+ *
+ * Compares the given @component to the regular expression used for the
+ * given view.
+ *
+ * Returns: TRUE if the object matches the expression, FALSE if not.
+ *
+ * Since: 3.4
+ */
+gboolean
+e_data_cal_view_component_matches (EDataCalView *view, ECalComponent *component)
+{
+	EDataCalViewPrivate *priv;
+
+	g_return_val_if_fail (view != NULL, FALSE);
+	g_return_val_if_fail (E_IS_DATA_CAL_VIEW (view), FALSE);
+	g_return_val_if_fail (E_IS_CAL_COMPONENT (component), FALSE);
+
+	priv = view->priv;
+
+	return e_cal_backend_sexp_match_comp (priv->sexp, component, priv->backend);
+}
+
+/**
  * e_data_cal_view_is_started:
  * @view: A view object.
  *
@@ -748,12 +812,245 @@ e_data_cal_view_get_fields_of_interest (EDataCalView *view)
 	return view->priv->fields_of_interest;
 }
 
+static gboolean
+filter_component (icalcomponent *icomponent, GHashTable *fields_of_interest, GString *string)
+{
+	gchar             *str;
+
+	/* RFC 2445 explicitly says that the newline is *ALWAYS* a \r\n (CRLF)!!!! */
+	const gchar        newline[] = "\r\n";
+	
+	icalcomponent_kind kind;
+	const gchar       *kind_string;
+	icalproperty      *prop;
+	icalcomponent     *icomp;
+	gboolean           fail = FALSE;
+
+	/* Open iCalendar string */
+	g_string_append (string, "BEGIN:");
+
+	kind = icalcomponent_isa (icomponent);
+
+	/* if (kind != ICAL_X_COMPONENT) { */
+	/* 	kind_string  = icalcomponent_kind_to_string (kind); */
+	/* } else { */
+	/* 	kind_string = icomponent->x_name; */
+	/* } */
+
+	kind_string  = icalcomponent_kind_to_string (kind);
+
+	g_string_append (string, kind_string);
+	g_string_append (string, newline);
+
+	for (prop = icalcomponent_get_first_property (icomponent, ICAL_ANY_PROPERTY);
+	     prop;
+	     prop = icalcomponent_get_next_property (icomponent, ICAL_ANY_PROPERTY)) {
+		const gchar *name;
+		gboolean     is_field_of_interest;
+
+		name = icalproperty_get_property_name (prop);
+
+		if (!name) {
+			g_warning ("NULL ical property name encountered while serializing component");
+			fail = TRUE;
+			break;
+		}
+
+		is_field_of_interest = GPOINTER_TO_INT (g_hash_table_lookup (fields_of_interest, name));
+
+		/* Append any name that is mentioned in the fields-of-interest */
+		if (is_field_of_interest) {
+			str = icalproperty_as_ical_string_r (prop);
+			g_string_append (string, str);
+			g_free (str);
+		}
+	}
+
+	for (icomp = icalcomponent_get_first_component (icomponent, ICAL_ANY_COMPONENT);
+	     fail == FALSE && icomp;
+	     icomp = icalcomponent_get_next_component (icomponent, ICAL_ANY_COMPONENT)) {
+		
+		if (!filter_component (icomp, fields_of_interest, string)) {
+			fail = TRUE;
+			break;
+		}
+	}
+
+	g_string_append (string, "END:");
+	g_string_append (string, icalcomponent_kind_to_string (kind));
+	g_string_append (string, newline);
+
+	return fail == FALSE;
+}
+
+/**
+ * e_data_cal_view_get_component_string:
+ * @view: A view object.
+ * @component: The #icalcomponent to get the string for.
+ *
+ * This function is similar to e_cal_component_get_as_string() except
+ * that it takes into account the fields-of-interest that @view is 
+ * configured with and filters out any unneeded fields.
+ *
+ * Returns: (transfer full): A newly allocated string representation of @component suitable for @view.
+ *
+ * Since: 3.4
+ */
+gchar *
+e_data_cal_view_get_component_string (EDataCalView *view, icalcomponent *component)
+{
+	g_return_val_if_fail (E_IS_DATA_CAL_VIEW (view), NULL);
+	g_return_val_if_fail (component != NULL, NULL);
+
+	if (view->priv->fields_of_interest) {
+		GString *string = g_string_new ("");
+
+		if (filter_component (component, view->priv->fields_of_interest, string))
+			return g_string_free (string, FALSE);
+
+		g_string_free (string, TRUE);
+	}
+
+	return icalcomponent_as_ical_string_r (component);
+}
+
+/**
+ * e_data_cal_view_notify_components_added:
+ * @view: A view object.
+ * @components: List of components that have been added.
+ *
+ * Notifies all view listeners of the addition of a list of components.
+ *
+ * Like e_data_cal_view_notify_objects_added() except takes a list
+ * of #icalcomponents instead of ical string representations and uses the 
+ * #EDataCalView's fields-of-interest to filter out unwanted information 
+ * from ical strings sent over the bus.
+ *
+ * Since: 3.4
+ */
+void
+e_data_cal_view_notify_components_added (EDataCalView *view,
+					 const GSList *components)
+{
+	EDataCalViewPrivate *priv;
+	const GSList *l;
+
+	g_return_if_fail (view && E_IS_DATA_CAL_VIEW (view));
+	priv = view->priv;
+
+	if (components == NULL)
+		return;
+
+	g_mutex_lock (priv->pending_mutex);
+
+	for (l = components; l; l = l->next) {
+		icalcomponent *comp = l->data;
+
+		notify_add_component (view, comp);
+	}
+
+	g_mutex_unlock (priv->pending_mutex);
+}
+
+/**
+ * e_data_cal_view_notify_components_added_1:
+ * @view: A view object.
+ * @component: The #icalcomponent that has been added.
+ *
+ * Notifies all the view listeners of the addition of a single object.
+ *
+ * Like e_data_cal_view_notify_objects_added_1() except takes an #icalcomponent
+ * instead of an ical string representation and uses the #EDataCalView's fields-of-interest
+ * to filter out unwanted information from ical strings sent over the bus.
+ *
+ * Since: 3.4
+ */
+void
+e_data_cal_view_notify_components_added_1 (EDataCalView        *view,
+					   const icalcomponent *component)
+{
+	GSList l = {NULL,};
+
+	g_return_if_fail (E_IS_DATA_CAL_VIEW (view));
+	g_return_if_fail (component != NULL);
+
+	l.data = (gpointer) component;
+	e_data_cal_view_notify_components_added (view, &l);
+}
+
+/**
+ * e_data_cal_view_notify_components_modified:
+ * @view: A view object.
+ * @components: List of modified components.
+ *
+ * Notifies all view listeners of the modification of a list of components.
+ *
+ * Like e_data_cal_view_notify_objects_modified() except takes a list of #icalcomponents
+ * instead of a ical string representations and uses the #EDataCalView's fields-of-interest
+ * to filter out unwanted information from ical strings sent over the bus.
+ *
+ * Since: 3.4
+ */
+void
+e_data_cal_view_notify_components_modified (EDataCalView *view,
+					    const GSList *components)
+{
+	EDataCalViewPrivate *priv;
+	const GSList *l;
+
+	g_return_if_fail (view && E_IS_DATA_CAL_VIEW (view));
+	priv = view->priv;
+
+	if (components == NULL)
+		return;
+
+	g_mutex_lock (priv->pending_mutex);
+
+	for (l = components; l; l = l->next) {
+		/* TODO: send add/remove/change as relevant, based on ->ids */
+		icalcomponent *comp = l->data;
+
+		notify_change_component (view, comp);
+	}
+
+	g_mutex_unlock (priv->pending_mutex);
+}
+
+/**
+ * e_data_cal_view_notify_components_modified_1:
+ * @view: A view object.
+ * @component: The modified #icalcomponent.
+ *
+ * Notifies all view listeners of the modification of @component.
+ * 
+ * Like e_data_cal_view_notify_objects_modified_1() except takes an #icalcomponent
+ * instead of an ical string representation and uses the #EDataCalView's fields-of-interest
+ * to filter out unwanted information from ical strings sent over the bus.
+ *
+ * Since: 3.4
+ */
+void
+e_data_cal_view_notify_components_modified_1 (EDataCalView        *view,
+					      const icalcomponent *component)
+{
+	GSList l = {NULL,};
+
+	g_return_if_fail (E_IS_DATA_CAL_VIEW (view));
+	g_return_if_fail (component != NULL);
+
+	l.data = (gpointer) component;
+	e_data_cal_view_notify_components_modified (view, &l);
+}
+
 /**
  * e_data_cal_view_notify_objects_added:
  * @view: A view object.
  * @objects: List of objects that have been added.
  *
  * Notifies all view listeners of the addition of a list of objects.
+ *
+ * If possible e_data_cal_view_notify_components_added() should be used
+ * instead.
  */
 void
 e_data_cal_view_notify_objects_added (EDataCalView *view,
@@ -783,6 +1080,9 @@ e_data_cal_view_notify_objects_added (EDataCalView *view,
  * @object: The object that has been added.
  *
  * Notifies all the view listeners of the addition of a single object.
+ *
+ * If possible e_data_cal_view_notify_components_added_1() should be used
+ * instead.
  */
 void
 e_data_cal_view_notify_objects_added_1 (EDataCalView *view,
@@ -803,6 +1103,9 @@ e_data_cal_view_notify_objects_added_1 (EDataCalView *view,
  * @objects: List of modified objects.
  *
  * Notifies all view listeners of the modification of a list of objects.
+ *
+ * If possible e_data_cal_view_notify_components_modified() should be used
+ * instead.
  */
 void
 e_data_cal_view_notify_objects_modified (EDataCalView *view,
@@ -833,6 +1136,9 @@ e_data_cal_view_notify_objects_modified (EDataCalView *view,
  * @object: The modified object.
  *
  * Notifies all view listeners of the modification of a single object.
+ *
+ * If possible e_data_cal_view_notify_components_modified_1() should be used
+ * instead.
  */
 void
 e_data_cal_view_notify_objects_modified_1 (EDataCalView *view,
diff --git a/calendar/libedata-cal/e-data-cal-view.h b/calendar/libedata-cal/e-data-cal-view.h
index 06a0f2e..bfe80e5 100644
--- a/calendar/libedata-cal/e-data-cal-view.h
+++ b/calendar/libedata-cal/e-data-cal-view.h
@@ -52,11 +52,19 @@ guint			e_data_cal_view_register_gdbus_object		(EDataCalView *view, GDBusConnect
 const gchar *		e_data_cal_view_get_text			(EDataCalView *view);
 ECalBackendSExp *	e_data_cal_view_get_object_sexp			(EDataCalView *view);
 gboolean		e_data_cal_view_object_matches			(EDataCalView *view, const gchar *object);
+gboolean		e_data_cal_view_component_matches		(EDataCalView *view, ECalComponent *component);
 gboolean		e_data_cal_view_is_started			(EDataCalView *view);
 gboolean		e_data_cal_view_is_completed			(EDataCalView *view);
 gboolean		e_data_cal_view_is_stopped			(EDataCalView *view);
 GHashTable *		e_data_cal_view_get_fields_of_interest		(EDataCalView *view);
 
+gchar                  *e_data_cal_view_get_component_string            (EDataCalView *view, icalcomponent *component);
+
+void			e_data_cal_view_notify_components_added	        (EDataCalView *view, const GSList *objects);
+void			e_data_cal_view_notify_components_added_1       (EDataCalView *view, const icalcomponent *component);
+void			e_data_cal_view_notify_components_modified      (EDataCalView *view, const GSList *objects);
+void			e_data_cal_view_notify_components_modified_1    (EDataCalView *view, const icalcomponent *component);
+
 void			e_data_cal_view_notify_objects_added		(EDataCalView *view, const GSList *objects);
 void			e_data_cal_view_notify_objects_added_1		(EDataCalView *view, const gchar *object);
 void			e_data_cal_view_notify_objects_modified		(EDataCalView *view, const GSList *objects);
diff --git a/calendar/libedata-cal/e-data-cal.c b/calendar/libedata-cal/e-data-cal.c
index b78fa98..52ca24e 100644
--- a/calendar/libedata-cal/e-data-cal.c
+++ b/calendar/libedata-cal/e-data-cal.c
@@ -1167,18 +1167,18 @@ e_data_cal_respond_get_free_busy (EDataCal *cal,
  * @cal: A calendar client interface.
  * @error: Operation error, if any, automatically freed if passed it.
  * @uid: UID of the object created.
- * @object: The object created as an iCalendar string.
+ * @component: The newly created #icalcomponent.
  *
  * Notifies listeners of the completion of the create_object method call.
  *
  * Since: 3.2
  */
 void
-e_data_cal_respond_create_object (EDataCal *cal,
-                                  guint32 opid,
-                                  GError *error,
-                                  const gchar *uid,
-                                  const gchar *object)
+e_data_cal_respond_create_object (EDataCal      *cal,
+				  guint32        opid,
+				  GError        *error,
+				  const gchar   *uid,
+				  icalcomponent *component)
 {
 	gchar *gdbus_uid = NULL;
 
@@ -1193,26 +1193,26 @@ e_data_cal_respond_create_object (EDataCal *cal,
 	if (error)
 		g_error_free (error);
 	else
-		e_cal_backend_notify_object_created (cal->priv->backend, object);
+		e_cal_backend_notify_component_created (cal->priv->backend, component);
 }
 
 /**
  * e_data_cal_respond_modify_object:
  * @cal: A calendar client interface.
  * @error: Operation error, if any, automatically freed if passed it.
- * @old_object: The old object as an iCalendar string.
- * @object: The modified object as an iCalendar string.
+ * @old_component: The old #icalcomponent.
+ * @component: The new #icalcomponent.
  *
  * Notifies listeners of the completion of the modify_object method call.
  *
  * Since: 3.2
  */
 void
-e_data_cal_respond_modify_object (EDataCal *cal,
-                                  guint32 opid,
-                                  GError *error,
-                                  const gchar *old_object,
-                                  const gchar *object)
+e_data_cal_respond_modify_object (EDataCal      *cal,
+				  guint32        opid,
+				  GError        *error,
+				  icalcomponent *old_component,
+				  icalcomponent *component)
 {
 	op_complete (cal, opid);
 
@@ -1224,7 +1224,7 @@ e_data_cal_respond_modify_object (EDataCal *cal,
 	if (error)
 		g_error_free (error);
 	else
-		e_cal_backend_notify_object_modified (cal->priv->backend, old_object, object);
+		e_cal_backend_notify_component_modified (cal->priv->backend, old_component, component);
 }
 
 /**
@@ -1232,8 +1232,8 @@ e_data_cal_respond_modify_object (EDataCal *cal,
  * @cal: A calendar client interface.
  * @error: Operation error, if any, automatically freed if passed it.
  * @uid: UID of the removed object.
- * @old_object: The old object as an iCalendar string.
- * @object: The new object as an iCalendar string. This will not be NULL only
+ * @old_component: The old #icalcomponent.
+ * @component: The new #icalcomponent. This will not be NULL only
  * when removing instances of a recurring appointment.
  *
  * Notifies listeners of the completion of the remove_object method call.
@@ -1245,8 +1245,8 @@ e_data_cal_respond_remove_object (EDataCal *cal,
                                   guint32 opid,
                                   GError *error,
                                   const ECalComponentId *id,
-                                  const gchar *old_object,
-                                  const gchar *object)
+				  icalcomponent *old_component,
+				  icalcomponent *component)
 {
 	op_complete (cal, opid);
 
@@ -1258,7 +1258,7 @@ e_data_cal_respond_remove_object (EDataCal *cal,
 	if (error)
 		g_error_free (error);
 	else
-		e_cal_backend_notify_object_removed (cal->priv->backend, id, old_object, object);
+		e_cal_backend_notify_component_removed (cal->priv->backend, id, old_component, component);
 }
 
 /**
diff --git a/calendar/libedata-cal/e-data-cal.h b/calendar/libedata-cal/e-data-cal.h
index 4bb9788..9f3e5f4 100644
--- a/calendar/libedata-cal/e-data-cal.h
+++ b/calendar/libedata-cal/e-data-cal.h
@@ -136,9 +136,9 @@ void		e_data_cal_respond_set_backend_property		(EDataCal *cal, guint32 opid, GEr
 void		e_data_cal_respond_get_object			(EDataCal *cal, guint32 opid, GError *error, const gchar *object);
 void		e_data_cal_respond_get_object_list		(EDataCal *cal, guint32 opid, GError *error, const GSList *objects);
 void		e_data_cal_respond_get_free_busy		(EDataCal *cal, guint32 opid, GError *error);
-void		e_data_cal_respond_create_object		(EDataCal *cal, guint32 opid, GError *error, const gchar *uid, const gchar *object);
-void		e_data_cal_respond_modify_object		(EDataCal *cal, guint32 opid, GError *error, const gchar *old_object, const gchar *object);
-void		e_data_cal_respond_remove_object		(EDataCal *cal, guint32 opid, GError *error, const ECalComponentId *id, const gchar *old_object, const gchar *object);
+void		e_data_cal_respond_create_object		(EDataCal *cal, guint32 opid, GError *error, const gchar *uid, icalcomponent *component);
+void		e_data_cal_respond_modify_object		(EDataCal *cal, guint32 opid, GError *error, icalcomponent *old_component, icalcomponent *component);
+void		e_data_cal_respond_remove_object		(EDataCal *cal, guint32 opid, GError *error, const ECalComponentId *id, icalcomponent *old_component, icalcomponent *component);
 void		e_data_cal_respond_receive_objects		(EDataCal *cal, guint32 opid, GError *error);
 void		e_data_cal_respond_send_objects			(EDataCal *cal, guint32 opid, GError *error, const GSList *users, const gchar *calobj);
 void		e_data_cal_respond_get_attachment_uris		(EDataCal *cal, guint32 opid, GError *error, const GSList *attachments);



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