Bug 670457: Add bulk methods to ECalClient
authorChristophe Dumez <christophe.dumez@intel.com>
Tue, 21 Feb 2012 07:38:43 +0000 (09:38 +0200)
committerChristophe Dumez <christophe.dumez@intel.com>
Tue, 27 Mar 2012 16:48:27 +0000 (19:48 +0300)
Add e_cal_client_create_objects*() / e_cal_client_modify_objects*() /
e_cal_client_remove_objects*() bulk methods to ECalClient.

21 files changed:
calendar/backends/caldav/e-cal-backend-caldav.c
calendar/backends/contacts/e-cal-backend-contacts.c
calendar/backends/file/e-cal-backend-file.c
calendar/backends/http/e-cal-backend-http.c
calendar/libecal/e-cal-client.c
calendar/libecal/e-cal-client.h
calendar/libecal/e-cal-util.h
calendar/libecal/e-cal.c
calendar/libedata-cal/e-cal-backend-sync.c
calendar/libedata-cal/e-cal-backend-sync.h
calendar/libedata-cal/e-cal-backend.c
calendar/libedata-cal/e-cal-backend.h
calendar/libedata-cal/e-data-cal.c
calendar/libedata-cal/e-data-cal.h
calendar/libegdbus/e-gdbus-cal.c
calendar/libegdbus/e-gdbus-cal.h
configure.ac
libedataserver/e-data-server-util.c
libedataserver/e-data-server-util.h
tests/libecal/client/Makefile.am
tests/libecal/client/test-client-bulk-methods.c [new file with mode: 0644]

index 323d228..8df9121 100644 (file)
@@ -3562,21 +3562,29 @@ get_ecalcomp_master_from_cache_or_fallback (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,
-                  ECalComponent **new_component,
-                  GError **perror)
+do_create_objects (ECalBackendCalDAV *cbdav,
+                   const GSList *in_calobjs,
+                   GSList **uids,
+                   GSList **new_components,
+                   GError **perror)
 {
        ECalComponent            *comp;
        gboolean                  online, did_put = FALSE;
        struct icaltimetype current;
        icalcomponent *icalcomp;
+       const gchar *in_calobj = in_calobjs->data;
        const gchar *comp_uid;
 
        if (!check_state (cbdav, &online, perror))
                return;
 
+       /* We make the assumption that the in_calobjs list we're passed is always exactly one element long, since we haven't specified "bulk-adds"
+        * in our static capability list. This simplifies a lot of the logic, especially around asynchronous results. */
+       if (in_calobjs->next != NULL) {
+               g_propagate_error (perror, e_data_cal_create_error (UnsupportedMethod, _("CalDAV does not support bulk additions")));
+               return;
+       }
+
        comp = e_cal_component_new_from_string (in_calobj);
 
        if (comp == NULL) {
@@ -3639,11 +3647,11 @@ do_create_object (ECalBackendCalDAV *cbdav,
        }
 
        if (did_put) {
-               if (uid)
-                       *uid = g_strdup (comp_uid);
+               if (uids)
+                       *uids = g_slist_prepend (*uids, g_strdup (comp_uid));
 
-               if (new_component)
-                       *new_component = get_ecalcomp_master_from_cache_or_fallback (cbdav, comp_uid, NULL, comp);
+               if (new_components)
+                       *new_components = g_slist_prepend(*new_components, get_ecalcomp_master_from_cache_or_fallback (cbdav, comp_uid, NULL, comp));
        }
 
        g_object_unref (comp);
@@ -3651,12 +3659,12 @@ 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,
-                  ECalComponent **old_component,
-                  ECalComponent **new_component,
-                  GError **error)
+do_modify_objects (ECalBackendCalDAV *cbdav,
+                   const GSList *calobjs,
+                   CalObjModType mod,
+                   GSList **old_components,
+                   GSList **new_components,
+                   GError **error)
 {
        ECalComponent            *comp;
        icalcomponent            *cache_comp;
@@ -3664,13 +3672,21 @@ do_modify_object (ECalBackendCalDAV *cbdav,
        ECalComponentId          *id;
        struct icaltimetype current;
        gchar *href = NULL, *etag = NULL;
+       const gchar *calobj = calobjs->data;
 
-       if (new_component)
-               *new_component = NULL;
+       if (new_components)
+               *new_components = NULL;
 
        if (!check_state (cbdav, &online, error))
                return;
 
+       /* We make the assumption that the calobjs list we're passed is always exactly one element long, since we haven't specified "bulk-modifies"
+        * in our static capability list. This simplifies a lot of the logic, especially around asynchronous results. */
+       if (calobjs->next != NULL) {
+               g_propagate_error (error, e_data_cal_create_error (UnsupportedMethod, _("CalDAV does not support bulk modifications")));
+               return;
+       }
+
        comp = e_cal_component_new_from_string (calobj);
 
        if (comp == NULL) {
@@ -3712,8 +3728,8 @@ do_modify_object (ECalBackendCalDAV *cbdav,
                /*ecalcomp_set_synch_state (comp, ECALCOMP_LOCALLY_MODIFIED);*/
        }
 
-       if (old_component) {
-               *old_component = NULL;
+       if (old_components) {
+               *old_components = NULL;
 
                if (e_cal_component_is_instance (comp)) {
                        /* set detached instance as the old object, if any */
@@ -3721,17 +3737,17 @@ do_modify_object (ECalBackendCalDAV *cbdav,
 
                        /* This will give a reference to 'old_component' */
                        if (old_instance) {
-                               *old_component = e_cal_component_clone (old_instance);
+                               *old_components = g_slist_prepend (*old_components, e_cal_component_clone (old_instance));
                                g_object_unref (old_instance);
                        }
                }
 
-               if (!*old_component) {
+               if (!*old_components) {
                        icalcomponent *master = get_master_comp (cbdav, cache_comp);
 
                        if (master) {
                                /* set full component as the old object */
-                               *old_component = e_cal_component_new_from_icalcomponent (icalcomponent_new_clone (master));
+                               *old_components = g_slist_prepend (*old_components, e_cal_component_new_from_icalcomponent (icalcomponent_new_clone (master)));
                        }
                }
        }
@@ -3743,8 +3759,8 @@ do_modify_object (ECalBackendCalDAV *cbdav,
                        icalcomponent *new_comp = e_cal_component_get_icalcomponent (comp);
 
                        /* new object is only this instance */
-                       if (new_component)
-                               *new_component = e_cal_component_clone (comp);
+                       if (new_components)
+                               *new_components = g_slist_prepend (*new_components, e_cal_component_clone (comp));
 
                        /* add the detached instance */
                        if (icalcomponent_isa (cache_comp) == ICAL_VCALENDAR_COMPONENT) {
@@ -3798,11 +3814,9 @@ do_modify_object (ECalBackendCalDAV *cbdav,
        }
 
        if (did_put) {
-               if (new_component && !*new_component) {
+               if (new_components && !*new_components) {
                        /* read the comp from cache again, as some servers can modify it on put */
-                       *new_component = get_ecalcomp_master_from_cache_or_fallback (cbdav, id->uid, id->rid, NULL);
-
-                       g_warn_if_fail (*new_component != NULL);
+                       *new_components = g_slist_prepend (*new_components, get_ecalcomp_master_from_cache_or_fallback (cbdav, id->uid, id->rid, NULL));
                }
        }
 
@@ -3815,24 +3829,32 @@ 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,
-                  ECalComponent **old_component,
-                  ECalComponent **new_component,
-                  GError **perror)
+do_remove_objects (ECalBackendCalDAV *cbdav,
+                   const GSList *ids,
+                   CalObjModType mod,
+                   GSList **old_components,
+                   GSList **new_components,
+                   GError **perror)
 {
        icalcomponent            *cache_comp;
        gboolean                  online;
        gchar *href = NULL, *etag = NULL;
+       const gchar *uid = ((ECalComponentId *)ids->data)->uid;
+       const gchar *rid = ((ECalComponentId *)ids->data)->rid;
 
-       if (new_component)
-               *new_component = NULL;
+       if (new_components)
+               *new_components = NULL;
 
        if (!check_state (cbdav, &online, perror))
                return;
 
+       /* We make the assumption that the ids list we're passed is always exactly one element long, since we haven't specified "bulk-removes"
+        * in our static capability list. This simplifies a lot of the logic, especially around asynchronous results. */
+       if (ids->next != NULL) {
+               g_propagate_error (perror, e_data_cal_create_error (UnsupportedMethod, _("CalDAV does not support bulk removals")));
+               return;
+       }
+
        cache_comp = get_comp_from_cache (cbdav, uid, NULL, &href, &etag);
 
        if (cache_comp == NULL) {
@@ -3840,17 +3862,16 @@ do_remove_object (ECalBackendCalDAV *cbdav,
                return;
        }
 
-       if (old_component) {
+       if (old_components) {
                ECalComponent *old = e_cal_backend_store_get_component (cbdav->priv->store, uid, rid);
 
                if (old) {
-                       *old_component = e_cal_component_clone (old);
+                       *old_components = g_slist_prepend (*old_components, e_cal_component_clone (old));
                        g_object_unref (old);
                } else {
                        icalcomponent *master = get_master_comp (cbdav, cache_comp);
-
                        if (master) {
-                               *old_component = e_cal_component_new_from_icalcomponent (icalcomponent_new_clone (master));
+                               *old_components = g_slist_prepend (*old_components, e_cal_component_new_from_icalcomponent (icalcomponent_new_clone (master)));
                        }
                }
        }
@@ -3861,11 +3882,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 (new_component) {
+                               if (new_components) {
                                        icalcomponent *master = get_master_comp (cbdav, cache_comp);
-
-                                       if (master)
-                                               *new_component = e_cal_component_new_from_icalcomponent (icalcomponent_new_clone (master));
+                                       if (master) {
+                                               *new_components = g_slist_prepend (*new_components, e_cal_component_new_from_icalcomponent (icalcomponent_new_clone (master)));
+                                       }
                                }
                        } else {
                                /* this was the last instance, thus delete whole component */
@@ -4022,69 +4043,72 @@ process_object (ECalBackendCalDAV *cbdav,
                is_declined = e_cal_backend_user_declined (e_cal_component_get_icalcomponent (ecomp));
                if (is_in_cache) {
                        if (!is_declined) {
-                               ECalComponent *new_component = NULL, *old_component = NULL;
-
-                               do_modify_object (cbdav, new_obj_str, mod,
-                                                 &old_component, &new_component, &err);
-                               if (!err) {
-                                       if (!old_component)
-                                               e_cal_backend_notify_component_created (backend, new_component);
-                                       else
-                                               e_cal_backend_notify_component_modified (backend, old_component, new_component);
+                               GSList *new_components = NULL, *old_components = NULL;
+                               GSList new_obj_strs = {0,};
+
+                               new_obj_strs.data = new_obj_str;
+                               do_modify_objects (cbdav, &new_obj_strs, mod,
+                                                 &old_components, &new_components, &err);
+                               if (!err && new_components && new_components->data) {
+                                       if (!old_components || !old_components->data) {
+                                               e_cal_backend_notify_component_created (backend, new_components->data);
+                                       } else {
+                                               e_cal_backend_notify_component_modified (backend, old_components->data, new_components->data);
+                                       }
                                }
 
-                               if (new_component)
-                                       g_object_unref (new_component);
-                               if (old_component)
-                                       g_object_unref (old_component);
+                               e_util_free_nullable_object_slist (old_components);
+                               e_util_free_nullable_object_slist (new_components);
                        } else {
-                               ECalComponent *new_component = NULL, *old_component = NULL;
-
-                               do_remove_object (cbdav, id->uid, id->rid, mod, &old_component, &new_component, &err);
-                               if (!err) {
-                                       if (new_component) {
-                                               e_cal_backend_notify_component_modified (backend, old_component, new_component);
+                               GSList *new_components = NULL, *old_components = NULL;
+                               GSList ids = {0,};
+
+                               ids.data = id;
+                               do_remove_objects (cbdav, &ids, mod, &old_components, &new_components, &err);
+                               if (!err && old_components && old_components->data) {
+                                       if (new_components && new_components->data) {
+                                               e_cal_backend_notify_component_modified (backend, old_components->data, new_components->data);
                                        } else {
-                                               e_cal_backend_notify_component_removed (backend, id, old_component, NULL);
+                                               e_cal_backend_notify_component_removed (backend, id, old_components->data, NULL);
                                        }
                                }
 
-                               if (new_component)
-                                       g_object_unref (new_component);
-                               if (old_component)
-                                       g_object_unref (old_component);
+                               e_util_free_nullable_object_slist (old_components);
+                               e_util_free_nullable_object_slist (new_components);
                        }
                } else if (!is_declined) {
-                       ECalComponent *new_component = NULL;
+                       GSList *new_components = NULL;
+                       GSList new_objs = {0,};
 
-                       do_create_object (cbdav, new_obj_str, NULL, &new_component, &err);
+                       new_objs.data = new_obj_str;
+
+                       do_create_objects (cbdav, &new_objs, NULL, &new_components, &err);
 
                        if (!err) {
-                               e_cal_backend_notify_component_created (backend, new_component);
+                               if (new_components && new_components->data)
+                                       e_cal_backend_notify_component_created (backend, new_components->data);
                        }
 
-                       if (new_component)
-                               g_object_unref (new_component);
-
+                       e_util_free_nullable_object_slist (new_components);
                }
                break;
        case ICAL_METHOD_CANCEL:
                if (is_in_cache) {
-                       ECalComponent *new_component = NULL, *old_component = NULL;
-
-                       do_remove_object (cbdav, id->uid, id->rid, CALOBJ_MOD_THIS, &old_component, &new_component, &err);
-                       if (!err) {
-                               if (new_component) {
-                                       e_cal_backend_notify_component_modified (backend, old_component, new_component);
+                       GSList *new_components = NULL, *old_components = NULL;
+                       GSList ids = {0,};
+
+                       ids.data = id;
+                       do_remove_objects (cbdav, &ids, CALOBJ_MOD_THIS, &old_components, &new_components, &err);
+                       if (!err && old_components && old_components->data) {
+                               if (new_components && new_components->data) {
+                                       e_cal_backend_notify_component_modified (backend, old_components->data, new_components->data);
                                } else {
-                                       e_cal_backend_notify_component_removed (backend, id, old_component, NULL);
+                                       e_cal_backend_notify_component_removed (backend, id, old_components->data, NULL);
                                }
                        }
 
-                       if (new_component)
-                               g_object_unref (new_component);
-                       if (old_component)
-                               g_object_unref (old_component);
+                       e_util_free_nullable_object_slist (old_components);
+                       e_util_free_nullable_object_slist (new_components);
                } else {
                        err = EDC_ERROR (ObjectNotFound);
                }
@@ -4203,57 +4227,55 @@ _func_name _params                                                      \
 }
 
 caldav_busy_stub (
-        caldav_create_object,
+        caldav_create_objects,
                   (ECalBackendSync *backend,
                   EDataCal *cal,
                   GCancellable *cancellable,
-                  const gchar *in_calobj,
-                  gchar **uid,
-                  ECalComponent **new_component,
+                  const GSList *in_calobjs,
+                  GSList **uids,
+                  GSList **new_components,
                   GError **perror),
-        do_create_object,
+        do_create_objects,
                   (cbdav,
-                  in_calobj,
-                  uid,
-                  new_component,
+                  in_calobjs,
+                  uids,
+                  new_components,
                   perror))
 
 caldav_busy_stub (
-        caldav_modify_object,
+        caldav_modify_objects,
                   (ECalBackendSync *backend,
                   EDataCal *cal,
                   GCancellable *cancellable,
-                  const gchar *calobj,
+                  const GSList *calobjs,
                   CalObjModType mod,
-                  ECalComponent **old_component,
-                  ECalComponent **new_component,
+                  GSList **old_components,
+                  GSList **new_components,
                   GError **perror),
-        do_modify_object,
+        do_modify_objects,
                   (cbdav,
-                  calobj,
+                  calobjs,
                   mod,
-                  old_component,
-                  new_component,
+                  old_components,
+                  new_components,
                   perror))
 
 caldav_busy_stub (
-        caldav_remove_object,
+        caldav_remove_objects,
                   (ECalBackendSync *backend,
                   EDataCal *cal,
                   GCancellable *cancellable,
-                  const gchar *uid,
-                  const gchar *rid,
+                  const GSList *ids,
                   CalObjModType mod,
-                  ECalComponent **old_component,
-                  ECalComponent **new_component,
+                  GSList **old_components,
+                  GSList **new_components,
                   GError **perror),
-        do_remove_object,
+        do_remove_objects,
                   (cbdav,
-                  uid,
-                  rid,
+                  ids,
                   mod,
-                  old_component,
-                  new_component,
+                  old_components,
+                  new_components,
                   perror))
 
 caldav_busy_stub (
@@ -4862,9 +4884,9 @@ e_cal_backend_caldav_class_init (ECalBackendCalDAVClass *class)
        sync_class->refresh_sync                = caldav_refresh;
        sync_class->remove_sync                 = caldav_remove;
 
-       sync_class->create_object_sync          = caldav_create_object;
-       sync_class->modify_object_sync          = caldav_modify_object;
-       sync_class->remove_object_sync          = caldav_remove_object;
+       sync_class->create_objects_sync         = caldav_create_objects;
+       sync_class->modify_objects_sync         = caldav_modify_objects;
+       sync_class->remove_objects_sync         = caldav_remove_objects;
 
        sync_class->receive_objects_sync        = caldav_receive_objects;
        sync_class->send_objects_sync           = caldav_send_objects;
index f595ece..d0e19d7 100644 (file)
@@ -1582,13 +1582,13 @@ 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,
-                                      ECalComponent **new_component,
-                                      GError **perror)
+e_cal_backend_contacts_create_objects (ECalBackendSync *backend,
+                                       EDataCal *cal,
+                                       GCancellable *cancellable,
+                                       const GSList *calobjs,
+                                       GSList **uids,
+                                       GSList **new_components,
+                                       GError **perror)
 {
        g_propagate_error (perror, EDC_ERROR (PermissionDenied));
 }
@@ -1612,7 +1612,7 @@ e_cal_backend_contacts_class_init (ECalBackendContactsClass *class)
        sync_class->get_backend_property_sync   = e_cal_backend_contacts_get_backend_property;
        sync_class->open_sync                   = e_cal_backend_contacts_open;
        sync_class->remove_sync                 = e_cal_backend_contacts_remove;
-       sync_class->create_object_sync          = e_cal_backend_contacts_create_object;
+       sync_class->create_objects_sync         = e_cal_backend_contacts_create_objects;
        sync_class->receive_objects_sync        = e_cal_backend_contacts_receive_objects;
        sync_class->send_objects_sync           = e_cal_backend_contacts_send_objects;
        sync_class->get_object_sync             = e_cal_backend_contacts_get_object;
index 79f4c8b..b63aea9 100644 (file)
@@ -485,7 +485,10 @@ e_cal_backend_file_get_backend_property (ECalBackendSync *backend,
                                        CAL_STATIC_CAPABILITY_NO_THISANDFUTURE ","
                                        CAL_STATIC_CAPABILITY_DELEGATE_SUPPORTED ","
                                        CAL_STATIC_CAPABILITY_REMOVE_ONLY_THIS ","
-                                       CAL_STATIC_CAPABILITY_NO_THISANDPRIOR);
+                                       CAL_STATIC_CAPABILITY_NO_THISANDPRIOR ","
+                                       CAL_STATIC_CAPABILITY_BULK_ADDS ","
+                                       CAL_STATIC_CAPABILITY_BULK_MODIFIES ","
+                                       CAL_STATIC_CAPABILITY_BULK_REMOVES);
        } else if (g_str_equal (prop_name, CAL_BACKEND_PROPERTY_CAL_EMAIL_ADDRESS) ||
                   g_str_equal (prop_name, CAL_BACKEND_PROPERTY_ALARM_EMAIL_ADDRESS)) {
                /* A file backend has no particular email address associated
@@ -2242,96 +2245,125 @@ sanitize_component (ECalBackendFile *cbfile,
 }
 
 static void
-e_cal_backend_file_create_object (ECalBackendSync *backend,
-                                  EDataCal *cal,
-                                  GCancellable *cancellable,
-                                  const gchar *in_calobj,
-                                  gchar **uid,
-                                  ECalComponent **new_component,
-                                  GError **error)
+e_cal_backend_file_create_objects (ECalBackendSync *backend,
+                                   EDataCal *cal,
+                                   GCancellable *cancellable,
+                                   const GSList *in_calobjs,
+                                   GSList **uids,
+                                   GSList **new_components,
+                                   GError **error)
 {
        ECalBackendFile *cbfile;
        ECalBackendFilePrivate *priv;
-       icalcomponent *icalcomp;
-       ECalComponent *comp;
-       const gchar *comp_uid;
-       struct icaltimetype current;
+       GSList *icalcomps = NULL;
+       const GSList *l;
 
        cbfile = E_CAL_BACKEND_FILE (backend);
        priv = cbfile->priv;
 
        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_component != NULL, ObjectNotFound);
-
-       /* Parse the icalendar text */
-       icalcomp = icalparser_parse_string (in_calobj);
-       if (!icalcomp) {
-               g_propagate_error (error, EDC_ERROR (InvalidObject));
-               return;
-       }
+       e_return_data_cal_error_if_fail (in_calobjs != NULL, ObjectNotFound);
+       e_return_data_cal_error_if_fail (new_components != NULL, ObjectNotFound);
 
-       /* Check kind with the parent */
-       if (icalcomponent_isa (icalcomp) != e_cal_backend_get_kind (E_CAL_BACKEND (backend))) {
-               icalcomponent_free (icalcomp);
-               g_propagate_error (error, EDC_ERROR (InvalidObject));
-               return;
-       }
+       if (uids)
+               *uids = NULL;
 
        g_static_rec_mutex_lock (&priv->idle_save_rmutex);
 
-       /* Get the UID */
-       comp_uid = icalcomponent_get_uid (icalcomp);
-       if (!comp_uid) {
-               gchar *new_uid;
+       /* First step, parse input strings and do uid verification: may fail */
+       for (l = in_calobjs; l; l = l->next) {
+               icalcomponent *icalcomp;
+               const gchar *comp_uid;
 
-               new_uid = e_cal_component_gen_uid ();
-               if (!new_uid) {
-                       icalcomponent_free (icalcomp);
+               /* Parse the icalendar text */
+               icalcomp = icalparser_parse_string ((gchar *) l->data);
+               if (!icalcomp) {
+                       g_slist_free_full (icalcomps, (GDestroyNotify) icalcomponent_free);
+                       g_static_rec_mutex_unlock (&priv->idle_save_rmutex);
+                       g_propagate_error (error, EDC_ERROR (InvalidObject));
+                       return;
+               }
+
+               /* Append icalcomponent to icalcomps */
+               icalcomps = g_slist_prepend (icalcomps, icalcomp);
+
+               /* Check kind with the parent */
+               if (icalcomponent_isa (icalcomp) != e_cal_backend_get_kind (E_CAL_BACKEND (backend))) {
+                       g_slist_free_full (icalcomps, (GDestroyNotify) icalcomponent_free);
                        g_static_rec_mutex_unlock (&priv->idle_save_rmutex);
                        g_propagate_error (error, EDC_ERROR (InvalidObject));
                        return;
                }
 
-               icalcomponent_set_uid (icalcomp, new_uid);
+               /* Get the UID */
                comp_uid = icalcomponent_get_uid (icalcomp);
+               if (!comp_uid) {
+                       gchar *new_uid;
 
-               g_free (new_uid);
-       }
+                       new_uid = e_cal_component_gen_uid ();
+                       if (!new_uid) {
+                               g_slist_free_full (icalcomps, (GDestroyNotify) icalcomponent_free);
+                               g_static_rec_mutex_unlock (&priv->idle_save_rmutex);
+                               g_propagate_error (error, EDC_ERROR (InvalidObject));
+                               return;
+                       }
 
-       /* check the object is not in our cache */
-       if (uid_in_use (cbfile, comp_uid)) {
-               icalcomponent_free (icalcomp);
-               g_static_rec_mutex_unlock (&priv->idle_save_rmutex);
-               g_propagate_error (error, EDC_ERROR (ObjectIdAlreadyExists));
-               return;
+                       icalcomponent_set_uid (icalcomp, new_uid);
+                       comp_uid = icalcomponent_get_uid (icalcomp);
+
+                       g_free (new_uid);
+               }
+
+               /* check that the object is not in our cache */
+               if (uid_in_use (cbfile, comp_uid)) {
+                       g_slist_free_full (icalcomps, (GDestroyNotify) icalcomponent_free);
+                       g_static_rec_mutex_unlock (&priv->idle_save_rmutex);
+                       g_propagate_error (error, EDC_ERROR (ObjectIdAlreadyExists));
+                       return;
+               }
        }
 
-       /* Create the cal component */
-       comp = e_cal_component_new ();
-       e_cal_component_set_icalcomponent (comp, icalcomp);
+       icalcomps = g_slist_reverse (icalcomps);
+
+       /* Second step, add the objects */
+       for (l = icalcomps; l; l = l->next) {
+               ECalComponent *comp;
+               struct icaltimetype current;
+               icalcomponent *icalcomp = l->data;
+
+               /* Create the cal component */
+               comp = e_cal_component_new ();
+               e_cal_component_set_icalcomponent (comp, icalcomp);
+
+               /* Set the created and last modified times on the component */
+               current = icaltime_current_time_with_zone (icaltimezone_get_utc_timezone ());
+               e_cal_component_set_created (comp, &current);
+               e_cal_component_set_last_modified (comp, &current);
+
+               /* sanitize the component*/
+               sanitize_component (cbfile, comp);
+
+               /* Add the object */
+               add_component (cbfile, comp, TRUE);
 
-       /* Set the created and last modified times on the component */
-       current = icaltime_current_time_with_zone (icaltimezone_get_utc_timezone ());
-       e_cal_component_set_created (comp, &current);
-       e_cal_component_set_last_modified (comp, &current);
+               /* Keep the UID and the modified component to return them later */
+               if (uids)
+                       *uids = g_slist_prepend (*uids, g_strdup (icalcomponent_get_uid (icalcomp)));
 
-       /* sanitize the component*/
-       sanitize_component (cbfile, comp);
+               *new_components = g_slist_prepend (*new_components, e_cal_component_clone (comp));
+       }
 
-       /* Add the object */
-       add_component (cbfile, comp, TRUE);
+       g_slist_free (icalcomps);
 
        /* Save the file */
        save (cbfile, TRUE);
 
-       /* Return the UID and the modified component */
-       if (uid)
-               *uid = g_strdup (comp_uid);
+       g_static_rec_mutex_unlock (&priv->idle_save_rmutex);
 
-       *new_component = e_cal_component_clone (comp);
+       if (uids)
+               *uids = g_slist_reverse (*uids);
 
-       g_static_rec_mutex_unlock (&priv->idle_save_rmutex);
+       *new_components = g_slist_reverse (*new_components);
 }
 
 typedef struct {
@@ -2371,32 +2403,25 @@ remove_object_instance_cb (gpointer key,
 }
 
 static void
-e_cal_backend_file_modify_object (ECalBackendSync *backend,
-                                  EDataCal *cal,
-                                  GCancellable *cancellable,
-                                  const gchar *calobj,
-                                  CalObjModType mod,
-                                  ECalComponent **old_component,
-                                  ECalComponent **new_component,
-                                  GError **error)
+e_cal_backend_file_modify_objects (ECalBackendSync *backend,
+                                   EDataCal *cal,
+                                   GCancellable *cancellable,
+                                   const GSList *calobjs,
+                                   CalObjModType mod,
+                                   GSList **old_components,
+                                   GSList **new_components,
+                                   GError **error)
 {
-       RemoveRecurrenceData rrdata;
        ECalBackendFile *cbfile;
        ECalBackendFilePrivate *priv;
-       icalcomponent *icalcomp;
-       const gchar *comp_uid;
-       gchar *rid = NULL;
-       gchar *real_rid;
-       ECalComponent *comp, *recurrence;
-       ECalBackendFileObject *obj_data;
-       struct icaltimetype current;
-       GList *detached = NULL;
+       GSList *icalcomps = NULL;
+       const GSList *l;
 
        cbfile = E_CAL_BACKEND_FILE (backend);
        priv = cbfile->priv;
 
        e_return_data_cal_error_if_fail (priv->icalcomp != NULL, NoSuchCal);
-       e_return_data_cal_error_if_fail (calobj != NULL, ObjectNotFound);
+       e_return_data_cal_error_if_fail (calobjs != NULL, ObjectNotFound);
        switch (mod) {
        case CALOBJ_MOD_THIS:
        case CALOBJ_MOD_THISANDPRIOR:
@@ -2408,226 +2433,251 @@ e_cal_backend_file_modify_object (ECalBackendSync *backend,
                return;
        }
 
-       /* Parse the icalendar text */
-       icalcomp = icalparser_parse_string ((gchar *) calobj);
-       if (!icalcomp) {
-               g_propagate_error (error, EDC_ERROR (InvalidObject));
-               return;
-       }
-
-       /* Check kind with the parent */
-       if (icalcomponent_isa (icalcomp) != e_cal_backend_get_kind (E_CAL_BACKEND (backend))) {
-               icalcomponent_free (icalcomp);
-               g_propagate_error (error, EDC_ERROR (InvalidObject));
-               return;
-       }
+       if (old_components)
+               *old_components = NULL;
+       if (new_components)
+               *new_components = NULL;
 
        g_static_rec_mutex_lock (&priv->idle_save_rmutex);
 
-       /* Get the uid */
-       comp_uid = icalcomponent_get_uid (icalcomp);
+       /* First step, parse input strings and do uid verification: may fail */
+       for (l = calobjs; l; l = l->next) {
+               const gchar *comp_uid;
+               icalcomponent *icalcomp;
 
-       /* Get the object from our cache */
-       if (!(obj_data = g_hash_table_lookup (priv->comp_uid_hash, comp_uid))) {
-               icalcomponent_free (icalcomp);
-               g_static_rec_mutex_unlock (&priv->idle_save_rmutex);
-               g_propagate_error (error, EDC_ERROR (ObjectNotFound));
-               return;
-       }
+               /* Parse the icalendar text */
+               icalcomp = icalparser_parse_string (l->data);
+               if (!icalcomp) {
+                       g_slist_free_full (icalcomps, (GDestroyNotify) icalcomponent_free);
+                       g_static_rec_mutex_unlock (&priv->idle_save_rmutex);
+                       g_propagate_error (error, EDC_ERROR (InvalidObject));
+                       return;
+               }
 
-       /* Create the cal component */
-       comp = e_cal_component_new ();
-       e_cal_component_set_icalcomponent (comp, icalcomp);
+               icalcomps = g_slist_prepend (icalcomps, icalcomp);
 
-       /* Set the last modified time on the component */
-       current = icaltime_current_time_with_zone (icaltimezone_get_utc_timezone ());
-       e_cal_component_set_last_modified (comp, &current);
+               /* Check kind with the parent */
+               if (icalcomponent_isa (icalcomp) != e_cal_backend_get_kind (E_CAL_BACKEND (backend))) {
+                       g_slist_free_full (icalcomps, (GDestroyNotify) icalcomponent_free);
+                       g_static_rec_mutex_unlock (&priv->idle_save_rmutex);
+                       g_propagate_error (error, EDC_ERROR (InvalidObject));
+                       return;
+               }
 
-       /* sanitize the component*/
-       sanitize_component (cbfile, comp);
-       rid = e_cal_component_get_recurid_as_string (comp);
+               /* Get the uid */
+               comp_uid = icalcomponent_get_uid (icalcomp);
 
-       /* handle mod_type */
-       switch (mod) {
-       case CALOBJ_MOD_THIS :
-               if (!rid || !*rid) {
-                       if (old_component && obj_data->full_object) {
-                               *old_component = e_cal_component_clone (obj_data->full_object);
-                       }
+               /* Get the object from our cache */
+               if (!g_hash_table_lookup (priv->comp_uid_hash, comp_uid)) {
+                       g_slist_free_full (icalcomps, (GDestroyNotify) icalcomponent_free);
+                       g_static_rec_mutex_unlock (&priv->idle_save_rmutex);
+                       g_propagate_error (error, EDC_ERROR (ObjectNotFound));
+                       return;
+               }
+       }
 
-                       /* replace only the full object */
-                       if (obj_data->full_object) {
-                               icalcomponent_remove_component (priv->icalcomp,
-                                                       e_cal_component_get_icalcomponent (obj_data->full_object));
-                               priv->comp = g_list_remove (priv->comp, obj_data->full_object);
+       icalcomps = g_slist_reverse (icalcomps);
 
-                               g_object_unref (obj_data->full_object);
-                       }
+       /* Second step, update the objects */
+       for (l = icalcomps; l; l = l->next) {
+               struct icaltimetype current;
+               RemoveRecurrenceData rrdata;
+               GList *detached = NULL;
+               gchar *rid = NULL;
+               gchar *real_rid;
+               const gchar *comp_uid;
+               icalcomponent * icalcomp = l->data;
+               ECalComponent *comp, *recurrence;
+               ECalBackendFileObject *obj_data;
 
-                       /* add the new object */
-                       obj_data->full_object = comp;
+               comp_uid = icalcomponent_get_uid (icalcomp);
+               obj_data = g_hash_table_lookup (priv->comp_uid_hash, comp_uid);
 
-                       icalcomponent_add_component (priv->icalcomp,
-                                                    e_cal_component_get_icalcomponent (obj_data->full_object));
-                       priv->comp = g_list_prepend (priv->comp, obj_data->full_object);
+               /* Create the cal component */
+               comp = e_cal_component_new ();
+               e_cal_component_set_icalcomponent (comp, icalcomp);
 
-                       save (cbfile, TRUE);
+               /* Set the last modified time on the component */
+               current = icaltime_current_time_with_zone (icaltimezone_get_utc_timezone ());
+               e_cal_component_set_last_modified (comp, &current);
 
-                       if (new_component) {
-                               *new_component = e_cal_component_clone (comp);
-                       }
+               /* sanitize the component*/
+               sanitize_component (cbfile, comp);
+               rid = e_cal_component_get_recurid_as_string (comp);
 
-                       g_static_rec_mutex_unlock (&priv->idle_save_rmutex);
-                       g_free (rid);
-                       return;
-               }
+               /* handle mod_type */
+               switch (mod) {
+               case CALOBJ_MOD_THIS :
+                       if (!rid || !*rid) {
+                               if (old_components)
+                                       *old_components = g_slist_prepend (*old_components, obj_data->full_object ? e_cal_component_clone (obj_data->full_object) : NULL);
 
-               if (g_hash_table_lookup_extended (obj_data->recurrences, rid, (gpointer *) &real_rid, (gpointer *) &recurrence)) {
-                       if (old_component) {
-                               *old_component = e_cal_component_clone (recurrence);
-                       }
+                               /* replace only the full object */
+                               if (obj_data->full_object) {
+                                       icalcomponent_remove_component (priv->icalcomp,
+                                                               e_cal_component_get_icalcomponent (obj_data->full_object));
+                                       priv->comp = g_list_remove (priv->comp, obj_data->full_object);
 
-                       /* remove the component from our data */
-                       icalcomponent_remove_component (priv->icalcomp,
-                                                       e_cal_component_get_icalcomponent (recurrence));
-                       priv->comp = g_list_remove (priv->comp, recurrence);
-                       obj_data->recurrences_list = g_list_remove (obj_data->recurrences_list, recurrence);
-                       g_hash_table_remove (obj_data->recurrences, rid);
-               }
+                                       g_object_unref (obj_data->full_object);
+                               }
 
-               /* add the detached instance */
-               g_hash_table_insert (obj_data->recurrences,
-                                    rid,
-                                    comp);
-               icalcomponent_add_component (priv->icalcomp,
-                                            e_cal_component_get_icalcomponent (comp));
-               priv->comp = g_list_append (priv->comp, comp);
-               obj_data->recurrences_list = g_list_append (obj_data->recurrences_list, comp);
-               rid = NULL;
-               break;
-       case CALOBJ_MOD_THISANDPRIOR :
-       case CALOBJ_MOD_THISANDFUTURE :
-               if (!rid || !*rid) {
+                               /* add the new object */
+                               obj_data->full_object = comp;
 
-                       if (old_component && obj_data->full_object) {
-                               *old_component = e_cal_component_clone (obj_data->full_object);
+                               icalcomponent_add_component (priv->icalcomp,
+                                                                e_cal_component_get_icalcomponent (obj_data->full_object));
+                               priv->comp = g_list_prepend (priv->comp, obj_data->full_object);
+                               break;
                        }
 
-                       remove_component (cbfile, comp_uid, obj_data);
+                       if (g_hash_table_lookup_extended (obj_data->recurrences, rid, (gpointer *) &real_rid, (gpointer *) &recurrence)) {
+                               if (*old_components)
+                                       *old_components = g_slist_prepend (*old_components, e_cal_component_clone (recurrence));
 
-                       /* Add the new object */
-                       add_component (cbfile, comp, TRUE);
-                       g_free (rid);
-                       rid = NULL;
+                               /* remove the component from our data */
+                               icalcomponent_remove_component (priv->icalcomp,
+                                                               e_cal_component_get_icalcomponent (recurrence));
+                               priv->comp = g_list_remove (priv->comp, recurrence);
+                               obj_data->recurrences_list = g_list_remove (obj_data->recurrences_list, recurrence);
+                               g_hash_table_remove (obj_data->recurrences, rid);
+                       } else {
+                               if (old_components)
+                                       *old_components = g_slist_prepend (*old_components, NULL);
+                       }
+
+                       /* add the detached instance */
+                       g_hash_table_insert (obj_data->recurrences,
+                                                g_strdup (rid),
+                                                comp);
+                       icalcomponent_add_component (priv->icalcomp,
+                                                        e_cal_component_get_icalcomponent (comp));
+                       priv->comp = g_list_append (priv->comp, comp);
+                       obj_data->recurrences_list = g_list_append (obj_data->recurrences_list, comp);
                        break;
-               }
+               case CALOBJ_MOD_THISANDPRIOR :
+               case CALOBJ_MOD_THISANDFUTURE :
+                       if (!rid || !*rid) {
+                               if (old_components)
+                                       *old_components = g_slist_prepend (*old_components, obj_data->full_object ? e_cal_component_clone (obj_data->full_object) : NULL);
 
-               /* remove the component from our data, temporarily */
-               if (obj_data->full_object) {
-                       icalcomponent_remove_component (priv->icalcomp,
-                                               e_cal_component_get_icalcomponent (obj_data->full_object));
-                       priv->comp = g_list_remove (priv->comp, obj_data->full_object);
-               }
+                               remove_component (cbfile, comp_uid, obj_data);
 
-               /* now deal with the detached recurrence */
-               if (g_hash_table_lookup_extended (obj_data->recurrences, rid,
-                                                 (gpointer *) &real_rid, (gpointer *) &recurrence)) {
+                               /* Add the new object */
+                               add_component (cbfile, comp, TRUE);
+                               break;
+                       }
 
-                       if (old_component) {
-                               *old_component = e_cal_component_clone (recurrence);
+                       /* remove the component from our data, temporarily */
+                       if (obj_data->full_object) {
+                               icalcomponent_remove_component (priv->icalcomp,
+                                                       e_cal_component_get_icalcomponent (obj_data->full_object));
+                               priv->comp = g_list_remove (priv->comp, obj_data->full_object);
                        }
 
-                       /* remove the component from our data */
-                       icalcomponent_remove_component (priv->icalcomp,
-                                                       e_cal_component_get_icalcomponent (recurrence));
-                       priv->comp = g_list_remove (priv->comp, recurrence);
-                       obj_data->recurrences_list = g_list_remove (obj_data->recurrences_list, recurrence);
-                       g_hash_table_remove (obj_data->recurrences, rid);
-               } else {
+                       /* now deal with the detached recurrence */
+                       if (g_hash_table_lookup_extended (obj_data->recurrences, rid,
+                                                         (gpointer *) &real_rid, (gpointer *) &recurrence)) {
+                               if (old_components)
+                                       *old_components = g_slist_prepend (*old_components, e_cal_component_clone (recurrence));
 
-                       if (old_component && obj_data->full_object) {
-                               *old_component = e_cal_component_clone (obj_data->full_object);
+                               /* remove the component from our data */
+                               icalcomponent_remove_component (priv->icalcomp,
+                                                               e_cal_component_get_icalcomponent (recurrence));
+                               priv->comp = g_list_remove (priv->comp, recurrence);
+                               obj_data->recurrences_list = g_list_remove (obj_data->recurrences_list, recurrence);
+                               g_hash_table_remove (obj_data->recurrences, rid);
+                       } else {
+                               if (*old_components)
+                                       *old_components = g_slist_prepend (*old_components, obj_data->full_object ? e_cal_component_clone (obj_data->full_object) : NULL);
                        }
-               }
 
-               rrdata.cbfile = cbfile;
-               rrdata.obj_data = obj_data;
-               rrdata.rid = rid;
-               rrdata.mod = mod;
-               g_hash_table_foreach_remove (obj_data->recurrences, (GHRFunc) remove_object_instance_cb, &rrdata);
+                       rrdata.cbfile = cbfile;
+                       rrdata.obj_data = obj_data;
+                       rrdata.rid = rid;
+                       rrdata.mod = mod;
+                       g_hash_table_foreach_remove (obj_data->recurrences, (GHRFunc) remove_object_instance_cb, &rrdata);
 
-               /* add the modified object to the beginning of the list,
-                * so that it's always before any detached instance we
-                * might have */
-               if (obj_data->full_object) {
-                       icalcomponent_add_component (priv->icalcomp,
-                                            e_cal_component_get_icalcomponent (obj_data->full_object));
-                       priv->comp = g_list_prepend (priv->comp, obj_data->full_object);
-               }
+                       /* add the modified object to the beginning of the list,
+                        * so that it's always before any detached instance we
+                        * might have */
+                       if (obj_data->full_object) {
+                               icalcomponent_add_component (priv->icalcomp,
+                                                        e_cal_component_get_icalcomponent (obj_data->full_object));
+                               priv->comp = g_list_prepend (priv->comp, obj_data->full_object);
+                       }
 
-               /* add the new detached recurrence */
-               g_hash_table_insert (obj_data->recurrences,
-                                    rid,
-                                    comp);
-               icalcomponent_add_component (priv->icalcomp,
-                                            e_cal_component_get_icalcomponent (comp));
-               priv->comp = g_list_append (priv->comp, comp);
-               obj_data->recurrences_list = g_list_append (obj_data->recurrences_list, comp);
-               rid = NULL;
-               break;
-       case CALOBJ_MOD_ALL :
-               /* Remove the old version */
-               if (old_component && obj_data->full_object) {
-                       *old_component = e_cal_component_clone (obj_data->full_object);
-               }
+                       /* add the new detached recurrence */
+                       g_hash_table_insert (obj_data->recurrences,
+                                                g_strdup (rid),
+                                                comp);
+                       icalcomponent_add_component (priv->icalcomp,
+                                                        e_cal_component_get_icalcomponent (comp));
+                       priv->comp = g_list_append (priv->comp, comp);
+                       obj_data->recurrences_list = g_list_append (obj_data->recurrences_list, comp);
+                       break;
+               case CALOBJ_MOD_ALL :
+                       /* Remove the old version */
+                       if (old_components)
+                               *old_components = g_slist_prepend (*old_components, obj_data->full_object ? e_cal_component_clone (obj_data->full_object) : NULL);
 
-               if (obj_data->recurrences_list) {
-                       /* has detached components, preserve them */
-                       GList *l;
+                       if (obj_data->recurrences_list) {
+                               /* has detached components, preserve them */
+                               GList *ll;
 
-                       for (l = obj_data->recurrences_list; l; l = l->next) {
-                               detached = g_list_prepend (detached, g_object_ref (l->data));
+                               for (ll = obj_data->recurrences_list; ll; ll = ll->next) {
+                                       detached = g_list_prepend (detached, g_object_ref (ll->data));
+                               }
                        }
-               }
 
-               remove_component (cbfile, comp_uid, obj_data);
+                       remove_component (cbfile, comp_uid, obj_data);
 
-               /* Add the new object */
-               add_component (cbfile, comp, TRUE);
+                       /* Add the new object */
+                       add_component (cbfile, comp, TRUE);
 
-               if (detached) {
-                       /* it had some detached components, place them back */
-                       comp_uid = icalcomponent_get_uid (e_cal_component_get_icalcomponent (comp));
+                       if (detached) {
+                               /* it had some detached components, place them back */
+                               comp_uid = icalcomponent_get_uid (e_cal_component_get_icalcomponent (comp));
 
-                       if ((obj_data = g_hash_table_lookup (priv->comp_uid_hash, comp_uid)) != NULL) {
-                               GList *l;
+                               if ((obj_data = g_hash_table_lookup (priv->comp_uid_hash, comp_uid)) != NULL) {
+                                       GList *ll;
 
-                               for (l = detached; l; l = l->next) {
-                                       ECalComponent *c = l->data;
+                                       for (ll = detached; ll; ll = ll->next) {
+                                               ECalComponent *c = ll->data;
 
-                                       g_hash_table_insert (obj_data->recurrences, e_cal_component_get_recurid_as_string (c), c);
-                                       icalcomponent_add_component (priv->icalcomp, e_cal_component_get_icalcomponent (c));
-                                       priv->comp = g_list_append (priv->comp, c);
-                                       obj_data->recurrences_list = g_list_append (obj_data->recurrences_list, c);
+                                               g_hash_table_insert (obj_data->recurrences, e_cal_component_get_recurid_as_string (c), c);
+                                               icalcomponent_add_component (priv->icalcomp, e_cal_component_get_icalcomponent (c));
+                                               priv->comp = g_list_append (priv->comp, c);
+                                               obj_data->recurrences_list = g_list_append (obj_data->recurrences_list, c);
+                                       }
                                }
+
+                               g_list_free (detached);
                        }
+                       break;
+               case CALOBJ_MOD_ONLY_THIS:
+                       /* not reached, keep compiler happy */
+                       break;
+               }
 
-                       g_list_free (detached);
+               g_free (rid);
+
+               if (new_components) {
+                       *new_components = g_slist_prepend (*new_components, e_cal_component_clone (comp));
                }
-               break;
-       case CALOBJ_MOD_ONLY_THIS:
-               /* not reached, keep compiler happy */
-               break;
        }
 
-       save (cbfile, TRUE);
-       g_free (rid);
+       g_slist_free (icalcomps);
 
-       if (new_component) {
-               *new_component = e_cal_component_clone (comp);
-       }
+       /* All the components were updated, now we save the file */
+       save (cbfile, TRUE);
 
        g_static_rec_mutex_unlock (&priv->idle_save_rmutex);
+
+       if (old_components)
+               *old_components = g_slist_reverse (*old_components);
+
+       if (new_components)
+               *new_components = g_slist_reverse (*new_components);
 }
 
 /**
@@ -2824,28 +2874,26 @@ notify_comp_removed_cb (gpointer pecalcomp,
 
 /* Remove_object handler for the file backend */
 static void
-e_cal_backend_file_remove_object (ECalBackendSync *backend,
-                                  EDataCal *cal,
-                                  GCancellable *cancellable,
-                                  const gchar *uid,
-                                  const gchar *rid,
-                                  CalObjModType mod,
-                                  ECalComponent **old_component,
-                                  ECalComponent **new_component,
-                                  GError **error)
+e_cal_backend_file_remove_objects (ECalBackendSync *backend,
+                                   EDataCal *cal,
+                                   GCancellable *cancellable,
+                                   const GSList *ids,
+                                   CalObjModType mod,
+                                   GSList **old_components,
+                                   GSList **new_components,
+                                   GError **error)
 {
        ECalBackendFile *cbfile;
        ECalBackendFilePrivate *priv;
-       ECalBackendFileObject *obj_data;
-       ECalComponent *comp;
-       RemoveRecurrenceData rrdata;
-       const gchar *recur_id = NULL;
+       const GSList *l;
 
        cbfile = E_CAL_BACKEND_FILE (backend);
        priv = cbfile->priv;
 
        e_return_data_cal_error_if_fail (priv->icalcomp != NULL, NoSuchCal);
-       e_return_data_cal_error_if_fail (uid != NULL, ObjectNotFound);
+       e_return_data_cal_error_if_fail (ids != NULL, ObjectNotFound);
+       e_return_data_cal_error_if_fail (old_components != NULL, ObjectNotFound);
+       e_return_data_cal_error_if_fail (new_components != NULL, ObjectNotFound);
 
        switch (mod) {
        case CALOBJ_MOD_THIS:
@@ -2859,78 +2907,115 @@ e_cal_backend_file_remove_object (ECalBackendSync *backend,
                return;
        }
 
-       *old_component = *new_component = NULL;
+       *old_components = *new_components = NULL;
 
        g_static_rec_mutex_lock (&priv->idle_save_rmutex);
 
-       obj_data = g_hash_table_lookup (priv->comp_uid_hash, uid);
-       if (!obj_data) {
-               g_static_rec_mutex_unlock (&priv->idle_save_rmutex);
-               g_propagate_error (error, EDC_ERROR (ObjectNotFound));
-               return;
+       /* First step, validate the input */
+       for (l = ids; l; l = l->next) {
+               ECalComponentId *id = l->data;
+                               /* Make the ID contains a uid */
+               if (!id || !id->uid) {
+                       g_static_rec_mutex_unlock (&priv->idle_save_rmutex);
+                       g_propagate_error (error, EDC_ERROR (ObjectNotFound));
+                       return;
+               }
+                               /* Check that it has a recurrence id if mod is CALOBJ_MOD_THISANDPRIOR
+                                        or CALOBJ_MOD_THISANDFUTURE */
+               if ((mod == CALOBJ_MOD_THISANDPRIOR || mod == CALOBJ_MOD_THISANDFUTURE) &&
+                       (!id->rid || !*(id->rid))) {
+                       g_static_rec_mutex_unlock (&priv->idle_save_rmutex);
+                       g_propagate_error (error, EDC_ERROR (ObjectNotFound));
+                       return;
+               }
+                               /* Make sure the uid exists in the local hash table */
+               if (!g_hash_table_lookup (priv->comp_uid_hash, id->uid)) {
+                       g_static_rec_mutex_unlock (&priv->idle_save_rmutex);
+                       g_propagate_error (error, EDC_ERROR (ObjectNotFound));
+                       return;
+               }
        }
 
-       if (rid && *rid)
-               recur_id = rid;
+       /* Second step, remove objects from the calendar */
+       for (l = ids; l; l = l->next) {
+               const gchar *recur_id = NULL;
+               ECalComponent *comp;
+               RemoveRecurrenceData rrdata;
+               ECalBackendFileObject *obj_data;
+               ECalComponentId *id = l->data;
 
-       switch (mod) {
-       case CALOBJ_MOD_ALL :
-               *old_component = clone_ecalcomp_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);
+               obj_data = g_hash_table_lookup (priv->comp_uid_hash, id->uid);
 
-               *new_component = NULL;
-               break;
-       case CALOBJ_MOD_ONLY_THIS:
-       case CALOBJ_MOD_THIS :
-               remove_instance (cbfile, obj_data, uid, recur_id, mod,
-                                old_component, new_component, error);
-               break;
-       case CALOBJ_MOD_THISANDPRIOR :
-       case CALOBJ_MOD_THISANDFUTURE :
-               comp = obj_data->full_object;
+               if (id->rid && *(id->rid))
+                       recur_id = id->rid;
 
-               if (!recur_id || !*recur_id) {
-                       g_static_rec_mutex_unlock (&priv->idle_save_rmutex);
-                       g_propagate_error (error, EDC_ERROR (ObjectNotFound));
-                       return;
-               }
+               switch (mod) {
+               case CALOBJ_MOD_ALL :
+                       *old_components = g_slist_prepend (*old_components, clone_ecalcomp_from_fileobject (obj_data, recur_id));
+                       *new_components = g_slist_prepend (*new_components, NULL);
 
-               if (comp) {
-                       *old_component = e_cal_component_clone (comp);
+                       if (obj_data->recurrences_list)
+                               g_list_foreach (obj_data->recurrences_list, notify_comp_removed_cb, cbfile);
+                       remove_component (cbfile, id->uid, obj_data);
+                       break;
+               case CALOBJ_MOD_ONLY_THIS:
+               case CALOBJ_MOD_THIS: {
+                       ECalComponent *old_component = NULL;
+                       ECalComponent *new_component = NULL;
 
-                       /* remove the component from our data, temporarily */
-                       icalcomponent_remove_component (priv->icalcomp,
-                                               e_cal_component_get_icalcomponent (comp));
-                       priv->comp = g_list_remove (priv->comp, comp);
+                       obj_data = remove_instance (cbfile, obj_data, id->uid, recur_id, mod,
+                                                       &old_component, &new_component, error);
 
-                       e_cal_util_remove_instances (e_cal_component_get_icalcomponent (comp),
-                                            icaltime_from_string (recur_id), mod);
+                       *old_components = g_slist_prepend (*old_components, old_component);
+                       *new_components = g_slist_prepend (*new_components, new_component);
+                       break;
                }
+               case CALOBJ_MOD_THISANDPRIOR :
+               case CALOBJ_MOD_THISANDFUTURE :
+                       comp = obj_data->full_object;
 
-               /* now remove all detached instances */
-               rrdata.cbfile = cbfile;
-               rrdata.obj_data = obj_data;
-               rrdata.rid = recur_id;
-               rrdata.mod = mod;
-               g_hash_table_foreach_remove (obj_data->recurrences, (GHRFunc) remove_object_instance_cb, &rrdata);
+                       if (comp) {
+                               *old_components = g_slist_prepend (*old_components, e_cal_component_clone (comp));
 
-               /* add the modified object to the beginning of the list,
-                * so that it's always before any detached instance we
-                * might have */
-               if (comp)
-                       priv->comp = g_list_prepend (priv->comp, comp);
+                               /* remove the component from our data, temporarily */
+                               icalcomponent_remove_component (priv->icalcomp,
+                                                       e_cal_component_get_icalcomponent (comp));
+                               priv->comp = g_list_remove (priv->comp, comp);
 
-               if (obj_data->full_object) {
-                       *new_component = e_cal_component_clone (obj_data->full_object);
+                               e_cal_util_remove_instances (e_cal_component_get_icalcomponent (comp),
+                                                        icaltime_from_string (recur_id), mod);
+                       } else {
+                               *old_components = g_slist_prepend (*old_components, NULL);
+                       }
+
+                       /* now remove all detached instances */
+                       rrdata.cbfile = cbfile;
+                       rrdata.obj_data = obj_data;
+                       rrdata.rid = recur_id;
+                       rrdata.mod = mod;
+                       g_hash_table_foreach_remove (obj_data->recurrences, (GHRFunc) remove_object_instance_cb, &rrdata);
+
+                       /* add the modified object to the beginning of the list,
+                        * so that it's always before any detached instance we
+                        * might have */
+                       if (comp)
+                               priv->comp = g_list_prepend (priv->comp, comp);
+
+                       if (obj_data->full_object) {
+                               *new_components = g_slist_prepend (*new_components, e_cal_component_clone (obj_data->full_object));
+                       } else {
+                               *new_components = g_slist_prepend (*new_components, NULL);
+                       }
+                       break;
                }
-               break;
        }
 
        save (cbfile, TRUE);
 
        g_static_rec_mutex_unlock (&priv->idle_save_rmutex);
+
+       *old_components = g_slist_reverse (*old_components);
+       *new_components = g_slist_reverse (*new_components);
 }
 
 static gboolean
@@ -3443,9 +3528,9 @@ e_cal_backend_file_class_init (ECalBackendFileClass *class)
        sync_class->get_backend_property_sync   = e_cal_backend_file_get_backend_property;
        sync_class->open_sync                   = e_cal_backend_file_open;
        sync_class->remove_sync                 = e_cal_backend_file_remove;
-       sync_class->create_object_sync          = e_cal_backend_file_create_object;
-       sync_class->modify_object_sync          = e_cal_backend_file_modify_object;
-       sync_class->remove_object_sync          = e_cal_backend_file_remove_object;
+       sync_class->create_objects_sync         = e_cal_backend_file_create_objects;
+       sync_class->modify_objects_sync         = e_cal_backend_file_modify_objects;
+       sync_class->remove_objects_sync         = e_cal_backend_file_remove_objects;
        sync_class->receive_objects_sync        = e_cal_backend_file_receive_objects;
        sync_class->send_objects_sync           = e_cal_backend_file_send_objects;
        sync_class->get_object_sync             = e_cal_backend_file_get_object;
index d120ce4..66a7e15 100644 (file)
@@ -1261,43 +1261,42 @@ 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,
-                                  ECalComponent **new_component,
-                                  GError **perror)
+e_cal_backend_http_create_objects (ECalBackendSync *backend,
+                                   EDataCal *cal,
+                                   GCancellable *cancellable,
+                                   const GSList *calobjs,
+                                   GSList **uids,
+                                   GSList **new_components,
+                                   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,
-                                  ECalComponent **old_component,
-                                  ECalComponent **new_component,
-                                  GError **perror)
+e_cal_backend_http_modify_objects (ECalBackendSync *backend,
+                                   EDataCal *cal,
+                                   GCancellable *cancellable,
+                                   const GSList *calobjs,
+                                   CalObjModType mod,
+                                   GSList **old_components,
+                                   GSList **new_components,
+                                   GError **perror)
 {
        g_propagate_error (perror, EDC_ERROR (PermissionDenied));
 }
 
-/* Remove_object handler for the file backend */
+/* Remove_objects 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,
-                                  ECalComponent **old_component,
-                                  ECalComponent **new_component,
-                                  GError **perror)
+e_cal_backend_http_remove_objects (ECalBackendSync *backend,
+                                   EDataCal *cal,
+                                   GCancellable *cancellable,
+                                   const GSList *ids,
+                                   CalObjModType mod,
+                                   GSList **old_components,
+                                   GSList **new_components,
+                                   GError **perror)
 {
-       *old_component = *new_component = NULL;
+       *old_components = *new_components = NULL;
 
        g_propagate_error (perror, EDC_ERROR (PermissionDenied));
 }
@@ -1389,9 +1388,9 @@ e_cal_backend_http_class_init (ECalBackendHttpClass *class)
        sync_class->authenticate_user_sync      = e_cal_backend_http_authenticate_user;
        sync_class->refresh_sync                = e_cal_backend_http_refresh;
        sync_class->remove_sync                 = e_cal_backend_http_remove;
-       sync_class->create_object_sync          = e_cal_backend_http_create_object;
-       sync_class->modify_object_sync          = e_cal_backend_http_modify_object;
-       sync_class->remove_object_sync          = e_cal_backend_http_remove_object;
+       sync_class->create_objects_sync         = e_cal_backend_http_create_objects;
+       sync_class->modify_objects_sync         = e_cal_backend_http_modify_objects;
+       sync_class->remove_objects_sync         = e_cal_backend_http_remove_objects;
        sync_class->receive_objects_sync        = e_cal_backend_http_receive_objects;
        sync_class->send_objects_sync           = e_cal_backend_http_send_objects;
        sync_class->get_object_sync             = e_cal_backend_http_get_object;
index 7f37f4e..6685e07 100644 (file)
@@ -562,6 +562,43 @@ convert_type (ECalClientSourceType type)
        return AnyType;
 }
 
+/*
+ * Converts a GSList of icalcomponents into a NULL-terminated array of
+ * valid UTF-8 strings, suitable for sending over DBus.
+ */
+static gchar **
+icalcomponent_slist_to_utf8_icomp_array (GSList *icalcomponents)
+{
+       gchar **array;
+       const GSList *l;
+       gint i = 0;
+
+       array = g_new0 (gchar *, g_slist_length (icalcomponents) + 1);
+       for (l = icalcomponents; l != NULL; l = l->next) {
+               gchar *comp_str = icalcomponent_as_ical_string_r ((icalcomponent *) l->data);
+               array[i++] = e_util_utf8_make_valid (comp_str);
+               g_free (comp_str);
+       }
+
+       return array;
+}
+
+/*
+ * Converts a GSList of icalcomponents into a GSList of strings.
+ */
+static GSList *
+icalcomponent_slist_to_string_slist (GSList *icalcomponents)
+{
+       GSList *strings = NULL;
+       const GSList *l;
+
+       for (l = icalcomponents; l != NULL; l = l->next) {
+               strings = g_slist_prepend (strings, icalcomponent_as_ical_string_r ((icalcomponent *) l->data));
+       }
+
+       return g_slist_reverse (strings);
+}
+
 /**
  * e_cal_client_new:
  * @source: An #ESource pointer
@@ -2693,6 +2730,29 @@ complete_string_exchange (gboolean res,
 }
 
 static gboolean
+complete_strv_exchange (gboolean res,
+                        gchar **out_strings,
+                        GSList **result,
+                        GError **error)
+{
+       g_return_val_if_fail (result != NULL, FALSE);
+
+       if (res && out_strings) {
+               *result = e_client_util_strv_to_slist ((const gchar * const*) out_strings);
+       } else {
+               *result = NULL;
+               res = FALSE;
+
+               if (error && !*error)
+                       g_propagate_error (error, e_client_error_create (E_CLIENT_ERROR_INVALID_ARG, NULL));
+       }
+
+       g_strfreev (out_strings);
+
+       return res;
+}
+
+static gboolean
 cal_client_get_default_object_from_cache_finish (EClient *client,
                                                  GAsyncResult *result,
                                                  gchar **prop_value,
@@ -3644,14 +3704,19 @@ e_cal_client_create_object (ECalClient *client,
                             gpointer user_data)
 {
        gchar *comp_str, *gdbus_comp = NULL;
+       const gchar *strv[2];
 
        g_return_if_fail (icalcomp != NULL);
 
        comp_str = icalcomponent_as_ical_string_r (icalcomp);
+       strv[0] = e_util_ensure_gdbus_string (comp_str, &gdbus_comp);
+       strv[1] = NULL;
 
-       e_client_proxy_call_string (E_CLIENT (client), e_util_ensure_gdbus_string (comp_str, &gdbus_comp), cancellable, callback, user_data, e_cal_client_create_object,
-                       e_gdbus_cal_call_create_object,
-                       NULL, NULL, e_gdbus_cal_call_create_object_finish, NULL, NULL);
+       g_return_if_fail (strv[0] != NULL);
+
+       e_client_proxy_call_strv (E_CLIENT (client), strv, cancellable, callback, user_data, e_cal_client_create_object,
+                       e_gdbus_cal_call_create_objects,
+                       NULL, NULL, NULL, e_gdbus_cal_call_create_objects_finish, NULL);
 
        g_free (comp_str);
        g_free (gdbus_comp);
@@ -3679,11 +3744,17 @@ e_cal_client_create_object_finish (ECalClient *client,
                                    GError **error)
 {
        gboolean res;
+       gchar **out_strings = NULL;
        gchar *out_string = NULL;
 
        g_return_val_if_fail (uid != NULL, FALSE);
 
-       res = e_client_proxy_call_finish_string (E_CLIENT (client), result, &out_string, error, e_cal_client_create_object);
+       res = e_client_proxy_call_finish_strv (E_CLIENT (client), result, &out_strings, error, e_cal_client_create_object);
+
+       if (res && out_strings) {
+               out_string = g_strdup (out_strings[0]);
+               g_strfreev (out_strings);
+       }
 
        return complete_string_exchange (res, out_string, uid, error);
 }
@@ -3715,6 +3786,8 @@ e_cal_client_create_object_sync (ECalClient *client,
 {
        gboolean res;
        gchar *comp_str, *gdbus_comp = NULL;
+       const gchar *strv[2];
+       gchar **out_strings = NULL;
        gchar *out_string = NULL;
 
        g_return_val_if_fail (client != NULL, FALSE);
@@ -3729,16 +3802,144 @@ e_cal_client_create_object_sync (ECalClient *client,
        }
 
        comp_str = icalcomponent_as_ical_string_r (icalcomp);
+       strv[0] = e_util_ensure_gdbus_string (comp_str, &gdbus_comp);
+       strv[1] = NULL;
+
+       g_return_val_if_fail (strv[0] != NULL, FALSE);
 
-       res = e_client_proxy_call_sync_string__string (E_CLIENT (client), e_util_ensure_gdbus_string (comp_str, &gdbus_comp), &out_string, cancellable, error, e_gdbus_cal_call_create_object_sync);
+       res = e_client_proxy_call_sync_strv__strv (E_CLIENT (client), strv, &out_strings, cancellable, error, e_gdbus_cal_call_create_objects_sync);
 
        g_free (comp_str);
        g_free (gdbus_comp);
 
+       if (res && out_strings) {
+               out_string = g_strdup (out_strings[0]);
+               g_strfreev (out_strings);
+       }
+
        return complete_string_exchange (res, out_string, uid, error);
 }
 
 /**
+ * e_cal_client_create_objects:
+ * @client: an #ECalClient
+ * @icalcomps: The components to create
+ * @cancellable: a #GCancellable; can be %NULL
+ * @callback: callback to call when a result is ready
+ * @user_data: user data for the @callback
+ *
+ * Requests the calendar backend to create the objects specified by the @icalcomps
+ * argument. Some backends would assign a specific UID to the newly created object,
+ * but this function does not modify the original @icalcomps if their UID changes.
+ * The call is finished by e_cal_client_create_objects_finish() from
+ * the @callback.
+ *
+ * Since: 3.6
+ **/
+void
+e_cal_client_create_objects (ECalClient *client,
+                             GSList *icalcomps,
+                             GCancellable *cancellable,
+                             GAsyncReadyCallback callback,
+                             gpointer user_data)
+{
+       gchar **array;
+
+       g_return_if_fail (client != NULL);
+       g_return_if_fail (E_IS_CAL_CLIENT (client));
+       g_return_if_fail (client->priv != NULL);
+       g_return_if_fail (icalcomps != NULL);
+
+       array = icalcomponent_slist_to_utf8_icomp_array (icalcomps);
+
+       e_client_proxy_call_strv (E_CLIENT (client), (const gchar * const *) array, cancellable, callback, user_data, e_cal_client_create_objects,
+                       e_gdbus_cal_call_create_objects,
+                       NULL, NULL, NULL, e_gdbus_cal_call_create_objects_finish, NULL);
+
+       g_strfreev (array);
+}
+
+/**
+ * e_cal_client_create_objects_finish:
+ * @client: an #ECalClient
+ * @result: a #GAsyncResult
+ * @uids: (out): Return value for the UIDs assigned to the new components by the calendar backend
+ * @error: (out): a #GError to set an error, if any
+ *
+ * Finishes previous call of e_cal_client_create_objects() and
+ * sets @uids to newly assigned UIDs for the created objects.
+ * This @uids should be freed with e_client_util_free_string_slist().
+ *
+ * Returns: %TRUE if successful, %FALSE otherwise.
+ *
+ * Since: 3.6
+ **/
+gboolean
+e_cal_client_create_objects_finish (ECalClient *client,
+                                    GAsyncResult *result,
+                                    GSList **uids,
+                                    GError **error)
+{
+       gboolean res;
+       gchar **out_strings = NULL;
+
+       g_return_val_if_fail (client != NULL, FALSE);
+       g_return_val_if_fail (E_IS_CAL_CLIENT (client), FALSE);
+       g_return_val_if_fail (client->priv != NULL, FALSE);
+       g_return_val_if_fail (uids != NULL, FALSE);
+
+       res = e_client_proxy_call_finish_strv (E_CLIENT (client), result, &out_strings, error, e_cal_client_create_objects);
+
+       return complete_strv_exchange (res, out_strings, uids, error);
+}
+
+/**
+ * e_cal_client_create_objects_sync:
+ * @client: an #ECalClient
+ * @icalcomps: The components to create
+ * @uids: (out): Return value for the UIDs assigned to the new components by the calendar backend
+ * @cancellable: a #GCancellable; can be %NULL
+ * @error: (out): a #GError to set an error, if any
+ *
+ * Requests the calendar backend to create the objects specified by the @icalcomps
+ * argument. Some backends would assign a specific UID to the newly created objects,
+ * in those cases these UIDs would be returned in the @uids argument. This function
+ * does not modify the original @icalcomps if their UID changes.
+ * Returned @uid should be freed with e_client_util_free_string_slist().
+ *
+ * Returns: %TRUE if successful, %FALSE otherwise.
+ *
+ * Since: 3.6
+ **/
+gboolean
+e_cal_client_create_objects_sync (ECalClient *client,
+                                  GSList *icalcomps,
+                                  GSList **uids,
+                                  GCancellable *cancellable,
+                                  GError **error)
+{
+       gboolean res;
+       gchar **array, **out_strings = NULL;
+
+       g_return_val_if_fail (client != NULL, FALSE);
+       g_return_val_if_fail (E_IS_CAL_CLIENT (client), FALSE);
+       g_return_val_if_fail (client->priv != NULL, FALSE);
+       g_return_val_if_fail (icalcomps != NULL, FALSE);
+       g_return_val_if_fail (uids != NULL, FALSE);
+
+       if (!client->priv->gdbus_cal) {
+               set_proxy_gone_error (error);
+               return FALSE;
+       }
+
+       array = icalcomponent_slist_to_utf8_icomp_array (icalcomps);
+
+       res = e_client_proxy_call_sync_strv__strv (E_CLIENT (client), (const gchar * const *) array, &out_strings, cancellable, error, e_gdbus_cal_call_create_objects_sync);
+
+       return complete_strv_exchange (res, out_strings, uids, error);
+}
+
+/**
  * e_cal_client_modify_object:
  * @client: an #ECalClient
  * @icalcomp: Component to modify
@@ -3769,15 +3970,17 @@ e_cal_client_modify_object (ECalClient *client,
                             gpointer user_data)
 {
        gchar *comp_str, **strv;
+       GSList comp_strings = {0,};
 
        g_return_if_fail (icalcomp != NULL);
 
        comp_str = icalcomponent_as_ical_string_r (icalcomp);
-       strv = e_gdbus_cal_encode_modify_object (comp_str, mod);
+       comp_strings.data = comp_str;
+       strv = e_gdbus_cal_encode_modify_objects (&comp_strings, mod);
 
        e_client_proxy_call_strv (E_CLIENT (client), (const gchar * const *) strv, cancellable, callback, user_data, e_cal_client_modify_object,
-                       e_gdbus_cal_call_modify_object,
-                       e_gdbus_cal_call_modify_object_finish, NULL, NULL, NULL, NULL);
+                       e_gdbus_cal_call_modify_objects,
+                       e_gdbus_cal_call_modify_objects_finish, NULL, NULL, NULL, NULL);
 
        g_strfreev (strv);
        g_free (comp_str);
@@ -3832,6 +4035,7 @@ e_cal_client_modify_object_sync (ECalClient *client,
 {
        gboolean res;
        gchar *comp_str, **strv;
+       GSList comp_strings = {0,};
 
        g_return_val_if_fail (client != NULL, FALSE);
        g_return_val_if_fail (E_IS_CAL_CLIENT (client), FALSE);
@@ -3844,9 +4048,10 @@ e_cal_client_modify_object_sync (ECalClient *client,
        }
 
        comp_str = icalcomponent_as_ical_string_r (icalcomp);
-       strv = e_gdbus_cal_encode_modify_object (comp_str, mod);
+       comp_strings.data = comp_str;
+       strv = e_gdbus_cal_encode_modify_objects (&comp_strings, mod);
 
-       res = e_client_proxy_call_sync_strv__void (E_CLIENT (client), (const gchar * const *) strv, cancellable, error, e_gdbus_cal_call_modify_object_sync);
+       res = e_client_proxy_call_sync_strv__void (E_CLIENT (client), (const gchar * const *) strv, cancellable, error, e_gdbus_cal_call_modify_objects_sync);
 
        g_strfreev (strv);
        g_free (comp_str);
@@ -3855,6 +4060,131 @@ e_cal_client_modify_object_sync (ECalClient *client,
 }
 
 /**
+ * e_cal_client_modify_objects:
+ * @client: an #ECalClient
+ * @comps: Components to modify
+ * @mod: Type of modification
+ * @cancellable: a #GCancellable; can be %NULL
+ * @callback: callback to call when a result is ready
+ * @user_data: user data for the @callback
+ *
+ * Requests the calendar backend to modify existing objects. If an object
+ * does not exist on the calendar, an error will be returned.
+ *
+ * For recurrent appointments, the @mod argument specifies what to modify,
+ * if all instances (CALOBJ_MOD_ALL), a single instance (CALOBJ_MOD_THIS),
+ * or a specific set of instances (CALOBJ_MOD_THISNADPRIOR and
+ * CALOBJ_MOD_THISANDFUTURE).
+ *
+ * The call is finished by e_cal_client_modify_objects_finish() from
+ * the @callback.
+ *
+ * Since: 3.6
+ **/
+void
+e_cal_client_modify_objects (ECalClient *client,
+                             /* const */ GSList *comps,
+                             CalObjModType mod,
+                             GCancellable *cancellable,
+                             GAsyncReadyCallback callback,
+                             gpointer user_data)
+{
+       GSList *comp_strings;
+       gchar **strv;
+
+       g_return_if_fail (client != NULL);
+       g_return_if_fail (E_IS_CAL_CLIENT (client));
+       g_return_if_fail (client->priv != NULL);
+       g_return_if_fail (comps != NULL);
+
+       comp_strings = icalcomponent_slist_to_string_slist(comps);
+       strv = e_gdbus_cal_encode_modify_objects (comp_strings, mod);
+
+       e_client_proxy_call_strv (E_CLIENT (client), (const gchar * const *) strv, cancellable, callback, user_data, e_cal_client_modify_objects,
+                       e_gdbus_cal_call_modify_objects,
+                       e_gdbus_cal_call_modify_objects_finish, NULL, NULL, NULL, NULL);
+
+       g_strfreev (strv);
+       e_client_util_free_string_slist (comp_strings);
+}
+
+/**
+ * e_cal_client_modify_objects_finish:
+ * @client: an #ECalClient
+ * @result: a #GAsyncResult
+ * @error: (out): a #GError to set an error, if any
+ *
+ * Finishes previous call of e_cal_client_modify_objects().
+ *
+ * Returns: %TRUE if successful, %FALSE otherwise.
+ *
+ * Since: 3.6
+ **/
+gboolean
+e_cal_client_modify_objects_finish (ECalClient *client,
+                                    GAsyncResult *result,
+                                    GError **error)
+{
+       g_return_val_if_fail (client != NULL, FALSE);
+       g_return_val_if_fail (E_IS_CAL_CLIENT (client), FALSE);
+       g_return_val_if_fail (client->priv != NULL, FALSE);
+
+       return e_client_proxy_call_finish_void (E_CLIENT (client), result, error, e_cal_client_modify_objects);
+}
+
+/**
+ * e_cal_client_modify_objects_sync:
+ * @client: an #ECalClient
+ * @comps: Components to modify
+ * @mod: Type of modification
+ * @cancellable: a #GCancellable; can be %NULL
+ * @error: (out): a #GError to set an error, if any
+ *
+ * Requests the calendar backend to modify existing objects. If an object
+ * does not exist on the calendar, an error will be returned.
+ *
+ * For recurrent appointments, the @mod argument specifies what to modify,
+ * if all instances (CALOBJ_MOD_ALL), a single instance (CALOBJ_MOD_THIS),
+ * or a specific set of instances (CALOBJ_MOD_THISNADPRIOR and
+ * CALOBJ_MOD_THISANDFUTURE).
+ *
+ * Returns: %TRUE if successful, %FALSE otherwise.
+ *
+ * Since: 3.6
+ **/
+gboolean
+e_cal_client_modify_objects_sync (ECalClient *client,
+                                  /* const */ GSList *comps,
+                                  CalObjModType mod,
+                                  GCancellable *cancellable,
+                                  GError **error)
+{
+       gboolean res;
+       gchar **strv;
+       GSList *comp_strings;
+
+       g_return_val_if_fail (client != NULL, FALSE);
+       g_return_val_if_fail (E_IS_CAL_CLIENT (client), FALSE);
+       g_return_val_if_fail (client->priv != NULL, FALSE);
+       g_return_val_if_fail (comps != NULL, FALSE);
+
+       if (!client->priv->gdbus_cal) {
+               set_proxy_gone_error (error);
+               return FALSE;
+       }
+
+       comp_strings = icalcomponent_slist_to_string_slist(comps);
+       strv = e_gdbus_cal_encode_modify_objects (comp_strings, mod);
+
+       res = e_client_proxy_call_sync_strv__void (E_CLIENT (client), (const gchar * const *) strv, cancellable, error, e_gdbus_cal_call_modify_objects_sync);
+
+       g_strfreev (strv);
+       e_client_util_free_string_slist (comp_strings);
+
+       return res;
+}
+
+/**
  * e_cal_client_remove_object:
  * @client: an #ECalClient
  * @uid: UID of the object to remove
@@ -3885,14 +4215,19 @@ e_cal_client_remove_object (ECalClient *client,
                             gpointer user_data)
 {
        gchar **strv;
+       GSList ids = {0,};
+       ECalComponentId id;
 
        g_return_if_fail (uid != NULL);
 
-       strv = e_gdbus_cal_encode_remove_object (uid, rid, mod);
+       id.uid = (gchar *)uid;
+       id.rid = (gchar *)rid;
+       ids.data = &id;
+       strv = e_gdbus_cal_encode_remove_objects (&ids, mod);
 
        e_client_proxy_call_strv (E_CLIENT (client), (const gchar * const *) strv, cancellable, callback, user_data, e_cal_client_remove_object,
-                       e_gdbus_cal_call_remove_object,
-                       e_gdbus_cal_call_remove_object_finish, NULL, NULL, NULL, NULL);
+                       e_gdbus_cal_call_remove_objects,
+                       e_gdbus_cal_call_remove_objects_finish, NULL, NULL, NULL, NULL);
 
        g_strfreev (strv);
 }
@@ -3946,6 +4281,8 @@ e_cal_client_remove_object_sync (ECalClient *client,
 {
        gboolean res;
        gchar **strv;
+       GSList ids = {0,};
+       ECalComponentId id;
 
        g_return_val_if_fail (client != NULL, FALSE);
        g_return_val_if_fail (E_IS_CAL_CLIENT (client), FALSE);
@@ -3957,9 +4294,118 @@ e_cal_client_remove_object_sync (ECalClient *client,
                return FALSE;
        }
 
-       strv = e_gdbus_cal_encode_remove_object (uid, rid, mod);
+       id.uid = (gchar *)uid;
+       id.rid = (gchar *)rid;
+       ids.data = &id;
+       strv = e_gdbus_cal_encode_remove_objects (&ids, mod);
+
+       res = e_client_proxy_call_sync_strv__void (E_CLIENT (client), (const gchar * const *) strv, cancellable, error, e_gdbus_cal_call_remove_objects_sync);
+
+       g_strfreev (strv);
+
+       return res;
+}
+
+/**
+ * e_cal_client_remove_objects:
+ * @client: an #ECalClient
+ * @ids: A list of #ECalComponentId objects identifying the objects to remove
+ * @mod: Type of the removal
+ * @cancellable: a #GCancellable; can be %NULL
+ * @callback: callback to call when a result is ready
+ * @user_data: user data for the @callback
+ *
+ * This function allows the removal of instances of recurrent
+ * appointments. #ECalComponentId objects can identify specific instances (if rid is not NULL).
+ * If what you want is to remove all instances, use a #NULL rid in the #ECalComponentId and CALOBJ_MOD_ALL
+ * for the @mod.
+ *
+ * The call is finished by e_cal_client_remove_objects_finish() from
+ * the @callback.
+ *
+ * Since: 3.6
+ **/
+void
+e_cal_client_remove_objects (ECalClient *client,
+                             const GSList *ids,
+                             CalObjModType mod,
+                             GCancellable *cancellable,
+                             GAsyncReadyCallback callback,
+                             gpointer user_data)
+{
+       gchar **strv;
+
+       g_return_if_fail (ids != NULL);
+
+       strv = e_gdbus_cal_encode_remove_objects (ids, mod);
+
+       e_client_proxy_call_strv (E_CLIENT (client), (const gchar * const *) strv, cancellable, callback, user_data, e_cal_client_remove_objects,
+                       e_gdbus_cal_call_remove_objects,
+                       e_gdbus_cal_call_remove_objects_finish, NULL, NULL, NULL, NULL);
+
+       g_strfreev (strv);
+}
+
+/**
+ * e_cal_client_remove_objects_finish:
+ * @client: an #ECalClient
+ * @result: a #GAsyncResult
+ * @error: (out): a #GError to set an error, if any
+ *
+ * Finishes previous call of e_cal_client_remove_objects().
+ *
+ * Returns: %TRUE if successful, %FALSE otherwise.
+ *
+ * Since: 3.6
+ **/
+gboolean
+e_cal_client_remove_objects_finish (ECalClient *client,
+                                    GAsyncResult *result,
+                                    GError **error)
+{
+       return e_client_proxy_call_finish_void (E_CLIENT (client), result, error, e_cal_client_remove_objects);
+}
+
+/**
+ * e_cal_client_remove_objects_sync:
+ * @client: an #ECalClient
+ * @ids: A list of #ECalComponentId objects identifying the objects to remove
+ * @mod: Type of the removal
+ * @cancellable: a #GCancellable; can be %NULL
+ * @error: (out): a #GError to set an error, if any
+ *
+ * This function allows the removal of instances of recurrent
+ * appointments. #ECalComponentId objects can identify specific instances (if rid is not NULL).
+ * If what you want is to remove all instances, use a #NULL rid in the #ECalComponentId and CALOBJ_MOD_ALL
+ * for the @mod.
+ *
+ * Returns: %TRUE if successful, %FALSE otherwise.
+ *
+ * Since: 3.6
+ **/
+gboolean
+e_cal_client_remove_objects_sync (ECalClient *client,
+                                  const GSList *ids,
+                                  CalObjModType mod,
+                                  GCancellable *cancellable,
+                                  GError **error)
+{
+       gboolean res;
+       gchar **strv;
+
+       g_return_val_if_fail (client != NULL, FALSE);
+       g_return_val_if_fail (E_IS_CAL_CLIENT (client), FALSE);
+       g_return_val_if_fail (client->priv != NULL, FALSE);
+       g_return_val_if_fail (ids != NULL, FALSE);
+
+       if (!client->priv->gdbus_cal) {
+               set_proxy_gone_error (error);
+               return FALSE;
+       }
+
+       strv = e_gdbus_cal_encode_remove_objects (ids, mod);
 
-       res = e_client_proxy_call_sync_strv__void (E_CLIENT (client), (const gchar * const *) strv, cancellable, error, e_gdbus_cal_call_remove_object_sync);
+       res = e_client_proxy_call_sync_strv__void (E_CLIENT (client), (const gchar * const *) strv, cancellable, error, e_gdbus_cal_call_remove_objects_sync);
 
        g_strfreev (strv);
 
index 3e77baf..1733511 100644 (file)
@@ -206,14 +206,26 @@ void              e_cal_client_create_object                      (ECalClient *client, /* const */ icalcomponen
 gboolean       e_cal_client_create_object_finish               (ECalClient *client, GAsyncResult *result, gchar **uid, GError **error);
 gboolean       e_cal_client_create_object_sync                 (ECalClient *client, /* const */ icalcomponent *icalcomp, gchar **uid, GCancellable *cancellable, GError **error);
 
+void           e_cal_client_create_objects                     (ECalClient *client, GSList *icalcomps, GCancellable *cancellable, GAsyncReadyCallback callback, gpointer user_data);
+gboolean       e_cal_client_create_objects_finish      (ECalClient *client, GAsyncResult *result, GSList **uids, GError **error);
+gboolean       e_cal_client_create_objects_sync        (ECalClient *client, GSList *icalcomps, GSList **uids, GCancellable *cancellable, GError **error);
+
 void           e_cal_client_modify_object                      (ECalClient *client, /* const */ icalcomponent *icalcomp, CalObjModType mod, GCancellable *cancellable, GAsyncReadyCallback callback, gpointer user_data);
 gboolean       e_cal_client_modify_object_finish               (ECalClient *client, GAsyncResult *result, GError **error);
 gboolean       e_cal_client_modify_object_sync                 (ECalClient *client, /* const */ icalcomponent *icalcomp, CalObjModType mod, GCancellable *cancellable, GError **error);
 
+void           e_cal_client_modify_objects                     (ECalClient *client, /* const */ GSList *icalcomps, CalObjModType mod, GCancellable *cancellable, GAsyncReadyCallback callback, gpointer user_data);
+gboolean       e_cal_client_modify_objects_finish      (ECalClient *client, GAsyncResult *result, GError **error);
+gboolean       e_cal_client_modify_objects_sync        (ECalClient *client, /* const */ GSList *icalcomps, CalObjModType mod, GCancellable *cancellable, GError **error);
+
 void           e_cal_client_remove_object                      (ECalClient *client, const gchar *uid, const gchar *rid, CalObjModType mod, GCancellable *cancellable, GAsyncReadyCallback callback, gpointer user_data);
 gboolean       e_cal_client_remove_object_finish               (ECalClient *client, GAsyncResult *result, GError **error);
 gboolean       e_cal_client_remove_object_sync                 (ECalClient *client, const gchar *uid, const gchar *rid, CalObjModType mod, GCancellable *cancellable, GError **error);
 
+void           e_cal_client_remove_objects                     (ECalClient *client, const GSList *ids, CalObjModType mod, GCancellable *cancellable, GAsyncReadyCallback callback, gpointer user_data);
+gboolean       e_cal_client_remove_objects_finish      (ECalClient *client, GAsyncResult *result, GError **error);
+gboolean       e_cal_client_remove_objects_sync        (ECalClient *client, const GSList *ids, CalObjModType mod, GCancellable *cancellable, GError **error);
+
 void           e_cal_client_receive_objects                    (ECalClient *client, /* const */ icalcomponent *icalcomp, GCancellable *cancellable, GAsyncReadyCallback callback, gpointer user_data);
 gboolean       e_cal_client_receive_objects_finish             (ECalClient *client, GAsyncResult *result, GError **error);
 gboolean       e_cal_client_receive_objects_sync               (ECalClient *client, /* const */ icalcomponent *icalcomp, GCancellable *cancellable, GError **error);
index fe6a48d..966aeb5 100644 (file)
@@ -113,6 +113,33 @@ gboolean e_cal_util_event_dates_match (icalcomponent *icalcomp1, icalcomponent *
 #define CAL_STATIC_CAPABILITY_NO_TRANSPARENCY             "no-transparency"
 
 /**
+ * CAL_STATIC_CAPABILITY_BULK_ADDS:
+ *
+ * Flag indicating that the backend supports bulk additions.
+ *
+ * Since: 3.6
+ */
+#define CAL_STATIC_CAPABILITY_BULK_ADDS                   "bulk-adds"
+
+/**
+ * CAL_STATIC_CAPABILITY_BULK_MODIFIES:
+ *
+ * Flag indicating that the backend supports bulk modifications.
+ *
+ * Since: 3.6
+ */
+#define CAL_STATIC_CAPABILITY_BULK_MODIFIES               "bulk-modifies"
+
+/**
+ * CAL_STATIC_CAPABILITY_BULK_REMOVES:
+ *
+ * Flag indicating that the backend supports bulk removals.
+ *
+ * Since: 3.6
+ */
+#define CAL_STATIC_CAPABILITY_BULK_REMOVES                "bulk-removes"
+
+/**
  * CAL_STATIC_CAPABILITY_REMOVE_ONLY_THIS:
  *
  * FIXME: Document me.
index c2ab5c9..2a9bca1 100644 (file)
@@ -3917,7 +3917,9 @@ e_cal_create_object (ECal *ecal,
                      GError **error)
 {
        ECalPrivate *priv;
-       gchar *obj, *muid = NULL, *gdbus_obj = NULL;
+       gchar *obj, *gdbus_obj = NULL;
+       const gchar *strv[2];
+       gchar **muids = NULL;
 
        e_return_error_if_fail (E_IS_CAL (ecal), E_CALENDAR_STATUS_INVALID_ARG);
        e_return_error_if_fail (icalcomp != NULL, E_CALENDAR_STATUS_INVALID_ARG);
@@ -3930,8 +3932,10 @@ e_cal_create_object (ECal *ecal,
        }
 
        obj = icalcomponent_as_ical_string_r (icalcomp);
-       if (!e_gdbus_cal_call_create_object_sync (priv->gdbus_cal, e_util_ensure_gdbus_string (obj, &gdbus_obj), &muid, NULL, error)) {
-               g_free (muid);
+       strv[0] = e_util_ensure_gdbus_string (obj, &gdbus_obj);
+       strv[1] = NULL;
+
+       if (!e_gdbus_cal_call_create_objects_sync (priv->gdbus_cal, strv, &muids, NULL, error)) {
                g_free (obj);
                g_free (gdbus_obj);
 
@@ -3941,15 +3945,15 @@ e_cal_create_object (ECal *ecal,
        g_free (obj);
        g_free (gdbus_obj);
 
-       if (!muid) {
+       if (!muids) {
                E_CALENDAR_CHECK_STATUS (E_CALENDAR_STATUS_OTHER_ERROR, error);
        } else {
-               icalcomponent_set_uid (icalcomp, muid);
+               icalcomponent_set_uid (icalcomp, muids[0]);
 
                if (uid)
-                       *uid = muid;
-               else
-                       g_free (muid);
+                       *uid = g_strdup (muids[0]);
+
+               g_strfreev (muids);
 
                E_CALENDAR_CHECK_STATUS (E_CALENDAR_STATUS_OK, error);
        }
@@ -3982,6 +3986,7 @@ e_cal_modify_object (ECal *ecal,
 {
        ECalPrivate *priv;
        gchar *obj, **strv;
+       GSList objs = {0,};
 
        e_return_error_if_fail (E_IS_CAL (ecal), E_CALENDAR_STATUS_INVALID_ARG);
        e_return_error_if_fail (icalcomp, E_CALENDAR_STATUS_INVALID_ARG);
@@ -4003,8 +4008,9 @@ e_cal_modify_object (ECal *ecal,
        }
 
        obj = icalcomponent_as_ical_string_r (icalcomp);
-       strv = e_gdbus_cal_encode_modify_object (obj, mod);
-       if (!e_gdbus_cal_call_modify_object_sync (priv->gdbus_cal, (const gchar * const *) strv, NULL, error)) {
+       objs.data = obj;
+       strv = e_gdbus_cal_encode_modify_objects (&objs, mod);
+       if (!e_gdbus_cal_call_modify_objects_sync (priv->gdbus_cal, (const gchar * const *) strv, NULL, error)) {
                g_free (obj);
                g_strfreev (strv);
 
@@ -4073,6 +4079,8 @@ e_cal_remove_object_with_mod (ECal *ecal,
 {
        ECalPrivate *priv;
        gchar **strv;
+       GSList ids = {0,};
+       ECalComponentId id;
 
        e_return_error_if_fail (E_IS_CAL (ecal), E_CALENDAR_STATUS_INVALID_ARG);
        e_return_error_if_fail (uid, E_CALENDAR_STATUS_INVALID_ARG);
@@ -4093,8 +4101,11 @@ e_cal_remove_object_with_mod (ECal *ecal,
                E_CALENDAR_CHECK_STATUS (E_CALENDAR_STATUS_URI_NOT_LOADED, error);
        }
 
-       strv = e_gdbus_cal_encode_remove_object (uid, rid, mod);
-       if (!e_gdbus_cal_call_remove_object_sync (priv->gdbus_cal, (const gchar * const *) strv, NULL, error)) {
+       id.uid = (gchar *)uid;
+       id.rid = (gchar *)rid;
+       ids.data = &id;
+       strv = e_gdbus_cal_encode_remove_objects (&ids, mod);
+       if (!e_gdbus_cal_call_remove_objects_sync (priv->gdbus_cal, (const gchar * const *) strv, NULL, error)) {
                g_strfreev (strv);
 
                E_CALENDAR_CHECK_STATUS (E_CALENDAR_STATUS_DBUS_EXCEPTION, error);
index 34ef6a2..f6226e5 100644 (file)
@@ -11,6 +11,7 @@
 #endif
 
 #include "e-cal-backend-sync.h"
+#include "libedataserver/e-data-server-util.h"
 #include <libical/icaltz-util.h>
 
 #define E_CAL_BACKEND_SYNC_GET_PRIVATE(obj) \
@@ -307,96 +308,93 @@ e_cal_backend_sync_get_free_busy (ECalBackendSync *backend,
 }
 
 /**
- * e_cal_backend_sync_create_object:
+ * e_cal_backend_sync_create_objects:
  * @backend: An ECalBackendSync object.
  * @cal: An EDataCal object.
  * @cancellable: a #GCancellable for the operation
- * @calobj: The object to be added.
- * @uid: Placeholder for server-generated UID.
- * @new_component: (out) (transfer full): Placeholder for returned #ECalComponent.
+ * @calobjs: The objects to be added.
+ * @uids: Placeholder for server-generated UIDs.
+ * @new_components: (out) (transfer full): Placeholder for returned #ECalComponent objects.
  * @error: Out parameter for a #GError.
  *
- * Calls the create_object_sync method on the given backend.
+ * Calls the create_objects_sync method on the given backend.
  */
 void
-e_cal_backend_sync_create_object (ECalBackendSync *backend,
-                                  EDataCal *cal,
-                                  GCancellable *cancellable,
-                                  const gchar *calobj,
-                                  gchar **uid,
-                                  ECalComponent **new_component,
-                                  GError **error)
+e_cal_backend_sync_create_objects (ECalBackendSync *backend,
+                                   EDataCal *cal,
+                                   GCancellable *cancellable,
+                                   const GSList *calobjs,
+                                   GSList **uids,
+                                   GSList **new_components,
+                                   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);
+       e_return_data_cal_error_if_fail (E_CAL_BACKEND_SYNC_GET_CLASS (backend)->create_objects_sync != NULL, UnsupportedMethod);
 
-       LOCK_WRAPPER (create_object_sync, (backend, cal, cancellable, calobj, uid, new_component, error));
+       LOCK_WRAPPER (create_objects_sync, (backend, cal, cancellable, calobjs, uids, new_components, error));
 }
 
 /**
- * e_cal_backend_sync_modify_object:
+ * e_cal_backend_sync_modify_objects:
  * @backend: An ECalBackendSync object.
  * @cal: An EDataCal object.
  * @cancellable: a #GCancellable for the operation
- * @calobj: Object to be modified.
+ * @calobjs: Objects to be modified.
  * @mod: Type of modification to be done.
- * @old_component: (out) (transfer full): Placeholder for returning the old component as it was stored on the
+ * @old_components: (out) (transfer full): Placeholder for returning the old components as they were stored on the
  * backend.
- * @new_component: (out) (transfer full): Placeholder for returning the new component as it has been stored
+ * @new_components: (out) (transfer full): Placeholder for returning the new components as they have been stored
  * on the backend.
  * @error: Out parameter for a #GError.
  *
- * Calls the modify_object_sync method on the given backend.
+ * Calls the modify_objects_sync method on the given backend.
  */
 void
-e_cal_backend_sync_modify_object (ECalBackendSync *backend,
-                                  EDataCal *cal,
-                                  GCancellable *cancellable,
-                                  const gchar *calobj,
-                                  CalObjModType mod,
-                                  ECalComponent **old_component,
-                                  ECalComponent **new_component,
-                                  GError **error)
+e_cal_backend_sync_modify_objects (ECalBackendSync *backend,
+                                                                  EDataCal *cal,
+                                                                  GCancellable *cancellable,
+                                                                  const GSList *calobjs,
+                                                                  CalObjModType mod,
+                                                                  GSList **old_components,
+                                                                  GSList **new_components,
+                                                                  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);
+       e_return_data_cal_error_if_fail (E_CAL_BACKEND_SYNC_GET_CLASS (backend)->modify_objects_sync != NULL, UnsupportedMethod);
 
-       LOCK_WRAPPER (modify_object_sync, (backend, cal, cancellable, calobj, mod, old_component, new_component, error));
+       LOCK_WRAPPER (modify_objects_sync, (backend, cal, cancellable, calobjs, mod, old_components, new_components, error));
 }
 
 /**
- * e_cal_backend_sync_remove_object:
+ * e_cal_backend_sync_remove_objects:
  * @backend: An ECalBackendSync object.
  * @cal: An EDataCal object.
  * @cancellable: a #GCancellable for the operation
- * @uid: UID of the object to remove.
- * @rid: Recurrence ID of the instance to remove, or NULL if removing the
- * whole object.
+ * @ids: List of #ECalComponentId objects identifying the objects to remove.
  * @mod: Type of removal.
- * @old_component: (out) (transfer full): Placeholder for returning the old component as it was stored on the
+ * @old_components: (out) (transfer full): Placeholder for returning the old components as they were stored on the
  * backend.
- * @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.
+ * @new_components: (out) (transfer full): Placeholder for returning the new components as they have been stored
+ * on the backend (when removing individual instances). If removing whole objects,
+ * they will be set to %NULL.
  * @error: Out parameter for a #GError.
  *
- * Calls the remove_object_sync method on the given backend.
+ * Calls the remove_objects_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,
-                                  ECalComponent **old_component,
-                                  ECalComponent **new_component,
-                                  GError **error)
+e_cal_backend_sync_remove_objects (ECalBackendSync *backend,
+                                   EDataCal *cal,
+                                   GCancellable *cancellable,
+                                   const GSList *ids,
+                                   CalObjModType mod,
+                                   GSList **old_components,
+                                   GSList **new_components,
+                                   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);
+       e_return_data_cal_error_if_fail (E_CAL_BACKEND_SYNC_GET_CLASS (backend)->remove_objects_sync != NULL, UnsupportedMethod);
 
-       LOCK_WRAPPER (remove_object_sync, (backend, cal, cancellable, uid, rid, mod, old_component, new_component, error));
+       LOCK_WRAPPER (remove_objects_sync, (backend, cal, cancellable, ids, mod, old_components, new_components, error));
 }
 
 /**
@@ -728,80 +726,81 @@ cal_backend_get_free_busy (ECalBackend *backend,
        g_slist_free (freebusyobjs);
 }
 
+static GSList *
+ecalcomponent_slist_from_strings (const GSList *strings)
+{
+       GSList *ecalcomps = NULL;
+       const GSList *l;
+
+       for (l = strings; l; l = l->next) {
+               ECalComponent *component = e_cal_component_new_from_string (l->data);
+               ecalcomps = g_slist_prepend (ecalcomps, component);
+       }
+
+       return g_slist_reverse (ecalcomps);
+}
+
 static void
-cal_backend_create_object (ECalBackend *backend,
-                           EDataCal *cal,
-                           guint32 opid,
-                           GCancellable *cancellable,
-                           const gchar *calobj)
+cal_backend_create_objects (ECalBackend *backend,
+                            EDataCal *cal,
+                            guint32 opid,
+                            GCancellable *cancellable,
+                            const GSList *calobjs)
 {
        GError *error = NULL;
-       gchar *uid = NULL;
-       ECalComponent *new_component = NULL;
+       GSList *uids = NULL;
+       GSList *new_components = NULL;
 
-       e_cal_backend_sync_create_object (E_CAL_BACKEND_SYNC (backend), cal, cancellable, calobj, &uid, &new_component, &error);
+       e_cal_backend_sync_create_objects (E_CAL_BACKEND_SYNC (backend), cal, cancellable, calobjs, &uids, &new_components, &error);
 
-       if (!new_component)
-               new_component = e_cal_component_new_from_string (calobj);
+       if (!new_components)
+               new_components = ecalcomponent_slist_from_strings (calobjs);
 
-       e_data_cal_respond_create_object (cal, opid, error, uid, new_component);
+       e_data_cal_respond_create_objects (cal, opid, error, uids, new_components);
 
-       g_free (uid);
-
-       if (new_component)
-               g_object_unref (new_component);
+       g_slist_free_full (uids, g_free);
+       e_util_free_nullable_object_slist (new_components);
 }
 
 static void
-cal_backend_modify_object (ECalBackend *backend,
-                           EDataCal *cal,
-                           guint32 opid,
-                           GCancellable *cancellable,
-                           const gchar *calobj,
-                           CalObjModType mod)
+cal_backend_modify_objects (ECalBackend *backend,
+                            EDataCal *cal,
+                            guint32 opid,
+                            GCancellable *cancellable,
+                            const GSList *calobjs,
+                            CalObjModType mod)
 {
        GError *error = NULL;
-       ECalComponent *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);
+       GSList *old_components = NULL, *new_components = NULL;
 
-       if (!old_component)
-               old_component = e_cal_component_new_from_string (calobj);
+       e_cal_backend_sync_modify_objects (E_CAL_BACKEND_SYNC (backend), cal, cancellable, calobjs, mod, &old_components, &new_components, &error);
 
-       e_data_cal_respond_modify_object (cal, opid, error, old_component, new_component);
+       if (!old_components)
+               old_components = ecalcomponent_slist_from_strings (calobjs);
 
-       if (old_component)
-               g_object_unref (old_component);
+       e_data_cal_respond_modify_objects (cal, opid, error, old_components, new_components);
 
-       if (new_component)
-               g_object_unref (new_component);
+       e_util_free_nullable_object_slist (old_components);
+       e_util_free_nullable_object_slist (new_components);
 }
 
 static void
-cal_backend_remove_object (ECalBackend *backend,
-                           EDataCal *cal,
-                           guint32 opid,
-                           GCancellable *cancellable,
-                           const gchar *uid,
-                           const gchar *rid,
-                           CalObjModType mod)
+cal_backend_remove_objects (ECalBackend *backend,
+                            EDataCal *cal,
+                            guint32 opid,
+                            GCancellable *cancellable,
+                            const GSList *ids,
+                            CalObjModType mod)
 {
        GError *error = NULL;
-       ECalComponent *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_component, &new_component, &error);
+       GSList *old_components = NULL, *new_components = NULL;
 
-       e_data_cal_respond_remove_object (cal, opid, error, &compid, old_component, new_component);
+       e_cal_backend_sync_remove_objects (E_CAL_BACKEND_SYNC (backend), cal, cancellable, ids, mod, &old_components, &new_components, &error);
 
-       if (old_component)
-               g_object_unref (old_component);
+       e_data_cal_respond_remove_objects (cal, opid, error, ids, old_components, new_components);
 
-       if (new_component)
-               g_object_unref (new_component);
+       e_util_free_nullable_object_slist (old_components);
+       e_util_free_nullable_object_slist (new_components);
 }
 
 static void
@@ -1049,9 +1048,9 @@ e_cal_backend_sync_class_init (ECalBackendSyncClass *class)
        backend_class->get_object               = cal_backend_get_object;
        backend_class->get_object_list          = cal_backend_get_object_list;
        backend_class->get_free_busy            = cal_backend_get_free_busy;
-       backend_class->create_object            = cal_backend_create_object;
-       backend_class->modify_object            = cal_backend_modify_object;
-       backend_class->remove_object            = cal_backend_remove_object;
+       backend_class->create_objects           = cal_backend_create_objects;
+       backend_class->modify_objects           = cal_backend_modify_objects;
+       backend_class->remove_objects           = cal_backend_remove_objects;
        backend_class->receive_objects          = cal_backend_receive_objects;
        backend_class->send_objects             = cal_backend_send_objects;
        backend_class->get_attachment_uris      = cal_backend_get_attachment_uris;
index d3c2d13..6b7d180 100644 (file)
@@ -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, ECalComponent **new_component, GError **error);
-       void    (* modify_object_sync)          (ECalBackendSync *backend, EDataCal *cal, GCancellable *cancellable, const gchar *calobj, CalObjModType mod, ECalComponent **old_component, ECalComponent **new_component, GError **error);
-       void    (* remove_object_sync)          (ECalBackendSync *backend, EDataCal *cal, GCancellable *cancellable, const gchar *uid, const gchar *rid, CalObjModType mod, ECalComponent **old_component, ECalComponent **new_component, GError **error);
+       void    (* create_objects_sync)         (ECalBackendSync *backend, EDataCal *cal, GCancellable *cancellable, const GSList *calobjs, GSList **uids, GSList **new_components, GError **error);
+       void    (* modify_objects_sync)         (ECalBackendSync *backend, EDataCal *cal, GCancellable *cancellable, const GSList *calobjs, CalObjModType mod, GSList **old_components, GSList **new_components, GError **error);
+       void    (* remove_objects_sync)         (ECalBackendSync *backend, EDataCal *cal, GCancellable *cancellable, const GSList *ids, CalObjModType mod, GSList **old_components, GSList **new_components, 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 **freebusyobjects, GError **error);
-void   e_cal_backend_sync_create_object        (ECalBackendSync *backend, EDataCal *cal, GCancellable *cancellable, const gchar *calobj, gchar **uid, ECalComponent **new_component, GError **error);
-void   e_cal_backend_sync_modify_object        (ECalBackendSync *backend, EDataCal *cal, GCancellable *cancellable, const gchar *calobj, CalObjModType mod, ECalComponent **old_component, ECalComponent **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, ECalComponent **old_component, ECalComponent **new_component, GError **error);
+void   e_cal_backend_sync_create_objects       (ECalBackendSync *backend, EDataCal *cal, GCancellable *cancellable, const GSList *calobjs, GSList **uids, GSList **new_components, GError **error);
+void   e_cal_backend_sync_modify_objects       (ECalBackendSync *backend, EDataCal *cal, GCancellable *cancellable, const GSList *calobjs, CalObjModType mod, GSList **old_components, GSList **new_components, GError **error);
+void   e_cal_backend_sync_remove_objects       (ECalBackendSync *backend, EDataCal *cal, GCancellable *cancellable, const GSList *ids, CalObjModType mod, GSList **old_components, GSList **new_components, 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);
index 1894690..d956ae3 100644 (file)
@@ -1014,105 +1014,103 @@ e_cal_backend_get_free_busy (ECalBackend *backend,
 }
 
 /**
- * e_cal_backend_create_object:
+ * e_cal_backend_create_objects:
  * @backend: an #ECalBackend
  * @cal: an #EDataCal
  * @opid: the ID to use for this operation
  * @cancellable: a #GCancellable for the operation
- * @calobj: The object to create.
+ * @calobjs: The objects to create (list of gchar *).
  *
  * Calls the create_object method on the given backend.
- * This might be finished with e_data_cal_respond_create_object().
+ * This might be finished with e_data_cal_respond_create_objects().
  **/
 void
-e_cal_backend_create_object (ECalBackend *backend,
-                             EDataCal *cal,
-                             guint32 opid,
-                             GCancellable *cancellable,
-                             const gchar *calobj)
+e_cal_backend_create_objects (ECalBackend *backend,
+                              EDataCal *cal,
+                              guint32 opid,
+                              GCancellable *cancellable,
+                              const GSList *calobjs)
 {
        g_return_if_fail (backend != NULL);
        g_return_if_fail (E_IS_CAL_BACKEND (backend));
-       g_return_if_fail (calobj != NULL);
+       g_return_if_fail (calobjs != NULL);
 
        if (e_cal_backend_is_opening (backend))
-               e_data_cal_respond_create_object (cal, opid, EDC_OPENING_ERROR, NULL, NULL);
-       else if (!E_CAL_BACKEND_GET_CLASS (backend)->create_object)
-               e_data_cal_respond_create_object (cal, opid, EDC_ERROR (UnsupportedMethod), NULL, NULL);
+               e_data_cal_respond_create_objects (cal, opid, EDC_OPENING_ERROR, NULL, NULL);
+       else if (!E_CAL_BACKEND_GET_CLASS (backend)->create_objects)
+               e_data_cal_respond_create_objects (cal, opid, EDC_ERROR (UnsupportedMethod), NULL, NULL);
        else if (!e_cal_backend_is_opened (backend))
-               e_data_cal_respond_create_object (cal, opid, EDC_NOT_OPENED_ERROR, NULL, NULL);
+               e_data_cal_respond_create_objects (cal, opid, EDC_NOT_OPENED_ERROR, NULL, NULL);
        else
-               (* E_CAL_BACKEND_GET_CLASS (backend)->create_object) (backend, cal, opid, cancellable, calobj);
+               (* E_CAL_BACKEND_GET_CLASS (backend)->create_objects) (backend, cal, opid, cancellable, calobjs);
 }
 
 /**
- * e_cal_backend_modify_object:
+ * e_cal_backend_modify_objects:
  * @backend: an #ECalBackend
  * @cal: an #EDataCal
  * @opid: the ID to use for this operation
  * @cancellable: a #GCancellable for the operation
- * @calobj: Object to be modified.
+ * @calobjs: Objects to be modified (list of gchar *).
  * @mod: Type of modification.
  *
- * Calls the modify_object method on the given backend.
- * This might be finished with e_data_cal_respond_modify_object().
+ * Calls the modify_objects method on the given backend.
+ * This might be finished with e_data_cal_respond_modify_objects().
  **/
 void
-e_cal_backend_modify_object (ECalBackend *backend,
-                             EDataCal *cal,
-                             guint32 opid,
-                             GCancellable *cancellable,
-                             const gchar *calobj,
-                             CalObjModType mod)
+e_cal_backend_modify_objects (ECalBackend *backend,
+                              EDataCal *cal,
+                              guint32 opid,
+                              GCancellable *cancellable,
+                              const GSList *calobjs,
+                              CalObjModType mod)
 {
        g_return_if_fail (backend != NULL);
        g_return_if_fail (E_IS_CAL_BACKEND (backend));
-       g_return_if_fail (calobj != NULL);
+       g_return_if_fail (calobjs != NULL);
 
        if (e_cal_backend_is_opening (backend))
-               e_data_cal_respond_modify_object (cal, opid, EDC_OPENING_ERROR, NULL, NULL);
-       else if (!E_CAL_BACKEND_GET_CLASS (backend)->modify_object)
-               e_data_cal_respond_modify_object (cal, opid, EDC_ERROR (UnsupportedMethod), NULL, NULL);
+               e_data_cal_respond_modify_objects (cal, opid, EDC_OPENING_ERROR, NULL, NULL);
+       else if (!E_CAL_BACKEND_GET_CLASS (backend)->modify_objects)
+               e_data_cal_respond_modify_objects (cal, opid, EDC_ERROR (UnsupportedMethod), NULL, NULL);
        else if (!e_cal_backend_is_opened (backend))
-               e_data_cal_respond_modify_object (cal, opid, EDC_NOT_OPENED_ERROR, NULL, NULL);
+               e_data_cal_respond_modify_objects (cal, opid, EDC_NOT_OPENED_ERROR, NULL, NULL);
        else
-               (* E_CAL_BACKEND_GET_CLASS (backend)->modify_object) (backend, cal, opid, cancellable, calobj, mod);
+               (* E_CAL_BACKEND_GET_CLASS (backend)->modify_objects) (backend, cal, opid, cancellable, calobjs, mod);
 }
 
 /**
- * e_cal_backend_remove_object:
+ * e_cal_backend_remove_objects:
  * @backend: an #ECalBackend
  * @cal: an #EDataCal
  * @opid: the ID to use for this operation
  * @cancellable: a #GCancellable for the operation
- * @uid: Unique identifier of the object to remove.
- * @rid: A recurrence ID.
+ * @ids: List of #ECalComponentId objects identifying the objects to remove
  * @mod: Type of removal.
  *
- * Removes an object in a calendar backend.  The backend will notify all of its
+ * Removes objects in a calendar backend.  The backend will notify all of its
  * clients about the change.
- * This might be finished with e_data_cal_respond_remove_object().
+ * This might be finished with e_data_cal_respond_remove_objects().
  **/
 void
-e_cal_backend_remove_object (ECalBackend *backend,
-                             EDataCal *cal,
-                             guint32 opid,
-                             GCancellable *cancellable,
-                             const gchar *uid,
-                             const gchar *rid,
-                             CalObjModType mod)
+e_cal_backend_remove_objects (ECalBackend *backend,
+                              EDataCal *cal,
+                              guint32 opid,
+                              GCancellable *cancellable,
+                              const GSList *ids,
+                              CalObjModType mod)
 {
        g_return_if_fail (backend != NULL);
        g_return_if_fail (E_IS_CAL_BACKEND (backend));
-       g_return_if_fail (uid != NULL);
-       g_return_if_fail (E_CAL_BACKEND_GET_CLASS (backend)->remove_object != NULL);
+       g_return_if_fail (ids != NULL);
+       g_return_if_fail (E_CAL_BACKEND_GET_CLASS (backend)->remove_objects != NULL);
 
        if (e_cal_backend_is_opening (backend))
-               e_data_cal_respond_remove_object (cal, opid, EDC_OPENING_ERROR, NULL, NULL, NULL);
+               e_data_cal_respond_remove_objects (cal, opid, EDC_OPENING_ERROR, NULL, NULL, NULL);
        else if (!e_cal_backend_is_opened (backend))
-               e_data_cal_respond_remove_object (cal, opid, EDC_NOT_OPENED_ERROR, NULL, NULL, NULL);
+               e_data_cal_respond_remove_objects (cal, opid, EDC_NOT_OPENED_ERROR, NULL, NULL, NULL);
        else
-               (* E_CAL_BACKEND_GET_CLASS (backend)->remove_object) (backend, cal, opid, cancellable, uid, rid, mod);
+               (* E_CAL_BACKEND_GET_CLASS (backend)->remove_objects) (backend, cal, opid, cancellable, ids, mod);
 }
 
 /**
index 13cf488..20e99d0 100644 (file)
@@ -160,9 +160,9 @@ struct _ECalBackendClass {
        void    (* get_object)                  (ECalBackend *backend, EDataCal *cal, guint32 opid, GCancellable *cancellable, const gchar *uid, const gchar *rid);
        void    (* get_object_list)             (ECalBackend *backend, EDataCal *cal, guint32 opid, GCancellable *cancellable, const gchar *sexp);
        void    (* get_free_busy)               (ECalBackend *backend, EDataCal *cal, guint32 opid, GCancellable *cancellable, const GSList *users, time_t start, time_t end);
-       void    (* create_object)               (ECalBackend *backend, EDataCal *cal, guint32 opid, GCancellable *cancellable, const gchar *calobj);
-       void    (* modify_object)               (ECalBackend *backend, EDataCal *cal, guint32 opid, GCancellable *cancellable, const gchar *calobj, CalObjModType mod);
-       void    (* remove_object)               (ECalBackend *backend, EDataCal *cal, guint32 opid, GCancellable *cancellable, const gchar *uid, const gchar *rid, CalObjModType mod);
+       void    (* create_objects)              (ECalBackend *backend, EDataCal *cal, guint32 opid, GCancellable *cancellable, const GSList *calobjs);
+       void    (* modify_objects)              (ECalBackend *backend, EDataCal *cal, guint32 opid, GCancellable *cancellable, const GSList *calobjs, CalObjModType mod);
+       void    (* remove_objects)              (ECalBackend *backend, EDataCal *cal, guint32 opid, GCancellable *cancellable, const GSList *ids, CalObjModType mod);
        void    (* receive_objects)             (ECalBackend *backend, EDataCal *cal, guint32 opid, GCancellable *cancellable, const gchar *calobj);
        void    (* send_objects)                (ECalBackend *backend, EDataCal *cal, guint32 opid, GCancellable *cancellable, const gchar *calobj);
        void    (* get_attachment_uris)         (ECalBackend *backend, EDataCal *cal, guint32 opid, GCancellable *cancellable, const gchar *uid, const gchar *rid);
@@ -212,9 +212,9 @@ void                e_cal_backend_refresh                   (ECalBackend *backend, EDataCal *cal, guint32 opid
 void           e_cal_backend_get_object                (ECalBackend *backend, EDataCal *cal, guint32 opid, GCancellable *cancellable, const gchar *uid, const gchar *rid);
 void           e_cal_backend_get_object_list           (ECalBackend *backend, EDataCal *cal, guint32 opid, GCancellable *cancellable, const gchar *sexp);
 void           e_cal_backend_get_free_busy             (ECalBackend *backend, EDataCal *cal, guint32 opid, GCancellable *cancellable, const GSList *users, time_t start, time_t end);
-void           e_cal_backend_create_object             (ECalBackend *backend, EDataCal *cal, guint32 opid, GCancellable *cancellable, const gchar *calobj);
-void           e_cal_backend_modify_object             (ECalBackend *backend, EDataCal *cal, guint32 opid, GCancellable *cancellable, const gchar *calobj, CalObjModType mod);
-void           e_cal_backend_remove_object             (ECalBackend *backend, EDataCal *cal, guint32 opid, GCancellable *cancellable, const gchar *uid, const gchar *rid, CalObjModType mod);
+void           e_cal_backend_create_objects            (ECalBackend *backend, EDataCal *cal, guint32 opid, GCancellable *cancellable, const GSList *calobjs);
+void           e_cal_backend_modify_objects            (ECalBackend *backend, EDataCal *cal, guint32 opid, GCancellable *cancellable, const GSList *calobjs, CalObjModType mod);
+void           e_cal_backend_remove_objects            (ECalBackend *backend, EDataCal *cal, guint32 opid, GCancellable *cancellable, const GSList *ids, CalObjModType mod);
 void           e_cal_backend_receive_objects           (ECalBackend *backend, EDataCal *cal, guint32 opid, GCancellable *cancellable, const gchar *calobj);
 void           e_cal_backend_send_objects              (ECalBackend *backend, EDataCal *cal, guint32 opid, GCancellable *cancellable, const gchar *calobj);
 void           e_cal_backend_get_attachment_uris       (ECalBackend *backend, EDataCal *cal, guint32 opid, GCancellable *cancellable, const gchar *uid, const gchar *rid);
index df1f682..680baf4 100644 (file)
@@ -71,9 +71,9 @@ typedef enum {
        OP_GET_OBJECT,
        OP_GET_OBJECT_LIST,
        OP_GET_FREE_BUSY,
-       OP_CREATE_OBJECT,
-       OP_MODIFY_OBJECT,
-       OP_REMOVE_OBJECT,
+       OP_CREATE_OBJECTS,
+       OP_MODIFY_OBJECTS,
+       OP_REMOVE_OBJECTS,
        OP_RECEIVE_OBJECTS,
        OP_SEND_OBJECTS,
        OP_GET_ATTACHMENT_URIS,
@@ -117,21 +117,21 @@ typedef struct {
                        time_t start, end;
                        GSList *users;
                } fb;
-               /* OP_CREATE_OBJECT */
+               /* OP_CREATE_OBJECTS */
+               GSList *calobjs;
                /* OP_RECEIVE_OBJECTS */
                /* OP_SEND_OBJECTS */
                struct _co {
                        gchar *calobj;
                } co;
-               /* OP_MODIFY_OBJECT */
+               /* OP_MODIFY_OBJECTS */
                struct _mo {
-                       gchar *calobj;
+                       GSList *calobjs;
                        EDataCalObjModType mod;
                } mo;
-               /* OP_REMOVE_OBJECT */
+               /* OP_REMOVE_OBJECTS */
                struct _ro {
-                       gchar *uid;
-                       gchar *rid;
+                       GSList *ids;
                        EDataCalObjModType mod;
                } ro;
                /* OP_GET_TIMEZONE */
@@ -214,21 +214,19 @@ operation_thread (gpointer data,
                break;
        case OP_GET_FREE_BUSY:
                e_cal_backend_get_free_busy (backend, op->cal, op->id, op->cancellable, op->d.fb.users, op->d.fb.start, op->d.fb.end);
-               g_slist_foreach (op->d.fb.users, (GFunc) g_free, NULL);
-               g_slist_free (op->d.fb.users);
+               g_slist_free_full (op->d.fb.users, g_free);
                break;
-       case OP_CREATE_OBJECT:
-               e_cal_backend_create_object (backend, op->cal, op->id, op->cancellable, op->d.co.calobj);
-               g_free (op->d.co.calobj);
+       case OP_CREATE_OBJECTS:
+               e_cal_backend_create_objects (backend, op->cal, op->id, op->cancellable, op->d.calobjs);
+               g_slist_free_full (op->d.calobjs, g_free);
                break;
-       case OP_MODIFY_OBJECT:
-               e_cal_backend_modify_object (backend, op->cal, op->id, op->cancellable, op->d.mo.calobj, op->d.mo.mod);
-               g_free (op->d.mo.calobj);
+       case OP_MODIFY_OBJECTS:
+               e_cal_backend_modify_objects (backend, op->cal, op->id, op->cancellable, op->d.mo.calobjs, op->d.mo.mod);
+               g_slist_free_full (op->d.mo.calobjs, g_free);
                break;
-       case OP_REMOVE_OBJECT:
-               e_cal_backend_remove_object (backend, op->cal, op->id, op->cancellable, op->d.ro.uid, op->d.ro.rid && *op->d.ro.rid ? op->d.ro.rid : NULL, op->d.ro.mod);
-               g_free (op->d.ro.uid);
-               g_free (op->d.ro.rid);
+       case OP_REMOVE_OBJECTS:
+               e_cal_backend_remove_objects (backend, op->cal, op->id, op->cancellable, op->d.ro.ids, op->d.ro.mod);
+               g_slist_free_full (op->d.ro.ids, (GDestroyNotify)e_cal_component_free_id);
                break;
        case OP_RECEIVE_OBJECTS:
                e_cal_backend_receive_objects (backend, op->cal, op->id, op->cancellable, op->d.co.calobj);
@@ -679,55 +677,55 @@ impl_Cal_get_free_busy (EGdbusCal *object,
 }
 
 static gboolean
-impl_Cal_create_object (EGdbusCal *object,
-                        GDBusMethodInvocation *invocation,
-                        const gchar *in_calobj,
-                        EDataCal *cal)
+impl_Cal_create_objects (EGdbusCal *object,
+                         GDBusMethodInvocation *invocation,
+                         const gchar * const *in_calobjs,
+                         EDataCal *cal)
 {
        OperationData *op;
 
-       op = op_new (OP_CREATE_OBJECT, cal);
-       op->d.co.calobj = g_strdup (in_calobj);
+       op = op_new (OP_CREATE_OBJECTS, cal);
+       op->d.calobjs = e_util_strv_to_slist (in_calobjs);
 
-       e_gdbus_cal_complete_create_object (cal->priv->gdbus_object, invocation, op->id);
+       e_gdbus_cal_complete_create_objects (cal->priv->gdbus_object, invocation, op->id);
        e_operation_pool_push (ops_pool, op);
 
        return TRUE;
 }
 
 static gboolean
-impl_Cal_modify_object (EGdbusCal *object,
-                        GDBusMethodInvocation *invocation,
-                        const gchar * const *in_calobj_mod,
-                        EDataCal *cal)
+impl_Cal_modify_objects (EGdbusCal *object,
+                         GDBusMethodInvocation *invocation,
+                         const gchar * const *in_mod_calobjs,
+                         EDataCal *cal)
 {
        OperationData *op;
        guint mod;
 
-       op = op_new (OP_MODIFY_OBJECT, cal);
-       g_return_val_if_fail (e_gdbus_cal_decode_modify_object (in_calobj_mod, &op->d.mo.calobj, &mod), FALSE);
+       op = op_new (OP_MODIFY_OBJECTS, cal);
+       g_return_val_if_fail (e_gdbus_cal_decode_modify_objects (in_mod_calobjs, &op->d.mo.calobjs, &mod), FALSE);
        op->d.mo.mod = mod;
 
-       e_gdbus_cal_complete_modify_object (cal->priv->gdbus_object, invocation, op->id);
+       e_gdbus_cal_complete_modify_objects (cal->priv->gdbus_object, invocation, op->id);
        e_operation_pool_push (ops_pool, op);
 
        return TRUE;
 }
 
 static gboolean
-impl_Cal_remove_object (EGdbusCal *object,
-                        GDBusMethodInvocation *invocation,
-                        const gchar * const *in_uid_rid_mod,
-                        EDataCal *cal)
+impl_Cal_remove_objects (EGdbusCal *object,
+                         GDBusMethodInvocation *invocation,
+                         const gchar * const *in_mod_ids,
+                         EDataCal *cal)
 {
        OperationData *op;
        guint mod = 0;
 
-       op = op_new (OP_REMOVE_OBJECT, cal);
-       g_return_val_if_fail (e_gdbus_cal_decode_remove_object (in_uid_rid_mod, &op->d.ro.uid, &op->d.ro.rid, &mod), FALSE);
+       op = op_new (OP_REMOVE_OBJECTS, cal);
+       g_return_val_if_fail (e_gdbus_cal_decode_remove_objects (in_mod_ids, &op->d.ro.ids, &mod), FALSE);
        op->d.ro.mod = mod;
 
-       e_gdbus_cal_complete_remove_object (cal->priv->gdbus_object, invocation, op->id);
+       e_gdbus_cal_complete_remove_objects (cal->priv->gdbus_object, invocation, op->id);
        e_operation_pool_push (ops_pool, op);
 
        return TRUE;
@@ -1163,102 +1161,125 @@ e_data_cal_respond_get_free_busy (EDataCal *cal,
 }
 
 /**
- * e_data_cal_respond_create_object:
+ * e_data_cal_respond_create_objects:
  * @cal: A calendar client interface.
  * @error: Operation error, if any, automatically freed if passed it.
- * @uid: UID of the object created.
- * @new_component: The newly created #ECalComponent.
+ * @uids: UIDs of the objects created.
+ * @new_components: The newly created #ECalComponent objects.
  *
- * Notifies listeners of the completion of the create_object method call.
+ * Notifies listeners of the completion of the create_objects method call.
  *
- * Since: 3.2
+ * Since: 3.6
  */
 void
-e_data_cal_respond_create_object (EDataCal *cal,
-                                  guint32 opid,
-                                  GError *error,
-                                  const gchar *uid,
-                                  /* const */ ECalComponent *new_component)
+e_data_cal_respond_create_objects (EDataCal *cal,
+                                   guint32 opid,
+                                   GError *error,
+                                   const GSList *uids,
+                                   /* const */ GSList *new_components)
 {
-       gchar *gdbus_uid = NULL;
+       gchar **array = NULL;
+       const GSList *l;
+       gint i = 0;
 
        op_complete (cal, opid);
 
+       array = g_new0 (gchar *, g_slist_length ((GSList *) uids) + 1);
+       for (l = uids; l != NULL; l = l->next) {
+               array[i++] = e_util_utf8_make_valid (l->data);
+       }
+
        /* Translators: This is prefix to a detailed error message */
        g_prefix_error (&error, "%s", _("Cannot create calendar object: "));
 
-       e_gdbus_cal_emit_create_object_done (cal->priv->gdbus_object, opid, error, e_util_ensure_gdbus_string (uid, &gdbus_uid));
+       e_gdbus_cal_emit_create_objects_done (cal->priv->gdbus_object, opid, error, (const gchar * const *)array);
 
-       g_free (gdbus_uid);
+       g_strfreev (array);
        if (error)
                g_error_free (error);
-       else
-               e_cal_backend_notify_component_created (cal->priv->backend, new_component);
+       else {
+               for (l = new_components; l; l = l->next) {
+                       e_cal_backend_notify_component_created (cal->priv->backend, l->data);
+               }
+       }
 }
 
 /**
- * e_data_cal_respond_modify_object:
+ * e_data_cal_respond_modify_objects:
  * @cal: A calendar client interface.
  * @error: Operation error, if any, automatically freed if passed it.
- * @old_component: The old #ECalComponent.
- * @new_component: The new #ECalComponent.
+ * @old_components: The old #ECalComponents.
+ * @new_components: The new #ECalComponents.
  *
- * Notifies listeners of the completion of the modify_object method call.
+ * Notifies listeners of the completion of the modify_objects method call.
  *
- * Since: 3.2
+ * Since: 3.6
  */
 void
-e_data_cal_respond_modify_object (EDataCal *cal,
-                                  guint32 opid,
-                                  GError *error,
-                                  /* const */ ECalComponent *old_component,
-                                  /* const */ ECalComponent *new_component)
+e_data_cal_respond_modify_objects (EDataCal *cal,
+                                   guint32 opid,
+                                   GError *error,
+                                   /* const */ GSList *old_components,
+                                   /* const */ GSList *new_components)
 {
        op_complete (cal, opid);
 
        /* Translators: This is prefix to a detailed error message */
        g_prefix_error (&error, "%s", _("Cannot modify calendar object: "));
 
-       e_gdbus_cal_emit_modify_object_done (cal->priv->gdbus_object, opid, error);
+       e_gdbus_cal_emit_modify_objects_done (cal->priv->gdbus_object, opid, error);
 
        if (error)
                g_error_free (error);
-       else
-               e_cal_backend_notify_component_modified (cal->priv->backend, old_component, new_component);
+       else {
+               const GSList *lold = old_components, *lnew = new_components;
+               while (lold && lnew) {
+                       e_cal_backend_notify_component_modified (cal->priv->backend, lold->data, lnew->data);
+                       lold = lold->next;
+                       lnew = lnew->next;
+               }
+       }
 }
 
 /**
- * e_data_cal_respond_remove_object:
+ * e_data_cal_respond_remove_objects:
  * @cal: A calendar client interface.
  * @error: Operation error, if any, automatically freed if passed it.
- * @id: ID of the removed object.
- * @old_component: The old #ECalComponent.
- * @new_component: The new #ECalComponent. This will not be NULL only
- * when removing instances of a recurring appointment.
+ * @ids: IDs of the removed objects.
+ * @old_components: The old #ECalComponents.
+ * @new_components: The new #ECalComponents. They will not be NULL only
+ * when removing instances of recurring appointments.
  *
- * Notifies listeners of the completion of the remove_object method call.
+ * Notifies listeners of the completion of the remove_objects method call.
  *
- * Since: 3.2
+ * Since: 3.6
  */
 void
-e_data_cal_respond_remove_object (EDataCal *cal,
+e_data_cal_respond_remove_objects (EDataCal *cal,
                                   guint32 opid,
                                   GError *error,
-                                  const ECalComponentId *id,
-                                  /* const */ ECalComponent *old_component,
-                                  /* const */ ECalComponent *new_component)
+                                  const GSList *ids,
+                                  /* const */ GSList *old_components,
+                                  /* const */ GSList *new_components)
 {
        op_complete (cal, opid);
 
        /* Translators: This is prefix to a detailed error message */
        g_prefix_error (&error, "%s", _("Cannot remove calendar object: "));
 
-       e_gdbus_cal_emit_remove_object_done (cal->priv->gdbus_object, opid, error);
+       e_gdbus_cal_emit_remove_objects_done (cal->priv->gdbus_object, opid, error);
 
        if (error)
                g_error_free (error);
-       else
-               e_cal_backend_notify_component_removed (cal->priv->backend, id, old_component, new_component);
+       else {
+               const GSList *lid = ids, *lold = old_components, *lnew = new_components;
+               while (lid && lold && lnew) {
+                       e_cal_backend_notify_component_removed (cal->priv->backend, lid->data, lold->data, lnew->data);
+                       lid = lid->next;
+                       lold = lold->next;
+                       lnew = lnew->next;
+               }
+       }
 }
 
 /**
@@ -1768,14 +1789,14 @@ e_data_cal_init (EDataCal *ecal)
                gdbus_object, "handle-get-free-busy",
                G_CALLBACK (impl_Cal_get_free_busy), ecal);
        g_signal_connect (
-               gdbus_object, "handle-create-object",
-               G_CALLBACK (impl_Cal_create_object), ecal);
+               gdbus_object, "handle-create-objects",
+               G_CALLBACK (impl_Cal_create_objects), ecal);
        g_signal_connect (
-               gdbus_object, "handle-modify-object",
-               G_CALLBACK (impl_Cal_modify_object), ecal);
+               gdbus_object, "handle-modify-objects",
+               G_CALLBACK (impl_Cal_modify_objects), ecal);
        g_signal_connect (
-               gdbus_object, "handle-remove-object",
-               G_CALLBACK (impl_Cal_remove_object), ecal);
+               gdbus_object, "handle-remove-objects",
+               G_CALLBACK (impl_Cal_remove_objects), ecal);
        g_signal_connect (
                gdbus_object, "handle-receive-objects",
                G_CALLBACK (impl_Cal_receive_objects), ecal);
index f9c5ecd..15daa43 100644 (file)
@@ -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 */ ECalComponent *new_component);
-void           e_data_cal_respond_modify_object                (EDataCal *cal, guint32 opid, GError *error, /* const */ ECalComponent *old_component, /* const */ ECalComponent *new_component);
-void           e_data_cal_respond_remove_object                (EDataCal *cal, guint32 opid, GError *error, const ECalComponentId *id, /* const */ ECalComponent *old_component, /* const */ ECalComponent *new_component);
+void           e_data_cal_respond_create_objects               (EDataCal *cal, guint32 opid, GError *error, const GSList *uids, /*const */ GSList *new_components);
+void           e_data_cal_respond_modify_objects               (EDataCal *cal, guint32 opid, GError *error, /* const */ GSList *old_components, /* const */ GSList *new_components);
+void           e_data_cal_respond_remove_objects               (EDataCal *cal, guint32 opid, GError *error, const GSList *ids, /* const */ GSList *old_components, /* const */ GSList *new_components);
 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 *attachment_uris);
index 8c9212a..c8edbd8 100644 (file)
@@ -25,6 +25,8 @@
 
 #include <libedataserver/e-data-server-util.h>
 #include <libedataserver/e-gdbus-marshallers.h>
+/* We only need the ECalComponentId structure from the following header */
+#include <libecal/e-cal-component.h>
 
 #include "e-gdbus-cal.h"
 
@@ -63,12 +65,12 @@ enum
        __GET_OBJECT_LIST_DONE_SIGNAL,
        __GET_FREE_BUSY_METHOD,
        __GET_FREE_BUSY_DONE_SIGNAL,
-       __CREATE_OBJECT_METHOD,
-       __CREATE_OBJECT_DONE_SIGNAL,
-       __MODIFY_OBJECT_METHOD,
-       __MODIFY_OBJECT_DONE_SIGNAL,
-       __REMOVE_OBJECT_METHOD,
-       __REMOVE_OBJECT_DONE_SIGNAL,
+       __CREATE_OBJECTS_METHOD,
+       __CREATE_OBJECTS_DONE_SIGNAL,
+       __MODIFY_OBJECTS_METHOD,
+       __MODIFY_OBJECTS_DONE_SIGNAL,
+       __REMOVE_OBJECTS_METHOD,
+       __REMOVE_OBJECTS_DONE_SIGNAL,
        __RECEIVE_OBJECTS_METHOD,
        __RECEIVE_OBJECTS_DONE_SIGNAL,
        __SEND_OBJECTS_METHOD,
@@ -163,12 +165,12 @@ E_DECLARE_GDBUS_METHOD_DONE_EMISSION_HOOK_ASYNC_STRV (GDBUS_CAL_INTERFACE_NAME,
                                                       get_object_list)
 E_DECLARE_GDBUS_METHOD_DONE_EMISSION_HOOK_ASYNC_VOID (GDBUS_CAL_INTERFACE_NAME,
                                                       get_free_busy)
-E_DECLARE_GDBUS_METHOD_DONE_EMISSION_HOOK_ASYNC_STRING (GDBUS_CAL_INTERFACE_NAME,
-                                                        create_object)
+E_DECLARE_GDBUS_METHOD_DONE_EMISSION_HOOK_ASYNC_STRV (GDBUS_CAL_INTERFACE_NAME,
+                                                                                                         create_objects)
 E_DECLARE_GDBUS_METHOD_DONE_EMISSION_HOOK_ASYNC_VOID (GDBUS_CAL_INTERFACE_NAME,
-                                                      modify_object)
+                                                                                                         modify_objects)
 E_DECLARE_GDBUS_METHOD_DONE_EMISSION_HOOK_ASYNC_VOID (GDBUS_CAL_INTERFACE_NAME,
-                                                      remove_object)
+                                                      remove_objects)
 E_DECLARE_GDBUS_METHOD_DONE_EMISSION_HOOK_ASYNC_VOID (GDBUS_CAL_INTERFACE_NAME,
                                                       receive_objects)
 E_DECLARE_GDBUS_METHOD_DONE_EMISSION_HOOK_ASYNC_STRV (GDBUS_CAL_INTERFACE_NAME,
@@ -211,9 +213,9 @@ e_gdbus_cal_default_init (EGdbusCalIface *iface)
        E_INIT_GDBUS_METHOD_ASYNC_STRV__STRING  (EGdbusCalIface, "get_object",                  get_object, __GET_OBJECT_METHOD, __GET_OBJECT_DONE_SIGNAL)
        E_INIT_GDBUS_METHOD_ASYNC_STRING__STRV  (EGdbusCalIface, "get_object_list",             get_object_list, __GET_OBJECT_LIST_METHOD, __GET_OBJECT_LIST_DONE_SIGNAL)
        E_INIT_GDBUS_METHOD_ASYNC_STRV__VOID    (EGdbusCalIface, "get_free_busy",               get_free_busy, __GET_FREE_BUSY_METHOD, __GET_FREE_BUSY_DONE_SIGNAL)
-       E_INIT_GDBUS_METHOD_ASYNC_STRING__STRING(EGdbusCalIface, "create_object",               create_object, __CREATE_OBJECT_METHOD, __CREATE_OBJECT_DONE_SIGNAL)
-       E_INIT_GDBUS_METHOD_ASYNC_STRV__VOID    (EGdbusCalIface, "modify_object",               modify_object, __MODIFY_OBJECT_METHOD, __MODIFY_OBJECT_DONE_SIGNAL)
-       E_INIT_GDBUS_METHOD_ASYNC_STRV__VOID    (EGdbusCalIface, "remove_object",               remove_object, __REMOVE_OBJECT_METHOD, __REMOVE_OBJECT_DONE_SIGNAL)
+       E_INIT_GDBUS_METHOD_ASYNC_STRV__STRV    (EGdbusCalIface, "create_objects",              create_objects, __CREATE_OBJECTS_METHOD, __CREATE_OBJECTS_DONE_SIGNAL)
+       E_INIT_GDBUS_METHOD_ASYNC_STRV__VOID    (EGdbusCalIface, "modify_objects",              modify_objects, __MODIFY_OBJECTS_METHOD, __MODIFY_OBJECTS_DONE_SIGNAL)
+       E_INIT_GDBUS_METHOD_ASYNC_STRV__VOID    (EGdbusCalIface, "remove_objects",              remove_objects, __REMOVE_OBJECTS_METHOD, __REMOVE_OBJECTS_DONE_SIGNAL)
        E_INIT_GDBUS_METHOD_ASYNC_STRING__VOID  (EGdbusCalIface, "receive_objects",             receive_objects, __RECEIVE_OBJECTS_METHOD, __RECEIVE_OBJECTS_DONE_SIGNAL)
        E_INIT_GDBUS_METHOD_ASYNC_STRING__STRV  (EGdbusCalIface, "send_objects",                send_objects, __SEND_OBJECTS_METHOD, __SEND_OBJECTS_DONE_SIGNAL)
        E_INIT_GDBUS_METHOD_ASYNC_STRV__STRV    (EGdbusCalIface, "get_attachment_uris",         get_attachment_uris, __GET_ATTACHMENT_URIS_METHOD, __GET_ATTACHMENT_URIS_DONE_SIGNAL)
@@ -547,170 +549,199 @@ e_gdbus_cal_call_get_free_busy_sync (GDBusProxy *proxy,
 }
 
 void
-e_gdbus_cal_call_create_object (GDBusProxy *proxy,
-                                const gchar *in_calobj,
-                                GCancellable *cancellable,
-                                GAsyncReadyCallback callback,
-                                gpointer user_data)
+e_gdbus_cal_call_create_objects (GDBusProxy *proxy,
+                                 const gchar * const *in_calobjs,
+                                 GCancellable *cancellable,
+                                 GAsyncReadyCallback callback,
+                                 gpointer user_data)
 {
-       e_gdbus_proxy_call_string ("create_object", e_gdbus_cal_call_create_object, E_GDBUS_ASYNC_OP_KEEPER (proxy), in_calobj, cancellable, callback, user_data);
+       e_gdbus_proxy_call_strv ("create_objects", e_gdbus_cal_call_create_objects, E_GDBUS_ASYNC_OP_KEEPER (proxy), in_calobjs, cancellable, callback, user_data);
 }
 
 gboolean
-e_gdbus_cal_call_create_object_finish (GDBusProxy *proxy,
-                                       GAsyncResult *result,
-                                       gchar **out_uid,
-                                       GError **error)
+e_gdbus_cal_call_create_objects_finish (GDBusProxy *proxy,
+                                        GAsyncResult *result,
+                                        gchar ***out_uids,
+                                        GError **error)
 {
-       return e_gdbus_proxy_finish_call_string (E_GDBUS_ASYNC_OP_KEEPER (proxy), result, out_uid, error, e_gdbus_cal_call_create_object);
+       return e_gdbus_proxy_finish_call_strv (E_GDBUS_ASYNC_OP_KEEPER (proxy), result, out_uids, error, e_gdbus_cal_call_create_objects);
 }
 
 gboolean
-e_gdbus_cal_call_create_object_sync (GDBusProxy *proxy,
-                                     const gchar *in_calobj,
-                                     gchar **out_uid,
-                                     GCancellable *cancellable,
-                                     GError **error)
+e_gdbus_cal_call_create_objects_sync (GDBusProxy *proxy,
+                                      const gchar * const *in_calobjs,
+                                      gchar ***out_uids,
+                                      GCancellable *cancellable,
+                                      GError **error)
 {
-       return e_gdbus_proxy_call_sync_string__string (proxy, in_calobj, out_uid, cancellable, error,
-               e_gdbus_cal_call_create_object,
-               e_gdbus_cal_call_create_object_finish);
+       return e_gdbus_proxy_call_sync_strv__strv (proxy, in_calobjs, out_uids, cancellable, error,
+               e_gdbus_cal_call_create_objects,
+               e_gdbus_cal_call_create_objects_finish);
 }
 
 /* free returned pointer with g_strfreev() */
 gchar **
-e_gdbus_cal_encode_modify_object (const gchar *in_calobj,
-                                  guint in_mod)
+e_gdbus_cal_encode_modify_objects (const GSList *in_calobjs,
+                                   guint in_mod)
 {
        gchar **strv;
+       const GSList *l;
+       gint i = 0;
 
-       g_return_val_if_fail (in_calobj != NULL, NULL);
+       g_return_val_if_fail (in_calobjs != NULL, NULL);
 
-       strv = g_new0 (gchar *, 3);
-       strv[0] = e_util_utf8_make_valid (in_calobj);
-       strv[1] = g_strdup_printf ("%u", (guint32) in_mod);
-       strv[2] = NULL;
+       strv = g_new0 (gchar *, g_slist_length ((GSList *)in_calobjs) + 2);
+       strv[i++] = g_strdup_printf ("%u", (guint32) in_mod);
+
+       for (l = in_calobjs; l; l = l->next) {
+               strv[i++] = e_util_utf8_make_valid ((gchar *) l->data);
+       }
+
+       strv[i] = NULL;
 
        return strv;
 }
 
-/* free out_calobj with g_free() */
+/* free calobjs with g_slist_free_full(calobjs, g_free) */
 gboolean
-e_gdbus_cal_decode_modify_object (const gchar * const *in_strv,
-                                  gchar **out_calobj,
-                                  guint *out_mod)
+e_gdbus_cal_decode_modify_objects (const gchar * const *in_strv,
+                                   GSList **calobjs,
+                                   guint *out_mod)
 {
+       gint ii;
+
        g_return_val_if_fail (in_strv != NULL, FALSE);
        g_return_val_if_fail (in_strv[0] != NULL, FALSE);
        g_return_val_if_fail (in_strv[1] != NULL, FALSE);
-       g_return_val_if_fail (in_strv[2] == NULL, FALSE);
-       g_return_val_if_fail (out_calobj != NULL, FALSE);
+       g_return_val_if_fail (calobjs != NULL, FALSE);
        g_return_val_if_fail (out_mod != NULL, FALSE);
 
-       *out_calobj = g_strdup (in_strv[0]);
-       *out_mod = atoi (in_strv[1]);
+       *out_mod = atoi (in_strv[0]);
+       *calobjs = NULL;
+
+       for (ii = 1; in_strv[ii]; ii++) {
+               *calobjs = g_slist_prepend (*calobjs, g_strdup (in_strv[ii]));
+       }
+
+       *calobjs = g_slist_reverse (*calobjs);
 
        return TRUE;
 }
 
 void
-e_gdbus_cal_call_modify_object (GDBusProxy *proxy,
-                                const gchar * const *in_calobj_mod,
-                                GCancellable *cancellable,
-                                GAsyncReadyCallback callback,
-                                gpointer user_data)
+e_gdbus_cal_call_modify_objects (GDBusProxy *proxy,
+                                 const gchar * const *in_mod_calobjs,
+                                 GCancellable *cancellable,
+                                 GAsyncReadyCallback callback,
+                                 gpointer user_data)
 {
-       e_gdbus_proxy_call_strv ("modify_object", e_gdbus_cal_call_modify_object, E_GDBUS_ASYNC_OP_KEEPER (proxy), in_calobj_mod, cancellable, callback, user_data);
+       e_gdbus_proxy_call_strv ("modify_objects", e_gdbus_cal_call_modify_objects, E_GDBUS_ASYNC_OP_KEEPER (proxy), in_mod_calobjs, cancellable, callback, user_data);
 }
 
 gboolean
-e_gdbus_cal_call_modify_object_finish (GDBusProxy *proxy,
-                                       GAsyncResult *result,
-                                       GError **error)
+e_gdbus_cal_call_modify_objects_finish (GDBusProxy *proxy,
+                                        GAsyncResult *result,
+                                        GError **error)
 {
-       return e_gdbus_proxy_finish_call_void (E_GDBUS_ASYNC_OP_KEEPER (proxy), result, error, e_gdbus_cal_call_modify_object);
+       return e_gdbus_proxy_finish_call_void (E_GDBUS_ASYNC_OP_KEEPER (proxy), result, error, e_gdbus_cal_call_modify_objects);
 }
 
 gboolean
-e_gdbus_cal_call_modify_object_sync (GDBusProxy *proxy,
-                                     const gchar * const *in_calobj_mod,
-                                     GCancellable *cancellable,
-                                     GError **error)
+e_gdbus_cal_call_modify_objects_sync (GDBusProxy *proxy,
+                                      const gchar * const *in_mod_calobjs,
+                                      GCancellable *cancellable,
+                                      GError **error)
 {
-       return e_gdbus_proxy_call_sync_strv__void (proxy, in_calobj_mod, cancellable, error,
-               e_gdbus_cal_call_modify_object,
-               e_gdbus_cal_call_modify_object_finish);
+       return e_gdbus_proxy_call_sync_strv__void (proxy, in_mod_calobjs, cancellable, error,
+               e_gdbus_cal_call_modify_objects,
+               e_gdbus_cal_call_modify_objects_finish);
 }
 
 /* free returned pointer with g_strfreev() */
 gchar **
-e_gdbus_cal_encode_remove_object (const gchar *in_uid,
-                                  const gchar *in_rid,
-                                  guint in_mod)
+e_gdbus_cal_encode_remove_objects (const GSList *in_ids,
+                                   guint in_mod)
 {
        gchar **strv;
+       const GSList *l;
+       gint i = 0;
 
-       g_return_val_if_fail (in_uid != NULL, NULL);
+       g_return_val_if_fail (in_ids != NULL, NULL);
 
-       strv = g_new0 (gchar *, 4);
-       strv[0] = e_util_utf8_make_valid (in_uid);
-       strv[1] = e_util_utf8_make_valid (in_rid ? in_rid : "");
-       strv[2] = g_strdup_printf ("%u", (guint32) in_mod);
-       strv[3] = NULL;
+       strv = g_new0 (gchar *, 2 + 2 * g_slist_length ((GSList *)in_ids));
+       strv[i++] = g_strdup_printf ("%u", (guint32) in_mod);
+
+       for (l = in_ids; l; l = l->next) {
+               ECalComponentId *id = l->data;
+
+               strv[i++] = e_util_utf8_make_valid (id->uid);
+               strv[i++] = e_util_utf8_make_valid (id->rid ? id->rid : "");
+       }
+
+       strv[i] = NULL;
 
        return strv;
 }
 
-/* free out_uid and out_rid with g_free() */
+/* free ids g_slist_free_full(ids, g_free) */
 gboolean
-e_gdbus_cal_decode_remove_object (const gchar * const *in_strv,
-                                  gchar **out_uid,
-                                  gchar **out_rid,
-                                  guint *out_mod)
+e_gdbus_cal_decode_remove_objects (const gchar * const *in_strv,
+                                                                                                                                        GSList **out_ids,
+                                   guint *out_mod)
 {
+       gint ii;
+
        g_return_val_if_fail (in_strv != NULL, FALSE);
        g_return_val_if_fail (in_strv[0] != NULL, FALSE);
        g_return_val_if_fail (in_strv[1] != NULL, FALSE);
        g_return_val_if_fail (in_strv[2] != NULL, FALSE);
-       g_return_val_if_fail (in_strv[3] == NULL, FALSE);
-       g_return_val_if_fail (out_uid != NULL, FALSE);
-       g_return_val_if_fail (out_rid != NULL, FALSE);
+       g_return_val_if_fail (out_ids != NULL, FALSE);
        g_return_val_if_fail (out_mod != NULL, FALSE);
 
-       *out_uid = g_strdup (in_strv[0]);
-       *out_rid = g_strdup (in_strv[1]);
-       *out_mod = atoi (in_strv[2]);
+       *out_mod = atoi (in_strv[0]);
+
+       *out_ids = NULL;
+
+       for (ii = 1; in_strv[ii] && in_strv[ii + 1]; ii += 2) {
+               ECalComponentId *id = g_new (ECalComponentId, 1);
+               id->uid = g_strdup (in_strv[ii]);
+               id->rid = *in_strv[ii + 1] ? g_strdup (in_strv[ii + 1]) : NULL;
+
+               *out_ids = g_slist_prepend (*out_ids, id);
+       }
+
+       *out_ids = g_slist_reverse (*out_ids);
 
        return TRUE;
 }
 
 void
-e_gdbus_cal_call_remove_object (GDBusProxy *proxy,
-                                const gchar * const *in_uid_rid_mod,
-                                GCancellable *cancellable,
-                                GAsyncReadyCallback callback,
-                                gpointer user_data)
+e_gdbus_cal_call_remove_objects (GDBusProxy *proxy,
+                                 const gchar * const *in_mod_ids,
+                                 GCancellable *cancellable,
+                                 GAsyncReadyCallback callback,
+                                 gpointer user_data)
 {
-       e_gdbus_proxy_call_strv ("remove_object", e_gdbus_cal_call_remove_object, E_GDBUS_ASYNC_OP_KEEPER (proxy), in_uid_rid_mod, cancellable, callback, user_data);
+       e_gdbus_proxy_call_strv ("remove_objects", e_gdbus_cal_call_remove_objects, E_GDBUS_ASYNC_OP_KEEPER (proxy), in_mod_ids, cancellable, callback, user_data);
 }
 
 gboolean
-e_gdbus_cal_call_remove_object_finish (GDBusProxy *proxy,
-                                       GAsyncResult *result,
-                                       GError **error)
+e_gdbus_cal_call_remove_objects_finish (GDBusProxy *proxy,
+                                        GAsyncResult *result,
+                                        GError **error)
 {
-       return e_gdbus_proxy_finish_call_void (E_GDBUS_ASYNC_OP_KEEPER (proxy), result, error, e_gdbus_cal_call_remove_object);
+       return e_gdbus_proxy_finish_call_void (E_GDBUS_ASYNC_OP_KEEPER (proxy), result, error, e_gdbus_cal_call_remove_objects);
 }
 
 gboolean
-e_gdbus_cal_call_remove_object_sync (GDBusProxy *proxy,
-                                     const gchar * const *in_uid_rid_mod,
-                                     GCancellable *cancellable,
-                                     GError **error)
+e_gdbus_cal_call_remove_objects_sync (GDBusProxy *proxy,
+                                      const gchar * const *in_mod_ids,
+                                      GCancellable *cancellable,
+                                      GError **error)
 {
-       return e_gdbus_proxy_call_sync_strv__void (proxy, in_uid_rid_mod, cancellable, error,
-               e_gdbus_cal_call_remove_object,
-               e_gdbus_cal_call_remove_object_finish);
+       return e_gdbus_proxy_call_sync_strv__void (proxy, in_mod_ids, cancellable, error,
+               e_gdbus_cal_call_remove_objects,
+               e_gdbus_cal_call_remove_objects_finish);
 }
 
 void
@@ -1163,13 +1194,13 @@ DECLARE_EMIT_DONE_SIGNAL_1 (get_object_list,
                             const gchar * const *)
 DECLARE_EMIT_DONE_SIGNAL_0 (get_free_busy,
                             __GET_FREE_BUSY_DONE_SIGNAL)
-DECLARE_EMIT_DONE_SIGNAL_1 (create_object,
-                            __CREATE_OBJECT_DONE_SIGNAL,
-                            const gchar *)
-DECLARE_EMIT_DONE_SIGNAL_0 (modify_object,
-                            __MODIFY_OBJECT_DONE_SIGNAL)
-DECLARE_EMIT_DONE_SIGNAL_0 (remove_object,
-                            __REMOVE_OBJECT_DONE_SIGNAL)
+DECLARE_EMIT_DONE_SIGNAL_1 (create_objects,
+                            __CREATE_OBJECTS_DONE_SIGNAL,
+                            const gchar * const *)
+DECLARE_EMIT_DONE_SIGNAL_0 (modify_objects,
+                            __MODIFY_OBJECTS_DONE_SIGNAL)
+DECLARE_EMIT_DONE_SIGNAL_0 (remove_objects,
+                            __REMOVE_OBJECTS_DONE_SIGNAL)
 DECLARE_EMIT_DONE_SIGNAL_0 (receive_objects,
                             __RECEIVE_OBJECTS_DONE_SIGNAL)
 DECLARE_EMIT_DONE_SIGNAL_1 (send_objects,
@@ -1259,9 +1290,9 @@ E_DECLARE_GDBUS_ASYNC_METHOD_1                    (cal, set_backend_property, propnamevalue, "as"
 E_DECLARE_GDBUS_ASYNC_METHOD_1_WITH_RETURN     (cal, get_object, uid_rid, "as", object, "s")
 E_DECLARE_GDBUS_ASYNC_METHOD_1_WITH_RETURN     (cal, get_object_list, sexp, "s", objects, "as")
 E_DECLARE_GDBUS_ASYNC_METHOD_1                 (cal, get_free_busy, start_stop_users, "as")
-E_DECLARE_GDBUS_ASYNC_METHOD_1_WITH_RETURN     (cal, create_object, object, "s", uid, "s")
-E_DECLARE_GDBUS_ASYNC_METHOD_1                 (cal, modify_object, object_mod, "as")
-E_DECLARE_GDBUS_ASYNC_METHOD_1                 (cal, remove_object, uid_rid_mod, "as")
+E_DECLARE_GDBUS_ASYNC_METHOD_1_WITH_RETURN     (cal, create_objects, objects, "as", uids, "as")
+E_DECLARE_GDBUS_ASYNC_METHOD_1                 (cal, modify_objects, object_mod, "as")
+E_DECLARE_GDBUS_ASYNC_METHOD_1                 (cal, remove_objects, mod_ids, "as")
 E_DECLARE_GDBUS_ASYNC_METHOD_1                 (cal, receive_objects, object, "s")
 E_DECLARE_GDBUS_ASYNC_METHOD_1_WITH_RETURN     (cal, send_objects, object, "s", object_users, "as")
 E_DECLARE_GDBUS_ASYNC_METHOD_1_WITH_RETURN     (cal, get_attachment_uris, uid_rid, "as", attachments, "as")
@@ -1287,9 +1318,9 @@ static const GDBusMethodInfo * const e_gdbus_cal_method_info_pointers[] =
        &E_DECLARED_GDBUS_METHOD_INFO_NAME (cal, get_object),
        &E_DECLARED_GDBUS_METHOD_INFO_NAME (cal, get_object_list),
        &E_DECLARED_GDBUS_METHOD_INFO_NAME (cal, get_free_busy),
-       &E_DECLARED_GDBUS_METHOD_INFO_NAME (cal, create_object),
-       &E_DECLARED_GDBUS_METHOD_INFO_NAME (cal, modify_object),
-       &E_DECLARED_GDBUS_METHOD_INFO_NAME (cal, remove_object),
+       &E_DECLARED_GDBUS_METHOD_INFO_NAME (cal, create_objects),
+       &E_DECLARED_GDBUS_METHOD_INFO_NAME (cal, modify_objects),
+       &E_DECLARED_GDBUS_METHOD_INFO_NAME (cal, remove_objects),
        &E_DECLARED_GDBUS_METHOD_INFO_NAME (cal, receive_objects),
        &E_DECLARED_GDBUS_METHOD_INFO_NAME (cal, send_objects),
        &E_DECLARED_GDBUS_METHOD_INFO_NAME (cal, get_attachment_uris),
@@ -1322,9 +1353,9 @@ static const GDBusSignalInfo * const e_gdbus_cal_signal_info_pointers[] =
        &E_DECLARED_GDBUS_SIGNAL_INFO_NAME (cal, get_object_done),
        &E_DECLARED_GDBUS_SIGNAL_INFO_NAME (cal, get_object_list_done),
        &E_DECLARED_GDBUS_SIGNAL_INFO_NAME (cal, get_free_busy_done),
-       &E_DECLARED_GDBUS_SIGNAL_INFO_NAME (cal, create_object_done),
-       &E_DECLARED_GDBUS_SIGNAL_INFO_NAME (cal, modify_object_done),
-       &E_DECLARED_GDBUS_SIGNAL_INFO_NAME (cal, remove_object_done),
+       &E_DECLARED_GDBUS_SIGNAL_INFO_NAME (cal, create_objects_done),
+       &E_DECLARED_GDBUS_SIGNAL_INFO_NAME (cal, modify_objects_done),
+       &E_DECLARED_GDBUS_SIGNAL_INFO_NAME (cal, remove_objects_done),
        &E_DECLARED_GDBUS_SIGNAL_INFO_NAME (cal, receive_objects_done),
        &E_DECLARED_GDBUS_SIGNAL_INFO_NAME (cal, send_objects_done),
        &E_DECLARED_GDBUS_SIGNAL_INFO_NAME (cal, get_attachment_uris_done),
@@ -1561,9 +1592,9 @@ e_gdbus_cal_proxy_init (EGdbusCalProxy *proxy)
        E_GDBUS_CONNECT_METHOD_DONE_SIGNAL_STRING (get_object);
        E_GDBUS_CONNECT_METHOD_DONE_SIGNAL_STRV   (get_object_list);
        E_GDBUS_CONNECT_METHOD_DONE_SIGNAL_VOID   (get_free_busy);
-       E_GDBUS_CONNECT_METHOD_DONE_SIGNAL_STRING (create_object);
-       E_GDBUS_CONNECT_METHOD_DONE_SIGNAL_VOID   (modify_object);
-       E_GDBUS_CONNECT_METHOD_DONE_SIGNAL_VOID   (remove_object);
+       E_GDBUS_CONNECT_METHOD_DONE_SIGNAL_STRV   (create_objects);
+       E_GDBUS_CONNECT_METHOD_DONE_SIGNAL_VOID   (modify_objects);
+       E_GDBUS_CONNECT_METHOD_DONE_SIGNAL_VOID   (remove_objects);
        E_GDBUS_CONNECT_METHOD_DONE_SIGNAL_VOID   (receive_objects);
        E_GDBUS_CONNECT_METHOD_DONE_SIGNAL_STRV   (send_objects);
        E_GDBUS_CONNECT_METHOD_DONE_SIGNAL_STRV   (get_attachment_uris);
index 695d13b..7220f64 100644 (file)
@@ -136,14 +136,14 @@ struct _EGdbusCalIface
        gboolean (*handle_get_free_busy)                (EGdbusCal *object, GDBusMethodInvocation *invocation, const gchar * const *in_start_end_userlist);
        void     (*get_free_busy_done)                  (EGdbusCal *object, guint arg_opid, const GError *arg_error);
 
-       gboolean (*handle_create_object)                (EGdbusCal *object, GDBusMethodInvocation *invocation, const gchar *in_calobj);
-       void     (*create_object_done)                  (EGdbusCal *object, guint arg_opid, const GError *arg_error, gchar **out_uid);
+       gboolean (*handle_create_objects)               (EGdbusCal *object, GDBusMethodInvocation *invocation, const gchar *const *in_calobjs);
+       void     (*create_objects_done)                 (EGdbusCal *object, guint arg_opid, const GError *arg_error, gchar ***out_uids);
 
-       gboolean (*handle_modify_object)                (EGdbusCal *object, GDBusMethodInvocation *invocation, const gchar * const *in_calobj_mod);
-       void     (*modify_object_done)                  (EGdbusCal *object, guint arg_opid, const GError *arg_error);
+       gboolean (*handle_modify_objects)               (EGdbusCal *object, GDBusMethodInvocation *invocation, const gchar * const *in_mod_calobjs);
+       void     (*modify_objects_done)                 (EGdbusCal *object, guint arg_opid, const GError *arg_error);
 
-       gboolean (*handle_remove_object)                (EGdbusCal *object, GDBusMethodInvocation *invocation, const gchar * const *in_uid_rid_mod);
-       void     (*remove_object_done)                  (EGdbusCal *object, guint arg_opid, const GError *arg_error);
+       gboolean (*handle_remove_objects)               (EGdbusCal *object, GDBusMethodInvocation *invocation, const gchar * const *in_mod_ids);
+       void     (*remove_objects_done)                 (EGdbusCal *object, guint arg_opid, const GError *arg_error);
 
        gboolean (*handle_receive_objects)              (EGdbusCal *object, GDBusMethodInvocation *invocation, const gchar *in_calobj);
        void     (*receive_objects_done)                (EGdbusCal *object, guint arg_opid, const GError *arg_error);
@@ -211,21 +211,21 @@ void              e_gdbus_cal_call_get_free_busy                  (GDBusProxy *proxy, const gchar * const *
 gboolean       e_gdbus_cal_call_get_free_busy_finish           (GDBusProxy *proxy, GAsyncResult *result, GError **error);
 gboolean       e_gdbus_cal_call_get_free_busy_sync             (GDBusProxy *proxy, const gchar * const *in_start_end_userlist, GCancellable *cancellable, GError **error);
 
-void           e_gdbus_cal_call_create_object                  (GDBusProxy *proxy, const gchar *in_calobj, GCancellable *cancellable, GAsyncReadyCallback callback, gpointer user_data);
-gboolean       e_gdbus_cal_call_create_object_finish           (GDBusProxy *proxy, GAsyncResult *result, gchar **out_uid, GError **error);
-gboolean       e_gdbus_cal_call_create_object_sync             (GDBusProxy *proxy, const gchar *in_calobj, gchar **out_uid, GCancellable *cancellable, GError **error);
+void           e_gdbus_cal_call_create_objects                 (GDBusProxy *proxy, const gchar * const *in_calobjs, GCancellable *cancellable, GAsyncReadyCallback callback, gpointer user_data);
+gboolean       e_gdbus_cal_call_create_objects_finish  (GDBusProxy *proxy, GAsyncResult *result, gchar ***out_uids, GError **error);
+gboolean       e_gdbus_cal_call_create_objects_sync    (GDBusProxy *proxy, const gchar * const *in_calobjs, gchar ***out_uids, GCancellable *cancellable, GError **error);
 
-gchar **       e_gdbus_cal_encode_modify_object                (const gchar *in_calobj, guint in_mod);
-gboolean       e_gdbus_cal_decode_modify_object                (const gchar * const *in_strv, gchar **out_calobj, guint *out_mod);
-void           e_gdbus_cal_call_modify_object                  (GDBusProxy *proxy, const gchar * const *in_calobj_mod, GCancellable *cancellable, GAsyncReadyCallback callback, gpointer user_data);
-gboolean       e_gdbus_cal_call_modify_object_finish           (GDBusProxy *proxy, GAsyncResult *result, GError **error);
-gboolean       e_gdbus_cal_call_modify_object_sync             (GDBusProxy *proxy, const gchar * const *in_calobj_mod, GCancellable *cancellable, GError **error);
+gchar **       e_gdbus_cal_encode_modify_objects               (const GSList *in_calobjs, guint in_mod);
+gboolean       e_gdbus_cal_decode_modify_objects               (const gchar * const *in_strv, GSList **out_calobjs, guint *out_mod);
+void           e_gdbus_cal_call_modify_objects                 (GDBusProxy *proxy, const gchar * const *in_mod_calobjs, GCancellable *cancellable, GAsyncReadyCallback callback, gpointer user_data);
+gboolean       e_gdbus_cal_call_modify_objects_finish  (GDBusProxy *proxy, GAsyncResult *result, GError **error);
+gboolean       e_gdbus_cal_call_modify_objects_sync    (GDBusProxy *proxy, const gchar * const *in_mod_calobjs, GCancellable *cancellable, GError **error);
 
-gchar **       e_gdbus_cal_encode_remove_object                (const gchar *in_uid, const gchar *in_rid, guint in_mod);
-gboolean       e_gdbus_cal_decode_remove_object                (const gchar * const *in_strv, gchar **out_uid, gchar **out_rid, guint *out_mod);
-void           e_gdbus_cal_call_remove_object                  (GDBusProxy *proxy, const gchar * const *in_uid_rid_mod, GCancellable *cancellable, GAsyncReadyCallback callback, gpointer user_data);
-gboolean       e_gdbus_cal_call_remove_object_finish           (GDBusProxy *proxy, GAsyncResult *result, GError **error);
-gboolean       e_gdbus_cal_call_remove_object_sync             (GDBusProxy *proxy, const gchar * const *in_uid_rid_mod, GCancellable *cancellable, GError **error);
+gchar **       e_gdbus_cal_encode_remove_objects               (const GSList *in_ids, guint in_mod);
+gboolean       e_gdbus_cal_decode_remove_objects               (const gchar * const *in_strv, GSList **out_ids, guint *out_mod);
+void           e_gdbus_cal_call_remove_objects                 (GDBusProxy *proxy, const gchar * const *in_mod_ids, GCancellable *cancellable, GAsyncReadyCallback callback, gpointer user_data);
+gboolean       e_gdbus_cal_call_remove_objects_finish  (GDBusProxy *proxy, GAsyncResult *result, GError **error);
+gboolean       e_gdbus_cal_call_remove_objects_sync    (GDBusProxy *proxy, const gchar * const *in_mod_ids, GCancellable *cancellable, GError **error);
 
 void           e_gdbus_cal_call_receive_objects                (GDBusProxy *proxy, const gchar *in_calobj, GCancellable *cancellable, GAsyncReadyCallback callback, gpointer user_data);
 gboolean       e_gdbus_cal_call_receive_objects_finish         (GDBusProxy *proxy, GAsyncResult *result, GError **error);
@@ -286,9 +286,9 @@ gboolean    e_gdbus_cal_call_close_sync                     (GDBusProxy *proxy, GCancellable *cancell
 #define e_gdbus_cal_complete_get_object                        e_gdbus_complete_async_method
 #define e_gdbus_cal_complete_get_object_list           e_gdbus_complete_async_method
 #define e_gdbus_cal_complete_get_free_busy             e_gdbus_complete_async_method
-#define e_gdbus_cal_complete_create_object             e_gdbus_complete_async_method
-#define e_gdbus_cal_complete_modify_object             e_gdbus_complete_async_method
-#define e_gdbus_cal_complete_remove_object             e_gdbus_complete_async_method
+#define e_gdbus_cal_complete_create_objects            e_gdbus_complete_async_method
+#define e_gdbus_cal_complete_modify_objects            e_gdbus_complete_async_method
+#define e_gdbus_cal_complete_remove_objects            e_gdbus_complete_async_method
 #define e_gdbus_cal_complete_receive_objects           e_gdbus_complete_async_method
 #define e_gdbus_cal_complete_send_objects              e_gdbus_complete_async_method
 #define e_gdbus_cal_complete_get_attachment_uris       e_gdbus_complete_async_method
@@ -310,9 +310,9 @@ void e_gdbus_cal_emit_get_object_done                       (EGdbusCal *object, guint arg_opid, cons
 void e_gdbus_cal_emit_get_object_list_done             (EGdbusCal *object, guint arg_opid, const GError *arg_error, const gchar * const *out_objects);
 void e_gdbus_cal_emit_get_free_busy_done               (EGdbusCal *object, guint arg_opid, const GError *arg_error);
 void e_gdbus_cal_emit_get_free_busy_data               (EGdbusCal *object, guint arg_opid, const GError *arg_error, const gchar * const *out_freebusy);
-void e_gdbus_cal_emit_create_object_done               (EGdbusCal *object, guint arg_opid, const GError *arg_error, const gchar *out_uid);
-void e_gdbus_cal_emit_modify_object_done               (EGdbusCal *object, guint arg_opid, const GError *arg_error);
-void e_gdbus_cal_emit_remove_object_done               (EGdbusCal *object, guint arg_opid, const GError *arg_error);
+void e_gdbus_cal_emit_create_objects_done              (EGdbusCal *object, guint arg_opid, const GError *arg_error, const gchar * const *out_uids);
+void e_gdbus_cal_emit_modify_objects_done              (EGdbusCal *object, guint arg_opid, const GError *arg_error);
+void e_gdbus_cal_emit_remove_objects_done              (EGdbusCal *object, guint arg_opid, const GError *arg_error);
 void e_gdbus_cal_emit_receive_objects_done             (EGdbusCal *object, guint arg_opid, const GError *arg_error);
 void e_gdbus_cal_emit_send_objects_done                        (EGdbusCal *object, guint arg_opid, const GError *arg_error, const gchar * const *out_calobj_users);
 void e_gdbus_cal_emit_get_attachment_uris_done         (EGdbusCal *object, guint arg_opid, const GError *arg_error, const gchar * const *out_attachments);
index d9a9e33..ad9bac2 100644 (file)
@@ -61,7 +61,7 @@ dnl ******************************
 dnl D-Bus versioning
 dnl ******************************
 ADDRESS_BOOK_DBUS_SERVICE_NAME="org.gnome.evolution.dataserver.AddressBook3"
-CALENDAR_DBUS_SERVICE_NAME="org.gnome.evolution.dataserver.Calendar1"
+CALENDAR_DBUS_SERVICE_NAME="org.gnome.evolution.dataserver.Calendar2"
 
 AC_DEFINE_UNQUOTED(
        ADDRESS_BOOK_DBUS_SERVICE_NAME,
@@ -87,11 +87,11 @@ LIBEDATASERVERUI_CURRENT=1
 LIBEDATASERVERUI_REVISION=0
 LIBEDATASERVERUI_AGE=0
 
-LIBECAL_CURRENT=13
+LIBECAL_CURRENT=14
 LIBECAL_REVISION=2
 LIBECAL_AGE=2
 
-LIBEDATACAL_CURRENT=15
+LIBEDATACAL_CURRENT=16
 LIBEDATACAL_REVISION=0
 LIBEDATACAL_AGE=0
 
index c7211a2..a608fbd 100644 (file)
@@ -947,6 +947,26 @@ e_util_free_object_slist (GSList *objects)
 }
 
 /**
+ * e_util_free_nullable_object_slist:
+ * @objects: a #GSList of nullable #GObject-s
+ *
+ * Calls g_object_unref() on each member of @objects if non-NULL and then frees
+ * also @objects itself.
+ *
+ * Since: 3.6
+ **/
+void
+e_util_free_nullable_object_slist (GSList *objects)
+{
+       const GSList *l;
+       for (l = objects; l; l = l->next) {
+               if (l->data)
+                       g_object_unref (l->data);
+       }
+       g_slist_free (objects);
+}
+
+/**
  * e_binding_transform_enum_value_to_nick:
  * @binding: a #GBinding
  * @source_value: a #GValue whose type is derived from #G_TYPE_ENUM
index 8450c63..b68c460 100644 (file)
@@ -69,6 +69,7 @@ GSList *      e_util_copy_string_slist        (GSList *copy_to, const GSList *strings);
 GSList *       e_util_copy_object_slist        (GSList *copy_to, const GSList *objects);
 void           e_util_free_string_slist        (GSList *strings);
 void           e_util_free_object_slist        (GSList *objects);
+void           e_util_free_nullable_object_slist       (GSList *objects);
 
 /* Useful GBinding transform functions */
 gboolean       e_binding_transform_enum_value_to_nick
index 68037ca..af2b893 100644 (file)
@@ -31,6 +31,7 @@ TESTS =                                       \
        test-client-get-revision                \
        test-client-send-objects                \
        test-client-receive-objects             \
+        test-client-bulk-methods               \
        test-client-get-attachment-uris         \
        test-client-get-view                    \
        test-client-revision-view               \
@@ -77,6 +78,8 @@ test_client_open_LDADD=$(TEST_LIBS)
 test_client_open_CPPFLAGS=$(TEST_CPPFLAGS)
 test_client_receive_objects_LDADD=$(TEST_LIBS)
 test_client_receive_objects_CPPFLAGS=$(TEST_CPPFLAGS)
+test_client_bulk_methods_LDADD=$(TEST_LIBS)
+test_client_bulk_methods_CPPFLAGS=$(TEST_CPPFLAGS)
 test_client_refresh_LDADD=$(TEST_LIBS)
 test_client_refresh_CPPFLAGS=$(TEST_CPPFLAGS)
 test_client_remove_object_LDADD=$(TEST_LIBS)
diff --git a/tests/libecal/client/test-client-bulk-methods.c b/tests/libecal/client/test-client-bulk-methods.c
new file mode 100644 (file)
index 0000000..c4d9069
--- /dev/null
@@ -0,0 +1,253 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+
+#include <stdlib.h>
+#include <libecal/e-cal-client.h>
+#include <libical/ical.h>
+
+#include "client-test-utils.h"
+
+#define NB_COMPONENTS 5
+
+static gboolean
+test_icalcomps (icalcomponent *icalcomp1,
+                               icalcomponent *icalcomp2)
+{
+       struct icaltimetype t1, t2;
+
+       if (!icalcomp2) {
+               g_printerr ("Failure: get object returned NULL\n");
+               return FALSE;
+       }
+
+       if (g_strcmp0 (icalcomponent_get_uid (icalcomp1), icalcomponent_get_uid (icalcomp2)) != 0) {
+               g_printerr ("Failure: uid doesn't match, expected '%s', got '%s'\n", icalcomponent_get_uid (icalcomp1), icalcomponent_get_uid (icalcomp2));
+               return FALSE;
+       }
+
+       if (g_strcmp0 (icalcomponent_get_summary (icalcomp1), icalcomponent_get_summary (icalcomp2)) != 0) {
+               g_printerr ("Failure: summary doesn't match, expected '%s', got '%s'\n", icalcomponent_get_summary (icalcomp1), icalcomponent_get_summary (icalcomp2));
+               return FALSE;
+       }
+
+       t1 = icalcomponent_get_dtstart (icalcomp1);
+       t2 = icalcomponent_get_dtstart (icalcomp2);
+
+       if (icaltime_compare (t1, t2) != 0) {
+               g_printerr ("Failure: dtend doesn't match, expected '%s', got '%s'\n", icaltime_as_ical_string (t1), icaltime_as_ical_string (t2));
+               return FALSE;
+       }
+
+       t1 = icalcomponent_get_dtend (icalcomp1);
+       t2 = icalcomponent_get_dtend (icalcomp2);
+
+       if (icaltime_compare (t1, t2) != 0) {
+               g_printerr ("Failure: dtend doesn't match, expected '%s', got '%s'\n", icaltime_as_ical_string (t1), icaltime_as_ical_string (t2));
+               return FALSE;
+       }
+
+       return TRUE;
+}
+
+static gboolean
+check_removed (ECalClient *cal_client,
+                          const GSList *uids)
+{
+       g_return_val_if_fail (cal_client != NULL, FALSE);
+       g_return_val_if_fail (uids != NULL, FALSE);
+
+       while (uids) {
+               GError *error = NULL;
+               icalcomponent *icalcomp = NULL;
+
+               if (!e_cal_client_get_object_sync(cal_client, uids->data, NULL, &icalcomp, NULL, &error) &&
+                               g_error_matches (error, E_CAL_CLIENT_ERROR, E_CAL_CLIENT_ERROR_OBJECT_NOT_FOUND)) {
+                       g_clear_error (&error);
+               } else {
+                       report_error ("check objects removed sync", &error);
+                       icalcomponent_free (icalcomp);
+                       return FALSE;
+               }
+
+               uids = uids->next;
+       }
+
+       return TRUE;
+}
+
+static GSList *
+uid_slist_to_ecalcomponentid_slist(GSList *uids)
+{
+       GSList *ids = NULL;
+       const GSList *l;
+
+       for (l = uids; l; l = l->next) {
+               ECalComponentId *id = g_new0 (ECalComponentId, 1);
+               id->uid = g_strdup (l->data);
+               ids = g_slist_append (ids, id);
+       }
+
+       return ids;
+}
+
+static gboolean
+check_icalcomps_exist (ECalClient *cal_client,
+                                          GSList *icalcomps)
+{
+       const GSList *l;
+
+       for (l = icalcomps; l; l = l->next) {
+               GError *error = NULL;
+               icalcomponent *icalcomp = l->data;
+               icalcomponent *icalcomp2 = NULL;
+               const char *uid = icalcomponent_get_uid(icalcomp);
+
+               if (!e_cal_client_get_object_sync(cal_client, uid, NULL, &icalcomp2, NULL, &error)) {
+                       report_error ("get object sync", &error);
+                       return FALSE;
+               }
+
+               g_return_val_if_fail (icalcomp2 != NULL, FALSE);
+
+               if (!test_icalcomps (icalcomp, icalcomp2)) {
+                       icalcomponent_free (icalcomp2);
+                       return FALSE;
+               }
+
+               icalcomponent_free (icalcomp2);
+       }
+
+       return TRUE;
+}
+
+static gboolean
+test_bulk_methods(GSList *icalcomps)
+{
+       ECalClient *cal_client;
+       GError *error = NULL;
+       GSList *uids = NULL, *ids = NULL;
+       const GSList *lcomp, *luid;
+       gint i = 0;
+
+       g_return_val_if_fail (icalcomps != NULL, FALSE);
+
+       cal_client = new_temp_client (E_CAL_CLIENT_SOURCE_TYPE_EVENTS, NULL);
+       g_return_val_if_fail (cal_client != NULL, FALSE);
+
+       if (!e_client_open_sync (E_CLIENT (cal_client), FALSE, NULL, &error)) {
+               report_error ("client open sync", &error);
+               g_object_unref (cal_client);
+               return FALSE;
+       }
+
+       /* Create all the objects in bulk */
+       if (!e_cal_client_create_objects_sync (cal_client, icalcomps, &uids, NULL, &error)) {
+               report_error ("create objects sync", &error);
+               g_object_unref (cal_client);
+               return FALSE;
+       }
+
+       g_return_val_if_fail (uids != NULL, FALSE);
+       g_return_val_if_fail (g_slist_length (uids) == NB_COMPONENTS, FALSE);
+
+       /* Update icalcomponents uids */
+       luid = uids;
+       lcomp = icalcomps;
+       while (luid && lcomp) {
+               icalcomponent_set_uid (lcomp->data, luid->data);
+               luid = luid->next;
+               lcomp = lcomp->next;
+       }
+
+       /* Retrieve all the objects and check that they are the same */
+       if (!check_icalcomps_exist (cal_client, icalcomps)) {
+               g_object_unref (cal_client);
+               g_slist_free_full (uids, g_free);
+               return FALSE;
+       }
+
+       /* Modify the objects */
+       for (lcomp = icalcomps; lcomp; lcomp = lcomp->next) {
+               gchar *summary;
+               icalcomponent *icalcomp = lcomp->data;
+
+               summary = g_strdup_printf ("Edited test summary %d", i);
+               icalcomponent_set_summary(icalcomp, summary);
+
+               g_free (summary);
+               ++i;
+       }
+
+       /* Save the modified objects in bulk */
+       if (!e_cal_client_modify_objects_sync(cal_client, icalcomps, CALOBJ_MOD_ALL, NULL, &error)) {
+               report_error ("modify objects sync", &error);
+               g_object_unref (cal_client);
+               g_slist_free_full (uids, g_free);
+               return FALSE;
+       }
+
+       /* Retrieve all the objects and check that they have been modified */
+       if (!check_icalcomps_exist (cal_client, icalcomps)) {
+               g_object_unref (cal_client);
+               g_slist_free_full (uids, g_free);
+               return FALSE;
+       }
+
+       /* Remove all the objects in bulk */
+       ids = uid_slist_to_ecalcomponentid_slist (uids);
+
+       if (!e_cal_client_remove_objects_sync(cal_client, ids, CALOBJ_MOD_ALL, NULL, &error)) {
+               report_error ("remove objects sync", &error);
+               g_object_unref (cal_client);
+               g_slist_free_full (ids, (GDestroyNotify) e_cal_component_free_id);
+               g_slist_free_full (uids, g_free);
+               return FALSE;
+       }
+       g_slist_free_full (ids, (GDestroyNotify) e_cal_component_free_id);
+
+       /* Check that the objects don't exist anymore */
+       if (!check_removed(cal_client, uids)) {
+               g_object_unref (cal_client);
+               g_slist_free_full (uids, g_free);
+               return FALSE;
+       }
+
+       g_slist_free_full (uids, g_free);
+       g_object_unref (cal_client);
+       return TRUE;
+}
+
+gint
+main (gint argc,
+         gchar **argv)
+{
+       GSList *icalcomps = NULL;
+       struct icaltimetype now;
+       gint i;
+       gboolean res;
+
+       main_initialize ();
+
+       now = icaltime_current_time_with_zone (icaltimezone_get_utc_timezone ());
+
+       /* Build up new components */
+       for (i = 0; i < NB_COMPONENTS; ++i) {
+               icalcomponent *icalcomp;
+               gchar *summary;
+
+               icalcomp = icalcomponent_new (ICAL_VEVENT_COMPONENT);
+               summary = g_strdup_printf ("Test summary %d", i);
+               icalcomponent_set_summary (icalcomp, summary);
+               icalcomponent_set_dtstart (icalcomp, now);
+               icalcomponent_set_dtend   (icalcomp, icaltime_from_timet (icaltime_as_timet (now) + 60 * 60 * 60, 0));
+
+               icalcomps = g_slist_append (icalcomps, icalcomp);
+               g_free (summary);
+       }
+
+       /* Test synchronous bulk methods */
+       res = test_bulk_methods (icalcomps);
+
+       g_slist_free_full (icalcomps, (GDestroyNotify)icalcomponent_free);
+
+       return (res != TRUE);
+}