[evolution-data-server/wip/mcrha/libical-glib] Add ECalComponentParameterBag to store ICalParameter objects



commit 998796cb3b5c63f159411bfbe94f9a3e43c95bc1
Author: Milan Crha <mcrha redhat com>
Date:   Fri Mar 1 13:39:40 2019 +0100

    Add ECalComponentParameterBag to store ICalParameter objects

 .../evolution-data-server-docs.sgml.in             |   1 +
 src/calendar/libecal/CMakeLists.txt                |   2 +
 .../libecal/e-cal-component-alarm-trigger.c        |  52 ++-
 .../libecal/e-cal-component-alarm-trigger.h        |   4 +
 src/calendar/libecal/e-cal-component-alarm.c       |   1 +
 src/calendar/libecal/e-cal-component-attendee.c    |  56 ++-
 src/calendar/libecal/e-cal-component-attendee.h    |   5 +
 src/calendar/libecal/e-cal-component-organizer.c   |  49 ++-
 src/calendar/libecal/e-cal-component-organizer.h   |   5 +
 .../libecal/e-cal-component-parameter-bag.c        | 354 ++++++++++++++++++
 .../libecal/e-cal-component-parameter-bag.h        |  98 +++++
 .../libecal/e-cal-component-property-bag.c         |   4 +-
 src/calendar/libecal/libecal.h                     |   1 +
 tests/libecal/test-cal-component.c                 | 402 ++++++++++++++++++---
 14 files changed, 976 insertions(+), 58 deletions(-)
---
diff --git a/docs/reference/evolution-data-server/evolution-data-server-docs.sgml.in 
b/docs/reference/evolution-data-server/evolution-data-server-docs.sgml.in
index c0ef85e2a..f3834222c 100644
--- a/docs/reference/evolution-data-server/evolution-data-server-docs.sgml.in
+++ b/docs/reference/evolution-data-server/evolution-data-server-docs.sgml.in
@@ -157,6 +157,7 @@
       <xi:include href="xml/e-cal-component-datetime.xml"/>
       <xi:include href="xml/e-cal-component-id.xml"/>
       <xi:include href="xml/e-cal-component-organizer.xml"/>
+      <xi:include href="xml/e-cal-component-parameter-bag.xml"/>
       <xi:include href="xml/e-cal-component-period.xml"/>
       <xi:include href="xml/e-cal-component-property-bag.xml"/>
       <xi:include href="xml/e-cal-component-range.xml"/>
diff --git a/src/calendar/libecal/CMakeLists.txt b/src/calendar/libecal/CMakeLists.txt
index e2b318931..e2b22c893 100644
--- a/src/calendar/libecal/CMakeLists.txt
+++ b/src/calendar/libecal/CMakeLists.txt
@@ -20,6 +20,7 @@ set(SOURCES
        e-cal-component-datetime.c
        e-cal-component-id.c
        e-cal-component-organizer.c
+       e-cal-component-parameter-bag.c
        e-cal-component-period.c
        e-cal-component-property-bag.c
        e-cal-component-range.c
@@ -47,6 +48,7 @@ set(HEADERS
        e-cal-component-attendee.h
        e-cal-component-datetime.h
        e-cal-component-id.h
+       e-cal-component-parameter-bag.h
        e-cal-component-organizer.h
        e-cal-component-period.h
        e-cal-component-property-bag.h
diff --git a/src/calendar/libecal/e-cal-component-alarm-trigger.c 
b/src/calendar/libecal/e-cal-component-alarm-trigger.c
index 3ff4d3c3b..823e0f97e 100644
--- a/src/calendar/libecal/e-cal-component-alarm-trigger.c
+++ b/src/calendar/libecal/e-cal-component-alarm-trigger.c
@@ -26,6 +26,8 @@
  * Contains functions to work with the #ECalComponentAlarmTrigger structure.
  **/
 
+#include "e-cal-component-parameter-bag.h"
+
 #include "e-cal-component-alarm-trigger.h"
 
 G_DEFINE_BOXED_TYPE (ECalComponentAlarmTrigger, e_cal_component_alarm_trigger, 
e_cal_component_alarm_trigger_copy, e_cal_component_alarm_trigger_free)
@@ -36,6 +38,8 @@ struct _ECalComponentAlarmTrigger {
        /* Only one of the below can be set, depending on the 'kind' */
        ICalDurationType *rel_duration;
        ICalTimetype *abs_time;
+
+       ECalComponentParameterBag *parameter_bag;
 };
 
 /**
@@ -62,6 +66,7 @@ e_cal_component_alarm_trigger_new_relative (ECalComponentAlarmTriggerKind kind,
        g_return_val_if_fail (I_CAL_IS_DURATION_TYPE (duration), NULL);
 
        trigger = g_new0 (ECalComponentAlarmTrigger, 1);
+       trigger->parameter_bag = e_cal_component_parameter_bag_new ();
 
        e_cal_component_alarm_trigger_set_relative (trigger, kind, duration);
 
@@ -91,6 +96,7 @@ e_cal_component_alarm_trigger_new_absolute (const ICalTimetype *absolute_time)
        g_return_val_if_fail (I_CAL_IS_TIMETYPE (absolute_time), NULL);
 
        trigger = g_new0 (ECalComponentAlarmTrigger, 1);
+       trigger->parameter_bag = e_cal_component_parameter_bag_new ();
 
        e_cal_component_alarm_trigger_set_absolute (trigger, absolute_time);
 
@@ -121,6 +127,7 @@ e_cal_component_alarm_trigger_new_from_property (const ICalProperty *property)
                return NULL;
 
        trigger = g_new0 (ECalComponentAlarmTrigger, 1);
+       trigger->parameter_bag = e_cal_component_parameter_bag_new ();
 
        e_cal_component_alarm_trigger_set_from_property (trigger, property);
 
@@ -141,12 +148,18 @@ e_cal_component_alarm_trigger_new_from_property (const ICalProperty *property)
 ECalComponentAlarmTrigger *
 e_cal_component_alarm_trigger_copy (const ECalComponentAlarmTrigger *trigger)
 {
+       ECalComponentAlarmTrigger *copy;
+
        g_return_val_if_fail (trigger != NULL, NULL);
 
        if (trigger->kind == E_CAL_COMPONENT_ALARM_TRIGGER_ABSOLUTE)
-               return e_cal_component_alarm_trigger_new_absolute (trigger->abs_time);
+               copy = e_cal_component_alarm_trigger_new_absolute (trigger->abs_time);
+       else
+               copy = e_cal_component_alarm_trigger_new_relative (trigger->kind, trigger->rel_duration);
 
-       return e_cal_component_alarm_trigger_new_relative (trigger->kind, trigger->rel_duration);
+       e_cal_component_parameter_bag_assign (copy->parameter_bag, trigger->parameter_bag);
+
+       return copy;
 }
 
 /**
@@ -166,12 +179,25 @@ e_cal_component_alarm_trigger_free (gpointer trigger)
        ECalComponentAlarmTrigger *trg = trigger;
 
        if (trg) {
+               e_cal_component_parameter_bag_free (trg->parameter_bag);
                g_clear_object (&trg->rel_duration);
                g_clear_object (&trg->abs_time);
                g_free (trg);
        }
 }
 
+static gboolean
+e_cal_component_alarm_trigger_bag_filter_params_cb (ICalParameter *param,
+                                                   gpointer user_data)
+{
+       ICalParameterKind kind;
+
+       kind = i_cal_parameter_isa (param);
+
+       return kind != I_CAL_VALUE_PARAMETER &&
+              kind != I_CAL_RELATED_PARAMETER;
+}
+
 /**
  * e_cal_component_alarm_trigger_set_from_property:
  * @trigger: an #ECalComponentAlarmTrigger
@@ -260,6 +286,8 @@ e_cal_component_alarm_trigger_set_from_property (ECalComponentAlarmTrigger *trig
        }
 
        g_clear_object (&trgtype);
+
+       e_cal_component_parameter_bag_set_from_property (trigger->parameter_bag, prop, 
e_cal_component_alarm_trigger_bag_filter_params_cb, NULL);
 }
 
 /**
@@ -364,6 +392,8 @@ e_cal_component_alarm_trigger_fill_property (const ECalComponentAlarmTrigger *tr
                i_cal_property_remove_parameter_by_kind (property, I_CAL_RELATED_PARAMETER);
        }
        g_clear_object (&param);
+
+       e_cal_component_parameter_bag_fill_property (trigger->parameter_bag, property);
 }
 
 /**
@@ -565,3 +595,21 @@ e_cal_component_alarm_trigger_set_absolute_time (ECalComponentAlarmTrigger *trig
                trigger->abs_time = i_cal_timetype_new_clone ((ICalTimetype *) absolute_time);
        }
 }
+
+/**
+ * e_cal_component_alarm_trigger_get_parameter_bag:
+ * @trigger: an #ECalComponentAlarmTrigger
+ *
+ * Returns: (transfer none): an #ECalComponentParameterBag with additional
+ *    parameters stored with the trigger property, other than those accessible
+ *    with the other functions of the @trigger.
+ *
+ * Since: 3.36
+ **/
+ECalComponentParameterBag *
+e_cal_component_alarm_trigger_get_parameter_bag (const ECalComponentAlarmTrigger *trigger)
+{
+       g_return_val_if_fail (trigger != NULL, NULL);
+
+       return trigger->parameter_bag;
+}
diff --git a/src/calendar/libecal/e-cal-component-alarm-trigger.h 
b/src/calendar/libecal/e-cal-component-alarm-trigger.h
index 8b9e165ff..bdd953304 100644
--- a/src/calendar/libecal/e-cal-component-alarm-trigger.h
+++ b/src/calendar/libecal/e-cal-component-alarm-trigger.h
@@ -26,6 +26,7 @@
 #include <glib-object.h>
 #include <libical-glib/libical-glib.h>
 
+#include <libecal/e-cal-component-parameter-bag.h>
 #include <libecal/e-cal-enums.h>
 
 G_BEGIN_DECLS
@@ -87,6 +88,9 @@ ICalTimetype *        e_cal_component_alarm_trigger_get_absolute_time
 void           e_cal_component_alarm_trigger_set_absolute_time
                                                (ECalComponentAlarmTrigger *trigger,
                                                 const ICalTimetype *absolute_time);
+ECalComponentParameterBag *
+               e_cal_component_alarm_trigger_get_parameter_bag
+                                               (const ECalComponentAlarmTrigger *trigger);
 
 G_END_DECLS
 
diff --git a/src/calendar/libecal/e-cal-component-alarm.c b/src/calendar/libecal/e-cal-component-alarm.c
index cb9de1b98..e52195c19 100644
--- a/src/calendar/libecal/e-cal-component-alarm.c
+++ b/src/calendar/libecal/e-cal-component-alarm.c
@@ -31,6 +31,7 @@
 #include "e-cal-component-alarm-repeat.h"
 #include "e-cal-component-alarm-trigger.h"
 #include "e-cal-component-attendee.h"
+#include "e-cal-component-property-bag.h"
 #include "e-cal-component-text.h"
 #include "e-cal-enums.h"
 
diff --git a/src/calendar/libecal/e-cal-component-attendee.c b/src/calendar/libecal/e-cal-component-attendee.c
index 7179e0373..b51cede6c 100644
--- a/src/calendar/libecal/e-cal-component-attendee.c
+++ b/src/calendar/libecal/e-cal-component-attendee.c
@@ -26,6 +26,8 @@
  * Contains functions to work with the #ECalComponentAttendee structure.
  **/
 
+#include "e-cal-component-parameter-bag.h"
+
 #include "e-cal-component-attendee.h"
 
 G_DEFINE_BOXED_TYPE (ECalComponentAttendee, e_cal_component_attendee, e_cal_component_attendee_copy, 
e_cal_component_attendee_free)
@@ -44,6 +46,8 @@ struct _ECalComponentAttendee {
        gchar *sentby;
        gchar *cn;
        gchar *language;
+
+       ECalComponentParameterBag *parameter_bag;
 };
 
 /**
@@ -65,6 +69,7 @@ e_cal_component_attendee_new (void)
        attendee->cutype = I_CAL_CUTYPE_NONE;
        attendee->role = I_CAL_ROLE_REQPARTICIPANT;
        attendee->partstat = I_CAL_PARTSTAT_NEEDSACTION;
+       attendee->parameter_bag = e_cal_component_parameter_bag_new ();
 
        return attendee;
 }
@@ -167,9 +172,11 @@ e_cal_component_attendee_new_from_property (const ICalProperty *property)
 ECalComponentAttendee *
 e_cal_component_attendee_copy (const ECalComponentAttendee *attendee)
 {
+       ECalComponentAttendee *copy;
+
        g_return_val_if_fail (attendee != NULL, NULL);
 
-       return e_cal_component_attendee_new_full (attendee->value,
+       copy = e_cal_component_attendee_new_full (attendee->value,
                attendee->member,
                attendee->cutype,
                attendee->role,
@@ -180,6 +187,10 @@ e_cal_component_attendee_copy (const ECalComponentAttendee *attendee)
                attendee->sentby,
                attendee->cn,
                attendee->language);
+
+       e_cal_component_parameter_bag_assign (copy->parameter_bag, attendee->parameter_bag);
+
+       return copy;
 }
 
 /**
@@ -199,6 +210,7 @@ e_cal_component_attendee_free (gpointer attendee)
        ECalComponentAttendee *att = attendee;
 
        if (att) {
+               e_cal_component_parameter_bag_free (att->parameter_bag);
                g_free (att->value);
                g_free (att->member);
                g_free (att->delegatedfrom);
@@ -210,6 +222,26 @@ e_cal_component_attendee_free (gpointer attendee)
        }
 }
 
+static gboolean
+e_cal_component_attendee_filter_params_cb (ICalParameter *param,
+                                          gpointer user_data)
+{
+       ICalParameterKind kind;
+
+       kind = i_cal_parameter_isa (param);
+
+       return kind != I_CAL_MEMBER_PARAMETER &&
+              kind != I_CAL_CUTYPE_PARAMETER &&
+              kind != I_CAL_ROLE_PARAMETER &&
+              kind != I_CAL_PARTSTAT_PARAMETER &&
+              kind != I_CAL_RSVP_PARAMETER &&
+              kind != I_CAL_DELEGATEDFROM_PARAMETER &&
+              kind != I_CAL_DELEGATEDTO_PARAMETER &&
+              kind != I_CAL_SENTBY_PARAMETER &&
+              kind != I_CAL_CN_PARAMETER &&
+              kind != I_CAL_LANGUAGE_PARAMETER;
+}
+
 /**
  * e_cal_component_attendee_set_from_property:
  * @attendee: an #ECalComponentAttendee
@@ -272,6 +304,8 @@ e_cal_component_attendee_set_from_property (ECalComponentAttendee *attendee,
        param = i_cal_property_get_first_parameter (prop, I_CAL_LANGUAGE_PARAMETER);
        e_cal_component_attendee_set_language (attendee, param ? i_cal_parameter_get_language (param) : NULL);
        g_clear_object (&param);
+
+       e_cal_component_parameter_bag_set_from_property (attendee->parameter_bag, prop, 
e_cal_component_attendee_filter_params_cb, NULL);
 }
 
 /**
@@ -360,6 +394,8 @@ e_cal_component_attendee_fill_property (const ECalComponentAttendee *attendee,
        fill_param (I_CAL_LANGUAGE_PARAMETER, language, attendee->language && *attendee->language);
 
        #undef fill_param
+
+       e_cal_component_parameter_bag_fill_property (attendee->parameter_bag, property);
 }
 
 /**
@@ -792,3 +828,21 @@ e_cal_component_attendee_set_language (ECalComponentAttendee *attendee,
                attendee->language = g_strdup (language);
        }
 }
+
+/**
+ * e_cal_component_attendee_get_parameter_bag:
+ * @attendee: an #ECalComponentAttendee
+ *
+ * Returns: (transfer none): an #ECalComponentParameterBag with additional
+ *    parameters stored with the attendee property, other than those accessible
+ *    with the other functions of the @attendee.
+ *
+ * Since: 3.36
+ **/
+ECalComponentParameterBag *
+e_cal_component_attendee_get_parameter_bag (const ECalComponentAttendee *attendee)
+{
+       g_return_val_if_fail (attendee != NULL, NULL);
+
+       return attendee->parameter_bag;
+}
diff --git a/src/calendar/libecal/e-cal-component-attendee.h b/src/calendar/libecal/e-cal-component-attendee.h
index 01f73fe6d..71015ddd8 100644
--- a/src/calendar/libecal/e-cal-component-attendee.h
+++ b/src/calendar/libecal/e-cal-component-attendee.h
@@ -26,6 +26,8 @@
 #include <glib-object.h>
 #include <libical-glib/libical-glib.h>
 
+#include <libecal/e-cal-component-parameter-bag.h>
+
 G_BEGIN_DECLS
 
 /**
@@ -122,6 +124,9 @@ const gchar *       e_cal_component_attendee_get_language
 void           e_cal_component_attendee_set_language
                                                (ECalComponentAttendee *attendee,
                                                 const gchar *language);
+ECalComponentParameterBag *
+               e_cal_component_attendee_get_parameter_bag
+                                               (const ECalComponentAttendee *attendee);
 
 G_END_DECLS
 
diff --git a/src/calendar/libecal/e-cal-component-organizer.c 
b/src/calendar/libecal/e-cal-component-organizer.c
index 6a19d863a..fd949a5b3 100644
--- a/src/calendar/libecal/e-cal-component-organizer.c
+++ b/src/calendar/libecal/e-cal-component-organizer.c
@@ -26,6 +26,8 @@
  * Contains functions to work with the #ECalComponentOrganizer structure.
  **/
 
+#include "e-cal-component-parameter-bag.h"
+
 #include "e-cal-component-organizer.h"
 
 G_DEFINE_BOXED_TYPE (ECalComponentOrganizer, e_cal_component_organizer, e_cal_component_organizer_copy, 
e_cal_component_organizer_free)
@@ -35,6 +37,8 @@ struct _ECalComponentOrganizer {
        gchar *sentby;
        gchar *cn;
        gchar *language;
+
+       ECalComponentParameterBag *parameter_bag;
 };
 
 /**
@@ -53,6 +57,7 @@ e_cal_component_organizer_new (void)
        ECalComponentOrganizer *organizer;
 
        organizer = g_new0 (ECalComponentOrganizer, 1);
+       organizer->parameter_bag = e_cal_component_parameter_bag_new ();
 
        return organizer;
 }
@@ -134,12 +139,18 @@ e_cal_component_organizer_new_from_property (const ICalProperty *property)
 ECalComponentOrganizer *
 e_cal_component_organizer_copy (const ECalComponentOrganizer *organizer)
 {
+       ECalComponentOrganizer *copy;
+
        g_return_val_if_fail (organizer != NULL, NULL);
 
-       return e_cal_component_organizer_new_full (organizer->value,
+       copy = e_cal_component_organizer_new_full (organizer->value,
                organizer->sentby,
                organizer->cn,
                organizer->language);
+
+       e_cal_component_parameter_bag_assign (copy->parameter_bag, organizer->parameter_bag);
+
+       return copy;
 }
 
 /**
@@ -159,6 +170,7 @@ e_cal_component_organizer_free (gpointer organizer)
        ECalComponentOrganizer *org = organizer;
 
        if (org) {
+               e_cal_component_parameter_bag_free (org->parameter_bag);
                g_free (org->value);
                g_free (org->sentby);
                g_free (org->cn);
@@ -167,6 +179,19 @@ e_cal_component_organizer_free (gpointer organizer)
        }
 }
 
+static gboolean
+e_cal_component_organizer_filter_params_cb (ICalParameter *param,
+                                           gpointer user_data)
+{
+       ICalParameterKind kind;
+
+       kind = i_cal_parameter_isa (param);
+
+       return kind != I_CAL_SENTBY_PARAMETER &&
+              kind != I_CAL_CN_PARAMETER &&
+              kind != I_CAL_LANGUAGE_PARAMETER;
+}
+
 /**
  * e_cal_component_organizer_set_from_property:
  * @organizer: an #ECalComponentOrganizer
@@ -201,6 +226,8 @@ e_cal_component_organizer_set_from_property (ECalComponentOrganizer *organizer,
        param = i_cal_property_get_first_parameter (prop, I_CAL_LANGUAGE_PARAMETER);
        e_cal_component_organizer_set_language (organizer, param ? i_cal_parameter_get_language (param) : 
NULL);
        g_clear_object (&param);
+
+       e_cal_component_parameter_bag_set_from_property (organizer->parameter_bag, prop, 
e_cal_component_organizer_filter_params_cb, NULL);
 }
 
 /**
@@ -272,6 +299,8 @@ e_cal_component_organizer_fill_property (const ECalComponentOrganizer *organizer
        fill_param (I_CAL_LANGUAGE_PARAMETER, language, organizer->language && *organizer->language);
 
        #undef fill_param
+
+       e_cal_component_parameter_bag_fill_property (organizer->parameter_bag, property);
 }
 
 /**
@@ -437,3 +466,21 @@ e_cal_component_organizer_set_language (ECalComponentOrganizer *organizer,
                organizer->language = g_strdup (language);
        }
 }
+
+/**
+ * e_cal_component_organizer_get_parameter_bag:
+ * @organizer: an #ECalComponentOrganizer
+ *
+ * Returns: (transfer none): an #ECalComponentParameterBag with additional
+ *    parameters stored with the organizer property, other than those accessible
+ *    with the other functions of the @organizer.
+ *
+ * Since: 3.36
+ **/
+ECalComponentParameterBag *
+e_cal_component_organizer_get_parameter_bag (const ECalComponentOrganizer *organizer)
+{
+       g_return_val_if_fail (organizer != NULL, NULL);
+
+       return organizer->parameter_bag;
+}
diff --git a/src/calendar/libecal/e-cal-component-organizer.h 
b/src/calendar/libecal/e-cal-component-organizer.h
index 4bac9945e..20a3db73d 100644
--- a/src/calendar/libecal/e-cal-component-organizer.h
+++ b/src/calendar/libecal/e-cal-component-organizer.h
@@ -26,6 +26,8 @@
 #include <glib-object.h>
 #include <libical-glib/libical-glib.h>
 
+#include <libecal/e-cal-component-parameter-bag.h>
+
 G_BEGIN_DECLS
 
 /**
@@ -77,6 +79,9 @@ const gchar * e_cal_component_organizer_get_language
 void           e_cal_component_organizer_set_language
                                                (ECalComponentOrganizer *organizer,
                                                 const gchar *language);
+ECalComponentParameterBag *
+               e_cal_component_organizer_get_parameter_bag
+                                               (const ECalComponentOrganizer *organizer);
 
 G_END_DECLS
 
diff --git a/src/calendar/libecal/e-cal-component-parameter-bag.c 
b/src/calendar/libecal/e-cal-component-parameter-bag.c
new file mode 100644
index 000000000..234338385
--- /dev/null
+++ b/src/calendar/libecal/e-cal-component-parameter-bag.c
@@ -0,0 +1,354 @@
+/*
+ * Copyright (C) 2019 Red Hat, Inc. (www.redhat.com)
+ *
+ * This library is free software: you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this library. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#include "evolution-data-server-config.h"
+
+/**
+ * SECTION:e-cal-component-parameter-bag
+ * @short_description: An ECalComponentParameterBag structure
+ * @include: libecal/libecal.h
+ *
+ * Contains functions to work with the #ECalComponentParameterBag structure.
+ **/
+
+#include "e-cal-component-parameter-bag.h"
+
+G_DEFINE_BOXED_TYPE (ECalComponentParameterBag, e_cal_component_parameter_bag, 
e_cal_component_parameter_bag_copy, e_cal_component_parameter_bag_free)
+
+struct _ECalComponentParameterBag {
+       GPtrArray *parameters; /* ICalParameter * */
+};
+
+/**
+ * e_cal_component_parameter_bag_new:
+ *
+ * Creates a new #ECalComponentParameterBag. Free the structure
+ * with e_cal_component_parameter_bag_free(), when no longer needed.
+ *
+ * Returns: (transfer full): a newly allocated #ECalComponentParameterBag
+ *
+ * Since: 3.36
+ **/
+ECalComponentParameterBag *
+e_cal_component_parameter_bag_new (void)
+{
+       ECalComponentParameterBag *bag;
+
+       bag = g_new0 (ECalComponentParameterBag, 1);
+       bag->parameters = g_ptr_array_new_with_free_func (g_object_unref);
+
+       return bag;
+}
+
+/**
+ * e_cal_component_parameter_bag_new_from_property:
+ * @property: an #ICalProperty containing the parameters to fill the bag with
+ * @func: (nullable) (scope call): an optional %ECalComponentParameterBagFilterFunc callback
+ * @user_data: (closure func): user data for the @func
+ *
+ * Creates a new #ECalComponentParameterBag, filled with parameters
+ * from the @property, for which the @func returned %TRUE. When
+ * the @func is %NULL, all the parameters are included.
+ *
+ * Free the structure with e_cal_component_parameter_bag_free(), when no longer needed.
+ *
+ * Returns: (transfer full): a newly allocated #ECalComponentParameterBag
+ *
+ * Since: 3.36
+ **/
+ECalComponentParameterBag *
+e_cal_component_parameter_bag_new_from_property (const ICalProperty *property,
+                                                ECalComponentParameterBagFilterFunc func,
+                                                gpointer user_data)
+{
+       ECalComponentParameterBag *bag;
+
+       bag = e_cal_component_parameter_bag_new ();
+
+       e_cal_component_parameter_bag_set_from_property (bag, property, func, user_data);
+
+       return bag;
+}
+
+/**
+ * e_cal_component_parameter_bag_copy:
+ * @bag: (not nullable): an #ECalComponentParameterBag
+ *
+ * Returns a newly allocated copy of @bag, which should be freed with
+ * e_cal_component_parameter_bag_free(), when no longer needed.
+ *
+ * Returns: (transfer full): a newly allocated copy of @bag
+ *
+ * Since: 3.36
+ **/
+ECalComponentParameterBag *
+e_cal_component_parameter_bag_copy (const ECalComponentParameterBag *bag)
+{
+       ECalComponentParameterBag *copy;
+
+       g_return_val_if_fail (bag != NULL, NULL);
+
+       copy = e_cal_component_parameter_bag_new ();
+
+       e_cal_component_parameter_bag_assign (copy, bag);
+
+       return copy;
+}
+
+/**
+ * e_cal_component_parameter_bag_free: (skip)
+ * @bag: (type ECalComponentParameterBag) (nullable): an #ECalComponentParameterBag to free
+ *
+ * Free @bag, previously created by e_cal_component_parameter_bag_new(),
+ * e_cal_component_parameter_bag_new_from_component() or
+ * e_cal_component_parameter_bag_copy(). The function does nothing, if @bag
+ * is %NULL.
+ *
+ * Since: 3.36
+ **/
+void
+e_cal_component_parameter_bag_free (gpointer bag)
+{
+       ECalComponentParameterBag *bg = bag;
+
+       if (bg) {
+               g_ptr_array_unref (bg->parameters);
+               g_free (bg);
+       }
+}
+
+/**
+ * e_cal_component_parameter_bag_set_from_property:
+ * @bag: an #ECalComponentParameterBag
+ * @property: an #ICalProperty containing the parameters to fill the @bag with
+ * @func: (nullable) (scope call): an optional %ECalComponentParameterBagFilterFunc callback
+ * @user_data: (closure func): user data for the @func
+ *
+ * Fills the @bag with parameters from the @property, for which the @func
+ * returned %TRUE. When the @func is %NULL, all the parameters are included.
+ * The @bag content is cleared before any parameter is added.
+ *
+ * Since: 3.36
+ **/
+void
+e_cal_component_parameter_bag_set_from_property (ECalComponentParameterBag *bag,
+                                                const ICalProperty *property,
+                                                ECalComponentParameterBagFilterFunc func,
+                                                gpointer user_data)
+{
+       ICalProperty *prop = (ICalProperty *) property;
+       ICalParameter *param;
+
+       g_return_if_fail (bag != NULL);
+       g_return_if_fail (I_CAL_IS_PROPERTY (property));
+
+       e_cal_component_parameter_bag_clear (bag);
+
+       for (param = i_cal_property_get_first_parameter (prop, I_CAL_ANY_PARAMETER);
+            param;
+            g_object_unref (param), param = i_cal_property_get_next_parameter (prop, I_CAL_ANY_PARAMETER)) {
+               if (!func || func (param, user_data)) {
+                       e_cal_component_parameter_bag_add (bag, param);
+               }
+       }
+}
+
+/**
+ * e_cal_component_parameter_bag_fill_property:
+ * @bag: an #ECalComponentParameterBag
+ * @property: an #ICalProperty
+ *
+ * Adds all the stored parameters in the @bag to the @property.
+ * The function replaces any existing parameter with the new value,
+ * if any such exists. Otherwise the parameter is added.
+ *
+ * Since: 3.36
+ **/
+void
+e_cal_component_parameter_bag_fill_property (const ECalComponentParameterBag *bag,
+                                            ICalProperty *property)
+{
+       guint ii;
+
+       g_return_if_fail (bag != NULL);
+       g_return_if_fail (I_CAL_IS_PROPERTY (property));
+
+       for (ii = 0; ii < bag->parameters->len; ii++) {
+               ICalParameter *param = g_ptr_array_index (bag->parameters, ii);
+
+               if (param)
+                       i_cal_property_take_parameter (property, i_cal_parameter_new_clone (param));
+       }
+}
+
+/**
+ * e_cal_component_parameter_bag_assign:
+ * @bag: a destination #ECalComponentParameterBag
+ * @src_bag: a source #ECalComponentParameterBag
+ *
+ * Assigns content of the @src_bag into the @bag.
+ *
+ * Since: 3.36
+ **/
+void
+e_cal_component_parameter_bag_assign (ECalComponentParameterBag *bag,
+                                    const ECalComponentParameterBag *src_bag)
+{
+       guint count, ii;
+
+       g_return_if_fail (bag != NULL);
+       g_return_if_fail (src_bag != NULL);
+
+       e_cal_component_parameter_bag_clear (bag);
+       count = e_cal_component_parameter_bag_get_count (src_bag);
+
+       if (count) {
+               for (ii = 0; ii < count; ii++) {
+                       ICalParameter *param;
+
+                       param = e_cal_component_parameter_bag_get (src_bag, ii);
+
+                       e_cal_component_parameter_bag_add (bag, param);
+               }
+       }
+}
+
+/**
+ * e_cal_component_parameter_bag_add:
+ * @bag: an #ECalComponentParameterBag
+ * @param: an #ICalParameter
+ *
+ * Adds a copy of the @param into the @bag.
+ *
+ * Since: 3.36
+ **/
+void
+e_cal_component_parameter_bag_add (ECalComponentParameterBag *bag,
+                                 const ICalParameter *param)
+{
+       g_return_if_fail (bag != NULL);
+       g_return_if_fail (I_CAL_IS_PARAMETER (param));
+
+       e_cal_component_parameter_bag_take (bag,
+               i_cal_parameter_new_clone ((ICalParameter *) param));
+}
+
+/**
+ * e_cal_component_parameter_bag_take:
+ * @bag: an #ECalComponentParameterBag
+ * @param: an #ICalParameter
+ *
+ * Adds the @param into the @bag and assumes ownership of the @param.
+ *
+ * Since: 3.36
+ **/
+void
+e_cal_component_parameter_bag_take (ECalComponentParameterBag *bag,
+                                  ICalParameter *param)
+{
+       g_return_if_fail (bag != NULL);
+       g_return_if_fail (I_CAL_IS_PARAMETER (param));
+
+       g_ptr_array_add (bag->parameters, param);
+}
+
+/**
+ * e_cal_component_parameter_bag_get_count:
+ * @bag: an #ECalComponentParameterBag
+ *
+ * Returns: how many parameters are stored in the @bag
+ *
+ * Since: 3.36
+ **/
+guint
+e_cal_component_parameter_bag_get_count (const ECalComponentParameterBag *bag)
+{
+       g_return_val_if_fail (bag != NULL, 0);
+       g_return_val_if_fail (bag->parameters != NULL, 0);
+
+       return bag->parameters->len;
+}
+
+/**
+ * e_cal_component_parameter_bag_get:
+ * @bag: an #ECalComponentParameterBag
+ * @index: an index of the parameter to get
+ *
+ * Returns the #ICalParameter at the given @index. If the @index is
+ * out of bounds (not lower than e_cal_component_parameter_bag_get_count()),
+ * then %NULL is returned.
+ *
+ * The returned parameter is owned by the @bag and should not be freed
+ * by the caller.
+ *
+ * Returns: (transfer none) (nullable): the #ICalParameter at the given @index,
+ *    or %NULL on error
+ *
+ * Since: 3.36
+ **/
+ICalParameter *
+e_cal_component_parameter_bag_get (const ECalComponentParameterBag *bag,
+                                 guint index)
+{
+       g_return_val_if_fail (bag != NULL, NULL);
+       g_return_val_if_fail (bag->parameters != NULL, NULL);
+
+       if (index >= bag->parameters->len)
+               return NULL;
+
+       return g_ptr_array_index (bag->parameters, index);
+}
+
+/**
+ * e_cal_component_parameter_bag_remove:
+ * @bag: an #ECalComponentParameterBag
+ * @index: an index of the parameter to remove
+ *
+ * Removes the #ICalParameter at the given @index. If the @index is
+ * out of bounds (not lower than e_cal_component_parameter_bag_get_count()),
+ * then the function does nothing.
+ *
+ * Since: 3.36
+ **/
+void
+e_cal_component_parameter_bag_remove (ECalComponentParameterBag *bag,
+                                    guint index)
+{
+       g_return_if_fail (bag != NULL);
+       g_return_if_fail (bag->parameters != NULL);
+
+       if (index < bag->parameters->len)
+               g_ptr_array_remove_index (bag->parameters, index);
+}
+
+/**
+ * e_cal_component_parameter_bag_clear:
+ * @bag: an #ECalComponentParameterBag
+ *
+ * Removes all parameters from the @bag, thus it doesn't contain any
+ * parameter after this function returns.
+ *
+ * Since: 3.36
+ **/
+void
+e_cal_component_parameter_bag_clear (ECalComponentParameterBag *bag)
+{
+       g_return_if_fail (bag != NULL);
+       g_return_if_fail (bag->parameters != NULL);
+
+       g_ptr_array_set_size (bag->parameters, 0);
+}
diff --git a/src/calendar/libecal/e-cal-component-parameter-bag.h 
b/src/calendar/libecal/e-cal-component-parameter-bag.h
new file mode 100644
index 000000000..3f4a998c4
--- /dev/null
+++ b/src/calendar/libecal/e-cal-component-parameter-bag.h
@@ -0,0 +1,98 @@
+/*
+ * Copyright (C) 2019 Red Hat, Inc. (www.redhat.com)
+ *
+ * This library is free software: you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this library. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#if !defined (__LIBECAL_H_INSIDE__) && !defined (LIBECAL_COMPILATION)
+#error "Only <libecal/libecal.h> should be included directly."
+#endif
+
+#ifndef E_CAL_COMPONENT_PARAMETER_BAG_H
+#define E_CAL_COMPONENT_PARAMETER_BAG_H
+
+#include <glib-object.h>
+#include <libical-glib/libical-glib.h>
+
+G_BEGIN_DECLS
+
+/**
+ * ECalComponentParameterBag:
+ *
+ * Opaque structure, which represents a bad (list) of #ICalParameter objects.
+ * Use the functions below to work with it.
+ **/
+typedef struct _ECalComponentParameterBag ECalComponentParameterBag;
+
+/**
+ * ECalComponentParameterBagFilterFunc:
+ * @parameter: an #ICalParameter
+ * @user_data: user data for the callback
+ *
+ * A function used to filter which parameters should be added to the bag,
+ * when filling it with e_cal_component_parameter_bag_new_from_property()
+ * and e_cal_component_parameter_bag_set_from_property().
+ *
+ * Returns: %TRUE, to add the parameter to the bag; %FALSE, to not add it to the bag
+ *
+ * Since: 3.36
+ **/
+typedef gboolean (* ECalComponentParameterBagFilterFunc)
+                                               (ICalParameter *parameter,
+                                                gpointer user_data);
+
+GType          e_cal_component_parameter_bag_get_type
+                                               (void);
+ECalComponentParameterBag *
+               e_cal_component_parameter_bag_new
+                                               (void);
+ECalComponentParameterBag *
+               e_cal_component_parameter_bag_new_from_property
+                                               (const ICalProperty *property,
+                                                ECalComponentParameterBagFilterFunc func,
+                                                gpointer user_data);
+ECalComponentParameterBag *
+               e_cal_component_parameter_bag_copy
+                                               (const ECalComponentParameterBag *bag);
+void           e_cal_component_parameter_bag_free
+                                               (gpointer bag); /* ECalComponentParameterBag * */
+void           e_cal_component_parameter_bag_set_from_property
+                                               (ECalComponentParameterBag *bag,
+                                                const ICalProperty *property,
+                                                ECalComponentParameterBagFilterFunc func,
+                                                gpointer user_data);
+void           e_cal_component_parameter_bag_fill_property
+                                               (const ECalComponentParameterBag *bag,
+                                                ICalProperty *property);
+void           e_cal_component_parameter_bag_assign
+                                               (ECalComponentParameterBag *bag,
+                                                const ECalComponentParameterBag *src_bag);
+void           e_cal_component_parameter_bag_add(ECalComponentParameterBag *bag,
+                                                const ICalParameter *param);
+void           e_cal_component_parameter_bag_take
+                                               (ECalComponentParameterBag *bag,
+                                                ICalParameter *param);
+guint          e_cal_component_parameter_bag_get_count
+                                               (const ECalComponentParameterBag *bag);
+ICalParameter *        e_cal_component_parameter_bag_get(const ECalComponentParameterBag *bag,
+                                                guint index);
+void           e_cal_component_parameter_bag_remove
+                                               (ECalComponentParameterBag *bag,
+                                                guint index);
+void           e_cal_component_parameter_bag_clear
+                                               (ECalComponentParameterBag *bag);
+
+G_END_DECLS
+
+#endif /* E_CAL_COMPONENT_PARAMETER_BAG_H */
diff --git a/src/calendar/libecal/e-cal-component-property-bag.c 
b/src/calendar/libecal/e-cal-component-property-bag.c
index 8a7107e69..5a38e2d9f 100644
--- a/src/calendar/libecal/e-cal-component-property-bag.c
+++ b/src/calendar/libecal/e-cal-component-property-bag.c
@@ -60,7 +60,7 @@ e_cal_component_property_bag_new (void)
  * @func: (nullable) (scope call): an optional %ECalComponentPropertyBagFilterFunc callback
  * @user_data: (closure func): user data for the @func
  *
- * Created a new #ECalComponentPropertyBag, filled with properties
+ * Creates a new #ECalComponentPropertyBag, filled with properties
  * from the @component, for which the @func returned %TRUE. When
  * the @func is %NULL, all the properties are included.
  *
@@ -172,7 +172,7 @@ e_cal_component_property_bag_set_from_component (ECalComponentPropertyBag *bag,
  * @bag: an #ECalComponentPropertyBag
  * @component: an #ICalComponent
  *
- * Adds all the stores properties in the @bag to the @component.
+ * Adds all the stored properties in the @bag to the @component.
  * The function doesn't verify whether the @component contains
  * the same property already.
  *
diff --git a/src/calendar/libecal/libecal.h b/src/calendar/libecal/libecal.h
index 7af321a04..5f9b09183 100644
--- a/src/calendar/libecal/libecal.h
+++ b/src/calendar/libecal/libecal.h
@@ -38,6 +38,7 @@
 #include <libecal/e-cal-component-datetime.h>
 #include <libecal/e-cal-component-id.h>
 #include <libecal/e-cal-component-organizer.h>
+#include <libecal/e-cal-component-parameter-bag.h>
 #include <libecal/e-cal-component-period.h>
 #include <libecal/e-cal-component-property-bag.h>
 #include <libecal/e-cal-component-range.h>
diff --git a/tests/libecal/test-cal-component.c b/tests/libecal/test-cal-component.c
index 9ea8d5c51..6f4fed116 100644
--- a/tests/libecal/test-cal-component.c
+++ b/tests/libecal/test-cal-component.c
@@ -114,6 +114,80 @@ verify_ical_timetype_equal (ICalTimetype *expected,
        }
 }
 
+static void
+verify_struct_parameter_bag_equal (const ECalComponentParameterBag *expected,
+                                  const ECalComponentParameterBag *received)
+{
+       gint ii, count;
+
+       if (!expected) {
+               g_assert_null (received);
+               return;
+       }
+
+       g_assert_nonnull (received);
+
+       g_assert_cmpint (e_cal_component_parameter_bag_get_count (expected), ==, 
e_cal_component_parameter_bag_get_count (received));
+
+       count = e_cal_component_parameter_bag_get_count (expected);
+       for (ii = 0; ii < count; ii++) {
+               ICalParameter *param_expected, *param_received;
+               gchar *value_expected, *value_received;
+
+               param_expected = e_cal_component_parameter_bag_get (expected, ii);
+               param_received = e_cal_component_parameter_bag_get (received, ii);
+
+               g_assert_nonnull (param_expected);
+               g_assert_nonnull (param_received);
+               g_assert_cmpint (i_cal_parameter_isa (param_expected), ==, i_cal_parameter_isa 
(param_received));
+
+               value_expected = i_cal_parameter_as_ical_string_r (param_expected);
+               value_received = i_cal_parameter_as_ical_string_r (param_received);
+
+               g_assert_cmpstr (value_expected, ==, value_received);
+
+               g_free (value_expected);
+               g_free (value_received);
+       }
+}
+
+static void
+verify_struct_property_bag_equal (const ECalComponentPropertyBag *expected,
+                                 const ECalComponentPropertyBag *received)
+{
+       gint ii, count;
+
+       if (!expected) {
+               g_assert_null (received);
+               return;
+       }
+
+       g_assert_nonnull (received);
+
+       g_assert_cmpint (e_cal_component_property_bag_get_count (expected), ==, 
e_cal_component_property_bag_get_count (received));
+
+       count = e_cal_component_property_bag_get_count (expected);
+       for (ii = 0; ii < count; ii++) {
+               ICalProperty *prop_expected, *prop_received;
+               gchar *value_expected, *value_received;
+
+               prop_expected = e_cal_component_property_bag_get (expected, ii);
+               prop_received = e_cal_component_property_bag_get (received, ii);
+
+               g_assert_nonnull (prop_expected);
+               g_assert_nonnull (prop_received);
+               g_assert_cmpint (i_cal_property_isa (prop_expected), ==, i_cal_property_isa (prop_received));
+
+               value_expected = i_cal_property_as_ical_string_r (prop_expected);
+               value_received = i_cal_property_as_ical_string_r (prop_received);
+
+               g_assert_cmpstr (value_expected, ==, value_received);
+
+               g_free (value_expected);
+               g_free (value_received);
+       }
+}
+
 static void
 verify_struct_attendee_equal (const ECalComponentAttendee *expected,
                              const ECalComponentAttendee *received)
@@ -136,6 +210,9 @@ verify_struct_attendee_equal (const ECalComponentAttendee *expected,
        g_assert_cmpstr (e_cal_component_attendee_get_sentby (expected), ==, 
e_cal_component_attendee_get_sentby (received));
        g_assert_cmpstr (e_cal_component_attendee_get_cn (expected), ==, e_cal_component_attendee_get_cn 
(received));
        g_assert_cmpstr (e_cal_component_attendee_get_language (expected), ==, 
e_cal_component_attendee_get_language (received));
+
+       verify_struct_parameter_bag_equal (e_cal_component_attendee_get_parameter_bag (expected),
+                                          e_cal_component_attendee_get_parameter_bag (received));
 }
 
 static void
@@ -208,6 +285,9 @@ verify_struct_organizer_equal (const ECalComponentOrganizer *expected,
        g_assert_cmpstr (e_cal_component_organizer_get_sentby (expected), ==, 
e_cal_component_organizer_get_sentby (received));
        g_assert_cmpstr (e_cal_component_organizer_get_cn (expected), ==, e_cal_component_organizer_get_cn 
(received));
        g_assert_cmpstr (e_cal_component_organizer_get_language (expected), ==, 
e_cal_component_organizer_get_language (received));
+
+       verify_struct_parameter_bag_equal (e_cal_component_organizer_get_parameter_bag (expected),
+                                          e_cal_component_organizer_get_parameter_bag (received));
 }
 
 static void
@@ -319,43 +399,9 @@ verify_struct_alarm_trigger_equal (const ECalComponentAlarmTrigger *expected,
                                            e_cal_component_alarm_trigger_get_absolute_time (received));
                break;
        }
-}
-
-static void
-verify_property_bag_equal (const ECalComponentPropertyBag *expected,
-                          const ECalComponentPropertyBag *received)
-{
-       gint ii, count;
-
-       if (!expected) {
-               g_assert_null (received);
-               return;
-       }
-
-       g_assert_nonnull (received);
-
-       g_assert_cmpint (e_cal_component_property_bag_get_count (expected), ==, 
e_cal_component_property_bag_get_count (received));
-
-       count = e_cal_component_property_bag_get_count (expected);
-       for (ii = 0; ii < count; ii++) {
-               ICalProperty *prop_expected, *prop_received;
-               gchar *value_expected, *value_received;
 
-               prop_expected = e_cal_component_property_bag_get (expected, ii);
-               prop_received = e_cal_component_property_bag_get (received, ii);
-
-               g_assert_nonnull (prop_expected);
-               g_assert_nonnull (prop_received);
-               g_assert_cmpint (i_cal_property_isa (prop_expected), ==, i_cal_property_isa (prop_received));
-
-               value_expected = i_cal_property_as_ical_string_r (prop_expected);
-               value_received = i_cal_property_as_ical_string_r (prop_received);
-
-               g_assert_cmpstr (value_expected, ==, value_received);
-
-               g_free (value_expected);
-               g_free (value_received);
-       }
+       verify_struct_parameter_bag_equal (e_cal_component_alarm_trigger_get_parameter_bag (expected),
+                                          e_cal_component_alarm_trigger_get_parameter_bag (received));
 }
 
 static void
@@ -391,8 +437,8 @@ verify_struct_alarm_equal (const ECalComponentAlarm *expected,
        verify_ical_attach_list_equal (e_cal_component_alarm_get_attachments (expected),
                                       e_cal_component_alarm_get_attachments (received));
 
-       verify_property_bag_equal (e_cal_component_alarm_get_property_bag (expected),
-                                  e_cal_component_alarm_get_property_bag (received));
+       verify_struct_property_bag_equal (e_cal_component_alarm_get_property_bag (expected),
+                                         e_cal_component_alarm_get_property_bag (received));
 }
 
 static void
@@ -791,6 +837,38 @@ test_component_struct_alarm_instance (void)
        g_assert_cmpint (ii, >, 1);
 }
 
+static void
+test_component_add_params_to_bag (ECalComponentParameterBag *bag,
+                                 gint n_params)
+{
+       gint ii;
+
+       g_assert_nonnull (bag);
+
+       for (ii = 0; ii < n_params; ii++) {
+               ICalParameter *param;
+
+               if (ii == 0) {
+                       param = i_cal_parameter_new_local (I_CAL_LOCAL_TRUE);
+               } else if (ii == 1) {
+                       param = i_cal_parameter_new_localize ("en_US");
+               } else {
+                       gchar *x_name;
+
+                       x_name = g_strdup_printf ("X-CUSTOM-PARAM-%d", ii);
+                       param = i_cal_parameter_new_x (x_name + 2);
+                       i_cal_parameter_set_xname (param, x_name);
+                       g_free (x_name);
+               }
+
+               g_assert_nonnull (param);
+
+               e_cal_component_parameter_bag_take (bag, param);
+       }
+
+       g_assert_cmpint (e_cal_component_parameter_bag_get_count (bag), ==, n_params);
+}
+
 static void
 test_component_struct_alarm_repeat (void)
 {
@@ -928,6 +1006,9 @@ test_component_struct_alarm_trigger (void)
 
                        g_assert_nonnull (expected);
 
+                       if (set_kind == 1)
+                               test_component_add_params_to_bag 
(e_cal_component_alarm_trigger_get_parameter_bag (expected), ii + 1);
+
                        g_assert_cmpint (values[ii].kind, ==, e_cal_component_alarm_trigger_get_kind 
(expected));
                        if (values[ii].kind == E_CAL_COMPONENT_ALARM_TRIGGER_ABSOLUTE) {
                                tt = i_cal_time_from_string (values[ii].abs_time);
@@ -1077,6 +1158,9 @@ test_component_struct_attendee (void)
 
                        g_assert_nonnull (expected);
 
+                       if (set_kind == 1)
+                               test_component_add_params_to_bag (e_cal_component_attendee_get_parameter_bag 
(expected), ii + 1);
+
                        g_assert_cmpstr (e_cal_component_attendee_get_value (expected), ==, values[ii].value);
                        g_assert_cmpstr (e_cal_component_attendee_get_member (expected), ==, 
values[ii].member);
                        g_assert_cmpint (e_cal_component_attendee_get_cutype (expected), ==, 
values[ii].cutype);
@@ -1302,6 +1386,9 @@ test_component_struct_organizer (void)
 
                        g_assert_nonnull (expected);
 
+                       if (set_kind == 1)
+                               test_component_add_params_to_bag (e_cal_component_organizer_get_parameter_bag 
(expected), ii + 1);
+
                        g_assert_cmpstr (e_cal_component_organizer_get_value (expected), ==, 
values[ii].value);
                        g_assert_cmpstr (e_cal_component_organizer_get_sentby (expected), ==, 
values[ii].sentby);
                        g_assert_cmpstr (e_cal_component_organizer_get_cn (expected), ==, values[ii].cn);
@@ -1337,6 +1424,181 @@ test_component_struct_organizer (void)
        }
 }
 
+#define X_PARAM_NAME "X-PARAM"
+#define X_PARAM_VALUE "xVaLuE"
+
+static gboolean
+test_parameter_bag_filter_cb (ICalParameter *param,
+                             gpointer user_data)
+{
+       ICalParameterKind *expected = user_data, kind;
+       gint ii;
+
+       g_return_val_if_fail (expected != NULL, FALSE);
+
+       kind = i_cal_parameter_isa (param);
+
+       for (ii = 0; expected[ii] != I_CAL_ANY_PARAMETER; ii++) {
+               if (kind == expected[ii])
+                       return TRUE;
+       }
+
+       return FALSE;
+}
+
+static void
+test_check_parameter_bag (const ECalComponentParameterBag *bag,
+                         const ICalParameterKind *expected)
+{
+       ICalParameter *param;
+       gint ii;
+
+       g_assert_nonnull (bag);
+       g_assert_nonnull (expected);
+
+       for (ii = 0; expected[ii] != I_CAL_ANY_PARAMETER; ii++) {
+               param = e_cal_component_parameter_bag_get (bag, ii);
+
+               g_assert_nonnull (param);
+               g_assert_cmpint (i_cal_parameter_isa (param), ==, expected[ii]);
+               if (i_cal_parameter_isa (param) == I_CAL_X_PARAMETER) {
+                       g_assert_cmpstr (i_cal_parameter_get_xname (param), ==, X_PARAM_NAME);
+                       g_assert_cmpstr (i_cal_parameter_get_xvalue (param), ==, X_PARAM_VALUE);
+               }
+       }
+
+       /* Out of bounds */
+       param = e_cal_component_parameter_bag_get (bag, ii);
+       g_assert_null (param);
+}
+
+static void
+test_component_struct_parameter_bag (void)
+{
+       const gchar *prop_str =
+               "ATTENDEE;CHARSET=utf-8;CN=User;CUTYPE=INDIVIDUAL;" X_PARAM_NAME "=" X_PARAM_VALUE 
";LANGUAGE=en_US:MAILTO:user@no.where";
+       ICalParameterKind expected_unfiltered[] = {
+               I_CAL_CHARSET_PARAMETER,
+               I_CAL_CN_PARAMETER,
+               I_CAL_CUTYPE_PARAMETER,
+               I_CAL_X_PARAMETER,
+               I_CAL_LANGUAGE_PARAMETER,
+               I_CAL_ANY_PARAMETER /* sentinel */
+       },
+       expected_filtered[] = {
+               I_CAL_CN_PARAMETER,
+               I_CAL_CUTYPE_PARAMETER,
+               I_CAL_X_PARAMETER,
+               I_CAL_ANY_PARAMETER /* sentinel */
+       };
+       ICalProperty *prop;
+       ICalParameter *param;
+       ECalComponentParameterBag *bag, *bag2;
+       gint ii;
+
+       prop = i_cal_property_new_from_string (prop_str);
+       g_assert_nonnull (prop);
+       g_assert_cmpint (i_cal_property_count_parameters (prop), ==, 5);
+
+       bag = e_cal_component_parameter_bag_new ();
+       g_assert_nonnull (bag);
+       e_cal_component_parameter_bag_set_from_property (bag, prop, NULL, NULL);
+       g_assert_cmpint (e_cal_component_parameter_bag_get_count (bag), ==, G_N_ELEMENTS 
(expected_unfiltered) - 1);
+       test_check_parameter_bag (bag, expected_unfiltered);
+
+       bag2 = e_cal_component_parameter_bag_copy (bag);
+       g_assert_nonnull (bag2);
+       g_assert_cmpint (e_cal_component_parameter_bag_get_count (bag2), ==, G_N_ELEMENTS 
(expected_unfiltered) - 1);
+       test_check_parameter_bag (bag2, expected_unfiltered);
+       e_cal_component_parameter_bag_free (bag2);
+       e_cal_component_parameter_bag_free (bag);
+
+       bag = e_cal_component_parameter_bag_new_from_property (prop, NULL, NULL);
+       g_assert_nonnull (bag);
+       g_assert_cmpint (e_cal_component_parameter_bag_get_count (bag), ==, G_N_ELEMENTS 
(expected_unfiltered) - 1);
+       test_check_parameter_bag (bag, expected_unfiltered);
+       e_cal_component_parameter_bag_free (bag);
+
+       bag = e_cal_component_parameter_bag_new ();
+       g_assert_nonnull (bag);
+       e_cal_component_parameter_bag_set_from_property (bag, prop, test_parameter_bag_filter_cb, 
expected_filtered);
+       g_assert_cmpint (e_cal_component_parameter_bag_get_count (bag), ==, G_N_ELEMENTS (expected_filtered) 
- 1);
+       test_check_parameter_bag (bag, expected_filtered);
+       e_cal_component_parameter_bag_free (bag);
+
+       bag = e_cal_component_parameter_bag_new_from_property (prop, test_parameter_bag_filter_cb, 
expected_filtered);
+       g_assert_nonnull (bag);
+       g_assert_cmpint (e_cal_component_parameter_bag_get_count (bag), ==, G_N_ELEMENTS (expected_filtered) 
- 1);
+       test_check_parameter_bag (bag, expected_filtered);
+
+       g_object_unref (prop);
+
+       prop = i_cal_property_new (I_CAL_COMMENT_PROPERTY);
+       g_assert_nonnull (prop);
+       e_cal_component_parameter_bag_fill_property (bag, prop);
+       g_assert_cmpint (i_cal_property_count_parameters (prop), ==, e_cal_component_parameter_bag_get_count 
(bag));
+       g_object_unref (prop);
+
+       bag2 = e_cal_component_parameter_bag_copy (bag);
+
+       while (e_cal_component_parameter_bag_get_count (bag) > 1) {
+               e_cal_component_parameter_bag_remove (bag, 1);
+       }
+
+       e_cal_component_parameter_bag_assign (bag2, bag);
+       g_assert_cmpint (e_cal_component_parameter_bag_get_count (bag), ==, 
e_cal_component_parameter_bag_get_count (bag2));
+       e_cal_component_parameter_bag_free (bag2);
+
+       prop = i_cal_property_new (I_CAL_ATTENDEE_PROPERTY);
+       g_assert_nonnull (prop);
+       e_cal_component_parameter_bag_fill_property (bag, prop);
+       g_assert_cmpint (i_cal_property_count_parameters (prop), ==, 1);
+       g_object_unref (prop);
+
+       e_cal_component_parameter_bag_clear (bag);
+
+       prop = i_cal_property_new (I_CAL_ATTENDEE_PROPERTY);
+       g_assert_nonnull (prop);
+       e_cal_component_parameter_bag_fill_property (bag, prop);
+       g_assert_cmpint (i_cal_property_count_parameters (prop), ==, 0);
+       g_object_unref (prop);
+
+       param = i_cal_parameter_new_cn ("234");
+       e_cal_component_parameter_bag_add (bag, param);
+       g_object_unref (param);
+
+       param = i_cal_parameter_new_cutype (I_CAL_CUTYPE_ROOM);
+       e_cal_component_parameter_bag_take (bag, param);
+
+       g_assert_cmpint (e_cal_component_parameter_bag_get_count (bag), ==, 2);
+
+       for (ii = 0; ii < 2; ii++) {
+               ICalParameter *param2;
+
+               param2 = e_cal_component_parameter_bag_get (bag, ii);
+               if (ii == 0) {
+                       g_assert (param != param2);
+                       g_assert_cmpint (i_cal_parameter_isa (param2), ==, I_CAL_CN_PARAMETER);
+                       g_assert_cmpstr (i_cal_parameter_get_cn (param2), ==, "234");
+               } else {
+                       g_assert (param == param2);
+                       g_assert_cmpint (i_cal_parameter_isa (param2), ==, I_CAL_CUTYPE_PARAMETER);
+                       g_assert_cmpint (i_cal_parameter_get_cutype (param2), ==, I_CAL_CUTYPE_ROOM);
+               }
+       }
+
+       prop = i_cal_property_new (I_CAL_DESCRIPTION_PROPERTY);
+       g_assert_nonnull (prop);
+       e_cal_component_parameter_bag_fill_property (bag, prop);
+       g_assert_cmpint (i_cal_property_count_parameters (prop), ==, e_cal_component_parameter_bag_get_count 
(bag));
+       g_object_unref (prop);
+
+       e_cal_component_parameter_bag_free (bag);
+}
+
+#undef X_PARAM_NAME
+#undef X_PARAM_VALUE
+
 static void
 test_component_struct_period (void)
 {
@@ -1533,6 +1795,7 @@ test_component_struct_property_bag (void)
 
        icomp = i_cal_component_new_from_string (comp_str);
        g_assert_nonnull (icomp);
+       g_assert_cmpint (i_cal_component_count_properties (icomp, I_CAL_ANY_PROPERTY), ==, 3);
 
        bag = e_cal_component_property_bag_new ();
        g_assert_nonnull (bag);
@@ -2685,9 +2948,13 @@ test_component_organizer (void)
        for (ii = 0; ii < G_N_ELEMENTS (values); ii++) {
                ECalComponentOrganizer *org = NULL;
 
-               if (values[ii].value)
+               if (values[ii].value) {
                        org = e_cal_component_organizer_new_full (values[ii].value, values[ii].sentby, 
values[ii].cn, values[ii].language);
 
+                       if (ii == 0)
+                               test_component_add_params_to_bag (e_cal_component_organizer_get_parameter_bag 
(org), ii + 1);
+               }
+
                e_cal_component_set_organizer (comp, org);
                verify_changes (comp, verify_component_organizer, org);
 
@@ -3204,6 +3471,7 @@ test_component_attendees (void)
                const gchar *sentby;
                const gchar *cn;
                const gchar *language;
+               gboolean with_parameters;
        } values[] = {
                { "MAILTO:att1",
                   "member",
@@ -3215,9 +3483,10 @@ test_component_attendees (void)
                   "MAILTO:delgto",
                   "MAILTO:sentby",
                   "First attendee",
-                  "en_US" },
-               { NULL, NULL, I_CAL_CUTYPE_NONE, I_CAL_ROLE_NONE, I_CAL_PARTSTAT_NONE, FALSE, NULL, NULL, 
NULL, NULL, NULL }, /* terminator */
-               { NULL, NULL, I_CAL_CUTYPE_NONE, I_CAL_ROLE_NONE, I_CAL_PARTSTAT_NONE, FALSE, NULL, NULL, 
NULL, NULL, NULL }, /* terminator */
+                  "en_US",
+                  FALSE },
+               { NULL, NULL, I_CAL_CUTYPE_NONE, I_CAL_ROLE_NONE, I_CAL_PARTSTAT_NONE, FALSE, NULL, NULL, 
NULL, NULL, NULL, FALSE }, /* terminator */
+               { NULL, NULL, I_CAL_CUTYPE_NONE, I_CAL_ROLE_NONE, I_CAL_PARTSTAT_NONE, FALSE, NULL, NULL, 
NULL, NULL, NULL, FALSE }, /* terminator */
                { "MAILTO:room",
                   NULL,
                   I_CAL_CUTYPE_ROOM,
@@ -3228,7 +3497,8 @@ test_component_attendees (void)
                   NULL,
                   NULL,
                   "Meeting room",
-                  NULL },
+                  NULL,
+                  TRUE },
                { "MAILTO:att2",
                   NULL,
                   I_CAL_CUTYPE_INDIVIDUAL,
@@ -3239,8 +3509,9 @@ test_component_attendees (void)
                   NULL,
                   NULL,
                   NULL,
-                  "en_US" },
-               { NULL, NULL, I_CAL_CUTYPE_NONE, I_CAL_ROLE_NONE, I_CAL_PARTSTAT_NONE, FALSE, NULL, NULL, 
NULL, NULL, NULL } /* terminator */
+                  "en_US",
+                  FALSE },
+               { NULL, NULL, I_CAL_CUTYPE_NONE, I_CAL_ROLE_NONE, I_CAL_PARTSTAT_NONE, FALSE, NULL, NULL, 
NULL, NULL, NULL, FALSE } /* terminator */
        };
        ECalComponent *comp;
        GSList *attendees = NULL;
@@ -3265,6 +3536,9 @@ test_component_attendees (void)
                                values[ii].cn,
                                values[ii].language);
 
+                       if (values[ii].with_parameters)
+                               test_component_add_params_to_bag (e_cal_component_attendee_get_parameter_bag 
(att), ii + 1);
+
                        attendees = g_slist_prepend (attendees, att);
                } else {
                        attendees = g_slist_reverse (attendees);
@@ -3512,14 +3786,15 @@ test_component_alarms (void)
                ECalComponentAlarmAction action;
                const gchar *description;
                gint trigger;
+               gboolean trigger_with_parameters;
        } values[] = {
-               { "alarm1", E_CAL_COMPONENT_ALARM_DISPLAY, "display reminder", -5 },
-               { NULL, E_CAL_COMPONENT_ALARM_NONE, NULL, 0 }, /* terminator */
-               { NULL, E_CAL_COMPONENT_ALARM_NONE, NULL, 0 }, /* terminator */
-               { "alarm2", E_CAL_COMPONENT_ALARM_AUDIO, "audio reminder", 10 },
-               { "alarm3", E_CAL_COMPONENT_ALARM_EMAIL, "email reminder", 0 },
-               { "alarm4", E_CAL_COMPONENT_ALARM_PROCEDURE, "procedure reminder", -30 },
-               { NULL, E_CAL_COMPONENT_ALARM_NONE, NULL, 0 }, /* terminator */
+               { "alarm1", E_CAL_COMPONENT_ALARM_DISPLAY, "display reminder", -5, TRUE },
+               { NULL, E_CAL_COMPONENT_ALARM_NONE, NULL, 0, FALSE }, /* terminator */
+               { NULL, E_CAL_COMPONENT_ALARM_NONE, NULL, 0, FALSE }, /* terminator */
+               { "alarm2", E_CAL_COMPONENT_ALARM_AUDIO, "audio reminder", 10, FALSE },
+               { "alarm3", E_CAL_COMPONENT_ALARM_EMAIL, "email reminder", 0, TRUE },
+               { "alarm4", E_CAL_COMPONENT_ALARM_PROCEDURE, "procedure reminder", -30, FALSE },
+               { NULL, E_CAL_COMPONENT_ALARM_NONE, NULL, 0, FALSE }, /* terminator */
        };
        ECalComponent *comp;
        GSList *alarms = NULL;
@@ -3546,6 +3821,28 @@ test_component_alarms (void)
                        e_cal_component_alarm_take_description (alarm, e_cal_component_text_new 
(values[ii].description, NULL));
                        e_cal_component_alarm_take_trigger (alarm, e_cal_component_alarm_trigger_new_relative 
(kind, duration));
 
+                       if (values[ii].trigger_with_parameters) {
+                               ECalComponentAlarmTrigger *trigger;
+
+                               trigger = e_cal_component_alarm_get_trigger (alarm);
+                               test_component_add_params_to_bag 
(e_cal_component_alarm_trigger_get_parameter_bag (trigger), ii + 1);
+                       }
+
+                       if (values[ii].trigger < 0) {
+                               ECalComponentPropertyBag *bag;
+                               ICalProperty *prop;
+
+                               bag = e_cal_component_alarm_get_property_bag (alarm);
+
+                               prop = i_cal_property_new_url ("https://www.gnome.org";);
+                               e_cal_component_property_bag_take (bag, prop);
+
+                               prop = i_cal_property_new_carlevel (I_CAL_CARLEVEL_CARFULL1);
+                               e_cal_component_property_bag_take (bag, prop);
+
+                               g_assert_cmpint (e_cal_component_property_bag_get_count (bag), ==, 2);
+                       }
+
                        e_cal_component_add_alarm (comp, alarm);
                        alarms = g_slist_prepend (alarms, alarm);
 
@@ -3617,6 +3914,7 @@ main (gint argc,
        g_test_add_func ("/ECalComponent/struct/DateTime", test_component_struct_datetime);
        g_test_add_func ("/ECalComponent/struct/Id", test_component_struct_id);
        g_test_add_func ("/ECalComponent/struct/Organizer", test_component_struct_organizer);
+       g_test_add_func ("/ECalComponent/struct/ParameterBag", test_component_struct_parameter_bag);
        g_test_add_func ("/ECalComponent/struct/Period", test_component_struct_period);
        g_test_add_func ("/ECalComponent/struct/PropertyBag", test_component_struct_property_bag);
        g_test_add_func ("/ECalComponent/struct/Range", test_component_struct_range);


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