[evolution-ews/gnome-40] I#152 - Declining Single Calendar Event Results in Declining the Whole Series
- From: Milan Crha <mcrha src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [evolution-ews/gnome-40] I#152 - Declining Single Calendar Event Results in Declining the Whole Series
- Date: Mon, 10 May 2021 17:25:55 +0000 (UTC)
commit 294b8bbd03563ee5a413765440fce96dd0d4eea7
Author: Milan Crha <mcrha redhat com>
Date: Mon May 10 19:24:30 2021 +0200
I#152 - Declining Single Calendar Event Results in Declining the Whole Series
Closes https://gitlab.gnome.org/GNOME/evolution-ews/-/issues/152
src/EWS/calendar/e-cal-backend-ews-utils.c | 33 ++---
src/EWS/calendar/e-cal-backend-ews.c | 205 ++++++++++++++++++++++++++++-
2 files changed, 208 insertions(+), 30 deletions(-)
---
diff --git a/src/EWS/calendar/e-cal-backend-ews-utils.c b/src/EWS/calendar/e-cal-backend-ews-utils.c
index 817f4b75..5ea8a218 100644
--- a/src/EWS/calendar/e-cal-backend-ews-utils.c
+++ b/src/EWS/calendar/e-cal-backend-ews-utils.c
@@ -1528,31 +1528,14 @@ convert_vevent_component_to_updatexml (ESoapMessage *msg,
gboolean dt_start_changed = FALSE, dt_end_changed = FALSE, dt_changed;
gboolean dt_start_changed_timezone_name = FALSE, dt_end_changed_timezone_name = FALSE;
gboolean satisfies, rsvp_requested = TRUE, is_all_day_event = FALSE;
- gchar *recid;
-
- /* Modifying a recurring meeting ? */
- if (e_cal_util_component_has_property (icomp_old, I_CAL_RRULE_PROPERTY)) {
- /* A single occurrence ? */
- prop = i_cal_component_get_first_property (icomp, I_CAL_RECURRENCEID_PROPERTY);
- if (prop != NULL) {
- recid = i_cal_property_get_value_as_string (prop);
- e_ews_message_start_item_change (
- msg,
- E_EWS_ITEMCHANGE_TYPE_OCCURRENCEITEM,
- convert_data->item_id,
- convert_data->change_key,
- e_cal_backend_ews_rid_to_index (
- convert_data->default_zone,
- recid,
- icomp_old,
- NULL));
- g_object_unref (prop);
- g_free (recid);
- } else {
- e_ews_message_start_item_change (
- msg, E_EWS_ITEMCHANGE_TYPE_ITEM,
- convert_data->item_id, convert_data->change_key, 0);
- }
+
+ if (convert_data->change_type == E_EWS_ITEMCHANGE_TYPE_OCCURRENCEITEM && convert_data->index > 0) {
+ e_ews_message_start_item_change (
+ msg,
+ convert_data->change_type,
+ convert_data->item_id,
+ convert_data->change_key,
+ convert_data->index);
} else {
e_ews_message_start_item_change (msg, E_EWS_ITEMCHANGE_TYPE_ITEM,
convert_data->item_id, convert_data->change_key, 0);
diff --git a/src/EWS/calendar/e-cal-backend-ews.c b/src/EWS/calendar/e-cal-backend-ews.c
index 5fa1f661..002b867f 100644
--- a/src/EWS/calendar/e-cal-backend-ews.c
+++ b/src/EWS/calendar/e-cal-backend-ews.c
@@ -839,6 +839,15 @@ ecb_ews_item_to_component_sync (ECalBackendEws *cbews,
}
g_object_unref (dt);
+
+ dt = e_cal_backend_ews_get_datetime_with_zone (timezone_cache, vcomp, icomp,
I_CAL_RECURRENCEID_PROPERTY, i_cal_property_get_recurrenceid);
+
+ if (dt && !i_cal_time_is_date (dt)) {
+ i_cal_time_convert_to_zone_inplace (dt, zone);
+ i_cal_component_set_recurrenceid (icomp, dt);
+ }
+
+ g_clear_object (&dt);
}
g_free (new_tzid);
@@ -988,6 +997,18 @@ ecb_ews_item_to_component_sync (ECalBackendEws *cbews,
i_cal_property_remove_parameter_by_kind (prop, I_CAL_TZID_PARAMETER);
}
+
+ for (prop = i_cal_component_get_first_property (icomp, I_CAL_RECURRENCEID_PROPERTY);
+ prop;
+ g_object_unref (prop), prop = i_cal_component_get_next_property (icomp,
I_CAL_RECURRENCEID_PROPERTY)) {
+ g_clear_object (&itt);
+
+ itt = i_cal_property_get_recurrenceid (prop);
+ i_cal_time_set_is_date (itt, TRUE);
+ i_cal_property_set_recurrenceid (prop, itt);
+
+ i_cal_property_remove_parameter_by_kind (prop, I_CAL_TZID_PARAMETER);
+ }
}
g_clear_object (&itt);
@@ -2530,10 +2551,11 @@ ecb_ews_remove_item_sync (ECalBackendEws *cbews,
if (rid && !*rid)
rid = NULL;
- if (!e_cal_cache_get_component (cal_cache, uid, rid, &comp, cancellable, error) ||
- (rid && !e_cal_cache_get_component (cal_cache, uid, NULL, &parent, cancellable, error))) {
+ if (!e_cal_cache_get_component (cal_cache, uid, rid, &comp, cancellable, NULL) ||
+ (rid && !e_cal_cache_get_component (cal_cache, uid, NULL, &parent, cancellable, NULL))) {
if (!parent && !comp) {
- g_propagate_error (error, ECC_ERROR (E_CAL_CLIENT_ERROR_OBJECT_NOT_FOUND));
+ if (!g_cancellable_set_error_if_cancelled (cancellable, error))
+ g_propagate_error (error, ECC_ERROR (E_CAL_CLIENT_ERROR_OBJECT_NOT_FOUND));
return FALSE;
}
}
@@ -2690,6 +2712,101 @@ ecb_ews_pick_all_tzids_out (ECalBackendEws *cbews,
i_cal_component_foreach_tzid (icomp, tzid_cb, &cbd);
}
+static gboolean
+ecb_ews_get_change_type_is_instance (ECalBackendEws *cbews,
+ ICalComponent *vcalendar,
+ ICalComponent *subcomp,
+ GCancellable *cancellable,
+ EEwsItemChangeType *out_change_type,
+ gint *out_index)
+{
+ gboolean res = FALSE;
+ gchar *rid;
+
+ g_return_val_if_fail (out_change_type != NULL, FALSE);
+ g_return_val_if_fail (out_index != NULL, FALSE);
+
+ if (!e_cal_util_component_is_instance (subcomp))
+ return FALSE;
+
+ rid = e_cal_util_component_get_recurid_as_string (subcomp);
+
+ if (rid && *rid) {
+ ICalComponent *main_comp = NULL;
+
+ if (vcalendar) {
+ ICalComponentKind kind;
+ ICalCompIter *iter;
+ const gchar *uid;
+
+ uid = i_cal_component_get_uid (subcomp);
+ kind = i_cal_component_isa (subcomp);
+
+ iter = i_cal_component_begin_component (vcalendar, kind);
+ main_comp = i_cal_comp_iter_deref (iter);
+ while (main_comp) {
+ if (g_strcmp0 (uid, i_cal_component_get_uid (main_comp)) == 0 &&
+ !e_cal_util_component_is_instance (main_comp) &&
+ e_cal_util_component_has_rrules (main_comp)) {
+ break;
+ }
+
+ g_object_unref (main_comp);
+ main_comp = i_cal_comp_iter_next (iter);
+ }
+
+ g_clear_object (&iter);
+ }
+
+ if (!main_comp) {
+ ECalCache *cal_cache;
+ ECalComponent *existing = NULL;
+
+ cal_cache = e_cal_meta_backend_ref_cache (E_CAL_META_BACKEND (cbews));
+
+ if (cal_cache && e_cal_cache_get_component (cal_cache, i_cal_component_get_uid
(subcomp), NULL, &existing, cancellable, NULL) && existing) {
+ main_comp = e_cal_component_get_icalcomponent (existing);
+ g_object_ref (main_comp);
+ g_object_unref (existing);
+ }
+
+ g_clear_object (&cal_cache);
+ }
+
+ if (main_comp) {
+ gchar *mid, *sid;
+
+ mid = e_cal_util_component_dup_x_property (main_comp, "X-EVOLUTION-ITEMID");
+ sid = e_cal_util_component_dup_x_property (subcomp, "X-EVOLUTION-ITEMID");
+
+ /* Already detached instances do not need to do this */
+ if (mid && g_strcmp0 (mid, sid) == 0) {
+ gint index;
+
+ index = e_cal_backend_ews_rid_to_index (
+ ecb_ews_get_timezone_from_icomponent (cbews, main_comp),
+ rid,
+ main_comp,
+ NULL);
+
+ if (index > 0) {
+ res = TRUE;
+ *out_change_type = E_EWS_ITEMCHANGE_TYPE_OCCURRENCEITEM;
+ *out_index = index;
+ }
+ }
+
+ g_clear_object (&main_comp);
+ g_free (mid);
+ g_free (sid);
+ }
+ }
+
+ g_free (rid);
+
+ return res;
+}
+
static gboolean
ecb_ews_modify_item_sync (ECalBackendEws *cbews,
guint32 opflags,
@@ -2839,6 +2956,12 @@ ecb_ews_modify_item_sync (ECalBackendEws *cbews,
const gchar *send_meeting_invitations;
const gchar *send_or_save;
+ if (!ecb_ews_get_change_type_is_instance (cbews, NULL, e_cal_component_get_icalcomponent
(comp),
+ cancellable, &convert_data.change_type, &convert_data.index)) {
+ convert_data.change_type = E_EWS_ITEMCHANGE_TYPE_ITEM;
+ convert_data.index = -1;
+ }
+
ews_settings = ecb_ews_get_collection_settings (cbews);
convert_data.connection = cbews->priv->cnc;
@@ -3736,6 +3859,51 @@ ecb_ews_do_method_request_publish_reply (ECalBackendEws *cbews,
ecb_ews_receive_objects_no_exchange_mail (cbews, vcalendar, subcomp, &ids,
cancellable, &local_error);
} else {
EwsCalendarConvertData convert_data = { 0 };
+ EEwsItemChangeType change_type = E_EWS_ITEMCHANGE_TYPE_ITEM;
+ gint index = -1;
+
+ /* Need to detach an instance before modifying the response on it */
+ if (ecb_ews_get_change_type_is_instance (cbews, vcalendar, subcomp, cancellable,
&change_type, &index)) {
+ EwsCalendarConvertData sub_convert_data = { 0 };
+ CamelEwsSettings *ews_settings;
+
+ ews_settings = ecb_ews_get_collection_settings (cbews);
+
+ sub_convert_data.change_type = change_type;
+ sub_convert_data.index = index;
+ sub_convert_data.connection = cbews->priv->cnc;
+ sub_convert_data.timezone_cache = E_TIMEZONE_CACHE (cbews);
+ sub_convert_data.user_email = camel_ews_settings_dup_email (ews_settings);
+ sub_convert_data.comp = comp;
+ sub_convert_data.old_comp = comp; /* no change, just detach the instance */
+ sub_convert_data.item_id = item_id;
+ sub_convert_data.change_key = change_key;
+ sub_convert_data.default_zone = i_cal_timezone_get_utc_timezone ();
+
+ e_ews_connection_update_items_sync (cbews->priv->cnc, EWS_PRIORITY_MEDIUM,
+ "AlwaysOverwrite", "SaveOnly", "SendToNone", cbews->priv->folder_id,
+ e_cal_backend_ews_convert_component_to_updatexml, &sub_convert_data,
+ &ids, cancellable, &local_error);
+
+ g_free (sub_convert_data.user_email);
+
+ if (!local_error && ids && !ids->next) {
+ EEwsItem *item = ids->data;
+ const EwsId *id = e_ews_item_get_id (item);
+
+ if (id) {
+ g_free (item_id);
+ g_free (change_key);
+
+ item_id = g_strdup (id->id);
+ change_key = g_strdup (id->change_key);
+ }
+ }
+
+ g_clear_error (&local_error);
+ g_slist_free_full (ids, g_object_unref);
+ ids = NULL;
+ }
convert_data.timezone_cache = E_TIMEZONE_CACHE (cbews);
convert_data.response_type = (gchar *) response_type;
@@ -3885,11 +4053,12 @@ ecb_ews_receive_objects_sync (ECalBackendSync *sync_backend,
ECalBackendEws *cbews;
ECalBackend *cal_backend;
CamelEwsSettings *ews_settings;
- ICalComponent *icomp, *subcomp;
+ ICalComponent *icomp, *subcomp, *decline_main = NULL;
ICalComponentKind kind;
GHashTable *aliases;
gchar *user_email;
gboolean success = TRUE, do_refresh = FALSE;
+ gboolean decline_main_rsvp_requested = FALSE;
g_return_if_fail (E_IS_CAL_BACKEND_EWS (sync_backend));
@@ -3934,9 +4103,20 @@ ecb_ews_receive_objects_sync (ECalBackendSync *sync_backend,
response_type = ecb_ews_get_current_user_meeting_reponse (cbews, subcomp, user_email,
aliases, &rsvp_requested);
rsvp_requested = rsvp_requested && !(opflags &
E_CAL_OPERATION_FLAG_DISABLE_ITIP_MESSAGE);
+ /* When the main component is declined, then decline also all detached instances and
do them
+ first, because the main component decline removes the whole series from the
calendar. */
+ if (!decline_main && response_type && g_ascii_strcasecmp (response_type, "DECLINED")
== 0 &&
+ !e_cal_util_component_is_instance (subcomp)) {
+ decline_main = g_object_ref (subcomp);
+ decline_main_rsvp_requested = rsvp_requested;
+ g_free (response_type);
+ continue;
+ }
+
comp = e_cal_component_new_from_icalcomponent (i_cal_component_clone (subcomp));
- success = ecb_ews_do_method_request_publish_reply (cbews, icomp, comp, subcomp,
response_type, user_email, rsvp_requested, cancellable, error);
+ success = ecb_ews_do_method_request_publish_reply (cbews, icomp, comp, subcomp,
+ decline_main ? "DECLINED" : response_type, user_email, rsvp_requested,
cancellable, error);
do_refresh = TRUE;
@@ -3944,6 +4124,21 @@ ecb_ews_receive_objects_sync (ECalBackendSync *sync_backend,
g_free (response_type);
}
g_clear_object (&subcomp);
+
+ if (decline_main && success) {
+ ECalComponent *comp;
+
+ comp = e_cal_component_new_from_icalcomponent (i_cal_component_clone (decline_main));
+
+ success = ecb_ews_do_method_request_publish_reply (cbews, icomp, comp, decline_main,
+ "DECLINED", user_email, decline_main_rsvp_requested, cancellable, error);
+
+ do_refresh = TRUE;
+
+ g_object_unref (comp);
+ }
+
+ g_clear_object (&decline_main);
break;
case I_CAL_METHOD_COUNTER:
/*
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]