[evolution-data-server] evo-I#1014 - Calendar: Correct RRULE's UNTIL value saving
- From: Milan Crha <mcrha src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [evolution-data-server] evo-I#1014 - Calendar: Correct RRULE's UNTIL value saving
- Date: Wed, 26 Aug 2020 12:11:26 +0000 (UTC)
commit 46966e450abad63755f0645c6d257b7627c0c7d1
Author: Milan Crha <mcrha redhat com>
Date: Wed Aug 26 14:10:01 2020 +0200
evo-I#1014 - Calendar: Correct RRULE's UNTIL value saving
Related to https://gitlab.gnome.org/GNOME/evolution/-/issues/1014
src/calendar/backends/file/e-cal-backend-file.c | 27 ++--
src/calendar/libecal/e-cal-util.c | 179 ++++++++++++++++++++++--
src/calendar/libecal/e-cal-util.h | 17 +++
src/calendar/libedata-cal/e-cal-meta-backend.c | 8 +-
4 files changed, 206 insertions(+), 25 deletions(-)
---
diff --git a/src/calendar/backends/file/e-cal-backend-file.c b/src/calendar/backends/file/e-cal-backend-file.c
index 78e96c6778..af10cb4781 100644
--- a/src/calendar/backends/file/e-cal-backend-file.c
+++ b/src/calendar/backends/file/e-cal-backend-file.c
@@ -2727,15 +2727,13 @@ e_cal_backend_file_modify_objects (ECalBackendSync *backend,
i_cal_time_convert_to_zone_inplace (rid_struct,
i_cal_time_get_timezone (master_dtstart));
}
- split_icomp = e_cal_util_split_at_instance (icomp, rid_struct,
master_dtstart);
+ split_icomp = e_cal_util_split_at_instance_ex (icomp, rid_struct,
master_dtstart, resolve_tzid_cb, &rtd);
if (split_icomp) {
ECalComponent *prev_comp;
prev_comp = e_cal_component_clone (obj_data->full_object);
- i_cal_time_convert_to_zone_inplace (rid_struct,
i_cal_timezone_get_utc_timezone ());
-
- e_cal_util_remove_instances (e_cal_component_get_icalcomponent
(obj_data->full_object), rid_struct, mod);
+ e_cal_util_remove_instances_ex (e_cal_component_get_icalcomponent
(obj_data->full_object), rid_struct, mod, resolve_tzid_cb, &rtd);
e_cal_recur_ensure_end_dates (obj_data->full_object, TRUE,
resolve_tzid_cb, &rtd, cancellable, NULL);
e_cal_backend_notify_component_modified (E_CAL_BACKEND (backend),
prev_comp, obj_data->full_object);
@@ -2753,7 +2751,7 @@ e_cal_backend_file_modify_objects (ECalBackendSync *backend,
} else {
ICalTime *rid_struct = i_cal_component_get_recurrenceid (icomp);
- split_icomp = e_cal_util_split_at_instance (icomp, rid_struct, NULL);
+ split_icomp = e_cal_util_split_at_instance_ex (icomp, rid_struct, NULL,
resolve_tzid_cb, &rtd);
g_object_unref (rid_struct);
}
@@ -2880,6 +2878,7 @@ remove_instance (ECalBackendFile *cbfile,
if (rid) {
ICalTime *rid_struct;
+ ResolveTzidData rtd;
gpointer value;
/* remove recurrence */
@@ -2954,14 +2953,15 @@ remove_instance (ECalBackendFile *cbfile,
if (master_dtstart && i_cal_time_get_timezone (master_dtstart)) {
i_cal_time_convert_to_zone_inplace (rid_struct, i_cal_time_get_timezone
(master_dtstart));
}
-
- i_cal_time_convert_to_zone_inplace (rid_struct, i_cal_timezone_get_utc_timezone ());
}
- e_cal_util_remove_instances (
+ resolve_tzid_data_init (&rtd, cbfile->priv->vcalendar);
+
+ e_cal_util_remove_instances_ex (
e_cal_component_get_icalcomponent (obj_data->full_object),
- rid_struct, E_CAL_OBJ_MOD_THIS);
+ rid_struct, E_CAL_OBJ_MOD_THIS, resolve_tzid_cb, &rtd);
+ resolve_tzid_data_clear (&rtd);
g_clear_object (&rid_struct);
/* Since we are only removing one instance of recurrence
@@ -3172,6 +3172,7 @@ e_cal_backend_file_remove_objects (ECalBackendSync *backend,
if (comp) {
ICalTime *rid_struct;
+ ResolveTzidData rtd;
*old_components = g_slist_prepend (*old_components, e_cal_component_clone
(comp));
@@ -3191,10 +3192,14 @@ e_cal_backend_file_remove_objects (ECalBackendSync *backend,
i_cal_time_convert_to_zone_inplace (rid_struct,
i_cal_timezone_get_utc_timezone ());
}
- e_cal_util_remove_instances (
+
+ resolve_tzid_data_init (&rtd, priv->vcalendar);
+
+ e_cal_util_remove_instances_ex (
e_cal_component_get_icalcomponent (comp),
- rid_struct, mod);
+ rid_struct, mod, resolve_tzid_cb, &rtd);
+ resolve_tzid_data_clear (&rtd);
g_object_unref (rid_struct);
} else {
*old_components = g_slist_prepend (*old_components, NULL);
diff --git a/src/calendar/libecal/e-cal-util.c b/src/calendar/libecal/e-cal-util.c
index 9b0f034502..7b34c40305 100644
--- a/src/calendar/libecal/e-cal-util.c
+++ b/src/calendar/libecal/e-cal-util.c
@@ -1294,12 +1294,95 @@ time_matches_rid (const ICalTime *itt,
return FALSE;
}
+/**
+ * e_cal_util_normalize_rrule_until_value:
+ * @icalcomp: An #ICalComponent
+ * @ttuntil: An UNTIL value to validate
+ * @tz_cb: (closure tz_cb_data) (scope call): The #ECalRecurResolveTimezoneCb to call
+ * @tz_cb_data: (closure): User data to be passed to the @tz_cb callback
+ *
+ * Makes sure the @ttuntil value matches the value type with
+ * the DTSTART value, as required by RFC 5545 section 3.3.10.
+ * Uses @tz_cb with @tz_cb_data to resolve time zones when needed.
+ *
+ * Since: 3.38
+ **/
+void
+e_cal_util_normalize_rrule_until_value (ICalComponent *icalcomp,
+ ICalTime *ttuntil,
+ ECalRecurResolveTimezoneCb tz_cb,
+ gpointer tz_cb_data)
+{
+ ICalProperty *prop;
+
+ g_return_if_fail (I_CAL_IS_COMPONENT (icalcomp));
+ g_return_if_fail (I_CAL_IS_TIME (ttuntil));
+
+ prop = i_cal_component_get_first_property (icalcomp, I_CAL_DTSTART_PROPERTY);
+
+ if (prop) {
+ ICalTime *dtstart;
+
+ dtstart = i_cal_component_get_dtstart (icalcomp);
+
+ if (dtstart) {
+ if (i_cal_time_is_date (dtstart)) {
+ i_cal_time_set_time (ttuntil, 0, 0, 0);
+ i_cal_time_set_is_date (ttuntil, TRUE);
+ } else {
+ if (i_cal_time_is_date (ttuntil)) {
+ gint hour = 0, minute = 0, second = 0;
+
+ i_cal_time_set_is_date (ttuntil, FALSE);
+
+ i_cal_time_get_time (dtstart, &hour, &minute, &second);
+ i_cal_time_set_time (ttuntil, hour, minute, second);
+ }
+
+ if (!i_cal_time_is_utc (dtstart)) {
+ ICalParameter *param;
+
+ param = i_cal_property_get_first_parameter (prop,
I_CAL_TZID_PARAMETER);
+
+ if (param) {
+ const gchar *tzid;
+
+ tzid = i_cal_parameter_get_tzid (param);
+
+ if (tzid && *tzid && g_ascii_strcasecmp (tzid, "UTC") != 0) {
+ ICalTimezone *tz;
+
+ tz = i_cal_time_get_timezone (dtstart);
+
+ if (!tz && tz_cb)
+ tz = tz_cb (tzid, tz_cb_data, NULL, NULL);
+
+ if (tz) {
+ i_cal_time_set_timezone (ttuntil, tz);
+ i_cal_time_convert_to_zone_inplace (ttuntil,
i_cal_timezone_get_utc_timezone ());
+ }
+ }
+
+ g_object_unref (param);
+ }
+ }
+ }
+
+ g_object_unref (dtstart);
+ }
+
+ g_object_unref (prop);
+ }
+}
+
static void
-e_cal_util_remove_instances_ex (ICalComponent *icalcomp,
- const ICalTime *rid,
- ECalObjModType mod,
- gboolean keep_rid,
- gboolean can_add_exrule)
+e_cal_util_remove_instances_impl (ICalComponent *icalcomp,
+ const ICalTime *rid,
+ ECalObjModType mod,
+ gboolean keep_rid,
+ gboolean can_add_exrule,
+ ECalRecurResolveTimezoneCb tz_cb,
+ gpointer tz_cb_data)
{
ICalProperty *prop;
ICalTime *itt, *recur;
@@ -1419,6 +1502,7 @@ e_cal_util_remove_instances_ex (ICalComponent *icalcomp,
g_clear_object (&dtstart);
} else {
ICalTime *ttuntil;
+ gboolean is_date;
if (keep_rid && i_cal_time_compare (recur, (ICalTime *) rid) == 0) {
ICalDuration *dur;
@@ -1429,7 +1513,13 @@ e_cal_util_remove_instances_ex (ICalComponent *icalcomp,
} else {
ttuntil = i_cal_time_clone (rid);
}
- i_cal_time_adjust (ttuntil, 0, 0, 0, -1);
+
+ e_cal_util_normalize_rrule_until_value (icalcomp, ttuntil, tz_cb,
tz_cb_data);
+
+ is_date = i_cal_time_is_date (ttuntil);
+
+ i_cal_time_adjust (ttuntil, is_date ? -1 : 0, 0, 0, is_date ? 0 : -1);
+
i_cal_recurrence_set_until (rule, ttuntil);
g_object_unref (ttuntil);
}
@@ -1466,6 +1556,7 @@ e_cal_util_remove_instances_ex (ICalComponent *icalcomp,
ttuntil = i_cal_time_add ((ICalTime *) rid, dur);
}
+ e_cal_util_normalize_rrule_until_value (icalcomp, ttuntil, tz_cb,
tz_cb_data);
i_cal_recurrence_set_until (rule, ttuntil);
g_clear_object (&ttuntil);
@@ -1501,6 +1592,9 @@ e_cal_util_remove_instances_ex (ICalComponent *icalcomp,
* @mod: How to interpret @rid
*
* Removes one or more instances from @icalcomp according to @rid and @mod.
+ *
+ * Deprecated: 3.38: Use e_cal_util_remove_instances_ex() instead, with provided
+ * timezone resolve function.
**/
void
e_cal_util_remove_instances (ICalComponent *icalcomp,
@@ -1511,7 +1605,34 @@ e_cal_util_remove_instances (ICalComponent *icalcomp,
g_return_if_fail (rid != NULL);
g_return_if_fail (mod != E_CAL_OBJ_MOD_ALL);
- e_cal_util_remove_instances_ex (icalcomp, rid, mod, FALSE, TRUE);
+ e_cal_util_remove_instances_ex (icalcomp, rid, mod, NULL, NULL);
+}
+
+/**
+ * e_cal_util_remove_instances_ex:
+ * @icalcomp: A (recurring) #ICalComponent
+ * @rid: The base RECURRENCE-ID to remove
+ * @mod: How to interpret @rid
+ * @tz_cb: (closure tz_cb_data) (scope call): The #ECalRecurResolveTimezoneCb to call
+ * @tz_cb_data: (closure): User data to be passed to the @tz_cb callback
+ *
+ * Removes one or more instances from @icalcomp according to @rid and @mod.
+ * Uses @tz_cb with @tz_cb_data to resolve time zones when needed.
+ *
+ * Since: 3.38
+ **/
+void
+e_cal_util_remove_instances_ex (ICalComponent *icalcomp,
+ const ICalTime *rid,
+ ECalObjModType mod,
+ ECalRecurResolveTimezoneCb tz_cb,
+ gpointer tz_cb_data)
+{
+ g_return_if_fail (icalcomp != NULL);
+ g_return_if_fail (rid != NULL);
+ g_return_if_fail (mod != E_CAL_OBJ_MOD_ALL);
+
+ e_cal_util_remove_instances_impl (icalcomp, rid, mod, FALSE, TRUE, tz_cb, tz_cb_data);
}
/**
@@ -1525,20 +1646,58 @@ e_cal_util_remove_instances (ICalComponent *icalcomp,
* The instance identified by @rid should exist. The @master_dtstart can be
* a null time, then it is read from the @icalcomp.
*
- * Use e_cal_util_remove_instances() with E_CAL_OBJ_MOD_THIS_AND_FUTURE mode
+ * Use e_cal_util_remove_instances_ex() with E_CAL_OBJ_MOD_THIS_AND_FUTURE mode
* on the @icalcomp to remove the overlapping interval from it, if needed.
*
* Free the returned non-NULL component with g_object_unref(), when
* done with it.
*
- * Returns: (transfer full) (nullable): the split @icalcom, or %NULL.
+ * Returns: (transfer full) (nullable): the split @icalcomp, or %NULL.
*
* Since: 3.16
+ *
+ * Deprecated: 3.38: Use e_cal_util_split_at_instance_ex() instead, with provided
+ * timezone resolve function.
**/
ICalComponent *
e_cal_util_split_at_instance (ICalComponent *icalcomp,
const ICalTime *rid,
const ICalTime *master_dtstart)
+{
+ return e_cal_util_split_at_instance_ex (icalcomp, rid, master_dtstart, NULL, NULL);
+}
+
+/**
+ * e_cal_util_split_at_instance_ex:
+ * @icalcomp: A (recurring) #ICalComponent
+ * @rid: The base RECURRENCE-ID to remove
+ * @master_dtstart: (nullable): The DTSTART of the master object
+ * @tz_cb: (closure tz_cb_data) (scope call): The #ECalRecurResolveTimezoneCb to call
+ * @tz_cb_data: (closure): User data to be passed to the @tz_cb callback
+ *
+ * Splits a recurring @icalcomp into two at time @rid. The returned #ICalComponent
+ * is modified @icalcomp which contains recurrences beginning at @rid, inclusive.
+ * The instance identified by @rid should exist. The @master_dtstart can be
+ * a null time, then it is read from the @icalcomp.
+ *
+ * Uses @tz_cb with @tz_cb_data to resolve time zones when needed.
+ *
+ * Use e_cal_util_remove_instances_ex() with E_CAL_OBJ_MOD_THIS_AND_FUTURE mode
+ * on the @icalcomp to remove the overlapping interval from it, if needed.
+ *
+ * Free the returned non-NULL component with g_object_unref(), when
+ * done with it.
+ *
+ * Returns: (transfer full) (nullable): the split @icalcomp, or %NULL.
+ *
+ * Since: 3.38
+ **/
+ICalComponent *
+e_cal_util_split_at_instance_ex (ICalComponent *icalcomp,
+ const ICalTime *rid,
+ const ICalTime *master_dtstart,
+ ECalRecurResolveTimezoneCb tz_cb,
+ gpointer tz_cb_data)
{
ICalProperty *prop;
struct instance_data instance;
@@ -1568,7 +1727,7 @@ e_cal_util_split_at_instance (ICalComponent *icalcomp,
/* Make the copy */
icalcomp = i_cal_component_clone (icalcomp);
- e_cal_util_remove_instances_ex (icalcomp, rid, E_CAL_OBJ_MOD_THIS_AND_PRIOR, TRUE, FALSE);
+ e_cal_util_remove_instances_impl (icalcomp, rid, E_CAL_OBJ_MOD_THIS_AND_PRIOR, TRUE, FALSE, tz_cb,
tz_cb_data);
start = i_cal_time_clone ((ICalTime *) rid);
diff --git a/src/calendar/libecal/e-cal-util.h b/src/calendar/libecal/e-cal-util.h
index 6fcb2172c9..a0d5ea2fbf 100644
--- a/src/calendar/libecal/e-cal-util.h
+++ b/src/calendar/libecal/e-cal-util.h
@@ -268,12 +268,29 @@ gchar * e_cal_util_component_get_recurid_as_string
(ICalComponent *icalcomp);
ICalComponent * e_cal_util_construct_instance (ICalComponent *icalcomp,
const ICalTime *rid);
+/* #ifndef EDS_DISABLE_DEPRECATED */ /* Fully deprecate it for 3.40 */
void e_cal_util_remove_instances (ICalComponent *icalcomp,
const ICalTime *rid,
ECalObjModType mod);
ICalComponent * e_cal_util_split_at_instance (ICalComponent *icalcomp,
const ICalTime *rid,
const ICalTime *master_dtstart);
+/* #endif / * EDS_DISABLE_DEPRECATED */
+void e_cal_util_normalize_rrule_until_value
+ (ICalComponent *icalcomp,
+ ICalTime *ttuntil,
+ ECalRecurResolveTimezoneCb tz_cb,
+ gpointer tz_cb_data);
+void e_cal_util_remove_instances_ex (ICalComponent *icalcomp,
+ const ICalTime *rid,
+ ECalObjModType mod,
+ ECalRecurResolveTimezoneCb tz_cb,
+ gpointer tz_cb_data);
+ICalComponent * e_cal_util_split_at_instance_ex (ICalComponent *icalcomp,
+ const ICalTime *rid,
+ const ICalTime *master_dtstart,
+ ECalRecurResolveTimezoneCb tz_cb,
+ gpointer tz_cb_data);
gboolean e_cal_util_is_first_instance (ECalComponent *comp,
const ICalTime *rid,
ECalRecurResolveTimezoneCb tz_cb,
diff --git a/src/calendar/libedata-cal/e-cal-meta-backend.c b/src/calendar/libedata-cal/e-cal-meta-backend.c
index 37fa037312..61cfb32289 100644
--- a/src/calendar/libedata-cal/e-cal-meta-backend.c
+++ b/src/calendar/libedata-cal/e-cal-meta-backend.c
@@ -1926,12 +1926,12 @@ ecmb_modify_object_sync (ECalMetaBackend *meta_backend,
}
master_dtstart = i_cal_component_get_dtstart (e_cal_component_get_icalcomponent
(master_comp));
- split_icomp = e_cal_util_split_at_instance (icomp, rid, master_dtstart);
+ split_icomp = e_cal_util_split_at_instance_ex (icomp, rid, master_dtstart,
e_cal_cache_resolve_timezone_cb, cal_cache);
if (split_icomp) {
ICalTime *rid_utc;
rid_utc = i_cal_time_convert_to_zone (rid, i_cal_timezone_get_utc_timezone
());
- e_cal_util_remove_instances (e_cal_component_get_icalcomponent (master_comp),
rid_utc, mod);
+ e_cal_util_remove_instances_ex (e_cal_component_get_icalcomponent
(master_comp), rid_utc, mod, e_cal_cache_resolve_timezone_cb, cal_cache);
e_cal_recur_ensure_end_dates (master_comp, TRUE,
e_cal_cache_resolve_timezone_cb, cal_cache, cancellable, NULL);
if (out_new_comp) {
@@ -2187,7 +2187,7 @@ ecmb_remove_object_sync (ECalMetaBackend *meta_backend,
}
if (master_comp)
- e_cal_util_remove_instances (e_cal_component_get_icalcomponent
(master_comp), itt, mod);
+ e_cal_util_remove_instances_ex (e_cal_component_get_icalcomponent
(master_comp), itt, mod, e_cal_cache_resolve_timezone_cb, cal_cache);
g_clear_object (&itt);
}
@@ -2220,7 +2220,7 @@ ecmb_remove_object_sync (ECalMetaBackend *meta_backend,
i_cal_time_convert_to_zone_inplace (itt, i_cal_timezone_get_utc_timezone ());
}
- e_cal_util_remove_instances (e_cal_component_get_icalcomponent (master_comp), itt,
mod);
+ e_cal_util_remove_instances_ex (e_cal_component_get_icalcomponent (master_comp), itt,
mod, e_cal_cache_resolve_timezone_cb, cal_cache);
fromtt = i_cal_time_as_timet (itt);
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]