From 4a3f2b0930e236580f9044217d77536170f48ab5 Mon Sep 17 00:00:00 2001 From: Christophe Dumez Date: Tue, 21 Feb 2012 09:38:43 +0200 Subject: [PATCH] Bug 670457: Add bulk methods to ECalClient Add e_cal_client_create_objects*() / e_cal_client_modify_objects*() / e_cal_client_remove_objects*() bulk methods to ECalClient. --- calendar/backends/caldav/e-cal-backend-caldav.c | 252 ++++---- .../backends/contacts/e-cal-backend-contacts.c | 16 +- calendar/backends/file/e-cal-backend-file.c | 713 ++++++++++++--------- calendar/backends/http/e-cal-backend-http.c | 57 +- calendar/libecal/e-cal-client.c | 476 +++++++++++++- calendar/libecal/e-cal-client.h | 12 + calendar/libecal/e-cal-util.h | 27 + calendar/libecal/e-cal.c | 35 +- calendar/libedata-cal/e-cal-backend-sync.c | 203 +++--- calendar/libedata-cal/e-cal-backend-sync.h | 12 +- calendar/libedata-cal/e-cal-backend.c | 92 ++- calendar/libedata-cal/e-cal-backend.h | 12 +- calendar/libedata-cal/e-data-cal.c | 201 +++--- calendar/libedata-cal/e-data-cal.h | 6 +- calendar/libegdbus/e-gdbus-cal.c | 271 ++++---- calendar/libegdbus/e-gdbus-cal.h | 50 +- configure.ac | 6 +- libedataserver/e-data-server-util.c | 20 + libedataserver/e-data-server-util.h | 1 + tests/libecal/client/Makefile.am | 3 + tests/libecal/client/test-client-bulk-methods.c | 253 ++++++++ 21 files changed, 1823 insertions(+), 895 deletions(-) create mode 100644 tests/libecal/client/test-client-bulk-methods.c diff --git a/calendar/backends/caldav/e-cal-backend-caldav.c b/calendar/backends/caldav/e-cal-backend-caldav.c index 323d228..8df9121 100644 --- a/calendar/backends/caldav/e-cal-backend-caldav.c +++ b/calendar/backends/caldav/e-cal-backend-caldav.c @@ -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; diff --git a/calendar/backends/contacts/e-cal-backend-contacts.c b/calendar/backends/contacts/e-cal-backend-contacts.c index f595ece..d0e19d7 100644 --- a/calendar/backends/contacts/e-cal-backend-contacts.c +++ b/calendar/backends/contacts/e-cal-backend-contacts.c @@ -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; diff --git a/calendar/backends/file/e-cal-backend-file.c b/calendar/backends/file/e-cal-backend-file.c index 79f4c8b..b63aea9 100644 --- a/calendar/backends/file/e-cal-backend-file.c +++ b/calendar/backends/file/e-cal-backend-file.c @@ -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, ¤t); + e_cal_component_set_last_modified (comp, ¤t); + + /* 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, ¤t); - e_cal_component_set_last_modified (comp, ¤t); + /* 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, ¤t); + /* 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, ¤t); - 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; diff --git a/calendar/backends/http/e-cal-backend-http.c b/calendar/backends/http/e-cal-backend-http.c index d120ce4..66a7e15 100644 --- a/calendar/backends/http/e-cal-backend-http.c +++ b/calendar/backends/http/e-cal-backend-http.c @@ -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; diff --git a/calendar/libecal/e-cal-client.c b/calendar/libecal/e-cal-client.c index 7f37f4e..6685e07 100644 --- a/calendar/libecal/e-cal-client.c +++ b/calendar/libecal/e-cal-client.c @@ -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); diff --git a/calendar/libecal/e-cal-client.h b/calendar/libecal/e-cal-client.h index 3e77baf..1733511 100644 --- a/calendar/libecal/e-cal-client.h +++ b/calendar/libecal/e-cal-client.h @@ -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); diff --git a/calendar/libecal/e-cal-util.h b/calendar/libecal/e-cal-util.h index fe6a48d..966aeb5 100644 --- a/calendar/libecal/e-cal-util.h +++ b/calendar/libecal/e-cal-util.h @@ -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. diff --git a/calendar/libecal/e-cal.c b/calendar/libecal/e-cal.c index c2ab5c9..2a9bca1 100644 --- a/calendar/libecal/e-cal.c +++ b/calendar/libecal/e-cal.c @@ -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); diff --git a/calendar/libedata-cal/e-cal-backend-sync.c b/calendar/libedata-cal/e-cal-backend-sync.c index 34ef6a2..f6226e5 100644 --- a/calendar/libedata-cal/e-cal-backend-sync.c +++ b/calendar/libedata-cal/e-cal-backend-sync.c @@ -11,6 +11,7 @@ #endif #include "e-cal-backend-sync.h" +#include "libedataserver/e-data-server-util.h" #include #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; diff --git a/calendar/libedata-cal/e-cal-backend-sync.h b/calendar/libedata-cal/e-cal-backend-sync.h index d3c2d13..6b7d180 100644 --- a/calendar/libedata-cal/e-cal-backend-sync.h +++ b/calendar/libedata-cal/e-cal-backend-sync.h @@ -39,9 +39,9 @@ struct _ECalBackendSyncClass { void (* get_object_sync) (ECalBackendSync *backend, EDataCal *cal, GCancellable *cancellable, const gchar *uid, const gchar *rid, gchar **calobj, GError **error); void (* get_object_list_sync) (ECalBackendSync *backend, EDataCal *cal, GCancellable *cancellable, const gchar *sexp, GSList **calobjs, GError **error); void (* get_free_busy_sync) (ECalBackendSync *backend, EDataCal *cal, GCancellable *cancellable, const GSList *users, time_t start, time_t end, GSList **freebusyobjs, GError **error); - void (* create_object_sync) (ECalBackendSync *backend, EDataCal *cal, GCancellable *cancellable, const gchar *calobj, gchar **uid, 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); diff --git a/calendar/libedata-cal/e-cal-backend.c b/calendar/libedata-cal/e-cal-backend.c index 1894690..d956ae3 100644 --- a/calendar/libedata-cal/e-cal-backend.c +++ b/calendar/libedata-cal/e-cal-backend.c @@ -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); } /** diff --git a/calendar/libedata-cal/e-cal-backend.h b/calendar/libedata-cal/e-cal-backend.h index 13cf488..20e99d0 100644 --- a/calendar/libedata-cal/e-cal-backend.h +++ b/calendar/libedata-cal/e-cal-backend.h @@ -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); diff --git a/calendar/libedata-cal/e-data-cal.c b/calendar/libedata-cal/e-data-cal.c index df1f682..680baf4 100644 --- a/calendar/libedata-cal/e-data-cal.c +++ b/calendar/libedata-cal/e-data-cal.c @@ -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); diff --git a/calendar/libedata-cal/e-data-cal.h b/calendar/libedata-cal/e-data-cal.h index f9c5ecd..15daa43 100644 --- a/calendar/libedata-cal/e-data-cal.h +++ b/calendar/libedata-cal/e-data-cal.h @@ -136,9 +136,9 @@ void e_data_cal_respond_set_backend_property (EDataCal *cal, guint32 opid, GEr void e_data_cal_respond_get_object (EDataCal *cal, guint32 opid, GError *error, const gchar *object); void e_data_cal_respond_get_object_list (EDataCal *cal, guint32 opid, GError *error, const GSList *objects); void e_data_cal_respond_get_free_busy (EDataCal *cal, guint32 opid, GError *error); -void e_data_cal_respond_create_object (EDataCal *cal, guint32 opid, GError *error, const gchar *uid, /*const */ 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); diff --git a/calendar/libegdbus/e-gdbus-cal.c b/calendar/libegdbus/e-gdbus-cal.c index 8c9212a..c8edbd8 100644 --- a/calendar/libegdbus/e-gdbus-cal.c +++ b/calendar/libegdbus/e-gdbus-cal.c @@ -25,6 +25,8 @@ #include #include +/* We only need the ECalComponentId structure from the following header */ +#include #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); diff --git a/calendar/libegdbus/e-gdbus-cal.h b/calendar/libegdbus/e-gdbus-cal.h index 695d13b..7220f64 100644 --- a/calendar/libegdbus/e-gdbus-cal.h +++ b/calendar/libegdbus/e-gdbus-cal.h @@ -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); diff --git a/configure.ac b/configure.ac index d9a9e33..ad9bac2 100644 --- a/configure.ac +++ b/configure.ac @@ -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 diff --git a/libedataserver/e-data-server-util.c b/libedataserver/e-data-server-util.c index c7211a2..a608fbd 100644 --- a/libedataserver/e-data-server-util.c +++ b/libedataserver/e-data-server-util.c @@ -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 diff --git a/libedataserver/e-data-server-util.h b/libedataserver/e-data-server-util.h index 8450c63..b68c460 100644 --- a/libedataserver/e-data-server-util.h +++ b/libedataserver/e-data-server-util.h @@ -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 diff --git a/tests/libecal/client/Makefile.am b/tests/libecal/client/Makefile.am index 68037ca..af2b893 100644 --- a/tests/libecal/client/Makefile.am +++ b/tests/libecal/client/Makefile.am @@ -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 index 0000000..c4d9069 --- /dev/null +++ b/tests/libecal/client/test-client-bulk-methods.c @@ -0,0 +1,253 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ + +#include +#include +#include + +#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); +} -- 2.7.4