[evolution-data-server] Calendar: Support THIS_AND_FUTURE range for the Recurrence-ID



commit 45abb196e1d26f406f4c549548e7df52bbe4ff93
Author: Milan Crha <mcrha redhat com>
Date:   Tue Jun 8 18:02:04 2021 +0200

    Calendar: Support THIS_AND_FUTURE range for the Recurrence-ID
    
    The ECalComponent needs to read/write the range kind, thus it's preserved.
    The backends need to read the kind and update the local components properly,
    when an update of the component is received.
    
    Related to https://gitlab.gnome.org/GNOME/evolution/-/issues/1527

 src/calendar/backends/file/e-cal-backend-file.c | 21 ++++--
 src/calendar/libecal/e-cal-component.c          | 87 ++++++++++++++++++++-----
 src/calendar/libedata-cal/e-cal-meta-backend.c  | 17 ++++-
 tests/libecal/test-cal-component.c              | 17 ++---
 4 files changed, 113 insertions(+), 29 deletions(-)
---
diff --git a/src/calendar/backends/file/e-cal-backend-file.c b/src/calendar/backends/file/e-cal-backend-file.c
index 617ac2975..da5e13f28 100644
--- a/src/calendar/backends/file/e-cal-backend-file.c
+++ b/src/calendar/backends/file/e-cal-backend-file.c
@@ -3038,7 +3038,7 @@ remove_instance (ECalBackendFile *cbfile,
 
                e_cal_util_remove_instances_ex (
                        e_cal_component_get_icalcomponent (obj_data->full_object),
-                       rid_struct, E_CAL_OBJ_MOD_THIS, resolve_tzid_cb, &rtd);
+                       rid_struct, mod, resolve_tzid_cb, &rtd);
 
                resolve_tzid_data_clear (&rtd);
                g_clear_object (&rid_struct);
@@ -3317,6 +3317,7 @@ e_cal_backend_file_remove_objects (ECalBackendSync *backend,
 static gboolean
 cancel_received_object (ECalBackendFile *cbfile,
                         ECalComponent *comp,
+                       ECalObjModType mod,
                         ECalComponent **old_comp,
                         ECalComponent **new_comp)
 {
@@ -3341,7 +3342,7 @@ cancel_received_object (ECalBackendFile *cbfile,
        rid = e_cal_component_get_recurid_as_string (comp);
        if (rid && *rid) {
                obj_data = remove_instance (
-                       cbfile, obj_data, uid, rid, E_CAL_OBJ_MOD_THIS,
+                       cbfile, obj_data, uid, rid, mod,
                        old_comp, new_comp, NULL);
                if (obj_data && obj_data->full_object && !*new_comp) {
                        *new_comp = e_cal_component_clone (obj_data->full_object);
@@ -3629,6 +3630,7 @@ e_cal_backend_file_receive_objects (ECalBackendSync *backend,
        for (link = comps; link; link = g_slist_next (link)) {
                ECalComponent *old_component = NULL;
                ECalComponent *new_component = NULL;
+               ECalObjModType mod = E_CAL_OBJ_MOD_THIS;
                ICalTime *current;
                const gchar *uid;
                gchar *rid;
@@ -3659,6 +3661,17 @@ e_cal_backend_file_receive_objects (ECalBackendSync *backend,
                uid = e_cal_component_get_uid (comp);
                rid = e_cal_component_get_recurid_as_string (comp);
 
+               if (rid) {
+                       ECalComponentRange *range;
+
+                       range = e_cal_component_get_recurid (comp);
+
+                       if (range && e_cal_component_range_get_kind (range) == 
E_CAL_COMPONENT_RANGE_THISFUTURE)
+                               mod = E_CAL_OBJ_MOD_THIS_AND_FUTURE;
+
+                       e_cal_component_range_free (range);
+               }
+
                if (e_cal_util_component_has_property (subcomp, I_CAL_METHOD_PROPERTY))
                        method = i_cal_component_get_method (subcomp);
                else
@@ -3680,7 +3693,7 @@ e_cal_backend_file_receive_objects (ECalBackendSync *backend,
                                        ECalComponent *ignore_comp = NULL;
 
                                        remove_instance (
-                                               cbfile, obj_data, uid, rid, E_CAL_OBJ_MOD_THIS,
+                                               cbfile, obj_data, uid, rid, mod,
                                                &old_component, &ignore_comp, NULL);
 
                                        if (ignore_comp)
@@ -3741,7 +3754,7 @@ e_cal_backend_file_receive_objects (ECalBackendSync *backend,
                        goto error;
                        break;
                case I_CAL_METHOD_CANCEL:
-                       if (cancel_received_object (cbfile, comp, &old_component, &new_component)) {
+                       if (cancel_received_object (cbfile, comp, mod, &old_component, &new_component)) {
                                ECalComponentId *id;
 
                                id = e_cal_component_get_id (comp);
diff --git a/src/calendar/libecal/e-cal-component.c b/src/calendar/libecal/e-cal-component.c
index 89824d84c..a3dddcc8f 100644
--- a/src/calendar/libecal/e-cal-component.c
+++ b/src/calendar/libecal/e-cal-component.c
@@ -1587,13 +1587,17 @@ e_cal_component_set_descriptions (ECalComponent *comp,
 static ECalComponentDateTime *
 get_datetime (ICalComponent *icalcomp,
              ICalPropertyKind prop_kind,
-              ICalTime * (* get_prop_func) (ICalProperty *prop))
+              ICalTime * (* get_prop_func) (ICalProperty *prop),
+             ICalProperty **out_prop)
 {
        ICalProperty *prop;
        ICalParameter *param;
        ICalTime *value = NULL;
        gchar *tzid;
 
+       if (out_prop)
+               *out_prop = NULL;
+
        prop = i_cal_component_get_first_property (icalcomp, prop_kind);
        if (prop)
                value = get_prop_func (prop);
@@ -1614,7 +1618,11 @@ get_datetime (ICalComponent *icalcomp,
                tzid = NULL;
 
        g_clear_object (&param);
-       g_clear_object (&prop);
+
+       if (out_prop)
+               *out_prop = prop;
+       else
+               g_clear_object (&prop);
 
        return e_cal_component_datetime_new_take (value, tzid);
 }
@@ -1626,13 +1634,17 @@ set_datetime (ICalComponent *icalcomp,
              ICalProperty *(* prop_new_func) (ICalTime *tt),
               void (* prop_set_func) (ICalProperty *prop,
                                      ICalTime *tt),
-             const ECalComponentDateTime *dt)
+             const ECalComponentDateTime *dt,
+             ICalProperty **out_prop)
 {
        ICalProperty *prop;
        ICalParameter *param;
        ICalTime *tt;
        const gchar *tzid;
 
+       if (out_prop)
+               *out_prop = NULL;
+
        prop = i_cal_component_get_first_property (icalcomp, prop_kind);
 
        /* If we are setting the property to NULL (i.e. removing it), then
@@ -1683,7 +1695,11 @@ set_datetime (ICalComponent *icalcomp,
        }
 
        g_clear_object (&param);
-       g_clear_object (&prop);
+
+       if (out_prop)
+               *out_prop = prop;
+       else
+               g_clear_object (&prop);
 }
 
 /* This tries to get the DTSTART + DURATION for a VEVENT or VTODO. In a
@@ -1704,7 +1720,7 @@ e_cal_component_get_start_plus_duration (ECalComponent *comp)
        }
 
        /* Get the DTSTART time. */
-       dt = get_datetime (comp->priv->icalcomp, I_CAL_DTSTART_PROPERTY, i_cal_property_get_dtstart);
+       dt = get_datetime (comp->priv->icalcomp, I_CAL_DTSTART_PROPERTY, i_cal_property_get_dtstart, NULL);
        if (!dt) {
                g_object_unref (duration);
                return NULL;
@@ -1760,7 +1776,7 @@ e_cal_component_get_dtend (ECalComponent *comp)
        g_return_val_if_fail (E_IS_CAL_COMPONENT (comp), NULL);
        g_return_val_if_fail (comp->priv->icalcomp != NULL, NULL);
 
-       dt = get_datetime (comp->priv->icalcomp, I_CAL_DTEND_PROPERTY, i_cal_property_get_dtend);
+       dt = get_datetime (comp->priv->icalcomp, I_CAL_DTEND_PROPERTY, i_cal_property_get_dtend, NULL);
 
        /* If we don't have a DTEND property, then we try to get DTSTART
         * + DURATION. */
@@ -1789,7 +1805,8 @@ e_cal_component_set_dtend (ECalComponent *comp,
        set_datetime (comp->priv->icalcomp, I_CAL_DTEND_PROPERTY,
                i_cal_property_new_dtend,
                i_cal_property_set_dtend,
-               dt);
+               dt,
+               NULL);
 
        /* Make sure we remove any existing DURATION property, as it can't be
         * used with a DTEND. If DTEND is set to NULL, i.e. removed, we also
@@ -1883,7 +1900,7 @@ e_cal_component_get_dtstart (ECalComponent *comp)
        g_return_val_if_fail (E_IS_CAL_COMPONENT (comp), NULL);
        g_return_val_if_fail (comp->priv->icalcomp != NULL, NULL);
 
-       return get_datetime (comp->priv->icalcomp, I_CAL_DTSTART_PROPERTY, i_cal_property_get_dtstart);
+       return get_datetime (comp->priv->icalcomp, I_CAL_DTSTART_PROPERTY, i_cal_property_get_dtstart, NULL);
 }
 
 /**
@@ -1905,7 +1922,8 @@ e_cal_component_set_dtstart (ECalComponent *comp,
        set_datetime (comp->priv->icalcomp, I_CAL_DTSTART_PROPERTY,
                i_cal_property_new_dtstart,
                i_cal_property_set_dtstart,
-               dt);
+               dt,
+               NULL);
 
        comp->priv->need_sequence_inc = TRUE;
 }
@@ -1931,7 +1949,7 @@ e_cal_component_get_due (ECalComponent *comp)
        g_return_val_if_fail (E_IS_CAL_COMPONENT (comp), NULL);
        g_return_val_if_fail (comp->priv->icalcomp != NULL, NULL);
 
-       dt = get_datetime (comp->priv->icalcomp, I_CAL_DUE_PROPERTY, i_cal_property_get_due);
+       dt = get_datetime (comp->priv->icalcomp, I_CAL_DUE_PROPERTY, i_cal_property_get_due, NULL);
 
        /* If we don't have a DTEND property, then we try to get DTSTART
         * + DURATION. */
@@ -1962,7 +1980,8 @@ e_cal_component_set_due (ECalComponent *comp,
        set_datetime (comp->priv->icalcomp, I_CAL_DUE_PROPERTY,
                i_cal_property_new_due,
                i_cal_property_set_due,
-               dt);
+               dt,
+               NULL);
 
        /* Make sure we remove any existing DURATION property, as it can't be
         * used with a DTEND. If DTEND is set to NULL, i.e. removed, we also
@@ -2788,16 +2807,31 @@ ECalComponentRange *
 e_cal_component_get_recurid (ECalComponent *comp)
 {
        ECalComponentDateTime *dt;
+       ECalComponentRangeKind range_kind;
+       ICalProperty *prop = NULL;
+       ICalParameter *param;
 
        g_return_val_if_fail (E_IS_CAL_COMPONENT (comp), NULL);
        g_return_val_if_fail (comp->priv->icalcomp != NULL, NULL);
 
-       dt = get_datetime (comp->priv->icalcomp, I_CAL_RECURRENCEID_PROPERTY, 
i_cal_property_get_recurrenceid);
+       dt = get_datetime (comp->priv->icalcomp, I_CAL_RECURRENCEID_PROPERTY, 
i_cal_property_get_recurrenceid, &prop);
 
-       if (!dt)
+       if (!dt) {
+               g_clear_object (&prop);
                return NULL;
+       }
+
+       range_kind = E_CAL_COMPONENT_RANGE_SINGLE;
+       param = i_cal_property_get_first_parameter (prop, I_CAL_RANGE_PARAMETER);
 
-       return e_cal_component_range_new_take (E_CAL_COMPONENT_RANGE_SINGLE, dt);
+       /* RFC 5545 says it can use only THIS_AND_FUTURE here */
+       if (param && i_cal_parameter_get_range (param) == I_CAL_RANGE_THISANDFUTURE)
+               range_kind = E_CAL_COMPONENT_RANGE_THISFUTURE;
+
+       g_clear_object (&param);
+       g_clear_object (&prop);
+
+       return e_cal_component_range_new_take (range_kind, dt);
 }
 
 /**
@@ -2830,6 +2864,7 @@ e_cal_component_set_recurid (ECalComponent *comp,
                             const ECalComponentRange *recur_id)
 {
        ECalComponentDateTime *dt;
+       ICalProperty *prop = NULL;
 
        g_return_if_fail (E_IS_CAL_COMPONENT (comp));
        g_return_if_fail (comp->priv->icalcomp != NULL);
@@ -2839,7 +2874,29 @@ e_cal_component_set_recurid (ECalComponent *comp,
        set_datetime (comp->priv->icalcomp, I_CAL_RECURRENCEID_PROPERTY,
                i_cal_property_new_recurrenceid,
                i_cal_property_set_recurrenceid,
-               dt);
+               dt,
+               &prop);
+
+       if (prop) {
+               ICalParameter *param;
+
+               param = i_cal_property_get_first_parameter (prop, I_CAL_RANGE_PARAMETER);
+
+               /* RFC 5545 says it can use only THIS_AND_FUTURE here */
+               if (e_cal_component_range_get_kind (recur_id) == E_CAL_COMPONENT_RANGE_THISFUTURE) {
+                       if (param) {
+                               i_cal_parameter_set_range (param, I_CAL_RANGE_THISANDFUTURE);
+                       } else {
+                               param = i_cal_parameter_new_range (I_CAL_RANGE_THISANDFUTURE);
+                               i_cal_property_add_parameter (prop, param);
+                       }
+               } else if (param) {
+                       i_cal_property_remove_parameter_by_ref (prop, param);
+               }
+
+               g_clear_object (&param);
+               g_clear_object (&prop);
+       }
 }
 
 /**
diff --git a/src/calendar/libedata-cal/e-cal-meta-backend.c b/src/calendar/libedata-cal/e-cal-meta-backend.c
index 7dd5ad065..10da9a258 100644
--- a/src/calendar/libedata-cal/e-cal-meta-backend.c
+++ b/src/calendar/libedata-cal/e-cal-meta-backend.c
@@ -2513,7 +2513,20 @@ ecmb_receive_object_sync (ECalMetaBackend *meta_backend,
                }
        }
 
-       mod = e_cal_component_is_instance (comp) ? E_CAL_OBJ_MOD_THIS : E_CAL_OBJ_MOD_ALL;
+       if (e_cal_component_is_instance (comp)) {
+               ECalComponentRange *range;
+
+               range = e_cal_component_get_recurid (comp);
+
+               if (range && e_cal_component_range_get_kind (range) == E_CAL_COMPONENT_RANGE_THISFUTURE)
+                       mod = E_CAL_OBJ_MOD_THIS_AND_FUTURE;
+               else
+                       mod = E_CAL_OBJ_MOD_THIS;
+
+               e_cal_component_range_free (range);
+       } else {
+               mod = E_CAL_OBJ_MOD_ALL;
+       }
 
        switch (method) {
        case I_CAL_METHOD_PUBLISH:
@@ -2535,7 +2548,7 @@ ecmb_receive_object_sync (ECalMetaBackend *meta_backend,
                break;
        case I_CAL_METHOD_CANCEL:
                if (is_in_cache) {
-                       success = ecmb_remove_object_sync (meta_backend, cal_cache, offline_flag, 
conflict_resolution, E_CAL_OBJ_MOD_THIS, opflags,
+                       success = ecmb_remove_object_sync (meta_backend, cal_cache, offline_flag, 
conflict_resolution, mod, opflags,
                                e_cal_component_id_get_uid (id), e_cal_component_id_get_rid (id), NULL, NULL, 
cancellable, error);
                } else {
                        g_propagate_error (error, e_cal_client_error_create 
(E_CAL_CLIENT_ERROR_OBJECT_NOT_FOUND, NULL));
diff --git a/tests/libecal/test-cal-component.c b/tests/libecal/test-cal-component.c
index 3c2368afb..124afb101 100644
--- a/tests/libecal/test-cal-component.c
+++ b/tests/libecal/test-cal-component.c
@@ -3158,14 +3158,15 @@ test_component_recurid (void)
        struct _values {
                const gchar *time;
                const gchar *tzid;
+               ECalComponentRangeKind range_kind;
        } values[] = {
-               { "20181215T111213Z", NULL },
-               { "20190131T121314Z", NULL },
-               { NULL, NULL },
-               { "20200708T010305Z", NULL },
-               { "20211215T101112", "America/New_York" },
-               { "20221110T090807", "UTC" },
-               { "20231009", NULL }
+               { "20181215T111213Z",   NULL,                   E_CAL_COMPONENT_RANGE_SINGLE },
+               { "20190131T121314Z",   NULL,                   E_CAL_COMPONENT_RANGE_THISFUTURE },
+               { NULL,                 NULL,                   E_CAL_COMPONENT_RANGE_SINGLE },
+               { "20200708T010305Z",   NULL,                   E_CAL_COMPONENT_RANGE_SINGLE },
+               { "20211215T101112",    "America/New_York",     E_CAL_COMPONENT_RANGE_SINGLE },
+               { "20221110T090807",    "UTC",                  E_CAL_COMPONENT_RANGE_THISFUTURE },
+               { "20231009",           NULL,                   E_CAL_COMPONENT_RANGE_THISFUTURE }
        };
        ECalComponent *comp;
        gint ii;
@@ -3193,7 +3194,7 @@ test_component_recurid (void)
                                }
                        }
 
-                       rid = e_cal_component_range_new_take (E_CAL_COMPONENT_RANGE_SINGLE, dt);
+                       rid = e_cal_component_range_new_take (values[ii].range_kind, dt);
                }
 
                e_cal_component_set_recurid (comp, rid);


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