1 /*
2  * Copyright (C) 2019 Red Hat, Inc. (www.redhat.com)
3  *
4  * This library is free software: you can redistribute it and/or modify it
5  * under the terms of the GNU Lesser General Public License as published by
6  * the Free Software Foundation.
7  *
8  * This library is distributed in the hope that it will be useful, but
9  * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
10  * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
11  * for more details.
12  *
13  * You should have received a copy of the GNU Lesser General Public License
14  * along with this library. If not, see <http://www.gnu.org/licenses/>.
15  *
16  */
17 
18 #include "evolution-data-server-config.h"
19 
20 /**
21  * SECTION:e-cal-component-parameter-bag
22  * @short_description: An ECalComponentParameterBag structure
23  * @include: libecal/libecal.h
24  *
25  * Contains functions to work with the #ECalComponentParameterBag structure.
26  **/
27 
28 #include "e-cal-component-parameter-bag.h"
29 
30 G_DEFINE_BOXED_TYPE (ECalComponentParameterBag, e_cal_component_parameter_bag, e_cal_component_parameter_bag_copy, e_cal_component_parameter_bag_free)
31 
32 struct _ECalComponentParameterBag {
33 	GPtrArray *parameters; /* ICalParameter * */
34 };
35 
36 /**
37  * e_cal_component_parameter_bag_new:
38  *
39  * Creates a new #ECalComponentParameterBag. Free the structure
40  * with e_cal_component_parameter_bag_free(), when no longer needed.
41  *
42  * Returns: (transfer full): a newly allocated #ECalComponentParameterBag
43  *
44  * Since: 3.34
45  **/
46 ECalComponentParameterBag *
e_cal_component_parameter_bag_new(void)47 e_cal_component_parameter_bag_new (void)
48 {
49 	ECalComponentParameterBag *bag;
50 
51 	bag = g_slice_new0 (ECalComponentParameterBag);
52 	bag->parameters = g_ptr_array_new_with_free_func (g_object_unref);
53 
54 	return bag;
55 }
56 
57 /**
58  * e_cal_component_parameter_bag_new_from_property:
59  * @property: an #ICalProperty containing the parameters to fill the bag with
60  * @func: (nullable) (scope call): an optional %ECalComponentParameterBagFilterFunc callback
61  * @user_data: (closure func): user data for the @func
62  *
63  * Creates a new #ECalComponentParameterBag, filled with parameters
64  * from the @property, for which the @func returned %TRUE. When
65  * the @func is %NULL, all the parameters are included.
66  *
67  * Free the structure with e_cal_component_parameter_bag_free(), when no longer needed.
68  *
69  * Returns: (transfer full): a newly allocated #ECalComponentParameterBag
70  *
71  * Since: 3.34
72  **/
73 ECalComponentParameterBag *
e_cal_component_parameter_bag_new_from_property(const ICalProperty * property,ECalComponentParameterBagFilterFunc func,gpointer user_data)74 e_cal_component_parameter_bag_new_from_property (const ICalProperty *property,
75 						 ECalComponentParameterBagFilterFunc func,
76 						 gpointer user_data)
77 {
78 	ECalComponentParameterBag *bag;
79 
80 	bag = e_cal_component_parameter_bag_new ();
81 
82 	e_cal_component_parameter_bag_set_from_property (bag, property, func, user_data);
83 
84 	return bag;
85 }
86 
87 /**
88  * e_cal_component_parameter_bag_copy:
89  * @bag: (not nullable): an #ECalComponentParameterBag
90  *
91  * Returns a newly allocated copy of @bag, which should be freed with
92  * e_cal_component_parameter_bag_free(), when no longer needed.
93  *
94  * Returns: (transfer full): a newly allocated copy of @bag
95  *
96  * Since: 3.34
97  **/
98 ECalComponentParameterBag *
e_cal_component_parameter_bag_copy(const ECalComponentParameterBag * bag)99 e_cal_component_parameter_bag_copy (const ECalComponentParameterBag *bag)
100 {
101 	ECalComponentParameterBag *copy;
102 
103 	g_return_val_if_fail (bag != NULL, NULL);
104 
105 	copy = e_cal_component_parameter_bag_new ();
106 
107 	e_cal_component_parameter_bag_assign (copy, bag);
108 
109 	return copy;
110 }
111 
112 /**
113  * e_cal_component_parameter_bag_free: (skip)
114  * @bag: (type ECalComponentParameterBag) (nullable): an #ECalComponentParameterBag to free
115  *
116  * Free @bag, previously created by e_cal_component_parameter_bag_new(),
117  * e_cal_component_parameter_bag_new_from_component() or
118  * e_cal_component_parameter_bag_copy(). The function does nothing, if @bag
119  * is %NULL.
120  *
121  * Since: 3.34
122  **/
123 void
e_cal_component_parameter_bag_free(gpointer bag)124 e_cal_component_parameter_bag_free (gpointer bag)
125 {
126 	ECalComponentParameterBag *bg = bag;
127 
128 	if (bg) {
129 		g_ptr_array_unref (bg->parameters);
130 		g_slice_free (ECalComponentParameterBag, bg);
131 	}
132 }
133 
134 /**
135  * e_cal_component_parameter_bag_set_from_property:
136  * @bag: an #ECalComponentParameterBag
137  * @property: an #ICalProperty containing the parameters to fill the @bag with
138  * @func: (nullable) (scope call): an optional %ECalComponentParameterBagFilterFunc callback
139  * @user_data: (closure func): user data for the @func
140  *
141  * Fills the @bag with parameters from the @property, for which the @func
142  * returned %TRUE. When the @func is %NULL, all the parameters are included.
143  * The @bag content is cleared before any parameter is added.
144  *
145  * Since: 3.34
146  **/
147 void
e_cal_component_parameter_bag_set_from_property(ECalComponentParameterBag * bag,const ICalProperty * property,ECalComponentParameterBagFilterFunc func,gpointer user_data)148 e_cal_component_parameter_bag_set_from_property (ECalComponentParameterBag *bag,
149 						 const ICalProperty *property,
150 						 ECalComponentParameterBagFilterFunc func,
151 						 gpointer user_data)
152 {
153 	ICalProperty *prop = (ICalProperty *) property;
154 	ICalParameter *param;
155 
156 	g_return_if_fail (bag != NULL);
157 	g_return_if_fail (I_CAL_IS_PROPERTY ((ICalProperty *) property));
158 
159 	e_cal_component_parameter_bag_clear (bag);
160 
161 	for (param = i_cal_property_get_first_parameter (prop, I_CAL_ANY_PARAMETER);
162 	     param;
163 	     g_object_unref (param), param = i_cal_property_get_next_parameter (prop, I_CAL_ANY_PARAMETER)) {
164 		if (!func || func (param, user_data)) {
165 			e_cal_component_parameter_bag_add (bag, param);
166 		}
167 	}
168 }
169 
170 /**
171  * e_cal_component_parameter_bag_fill_property:
172  * @bag: an #ECalComponentParameterBag
173  * @property: an #ICalProperty
174  *
175  * Adds all the stored parameters in the @bag to the @property.
176  * The function replaces any existing parameter with the new value,
177  * if any such exists. Otherwise the parameter is added.
178  *
179  * Since: 3.34
180  **/
181 void
e_cal_component_parameter_bag_fill_property(const ECalComponentParameterBag * bag,ICalProperty * property)182 e_cal_component_parameter_bag_fill_property (const ECalComponentParameterBag *bag,
183 					     ICalProperty *property)
184 {
185 	guint ii;
186 
187 	g_return_if_fail (bag != NULL);
188 	g_return_if_fail (I_CAL_IS_PROPERTY (property));
189 
190 	for (ii = 0; ii < bag->parameters->len; ii++) {
191 		ICalParameter *param = g_ptr_array_index (bag->parameters, ii);
192 
193 		if (param)
194 			i_cal_property_take_parameter (property, i_cal_parameter_clone (param));
195 	}
196 }
197 
198 /**
199  * e_cal_component_parameter_bag_assign:
200  * @bag: a destination #ECalComponentParameterBag
201  * @src_bag: a source #ECalComponentParameterBag
202  *
203  * Assigns content of the @src_bag into the @bag.
204  *
205  * Since: 3.34
206  **/
207 void
e_cal_component_parameter_bag_assign(ECalComponentParameterBag * bag,const ECalComponentParameterBag * src_bag)208 e_cal_component_parameter_bag_assign (ECalComponentParameterBag *bag,
209 				     const ECalComponentParameterBag *src_bag)
210 {
211 	guint count, ii;
212 
213 	g_return_if_fail (bag != NULL);
214 	g_return_if_fail (src_bag != NULL);
215 
216 	e_cal_component_parameter_bag_clear (bag);
217 	count = e_cal_component_parameter_bag_get_count (src_bag);
218 
219 	if (count) {
220 		for (ii = 0; ii < count; ii++) {
221 			ICalParameter *param;
222 
223 			param = e_cal_component_parameter_bag_get (src_bag, ii);
224 
225 			e_cal_component_parameter_bag_add (bag, param);
226 		}
227 	}
228 }
229 
230 /**
231  * e_cal_component_parameter_bag_add:
232  * @bag: an #ECalComponentParameterBag
233  * @param: an #ICalParameter
234  *
235  * Adds a copy of the @param into the @bag.
236  *
237  * Since: 3.34
238  **/
239 void
e_cal_component_parameter_bag_add(ECalComponentParameterBag * bag,const ICalParameter * param)240 e_cal_component_parameter_bag_add (ECalComponentParameterBag *bag,
241 				  const ICalParameter *param)
242 {
243 	g_return_if_fail (bag != NULL);
244 	g_return_if_fail (I_CAL_IS_PARAMETER ((ICalParameter *) param));
245 
246 	e_cal_component_parameter_bag_take (bag,
247 		i_cal_parameter_clone ((ICalParameter *) param));
248 }
249 
250 /**
251  * e_cal_component_parameter_bag_take:
252  * @bag: an #ECalComponentParameterBag
253  * @param: (transfer full): an #ICalParameter
254  *
255  * Adds the @param into the @bag and assumes ownership of the @param.
256  *
257  * Since: 3.34
258  **/
259 void
e_cal_component_parameter_bag_take(ECalComponentParameterBag * bag,ICalParameter * param)260 e_cal_component_parameter_bag_take (ECalComponentParameterBag *bag,
261 				   ICalParameter *param)
262 {
263 	g_return_if_fail (bag != NULL);
264 	g_return_if_fail (I_CAL_IS_PARAMETER (param));
265 
266 	g_ptr_array_add (bag->parameters, param);
267 }
268 
269 /**
270  * e_cal_component_parameter_bag_get_count:
271  * @bag: an #ECalComponentParameterBag
272  *
273  * Returns: how many parameters are stored in the @bag
274  *
275  * Since: 3.34
276  **/
277 guint
e_cal_component_parameter_bag_get_count(const ECalComponentParameterBag * bag)278 e_cal_component_parameter_bag_get_count (const ECalComponentParameterBag *bag)
279 {
280 	g_return_val_if_fail (bag != NULL, 0);
281 	g_return_val_if_fail (bag->parameters != NULL, 0);
282 
283 	return bag->parameters->len;
284 }
285 
286 /**
287  * e_cal_component_parameter_bag_get:
288  * @bag: an #ECalComponentParameterBag
289  * @index: an index of the parameter to get
290  *
291  * Returns the #ICalParameter at the given @index. If the @index is
292  * out of bounds (not lower than e_cal_component_parameter_bag_get_count()),
293  * then %NULL is returned.
294  *
295  * The returned parameter is owned by the @bag and should not be freed
296  * by the caller.
297  *
298  * Returns: (transfer none) (nullable): the #ICalParameter at the given @index,
299  *    or %NULL on error
300  *
301  * Since: 3.34
302  **/
303 ICalParameter *
e_cal_component_parameter_bag_get(const ECalComponentParameterBag * bag,guint index)304 e_cal_component_parameter_bag_get (const ECalComponentParameterBag *bag,
305 				  guint index)
306 {
307 	g_return_val_if_fail (bag != NULL, NULL);
308 	g_return_val_if_fail (bag->parameters != NULL, NULL);
309 
310 	if (index >= bag->parameters->len)
311 		return NULL;
312 
313 	return g_ptr_array_index (bag->parameters, index);
314 }
315 
316 /**
317  * e_cal_component_parameter_bag_get_first_by_kind:
318  * @bag: an #ECalComponentParameterBag
319  * @kind: an #ICalParameterKind to search for
320  *
321  * Returns: the index of the first parameter of the given @kind, or value
322  *    out of bounds, if such parameter cannot be found
323  *
324  * Since: 3.34
325  **/
326 guint
e_cal_component_parameter_bag_get_first_by_kind(const ECalComponentParameterBag * bag,ICalParameterKind kind)327 e_cal_component_parameter_bag_get_first_by_kind (const ECalComponentParameterBag *bag,
328 						 ICalParameterKind kind)
329 {
330 	guint index;
331 
332 	g_return_val_if_fail (bag != NULL, ~0);
333 	g_return_val_if_fail (bag->parameters != NULL, ~0);
334 
335 	for (index = 0; index < bag->parameters->len; index++) {
336 		ICalParameter *param;
337 
338 		param = g_ptr_array_index (bag->parameters, index);
339 		if (param && i_cal_parameter_isa (param) == kind)
340 			return index;
341 	}
342 
343 	return ~0;
344 }
345 
346 /**
347  * e_cal_component_parameter_bag_remove:
348  * @bag: an #ECalComponentParameterBag
349  * @index: an index of the parameter to remove
350  *
351  * Removes the #ICalParameter at the given @index. If the @index is
352  * out of bounds (not lower than e_cal_component_parameter_bag_get_count()),
353  * then the function does nothing.
354  *
355  * Since: 3.34
356  **/
357 void
e_cal_component_parameter_bag_remove(ECalComponentParameterBag * bag,guint index)358 e_cal_component_parameter_bag_remove (ECalComponentParameterBag *bag,
359 				     guint index)
360 {
361 	g_return_if_fail (bag != NULL);
362 	g_return_if_fail (bag->parameters != NULL);
363 
364 	if (index < bag->parameters->len)
365 		g_ptr_array_remove_index (bag->parameters, index);
366 }
367 
368 /**
369  * e_cal_component_parameter_bag_remove_by_kind:
370  * @bag: an #ECalComponentParameterBag
371  * @kind: an #ICalParameterKind to remove
372  * @all: %TRUE to remove all parameters of the @kind, or %FALSE to only the first
373  *
374  * Removes the first or all (depending on the @all) parameters of the given @kind.
375  *
376  * Returns: how many parameters had been removed
377  *
378  * Since: 3.34
379  **/
380 guint
e_cal_component_parameter_bag_remove_by_kind(ECalComponentParameterBag * bag,ICalParameterKind kind,gboolean all)381 e_cal_component_parameter_bag_remove_by_kind (ECalComponentParameterBag *bag,
382 					      ICalParameterKind kind,
383 					      gboolean all)
384 {
385 	guint index, count = 0;
386 
387 	g_return_val_if_fail (bag != NULL, 0);
388 	g_return_val_if_fail (bag->parameters != NULL, 0);
389 
390 	index = 0;
391 	while (index < bag->parameters->len) {
392 		ICalParameter *param;
393 
394 		param = g_ptr_array_index (bag->parameters, index);
395 		if (param && i_cal_parameter_isa (param) == kind) {
396 			g_ptr_array_remove_index (bag->parameters, index);
397 			count++;
398 
399 			if (!all)
400 				break;
401 		} else {
402 			index++;
403 		}
404 	}
405 
406 	return count;
407 }
408 
409 /**
410  * e_cal_component_parameter_bag_clear:
411  * @bag: an #ECalComponentParameterBag
412  *
413  * Removes all parameters from the @bag, thus it doesn't contain any
414  * parameter after this function returns.
415  *
416  * Since: 3.34
417  **/
418 void
e_cal_component_parameter_bag_clear(ECalComponentParameterBag * bag)419 e_cal_component_parameter_bag_clear (ECalComponentParameterBag *bag)
420 {
421 	g_return_if_fail (bag != NULL);
422 	g_return_if_fail (bag->parameters != NULL);
423 
424 	g_ptr_array_set_size (bag->parameters, 0);
425 }
426